From c085e3bac28076bf0dc047b9981d06555c1e709e Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Wed, 1 Mar 2017 21:28:44 +0100 Subject: [PATCH 01/52] :hammer: started with user-defined exceptions #301 #244 Added class hierarchy for user-defined exceptions (#244). Integrated parse exceptions 101-103. Parse exceptions include the byte count of the last read character to locate the position of the error (#301). --- doc/Makefile | 1 + src/json.hpp | 209 +++++++++++++++- src/json.hpp.re2c | 210 +++++++++++++++- test/src/unit-class_lexer.cpp | 8 +- test/src/unit-class_parser.cpp | 392 ++++++++++++++++-------------- test/src/unit-deserialization.cpp | 58 +++-- test/src/unit-regression.cpp | 7 +- test/src/unit-testsuites.cpp | 6 +- test/src/unit-unicode.cpp | 11 +- 9 files changed, 650 insertions(+), 252 deletions(-) diff --git a/doc/Makefile b/doc/Makefile index 37a0e19f3..cd23a9f77 100644 --- a/doc/Makefile +++ b/doc/Makefile @@ -58,6 +58,7 @@ doxygen: create_output create_links $(SED) -i 's@< ObjectType, ArrayType, StringType, BooleanType, NumberIntegerType, NumberUnsignedType, NumberFloatType, AllocatorType, JSONSerializer >@@g' html/*.html $(SED) -i 's@< ObjectType, ArrayType, StringType, BooleanType, NumberIntegerType, NumberUnsignedType, NumberFloatType, AllocatorType, JSONSerializer >@@g' html/*.html $(SED) -i 's@< ObjectType, ArrayType, StringType, BooleanType, NumberIntegerType, NumberUnsignedType, NumberFloatType, AllocatorType JSONSerializer >@@g' html/*.html + $(SED) -i 's@template<template< typename U, typename V, typename... Args > class ObjectType = std::map, template< typename U, typename... Args > class ArrayType = std::vector, class StringType = std::string, class BooleanType = bool, class NumberIntegerType = std::int64_t, class NumberUnsignedType = std::uint64_t, class NumberFloatType = double, template< typename U > class AllocatorType = std::allocator, template< typename T, typename SFINAE=void > class JSONSerializer = adl_serializer>@@g' html/*.html upload: clean doxygen check_output cd html ; ../scripts/git-update-ghpages nlohmann/json diff --git a/src/json.hpp b/src/json.hpp index ff0ce5add..d4e87e5e4 100644 --- a/src/json.hpp +++ b/src/json.hpp @@ -1088,6 +1088,178 @@ class basic_json /// @} + public: + //////////////// + // exceptions // + //////////////// + + /// @name exceptions + /// Classes to implement user-defined exceptions. + /// @{ + + /*! + @brief general exception of the @ref basic_json class + + Extension of std::exception objects with a member @a id for exception ids. + + name / id | example massage | description + ------------------------------ | --------------- | ------------------------- + json.exception.[parse_error](@ref parse_error).101 | `"parse error at 2: unexpected end of input; expected string literal"` | This error indicates a syntax error while deserializing a JSON text. The error message describes that an unexpected token (character) was encountered, and the member @ref parse_error::byte indicates the error position. + json.exception.[parse_error](@ref parse_error).102 | `"parse error at 14: missing or wrong low surrogate"` | JSON uses the `\uxxxx` format to describe Unicode characters. Code points above above 0xFFFF are split into two `\uxxxx` entries ("surrogate pairs"). This error indicates that the surrogate pair is incomplete or contains an invalid code point. + json.exception.[parse_error](@ref parse_error).103 | `"parse error: code points above 0x10FFFF are invalid"` | Unicode supports code points up to 0x10FFFF. Code points above 0x10FFFF are invalid. + json.exception.[parse_error](@ref parse_error).104 | "parse error: JSON patch must be an array of objects" | [RFC 6902](https://tools.ietf.org/html/rfc6902) requires a JSON Patch document to be a JSON documentthat represents an array of objects. + json.exception.[parse_error](@ref parse_error).105 | "parse error: operation must have string member 'op'" | An operation of a JSON Patch document must contain Operation objects MUST have exactly one "op" member, whose value indicates the operation to perform. Its value MUST be one of "add", "remove", "replace", "move", "copy", or "test"; other values are errors. + json.exception.[parse_error](@ref parse_error).106 | "parse error: array index must not begin with '0'" | An array index in a JSON Pointer ([RFC 6901](https://tools.ietf.org/html/rfc6901)) may be `0` or any number wihtout a leading `0`. + json.exception.[parse_error](@ref parse_error).107 | "parse error: JSON pointer must be empty or begin with '/'" | A JSON Pointer must be a Unicode string containing a sequence of zero or more reference tokens, each prefixed by a `/` character. + json.exception.[parse_error](@ref parse_error).108 | "parse error: escape character '~' must be followed with '0' or '1'" | In a JSON Pointer, only `~0` and `~1` are valid escape sequences. + json.exception.[parse_error](@ref parse_error).109 | "parse error: array index 'one' is not a number" | A JSON Pointer array index must be a number. + json.exception.[invalid_iterator](@ref invalid_iterator).201 | "iterators are not compatible" | The iterators passed to constructor @ref basic_json(InputIT first, InputIT last) are not compatible, meaning they do not belong to the same container. Therefore, the range (@a first, @a last) is invalid. + json.exception.[invalid_iterator](@ref invalid_iterator).202 | "iterator does not fit current value" | In an erase or insert function, the passed iterator @a pos does not belong to the JSON value for which the function was called. It hence does not define a valid position for the deletion/insertion. + json.exception.[invalid_iterator](@ref invalid_iterator).203 | "iterators do not fit current value" | Either iterator passed to function @ref erase(IteratorType first, IteratorType last) does not belong to the JSON value from which values shall be erased. It hence does not define a valid range to delete values from. + json.exception.[invalid_iterator](@ref invalid_iterator).204 | "iterators out of range" | When an iterator range for a primitive type (number, boolean, or string) is passed to a constructor or an erase function, this range has to be exactly (@ref begin(), @ref end()), because this is the only way the single stored value is expressed. All other ranges are invalid. + json.exception.[invalid_iterator](@ref invalid_iterator).205 | "iterator out of range" | When an iterator for a primitive type (number, boolean, or string) is passed to an erase function, the iterator has to be the @ref begin() iterator, because it is the only way to address the stored value. All other iterators are invalid. + json.exception.[invalid_iterator](@ref invalid_iterator).206 | "cannot construct with iterators from null" | The iterators passed to constructor @ref basic_json(InputIT first, InputIT last) belong to a JSON null value and hence to not define a valid range. + json.exception.[invalid_iterator](@ref invalid_iterator).207 | "cannot use key() for non-object iterators" | The key() member function can only be used on iterators belonging to a JSON object, because other types do not have a concept of a key. + json.exception.[invalid_iterator](@ref invalid_iterator).208 | "cannot use operator[] for object iterators" | The operator[] to specify a concrete offset cannot be used on iterators belonging to a JSON object, because JSON objects are unordered. + json.exception.[invalid_iterator](@ref invalid_iterator).209 | "cannot use offsets with object iterators" | The offset operators (+, -, +=, -=) cannot be used on iterators belonging to a JSON object, because JSON objects are unordered. + json.exception.[invalid_iterator](@ref invalid_iterator).210 | "iterators do not fit" | The iterator range passed to the insert function are not compatible, meaning they do not belong to the same container. Therefore, the range (@a first, @a last) is invalid. + json.exception.[invalid_iterator](@ref invalid_iterator).211 | "passed iterators may not belong to container" | The iterator range passed to the insert function must not be a subrange of the container to insert to. + json.exception.[invalid_iterator](@ref invalid_iterator).212 | "cannot compare iterators of different containers" | When two iterators are compared, they must belong to the same container. + json.exception.[invalid_iterator](@ref invalid_iterator).213 | "cannot compare order of object iterators" | The order of object iterators cannot be compated, because JSON objects are unordered. + json.exception.[invalid_iterator](@ref invalid_iterator).214 | "cannot get value" | Cannot get value for iterator: Either the iterator belongs to a null value or it is an iterator to a primitive type (number, boolean, or string), but the iterator is different to @ref begin(). + json.exception.[type_error](@ref type_error).301 | "cannot create object from initializer list" | To create an object from an initializer list, the initializer list must consist only of a list of pairs whose first element is a string. When this constraint is violated, an array is created instead. + json.exception.[type_error](@ref type_error).302 | "type must be object, but is array" | During implicit or explicit value conversion, the JSON type must be compatible to the target type. For instance, a JSON string can only be converted into string types, but not into numbers or boolean types. + json.exception.[type_error](@ref type_error).303 | "incompatible ReferenceType for get_ref, actual type is object" | To retrieve a reference to a value stored in a @ref basic_json object with @ref get_ref, the type of the reference must match the value type. For instance, for a JSON array, the @a ReferenceType must be @ref array_t&. + json.exception.[type_error](@ref type_error).304 | "cannot use at() with string" | The @ref at() member functions can only be executed for certain JSON types. + json.exception.[type_error](@ref type_error).305 | "cannot use operator[] with string" | The @ref operator[] member functions can only be executed for certain JSON types. + json.exception.[type_error](@ref type_error).306 | "cannot use value() with string" | The @ref value() member functions can only be executed for certain JSON types. + json.exception.[type_error](@ref type_error).307 | "cannot use erase() with string" | The @ref erase() member functions can only be executed for certain JSON types. + json.exception.[type_error](@ref type_error).308 | "cannot use push_back() with string" | The @ref push_back() and @ref operator+= member functions can only be executed for certain JSON types. + json.exception.[type_error](@ref type_error).309 | "cannot use insert() with" | The @ref insert() member functions can only be executed for certain JSON types. + json.exception.[type_error](@ref type_error).310 | "cannot use swap() with number" | The @ref swap() member functions can only be executed for certain JSON types. + json.exception.[type_error](@ref type_error).313 | "invalid value to unflatten" | The @ref unflatten function converts an object whose keys are JSON Pointers back into an arbitrary nested JSON value. The JSON Pointers must not overlap, because then the resulting value would not be well defined. + json.exception.[type_error](@ref type_error).314 | "only objects can be unflattened" | The @ref unflatten function only works for an object whose keys are JSON Pointers. + json.exception.[type_error](@ref type_error).315 | "values in object must be primitive" | The @ref unflatten function only works for an object whose keys are JSON Pointers and whose values are primitive. + json.exception.[out_of_range](@ref out_of_range).401 | "array index 3 is out of range" | The provided array index @a i is larger than @a size-1. + json.exception.[out_of_range](@ref out_of_range).402 | "array index '-' (3) is out of range" | The special array index `-` in a JSON Pointer never describes a valid element of the array, but the index past the end. + json.exception.[out_of_range](@ref out_of_range).403 | "key 'foo' not found" | The provided key was not found in the JSON object. + json.exception.[out_of_range](@ref out_of_range).404 | "unresolved reference token 'foo'" | A reference token in a JSON Pointer could not be resolved. + json.exception.[out_of_range](@ref out_of_range).405 | "JSON pointer has no parent" | The JSON Patch operations 'remove' and 'add' can not be applied to the root element of the JSON value. + json.exception.other.500 | "unsuccessful" | A JSON Patch operation 'test' failed. + + @since version 3.0.0 + */ + class exception : public std::exception + { + public: + /// create exception with id an explanatory string + exception(int id_, const std::string& ename, const std::string& what_arg_) + : id(id_), + what_arg("[json.exception." + ename + "." + std::to_string(id_) + "] " + what_arg_) + {} + + /// returns the explanatory string + virtual const char* what() const noexcept + { + return what_arg.c_str(); + } + + /// the id of the exception + const int id; + + private: + /// the explanatory string + const std::string what_arg; + }; + + /*! + @brief exception indicating a parse error + + This excpetion is thrown by the library when a parse error occurs. Parse + errors can occur during the deserialization of JSON text as well as when + using JSON Patch. + + Exceptions have ids 1xx. + + @since version 3.0.0 + */ + class parse_error : public exception + { + public: + /*! + @brief create a parse error exception + @param[in] id_ the id of the exception + @param[in] byte_ the byte index where the error occured (or 0 if + the position cannot be determined) + @param[in] what_arg_ the explanatory string + */ + parse_error(int id_, size_t byte_, const std::string& what_arg_) + : exception(id_, "parse_error", "parse error" + + (byte_ != 0 ? (" at " + std::to_string(byte_)) : "") + + ": " + what_arg_), + byte(byte_) + {} + + /*! + @brief byte index of the parse error + + The byte index of the last read character in the input file. + + @note For an input with n bytes, 1 is the index of the first character + and n+1 is the index of the terminating null byte or the end of + file. + */ + const size_t byte; + }; + + /*! + @brief exception indicating errors with iterators + + Exceptions have ids 2xx. + + @since version 3.0.0 + */ + class invalid_iterator : public exception + { + public: + invalid_iterator(int id_, const std::string& what_arg_) + : exception(id_, "invalid_iterator", what_arg_) + {} + }; + + /*! + @brief exception indicating executing a member function with a wrong type + + Exceptions have ids 3xx. + + @since version 3.0.0 + */ + class type_error : public exception + { + public: + type_error(int id_, const std::string& what_arg_) + : exception(id_, "type_error", what_arg_) + {} + }; + + /*! + @brief exception indicating access out of the defined range + + Exceptions have ids 4xx. + + @since version 3.0.0 + */ + class out_of_range : public exception + { + public: + out_of_range(int id_, const std::string& what_arg_) + : exception(id_, "out_of_range", what_arg_) + {} + }; + + /// @} + + /*! @brief returns the allocator associated with the container */ @@ -6801,6 +6973,9 @@ class basic_json @return result of the deserialization + @throw parse_error.101 if a parse error occurs; example: `""unexpected end + of input; expected string literal""` + @complexity Linear in the length of the input. The parser is a predictive LL(1) parser. The complexity can be higher if the parser callback function @a cb has a super-linear complexity. @@ -9707,17 +9882,17 @@ class basic_json @return string representation of the code point; the length of the result string is between 1 and 4 characters. - @throw std::out_of_range if code point is > 0x10ffff; example: `"code - points above 0x10FFFF are invalid"` - @throw std::invalid_argument if the low surrogate is invalid; example: + @throw parse_error.102 if the low surrogate is invalid; example: `""missing or wrong low surrogate""` + @throw parse_error.103 if code point is > 0x10ffff; example: `"code + points above 0x10FFFF are invalid"` @complexity Constant. @see */ - static string_t to_unicode(const std::size_t codepoint1, - const std::size_t codepoint2 = 0) + string_t to_unicode(const std::size_t codepoint1, + const std::size_t codepoint2 = 0) const { // calculate the code point from the given code points std::size_t codepoint = codepoint1; @@ -9740,7 +9915,7 @@ class basic_json } else { - JSON_THROW(std::invalid_argument("missing or wrong low surrogate")); + JSON_THROW(parse_error(102, get_position(), "missing or wrong low surrogate")); } } @@ -9774,7 +9949,7 @@ class basic_json } else { - JSON_THROW(std::out_of_range("code points above 0x10FFFF are invalid")); + JSON_THROW(parse_error(103, get_position(), "code points above 0x10FFFF are invalid")); } return result; @@ -10034,6 +10209,7 @@ basic_json_parser_6: goto basic_json_parser_6; } { + position += static_cast((m_cursor - m_start)); continue; } basic_json_parser_9: @@ -10889,6 +11065,7 @@ basic_json_parser_74: } + position += static_cast((m_cursor - m_start)); return last_token_type; } @@ -11044,7 +11221,8 @@ basic_json_parser_74: @return string value of current token without opening and closing quotes - @throw std::out_of_range if to_unicode fails + @throw parse_error.102 if to_unicode fails + @throw parse_error.103 if to_unicode fails */ string_t get_string() const { @@ -11130,7 +11308,7 @@ basic_json_parser_74: // make sure there is a subsequent unicode if ((i + 6 >= m_limit) or * (i + 5) != '\\' or * (i + 6) != 'u') { - JSON_THROW(std::invalid_argument("missing low surrogate")); + JSON_THROW(parse_error(102, get_position(), "missing low surrogate")); } // get code yyyy from uxxxx\uyyyy @@ -11143,7 +11321,7 @@ basic_json_parser_74: else if (codepoint >= 0xDC00 and codepoint <= 0xDFFF) { // we found a lone low surrogate - JSON_THROW(std::invalid_argument("missing high surrogate")); + JSON_THROW(parse_error(102, get_position(), "missing high surrogate")); } else { @@ -11398,6 +11576,11 @@ basic_json_parser_74: return false; } + constexpr size_t get_position() const + { + return position; + } + private: /// optional input stream std::istream* m_stream = nullptr; @@ -11417,6 +11600,8 @@ basic_json_parser_74: const lexer_char_t* m_limit = nullptr; /// the last token type token_type last_token_type = token_type::end_of_input; + /// current position in the input (read bytes) + size_t position = 0; }; /*! @@ -11678,7 +11863,7 @@ basic_json_parser_74: "'") : lexer::token_type_name(last_token)); error_msg += "; expected " + lexer::token_type_name(t); - JSON_THROW(std::invalid_argument(error_msg)); + JSON_THROW(parse_error(101, m_lexer.get_position(), error_msg)); } } @@ -11690,7 +11875,7 @@ basic_json_parser_74: error_msg += (last_token == lexer::token_type::parse_error ? ("'" + m_lexer.get_token_string() + "'") : lexer::token_type_name(last_token)); - JSON_THROW(std::invalid_argument(error_msg)); + JSON_THROW(parse_error(101, m_lexer.get_position(), error_msg)); } } diff --git a/src/json.hpp.re2c b/src/json.hpp.re2c index fc7cf9653..1afc025a3 100644 --- a/src/json.hpp.re2c +++ b/src/json.hpp.re2c @@ -1088,6 +1088,178 @@ class basic_json /// @} + public: + //////////////// + // exceptions // + //////////////// + + /// @name exceptions + /// Classes to implement user-defined exceptions. + /// @{ + + /*! + @brief general exception of the @ref basic_json class + + Extension of std::exception objects with a member @a id for exception ids. + + name / id | example massage | description + ------------------------------ | --------------- | ------------------------- + json.exception.[parse_error](@ref parse_error).101 | `"parse error at 2: unexpected end of input; expected string literal"` | This error indicates a syntax error while deserializing a JSON text. The error message describes that an unexpected token (character) was encountered, and the member @ref parse_error::byte indicates the error position. + json.exception.[parse_error](@ref parse_error).102 | `"parse error at 14: missing or wrong low surrogate"` | JSON uses the `\uxxxx` format to describe Unicode characters. Code points above above 0xFFFF are split into two `\uxxxx` entries ("surrogate pairs"). This error indicates that the surrogate pair is incomplete or contains an invalid code point. + json.exception.[parse_error](@ref parse_error).103 | `"parse error: code points above 0x10FFFF are invalid"` | Unicode supports code points up to 0x10FFFF. Code points above 0x10FFFF are invalid. + json.exception.[parse_error](@ref parse_error).104 | "parse error: JSON patch must be an array of objects" | [RFC 6902](https://tools.ietf.org/html/rfc6902) requires a JSON Patch document to be a JSON documentthat represents an array of objects. + json.exception.[parse_error](@ref parse_error).105 | "parse error: operation must have string member 'op'" | An operation of a JSON Patch document must contain Operation objects MUST have exactly one "op" member, whose value indicates the operation to perform. Its value MUST be one of "add", "remove", "replace", "move", "copy", or "test"; other values are errors. + json.exception.[parse_error](@ref parse_error).106 | "parse error: array index must not begin with '0'" | An array index in a JSON Pointer ([RFC 6901](https://tools.ietf.org/html/rfc6901)) may be `0` or any number wihtout a leading `0`. + json.exception.[parse_error](@ref parse_error).107 | "parse error: JSON pointer must be empty or begin with '/'" | A JSON Pointer must be a Unicode string containing a sequence of zero or more reference tokens, each prefixed by a `/` character. + json.exception.[parse_error](@ref parse_error).108 | "parse error: escape character '~' must be followed with '0' or '1'" | In a JSON Pointer, only `~0` and `~1` are valid escape sequences. + json.exception.[parse_error](@ref parse_error).109 | "parse error: array index 'one' is not a number" | A JSON Pointer array index must be a number. + json.exception.[invalid_iterator](@ref invalid_iterator).201 | "iterators are not compatible" | The iterators passed to constructor @ref basic_json(InputIT first, InputIT last) are not compatible, meaning they do not belong to the same container. Therefore, the range (@a first, @a last) is invalid. + json.exception.[invalid_iterator](@ref invalid_iterator).202 | "iterator does not fit current value" | In an erase or insert function, the passed iterator @a pos does not belong to the JSON value for which the function was called. It hence does not define a valid position for the deletion/insertion. + json.exception.[invalid_iterator](@ref invalid_iterator).203 | "iterators do not fit current value" | Either iterator passed to function @ref erase(IteratorType first, IteratorType last) does not belong to the JSON value from which values shall be erased. It hence does not define a valid range to delete values from. + json.exception.[invalid_iterator](@ref invalid_iterator).204 | "iterators out of range" | When an iterator range for a primitive type (number, boolean, or string) is passed to a constructor or an erase function, this range has to be exactly (@ref begin(), @ref end()), because this is the only way the single stored value is expressed. All other ranges are invalid. + json.exception.[invalid_iterator](@ref invalid_iterator).205 | "iterator out of range" | When an iterator for a primitive type (number, boolean, or string) is passed to an erase function, the iterator has to be the @ref begin() iterator, because it is the only way to address the stored value. All other iterators are invalid. + json.exception.[invalid_iterator](@ref invalid_iterator).206 | "cannot construct with iterators from null" | The iterators passed to constructor @ref basic_json(InputIT first, InputIT last) belong to a JSON null value and hence to not define a valid range. + json.exception.[invalid_iterator](@ref invalid_iterator).207 | "cannot use key() for non-object iterators" | The key() member function can only be used on iterators belonging to a JSON object, because other types do not have a concept of a key. + json.exception.[invalid_iterator](@ref invalid_iterator).208 | "cannot use operator[] for object iterators" | The operator[] to specify a concrete offset cannot be used on iterators belonging to a JSON object, because JSON objects are unordered. + json.exception.[invalid_iterator](@ref invalid_iterator).209 | "cannot use offsets with object iterators" | The offset operators (+, -, +=, -=) cannot be used on iterators belonging to a JSON object, because JSON objects are unordered. + json.exception.[invalid_iterator](@ref invalid_iterator).210 | "iterators do not fit" | The iterator range passed to the insert function are not compatible, meaning they do not belong to the same container. Therefore, the range (@a first, @a last) is invalid. + json.exception.[invalid_iterator](@ref invalid_iterator).211 | "passed iterators may not belong to container" | The iterator range passed to the insert function must not be a subrange of the container to insert to. + json.exception.[invalid_iterator](@ref invalid_iterator).212 | "cannot compare iterators of different containers" | When two iterators are compared, they must belong to the same container. + json.exception.[invalid_iterator](@ref invalid_iterator).213 | "cannot compare order of object iterators" | The order of object iterators cannot be compated, because JSON objects are unordered. + json.exception.[invalid_iterator](@ref invalid_iterator).214 | "cannot get value" | Cannot get value for iterator: Either the iterator belongs to a null value or it is an iterator to a primitive type (number, boolean, or string), but the iterator is different to @ref begin(). + json.exception.[type_error](@ref type_error).301 | "cannot create object from initializer list" | To create an object from an initializer list, the initializer list must consist only of a list of pairs whose first element is a string. When this constraint is violated, an array is created instead. + json.exception.[type_error](@ref type_error).302 | "type must be object, but is array" | During implicit or explicit value conversion, the JSON type must be compatible to the target type. For instance, a JSON string can only be converted into string types, but not into numbers or boolean types. + json.exception.[type_error](@ref type_error).303 | "incompatible ReferenceType for get_ref, actual type is object" | To retrieve a reference to a value stored in a @ref basic_json object with @ref get_ref, the type of the reference must match the value type. For instance, for a JSON array, the @a ReferenceType must be @ref array_t&. + json.exception.[type_error](@ref type_error).304 | "cannot use at() with string" | The @ref at() member functions can only be executed for certain JSON types. + json.exception.[type_error](@ref type_error).305 | "cannot use operator[] with string" | The @ref operator[] member functions can only be executed for certain JSON types. + json.exception.[type_error](@ref type_error).306 | "cannot use value() with string" | The @ref value() member functions can only be executed for certain JSON types. + json.exception.[type_error](@ref type_error).307 | "cannot use erase() with string" | The @ref erase() member functions can only be executed for certain JSON types. + json.exception.[type_error](@ref type_error).308 | "cannot use push_back() with string" | The @ref push_back() and @ref operator+= member functions can only be executed for certain JSON types. + json.exception.[type_error](@ref type_error).309 | "cannot use insert() with" | The @ref insert() member functions can only be executed for certain JSON types. + json.exception.[type_error](@ref type_error).310 | "cannot use swap() with number" | The @ref swap() member functions can only be executed for certain JSON types. + json.exception.[type_error](@ref type_error).313 | "invalid value to unflatten" | The @ref unflatten function converts an object whose keys are JSON Pointers back into an arbitrary nested JSON value. The JSON Pointers must not overlap, because then the resulting value would not be well defined. + json.exception.[type_error](@ref type_error).314 | "only objects can be unflattened" | The @ref unflatten function only works for an object whose keys are JSON Pointers. + json.exception.[type_error](@ref type_error).315 | "values in object must be primitive" | The @ref unflatten function only works for an object whose keys are JSON Pointers and whose values are primitive. + json.exception.[out_of_range](@ref out_of_range).401 | "array index 3 is out of range" | The provided array index @a i is larger than @a size-1. + json.exception.[out_of_range](@ref out_of_range).402 | "array index '-' (3) is out of range" | The special array index `-` in a JSON Pointer never describes a valid element of the array, but the index past the end. + json.exception.[out_of_range](@ref out_of_range).403 | "key 'foo' not found" | The provided key was not found in the JSON object. + json.exception.[out_of_range](@ref out_of_range).404 | "unresolved reference token 'foo'" | A reference token in a JSON Pointer could not be resolved. + json.exception.[out_of_range](@ref out_of_range).405 | "JSON pointer has no parent" | The JSON Patch operations 'remove' and 'add' can not be applied to the root element of the JSON value. + json.exception.other.500 | "unsuccessful" | A JSON Patch operation 'test' failed. + + @since version 3.0.0 + */ + class exception : public std::exception + { + public: + /// create exception with id an explanatory string + exception(int id_, const std::string& ename, const std::string& what_arg_) + : id(id_), + what_arg("[json.exception." + ename + "." + std::to_string(id_) + "] " + what_arg_) + {} + + /// returns the explanatory string + virtual const char* what() const noexcept + { + return what_arg.c_str(); + } + + /// the id of the exception + const int id; + + private: + /// the explanatory string + const std::string what_arg; + }; + + /*! + @brief exception indicating a parse error + + This excpetion is thrown by the library when a parse error occurs. Parse + errors can occur during the deserialization of JSON text as well as when + using JSON Patch. + + Exceptions have ids 1xx. + + @since version 3.0.0 + */ + class parse_error : public exception + { + public: + /*! + @brief create a parse error exception + @param[in] id_ the id of the exception + @param[in] byte_ the byte index where the error occured (or 0 if + the position cannot be determined) + @param[in] what_arg_ the explanatory string + */ + parse_error(int id_, size_t byte_, const std::string& what_arg_) + : exception(id_, "parse_error", "parse error" + + (byte_ != 0 ? (" at " + std::to_string(byte_)) : "") + + ": " + what_arg_), + byte(byte_) + {} + + /*! + @brief byte index of the parse error + + The byte index of the last read character in the input file. + + @note For an input with n bytes, 1 is the index of the first character + and n+1 is the index of the terminating null byte or the end of + file. + */ + const size_t byte; + }; + + /*! + @brief exception indicating errors with iterators + + Exceptions have ids 2xx. + + @since version 3.0.0 + */ + class invalid_iterator : public exception + { + public: + invalid_iterator(int id_, const std::string& what_arg_) + : exception(id_, "invalid_iterator", what_arg_) + {} + }; + + /*! + @brief exception indicating executing a member function with a wrong type + + Exceptions have ids 3xx. + + @since version 3.0.0 + */ + class type_error : public exception + { + public: + type_error(int id_, const std::string& what_arg_) + : exception(id_, "type_error", what_arg_) + {} + }; + + /*! + @brief exception indicating access out of the defined range + + Exceptions have ids 4xx. + + @since version 3.0.0 + */ + class out_of_range : public exception + { + public: + out_of_range(int id_, const std::string& what_arg_) + : exception(id_, "out_of_range", what_arg_) + {} + }; + + /// @} + + /*! @brief returns the allocator associated with the container */ @@ -6801,6 +6973,9 @@ class basic_json @return result of the deserialization + @throw parse_error.101 if a parse error occurs; example: `""unexpected end + of input; expected string literal""` + @complexity Linear in the length of the input. The parser is a predictive LL(1) parser. The complexity can be higher if the parser callback function @a cb has a super-linear complexity. @@ -9707,17 +9882,17 @@ class basic_json @return string representation of the code point; the length of the result string is between 1 and 4 characters. - @throw std::out_of_range if code point is > 0x10ffff; example: `"code - points above 0x10FFFF are invalid"` - @throw std::invalid_argument if the low surrogate is invalid; example: + @throw parse_error.102 if the low surrogate is invalid; example: `""missing or wrong low surrogate""` + @throw parse_error.103 if code point is > 0x10ffff; example: `"code + points above 0x10FFFF are invalid"` @complexity Constant. @see */ - static string_t to_unicode(const std::size_t codepoint1, - const std::size_t codepoint2 = 0) + string_t to_unicode(const std::size_t codepoint1, + const std::size_t codepoint2 = 0) const { // calculate the code point from the given code points std::size_t codepoint = codepoint1; @@ -9740,7 +9915,7 @@ class basic_json } else { - JSON_THROW(std::invalid_argument("missing or wrong low surrogate")); + JSON_THROW(parse_error(102, get_position(), "missing or wrong low surrogate")); } } @@ -9774,7 +9949,7 @@ class basic_json } else { - JSON_THROW(std::out_of_range("code points above 0x10FFFF are invalid")); + JSON_THROW(parse_error(103, get_position(), "code points above 0x10FFFF are invalid")); } return result; @@ -9869,7 +10044,7 @@ class basic_json // ignore whitespace ws = [ \t\n\r]+; - ws { continue; } + ws { position += static_cast((m_cursor - m_start)); continue; } // structural characters "[" { last_token_type = token_type::begin_array; break; } @@ -9923,6 +10098,7 @@ class basic_json */ } + position += static_cast((m_cursor - m_start)); return last_token_type; } @@ -10078,7 +10254,8 @@ class basic_json @return string value of current token without opening and closing quotes - @throw std::out_of_range if to_unicode fails + @throw parse_error.102 if to_unicode fails + @throw parse_error.103 if to_unicode fails */ string_t get_string() const { @@ -10164,7 +10341,7 @@ class basic_json // make sure there is a subsequent unicode if ((i + 6 >= m_limit) or * (i + 5) != '\\' or * (i + 6) != 'u') { - JSON_THROW(std::invalid_argument("missing low surrogate")); + JSON_THROW(parse_error(102, get_position(), "missing low surrogate")); } // get code yyyy from uxxxx\uyyyy @@ -10177,7 +10354,7 @@ class basic_json else if (codepoint >= 0xDC00 and codepoint <= 0xDFFF) { // we found a lone low surrogate - JSON_THROW(std::invalid_argument("missing high surrogate")); + JSON_THROW(parse_error(102, get_position(), "missing high surrogate")); } else { @@ -10432,6 +10609,11 @@ class basic_json return false; } + constexpr size_t get_position() const + { + return position; + } + private: /// optional input stream std::istream* m_stream = nullptr; @@ -10451,6 +10633,8 @@ class basic_json const lexer_char_t* m_limit = nullptr; /// the last token type token_type last_token_type = token_type::end_of_input; + /// current position in the input (read bytes) + size_t position = 0; }; /*! @@ -10712,7 +10896,7 @@ class basic_json "'") : lexer::token_type_name(last_token)); error_msg += "; expected " + lexer::token_type_name(t); - JSON_THROW(std::invalid_argument(error_msg)); + JSON_THROW(parse_error(101, m_lexer.get_position(), error_msg)); } } @@ -10724,7 +10908,7 @@ class basic_json error_msg += (last_token == lexer::token_type::parse_error ? ("'" + m_lexer.get_token_string() + "'") : lexer::token_type_name(last_token)); - JSON_THROW(std::invalid_argument(error_msg)); + JSON_THROW(parse_error(101, m_lexer.get_position(), error_msg)); } } diff --git a/test/src/unit-class_lexer.cpp b/test/src/unit-class_lexer.cpp index 0b019bfef..b9e602b7b 100644 --- a/test/src/unit-class_lexer.cpp +++ b/test/src/unit-class_lexer.cpp @@ -190,8 +190,10 @@ TEST_CASE("lexer class") SECTION("to_unicode") { - CHECK(json::lexer::to_unicode(0x1F4A9) == "💩"); - CHECK_THROWS_AS(json::lexer::to_unicode(0x200000), std::out_of_range); - CHECK_THROWS_WITH(json::lexer::to_unicode(0x200000), "code points above 0x10FFFF are invalid"); + // lexer to call to_unicode on + json::lexer dummy_lexer(reinterpret_cast(""), 0); + CHECK(dummy_lexer.to_unicode(0x1F4A9) == "💩"); + CHECK_THROWS_AS(dummy_lexer.to_unicode(0x200000), json::parse_error); + CHECK_THROWS_WITH(dummy_lexer.to_unicode(0x200000), "[json.exception.parse_error.103] parse error: code points above 0x10FFFF are invalid"); } } diff --git a/test/src/unit-class_parser.cpp b/test/src/unit-class_parser.cpp index e3ad3723a..d5e7c99b8 100644 --- a/test/src/unit-class_parser.cpp +++ b/test/src/unit-class_parser.cpp @@ -89,52 +89,56 @@ TEST_CASE("parser class") SECTION("errors") { // error: tab in string - CHECK_THROWS_AS(json::parser("\"\t\"").parse(), std::invalid_argument); - CHECK_THROWS_WITH(json::parser("\"\t\"").parse(), "parse error - unexpected '\"'"); + CHECK_THROWS_AS(json::parser("\"\t\"").parse(), json::parse_error); + CHECK_THROWS_WITH(json::parser("\"\t\"").parse(), + "[json.exception.parse_error.101] parse error at 1: parse error - unexpected '\"'"); // error: newline in string - CHECK_THROWS_AS(json::parser("\"\n\"").parse(), std::invalid_argument); - CHECK_THROWS_AS(json::parser("\"\r\"").parse(), std::invalid_argument); - CHECK_THROWS_WITH(json::parser("\"\n\"").parse(), "parse error - unexpected '\"'"); - CHECK_THROWS_WITH(json::parser("\"\r\"").parse(), "parse error - unexpected '\"'"); + CHECK_THROWS_AS(json::parser("\"\n\"").parse(), json::parse_error); + CHECK_THROWS_AS(json::parser("\"\r\"").parse(), json::parse_error); + CHECK_THROWS_WITH(json::parser("\"\n\"").parse(), + "[json.exception.parse_error.101] parse error at 1: parse error - unexpected '\"'"); + CHECK_THROWS_WITH(json::parser("\"\r\"").parse(), + "[json.exception.parse_error.101] parse error at 1: parse error - unexpected '\"'"); // error: backspace in string - CHECK_THROWS_AS(json::parser("\"\b\"").parse(), std::invalid_argument); - CHECK_THROWS_WITH(json::parser("\"\b\"").parse(), "parse error - unexpected '\"'"); + CHECK_THROWS_AS(json::parser("\"\b\"").parse(), json::parse_error); + CHECK_THROWS_WITH(json::parser("\"\b\"").parse(), + "[json.exception.parse_error.101] parse error at 1: parse error - unexpected '\"'"); // improve code coverage - CHECK_THROWS_AS(json::parser("\uFF01").parse(), std::invalid_argument); - CHECK_THROWS_AS(json::parser("[-4:1,]").parse(), std::invalid_argument); + CHECK_THROWS_AS(json::parser("\uFF01").parse(), json::parse_error); + CHECK_THROWS_AS(json::parser("[-4:1,]").parse(), json::parse_error); // unescaped control characters - CHECK_THROWS_AS(json::parser("\"\x00\"").parse(), std::invalid_argument); - CHECK_THROWS_AS(json::parser("\"\x01\"").parse(), std::invalid_argument); - CHECK_THROWS_AS(json::parser("\"\x02\"").parse(), std::invalid_argument); - CHECK_THROWS_AS(json::parser("\"\x03\"").parse(), std::invalid_argument); - CHECK_THROWS_AS(json::parser("\"\x04\"").parse(), std::invalid_argument); - CHECK_THROWS_AS(json::parser("\"\x05\"").parse(), std::invalid_argument); - CHECK_THROWS_AS(json::parser("\"\x06\"").parse(), std::invalid_argument); - CHECK_THROWS_AS(json::parser("\"\x07\"").parse(), std::invalid_argument); - CHECK_THROWS_AS(json::parser("\"\x08\"").parse(), std::invalid_argument); - CHECK_THROWS_AS(json::parser("\"\x09\"").parse(), std::invalid_argument); - CHECK_THROWS_AS(json::parser("\"\x0a\"").parse(), std::invalid_argument); - CHECK_THROWS_AS(json::parser("\"\x0b\"").parse(), std::invalid_argument); - CHECK_THROWS_AS(json::parser("\"\x0c\"").parse(), std::invalid_argument); - CHECK_THROWS_AS(json::parser("\"\x0d\"").parse(), std::invalid_argument); - CHECK_THROWS_AS(json::parser("\"\x0e\"").parse(), std::invalid_argument); - CHECK_THROWS_AS(json::parser("\"\x0f\"").parse(), std::invalid_argument); - CHECK_THROWS_AS(json::parser("\"\x10\"").parse(), std::invalid_argument); - CHECK_THROWS_AS(json::parser("\"\x11\"").parse(), std::invalid_argument); - CHECK_THROWS_AS(json::parser("\"\x12\"").parse(), std::invalid_argument); - CHECK_THROWS_AS(json::parser("\"\x13\"").parse(), std::invalid_argument); - CHECK_THROWS_AS(json::parser("\"\x14\"").parse(), std::invalid_argument); - CHECK_THROWS_AS(json::parser("\"\x15\"").parse(), std::invalid_argument); - CHECK_THROWS_AS(json::parser("\"\x16\"").parse(), std::invalid_argument); - CHECK_THROWS_AS(json::parser("\"\x17\"").parse(), std::invalid_argument); - CHECK_THROWS_AS(json::parser("\"\x18\"").parse(), std::invalid_argument); - CHECK_THROWS_AS(json::parser("\"\x19\"").parse(), std::invalid_argument); - CHECK_THROWS_AS(json::parser("\"\x1a\"").parse(), std::invalid_argument); - CHECK_THROWS_AS(json::parser("\"\x1b\"").parse(), std::invalid_argument); - CHECK_THROWS_AS(json::parser("\"\x1c\"").parse(), std::invalid_argument); - CHECK_THROWS_AS(json::parser("\"\x1d\"").parse(), std::invalid_argument); - CHECK_THROWS_AS(json::parser("\"\x1e\"").parse(), std::invalid_argument); - CHECK_THROWS_AS(json::parser("\"\x1f\"").parse(), std::invalid_argument); + CHECK_THROWS_AS(json::parser("\"\x00\"").parse(), json::parse_error); + CHECK_THROWS_AS(json::parser("\"\x01\"").parse(), json::parse_error); + CHECK_THROWS_AS(json::parser("\"\x02\"").parse(), json::parse_error); + CHECK_THROWS_AS(json::parser("\"\x03\"").parse(), json::parse_error); + CHECK_THROWS_AS(json::parser("\"\x04\"").parse(), json::parse_error); + CHECK_THROWS_AS(json::parser("\"\x05\"").parse(), json::parse_error); + CHECK_THROWS_AS(json::parser("\"\x06\"").parse(), json::parse_error); + CHECK_THROWS_AS(json::parser("\"\x07\"").parse(), json::parse_error); + CHECK_THROWS_AS(json::parser("\"\x08\"").parse(), json::parse_error); + CHECK_THROWS_AS(json::parser("\"\x09\"").parse(), json::parse_error); + CHECK_THROWS_AS(json::parser("\"\x0a\"").parse(), json::parse_error); + CHECK_THROWS_AS(json::parser("\"\x0b\"").parse(), json::parse_error); + CHECK_THROWS_AS(json::parser("\"\x0c\"").parse(), json::parse_error); + CHECK_THROWS_AS(json::parser("\"\x0d\"").parse(), json::parse_error); + CHECK_THROWS_AS(json::parser("\"\x0e\"").parse(), json::parse_error); + CHECK_THROWS_AS(json::parser("\"\x0f\"").parse(), json::parse_error); + CHECK_THROWS_AS(json::parser("\"\x10\"").parse(), json::parse_error); + CHECK_THROWS_AS(json::parser("\"\x11\"").parse(), json::parse_error); + CHECK_THROWS_AS(json::parser("\"\x12\"").parse(), json::parse_error); + CHECK_THROWS_AS(json::parser("\"\x13\"").parse(), json::parse_error); + CHECK_THROWS_AS(json::parser("\"\x14\"").parse(), json::parse_error); + CHECK_THROWS_AS(json::parser("\"\x15\"").parse(), json::parse_error); + CHECK_THROWS_AS(json::parser("\"\x16\"").parse(), json::parse_error); + CHECK_THROWS_AS(json::parser("\"\x17\"").parse(), json::parse_error); + CHECK_THROWS_AS(json::parser("\"\x18\"").parse(), json::parse_error); + CHECK_THROWS_AS(json::parser("\"\x19\"").parse(), json::parse_error); + CHECK_THROWS_AS(json::parser("\"\x1a\"").parse(), json::parse_error); + CHECK_THROWS_AS(json::parser("\"\x1b\"").parse(), json::parse_error); + CHECK_THROWS_AS(json::parser("\"\x1c\"").parse(), json::parse_error); + CHECK_THROWS_AS(json::parser("\"\x1d\"").parse(), json::parse_error); + CHECK_THROWS_AS(json::parser("\"\x1e\"").parse(), json::parse_error); + CHECK_THROWS_AS(json::parser("\"\x1f\"").parse(), json::parse_error); } SECTION("escaped") @@ -277,60 +281,61 @@ TEST_CASE("parser class") SECTION("invalid numbers") { - CHECK_THROWS_AS(json::parser("01").parse(), std::invalid_argument); - CHECK_THROWS_AS(json::parser("--1").parse(), std::invalid_argument); - CHECK_THROWS_AS(json::parser("1.").parse(), std::invalid_argument); - CHECK_THROWS_AS(json::parser("1E").parse(), std::invalid_argument); - CHECK_THROWS_AS(json::parser("1E-").parse(), std::invalid_argument); - CHECK_THROWS_AS(json::parser("1.E1").parse(), std::invalid_argument); - CHECK_THROWS_AS(json::parser("-1E").parse(), std::invalid_argument); - CHECK_THROWS_AS(json::parser("-0E#").parse(), std::invalid_argument); - CHECK_THROWS_AS(json::parser("-0E-#").parse(), std::invalid_argument); - CHECK_THROWS_AS(json::parser("-0#").parse(), std::invalid_argument); - CHECK_THROWS_AS(json::parser("-0.0:").parse(), std::invalid_argument); - CHECK_THROWS_AS(json::parser("-0.0Z").parse(), std::invalid_argument); - CHECK_THROWS_AS(json::parser("-0E123:").parse(), std::invalid_argument); - CHECK_THROWS_AS(json::parser("-0e0-:").parse(), std::invalid_argument); - CHECK_THROWS_AS(json::parser("-0e-:").parse(), std::invalid_argument); - CHECK_THROWS_AS(json::parser("-0f").parse(), std::invalid_argument); + CHECK_THROWS_AS(json::parser("01").parse(), json::parse_error); + CHECK_THROWS_AS(json::parser("--1").parse(), json::parse_error); + CHECK_THROWS_AS(json::parser("1.").parse(), json::parse_error); + CHECK_THROWS_AS(json::parser("1E").parse(), json::parse_error); + CHECK_THROWS_AS(json::parser("1E-").parse(), json::parse_error); + CHECK_THROWS_AS(json::parser("1.E1").parse(), json::parse_error); + CHECK_THROWS_AS(json::parser("-1E").parse(), json::parse_error); + CHECK_THROWS_AS(json::parser("-0E#").parse(), json::parse_error); + CHECK_THROWS_AS(json::parser("-0E-#").parse(), json::parse_error); + CHECK_THROWS_AS(json::parser("-0#").parse(), json::parse_error); + CHECK_THROWS_AS(json::parser("-0.0:").parse(), json::parse_error); + CHECK_THROWS_AS(json::parser("-0.0Z").parse(), json::parse_error); + CHECK_THROWS_AS(json::parser("-0E123:").parse(), json::parse_error); + CHECK_THROWS_AS(json::parser("-0e0-:").parse(), json::parse_error); + CHECK_THROWS_AS(json::parser("-0e-:").parse(), json::parse_error); + CHECK_THROWS_AS(json::parser("-0f").parse(), json::parse_error); // numbers must not begin with "+" - CHECK_THROWS_AS(json::parser("+1").parse(), std::invalid_argument); - CHECK_THROWS_AS(json::parser("+0").parse(), std::invalid_argument); + CHECK_THROWS_AS(json::parser("+1").parse(), json::parse_error); + CHECK_THROWS_AS(json::parser("+0").parse(), json::parse_error); CHECK_THROWS_WITH(json::parser("01").parse(), - "parse error - unexpected '01'"); + "[json.exception.parse_error.101] parse error at 2: parse error - unexpected '01'"); CHECK_THROWS_WITH(json::parser("-01").parse(), - "parse error - unexpected '-01'"); - CHECK_THROWS_WITH(json::parser("--1").parse(), "parse error - unexpected '-'"); + "[json.exception.parse_error.101] parse error at 3: parse error - unexpected '-01'"); + CHECK_THROWS_WITH(json::parser("--1").parse(), + "[json.exception.parse_error.101] parse error at 1: parse error - unexpected '-'"); CHECK_THROWS_WITH(json::parser("1.").parse(), - "parse error - unexpected '.'; expected end of input"); + "[json.exception.parse_error.101] parse error at 2: parse error - unexpected '.'; expected end of input"); CHECK_THROWS_WITH(json::parser("1E").parse(), - "parse error - unexpected 'E'; expected end of input"); + "[json.exception.parse_error.101] parse error at 2: parse error - unexpected 'E'; expected end of input"); CHECK_THROWS_WITH(json::parser("1E-").parse(), - "parse error - unexpected 'E'; expected end of input"); + "[json.exception.parse_error.101] parse error at 2: parse error - unexpected 'E'; expected end of input"); CHECK_THROWS_WITH(json::parser("1.E1").parse(), - "parse error - unexpected '.'; expected end of input"); + "[json.exception.parse_error.101] parse error at 2: parse error - unexpected '.'; expected end of input"); CHECK_THROWS_WITH(json::parser("-1E").parse(), - "parse error - unexpected 'E'; expected end of input"); + "[json.exception.parse_error.101] parse error at 3: parse error - unexpected 'E'; expected end of input"); CHECK_THROWS_WITH(json::parser("-0E#").parse(), - "parse error - unexpected 'E'; expected end of input"); + "[json.exception.parse_error.101] parse error at 3: parse error - unexpected 'E'; expected end of input"); CHECK_THROWS_WITH(json::parser("-0E-#").parse(), - "parse error - unexpected 'E'; expected end of input"); + "[json.exception.parse_error.101] parse error at 3: parse error - unexpected 'E'; expected end of input"); CHECK_THROWS_WITH(json::parser("-0#").parse(), - "parse error - unexpected '#'; expected end of input"); + "[json.exception.parse_error.101] parse error at 3: parse error - unexpected '#'; expected end of input"); CHECK_THROWS_WITH(json::parser("-0.0:").parse(), - "parse error - unexpected ':'; expected end of input"); + "[json.exception.parse_error.101] parse error at 5: parse error - unexpected ':'; expected end of input"); CHECK_THROWS_WITH(json::parser("-0.0Z").parse(), - "parse error - unexpected 'Z'; expected end of input"); + "[json.exception.parse_error.101] parse error at 5: parse error - unexpected 'Z'; expected end of input"); CHECK_THROWS_WITH(json::parser("-0E123:").parse(), - "parse error - unexpected ':'; expected end of input"); + "[json.exception.parse_error.101] parse error at 7: parse error - unexpected ':'; expected end of input"); CHECK_THROWS_WITH(json::parser("-0e0-:").parse(), - "parse error - unexpected '-'; expected end of input"); + "[json.exception.parse_error.101] parse error at 5: parse error - unexpected '-'; expected end of input"); CHECK_THROWS_WITH(json::parser("-0e-:").parse(), - "parse error - unexpected 'e'; expected end of input"); + "[json.exception.parse_error.101] parse error at 3: parse error - unexpected 'e'; expected end of input"); CHECK_THROWS_WITH(json::parser("-0f").parse(), - "parse error - unexpected 'f'; expected end of input"); + "[json.exception.parse_error.101] parse error at 3: parse error - unexpected 'f'; expected end of input"); } } } @@ -338,147 +343,150 @@ TEST_CASE("parser class") SECTION("parse errors") { // unexpected end of number - CHECK_THROWS_AS(json::parser("0.").parse(), std::invalid_argument); - CHECK_THROWS_AS(json::parser("-").parse(), std::invalid_argument); - CHECK_THROWS_AS(json::parser("--").parse(), std::invalid_argument); - CHECK_THROWS_AS(json::parser("-0.").parse(), std::invalid_argument); - CHECK_THROWS_AS(json::parser("-.").parse(), std::invalid_argument); - CHECK_THROWS_AS(json::parser("-:").parse(), std::invalid_argument); - CHECK_THROWS_AS(json::parser("0.:").parse(), std::invalid_argument); - CHECK_THROWS_AS(json::parser("e.").parse(), std::invalid_argument); - CHECK_THROWS_AS(json::parser("1e.").parse(), std::invalid_argument); - CHECK_THROWS_AS(json::parser("1e/").parse(), std::invalid_argument); - CHECK_THROWS_AS(json::parser("1e:").parse(), std::invalid_argument); - CHECK_THROWS_AS(json::parser("1E.").parse(), std::invalid_argument); - CHECK_THROWS_AS(json::parser("1E/").parse(), std::invalid_argument); - CHECK_THROWS_AS(json::parser("1E:").parse(), std::invalid_argument); + CHECK_THROWS_AS(json::parser("0.").parse(), json::parse_error); + CHECK_THROWS_AS(json::parser("-").parse(), json::parse_error); + CHECK_THROWS_AS(json::parser("--").parse(), json::parse_error); + CHECK_THROWS_AS(json::parser("-0.").parse(), json::parse_error); + CHECK_THROWS_AS(json::parser("-.").parse(), json::parse_error); + CHECK_THROWS_AS(json::parser("-:").parse(), json::parse_error); + CHECK_THROWS_AS(json::parser("0.:").parse(), json::parse_error); + CHECK_THROWS_AS(json::parser("e.").parse(), json::parse_error); + CHECK_THROWS_AS(json::parser("1e.").parse(), json::parse_error); + CHECK_THROWS_AS(json::parser("1e/").parse(), json::parse_error); + CHECK_THROWS_AS(json::parser("1e:").parse(), json::parse_error); + CHECK_THROWS_AS(json::parser("1E.").parse(), json::parse_error); + CHECK_THROWS_AS(json::parser("1E/").parse(), json::parse_error); + CHECK_THROWS_AS(json::parser("1E:").parse(), json::parse_error); CHECK_THROWS_WITH(json::parser("0.").parse(), - "parse error - unexpected '.'; expected end of input"); - CHECK_THROWS_WITH(json::parser("-").parse(), "parse error - unexpected '-'"); + "[json.exception.parse_error.101] parse error at 2: parse error - unexpected '.'; expected end of input"); + CHECK_THROWS_WITH(json::parser("-").parse(), + "[json.exception.parse_error.101] parse error at 1: parse error - unexpected '-'"); CHECK_THROWS_WITH(json::parser("--").parse(), - "parse error - unexpected '-'"); + "[json.exception.parse_error.101] parse error at 1: parse error - unexpected '-'"); CHECK_THROWS_WITH(json::parser("-0.").parse(), - "parse error - unexpected '.'; expected end of input"); + "[json.exception.parse_error.101] parse error at 3: parse error - unexpected '.'; expected end of input"); CHECK_THROWS_WITH(json::parser("-.").parse(), - "parse error - unexpected '-'"); + "[json.exception.parse_error.101] parse error at 1: parse error - unexpected '-'"); CHECK_THROWS_WITH(json::parser("-:").parse(), - "parse error - unexpected '-'"); + "[json.exception.parse_error.101] parse error at 1: parse error - unexpected '-'"); CHECK_THROWS_WITH(json::parser("0.:").parse(), - "parse error - unexpected '.'; expected end of input"); + "[json.exception.parse_error.101] parse error at 2: parse error - unexpected '.'; expected end of input"); CHECK_THROWS_WITH(json::parser("e.").parse(), - "parse error - unexpected 'e'"); + "[json.exception.parse_error.101] parse error at 1: parse error - unexpected 'e'"); CHECK_THROWS_WITH(json::parser("1e.").parse(), - "parse error - unexpected 'e'; expected end of input"); + "[json.exception.parse_error.101] parse error at 2: parse error - unexpected 'e'; expected end of input"); CHECK_THROWS_WITH(json::parser("1e/").parse(), - "parse error - unexpected 'e'; expected end of input"); + "[json.exception.parse_error.101] parse error at 2: parse error - unexpected 'e'; expected end of input"); CHECK_THROWS_WITH(json::parser("1e:").parse(), - "parse error - unexpected 'e'; expected end of input"); + "[json.exception.parse_error.101] parse error at 2: parse error - unexpected 'e'; expected end of input"); CHECK_THROWS_WITH(json::parser("1E.").parse(), - "parse error - unexpected 'E'; expected end of input"); + "[json.exception.parse_error.101] parse error at 2: parse error - unexpected 'E'; expected end of input"); CHECK_THROWS_WITH(json::parser("1E/").parse(), - "parse error - unexpected 'E'; expected end of input"); + "[json.exception.parse_error.101] parse error at 2: parse error - unexpected 'E'; expected end of input"); CHECK_THROWS_WITH(json::parser("1E:").parse(), - "parse error - unexpected 'E'; expected end of input"); + "[json.exception.parse_error.101] parse error at 2: parse error - unexpected 'E'; expected end of input"); // unexpected end of null - CHECK_THROWS_AS(json::parser("n").parse(), std::invalid_argument); - CHECK_THROWS_AS(json::parser("nu").parse(), std::invalid_argument); - CHECK_THROWS_AS(json::parser("nul").parse(), std::invalid_argument); - CHECK_THROWS_WITH(json::parser("n").parse(), "parse error - unexpected 'n'"); + CHECK_THROWS_AS(json::parser("n").parse(), json::parse_error); + CHECK_THROWS_AS(json::parser("nu").parse(), json::parse_error); + CHECK_THROWS_AS(json::parser("nul").parse(), json::parse_error); + CHECK_THROWS_WITH(json::parser("n").parse(), "[json.exception.parse_error.101] parse error at 1: parse error - unexpected 'n'"); CHECK_THROWS_WITH(json::parser("nu").parse(), - "parse error - unexpected 'n'"); + "[json.exception.parse_error.101] parse error at 1: parse error - unexpected 'n'"); CHECK_THROWS_WITH(json::parser("nul").parse(), - "parse error - unexpected 'n'"); + "[json.exception.parse_error.101] parse error at 1: parse error - unexpected 'n'"); // unexpected end of true - CHECK_THROWS_AS(json::parser("t").parse(), std::invalid_argument); - CHECK_THROWS_AS(json::parser("tr").parse(), std::invalid_argument); - CHECK_THROWS_AS(json::parser("tru").parse(), std::invalid_argument); - CHECK_THROWS_WITH(json::parser("t").parse(), "parse error - unexpected 't'"); + CHECK_THROWS_AS(json::parser("t").parse(), json::parse_error); + CHECK_THROWS_AS(json::parser("tr").parse(), json::parse_error); + CHECK_THROWS_AS(json::parser("tru").parse(), json::parse_error); + CHECK_THROWS_WITH(json::parser("t").parse(), "[json.exception.parse_error.101] parse error at 1: parse error - unexpected 't'"); CHECK_THROWS_WITH(json::parser("tr").parse(), - "parse error - unexpected 't'"); + "[json.exception.parse_error.101] parse error at 1: parse error - unexpected 't'"); CHECK_THROWS_WITH(json::parser("tru").parse(), - "parse error - unexpected 't'"); + "[json.exception.parse_error.101] parse error at 1: parse error - unexpected 't'"); // unexpected end of false - CHECK_THROWS_AS(json::parser("f").parse(), std::invalid_argument); - CHECK_THROWS_AS(json::parser("fa").parse(), std::invalid_argument); - CHECK_THROWS_AS(json::parser("fal").parse(), std::invalid_argument); - CHECK_THROWS_AS(json::parser("fals").parse(), std::invalid_argument); - CHECK_THROWS_WITH(json::parser("f").parse(), "parse error - unexpected 'f'"); + CHECK_THROWS_AS(json::parser("f").parse(), json::parse_error); + CHECK_THROWS_AS(json::parser("fa").parse(), json::parse_error); + CHECK_THROWS_AS(json::parser("fal").parse(), json::parse_error); + CHECK_THROWS_AS(json::parser("fals").parse(), json::parse_error); + CHECK_THROWS_WITH(json::parser("f").parse(), "[json.exception.parse_error.101] parse error at 1: parse error - unexpected 'f'"); CHECK_THROWS_WITH(json::parser("fa").parse(), - "parse error - unexpected 'f'"); + "[json.exception.parse_error.101] parse error at 1: parse error - unexpected 'f'"); CHECK_THROWS_WITH(json::parser("fal").parse(), - "parse error - unexpected 'f'"); + "[json.exception.parse_error.101] parse error at 1: parse error - unexpected 'f'"); CHECK_THROWS_WITH(json::parser("fals").parse(), - "parse error - unexpected 'f'"); + "[json.exception.parse_error.101] parse error at 1: parse error - unexpected 'f'"); // missing/unexpected end of array - CHECK_THROWS_AS(json::parser("[").parse(), std::invalid_argument); - CHECK_THROWS_AS(json::parser("[1").parse(), std::invalid_argument); - CHECK_THROWS_AS(json::parser("[1,").parse(), std::invalid_argument); - CHECK_THROWS_AS(json::parser("[1,]").parse(), std::invalid_argument); - CHECK_THROWS_AS(json::parser("]").parse(), std::invalid_argument); + CHECK_THROWS_AS(json::parser("[").parse(), json::parse_error); + CHECK_THROWS_AS(json::parser("[1").parse(), json::parse_error); + CHECK_THROWS_AS(json::parser("[1,").parse(), json::parse_error); + CHECK_THROWS_AS(json::parser("[1,]").parse(), json::parse_error); + CHECK_THROWS_AS(json::parser("]").parse(), json::parse_error); CHECK_THROWS_WITH(json::parser("[").parse(), - "parse error - unexpected end of input"); + "[json.exception.parse_error.101] parse error at 2: parse error - unexpected end of input"); CHECK_THROWS_WITH(json::parser("[1").parse(), - "parse error - unexpected end of input; expected ']'"); + "[json.exception.parse_error.101] parse error at 3: parse error - unexpected end of input; expected ']'"); CHECK_THROWS_WITH(json::parser("[1,").parse(), - "parse error - unexpected end of input"); + "[json.exception.parse_error.101] parse error at 4: parse error - unexpected end of input"); CHECK_THROWS_WITH(json::parser("[1,]").parse(), - "parse error - unexpected ']'"); - CHECK_THROWS_WITH(json::parser("]").parse(), "parse error - unexpected ']'"); + "[json.exception.parse_error.101] parse error at 4: parse error - unexpected ']'"); + CHECK_THROWS_WITH(json::parser("]").parse(), + "[json.exception.parse_error.101] parse error at 1: parse error - unexpected ']'"); // missing/unexpected end of object - CHECK_THROWS_AS(json::parser("{").parse(), std::invalid_argument); - CHECK_THROWS_AS(json::parser("{\"foo\"").parse(), std::invalid_argument); - CHECK_THROWS_AS(json::parser("{\"foo\":").parse(), std::invalid_argument); - CHECK_THROWS_AS(json::parser("{\"foo\":}").parse(), std::invalid_argument); - CHECK_THROWS_AS(json::parser("{\"foo\":1,}").parse(), std::invalid_argument); - CHECK_THROWS_AS(json::parser("}").parse(), std::invalid_argument); + CHECK_THROWS_AS(json::parser("{").parse(), json::parse_error); + CHECK_THROWS_AS(json::parser("{\"foo\"").parse(), json::parse_error); + CHECK_THROWS_AS(json::parser("{\"foo\":").parse(), json::parse_error); + CHECK_THROWS_AS(json::parser("{\"foo\":}").parse(), json::parse_error); + CHECK_THROWS_AS(json::parser("{\"foo\":1,}").parse(), json::parse_error); + CHECK_THROWS_AS(json::parser("}").parse(), json::parse_error); CHECK_THROWS_WITH(json::parser("{").parse(), - "parse error - unexpected end of input; expected string literal"); + "[json.exception.parse_error.101] parse error at 2: parse error - unexpected end of input; expected string literal"); CHECK_THROWS_WITH(json::parser("{\"foo\"").parse(), - "parse error - unexpected end of input; expected ':'"); + "[json.exception.parse_error.101] parse error at 7: parse error - unexpected end of input; expected ':'"); CHECK_THROWS_WITH(json::parser("{\"foo\":").parse(), - "parse error - unexpected end of input"); + "[json.exception.parse_error.101] parse error at 8: parse error - unexpected end of input"); CHECK_THROWS_WITH(json::parser("{\"foo\":}").parse(), - "parse error - unexpected '}'"); + "[json.exception.parse_error.101] parse error at 8: parse error - unexpected '}'"); CHECK_THROWS_WITH(json::parser("{\"foo\":1,}").parse(), - "parse error - unexpected '}'; expected string literal"); - CHECK_THROWS_WITH(json::parser("}").parse(), "parse error - unexpected '}'"); + "[json.exception.parse_error.101] parse error at 10: parse error - unexpected '}'; expected string literal"); + CHECK_THROWS_WITH(json::parser("}").parse(), + "[json.exception.parse_error.101] parse error at 1: parse error - unexpected '}'"); // missing/unexpected end of string - CHECK_THROWS_AS(json::parser("\"").parse(), std::invalid_argument); - CHECK_THROWS_AS(json::parser("\"\\\"").parse(), std::invalid_argument); - CHECK_THROWS_AS(json::parser("\"\\u\"").parse(), std::invalid_argument); - CHECK_THROWS_AS(json::parser("\"\\u0\"").parse(), std::invalid_argument); - CHECK_THROWS_AS(json::parser("\"\\u01\"").parse(), std::invalid_argument); - CHECK_THROWS_AS(json::parser("\"\\u012\"").parse(), std::invalid_argument); - CHECK_THROWS_AS(json::parser("\"\\u").parse(), std::invalid_argument); - CHECK_THROWS_AS(json::parser("\"\\u0").parse(), std::invalid_argument); - CHECK_THROWS_AS(json::parser("\"\\u01").parse(), std::invalid_argument); - CHECK_THROWS_AS(json::parser("\"\\u012").parse(), std::invalid_argument); + CHECK_THROWS_AS(json::parser("\"").parse(), json::parse_error); + CHECK_THROWS_AS(json::parser("\"\\\"").parse(), json::parse_error); + CHECK_THROWS_AS(json::parser("\"\\u\"").parse(), json::parse_error); + CHECK_THROWS_AS(json::parser("\"\\u0\"").parse(), json::parse_error); + CHECK_THROWS_AS(json::parser("\"\\u01\"").parse(), json::parse_error); + CHECK_THROWS_AS(json::parser("\"\\u012\"").parse(), json::parse_error); + CHECK_THROWS_AS(json::parser("\"\\u").parse(), json::parse_error); + CHECK_THROWS_AS(json::parser("\"\\u0").parse(), json::parse_error); + CHECK_THROWS_AS(json::parser("\"\\u01").parse(), json::parse_error); + CHECK_THROWS_AS(json::parser("\"\\u012").parse(), json::parse_error); CHECK_THROWS_WITH(json::parser("\"").parse(), - "parse error - unexpected '\"'"); + "[json.exception.parse_error.101] parse error at 1: parse error - unexpected '\"'"); CHECK_THROWS_WITH(json::parser("\"\\\"").parse(), - "parse error - unexpected '\"'"); + "[json.exception.parse_error.101] parse error at 1: parse error - unexpected '\"'"); CHECK_THROWS_WITH(json::parser("\"\\u\"").parse(), - "parse error - unexpected '\"'"); + "[json.exception.parse_error.101] parse error at 1: parse error - unexpected '\"'"); CHECK_THROWS_WITH(json::parser("\"\\u0\"").parse(), - "parse error - unexpected '\"'"); + "[json.exception.parse_error.101] parse error at 1: parse error - unexpected '\"'"); CHECK_THROWS_WITH(json::parser("\"\\u01\"").parse(), - "parse error - unexpected '\"'"); + "[json.exception.parse_error.101] parse error at 1: parse error - unexpected '\"'"); CHECK_THROWS_WITH(json::parser("\"\\u012\"").parse(), - "parse error - unexpected '\"'"); + "[json.exception.parse_error.101] parse error at 1: parse error - unexpected '\"'"); CHECK_THROWS_WITH(json::parser("\"\\u").parse(), - "parse error - unexpected '\"'"); + "[json.exception.parse_error.101] parse error at 1: parse error - unexpected '\"'"); CHECK_THROWS_WITH(json::parser("\"\\u0").parse(), - "parse error - unexpected '\"'"); + "[json.exception.parse_error.101] parse error at 1: parse error - unexpected '\"'"); CHECK_THROWS_WITH(json::parser("\"\\u01").parse(), - "parse error - unexpected '\"'"); + "[json.exception.parse_error.101] parse error at 1: parse error - unexpected '\"'"); CHECK_THROWS_WITH(json::parser("\"\\u012").parse(), - "parse error - unexpected '\"'"); + "[json.exception.parse_error.101] parse error at 1: parse error - unexpected '\"'"); // invalid escapes for (int c = 1; c < 128; ++c) @@ -510,8 +518,9 @@ TEST_CASE("parser class") // any other combination of backslash and character is invalid default: { - CHECK_THROWS_AS(json::parser(s.c_str()).parse(), std::invalid_argument); - CHECK_THROWS_WITH(json::parser(s.c_str()).parse(), "parse error - unexpected '\"'"); + CHECK_THROWS_AS(json::parser(s.c_str()).parse(), json::parse_error); + CHECK_THROWS_WITH(json::parser(s.c_str()).parse(), + "[json.exception.parse_error.101] parse error at 1: parse error - unexpected '\"'"); break; } } @@ -576,40 +585,49 @@ TEST_CASE("parser class") } else { - CHECK_THROWS_AS(json::parser(s1.c_str()).parse(), std::invalid_argument); - CHECK_THROWS_AS(json::parser(s2.c_str()).parse(), std::invalid_argument); - CHECK_THROWS_AS(json::parser(s3.c_str()).parse(), std::invalid_argument); - CHECK_THROWS_AS(json::parser(s4.c_str()).parse(), std::invalid_argument); + CHECK_THROWS_AS(json::parser(s1.c_str()).parse(), json::parse_error); + CHECK_THROWS_AS(json::parser(s2.c_str()).parse(), json::parse_error); + CHECK_THROWS_AS(json::parser(s3.c_str()).parse(), json::parse_error); + CHECK_THROWS_AS(json::parser(s4.c_str()).parse(), json::parse_error); - CHECK_THROWS_WITH(json::parser(s1.c_str()).parse(), "parse error - unexpected '\"'"); - CHECK_THROWS_WITH(json::parser(s2.c_str()).parse(), "parse error - unexpected '\"'"); - CHECK_THROWS_WITH(json::parser(s3.c_str()).parse(), "parse error - unexpected '\"'"); - CHECK_THROWS_WITH(json::parser(s4.c_str()).parse(), "parse error - unexpected '\"'"); + CHECK_THROWS_WITH(json::parser(s1.c_str()).parse(), + "[json.exception.parse_error.101] parse error at 1: parse error - unexpected '\"'"); + CHECK_THROWS_WITH(json::parser(s2.c_str()).parse(), + "[json.exception.parse_error.101] parse error at 1: parse error - unexpected '\"'"); + CHECK_THROWS_WITH(json::parser(s3.c_str()).parse(), + "[json.exception.parse_error.101] parse error at 1: parse error - unexpected '\"'"); + CHECK_THROWS_WITH(json::parser(s4.c_str()).parse(), + "[json.exception.parse_error.101] parse error at 1: parse error - unexpected '\"'"); } } } // missing part of a surrogate pair - CHECK_THROWS_AS(json::parse("\"\\uD80C\""), std::invalid_argument); - CHECK_THROWS_WITH(json::parse("\"\\uD80C\""), "missing low surrogate"); + CHECK_THROWS_AS(json::parse("\"\\uD80C\""), json::parse_error); + CHECK_THROWS_WITH(json::parse("\"\\uD80C\""), + "[json.exception.parse_error.102] parse error at 8: missing low surrogate"); // invalid surrogate pair - CHECK_THROWS_AS(json::parse("\"\\uD80C\\uD80C\""), std::invalid_argument); - CHECK_THROWS_AS(json::parse("\"\\uD80C\\u0000\""), std::invalid_argument); - CHECK_THROWS_AS(json::parse("\"\\uD80C\\uFFFF\""), std::invalid_argument); + CHECK_THROWS_AS(json::parse("\"\\uD80C\\uD80C\""), json::parse_error); + CHECK_THROWS_AS(json::parse("\"\\uD80C\\u0000\""), json::parse_error); + CHECK_THROWS_AS(json::parse("\"\\uD80C\\uFFFF\""), json::parse_error); CHECK_THROWS_WITH(json::parse("\"\\uD80C\\uD80C\""), - "missing or wrong low surrogate"); + "[json.exception.parse_error.102] parse error at 14: missing or wrong low surrogate"); CHECK_THROWS_WITH(json::parse("\"\\uD80C\\u0000\""), - "missing or wrong low surrogate"); + "[json.exception.parse_error.102] parse error at 14: missing or wrong low surrogate"); CHECK_THROWS_WITH(json::parse("\"\\uD80C\\uFFFF\""), - "missing or wrong low surrogate"); + "[json.exception.parse_error.102] parse error at 14: missing or wrong low surrogate"); } SECTION("tests found by mutate++") { // test case to make sure no comma preceeds the first key - CHECK_THROWS_AS(json::parser("{,\"key\": false}").parse(), std::invalid_argument); + CHECK_THROWS_AS(json::parser("{,\"key\": false}").parse(), json::parse_error); + CHECK_THROWS_WITH(json::parser("{,\"key\": false}").parse(), + "[json.exception.parse_error.101] parse error at 2: parse error - unexpected ','"); // test case to make sure an object is properly closed - CHECK_THROWS_AS(json::parser("[{\"key\": false true]").parse(), std::invalid_argument); + CHECK_THROWS_AS(json::parser("[{\"key\": false true]").parse(), json::parse_error); + CHECK_THROWS_WITH(json::parser("[{\"key\": false true]").parse(), + "[json.exception.parse_error.101] parse error at 19: parse error - unexpected true literal; expected '}'"); // test case to make sure the callback is properly evaluated after reading a key { diff --git a/test/src/unit-deserialization.cpp b/test/src/unit-deserialization.cpp index 9028fdfbb..cacf66870 100644 --- a/test/src/unit-deserialization.cpp +++ b/test/src/unit-deserialization.cpp @@ -90,15 +90,17 @@ TEST_CASE("deserialization") std::stringstream ss1, ss2; ss1 << "[\"foo\",1,2,3,false,{\"one\":1}"; ss2 << "[\"foo\",1,2,3,false,{\"one\":1}"; - CHECK_THROWS_AS(json::parse(ss1), std::invalid_argument); - CHECK_THROWS_WITH(json::parse(ss2), "parse error - unexpected end of input; expected ']'"); + CHECK_THROWS_AS(json::parse(ss1), json::parse_error); + CHECK_THROWS_WITH(json::parse(ss2), + "[json.exception.parse_error.101] parse error at 30: parse error - unexpected end of input; expected ']'"); } SECTION("string") { json::string_t s = "[\"foo\",1,2,3,false,{\"one\":1}"; - CHECK_THROWS_AS(json::parse(s), std::invalid_argument); - CHECK_THROWS_WITH(json::parse(s), "parse error - unexpected end of input; expected ']'"); + CHECK_THROWS_AS(json::parse(s), json::parse_error); + CHECK_THROWS_WITH(json::parse(s), + "[json.exception.parse_error.101] parse error at 29: parse error - unexpected end of input; expected ']'"); } SECTION("operator<<") @@ -107,8 +109,9 @@ TEST_CASE("deserialization") ss1 << "[\"foo\",1,2,3,false,{\"one\":1}"; ss2 << "[\"foo\",1,2,3,false,{\"one\":1}"; json j; - CHECK_THROWS_AS(j << ss1, std::invalid_argument); - CHECK_THROWS_WITH(j << ss2, "parse error - unexpected end of input; expected ']'"); + CHECK_THROWS_AS(j << ss1, json::parse_error); + CHECK_THROWS_WITH(j << ss2, + "[json.exception.parse_error.101] parse error at 30: parse error - unexpected end of input; expected ']'"); } SECTION("operator>>") @@ -117,15 +120,16 @@ TEST_CASE("deserialization") ss1 << "[\"foo\",1,2,3,false,{\"one\":1}"; ss2 << "[\"foo\",1,2,3,false,{\"one\":1}"; json j; - CHECK_THROWS_AS(ss1 >> j, std::invalid_argument); - CHECK_THROWS_WITH(ss2 >> j, "parse error - unexpected end of input; expected ']'"); + CHECK_THROWS_AS(ss1 >> j, json::parse_error); + CHECK_THROWS_WITH(ss2 >> j, + "[json.exception.parse_error.101] parse error at 30: parse error - unexpected end of input; expected ']'"); } SECTION("user-defined string literal") { - CHECK_THROWS_AS("[\"foo\",1,2,3,false,{\"one\":1}"_json, std::invalid_argument); + CHECK_THROWS_AS("[\"foo\",1,2,3,false,{\"one\":1}"_json, json::parse_error); CHECK_THROWS_WITH("[\"foo\",1,2,3,false,{\"one\":1}"_json, - "parse error - unexpected end of input; expected ']'"); + "[json.exception.parse_error.101] parse error at 29: parse error - unexpected end of input; expected ']'"); } } @@ -178,7 +182,7 @@ TEST_CASE("deserialization") SECTION("empty container") { std::vector v; - CHECK_THROWS_AS(json::parse(v), std::invalid_argument); + CHECK_THROWS_AS(json::parse(v), json::parse_error); } } @@ -223,7 +227,7 @@ TEST_CASE("deserialization") SECTION("with empty range") { std::vector v; - CHECK_THROWS_AS(json::parse(std::begin(v), std::end(v)), std::invalid_argument); + CHECK_THROWS_AS(json::parse(std::begin(v), std::end(v)), json::parse_error); } } @@ -233,91 +237,91 @@ TEST_CASE("deserialization") SECTION("case 1") { uint8_t v[] = {'\"', 'a', 'a', 'a', 'a', 'a', 'a', '\\', 'u'}; - CHECK_THROWS_AS(json::parse(std::begin(v), std::end(v)), std::invalid_argument); + CHECK_THROWS_AS(json::parse(std::begin(v), std::end(v)), json::parse_error); } SECTION("case 2") { uint8_t v[] = {'\"', 'a', 'a', 'a', 'a', 'a', 'a', '\\', 'u', '1'}; - CHECK_THROWS_AS(json::parse(std::begin(v), std::end(v)), std::invalid_argument); + CHECK_THROWS_AS(json::parse(std::begin(v), std::end(v)), json::parse_error); } SECTION("case 3") { uint8_t v[] = {'\"', 'a', 'a', 'a', 'a', 'a', 'a', '\\', 'u', '1', '1', '1', '1', '1', '1', '1', '1'}; - CHECK_THROWS_AS(json::parse(std::begin(v), std::end(v)), std::invalid_argument); + CHECK_THROWS_AS(json::parse(std::begin(v), std::end(v)), json::parse_error); } SECTION("case 4") { uint8_t v[] = {'\"', 'a', 'a', 'a', 'a', 'a', 'a', 'u', '1', '1', '1', '1', '1', '1', '1', '1', '\\'}; - CHECK_THROWS_AS(json::parse(std::begin(v), std::end(v)), std::invalid_argument); + CHECK_THROWS_AS(json::parse(std::begin(v), std::end(v)), json::parse_error); } SECTION("case 5") { uint8_t v[] = {'\"', 0x7F, 0xC1}; - CHECK_THROWS_AS(json::parse(std::begin(v), std::end(v)), std::invalid_argument); + CHECK_THROWS_AS(json::parse(std::begin(v), std::end(v)), json::parse_error); } SECTION("case 6") { uint8_t v[] = {'\"', 0x7F, 0xDF, 0x7F}; - CHECK_THROWS_AS(json::parse(std::begin(v), std::end(v)), std::invalid_argument); + CHECK_THROWS_AS(json::parse(std::begin(v), std::end(v)), json::parse_error); } SECTION("case 7") { uint8_t v[] = {'\"', 0x7F, 0xDF, 0xC0}; - CHECK_THROWS_AS(json::parse(std::begin(v), std::end(v)), std::invalid_argument); + CHECK_THROWS_AS(json::parse(std::begin(v), std::end(v)), json::parse_error); } SECTION("case 8") { uint8_t v[] = {'\"', 0x7F, 0xE0, 0x9F}; - CHECK_THROWS_AS(json::parse(std::begin(v), std::end(v)), std::invalid_argument); + CHECK_THROWS_AS(json::parse(std::begin(v), std::end(v)), json::parse_error); } SECTION("case 9") { uint8_t v[] = {'\"', 0x7F, 0xEF, 0xC0}; - CHECK_THROWS_AS(json::parse(std::begin(v), std::end(v)), std::invalid_argument); + CHECK_THROWS_AS(json::parse(std::begin(v), std::end(v)), json::parse_error); } SECTION("case 10") { uint8_t v[] = {'\"', 0x7F, 0xED, 0x7F}; - CHECK_THROWS_AS(json::parse(std::begin(v), std::end(v)), std::invalid_argument); + CHECK_THROWS_AS(json::parse(std::begin(v), std::end(v)), json::parse_error); } SECTION("case 11") { uint8_t v[] = {'\"', 0x7F, 0xF0, 0x8F}; - CHECK_THROWS_AS(json::parse(std::begin(v), std::end(v)), std::invalid_argument); + CHECK_THROWS_AS(json::parse(std::begin(v), std::end(v)), json::parse_error); } SECTION("case 12") { uint8_t v[] = {'\"', 0x7F, 0xF0, 0xC0}; - CHECK_THROWS_AS(json::parse(std::begin(v), std::end(v)), std::invalid_argument); + CHECK_THROWS_AS(json::parse(std::begin(v), std::end(v)), json::parse_error); } SECTION("case 13") { uint8_t v[] = {'\"', 0x7F, 0xF3, 0x7F}; - CHECK_THROWS_AS(json::parse(std::begin(v), std::end(v)), std::invalid_argument); + CHECK_THROWS_AS(json::parse(std::begin(v), std::end(v)), json::parse_error); } SECTION("case 14") { uint8_t v[] = {'\"', 0x7F, 0xF3, 0xC0}; - CHECK_THROWS_AS(json::parse(std::begin(v), std::end(v)), std::invalid_argument); + CHECK_THROWS_AS(json::parse(std::begin(v), std::end(v)), json::parse_error); } SECTION("case 15") { uint8_t v[] = {'\"', 0x7F, 0xF4, 0x7F}; - CHECK_THROWS_AS(json::parse(std::begin(v), std::end(v)), std::invalid_argument); + CHECK_THROWS_AS(json::parse(std::begin(v), std::end(v)), json::parse_error); } } } diff --git a/test/src/unit-regression.cpp b/test/src/unit-regression.cpp index 7980371bc..9dea8083b 100644 --- a/test/src/unit-regression.cpp +++ b/test/src/unit-regression.cpp @@ -579,8 +579,9 @@ TEST_CASE("regression tests") // ss is not at EOF; this yielded an error before the fix // (threw basic_string::append). No, it should just throw // a parse error because of the EOF. - CHECK_THROWS_AS(j << ss, std::invalid_argument); - CHECK_THROWS_WITH(j << ss, "parse error - unexpected end of input"); + CHECK_THROWS_AS(j << ss, json::parse_error); + CHECK_THROWS_WITH(j << ss, + "[json.exception.parse_error.101] parse error at 1: parse error - unexpected end of input"); } SECTION("issue #389 - Integer-overflow (OSS-Fuzz issue 267)") @@ -778,7 +779,7 @@ TEST_CASE("regression tests") SECTION("issue #452 - Heap-buffer-overflow (OSS-Fuzz issue 585)") { std::vector vec = {'-', '0', '1', '2', '2', '7', '4'}; - CHECK_THROWS_AS(json::parse(vec), std::invalid_argument); + CHECK_THROWS_AS(json::parse(vec), json::parse_error); } SECTION("issue #454 - doubles are printed as integers") diff --git a/test/src/unit-testsuites.cpp b/test/src/unit-testsuites.cpp index e83d5b740..701348a80 100644 --- a/test/src/unit-testsuites.cpp +++ b/test/src/unit-testsuites.cpp @@ -79,7 +79,7 @@ TEST_CASE("compliance tests from json.org") CAPTURE(filename); json j; std::ifstream f(filename); - CHECK_THROWS_AS(j << f, std::invalid_argument); + CHECK_THROWS_AS(j << f, json::parse_error); } } @@ -757,7 +757,7 @@ TEST_CASE("nst's JSONTestSuite") CAPTURE(filename); std::ifstream f(filename); json j; - CHECK_THROWS_AS(j << f, std::invalid_argument); + CHECK_THROWS_AS(j << f, json::parse_error); } } @@ -810,7 +810,7 @@ TEST_CASE("nst's JSONTestSuite") CAPTURE(filename); std::ifstream f(filename); json j; - CHECK_THROWS_AS(j << f, std::invalid_argument); + CHECK_THROWS_AS(j << f, json::parse_error); } } } diff --git a/test/src/unit-unicode.cpp b/test/src/unit-unicode.cpp index c429b91cb..f7cf0ada3 100644 --- a/test/src/unit-unicode.cpp +++ b/test/src/unit-unicode.cpp @@ -38,6 +38,9 @@ TEST_CASE("Unicode", "[hide]") { SECTION("full enumeration of Unicode code points") { + // lexer to call to_unicode on + json::lexer dummy_lexer(reinterpret_cast(""), 0); + // create an escaped string from a code point const auto codepoint_to_unicode = [](std::size_t cp) { @@ -85,7 +88,7 @@ TEST_CASE("Unicode", "[hide]") // they are checked with codepoint_to_unicode. if (cp > 0x1f and cp != 0x22 and cp != 0x5c) { - unescaped_string = json::lexer::to_unicode(cp); + unescaped_string = dummy_lexer.to_unicode(cp); } } else @@ -97,7 +100,7 @@ TEST_CASE("Unicode", "[hide]") const auto codepoint2 = 0xdc00u + ((cp - 0x10000u) & 0x3ffu); escaped_string = codepoint_to_unicode(codepoint1); escaped_string += codepoint_to_unicode(codepoint2); - unescaped_string += json::lexer::to_unicode(codepoint1, codepoint2); + unescaped_string += dummy_lexer.to_unicode(codepoint1, codepoint2); } // all other code points are valid and must not yield parse errors @@ -170,7 +173,7 @@ TEST_CASE("Unicode", "[hide]") SECTION("error for incomplete/wrong BOM") { - CHECK_THROWS_AS(json::parse("\xef\xbb"), std::invalid_argument); - CHECK_THROWS_AS(json::parse("\xef\xbb\xbb"), std::invalid_argument); + CHECK_THROWS_AS(json::parse("\xef\xbb"), json::parse_error); + CHECK_THROWS_AS(json::parse("\xef\xbb\xbb"), json::parse_error); } } From 06815d274e6dc95e61411e01596d8f0cc8748e99 Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Thu, 2 Mar 2017 17:55:13 +0100 Subject: [PATCH 02/52] :hammer: added user-defined exceptions 104 and 105 These exceptions are thrown in case of parse errors in JSON patch documents. --- src/json.hpp | 21 +++--- src/json.hpp.re2c | 21 +++--- test/src/unit-json_patch.cpp | 120 +++++++++++++++++++++-------------- 3 files changed, 94 insertions(+), 68 deletions(-) diff --git a/src/json.hpp b/src/json.hpp index d4e87e5e4..6451d732d 100644 --- a/src/json.hpp +++ b/src/json.hpp @@ -1107,8 +1107,8 @@ class basic_json json.exception.[parse_error](@ref parse_error).101 | `"parse error at 2: unexpected end of input; expected string literal"` | This error indicates a syntax error while deserializing a JSON text. The error message describes that an unexpected token (character) was encountered, and the member @ref parse_error::byte indicates the error position. json.exception.[parse_error](@ref parse_error).102 | `"parse error at 14: missing or wrong low surrogate"` | JSON uses the `\uxxxx` format to describe Unicode characters. Code points above above 0xFFFF are split into two `\uxxxx` entries ("surrogate pairs"). This error indicates that the surrogate pair is incomplete or contains an invalid code point. json.exception.[parse_error](@ref parse_error).103 | `"parse error: code points above 0x10FFFF are invalid"` | Unicode supports code points up to 0x10FFFF. Code points above 0x10FFFF are invalid. - json.exception.[parse_error](@ref parse_error).104 | "parse error: JSON patch must be an array of objects" | [RFC 6902](https://tools.ietf.org/html/rfc6902) requires a JSON Patch document to be a JSON documentthat represents an array of objects. - json.exception.[parse_error](@ref parse_error).105 | "parse error: operation must have string member 'op'" | An operation of a JSON Patch document must contain Operation objects MUST have exactly one "op" member, whose value indicates the operation to perform. Its value MUST be one of "add", "remove", "replace", "move", "copy", or "test"; other values are errors. + json.exception.[parse_error](@ref parse_error).104 | `"parse error: JSON patch must be an array of objects"` | [RFC 6902](https://tools.ietf.org/html/rfc6902) requires a JSON Patch document to be a JSON document that represents an array of objects. + json.exception.[parse_error](@ref parse_error).105 | `"parse error: operation must have string member 'op'"` | An operation of a JSON Patch document must contain exactly one "op" member, whose value indicates the operation to perform. Its value must be one of "add", "remove", "replace", "move", "copy", or "test"; other values are errors. json.exception.[parse_error](@ref parse_error).106 | "parse error: array index must not begin with '0'" | An array index in a JSON Pointer ([RFC 6901](https://tools.ietf.org/html/rfc6901)) may be `0` or any number wihtout a leading `0`. json.exception.[parse_error](@ref parse_error).107 | "parse error: JSON pointer must be empty or begin with '/'" | A JSON Pointer must be a Unicode string containing a sequence of zero or more reference tokens, each prefixed by a `/` character. json.exception.[parse_error](@ref parse_error).108 | "parse error: escape character '~' must be followed with '0' or '1'" | In a JSON Pointer, only `~0` and `~1` are valid escape sequences. @@ -12713,6 +12713,8 @@ basic_json_parser_74: not found"` @throw invalid_argument if the JSON patch is malformed (e.g., mandatory attributes are missing); example: `"operation add must have member path"` + @throw parse_error.104 if the JSON patch does not consist of an array of + objects @complexity Linear in the size of the JSON value and the length of the JSON patch. As usually only a fraction of the JSON value is affected by @@ -12858,11 +12860,10 @@ basic_json_parser_74: } }; - // type check + // type check: top level value must be an array if (not json_patch.is_array()) { - // a JSON patch must be an array of objects - JSON_THROW(std::invalid_argument("JSON patch must be an array of objects")); + JSON_THROW(parse_error(104, 0, "JSON patch must be an array of objects")); } // iterate and apply the operations @@ -12882,23 +12883,23 @@ basic_json_parser_74: // check if desired value is present if (it == val.m_value.object->end()) { - JSON_THROW(std::invalid_argument(error_msg + " must have member '" + member + "'")); + JSON_THROW(parse_error(105, 0, error_msg + " must have member '" + member + "'")); } // check if result is of type string if (string_type and not it->second.is_string()) { - JSON_THROW(std::invalid_argument(error_msg + " must have string member '" + member + "'")); + JSON_THROW(parse_error(105, 0, error_msg + " must have string member '" + member + "'")); } // no error: return value return it->second; }; - // type check + // type check: every element of the array must be an object if (not val.is_object()) { - JSON_THROW(std::invalid_argument("JSON patch must be an array of objects")); + JSON_THROW(parse_error(104, 0, "JSON patch must be an array of objects")); } // collect mandatory members @@ -12981,7 +12982,7 @@ basic_json_parser_74: { // op must be "add", "remove", "replace", "move", "copy", or // "test" - JSON_THROW(std::invalid_argument("operation value '" + op + "' is invalid")); + JSON_THROW(parse_error(105, 0, "operation value '" + op + "' is invalid")); } } } diff --git a/src/json.hpp.re2c b/src/json.hpp.re2c index 1afc025a3..3ed26c53a 100644 --- a/src/json.hpp.re2c +++ b/src/json.hpp.re2c @@ -1107,8 +1107,8 @@ class basic_json json.exception.[parse_error](@ref parse_error).101 | `"parse error at 2: unexpected end of input; expected string literal"` | This error indicates a syntax error while deserializing a JSON text. The error message describes that an unexpected token (character) was encountered, and the member @ref parse_error::byte indicates the error position. json.exception.[parse_error](@ref parse_error).102 | `"parse error at 14: missing or wrong low surrogate"` | JSON uses the `\uxxxx` format to describe Unicode characters. Code points above above 0xFFFF are split into two `\uxxxx` entries ("surrogate pairs"). This error indicates that the surrogate pair is incomplete or contains an invalid code point. json.exception.[parse_error](@ref parse_error).103 | `"parse error: code points above 0x10FFFF are invalid"` | Unicode supports code points up to 0x10FFFF. Code points above 0x10FFFF are invalid. - json.exception.[parse_error](@ref parse_error).104 | "parse error: JSON patch must be an array of objects" | [RFC 6902](https://tools.ietf.org/html/rfc6902) requires a JSON Patch document to be a JSON documentthat represents an array of objects. - json.exception.[parse_error](@ref parse_error).105 | "parse error: operation must have string member 'op'" | An operation of a JSON Patch document must contain Operation objects MUST have exactly one "op" member, whose value indicates the operation to perform. Its value MUST be one of "add", "remove", "replace", "move", "copy", or "test"; other values are errors. + json.exception.[parse_error](@ref parse_error).104 | `"parse error: JSON patch must be an array of objects"` | [RFC 6902](https://tools.ietf.org/html/rfc6902) requires a JSON Patch document to be a JSON document that represents an array of objects. + json.exception.[parse_error](@ref parse_error).105 | `"parse error: operation must have string member 'op'"` | An operation of a JSON Patch document must contain exactly one "op" member, whose value indicates the operation to perform. Its value must be one of "add", "remove", "replace", "move", "copy", or "test"; other values are errors. json.exception.[parse_error](@ref parse_error).106 | "parse error: array index must not begin with '0'" | An array index in a JSON Pointer ([RFC 6901](https://tools.ietf.org/html/rfc6901)) may be `0` or any number wihtout a leading `0`. json.exception.[parse_error](@ref parse_error).107 | "parse error: JSON pointer must be empty or begin with '/'" | A JSON Pointer must be a Unicode string containing a sequence of zero or more reference tokens, each prefixed by a `/` character. json.exception.[parse_error](@ref parse_error).108 | "parse error: escape character '~' must be followed with '0' or '1'" | In a JSON Pointer, only `~0` and `~1` are valid escape sequences. @@ -11746,6 +11746,8 @@ class basic_json not found"` @throw invalid_argument if the JSON patch is malformed (e.g., mandatory attributes are missing); example: `"operation add must have member path"` + @throw parse_error.104 if the JSON patch does not consist of an array of + objects @complexity Linear in the size of the JSON value and the length of the JSON patch. As usually only a fraction of the JSON value is affected by @@ -11891,11 +11893,10 @@ class basic_json } }; - // type check + // type check: top level value must be an array if (not json_patch.is_array()) { - // a JSON patch must be an array of objects - JSON_THROW(std::invalid_argument("JSON patch must be an array of objects")); + JSON_THROW(parse_error(104, 0, "JSON patch must be an array of objects")); } // iterate and apply the operations @@ -11915,23 +11916,23 @@ class basic_json // check if desired value is present if (it == val.m_value.object->end()) { - JSON_THROW(std::invalid_argument(error_msg + " must have member '" + member + "'")); + JSON_THROW(parse_error(105, 0, error_msg + " must have member '" + member + "'")); } // check if result is of type string if (string_type and not it->second.is_string()) { - JSON_THROW(std::invalid_argument(error_msg + " must have string member '" + member + "'")); + JSON_THROW(parse_error(105, 0, error_msg + " must have string member '" + member + "'")); } // no error: return value return it->second; }; - // type check + // type check: every element of the array must be an object if (not val.is_object()) { - JSON_THROW(std::invalid_argument("JSON patch must be an array of objects")); + JSON_THROW(parse_error(104, 0, "JSON patch must be an array of objects")); } // collect mandatory members @@ -12014,7 +12015,7 @@ class basic_json { // op must be "add", "remove", "replace", "move", "copy", or // "test" - JSON_THROW(std::invalid_argument("operation value '" + op + "' is invalid")); + JSON_THROW(parse_error(105, 0, "operation value '" + op + "' is invalid")); } } } diff --git a/test/src/unit-json_patch.cpp b/test/src/unit-json_patch.cpp index 05ed7502f..4dd89b750 100644 --- a/test/src/unit-json_patch.cpp +++ b/test/src/unit-json_patch.cpp @@ -666,40 +666,45 @@ TEST_CASE("JSON patch") { json j; json patch = {{"op", "add"}, {"path", ""}, {"value", 1}}; - CHECK_THROWS_AS(j.patch(patch), std::invalid_argument); - CHECK_THROWS_WITH(j.patch(patch), "JSON patch must be an array of objects"); + CHECK_THROWS_AS(j.patch(patch), json::parse_error); + CHECK_THROWS_WITH(j.patch(patch), + "[json.exception.parse_error.104] parse error: JSON patch must be an array of objects"); } SECTION("not an array of objects") { json j; json patch = {"op", "add", "path", "", "value", 1}; - CHECK_THROWS_AS(j.patch(patch), std::invalid_argument); - CHECK_THROWS_WITH(j.patch(patch), "JSON patch must be an array of objects"); + CHECK_THROWS_AS(j.patch(patch), json::parse_error); + CHECK_THROWS_WITH(j.patch(patch), + "[json.exception.parse_error.104] parse error: JSON patch must be an array of objects"); } SECTION("missing 'op'") { json j; json patch = {{{"foo", "bar"}}}; - CHECK_THROWS_AS(j.patch(patch), std::invalid_argument); - CHECK_THROWS_WITH(j.patch(patch), "operation must have member 'op'"); + CHECK_THROWS_AS(j.patch(patch), json::parse_error); + CHECK_THROWS_WITH(j.patch(patch), + "[json.exception.parse_error.105] parse error: operation must have member 'op'"); } SECTION("non-string 'op'") { json j; json patch = {{{"op", 1}}}; - CHECK_THROWS_AS(j.patch(patch), std::invalid_argument); - CHECK_THROWS_WITH(j.patch(patch), "operation must have string member 'op'"); + CHECK_THROWS_AS(j.patch(patch), json::parse_error); + CHECK_THROWS_WITH(j.patch(patch), + "[json.exception.parse_error.105] parse error: operation must have string member 'op'"); } SECTION("invalid operation") { json j; json patch = {{{"op", "foo"}, {"path", ""}}}; - CHECK_THROWS_AS(j.patch(patch), std::invalid_argument); - CHECK_THROWS_WITH(j.patch(patch), "operation value 'foo' is invalid"); + CHECK_THROWS_AS(j.patch(patch), json::parse_error); + CHECK_THROWS_WITH(j.patch(patch), + "[json.exception.parse_error.105] parse error: operation value 'foo' is invalid"); } } @@ -709,24 +714,27 @@ TEST_CASE("JSON patch") { json j; json patch = {{{"op", "add"}}}; - CHECK_THROWS_AS(j.patch(patch), std::invalid_argument); - CHECK_THROWS_WITH(j.patch(patch), "operation 'add' must have member 'path'"); + CHECK_THROWS_AS(j.patch(patch), json::parse_error); + CHECK_THROWS_WITH(j.patch(patch), + "[json.exception.parse_error.105] parse error: operation 'add' must have member 'path'"); } SECTION("non-string 'path'") { json j; json patch = {{{"op", "add"}, {"path", 1}}}; - CHECK_THROWS_AS(j.patch(patch), std::invalid_argument); - CHECK_THROWS_WITH(j.patch(patch), "operation 'add' must have string member 'path'"); + CHECK_THROWS_AS(j.patch(patch), json::parse_error); + CHECK_THROWS_WITH(j.patch(patch), + "[json.exception.parse_error.105] parse error: operation 'add' must have string member 'path'"); } SECTION("missing 'value'") { json j; json patch = {{{"op", "add"}, {"path", ""}}}; - CHECK_THROWS_AS(j.patch(patch), std::invalid_argument); - CHECK_THROWS_WITH(j.patch(patch), "operation 'add' must have member 'value'"); + CHECK_THROWS_AS(j.patch(patch), json::parse_error); + CHECK_THROWS_WITH(j.patch(patch), + "[json.exception.parse_error.105] parse error: operation 'add' must have member 'value'"); } SECTION("invalid array index") @@ -744,16 +752,18 @@ TEST_CASE("JSON patch") { json j; json patch = {{{"op", "remove"}}}; - CHECK_THROWS_AS(j.patch(patch), std::invalid_argument); - CHECK_THROWS_WITH(j.patch(patch), "operation 'remove' must have member 'path'"); + CHECK_THROWS_AS(j.patch(patch), json::parse_error); + CHECK_THROWS_WITH(j.patch(patch), + "[json.exception.parse_error.105] parse error: operation 'remove' must have member 'path'"); } SECTION("non-string 'path'") { json j; json patch = {{{"op", "remove"}, {"path", 1}}}; - CHECK_THROWS_AS(j.patch(patch), std::invalid_argument); - CHECK_THROWS_WITH(j.patch(patch), "operation 'remove' must have string member 'path'"); + CHECK_THROWS_AS(j.patch(patch), json::parse_error); + CHECK_THROWS_WITH(j.patch(patch), + "[json.exception.parse_error.105] parse error: operation 'remove' must have string member 'path'"); } SECTION("nonexisting target location (array)") @@ -787,24 +797,27 @@ TEST_CASE("JSON patch") { json j; json patch = {{{"op", "replace"}}}; - CHECK_THROWS_AS(j.patch(patch), std::invalid_argument); - CHECK_THROWS_WITH(j.patch(patch), "operation 'replace' must have member 'path'"); + CHECK_THROWS_AS(j.patch(patch), json::parse_error); + CHECK_THROWS_WITH(j.patch(patch), + "[json.exception.parse_error.105] parse error: operation 'replace' must have member 'path'"); } SECTION("non-string 'path'") { json j; json patch = {{{"op", "replace"}, {"path", 1}}}; - CHECK_THROWS_AS(j.patch(patch), std::invalid_argument); - CHECK_THROWS_WITH(j.patch(patch), "operation 'replace' must have string member 'path'"); + CHECK_THROWS_AS(j.patch(patch), json::parse_error); + CHECK_THROWS_WITH(j.patch(patch), + "[json.exception.parse_error.105] parse error: operation 'replace' must have string member 'path'"); } SECTION("missing 'value'") { json j; json patch = {{{"op", "replace"}, {"path", ""}}}; - CHECK_THROWS_AS(j.patch(patch), std::invalid_argument); - CHECK_THROWS_WITH(j.patch(patch), "operation 'replace' must have member 'value'"); + CHECK_THROWS_AS(j.patch(patch), json::parse_error); + CHECK_THROWS_WITH(j.patch(patch), + "[json.exception.parse_error.105] parse error: operation 'replace' must have member 'value'"); } SECTION("nonexisting target location (array)") @@ -830,32 +843,36 @@ TEST_CASE("JSON patch") { json j; json patch = {{{"op", "move"}}}; - CHECK_THROWS_AS(j.patch(patch), std::invalid_argument); - CHECK_THROWS_WITH(j.patch(patch), "operation 'move' must have member 'path'"); + CHECK_THROWS_AS(j.patch(patch), json::parse_error); + CHECK_THROWS_WITH(j.patch(patch), + "[json.exception.parse_error.105] parse error: operation 'move' must have member 'path'"); } SECTION("non-string 'path'") { json j; json patch = {{{"op", "move"}, {"path", 1}}}; - CHECK_THROWS_AS(j.patch(patch), std::invalid_argument); - CHECK_THROWS_WITH(j.patch(patch), "operation 'move' must have string member 'path'"); + CHECK_THROWS_AS(j.patch(patch), json::parse_error); + CHECK_THROWS_WITH(j.patch(patch), + "[json.exception.parse_error.105] parse error: operation 'move' must have string member 'path'"); } SECTION("missing 'from'") { json j; json patch = {{{"op", "move"}, {"path", ""}}}; - CHECK_THROWS_AS(j.patch(patch), std::invalid_argument); - CHECK_THROWS_WITH(j.patch(patch), "operation 'move' must have member 'from'"); + CHECK_THROWS_AS(j.patch(patch), json::parse_error); + CHECK_THROWS_WITH(j.patch(patch), + "[json.exception.parse_error.105] parse error: operation 'move' must have member 'from'"); } SECTION("non-string 'from'") { json j; json patch = {{{"op", "move"}, {"path", ""}, {"from", 1}}}; - CHECK_THROWS_AS(j.patch(patch), std::invalid_argument); - CHECK_THROWS_WITH(j.patch(patch), "operation 'move' must have string member 'from'"); + CHECK_THROWS_AS(j.patch(patch), json::parse_error); + CHECK_THROWS_WITH(j.patch(patch), + "[json.exception.parse_error.105] parse error: operation 'move' must have string member 'from'"); } SECTION("nonexisting from location (array)") @@ -881,32 +898,36 @@ TEST_CASE("JSON patch") { json j; json patch = {{{"op", "copy"}}}; - CHECK_THROWS_AS(j.patch(patch), std::invalid_argument); - CHECK_THROWS_WITH(j.patch(patch), "operation 'copy' must have member 'path'"); + CHECK_THROWS_AS(j.patch(patch), json::parse_error); + CHECK_THROWS_WITH(j.patch(patch), + "[json.exception.parse_error.105] parse error: operation 'copy' must have member 'path'"); } SECTION("non-string 'path'") { json j; json patch = {{{"op", "copy"}, {"path", 1}}}; - CHECK_THROWS_AS(j.patch(patch), std::invalid_argument); - CHECK_THROWS_WITH(j.patch(patch), "operation 'copy' must have string member 'path'"); + CHECK_THROWS_AS(j.patch(patch), json::parse_error); + CHECK_THROWS_WITH(j.patch(patch), + "[json.exception.parse_error.105] parse error: operation 'copy' must have string member 'path'"); } SECTION("missing 'from'") { json j; json patch = {{{"op", "copy"}, {"path", ""}}}; - CHECK_THROWS_AS(j.patch(patch), std::invalid_argument); - CHECK_THROWS_WITH(j.patch(patch), "operation 'copy' must have member 'from'"); + CHECK_THROWS_AS(j.patch(patch), json::parse_error); + CHECK_THROWS_WITH(j.patch(patch), + "[json.exception.parse_error.105] parse error: operation 'copy' must have member 'from'"); } SECTION("non-string 'from'") { json j; json patch = {{{"op", "copy"}, {"path", ""}, {"from", 1}}}; - CHECK_THROWS_AS(j.patch(patch), std::invalid_argument); - CHECK_THROWS_WITH(j.patch(patch), "operation 'copy' must have string member 'from'"); + CHECK_THROWS_AS(j.patch(patch), json::parse_error); + CHECK_THROWS_WITH(j.patch(patch), + "[json.exception.parse_error.105] parse error: operation 'copy' must have string member 'from'"); } SECTION("nonexisting from location (array)") @@ -932,24 +953,27 @@ TEST_CASE("JSON patch") { json j; json patch = {{{"op", "test"}}}; - CHECK_THROWS_AS(j.patch(patch), std::invalid_argument); - CHECK_THROWS_WITH(j.patch(patch), "operation 'test' must have member 'path'"); + CHECK_THROWS_AS(j.patch(patch), json::parse_error); + CHECK_THROWS_WITH(j.patch(patch), + "[json.exception.parse_error.105] parse error: operation 'test' must have member 'path'"); } SECTION("non-string 'path'") { json j; json patch = {{{"op", "test"}, {"path", 1}}}; - CHECK_THROWS_AS(j.patch(patch), std::invalid_argument); - CHECK_THROWS_WITH(j.patch(patch), "operation 'test' must have string member 'path'"); + CHECK_THROWS_AS(j.patch(patch), json::parse_error); + CHECK_THROWS_WITH(j.patch(patch), + "[json.exception.parse_error.105] parse error: operation 'test' must have string member 'path'"); } SECTION("missing 'value'") { json j; json patch = {{{"op", "test"}, {"path", ""}}}; - CHECK_THROWS_AS(j.patch(patch), std::invalid_argument); - CHECK_THROWS_WITH(j.patch(patch), "operation 'test' must have member 'value'"); + CHECK_THROWS_AS(j.patch(patch), json::parse_error); + CHECK_THROWS_WITH(j.patch(patch), + "[json.exception.parse_error.105] parse error: operation 'test' must have member 'value'"); } } } From b86d2148ef09f3ec005f39b024f8fff50cedf196 Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Fri, 3 Mar 2017 11:56:58 +0100 Subject: [PATCH 03/52] :hammer: added user-defined exceptions 106-108 These exceptions occur when JSON pointers are malformed. --- src/json.hpp | 30 +++++++++++------------ src/json.hpp.re2c | 30 +++++++++++------------ test/src/unit-json_patch.cpp | 44 +++++++++++++++++----------------- test/src/unit-json_pointer.cpp | 35 ++++++++++++++++----------- 4 files changed, 73 insertions(+), 66 deletions(-) diff --git a/src/json.hpp b/src/json.hpp index 6451d732d..e2380dbda 100644 --- a/src/json.hpp +++ b/src/json.hpp @@ -1109,9 +1109,9 @@ class basic_json json.exception.[parse_error](@ref parse_error).103 | `"parse error: code points above 0x10FFFF are invalid"` | Unicode supports code points up to 0x10FFFF. Code points above 0x10FFFF are invalid. json.exception.[parse_error](@ref parse_error).104 | `"parse error: JSON patch must be an array of objects"` | [RFC 6902](https://tools.ietf.org/html/rfc6902) requires a JSON Patch document to be a JSON document that represents an array of objects. json.exception.[parse_error](@ref parse_error).105 | `"parse error: operation must have string member 'op'"` | An operation of a JSON Patch document must contain exactly one "op" member, whose value indicates the operation to perform. Its value must be one of "add", "remove", "replace", "move", "copy", or "test"; other values are errors. - json.exception.[parse_error](@ref parse_error).106 | "parse error: array index must not begin with '0'" | An array index in a JSON Pointer ([RFC 6901](https://tools.ietf.org/html/rfc6901)) may be `0` or any number wihtout a leading `0`. - json.exception.[parse_error](@ref parse_error).107 | "parse error: JSON pointer must be empty or begin with '/'" | A JSON Pointer must be a Unicode string containing a sequence of zero or more reference tokens, each prefixed by a `/` character. - json.exception.[parse_error](@ref parse_error).108 | "parse error: escape character '~' must be followed with '0' or '1'" | In a JSON Pointer, only `~0` and `~1` are valid escape sequences. + json.exception.[parse_error](@ref parse_error).106 | `"parse error: array index '01' must not begin with '0'"` | An array index in a JSON Pointer ([RFC 6901](https://tools.ietf.org/html/rfc6901)) may be `0` or any number wihtout a leading `0`. + json.exception.[parse_error](@ref parse_error).107 | `"parse error: JSON pointer must be empty or begin with '/' - was: 'foo'"` | A JSON Pointer must be a Unicode string containing a sequence of zero or more reference tokens, each prefixed by a `/` character. + json.exception.[parse_error](@ref parse_error).108 | `"parse error: escape character '~' must be followed with '0' or '1'"` | In a JSON Pointer, only `~0` and `~1` are valid escape sequences. json.exception.[parse_error](@ref parse_error).109 | "parse error: array index 'one' is not a number" | A JSON Pointer array index must be a number. json.exception.[invalid_iterator](@ref invalid_iterator).201 | "iterators are not compatible" | The iterators passed to constructor @ref basic_json(InputIT first, InputIT last) are not compatible, meaning they do not belong to the same container. Therefore, the range (@a first, @a last) is invalid. json.exception.[invalid_iterator](@ref invalid_iterator).202 | "iterator does not fit current value" | In an erase or insert function, the passed iterator @a pos does not belong to the JSON value for which the function was called. It hence does not define a valid position for the deletion/insertion. @@ -11918,12 +11918,12 @@ basic_json_parser_74: empty string is assumed which references the whole JSON value - @throw std::domain_error if reference token is nonempty and does not + @throw parse_error.107 if reference token is nonempty and does not begin with a slash (`/`); example: `"JSON pointer must be empty or - begin with /"` - @throw std::domain_error if a tilde (`~`) is not followed by `0` - (representing `~`) or `1` (representing `/`); example: `"escape error: - ~ must be followed with 0 or 1"` + begin with / - was: 'foo'"` + @throw parse_error.108 if a tilde (`~`) is not followed by `0` + (representing `~`) or `1` (representing `/`); example: `"escape + character '~' must be followed with '0' or '1'"` @liveexample{The example shows the construction several valid JSON pointers as well as the exceptional behavior.,json_pointer} @@ -12074,7 +12074,7 @@ basic_json_parser_74: @complexity Linear in the length of the JSON pointer. @throw std::out_of_range if the JSON pointer can not be resolved - @throw std::domain_error if an array index begins with '0' + @throw parse_error.106 if an array index begins with '0' @throw std::invalid_argument if an array index was not a number */ reference get_unchecked(pointer ptr) const @@ -12118,7 +12118,7 @@ basic_json_parser_74: // error condition (cf. RFC 6901, Sect. 4) if (reference_token.size() > 1 and reference_token[0] == '0') { - JSON_THROW(std::domain_error("array index must not begin with '0'")); + JSON_THROW(parse_error(106, 0, "array index '" + reference_token + "' must not begin with '0'")); } if (reference_token == "-") @@ -12170,7 +12170,7 @@ basic_json_parser_74: // error condition (cf. RFC 6901, Sect. 4) if (reference_token.size() > 1 and reference_token[0] == '0') { - JSON_THROW(std::domain_error("array index must not begin with '0'")); + JSON_THROW(parse_error(106, 0, "array index '" + reference_token + "' must not begin with '0'")); } // note: at performs range check @@ -12222,7 +12222,7 @@ basic_json_parser_74: // error condition (cf. RFC 6901, Sect. 4) if (reference_token.size() > 1 and reference_token[0] == '0') { - JSON_THROW(std::domain_error("array index must not begin with '0'")); + JSON_THROW(parse_error(106, 0, "array index '" + reference_token + "' must not begin with '0'")); } // use unchecked array access @@ -12266,7 +12266,7 @@ basic_json_parser_74: // error condition (cf. RFC 6901, Sect. 4) if (reference_token.size() > 1 and reference_token[0] == '0') { - JSON_THROW(std::domain_error("array index must not begin with '0'")); + JSON_THROW(parse_error(106, 0, "array index '" + reference_token + "' must not begin with '0'")); } // note: at performs range check @@ -12298,7 +12298,7 @@ basic_json_parser_74: // check if nonempty reference string begins with slash if (reference_string[0] != '/') { - JSON_THROW(std::domain_error("JSON pointer must be empty or begin with '/'")); + JSON_THROW(parse_error(107, 1, "JSON pointer must be empty or begin with '/' - was: '" + reference_string + "'")); } // extract the reference tokens: @@ -12333,7 +12333,7 @@ basic_json_parser_74: (reference_token[pos + 1] != '0' and reference_token[pos + 1] != '1')) { - JSON_THROW(std::domain_error("escape error: '~' must be followed with '0' or '1'")); + JSON_THROW(parse_error(108, 0, "escape character '~' must be followed with '0' or '1'")); } } diff --git a/src/json.hpp.re2c b/src/json.hpp.re2c index 3ed26c53a..d1727df58 100644 --- a/src/json.hpp.re2c +++ b/src/json.hpp.re2c @@ -1109,9 +1109,9 @@ class basic_json json.exception.[parse_error](@ref parse_error).103 | `"parse error: code points above 0x10FFFF are invalid"` | Unicode supports code points up to 0x10FFFF. Code points above 0x10FFFF are invalid. json.exception.[parse_error](@ref parse_error).104 | `"parse error: JSON patch must be an array of objects"` | [RFC 6902](https://tools.ietf.org/html/rfc6902) requires a JSON Patch document to be a JSON document that represents an array of objects. json.exception.[parse_error](@ref parse_error).105 | `"parse error: operation must have string member 'op'"` | An operation of a JSON Patch document must contain exactly one "op" member, whose value indicates the operation to perform. Its value must be one of "add", "remove", "replace", "move", "copy", or "test"; other values are errors. - json.exception.[parse_error](@ref parse_error).106 | "parse error: array index must not begin with '0'" | An array index in a JSON Pointer ([RFC 6901](https://tools.ietf.org/html/rfc6901)) may be `0` or any number wihtout a leading `0`. - json.exception.[parse_error](@ref parse_error).107 | "parse error: JSON pointer must be empty or begin with '/'" | A JSON Pointer must be a Unicode string containing a sequence of zero or more reference tokens, each prefixed by a `/` character. - json.exception.[parse_error](@ref parse_error).108 | "parse error: escape character '~' must be followed with '0' or '1'" | In a JSON Pointer, only `~0` and `~1` are valid escape sequences. + json.exception.[parse_error](@ref parse_error).106 | `"parse error: array index '01' must not begin with '0'"` | An array index in a JSON Pointer ([RFC 6901](https://tools.ietf.org/html/rfc6901)) may be `0` or any number wihtout a leading `0`. + json.exception.[parse_error](@ref parse_error).107 | `"parse error: JSON pointer must be empty or begin with '/' - was: 'foo'"` | A JSON Pointer must be a Unicode string containing a sequence of zero or more reference tokens, each prefixed by a `/` character. + json.exception.[parse_error](@ref parse_error).108 | `"parse error: escape character '~' must be followed with '0' or '1'"` | In a JSON Pointer, only `~0` and `~1` are valid escape sequences. json.exception.[parse_error](@ref parse_error).109 | "parse error: array index 'one' is not a number" | A JSON Pointer array index must be a number. json.exception.[invalid_iterator](@ref invalid_iterator).201 | "iterators are not compatible" | The iterators passed to constructor @ref basic_json(InputIT first, InputIT last) are not compatible, meaning they do not belong to the same container. Therefore, the range (@a first, @a last) is invalid. json.exception.[invalid_iterator](@ref invalid_iterator).202 | "iterator does not fit current value" | In an erase or insert function, the passed iterator @a pos does not belong to the JSON value for which the function was called. It hence does not define a valid position for the deletion/insertion. @@ -10951,12 +10951,12 @@ class basic_json empty string is assumed which references the whole JSON value - @throw std::domain_error if reference token is nonempty and does not + @throw parse_error.107 if reference token is nonempty and does not begin with a slash (`/`); example: `"JSON pointer must be empty or - begin with /"` - @throw std::domain_error if a tilde (`~`) is not followed by `0` - (representing `~`) or `1` (representing `/`); example: `"escape error: - ~ must be followed with 0 or 1"` + begin with / - was: 'foo'"` + @throw parse_error.108 if a tilde (`~`) is not followed by `0` + (representing `~`) or `1` (representing `/`); example: `"escape + character '~' must be followed with '0' or '1'"` @liveexample{The example shows the construction several valid JSON pointers as well as the exceptional behavior.,json_pointer} @@ -11107,7 +11107,7 @@ class basic_json @complexity Linear in the length of the JSON pointer. @throw std::out_of_range if the JSON pointer can not be resolved - @throw std::domain_error if an array index begins with '0' + @throw parse_error.106 if an array index begins with '0' @throw std::invalid_argument if an array index was not a number */ reference get_unchecked(pointer ptr) const @@ -11151,7 +11151,7 @@ class basic_json // error condition (cf. RFC 6901, Sect. 4) if (reference_token.size() > 1 and reference_token[0] == '0') { - JSON_THROW(std::domain_error("array index must not begin with '0'")); + JSON_THROW(parse_error(106, 0, "array index '" + reference_token + "' must not begin with '0'")); } if (reference_token == "-") @@ -11203,7 +11203,7 @@ class basic_json // error condition (cf. RFC 6901, Sect. 4) if (reference_token.size() > 1 and reference_token[0] == '0') { - JSON_THROW(std::domain_error("array index must not begin with '0'")); + JSON_THROW(parse_error(106, 0, "array index '" + reference_token + "' must not begin with '0'")); } // note: at performs range check @@ -11255,7 +11255,7 @@ class basic_json // error condition (cf. RFC 6901, Sect. 4) if (reference_token.size() > 1 and reference_token[0] == '0') { - JSON_THROW(std::domain_error("array index must not begin with '0'")); + JSON_THROW(parse_error(106, 0, "array index '" + reference_token + "' must not begin with '0'")); } // use unchecked array access @@ -11299,7 +11299,7 @@ class basic_json // error condition (cf. RFC 6901, Sect. 4) if (reference_token.size() > 1 and reference_token[0] == '0') { - JSON_THROW(std::domain_error("array index must not begin with '0'")); + JSON_THROW(parse_error(106, 0, "array index '" + reference_token + "' must not begin with '0'")); } // note: at performs range check @@ -11331,7 +11331,7 @@ class basic_json // check if nonempty reference string begins with slash if (reference_string[0] != '/') { - JSON_THROW(std::domain_error("JSON pointer must be empty or begin with '/'")); + JSON_THROW(parse_error(107, 1, "JSON pointer must be empty or begin with '/' - was: '" + reference_string + "'")); } // extract the reference tokens: @@ -11366,7 +11366,7 @@ class basic_json (reference_token[pos + 1] != '0' and reference_token[pos + 1] != '1')) { - JSON_THROW(std::domain_error("escape error: '~' must be followed with '0' or '1'")); + JSON_THROW(parse_error(108, 0, "escape character '~' must be followed with '0' or '1'")); } } diff --git a/test/src/unit-json_patch.cpp b/test/src/unit-json_patch.cpp index 4dd89b750..1d905bb5e 100644 --- a/test/src/unit-json_patch.cpp +++ b/test/src/unit-json_patch.cpp @@ -686,7 +686,7 @@ TEST_CASE("JSON patch") json patch = {{{"foo", "bar"}}}; CHECK_THROWS_AS(j.patch(patch), json::parse_error); CHECK_THROWS_WITH(j.patch(patch), - "[json.exception.parse_error.105] parse error: operation must have member 'op'"); + "[json.exception.parse_error.105] parse error: operation must have member 'op'"); } SECTION("non-string 'op'") @@ -695,7 +695,7 @@ TEST_CASE("JSON patch") json patch = {{{"op", 1}}}; CHECK_THROWS_AS(j.patch(patch), json::parse_error); CHECK_THROWS_WITH(j.patch(patch), - "[json.exception.parse_error.105] parse error: operation must have string member 'op'"); + "[json.exception.parse_error.105] parse error: operation must have string member 'op'"); } SECTION("invalid operation") @@ -704,7 +704,7 @@ TEST_CASE("JSON patch") json patch = {{{"op", "foo"}, {"path", ""}}}; CHECK_THROWS_AS(j.patch(patch), json::parse_error); CHECK_THROWS_WITH(j.patch(patch), - "[json.exception.parse_error.105] parse error: operation value 'foo' is invalid"); + "[json.exception.parse_error.105] parse error: operation value 'foo' is invalid"); } } @@ -716,7 +716,7 @@ TEST_CASE("JSON patch") json patch = {{{"op", "add"}}}; CHECK_THROWS_AS(j.patch(patch), json::parse_error); CHECK_THROWS_WITH(j.patch(patch), - "[json.exception.parse_error.105] parse error: operation 'add' must have member 'path'"); + "[json.exception.parse_error.105] parse error: operation 'add' must have member 'path'"); } SECTION("non-string 'path'") @@ -725,7 +725,7 @@ TEST_CASE("JSON patch") json patch = {{{"op", "add"}, {"path", 1}}}; CHECK_THROWS_AS(j.patch(patch), json::parse_error); CHECK_THROWS_WITH(j.patch(patch), - "[json.exception.parse_error.105] parse error: operation 'add' must have string member 'path'"); + "[json.exception.parse_error.105] parse error: operation 'add' must have string member 'path'"); } SECTION("missing 'value'") @@ -734,7 +734,7 @@ TEST_CASE("JSON patch") json patch = {{{"op", "add"}, {"path", ""}}}; CHECK_THROWS_AS(j.patch(patch), json::parse_error); CHECK_THROWS_WITH(j.patch(patch), - "[json.exception.parse_error.105] parse error: operation 'add' must have member 'value'"); + "[json.exception.parse_error.105] parse error: operation 'add' must have member 'value'"); } SECTION("invalid array index") @@ -754,7 +754,7 @@ TEST_CASE("JSON patch") json patch = {{{"op", "remove"}}}; CHECK_THROWS_AS(j.patch(patch), json::parse_error); CHECK_THROWS_WITH(j.patch(patch), - "[json.exception.parse_error.105] parse error: operation 'remove' must have member 'path'"); + "[json.exception.parse_error.105] parse error: operation 'remove' must have member 'path'"); } SECTION("non-string 'path'") @@ -763,7 +763,7 @@ TEST_CASE("JSON patch") json patch = {{{"op", "remove"}, {"path", 1}}}; CHECK_THROWS_AS(j.patch(patch), json::parse_error); CHECK_THROWS_WITH(j.patch(patch), - "[json.exception.parse_error.105] parse error: operation 'remove' must have string member 'path'"); + "[json.exception.parse_error.105] parse error: operation 'remove' must have string member 'path'"); } SECTION("nonexisting target location (array)") @@ -799,7 +799,7 @@ TEST_CASE("JSON patch") json patch = {{{"op", "replace"}}}; CHECK_THROWS_AS(j.patch(patch), json::parse_error); CHECK_THROWS_WITH(j.patch(patch), - "[json.exception.parse_error.105] parse error: operation 'replace' must have member 'path'"); + "[json.exception.parse_error.105] parse error: operation 'replace' must have member 'path'"); } SECTION("non-string 'path'") @@ -808,7 +808,7 @@ TEST_CASE("JSON patch") json patch = {{{"op", "replace"}, {"path", 1}}}; CHECK_THROWS_AS(j.patch(patch), json::parse_error); CHECK_THROWS_WITH(j.patch(patch), - "[json.exception.parse_error.105] parse error: operation 'replace' must have string member 'path'"); + "[json.exception.parse_error.105] parse error: operation 'replace' must have string member 'path'"); } SECTION("missing 'value'") @@ -817,7 +817,7 @@ TEST_CASE("JSON patch") json patch = {{{"op", "replace"}, {"path", ""}}}; CHECK_THROWS_AS(j.patch(patch), json::parse_error); CHECK_THROWS_WITH(j.patch(patch), - "[json.exception.parse_error.105] parse error: operation 'replace' must have member 'value'"); + "[json.exception.parse_error.105] parse error: operation 'replace' must have member 'value'"); } SECTION("nonexisting target location (array)") @@ -845,7 +845,7 @@ TEST_CASE("JSON patch") json patch = {{{"op", "move"}}}; CHECK_THROWS_AS(j.patch(patch), json::parse_error); CHECK_THROWS_WITH(j.patch(patch), - "[json.exception.parse_error.105] parse error: operation 'move' must have member 'path'"); + "[json.exception.parse_error.105] parse error: operation 'move' must have member 'path'"); } SECTION("non-string 'path'") @@ -854,7 +854,7 @@ TEST_CASE("JSON patch") json patch = {{{"op", "move"}, {"path", 1}}}; CHECK_THROWS_AS(j.patch(patch), json::parse_error); CHECK_THROWS_WITH(j.patch(patch), - "[json.exception.parse_error.105] parse error: operation 'move' must have string member 'path'"); + "[json.exception.parse_error.105] parse error: operation 'move' must have string member 'path'"); } SECTION("missing 'from'") @@ -863,7 +863,7 @@ TEST_CASE("JSON patch") json patch = {{{"op", "move"}, {"path", ""}}}; CHECK_THROWS_AS(j.patch(patch), json::parse_error); CHECK_THROWS_WITH(j.patch(patch), - "[json.exception.parse_error.105] parse error: operation 'move' must have member 'from'"); + "[json.exception.parse_error.105] parse error: operation 'move' must have member 'from'"); } SECTION("non-string 'from'") @@ -872,7 +872,7 @@ TEST_CASE("JSON patch") json patch = {{{"op", "move"}, {"path", ""}, {"from", 1}}}; CHECK_THROWS_AS(j.patch(patch), json::parse_error); CHECK_THROWS_WITH(j.patch(patch), - "[json.exception.parse_error.105] parse error: operation 'move' must have string member 'from'"); + "[json.exception.parse_error.105] parse error: operation 'move' must have string member 'from'"); } SECTION("nonexisting from location (array)") @@ -900,7 +900,7 @@ TEST_CASE("JSON patch") json patch = {{{"op", "copy"}}}; CHECK_THROWS_AS(j.patch(patch), json::parse_error); CHECK_THROWS_WITH(j.patch(patch), - "[json.exception.parse_error.105] parse error: operation 'copy' must have member 'path'"); + "[json.exception.parse_error.105] parse error: operation 'copy' must have member 'path'"); } SECTION("non-string 'path'") @@ -909,7 +909,7 @@ TEST_CASE("JSON patch") json patch = {{{"op", "copy"}, {"path", 1}}}; CHECK_THROWS_AS(j.patch(patch), json::parse_error); CHECK_THROWS_WITH(j.patch(patch), - "[json.exception.parse_error.105] parse error: operation 'copy' must have string member 'path'"); + "[json.exception.parse_error.105] parse error: operation 'copy' must have string member 'path'"); } SECTION("missing 'from'") @@ -918,7 +918,7 @@ TEST_CASE("JSON patch") json patch = {{{"op", "copy"}, {"path", ""}}}; CHECK_THROWS_AS(j.patch(patch), json::parse_error); CHECK_THROWS_WITH(j.patch(patch), - "[json.exception.parse_error.105] parse error: operation 'copy' must have member 'from'"); + "[json.exception.parse_error.105] parse error: operation 'copy' must have member 'from'"); } SECTION("non-string 'from'") @@ -927,7 +927,7 @@ TEST_CASE("JSON patch") json patch = {{{"op", "copy"}, {"path", ""}, {"from", 1}}}; CHECK_THROWS_AS(j.patch(patch), json::parse_error); CHECK_THROWS_WITH(j.patch(patch), - "[json.exception.parse_error.105] parse error: operation 'copy' must have string member 'from'"); + "[json.exception.parse_error.105] parse error: operation 'copy' must have string member 'from'"); } SECTION("nonexisting from location (array)") @@ -955,7 +955,7 @@ TEST_CASE("JSON patch") json patch = {{{"op", "test"}}}; CHECK_THROWS_AS(j.patch(patch), json::parse_error); CHECK_THROWS_WITH(j.patch(patch), - "[json.exception.parse_error.105] parse error: operation 'test' must have member 'path'"); + "[json.exception.parse_error.105] parse error: operation 'test' must have member 'path'"); } SECTION("non-string 'path'") @@ -964,7 +964,7 @@ TEST_CASE("JSON patch") json patch = {{{"op", "test"}, {"path", 1}}}; CHECK_THROWS_AS(j.patch(patch), json::parse_error); CHECK_THROWS_WITH(j.patch(patch), - "[json.exception.parse_error.105] parse error: operation 'test' must have string member 'path'"); + "[json.exception.parse_error.105] parse error: operation 'test' must have string member 'path'"); } SECTION("missing 'value'") @@ -973,7 +973,7 @@ TEST_CASE("JSON patch") json patch = {{{"op", "test"}, {"path", ""}}}; CHECK_THROWS_AS(j.patch(patch), json::parse_error); CHECK_THROWS_WITH(j.patch(patch), - "[json.exception.parse_error.105] parse error: operation 'test' must have member 'value'"); + "[json.exception.parse_error.105] parse error: operation 'test' must have member 'value'"); } } } diff --git a/test/src/unit-json_pointer.cpp b/test/src/unit-json_pointer.cpp index 495d70668..917f8c093 100644 --- a/test/src/unit-json_pointer.cpp +++ b/test/src/unit-json_pointer.cpp @@ -36,14 +36,17 @@ TEST_CASE("JSON pointers") { SECTION("errors") { - CHECK_THROWS_AS(json::json_pointer("foo"), std::domain_error); - CHECK_THROWS_WITH(json::json_pointer("foo"), "JSON pointer must be empty or begin with '/'"); + CHECK_THROWS_AS(json::json_pointer("foo"), json::parse_error); + CHECK_THROWS_WITH(json::json_pointer("foo"), + "[json.exception.parse_error.107] parse error at 1: JSON pointer must be empty or begin with '/' - was: 'foo'"); - CHECK_THROWS_AS(json::json_pointer("/~~"), std::domain_error); - CHECK_THROWS_WITH(json::json_pointer("/~~"), "escape error: '~' must be followed with '0' or '1'"); + CHECK_THROWS_AS(json::json_pointer("/~~"), json::parse_error); + CHECK_THROWS_WITH(json::json_pointer("/~~"), + "[json.exception.parse_error.108] parse error: escape character '~' must be followed with '0' or '1'"); - CHECK_THROWS_AS(json::json_pointer("/~"), std::domain_error); - CHECK_THROWS_WITH(json::json_pointer("/~"), "escape error: '~' must be followed with '0' or '1'"); + CHECK_THROWS_AS(json::json_pointer("/~"), json::parse_error); + CHECK_THROWS_WITH(json::json_pointer("/~"), + "[json.exception.parse_error.108] parse error: escape character '~' must be followed with '0' or '1'"); json::json_pointer p; CHECK_THROWS_AS(p.top(), std::domain_error); @@ -245,14 +248,18 @@ TEST_CASE("JSON pointers") CHECK(j == json({1, 13, 3, 33, nullptr, 55})); // error with leading 0 - CHECK_THROWS_AS(j["/01"_json_pointer], std::domain_error); - CHECK_THROWS_WITH(j["/01"_json_pointer], "array index must not begin with '0'"); - CHECK_THROWS_AS(j_const["/01"_json_pointer], std::domain_error); - CHECK_THROWS_WITH(j_const["/01"_json_pointer], "array index must not begin with '0'"); - CHECK_THROWS_AS(j.at("/01"_json_pointer), std::domain_error); - CHECK_THROWS_WITH(j.at("/01"_json_pointer), "array index must not begin with '0'"); - CHECK_THROWS_AS(j_const.at("/01"_json_pointer), std::domain_error); - CHECK_THROWS_WITH(j_const.at("/01"_json_pointer), "array index must not begin with '0'"); + CHECK_THROWS_AS(j["/01"_json_pointer], json::parse_error); + CHECK_THROWS_WITH(j["/01"_json_pointer], + "[json.exception.parse_error.106] parse error: array index '01' must not begin with '0'"); + CHECK_THROWS_AS(j_const["/01"_json_pointer], json::parse_error); + CHECK_THROWS_WITH(j_const["/01"_json_pointer], + "[json.exception.parse_error.106] parse error: array index '01' must not begin with '0'"); + CHECK_THROWS_AS(j.at("/01"_json_pointer), json::parse_error); + CHECK_THROWS_WITH(j.at("/01"_json_pointer), + "[json.exception.parse_error.106] parse error: array index '01' must not begin with '0'"); + CHECK_THROWS_AS(j_const.at("/01"_json_pointer), json::parse_error); + CHECK_THROWS_WITH(j_const.at("/01"_json_pointer), + "[json.exception.parse_error.106] parse error: array index '01' must not begin with '0'"); // error with incorrect numbers CHECK_THROWS_AS(j["/one"_json_pointer] = 1, std::invalid_argument); From 776758d7a26e720731ed2cefcf33e87b8abba158 Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Fri, 3 Mar 2017 12:54:37 +0100 Subject: [PATCH 04/52] :hammer: added user-defined exception 109 This exception occurs when a JSON pointer contains an array index that can not be converted into a number. --- src/json.hpp | 61 ++++++++++++++++++++++++++-------- src/json.hpp.re2c | 61 ++++++++++++++++++++++++++-------- test/src/unit-json_pointer.cpp | 4 ++- 3 files changed, 99 insertions(+), 27 deletions(-) diff --git a/src/json.hpp b/src/json.hpp index e2380dbda..284a6400a 100644 --- a/src/json.hpp +++ b/src/json.hpp @@ -1104,14 +1104,14 @@ class basic_json name / id | example massage | description ------------------------------ | --------------- | ------------------------- - json.exception.[parse_error](@ref parse_error).101 | `"parse error at 2: unexpected end of input; expected string literal"` | This error indicates a syntax error while deserializing a JSON text. The error message describes that an unexpected token (character) was encountered, and the member @ref parse_error::byte indicates the error position. - json.exception.[parse_error](@ref parse_error).102 | `"parse error at 14: missing or wrong low surrogate"` | JSON uses the `\uxxxx` format to describe Unicode characters. Code points above above 0xFFFF are split into two `\uxxxx` entries ("surrogate pairs"). This error indicates that the surrogate pair is incomplete or contains an invalid code point. - json.exception.[parse_error](@ref parse_error).103 | `"parse error: code points above 0x10FFFF are invalid"` | Unicode supports code points up to 0x10FFFF. Code points above 0x10FFFF are invalid. - json.exception.[parse_error](@ref parse_error).104 | `"parse error: JSON patch must be an array of objects"` | [RFC 6902](https://tools.ietf.org/html/rfc6902) requires a JSON Patch document to be a JSON document that represents an array of objects. - json.exception.[parse_error](@ref parse_error).105 | `"parse error: operation must have string member 'op'"` | An operation of a JSON Patch document must contain exactly one "op" member, whose value indicates the operation to perform. Its value must be one of "add", "remove", "replace", "move", "copy", or "test"; other values are errors. - json.exception.[parse_error](@ref parse_error).106 | `"parse error: array index '01' must not begin with '0'"` | An array index in a JSON Pointer ([RFC 6901](https://tools.ietf.org/html/rfc6901)) may be `0` or any number wihtout a leading `0`. - json.exception.[parse_error](@ref parse_error).107 | `"parse error: JSON pointer must be empty or begin with '/' - was: 'foo'"` | A JSON Pointer must be a Unicode string containing a sequence of zero or more reference tokens, each prefixed by a `/` character. - json.exception.[parse_error](@ref parse_error).108 | `"parse error: escape character '~' must be followed with '0' or '1'"` | In a JSON Pointer, only `~0` and `~1` are valid escape sequences. + json.exception.[parse_error](@ref parse_error).101 | "parse error at 2: unexpected end of input; expected string literal" | This error indicates a syntax error while deserializing a JSON text. The error message describes that an unexpected token (character) was encountered, and the member @ref parse_error::byte indicates the error position. + json.exception.[parse_error](@ref parse_error).102 | "parse error at 14: missing or wrong low surrogate" | JSON uses the `\uxxxx` format to describe Unicode characters. Code points above above 0xFFFF are split into two `\uxxxx` entries ("surrogate pairs"). This error indicates that the surrogate pair is incomplete or contains an invalid code point. + json.exception.[parse_error](@ref parse_error).103 | "parse error: code points above 0x10FFFF are invalid" | Unicode supports code points up to 0x10FFFF. Code points above 0x10FFFF are invalid. + json.exception.[parse_error](@ref parse_error).104 | "parse error: JSON patch must be an array of objects" | [RFC 6902](https://tools.ietf.org/html/rfc6902) requires a JSON Patch document to be a JSON document that represents an array of objects. + json.exception.[parse_error](@ref parse_error).105 | "parse error: operation must have string member 'op'" | An operation of a JSON Patch document must contain exactly one "op" member, whose value indicates the operation to perform. Its value must be one of "add", "remove", "replace", "move", "copy", or "test"; other values are errors. + json.exception.[parse_error](@ref parse_error).106 | "parse error: array index '01' must not begin with '0'" | An array index in a JSON Pointer ([RFC 6901](https://tools.ietf.org/html/rfc6901)) may be `0` or any number wihtout a leading `0`. + json.exception.[parse_error](@ref parse_error).107 | "parse error: JSON pointer must be empty or begin with '/' - was: 'foo'" | A JSON Pointer must be a Unicode string containing a sequence of zero or more reference tokens, each prefixed by a `/` character. + json.exception.[parse_error](@ref parse_error).108 | "parse error: escape character '~' must be followed with '0' or '1'" | In a JSON Pointer, only `~0` and `~1` are valid escape sequences. json.exception.[parse_error](@ref parse_error).109 | "parse error: array index 'one' is not a number" | A JSON Pointer array index must be a number. json.exception.[invalid_iterator](@ref invalid_iterator).201 | "iterators are not compatible" | The iterators passed to constructor @ref basic_json(InputIT first, InputIT last) are not compatible, meaning they do not belong to the same container. Therefore, the range (@a first, @a last) is invalid. json.exception.[invalid_iterator](@ref invalid_iterator).202 | "iterator does not fit current value" | In an erase or insert function, the passed iterator @a pos does not belong to the JSON value for which the function was called. It hence does not define a valid position for the deletion/insertion. @@ -12037,7 +12037,14 @@ basic_json_parser_74: case value_t::array: { // create an entry in the array - result = &result->operator[](static_cast(std::stoi(reference_token))); + JSON_TRY + { + result = &result->operator[](static_cast(std::stoi(reference_token))); + } + JSON_CATCH(std::invalid_argument&) + { + JSON_THROW(parse_error(109, 0, "array index '" + reference_token + "' is not a number")); + } break; } @@ -12129,7 +12136,14 @@ basic_json_parser_74: else { // convert array index to number; unchecked access - ptr = &ptr->operator[](static_cast(std::stoi(reference_token))); + JSON_TRY + { + ptr = &ptr->operator[](static_cast(std::stoi(reference_token))); + } + JSON_CATCH(std::invalid_argument&) + { + JSON_THROW(parse_error(109, 0, "array index '" + reference_token + "' is not a number")); + } } break; } @@ -12174,7 +12188,14 @@ basic_json_parser_74: } // note: at performs range check - ptr = &ptr->at(static_cast(std::stoi(reference_token))); + JSON_TRY + { + ptr = &ptr->at(static_cast(std::stoi(reference_token))); + } + JSON_CATCH(std::invalid_argument&) + { + JSON_THROW(parse_error(109, 0, "array index '" + reference_token + "' is not a number")); + } break; } @@ -12226,7 +12247,14 @@ basic_json_parser_74: } // use unchecked array access - ptr = &ptr->operator[](static_cast(std::stoi(reference_token))); + JSON_TRY + { + ptr = &ptr->operator[](static_cast(std::stoi(reference_token))); + } + JSON_CATCH(std::invalid_argument&) + { + JSON_THROW(parse_error(109, 0, "array index '" + reference_token + "' is not a number")); + } break; } @@ -12270,7 +12298,14 @@ basic_json_parser_74: } // note: at performs range check - ptr = &ptr->at(static_cast(std::stoi(reference_token))); + JSON_TRY + { + ptr = &ptr->at(static_cast(std::stoi(reference_token))); + } + JSON_CATCH(std::invalid_argument&) + { + JSON_THROW(parse_error(109, 0, "array index '" + reference_token + "' is not a number")); + } break; } diff --git a/src/json.hpp.re2c b/src/json.hpp.re2c index d1727df58..552041361 100644 --- a/src/json.hpp.re2c +++ b/src/json.hpp.re2c @@ -1104,14 +1104,14 @@ class basic_json name / id | example massage | description ------------------------------ | --------------- | ------------------------- - json.exception.[parse_error](@ref parse_error).101 | `"parse error at 2: unexpected end of input; expected string literal"` | This error indicates a syntax error while deserializing a JSON text. The error message describes that an unexpected token (character) was encountered, and the member @ref parse_error::byte indicates the error position. - json.exception.[parse_error](@ref parse_error).102 | `"parse error at 14: missing or wrong low surrogate"` | JSON uses the `\uxxxx` format to describe Unicode characters. Code points above above 0xFFFF are split into two `\uxxxx` entries ("surrogate pairs"). This error indicates that the surrogate pair is incomplete or contains an invalid code point. - json.exception.[parse_error](@ref parse_error).103 | `"parse error: code points above 0x10FFFF are invalid"` | Unicode supports code points up to 0x10FFFF. Code points above 0x10FFFF are invalid. - json.exception.[parse_error](@ref parse_error).104 | `"parse error: JSON patch must be an array of objects"` | [RFC 6902](https://tools.ietf.org/html/rfc6902) requires a JSON Patch document to be a JSON document that represents an array of objects. - json.exception.[parse_error](@ref parse_error).105 | `"parse error: operation must have string member 'op'"` | An operation of a JSON Patch document must contain exactly one "op" member, whose value indicates the operation to perform. Its value must be one of "add", "remove", "replace", "move", "copy", or "test"; other values are errors. - json.exception.[parse_error](@ref parse_error).106 | `"parse error: array index '01' must not begin with '0'"` | An array index in a JSON Pointer ([RFC 6901](https://tools.ietf.org/html/rfc6901)) may be `0` or any number wihtout a leading `0`. - json.exception.[parse_error](@ref parse_error).107 | `"parse error: JSON pointer must be empty or begin with '/' - was: 'foo'"` | A JSON Pointer must be a Unicode string containing a sequence of zero or more reference tokens, each prefixed by a `/` character. - json.exception.[parse_error](@ref parse_error).108 | `"parse error: escape character '~' must be followed with '0' or '1'"` | In a JSON Pointer, only `~0` and `~1` are valid escape sequences. + json.exception.[parse_error](@ref parse_error).101 | "parse error at 2: unexpected end of input; expected string literal" | This error indicates a syntax error while deserializing a JSON text. The error message describes that an unexpected token (character) was encountered, and the member @ref parse_error::byte indicates the error position. + json.exception.[parse_error](@ref parse_error).102 | "parse error at 14: missing or wrong low surrogate" | JSON uses the `\uxxxx` format to describe Unicode characters. Code points above above 0xFFFF are split into two `\uxxxx` entries ("surrogate pairs"). This error indicates that the surrogate pair is incomplete or contains an invalid code point. + json.exception.[parse_error](@ref parse_error).103 | "parse error: code points above 0x10FFFF are invalid" | Unicode supports code points up to 0x10FFFF. Code points above 0x10FFFF are invalid. + json.exception.[parse_error](@ref parse_error).104 | "parse error: JSON patch must be an array of objects" | [RFC 6902](https://tools.ietf.org/html/rfc6902) requires a JSON Patch document to be a JSON document that represents an array of objects. + json.exception.[parse_error](@ref parse_error).105 | "parse error: operation must have string member 'op'" | An operation of a JSON Patch document must contain exactly one "op" member, whose value indicates the operation to perform. Its value must be one of "add", "remove", "replace", "move", "copy", or "test"; other values are errors. + json.exception.[parse_error](@ref parse_error).106 | "parse error: array index '01' must not begin with '0'" | An array index in a JSON Pointer ([RFC 6901](https://tools.ietf.org/html/rfc6901)) may be `0` or any number wihtout a leading `0`. + json.exception.[parse_error](@ref parse_error).107 | "parse error: JSON pointer must be empty or begin with '/' - was: 'foo'" | A JSON Pointer must be a Unicode string containing a sequence of zero or more reference tokens, each prefixed by a `/` character. + json.exception.[parse_error](@ref parse_error).108 | "parse error: escape character '~' must be followed with '0' or '1'" | In a JSON Pointer, only `~0` and `~1` are valid escape sequences. json.exception.[parse_error](@ref parse_error).109 | "parse error: array index 'one' is not a number" | A JSON Pointer array index must be a number. json.exception.[invalid_iterator](@ref invalid_iterator).201 | "iterators are not compatible" | The iterators passed to constructor @ref basic_json(InputIT first, InputIT last) are not compatible, meaning they do not belong to the same container. Therefore, the range (@a first, @a last) is invalid. json.exception.[invalid_iterator](@ref invalid_iterator).202 | "iterator does not fit current value" | In an erase or insert function, the passed iterator @a pos does not belong to the JSON value for which the function was called. It hence does not define a valid position for the deletion/insertion. @@ -11070,7 +11070,14 @@ class basic_json case value_t::array: { // create an entry in the array - result = &result->operator[](static_cast(std::stoi(reference_token))); + JSON_TRY + { + result = &result->operator[](static_cast(std::stoi(reference_token))); + } + JSON_CATCH(std::invalid_argument&) + { + JSON_THROW(parse_error(109, 0, "array index '" + reference_token + "' is not a number")); + } break; } @@ -11162,7 +11169,14 @@ class basic_json else { // convert array index to number; unchecked access - ptr = &ptr->operator[](static_cast(std::stoi(reference_token))); + JSON_TRY + { + ptr = &ptr->operator[](static_cast(std::stoi(reference_token))); + } + JSON_CATCH(std::invalid_argument&) + { + JSON_THROW(parse_error(109, 0, "array index '" + reference_token + "' is not a number")); + } } break; } @@ -11207,7 +11221,14 @@ class basic_json } // note: at performs range check - ptr = &ptr->at(static_cast(std::stoi(reference_token))); + JSON_TRY + { + ptr = &ptr->at(static_cast(std::stoi(reference_token))); + } + JSON_CATCH(std::invalid_argument&) + { + JSON_THROW(parse_error(109, 0, "array index '" + reference_token + "' is not a number")); + } break; } @@ -11259,7 +11280,14 @@ class basic_json } // use unchecked array access - ptr = &ptr->operator[](static_cast(std::stoi(reference_token))); + JSON_TRY + { + ptr = &ptr->operator[](static_cast(std::stoi(reference_token))); + } + JSON_CATCH(std::invalid_argument&) + { + JSON_THROW(parse_error(109, 0, "array index '" + reference_token + "' is not a number")); + } break; } @@ -11303,7 +11331,14 @@ class basic_json } // note: at performs range check - ptr = &ptr->at(static_cast(std::stoi(reference_token))); + JSON_TRY + { + ptr = &ptr->at(static_cast(std::stoi(reference_token))); + } + JSON_CATCH(std::invalid_argument&) + { + JSON_THROW(parse_error(109, 0, "array index '" + reference_token + "' is not a number")); + } break; } diff --git a/test/src/unit-json_pointer.cpp b/test/src/unit-json_pointer.cpp index 917f8c093..3c05a2783 100644 --- a/test/src/unit-json_pointer.cpp +++ b/test/src/unit-json_pointer.cpp @@ -262,7 +262,9 @@ TEST_CASE("JSON pointers") "[json.exception.parse_error.106] parse error: array index '01' must not begin with '0'"); // error with incorrect numbers - CHECK_THROWS_AS(j["/one"_json_pointer] = 1, std::invalid_argument); + CHECK_THROWS_AS(j["/one"_json_pointer] = 1, json::parse_error); + CHECK_THROWS_WITH(j["/one"_json_pointer] = 1, + "[json.exception.parse_error.109] parse error: array index 'one' is not a number"); // assign to "-" j["/-"_json_pointer] = 99; From 9381f6c4dae9d1a163e5a660646ce0363c886753 Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Fri, 3 Mar 2017 13:19:45 +0100 Subject: [PATCH 05/52] :hammer: added user-defined exceptions 201-202 Started implementing exceptions for invalid iterators. --- src/json.hpp | 38 ++++++++++++++++--------------- src/json.hpp.re2c | 38 ++++++++++++++++--------------- test/src/unit-constructor1.cpp | 32 +++++++++++++------------- test/src/unit-element_access1.cpp | 10 ++++---- test/src/unit-element_access2.cpp | 10 ++++---- test/src/unit-modifiers.cpp | 24 +++++++++---------- 6 files changed, 80 insertions(+), 72 deletions(-) diff --git a/src/json.hpp b/src/json.hpp index 284a6400a..21601fcdb 100644 --- a/src/json.hpp +++ b/src/json.hpp @@ -2415,8 +2415,9 @@ class basic_json @pre Iterators @a first and @a last must be initialized. **This precondition is enforced with an assertion.** - @throw std::domain_error if iterators are not compatible; that is, do not - belong to the same JSON value; example: `"iterators are not compatible"` + @throw invalid_iterator.201 if iterators are not compatible; that is, do + not belong to the same JSON value; example: `"iterators are not + compatible"` @throw std::out_of_range if iterators are for a primitive type (number, boolean, or string) where an out of range error can be detected easily; example: `"iterators out of range"` @@ -2442,7 +2443,7 @@ class basic_json // make sure iterator fits the current value if (first.m_object != last.m_object) { - JSON_THROW(std::domain_error("iterators are not compatible")); + JSON_THROW(invalid_iterator(201, "iterators are not compatible")); } // copy type from first iterator @@ -4398,8 +4399,9 @@ class basic_json @throw std::domain_error if called on a `null` value; example: `"cannot use erase() with null"` - @throw std::domain_error if called on an iterator which does not belong to - the current JSON value; example: `"iterator does not fit current value"` + @throw invalid_iterator.202 if called on an iterator which does not belong + to the current JSON value; example: `"iterator does not fit current + value"` @throw std::out_of_range if called on a primitive type with invalid iterator (i.e., any iterator which is not `begin()`); example: `"iterator out of range"` @@ -4431,7 +4433,7 @@ class basic_json // make sure iterator fits the current value if (this != pos.m_object) { - JSON_THROW(std::domain_error("iterator does not fit current value")); + JSON_THROW(invalid_iterator(202, "iterator does not fit current value")); } IteratorType result = end(); @@ -5655,8 +5657,8 @@ class basic_json @throw std::domain_error if called on JSON values other than arrays; example: `"cannot use insert() with string"` - @throw std::domain_error if @a pos is not an iterator of *this; example: - `"iterator does not fit current value"` + @throw invalid_iterator.202 if @a pos is not an iterator of *this; + example: `"iterator does not fit current value"` @complexity Constant plus linear in the distance between @a pos and end of the container. @@ -5673,7 +5675,7 @@ class basic_json // check if iterator pos fits to this JSON value if (pos.m_object != this) { - JSON_THROW(std::domain_error("iterator does not fit current value")); + JSON_THROW(invalid_iterator(202, "iterator does not fit current value")); } // insert to array and return iterator @@ -5708,8 +5710,8 @@ class basic_json @throw std::domain_error if called on JSON values other than arrays; example: `"cannot use insert() with string"` - @throw std::domain_error if @a pos is not an iterator of *this; example: - `"iterator does not fit current value"` + @throw invalid_iterator.202 if @a pos is not an iterator of *this; + example: `"iterator does not fit current value"` @complexity Linear in @a cnt plus linear in the distance between @a pos and end of the container. @@ -5726,7 +5728,7 @@ class basic_json // check if iterator pos fits to this JSON value if (pos.m_object != this) { - JSON_THROW(std::domain_error("iterator does not fit current value")); + JSON_THROW(invalid_iterator(202, "iterator does not fit current value")); } // insert to array and return iterator @@ -5750,8 +5752,8 @@ class basic_json @throw std::domain_error if called on JSON values other than arrays; example: `"cannot use insert() with string"` - @throw std::domain_error if @a pos is not an iterator of *this; example: - `"iterator does not fit current value"` + @throw invalid_iterator.202 if @a pos is not an iterator of *this; + example: `"iterator does not fit current value"` @throw std::domain_error if @a first and @a last do not belong to the same JSON value; example: `"iterators do not fit"` @throw std::domain_error if @a first or @a last are iterators into @@ -5779,7 +5781,7 @@ class basic_json // check if iterator pos fits to this JSON value if (pos.m_object != this) { - JSON_THROW(std::domain_error("iterator does not fit current value")); + JSON_THROW(invalid_iterator(202, "iterator does not fit current value")); } // check if range iterators belong to the same JSON object @@ -5813,8 +5815,8 @@ class basic_json @throw std::domain_error if called on JSON values other than arrays; example: `"cannot use insert() with string"` - @throw std::domain_error if @a pos is not an iterator of *this; example: - `"iterator does not fit current value"` + @throw invalid_iterator.202 if @a pos is not an iterator of *this; + example: `"iterator does not fit current value"` @return iterator pointing to the first element inserted, or @a pos if `ilist` is empty @@ -5837,7 +5839,7 @@ class basic_json // check if iterator pos fits to this JSON value if (pos.m_object != this) { - JSON_THROW(std::domain_error("iterator does not fit current value")); + JSON_THROW(invalid_iterator(202, "iterator does not fit current value")); } // insert to array and return iterator diff --git a/src/json.hpp.re2c b/src/json.hpp.re2c index 552041361..72b073f06 100644 --- a/src/json.hpp.re2c +++ b/src/json.hpp.re2c @@ -2415,8 +2415,9 @@ class basic_json @pre Iterators @a first and @a last must be initialized. **This precondition is enforced with an assertion.** - @throw std::domain_error if iterators are not compatible; that is, do not - belong to the same JSON value; example: `"iterators are not compatible"` + @throw invalid_iterator.201 if iterators are not compatible; that is, do + not belong to the same JSON value; example: `"iterators are not + compatible"` @throw std::out_of_range if iterators are for a primitive type (number, boolean, or string) where an out of range error can be detected easily; example: `"iterators out of range"` @@ -2442,7 +2443,7 @@ class basic_json // make sure iterator fits the current value if (first.m_object != last.m_object) { - JSON_THROW(std::domain_error("iterators are not compatible")); + JSON_THROW(invalid_iterator(201, "iterators are not compatible")); } // copy type from first iterator @@ -4398,8 +4399,9 @@ class basic_json @throw std::domain_error if called on a `null` value; example: `"cannot use erase() with null"` - @throw std::domain_error if called on an iterator which does not belong to - the current JSON value; example: `"iterator does not fit current value"` + @throw invalid_iterator.202 if called on an iterator which does not belong + to the current JSON value; example: `"iterator does not fit current + value"` @throw std::out_of_range if called on a primitive type with invalid iterator (i.e., any iterator which is not `begin()`); example: `"iterator out of range"` @@ -4431,7 +4433,7 @@ class basic_json // make sure iterator fits the current value if (this != pos.m_object) { - JSON_THROW(std::domain_error("iterator does not fit current value")); + JSON_THROW(invalid_iterator(202, "iterator does not fit current value")); } IteratorType result = end(); @@ -5655,8 +5657,8 @@ class basic_json @throw std::domain_error if called on JSON values other than arrays; example: `"cannot use insert() with string"` - @throw std::domain_error if @a pos is not an iterator of *this; example: - `"iterator does not fit current value"` + @throw invalid_iterator.202 if @a pos is not an iterator of *this; + example: `"iterator does not fit current value"` @complexity Constant plus linear in the distance between @a pos and end of the container. @@ -5673,7 +5675,7 @@ class basic_json // check if iterator pos fits to this JSON value if (pos.m_object != this) { - JSON_THROW(std::domain_error("iterator does not fit current value")); + JSON_THROW(invalid_iterator(202, "iterator does not fit current value")); } // insert to array and return iterator @@ -5708,8 +5710,8 @@ class basic_json @throw std::domain_error if called on JSON values other than arrays; example: `"cannot use insert() with string"` - @throw std::domain_error if @a pos is not an iterator of *this; example: - `"iterator does not fit current value"` + @throw invalid_iterator.202 if @a pos is not an iterator of *this; + example: `"iterator does not fit current value"` @complexity Linear in @a cnt plus linear in the distance between @a pos and end of the container. @@ -5726,7 +5728,7 @@ class basic_json // check if iterator pos fits to this JSON value if (pos.m_object != this) { - JSON_THROW(std::domain_error("iterator does not fit current value")); + JSON_THROW(invalid_iterator(202, "iterator does not fit current value")); } // insert to array and return iterator @@ -5750,8 +5752,8 @@ class basic_json @throw std::domain_error if called on JSON values other than arrays; example: `"cannot use insert() with string"` - @throw std::domain_error if @a pos is not an iterator of *this; example: - `"iterator does not fit current value"` + @throw invalid_iterator.202 if @a pos is not an iterator of *this; + example: `"iterator does not fit current value"` @throw std::domain_error if @a first and @a last do not belong to the same JSON value; example: `"iterators do not fit"` @throw std::domain_error if @a first or @a last are iterators into @@ -5779,7 +5781,7 @@ class basic_json // check if iterator pos fits to this JSON value if (pos.m_object != this) { - JSON_THROW(std::domain_error("iterator does not fit current value")); + JSON_THROW(invalid_iterator(202, "iterator does not fit current value")); } // check if range iterators belong to the same JSON object @@ -5813,8 +5815,8 @@ class basic_json @throw std::domain_error if called on JSON values other than arrays; example: `"cannot use insert() with string"` - @throw std::domain_error if @a pos is not an iterator of *this; example: - `"iterator does not fit current value"` + @throw invalid_iterator.202 if @a pos is not an iterator of *this; + example: `"iterator does not fit current value"` @return iterator pointing to the first element inserted, or @a pos if `ilist` is empty @@ -5837,7 +5839,7 @@ class basic_json // check if iterator pos fits to this JSON value if (pos.m_object != this) { - JSON_THROW(std::domain_error("iterator does not fit current value")); + JSON_THROW(invalid_iterator(202, "iterator does not fit current value")); } // insert to array and return iterator diff --git a/test/src/unit-constructor1.cpp b/test/src/unit-constructor1.cpp index 9363f0ba2..3179863e2 100644 --- a/test/src/unit-constructor1.cpp +++ b/test/src/unit-constructor1.cpp @@ -1017,18 +1017,18 @@ TEST_CASE("constructors") { json jobject = {{"a", "a"}, {"b", 1}, {"c", 17u}, {"d", false}, {"e", true}}; json jobject2 = {{"a", "a"}, {"b", 1}, {"c", 17u}}; - CHECK_THROWS_AS(json(jobject.begin(), jobject2.end()), std::domain_error); - CHECK_THROWS_AS(json(jobject2.begin(), jobject.end()), std::domain_error); - CHECK_THROWS_WITH(json(jobject.begin(), jobject2.end()), "iterators are not compatible"); - CHECK_THROWS_WITH(json(jobject2.begin(), jobject.end()), "iterators are not compatible"); + CHECK_THROWS_AS(json(jobject.begin(), jobject2.end()), json::invalid_iterator); + CHECK_THROWS_AS(json(jobject2.begin(), jobject.end()), json::invalid_iterator); + CHECK_THROWS_WITH(json(jobject.begin(), jobject2.end()), "[json.exception.invalid_iterator.201] iterators are not compatible"); + CHECK_THROWS_WITH(json(jobject2.begin(), jobject.end()), "[json.exception.invalid_iterator.201] iterators are not compatible"); } { json jobject = {{"a", "a"}, {"b", 1}, {"c", 17u}, {"d", false}, {"e", true}}; json jobject2 = {{"a", "a"}, {"b", 1}, {"c", 17u}}; - CHECK_THROWS_AS(json(jobject.cbegin(), jobject2.cend()), std::domain_error); - CHECK_THROWS_AS(json(jobject2.cbegin(), jobject.cend()), std::domain_error); - CHECK_THROWS_WITH(json(jobject.cbegin(), jobject2.cend()), "iterators are not compatible"); - CHECK_THROWS_WITH(json(jobject2.cbegin(), jobject.cend()), "iterators are not compatible"); + CHECK_THROWS_AS(json(jobject.cbegin(), jobject2.cend()), json::invalid_iterator); + CHECK_THROWS_AS(json(jobject2.cbegin(), jobject.cend()), json::invalid_iterator); + CHECK_THROWS_WITH(json(jobject.cbegin(), jobject2.cend()), "[json.exception.invalid_iterator.201] iterators are not compatible"); + CHECK_THROWS_WITH(json(jobject2.cbegin(), jobject.cend()), "[json.exception.invalid_iterator.201] iterators are not compatible"); } } } @@ -1082,18 +1082,18 @@ TEST_CASE("constructors") { json jarray = {1, 2, 3, 4}; json jarray2 = {2, 3, 4, 5}; - CHECK_THROWS_AS(json(jarray.begin(), jarray2.end()), std::domain_error); - CHECK_THROWS_AS(json(jarray2.begin(), jarray.end()), std::domain_error); - CHECK_THROWS_WITH(json(jarray.begin(), jarray2.end()), "iterators are not compatible"); - CHECK_THROWS_WITH(json(jarray2.begin(), jarray.end()), "iterators are not compatible"); + CHECK_THROWS_AS(json(jarray.begin(), jarray2.end()), json::invalid_iterator); + CHECK_THROWS_AS(json(jarray2.begin(), jarray.end()), json::invalid_iterator); + CHECK_THROWS_WITH(json(jarray.begin(), jarray2.end()), "[json.exception.invalid_iterator.201] iterators are not compatible"); + CHECK_THROWS_WITH(json(jarray2.begin(), jarray.end()), "[json.exception.invalid_iterator.201] iterators are not compatible"); } { json jarray = {1, 2, 3, 4}; json jarray2 = {2, 3, 4, 5}; - CHECK_THROWS_AS(json(jarray.cbegin(), jarray2.cend()), std::domain_error); - CHECK_THROWS_AS(json(jarray2.cbegin(), jarray.cend()), std::domain_error); - CHECK_THROWS_WITH(json(jarray.cbegin(), jarray2.cend()), "iterators are not compatible"); - CHECK_THROWS_WITH(json(jarray2.cbegin(), jarray.cend()), "iterators are not compatible"); + CHECK_THROWS_AS(json(jarray.cbegin(), jarray2.cend()), json::invalid_iterator); + CHECK_THROWS_AS(json(jarray2.cbegin(), jarray.cend()), json::invalid_iterator); + CHECK_THROWS_WITH(json(jarray.cbegin(), jarray2.cend()), "[json.exception.invalid_iterator.201] iterators are not compatible"); + CHECK_THROWS_WITH(json(jarray2.cbegin(), jarray.cend()), "[json.exception.invalid_iterator.201] iterators are not compatible"); } } } diff --git a/test/src/unit-element_access1.cpp b/test/src/unit-element_access1.cpp index f0763c5d4..d4ec045ee 100644 --- a/test/src/unit-element_access1.cpp +++ b/test/src/unit-element_access1.cpp @@ -405,12 +405,13 @@ TEST_CASE("element access 1") { json jarray = {1, 1u, true, nullptr, "string", 42.23, json::object(), {1, 2, 3}}; json jarray2 = {"foo", "bar"}; - CHECK_THROWS_AS(jarray.erase(jarray2.begin()), std::domain_error); + CHECK_THROWS_AS(jarray.erase(jarray2.begin()), json::invalid_iterator); CHECK_THROWS_AS(jarray.erase(jarray.begin(), jarray2.end()), std::domain_error); CHECK_THROWS_AS(jarray.erase(jarray2.begin(), jarray.end()), std::domain_error); CHECK_THROWS_AS(jarray.erase(jarray2.begin(), jarray2.end()), std::domain_error); - CHECK_THROWS_WITH(jarray.erase(jarray2.begin()), "iterator does not fit current value"); + CHECK_THROWS_WITH(jarray.erase(jarray2.begin()), + "[json.exception.invalid_iterator.202] iterator does not fit current value"); CHECK_THROWS_WITH(jarray.erase(jarray.begin(), jarray2.end()), "iterators do not fit current value"); CHECK_THROWS_WITH(jarray.erase(jarray2.begin(), jarray.end()), @@ -421,12 +422,13 @@ TEST_CASE("element access 1") { json jarray = {1, 1u, true, nullptr, "string", 42.23, json::object(), {1, 2, 3}}; json jarray2 = {"foo", "bar"}; - CHECK_THROWS_AS(jarray.erase(jarray2.cbegin()), std::domain_error); + CHECK_THROWS_AS(jarray.erase(jarray2.cbegin()), json::invalid_iterator); CHECK_THROWS_AS(jarray.erase(jarray.cbegin(), jarray2.cend()), std::domain_error); CHECK_THROWS_AS(jarray.erase(jarray2.cbegin(), jarray.cend()), std::domain_error); CHECK_THROWS_AS(jarray.erase(jarray2.cbegin(), jarray2.cend()), std::domain_error); - CHECK_THROWS_WITH(jarray.erase(jarray2.cbegin()), "iterator does not fit current value"); + CHECK_THROWS_WITH(jarray.erase(jarray2.cbegin()), + "[json.exception.invalid_iterator.202] iterator does not fit current value"); CHECK_THROWS_WITH(jarray.erase(jarray.cbegin(), jarray2.cend()), "iterators do not fit current value"); CHECK_THROWS_WITH(jarray.erase(jarray2.cbegin(), jarray.cend()), diff --git a/test/src/unit-element_access2.cpp b/test/src/unit-element_access2.cpp index 8e91e89d1..d7e2cadc5 100644 --- a/test/src/unit-element_access2.cpp +++ b/test/src/unit-element_access2.cpp @@ -685,11 +685,12 @@ TEST_CASE("element access 2") { json jobject = {{"a", "a"}, {"b", 1}, {"c", 17u}, {"d", false}, {"e", true}}; json jobject2 = {{"a", "a"}, {"b", 1}, {"c", 17u}}; - CHECK_THROWS_AS(jobject.erase(jobject2.begin()), std::domain_error); + CHECK_THROWS_AS(jobject.erase(jobject2.begin()), json::invalid_iterator); CHECK_THROWS_AS(jobject.erase(jobject.begin(), jobject2.end()), std::domain_error); CHECK_THROWS_AS(jobject.erase(jobject2.begin(), jobject.end()), std::domain_error); CHECK_THROWS_AS(jobject.erase(jobject2.begin(), jobject2.end()), std::domain_error); - CHECK_THROWS_WITH(jobject.erase(jobject2.begin()), "iterator does not fit current value"); + CHECK_THROWS_WITH(jobject.erase(jobject2.begin()), + "[json.exception.invalid_iterator.202] iterator does not fit current value"); CHECK_THROWS_WITH(jobject.erase(jobject.begin(), jobject2.end()), "iterators do not fit current value"); CHECK_THROWS_WITH(jobject.erase(jobject2.begin(), jobject.end()), @@ -700,11 +701,12 @@ TEST_CASE("element access 2") { json jobject = {{"a", "a"}, {"b", 1}, {"c", 17u}, {"d", false}, {"e", true}}; json jobject2 = {{"a", "a"}, {"b", 1}, {"c", 17u}}; - CHECK_THROWS_AS(jobject.erase(jobject2.cbegin()), std::domain_error); + CHECK_THROWS_AS(jobject.erase(jobject2.cbegin()), json::invalid_iterator); CHECK_THROWS_AS(jobject.erase(jobject.cbegin(), jobject2.cend()), std::domain_error); CHECK_THROWS_AS(jobject.erase(jobject2.cbegin(), jobject.cend()), std::domain_error); CHECK_THROWS_AS(jobject.erase(jobject2.cbegin(), jobject2.cend()), std::domain_error); - CHECK_THROWS_WITH(jobject.erase(jobject2.cbegin()), "iterator does not fit current value"); + CHECK_THROWS_WITH(jobject.erase(jobject2.cbegin()), + "[json.exception.invalid_iterator.202] iterator does not fit current value"); CHECK_THROWS_WITH(jobject.erase(jobject.cbegin(), jobject2.cend()), "iterators do not fit current value"); CHECK_THROWS_WITH(jobject.erase(jobject2.cbegin(), jobject.cend()), diff --git a/test/src/unit-modifiers.cpp b/test/src/unit-modifiers.cpp index 0edc9a129..005215353 100644 --- a/test/src/unit-modifiers.cpp +++ b/test/src/unit-modifiers.cpp @@ -662,22 +662,22 @@ TEST_CASE("modifiers") // pass iterator to a different array json j_another_array = {1, 2}; json j_yet_another_array = {"first", "second"}; - CHECK_THROWS_AS(j_array.insert(j_another_array.end(), 10), std::domain_error); - CHECK_THROWS_AS(j_array.insert(j_another_array.end(), j_value), std::domain_error); - CHECK_THROWS_AS(j_array.insert(j_another_array.end(), 10, 11), std::domain_error); - CHECK_THROWS_AS(j_array.insert(j_another_array.end(), j_yet_another_array.begin(), - j_yet_another_array.end()), std::domain_error); - CHECK_THROWS_AS(j_array.insert(j_another_array.end(), {1, 2, 3, 4}), std::domain_error); + CHECK_THROWS_AS(j_array.insert(j_another_array.end(), 10), json::invalid_iterator); + CHECK_THROWS_AS(j_array.insert(j_another_array.end(), j_value), json::invalid_iterator); + CHECK_THROWS_AS(j_array.insert(j_another_array.end(), 10, 11), json::invalid_iterator); + CHECK_THROWS_AS(j_array.insert(j_another_array.end(), j_yet_another_array.begin(), j_yet_another_array.end()), json::invalid_iterator); + CHECK_THROWS_AS(j_array.insert(j_another_array.end(), {1, 2, 3, 4}), json::invalid_iterator); - CHECK_THROWS_WITH(j_array.insert(j_another_array.end(), 10), "iterator does not fit current value"); + CHECK_THROWS_WITH(j_array.insert(j_another_array.end(), 10), + "[json.exception.invalid_iterator.202] iterator does not fit current value"); CHECK_THROWS_WITH(j_array.insert(j_another_array.end(), j_value), - "iterator does not fit current value"); + "[json.exception.invalid_iterator.202] iterator does not fit current value"); CHECK_THROWS_WITH(j_array.insert(j_another_array.end(), 10, 11), - "iterator does not fit current value"); - CHECK_THROWS_WITH(j_array.insert(j_another_array.end(), j_yet_another_array.begin(), - j_yet_another_array.end()), "iterator does not fit current value"); + "[json.exception.invalid_iterator.202] iterator does not fit current value"); + CHECK_THROWS_WITH(j_array.insert(j_another_array.end(), j_yet_another_array.begin(), j_yet_another_array.end()), + "[json.exception.invalid_iterator.202] iterator does not fit current value"); CHECK_THROWS_WITH(j_array.insert(j_another_array.end(), {1, 2, 3, 4}), - "iterator does not fit current value"); + "[json.exception.invalid_iterator.202] iterator does not fit current value"); } SECTION("non-array type") From 875b2da95d5a0bbd0af8d16631de071ea61a6e7c Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Fri, 3 Mar 2017 13:38:14 +0100 Subject: [PATCH 06/52] :hammer: added user-defined exceptions 203-204 --- src/json.hpp | 14 ++-- src/json.hpp.re2c | 14 ++-- test/src/unit-constructor1.cpp | 80 +++++++++++------------ test/src/unit-element_access1.cpp | 104 +++++++++++++++--------------- test/src/unit-element_access2.cpp | 24 +++---- 5 files changed, 118 insertions(+), 118 deletions(-) diff --git a/src/json.hpp b/src/json.hpp index 21601fcdb..89bcc2ff0 100644 --- a/src/json.hpp +++ b/src/json.hpp @@ -2418,7 +2418,7 @@ class basic_json @throw invalid_iterator.201 if iterators are not compatible; that is, do not belong to the same JSON value; example: `"iterators are not compatible"` - @throw std::out_of_range if iterators are for a primitive type (number, + @throw invalid_iterator.204 if iterators are for a primitive type (number, boolean, or string) where an out of range error can be detected easily; example: `"iterators out of range"` @throw std::bad_alloc if allocation for object, array, or string fails @@ -2460,7 +2460,7 @@ class basic_json { if (not first.m_it.primitive_iterator.is_begin() or not last.m_it.primitive_iterator.is_end()) { - JSON_THROW(std::out_of_range("iterators out of range")); + JSON_THROW(invalid_iterator(204, "iterators out of range")); } break; } @@ -4507,9 +4507,9 @@ class basic_json @throw std::domain_error if called on a `null` value; example: `"cannot use erase() with null"` - @throw std::domain_error if called on iterators which does not belong to - the current JSON value; example: `"iterators do not fit current value"` - @throw std::out_of_range if called on a primitive type with invalid + @throw invalid_iterator.203 if called on iterators which does not belong + to the current JSON value; example: `"iterators do not fit current value"` + @throw invalid_iterator.204 if called on a primitive type with invalid iterators (i.e., if `first != begin()` and `last != end()`); example: `"iterators out of range"` @@ -4540,7 +4540,7 @@ class basic_json // make sure iterator fits the current value if (this != first.m_object or this != last.m_object) { - JSON_THROW(std::domain_error("iterators do not fit current value")); + JSON_THROW(invalid_iterator(203, "iterators do not fit current value")); } IteratorType result = end(); @@ -4555,7 +4555,7 @@ class basic_json { if (not first.m_it.primitive_iterator.is_begin() or not last.m_it.primitive_iterator.is_end()) { - JSON_THROW(std::out_of_range("iterators out of range")); + JSON_THROW(invalid_iterator(204, "iterators out of range")); } if (is_string()) diff --git a/src/json.hpp.re2c b/src/json.hpp.re2c index 72b073f06..5ad644b69 100644 --- a/src/json.hpp.re2c +++ b/src/json.hpp.re2c @@ -2418,7 +2418,7 @@ class basic_json @throw invalid_iterator.201 if iterators are not compatible; that is, do not belong to the same JSON value; example: `"iterators are not compatible"` - @throw std::out_of_range if iterators are for a primitive type (number, + @throw invalid_iterator.204 if iterators are for a primitive type (number, boolean, or string) where an out of range error can be detected easily; example: `"iterators out of range"` @throw std::bad_alloc if allocation for object, array, or string fails @@ -2460,7 +2460,7 @@ class basic_json { if (not first.m_it.primitive_iterator.is_begin() or not last.m_it.primitive_iterator.is_end()) { - JSON_THROW(std::out_of_range("iterators out of range")); + JSON_THROW(invalid_iterator(204, "iterators out of range")); } break; } @@ -4507,9 +4507,9 @@ class basic_json @throw std::domain_error if called on a `null` value; example: `"cannot use erase() with null"` - @throw std::domain_error if called on iterators which does not belong to - the current JSON value; example: `"iterators do not fit current value"` - @throw std::out_of_range if called on a primitive type with invalid + @throw invalid_iterator.203 if called on iterators which does not belong + to the current JSON value; example: `"iterators do not fit current value"` + @throw invalid_iterator.204 if called on a primitive type with invalid iterators (i.e., if `first != begin()` and `last != end()`); example: `"iterators out of range"` @@ -4540,7 +4540,7 @@ class basic_json // make sure iterator fits the current value if (this != first.m_object or this != last.m_object) { - JSON_THROW(std::domain_error("iterators do not fit current value")); + JSON_THROW(invalid_iterator(203, "iterators do not fit current value")); } IteratorType result = end(); @@ -4555,7 +4555,7 @@ class basic_json { if (not first.m_it.primitive_iterator.is_begin() or not last.m_it.primitive_iterator.is_end()) { - JSON_THROW(std::out_of_range("iterators out of range")); + JSON_THROW(invalid_iterator(204, "iterators out of range")); } if (is_string()) diff --git a/test/src/unit-constructor1.cpp b/test/src/unit-constructor1.cpp index 3179863e2..3f7d9bbf0 100644 --- a/test/src/unit-constructor1.cpp +++ b/test/src/unit-constructor1.cpp @@ -1193,17 +1193,17 @@ TEST_CASE("constructors") { { json j = "foo"; - CHECK_THROWS_AS(json(j.end(), j.end()), std::out_of_range); - CHECK_THROWS_AS(json(j.begin(), j.begin()), std::out_of_range); - CHECK_THROWS_WITH(json(j.end(), j.end()), "iterators out of range"); - CHECK_THROWS_WITH(json(j.begin(), j.begin()), "iterators out of range"); + CHECK_THROWS_AS(json(j.end(), j.end()), json::invalid_iterator); + CHECK_THROWS_AS(json(j.begin(), j.begin()), json::invalid_iterator); + CHECK_THROWS_WITH(json(j.end(), j.end()), "[json.exception.invalid_iterator.204] iterators out of range"); + CHECK_THROWS_WITH(json(j.begin(), j.begin()), "[json.exception.invalid_iterator.204] iterators out of range"); } { json j = "bar"; - CHECK_THROWS_AS(json(j.cend(), j.cend()), std::out_of_range); - CHECK_THROWS_AS(json(j.cbegin(), j.cbegin()), std::out_of_range); - CHECK_THROWS_WITH(json(j.cend(), j.cend()), "iterators out of range"); - CHECK_THROWS_WITH(json(j.cbegin(), j.cbegin()), "iterators out of range"); + CHECK_THROWS_AS(json(j.cend(), j.cend()), json::invalid_iterator); + CHECK_THROWS_AS(json(j.cbegin(), j.cbegin()), json::invalid_iterator); + CHECK_THROWS_WITH(json(j.cend(), j.cend()), "[json.exception.invalid_iterator.204] iterators out of range"); + CHECK_THROWS_WITH(json(j.cbegin(), j.cbegin()), "[json.exception.invalid_iterator.204] iterators out of range"); } } @@ -1211,17 +1211,17 @@ TEST_CASE("constructors") { { json j = false; - CHECK_THROWS_AS(json(j.end(), j.end()), std::out_of_range); - CHECK_THROWS_AS(json(j.begin(), j.begin()), std::out_of_range); - CHECK_THROWS_WITH(json(j.end(), j.end()), "iterators out of range"); - CHECK_THROWS_WITH(json(j.begin(), j.begin()), "iterators out of range"); + CHECK_THROWS_AS(json(j.end(), j.end()), json::invalid_iterator); + CHECK_THROWS_AS(json(j.begin(), j.begin()), json::invalid_iterator); + CHECK_THROWS_WITH(json(j.end(), j.end()), "[json.exception.invalid_iterator.204] iterators out of range"); + CHECK_THROWS_WITH(json(j.begin(), j.begin()), "[json.exception.invalid_iterator.204] iterators out of range"); } { json j = true; - CHECK_THROWS_AS(json(j.cend(), j.cend()), std::out_of_range); - CHECK_THROWS_AS(json(j.cbegin(), j.cbegin()), std::out_of_range); - CHECK_THROWS_WITH(json(j.cend(), j.cend()), "iterators out of range"); - CHECK_THROWS_WITH(json(j.cbegin(), j.cbegin()), "iterators out of range"); + CHECK_THROWS_AS(json(j.cend(), j.cend()), json::invalid_iterator); + CHECK_THROWS_AS(json(j.cbegin(), j.cbegin()), json::invalid_iterator); + CHECK_THROWS_WITH(json(j.cend(), j.cend()), "[json.exception.invalid_iterator.204] iterators out of range"); + CHECK_THROWS_WITH(json(j.cbegin(), j.cbegin()), "[json.exception.invalid_iterator.204] iterators out of range"); } } @@ -1229,17 +1229,17 @@ TEST_CASE("constructors") { { json j = 17; - CHECK_THROWS_AS(json(j.end(), j.end()), std::out_of_range); - CHECK_THROWS_AS(json(j.begin(), j.begin()), std::out_of_range); - CHECK_THROWS_WITH(json(j.end(), j.end()), "iterators out of range"); - CHECK_THROWS_WITH(json(j.begin(), j.begin()), "iterators out of range"); + CHECK_THROWS_AS(json(j.end(), j.end()), json::invalid_iterator); + CHECK_THROWS_AS(json(j.begin(), j.begin()), json::invalid_iterator); + CHECK_THROWS_WITH(json(j.end(), j.end()), "[json.exception.invalid_iterator.204] iterators out of range"); + CHECK_THROWS_WITH(json(j.begin(), j.begin()), "[json.exception.invalid_iterator.204] iterators out of range"); } { json j = 17; - CHECK_THROWS_AS(json(j.cend(), j.cend()), std::out_of_range); - CHECK_THROWS_AS(json(j.cbegin(), j.cbegin()), std::out_of_range); - CHECK_THROWS_WITH(json(j.cend(), j.cend()), "iterators out of range"); - CHECK_THROWS_WITH(json(j.cbegin(), j.cbegin()), "iterators out of range"); + CHECK_THROWS_AS(json(j.cend(), j.cend()), json::invalid_iterator); + CHECK_THROWS_AS(json(j.cbegin(), j.cbegin()), json::invalid_iterator); + CHECK_THROWS_WITH(json(j.cend(), j.cend()), "[json.exception.invalid_iterator.204] iterators out of range"); + CHECK_THROWS_WITH(json(j.cbegin(), j.cbegin()), "[json.exception.invalid_iterator.204] iterators out of range"); } } @@ -1247,17 +1247,17 @@ TEST_CASE("constructors") { { json j = 17u; - CHECK_THROWS_AS(json(j.end(), j.end()), std::out_of_range); - CHECK_THROWS_AS(json(j.begin(), j.begin()), std::out_of_range); - CHECK_THROWS_WITH(json(j.end(), j.end()), "iterators out of range"); - CHECK_THROWS_WITH(json(j.begin(), j.begin()), "iterators out of range"); + CHECK_THROWS_AS(json(j.end(), j.end()), json::invalid_iterator); + CHECK_THROWS_AS(json(j.begin(), j.begin()), json::invalid_iterator); + CHECK_THROWS_WITH(json(j.end(), j.end()), "[json.exception.invalid_iterator.204] iterators out of range"); + CHECK_THROWS_WITH(json(j.begin(), j.begin()), "[json.exception.invalid_iterator.204] iterators out of range"); } { json j = 17u; - CHECK_THROWS_AS(json(j.cend(), j.cend()), std::out_of_range); - CHECK_THROWS_AS(json(j.cbegin(), j.cbegin()), std::out_of_range); - CHECK_THROWS_WITH(json(j.cend(), j.cend()), "iterators out of range"); - CHECK_THROWS_WITH(json(j.cbegin(), j.cbegin()), "iterators out of range"); + CHECK_THROWS_AS(json(j.cend(), j.cend()), json::invalid_iterator); + CHECK_THROWS_AS(json(j.cbegin(), j.cbegin()), json::invalid_iterator); + CHECK_THROWS_WITH(json(j.cend(), j.cend()), "[json.exception.invalid_iterator.204] iterators out of range"); + CHECK_THROWS_WITH(json(j.cbegin(), j.cbegin()), "[json.exception.invalid_iterator.204] iterators out of range"); } } @@ -1265,17 +1265,17 @@ TEST_CASE("constructors") { { json j = 23.42; - CHECK_THROWS_AS(json(j.end(), j.end()), std::out_of_range); - CHECK_THROWS_AS(json(j.begin(), j.begin()), std::out_of_range); - CHECK_THROWS_WITH(json(j.end(), j.end()), "iterators out of range"); - CHECK_THROWS_WITH(json(j.begin(), j.begin()), "iterators out of range"); + CHECK_THROWS_AS(json(j.end(), j.end()), json::invalid_iterator); + CHECK_THROWS_AS(json(j.begin(), j.begin()), json::invalid_iterator); + CHECK_THROWS_WITH(json(j.end(), j.end()), "[json.exception.invalid_iterator.204] iterators out of range"); + CHECK_THROWS_WITH(json(j.begin(), j.begin()), "[json.exception.invalid_iterator.204] iterators out of range"); } { json j = 23.42; - CHECK_THROWS_AS(json(j.cend(), j.cend()), std::out_of_range); - CHECK_THROWS_AS(json(j.cbegin(), j.cbegin()), std::out_of_range); - CHECK_THROWS_WITH(json(j.cend(), j.cend()), "iterators out of range"); - CHECK_THROWS_WITH(json(j.cbegin(), j.cbegin()), "iterators out of range"); + CHECK_THROWS_AS(json(j.cend(), j.cend()), json::invalid_iterator); + CHECK_THROWS_AS(json(j.cbegin(), j.cbegin()), json::invalid_iterator); + CHECK_THROWS_WITH(json(j.cend(), j.cend()), "[json.exception.invalid_iterator.204] iterators out of range"); + CHECK_THROWS_WITH(json(j.cbegin(), j.cbegin()), "[json.exception.invalid_iterator.204] iterators out of range"); } } } diff --git a/test/src/unit-element_access1.cpp b/test/src/unit-element_access1.cpp index d4ec045ee..c84afd38a 100644 --- a/test/src/unit-element_access1.cpp +++ b/test/src/unit-element_access1.cpp @@ -406,35 +406,35 @@ TEST_CASE("element access 1") json jarray = {1, 1u, true, nullptr, "string", 42.23, json::object(), {1, 2, 3}}; json jarray2 = {"foo", "bar"}; CHECK_THROWS_AS(jarray.erase(jarray2.begin()), json::invalid_iterator); - CHECK_THROWS_AS(jarray.erase(jarray.begin(), jarray2.end()), std::domain_error); - CHECK_THROWS_AS(jarray.erase(jarray2.begin(), jarray.end()), std::domain_error); - CHECK_THROWS_AS(jarray.erase(jarray2.begin(), jarray2.end()), std::domain_error); + CHECK_THROWS_AS(jarray.erase(jarray.begin(), jarray2.end()), json::invalid_iterator); + CHECK_THROWS_AS(jarray.erase(jarray2.begin(), jarray.end()), json::invalid_iterator); + CHECK_THROWS_AS(jarray.erase(jarray2.begin(), jarray2.end()), json::invalid_iterator); CHECK_THROWS_WITH(jarray.erase(jarray2.begin()), "[json.exception.invalid_iterator.202] iterator does not fit current value"); CHECK_THROWS_WITH(jarray.erase(jarray.begin(), jarray2.end()), - "iterators do not fit current value"); + "[json.exception.invalid_iterator.203] iterators do not fit current value"); CHECK_THROWS_WITH(jarray.erase(jarray2.begin(), jarray.end()), - "iterators do not fit current value"); + "[json.exception.invalid_iterator.203] iterators do not fit current value"); CHECK_THROWS_WITH(jarray.erase(jarray2.begin(), jarray2.end()), - "iterators do not fit current value"); + "[json.exception.invalid_iterator.203] iterators do not fit current value"); } { json jarray = {1, 1u, true, nullptr, "string", 42.23, json::object(), {1, 2, 3}}; json jarray2 = {"foo", "bar"}; CHECK_THROWS_AS(jarray.erase(jarray2.cbegin()), json::invalid_iterator); - CHECK_THROWS_AS(jarray.erase(jarray.cbegin(), jarray2.cend()), std::domain_error); - CHECK_THROWS_AS(jarray.erase(jarray2.cbegin(), jarray.cend()), std::domain_error); - CHECK_THROWS_AS(jarray.erase(jarray2.cbegin(), jarray2.cend()), std::domain_error); + CHECK_THROWS_AS(jarray.erase(jarray.cbegin(), jarray2.cend()), json::invalid_iterator); + CHECK_THROWS_AS(jarray.erase(jarray2.cbegin(), jarray.cend()), json::invalid_iterator); + CHECK_THROWS_AS(jarray.erase(jarray2.cbegin(), jarray2.cend()), json::invalid_iterator); CHECK_THROWS_WITH(jarray.erase(jarray2.cbegin()), "[json.exception.invalid_iterator.202] iterator does not fit current value"); CHECK_THROWS_WITH(jarray.erase(jarray.cbegin(), jarray2.cend()), - "iterators do not fit current value"); + "[json.exception.invalid_iterator.203] iterators do not fit current value"); CHECK_THROWS_WITH(jarray.erase(jarray2.cbegin(), jarray.cend()), - "iterators do not fit current value"); + "[json.exception.invalid_iterator.203] iterators do not fit current value"); CHECK_THROWS_WITH(jarray.erase(jarray2.cbegin(), jarray2.cend()), - "iterators do not fit current value"); + "[json.exception.invalid_iterator.203] iterators do not fit current value"); } } } @@ -859,17 +859,17 @@ TEST_CASE("element access 1") { { json j = "foo"; - CHECK_THROWS_AS(j.erase(j.end(), j.end()), std::out_of_range); - CHECK_THROWS_AS(j.erase(j.begin(), j.begin()), std::out_of_range); - CHECK_THROWS_WITH(j.erase(j.end(), j.end()), "iterators out of range"); - CHECK_THROWS_WITH(j.erase(j.begin(), j.begin()), "iterators out of range"); + CHECK_THROWS_AS(j.erase(j.end(), j.end()), json::invalid_iterator); + CHECK_THROWS_AS(j.erase(j.begin(), j.begin()), json::invalid_iterator); + CHECK_THROWS_WITH(j.erase(j.end(), j.end()), "[json.exception.invalid_iterator.204] iterators out of range"); + CHECK_THROWS_WITH(j.erase(j.begin(), j.begin()), "[json.exception.invalid_iterator.204] iterators out of range"); } { json j = "bar"; - CHECK_THROWS_AS(j.erase(j.cend(), j.cend()), std::out_of_range); - CHECK_THROWS_AS(j.erase(j.cbegin(), j.cbegin()), std::out_of_range); - CHECK_THROWS_WITH(j.erase(j.cend(), j.cend()), "iterators out of range"); - CHECK_THROWS_WITH(j.erase(j.cbegin(), j.cbegin()), "iterators out of range"); + CHECK_THROWS_AS(j.erase(j.cend(), j.cend()), json::invalid_iterator); + CHECK_THROWS_AS(j.erase(j.cbegin(), j.cbegin()), json::invalid_iterator); + CHECK_THROWS_WITH(j.erase(j.cend(), j.cend()), "[json.exception.invalid_iterator.204] iterators out of range"); + CHECK_THROWS_WITH(j.erase(j.cbegin(), j.cbegin()), "[json.exception.invalid_iterator.204] iterators out of range"); } } @@ -877,17 +877,17 @@ TEST_CASE("element access 1") { { json j = false; - CHECK_THROWS_AS(j.erase(j.end(), j.end()), std::out_of_range); - CHECK_THROWS_AS(j.erase(j.begin(), j.begin()), std::out_of_range); - CHECK_THROWS_WITH(j.erase(j.end(), j.end()), "iterators out of range"); - CHECK_THROWS_WITH(j.erase(j.begin(), j.begin()), "iterators out of range"); + CHECK_THROWS_AS(j.erase(j.end(), j.end()), json::invalid_iterator); + CHECK_THROWS_AS(j.erase(j.begin(), j.begin()), json::invalid_iterator); + CHECK_THROWS_WITH(j.erase(j.end(), j.end()), "[json.exception.invalid_iterator.204] iterators out of range"); + CHECK_THROWS_WITH(j.erase(j.begin(), j.begin()), "[json.exception.invalid_iterator.204] iterators out of range"); } { json j = true; - CHECK_THROWS_AS(j.erase(j.cend(), j.cend()), std::out_of_range); - CHECK_THROWS_AS(j.erase(j.cbegin(), j.cbegin()), std::out_of_range); - CHECK_THROWS_WITH(j.erase(j.cend(), j.cend()), "iterators out of range"); - CHECK_THROWS_WITH(j.erase(j.cbegin(), j.cbegin()), "iterators out of range"); + CHECK_THROWS_AS(j.erase(j.cend(), j.cend()), json::invalid_iterator); + CHECK_THROWS_AS(j.erase(j.cbegin(), j.cbegin()), json::invalid_iterator); + CHECK_THROWS_WITH(j.erase(j.cend(), j.cend()), "[json.exception.invalid_iterator.204] iterators out of range"); + CHECK_THROWS_WITH(j.erase(j.cbegin(), j.cbegin()), "[json.exception.invalid_iterator.204] iterators out of range"); } } @@ -895,17 +895,17 @@ TEST_CASE("element access 1") { { json j = 17; - CHECK_THROWS_AS(j.erase(j.end(), j.end()), std::out_of_range); - CHECK_THROWS_AS(j.erase(j.begin(), j.begin()), std::out_of_range); - CHECK_THROWS_WITH(j.erase(j.end(), j.end()), "iterators out of range"); - CHECK_THROWS_WITH(j.erase(j.begin(), j.begin()), "iterators out of range"); + CHECK_THROWS_AS(j.erase(j.end(), j.end()), json::invalid_iterator); + CHECK_THROWS_AS(j.erase(j.begin(), j.begin()), json::invalid_iterator); + CHECK_THROWS_WITH(j.erase(j.end(), j.end()), "[json.exception.invalid_iterator.204] iterators out of range"); + CHECK_THROWS_WITH(j.erase(j.begin(), j.begin()), "[json.exception.invalid_iterator.204] iterators out of range"); } { json j = 17; - CHECK_THROWS_AS(j.erase(j.cend(), j.cend()), std::out_of_range); - CHECK_THROWS_AS(j.erase(j.cbegin(), j.cbegin()), std::out_of_range); - CHECK_THROWS_WITH(j.erase(j.cend(), j.cend()), "iterators out of range"); - CHECK_THROWS_WITH(j.erase(j.cbegin(), j.cbegin()), "iterators out of range"); + CHECK_THROWS_AS(j.erase(j.cend(), j.cend()), json::invalid_iterator); + CHECK_THROWS_AS(j.erase(j.cbegin(), j.cbegin()), json::invalid_iterator); + CHECK_THROWS_WITH(j.erase(j.cend(), j.cend()), "[json.exception.invalid_iterator.204] iterators out of range"); + CHECK_THROWS_WITH(j.erase(j.cbegin(), j.cbegin()), "[json.exception.invalid_iterator.204] iterators out of range"); } } @@ -913,17 +913,17 @@ TEST_CASE("element access 1") { { json j = 17u; - CHECK_THROWS_AS(j.erase(j.end(), j.end()), std::out_of_range); - CHECK_THROWS_AS(j.erase(j.begin(), j.begin()), std::out_of_range); - CHECK_THROWS_WITH(j.erase(j.end(), j.end()), "iterators out of range"); - CHECK_THROWS_WITH(j.erase(j.begin(), j.begin()), "iterators out of range"); + CHECK_THROWS_AS(j.erase(j.end(), j.end()), json::invalid_iterator); + CHECK_THROWS_AS(j.erase(j.begin(), j.begin()), json::invalid_iterator); + CHECK_THROWS_WITH(j.erase(j.end(), j.end()), "[json.exception.invalid_iterator.204] iterators out of range"); + CHECK_THROWS_WITH(j.erase(j.begin(), j.begin()), "[json.exception.invalid_iterator.204] iterators out of range"); } { json j = 17u; - CHECK_THROWS_AS(j.erase(j.cend(), j.cend()), std::out_of_range); - CHECK_THROWS_AS(j.erase(j.cbegin(), j.cbegin()), std::out_of_range); - CHECK_THROWS_WITH(j.erase(j.cend(), j.cend()), "iterators out of range"); - CHECK_THROWS_WITH(j.erase(j.cbegin(), j.cbegin()), "iterators out of range"); + CHECK_THROWS_AS(j.erase(j.cend(), j.cend()), json::invalid_iterator); + CHECK_THROWS_AS(j.erase(j.cbegin(), j.cbegin()), json::invalid_iterator); + CHECK_THROWS_WITH(j.erase(j.cend(), j.cend()), "[json.exception.invalid_iterator.204] iterators out of range"); + CHECK_THROWS_WITH(j.erase(j.cbegin(), j.cbegin()), "[json.exception.invalid_iterator.204] iterators out of range"); } } @@ -931,17 +931,17 @@ TEST_CASE("element access 1") { { json j = 23.42; - CHECK_THROWS_AS(j.erase(j.end(), j.end()), std::out_of_range); - CHECK_THROWS_AS(j.erase(j.begin(), j.begin()), std::out_of_range); - CHECK_THROWS_WITH(j.erase(j.end(), j.end()), "iterators out of range"); - CHECK_THROWS_WITH(j.erase(j.begin(), j.begin()), "iterators out of range"); + CHECK_THROWS_AS(j.erase(j.end(), j.end()), json::invalid_iterator); + CHECK_THROWS_AS(j.erase(j.begin(), j.begin()), json::invalid_iterator); + CHECK_THROWS_WITH(j.erase(j.end(), j.end()), "[json.exception.invalid_iterator.204] iterators out of range"); + CHECK_THROWS_WITH(j.erase(j.begin(), j.begin()), "[json.exception.invalid_iterator.204] iterators out of range"); } { json j = 23.42; - CHECK_THROWS_AS(j.erase(j.cend(), j.cend()), std::out_of_range); - CHECK_THROWS_AS(j.erase(j.cbegin(), j.cbegin()), std::out_of_range); - CHECK_THROWS_WITH(j.erase(j.cend(), j.cend()), "iterators out of range"); - CHECK_THROWS_WITH(j.erase(j.cbegin(), j.cbegin()), "iterators out of range"); + CHECK_THROWS_AS(j.erase(j.cend(), j.cend()), json::invalid_iterator); + CHECK_THROWS_AS(j.erase(j.cbegin(), j.cbegin()), json::invalid_iterator); + CHECK_THROWS_WITH(j.erase(j.cend(), j.cend()), "[json.exception.invalid_iterator.204] iterators out of range"); + CHECK_THROWS_WITH(j.erase(j.cbegin(), j.cbegin()), "[json.exception.invalid_iterator.204] iterators out of range"); } } } diff --git a/test/src/unit-element_access2.cpp b/test/src/unit-element_access2.cpp index d7e2cadc5..3c3122f1c 100644 --- a/test/src/unit-element_access2.cpp +++ b/test/src/unit-element_access2.cpp @@ -686,33 +686,33 @@ TEST_CASE("element access 2") json jobject = {{"a", "a"}, {"b", 1}, {"c", 17u}, {"d", false}, {"e", true}}; json jobject2 = {{"a", "a"}, {"b", 1}, {"c", 17u}}; CHECK_THROWS_AS(jobject.erase(jobject2.begin()), json::invalid_iterator); - CHECK_THROWS_AS(jobject.erase(jobject.begin(), jobject2.end()), std::domain_error); - CHECK_THROWS_AS(jobject.erase(jobject2.begin(), jobject.end()), std::domain_error); - CHECK_THROWS_AS(jobject.erase(jobject2.begin(), jobject2.end()), std::domain_error); + CHECK_THROWS_AS(jobject.erase(jobject.begin(), jobject2.end()), json::invalid_iterator); + CHECK_THROWS_AS(jobject.erase(jobject2.begin(), jobject.end()), json::invalid_iterator); + CHECK_THROWS_AS(jobject.erase(jobject2.begin(), jobject2.end()), json::invalid_iterator); CHECK_THROWS_WITH(jobject.erase(jobject2.begin()), "[json.exception.invalid_iterator.202] iterator does not fit current value"); CHECK_THROWS_WITH(jobject.erase(jobject.begin(), jobject2.end()), - "iterators do not fit current value"); + "[json.exception.invalid_iterator.203] iterators do not fit current value"); CHECK_THROWS_WITH(jobject.erase(jobject2.begin(), jobject.end()), - "iterators do not fit current value"); + "[json.exception.invalid_iterator.203] iterators do not fit current value"); CHECK_THROWS_WITH(jobject.erase(jobject2.begin(), jobject2.end()), - "iterators do not fit current value"); + "[json.exception.invalid_iterator.203] iterators do not fit current value"); } { json jobject = {{"a", "a"}, {"b", 1}, {"c", 17u}, {"d", false}, {"e", true}}; json jobject2 = {{"a", "a"}, {"b", 1}, {"c", 17u}}; CHECK_THROWS_AS(jobject.erase(jobject2.cbegin()), json::invalid_iterator); - CHECK_THROWS_AS(jobject.erase(jobject.cbegin(), jobject2.cend()), std::domain_error); - CHECK_THROWS_AS(jobject.erase(jobject2.cbegin(), jobject.cend()), std::domain_error); - CHECK_THROWS_AS(jobject.erase(jobject2.cbegin(), jobject2.cend()), std::domain_error); + CHECK_THROWS_AS(jobject.erase(jobject.cbegin(), jobject2.cend()), json::invalid_iterator); + CHECK_THROWS_AS(jobject.erase(jobject2.cbegin(), jobject.cend()), json::invalid_iterator); + CHECK_THROWS_AS(jobject.erase(jobject2.cbegin(), jobject2.cend()), json::invalid_iterator); CHECK_THROWS_WITH(jobject.erase(jobject2.cbegin()), "[json.exception.invalid_iterator.202] iterator does not fit current value"); CHECK_THROWS_WITH(jobject.erase(jobject.cbegin(), jobject2.cend()), - "iterators do not fit current value"); + "[json.exception.invalid_iterator.203] iterators do not fit current value"); CHECK_THROWS_WITH(jobject.erase(jobject2.cbegin(), jobject.cend()), - "iterators do not fit current value"); + "[json.exception.invalid_iterator.203] iterators do not fit current value"); CHECK_THROWS_WITH(jobject.erase(jobject2.cbegin(), jobject2.cend()), - "iterators do not fit current value"); + "[json.exception.invalid_iterator.203] iterators do not fit current value"); } } } From a4274d776683f592469bad9463639f1b2ce483f9 Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Fri, 3 Mar 2017 14:00:42 +0100 Subject: [PATCH 07/52] :hammer: added user-defined exceptions 205-206 --- src/json.hpp | 15 +++-- src/json.hpp.re2c | 15 +++-- test/src/unit-constructor1.cpp | 10 +-- test/src/unit-element_access1.cpp | 40 ++++++------ test/src/unit-iterators1.cpp | 104 +++++++++++++++--------------- test/src/unit-iterators2.cpp | 16 ++--- 6 files changed, 102 insertions(+), 98 deletions(-) diff --git a/src/json.hpp b/src/json.hpp index 89bcc2ff0..039223dc0 100644 --- a/src/json.hpp +++ b/src/json.hpp @@ -2422,8 +2422,8 @@ class basic_json boolean, or string) where an out of range error can be detected easily; example: `"iterators out of range"` @throw std::bad_alloc if allocation for object, array, or string fails - @throw std::domain_error if called with a null value; example: `"cannot - use construct with iterators from null"` + @throw invalid_iterator.206 if called with a null value; example: `"cannot + construct with iterators from null"` @complexity Linear in distance between @a first and @a last. @@ -2519,7 +2519,8 @@ class basic_json default: { - JSON_THROW(std::domain_error("cannot use construct with iterators from " + first.m_object->type_name())); + JSON_THROW(invalid_iterator(206, "cannot construct with iterators from " + + first.m_object->type_name())); } } @@ -4402,7 +4403,7 @@ class basic_json @throw invalid_iterator.202 if called on an iterator which does not belong to the current JSON value; example: `"iterator does not fit current value"` - @throw std::out_of_range if called on a primitive type with invalid + @throw invalid_iterator.205 if called on a primitive type with invalid iterator (i.e., any iterator which is not `begin()`); example: `"iterator out of range"` @@ -4448,7 +4449,7 @@ class basic_json { if (not pos.m_it.primitive_iterator.is_begin()) { - JSON_THROW(std::out_of_range("iterator out of range")); + JSON_THROW(invalid_iterator(205, "iterator out of range")); } if (is_string()) @@ -9625,7 +9626,7 @@ class basic_json { case basic_json::value_t::object: { - JSON_THROW(std::domain_error("cannot use operator[] for object iterators")); + JSON_THROW(invalid_iterator(208, "cannot use operator[] for object iterators")); } case basic_json::value_t::array: @@ -9663,7 +9664,7 @@ class basic_json return m_it.object_iterator->first; } - JSON_THROW(std::domain_error("cannot use key() for non-object iterators")); + JSON_THROW(invalid_iterator(207, "cannot use key() for non-object iterators")); } /*! diff --git a/src/json.hpp.re2c b/src/json.hpp.re2c index 5ad644b69..b4e596a2f 100644 --- a/src/json.hpp.re2c +++ b/src/json.hpp.re2c @@ -2422,8 +2422,8 @@ class basic_json boolean, or string) where an out of range error can be detected easily; example: `"iterators out of range"` @throw std::bad_alloc if allocation for object, array, or string fails - @throw std::domain_error if called with a null value; example: `"cannot - use construct with iterators from null"` + @throw invalid_iterator.206 if called with a null value; example: `"cannot + construct with iterators from null"` @complexity Linear in distance between @a first and @a last. @@ -2519,7 +2519,8 @@ class basic_json default: { - JSON_THROW(std::domain_error("cannot use construct with iterators from " + first.m_object->type_name())); + JSON_THROW(invalid_iterator(206, "cannot construct with iterators from " + + first.m_object->type_name())); } } @@ -4402,7 +4403,7 @@ class basic_json @throw invalid_iterator.202 if called on an iterator which does not belong to the current JSON value; example: `"iterator does not fit current value"` - @throw std::out_of_range if called on a primitive type with invalid + @throw invalid_iterator.205 if called on a primitive type with invalid iterator (i.e., any iterator which is not `begin()`); example: `"iterator out of range"` @@ -4448,7 +4449,7 @@ class basic_json { if (not pos.m_it.primitive_iterator.is_begin()) { - JSON_THROW(std::out_of_range("iterator out of range")); + JSON_THROW(invalid_iterator(205, "iterator out of range")); } if (is_string()) @@ -9625,7 +9626,7 @@ class basic_json { case basic_json::value_t::object: { - JSON_THROW(std::domain_error("cannot use operator[] for object iterators")); + JSON_THROW(invalid_iterator(208, "cannot use operator[] for object iterators")); } case basic_json::value_t::array: @@ -9663,7 +9664,7 @@ class basic_json return m_it.object_iterator->first; } - JSON_THROW(std::domain_error("cannot use key() for non-object iterators")); + JSON_THROW(invalid_iterator(207, "cannot use key() for non-object iterators")); } /*! diff --git a/test/src/unit-constructor1.cpp b/test/src/unit-constructor1.cpp index 3f7d9bbf0..d99855d83 100644 --- a/test/src/unit-constructor1.cpp +++ b/test/src/unit-constructor1.cpp @@ -1106,13 +1106,15 @@ TEST_CASE("constructors") { { json j; - CHECK_THROWS_AS(json(j.begin(), j.end()), std::domain_error); - CHECK_THROWS_WITH(json(j.begin(), j.end()), "cannot use construct with iterators from null"); + CHECK_THROWS_AS(json(j.begin(), j.end()), json::invalid_iterator); + CHECK_THROWS_WITH(json(j.begin(), j.end()), + "[json.exception.invalid_iterator.206] cannot construct with iterators from null"); } { json j; - CHECK_THROWS_AS(json(j.cbegin(), j.cend()), std::domain_error); - CHECK_THROWS_WITH(json(j.cbegin(), j.cend()), "cannot use construct with iterators from null"); + CHECK_THROWS_AS(json(j.cbegin(), j.cend()), json::invalid_iterator); + CHECK_THROWS_WITH(json(j.cbegin(), j.cend()), + "[json.exception.invalid_iterator.206] cannot construct with iterators from null"); } } diff --git a/test/src/unit-element_access1.cpp b/test/src/unit-element_access1.cpp index c84afd38a..265f28e11 100644 --- a/test/src/unit-element_access1.cpp +++ b/test/src/unit-element_access1.cpp @@ -689,13 +689,13 @@ TEST_CASE("element access 1") { { json j = "foo"; - CHECK_THROWS_AS(j.erase(j.end()), std::out_of_range); - CHECK_THROWS_WITH(j.erase(j.end()), "iterator out of range"); + CHECK_THROWS_AS(j.erase(j.end()), json::invalid_iterator); + CHECK_THROWS_WITH(j.erase(j.end()), "[json.exception.invalid_iterator.205] iterator out of range"); } { json j = "bar"; - CHECK_THROWS_AS(j.erase(j.cend()), std::out_of_range); - CHECK_THROWS_WITH(j.erase(j.cend()), "iterator out of range"); + CHECK_THROWS_AS(j.erase(j.cend()), json::invalid_iterator); + CHECK_THROWS_WITH(j.erase(j.cend()), "[json.exception.invalid_iterator.205] iterator out of range"); } } @@ -703,13 +703,13 @@ TEST_CASE("element access 1") { { json j = false; - CHECK_THROWS_AS(j.erase(j.end()), std::out_of_range); - CHECK_THROWS_WITH(j.erase(j.end()), "iterator out of range"); + CHECK_THROWS_AS(j.erase(j.end()), json::invalid_iterator); + CHECK_THROWS_WITH(j.erase(j.end()), "[json.exception.invalid_iterator.205] iterator out of range"); } { json j = true; - CHECK_THROWS_AS(j.erase(j.cend()), std::out_of_range); - CHECK_THROWS_WITH(j.erase(j.cend()), "iterator out of range"); + CHECK_THROWS_AS(j.erase(j.cend()), json::invalid_iterator); + CHECK_THROWS_WITH(j.erase(j.cend()), "[json.exception.invalid_iterator.205] iterator out of range"); } } @@ -717,13 +717,13 @@ TEST_CASE("element access 1") { { json j = 17; - CHECK_THROWS_AS(j.erase(j.end()), std::out_of_range); - CHECK_THROWS_WITH(j.erase(j.end()), "iterator out of range"); + CHECK_THROWS_AS(j.erase(j.end()), json::invalid_iterator); + CHECK_THROWS_WITH(j.erase(j.end()), "[json.exception.invalid_iterator.205] iterator out of range"); } { json j = 17; - CHECK_THROWS_AS(j.erase(j.cend()), std::out_of_range); - CHECK_THROWS_WITH(j.erase(j.cend()), "iterator out of range"); + CHECK_THROWS_AS(j.erase(j.cend()), json::invalid_iterator); + CHECK_THROWS_WITH(j.erase(j.cend()), "[json.exception.invalid_iterator.205] iterator out of range"); } } @@ -731,13 +731,13 @@ TEST_CASE("element access 1") { { json j = 17u; - CHECK_THROWS_AS(j.erase(j.end()), std::out_of_range); - CHECK_THROWS_WITH(j.erase(j.end()), "iterator out of range"); + CHECK_THROWS_AS(j.erase(j.end()), json::invalid_iterator); + CHECK_THROWS_WITH(j.erase(j.end()), "[json.exception.invalid_iterator.205] iterator out of range"); } { json j = 17u; - CHECK_THROWS_AS(j.erase(j.cend()), std::out_of_range); - CHECK_THROWS_WITH(j.erase(j.cend()), "iterator out of range"); + CHECK_THROWS_AS(j.erase(j.cend()), json::invalid_iterator); + CHECK_THROWS_WITH(j.erase(j.cend()), "[json.exception.invalid_iterator.205] iterator out of range"); } } @@ -745,13 +745,13 @@ TEST_CASE("element access 1") { { json j = 23.42; - CHECK_THROWS_AS(j.erase(j.end()), std::out_of_range); - CHECK_THROWS_WITH(j.erase(j.end()), "iterator out of range"); + CHECK_THROWS_AS(j.erase(j.end()), json::invalid_iterator); + CHECK_THROWS_WITH(j.erase(j.end()), "[json.exception.invalid_iterator.205] iterator out of range"); } { json j = 23.42; - CHECK_THROWS_AS(j.erase(j.cend()), std::out_of_range); - CHECK_THROWS_WITH(j.erase(j.cend()), "iterator out of range"); + CHECK_THROWS_AS(j.erase(j.cend()), json::invalid_iterator); + CHECK_THROWS_WITH(j.erase(j.cend()), "[json.exception.invalid_iterator.205] iterator out of range"); } } } diff --git a/test/src/unit-iterators1.cpp b/test/src/unit-iterators1.cpp index eebee1107..c1f179fd7 100644 --- a/test/src/unit-iterators1.cpp +++ b/test/src/unit-iterators1.cpp @@ -229,22 +229,22 @@ TEST_CASE("iterators 1") { auto it = j.begin(); auto cit = j_const.cbegin(); - CHECK_THROWS_AS(it.key(), std::domain_error); - CHECK_THROWS_WITH(it.key(), "cannot use key() for non-object iterators"); + CHECK_THROWS_AS(it.key(), json::invalid_iterator); + CHECK_THROWS_WITH(it.key(), "[json.exception.invalid_iterator.207] cannot use key() for non-object iterators"); CHECK(it.value() == json(true)); - CHECK_THROWS_AS(cit.key(), std::domain_error); - CHECK_THROWS_WITH(cit.key(), "cannot use key() for non-object iterators"); + CHECK_THROWS_AS(cit.key(), json::invalid_iterator); + CHECK_THROWS_WITH(cit.key(), "[json.exception.invalid_iterator.207] cannot use key() for non-object iterators"); CHECK(cit.value() == json(true)); auto rit = j.rend(); auto crit = j.crend(); - CHECK_THROWS_AS(rit.key(), std::domain_error); + CHECK_THROWS_AS(rit.key(), json::invalid_iterator); CHECK_THROWS_AS(rit.value(), std::out_of_range); - CHECK_THROWS_AS(crit.key(), std::domain_error); + CHECK_THROWS_AS(crit.key(), json::invalid_iterator); CHECK_THROWS_AS(crit.value(), std::out_of_range); - CHECK_THROWS_WITH(rit.key(), "cannot use key() for non-object iterators"); + CHECK_THROWS_WITH(rit.key(), "[json.exception.invalid_iterator.207] cannot use key() for non-object iterators"); CHECK_THROWS_WITH(rit.value(), "cannot get value"); - CHECK_THROWS_WITH(crit.key(), "cannot use key() for non-object iterators"); + CHECK_THROWS_WITH(crit.key(), "[json.exception.invalid_iterator.207] cannot use key() for non-object iterators"); CHECK_THROWS_WITH(crit.value(), "cannot get value"); } } @@ -433,22 +433,22 @@ TEST_CASE("iterators 1") { auto it = j.begin(); auto cit = j_const.cbegin(); - CHECK_THROWS_AS(it.key(), std::domain_error); - CHECK_THROWS_WITH(it.key(), "cannot use key() for non-object iterators"); + CHECK_THROWS_AS(it.key(), json::invalid_iterator); + CHECK_THROWS_WITH(it.key(), "[json.exception.invalid_iterator.207] cannot use key() for non-object iterators"); CHECK(it.value() == json("hello world")); - CHECK_THROWS_AS(cit.key(), std::domain_error); - CHECK_THROWS_WITH(cit.key(), "cannot use key() for non-object iterators"); + CHECK_THROWS_AS(cit.key(), json::invalid_iterator); + CHECK_THROWS_WITH(cit.key(), "[json.exception.invalid_iterator.207] cannot use key() for non-object iterators"); CHECK(cit.value() == json("hello world")); auto rit = j.rend(); auto crit = j.crend(); - CHECK_THROWS_AS(rit.key(), std::domain_error); + CHECK_THROWS_AS(rit.key(), json::invalid_iterator); CHECK_THROWS_AS(rit.value(), std::out_of_range); - CHECK_THROWS_AS(crit.key(), std::domain_error); + CHECK_THROWS_AS(crit.key(), json::invalid_iterator); CHECK_THROWS_AS(crit.value(), std::out_of_range); - CHECK_THROWS_WITH(rit.key(), "cannot use key() for non-object iterators"); + CHECK_THROWS_WITH(rit.key(), "[json.exception.invalid_iterator.207] cannot use key() for non-object iterators"); CHECK_THROWS_WITH(rit.value(), "cannot get value"); - CHECK_THROWS_WITH(crit.key(), "cannot use key() for non-object iterators"); + CHECK_THROWS_WITH(crit.key(), "[json.exception.invalid_iterator.207] cannot use key() for non-object iterators"); CHECK_THROWS_WITH(crit.value(), "cannot get value"); } } @@ -630,11 +630,11 @@ TEST_CASE("iterators 1") { auto it = j.begin(); auto cit = j_const.cbegin(); - CHECK_THROWS_AS(it.key(), std::domain_error); - CHECK_THROWS_WITH(it.key(), "cannot use key() for non-object iterators"); + CHECK_THROWS_AS(it.key(), json::invalid_iterator); + CHECK_THROWS_WITH(it.key(), "[json.exception.invalid_iterator.207] cannot use key() for non-object iterators"); CHECK(it.value() == json(1)); - CHECK_THROWS_AS(cit.key(), std::domain_error); - CHECK_THROWS_WITH(cit.key(), "cannot use key() for non-object iterators"); + CHECK_THROWS_AS(cit.key(), json::invalid_iterator); + CHECK_THROWS_WITH(cit.key(), "[json.exception.invalid_iterator.207] cannot use key() for non-object iterators"); CHECK(cit.value() == json(1)); } } @@ -1007,22 +1007,22 @@ TEST_CASE("iterators 1") { auto it = j.begin(); auto cit = j_const.cbegin(); - CHECK_THROWS_AS(it.key(), std::domain_error); - CHECK_THROWS_WITH(it.key(), "cannot use key() for non-object iterators"); + CHECK_THROWS_AS(it.key(), json::invalid_iterator); + CHECK_THROWS_WITH(it.key(), "[json.exception.invalid_iterator.207] cannot use key() for non-object iterators"); CHECK(it.value() == json(23)); - CHECK_THROWS_AS(cit.key(), std::domain_error); - CHECK_THROWS_WITH(cit.key(), "cannot use key() for non-object iterators"); + CHECK_THROWS_AS(cit.key(), json::invalid_iterator); + CHECK_THROWS_WITH(cit.key(), "[json.exception.invalid_iterator.207] cannot use key() for non-object iterators"); CHECK(cit.value() == json(23)); auto rit = j.rend(); auto crit = j.crend(); - CHECK_THROWS_AS(rit.key(), std::domain_error); + CHECK_THROWS_AS(rit.key(), json::invalid_iterator); CHECK_THROWS_AS(rit.value(), std::out_of_range); - CHECK_THROWS_AS(crit.key(), std::domain_error); + CHECK_THROWS_AS(crit.key(), json::invalid_iterator); CHECK_THROWS_AS(crit.value(), std::out_of_range); - CHECK_THROWS_WITH(rit.key(), "cannot use key() for non-object iterators"); + CHECK_THROWS_WITH(rit.key(), "[json.exception.invalid_iterator.207] cannot use key() for non-object iterators"); CHECK_THROWS_WITH(rit.value(), "cannot get value"); - CHECK_THROWS_WITH(crit.key(), "cannot use key() for non-object iterators"); + CHECK_THROWS_WITH(crit.key(), "[json.exception.invalid_iterator.207] cannot use key() for non-object iterators"); CHECK_THROWS_WITH(crit.value(), "cannot get value"); } } @@ -1211,22 +1211,22 @@ TEST_CASE("iterators 1") { auto it = j.begin(); auto cit = j_const.cbegin(); - CHECK_THROWS_AS(it.key(), std::domain_error); - CHECK_THROWS_WITH(it.key(), "cannot use key() for non-object iterators"); + CHECK_THROWS_AS(it.key(), json::invalid_iterator); + CHECK_THROWS_WITH(it.key(), "[json.exception.invalid_iterator.207] cannot use key() for non-object iterators"); CHECK(it.value() == json(23)); - CHECK_THROWS_AS(cit.key(), std::domain_error); - CHECK_THROWS_WITH(cit.key(), "cannot use key() for non-object iterators"); + CHECK_THROWS_AS(cit.key(), json::invalid_iterator); + CHECK_THROWS_WITH(cit.key(), "[json.exception.invalid_iterator.207] cannot use key() for non-object iterators"); CHECK(cit.value() == json(23)); auto rit = j.rend(); auto crit = j.crend(); - CHECK_THROWS_AS(rit.key(), std::domain_error); + CHECK_THROWS_AS(rit.key(), json::invalid_iterator); CHECK_THROWS_AS(rit.value(), std::out_of_range); - CHECK_THROWS_AS(crit.key(), std::domain_error); + CHECK_THROWS_AS(crit.key(), json::invalid_iterator); CHECK_THROWS_AS(crit.value(), std::out_of_range); - CHECK_THROWS_WITH(rit.key(), "cannot use key() for non-object iterators"); + CHECK_THROWS_WITH(rit.key(), "[json.exception.invalid_iterator.207] cannot use key() for non-object iterators"); CHECK_THROWS_WITH(rit.value(), "cannot get value"); - CHECK_THROWS_WITH(crit.key(), "cannot use key() for non-object iterators"); + CHECK_THROWS_WITH(crit.key(), "[json.exception.invalid_iterator.207] cannot use key() for non-object iterators"); CHECK_THROWS_WITH(crit.value(), "cannot get value"); } } @@ -1415,22 +1415,22 @@ TEST_CASE("iterators 1") { auto it = j.begin(); auto cit = j_const.cbegin(); - CHECK_THROWS_AS(it.key(), std::domain_error); - CHECK_THROWS_WITH(it.key(), "cannot use key() for non-object iterators"); + CHECK_THROWS_AS(it.key(), json::invalid_iterator); + CHECK_THROWS_WITH(it.key(), "[json.exception.invalid_iterator.207] cannot use key() for non-object iterators"); CHECK(it.value() == json(23.42)); - CHECK_THROWS_AS(cit.key(), std::domain_error); - CHECK_THROWS_WITH(cit.key(), "cannot use key() for non-object iterators"); + CHECK_THROWS_AS(cit.key(), json::invalid_iterator); + CHECK_THROWS_WITH(cit.key(), "[json.exception.invalid_iterator.207] cannot use key() for non-object iterators"); CHECK(cit.value() == json(23.42)); auto rit = j.rend(); auto crit = j.crend(); - CHECK_THROWS_AS(rit.key(), std::domain_error); + CHECK_THROWS_AS(rit.key(), json::invalid_iterator); CHECK_THROWS_AS(rit.value(), std::out_of_range); - CHECK_THROWS_AS(crit.key(), std::domain_error); + CHECK_THROWS_AS(crit.key(), json::invalid_iterator); CHECK_THROWS_AS(crit.value(), std::out_of_range); - CHECK_THROWS_WITH(rit.key(), "cannot use key() for non-object iterators"); + CHECK_THROWS_WITH(rit.key(), "[json.exception.invalid_iterator.207] cannot use key() for non-object iterators"); CHECK_THROWS_WITH(rit.value(), "cannot get value"); - CHECK_THROWS_WITH(crit.key(), "cannot use key() for non-object iterators"); + CHECK_THROWS_WITH(crit.key(), "[json.exception.invalid_iterator.207] cannot use key() for non-object iterators"); CHECK_THROWS_WITH(crit.value(), "cannot get value"); } } @@ -1489,24 +1489,24 @@ TEST_CASE("iterators 1") { auto it = j.begin(); auto cit = j_const.cbegin(); - CHECK_THROWS_AS(it.key(), std::domain_error); + CHECK_THROWS_AS(it.key(), json::invalid_iterator); CHECK_THROWS_AS(it.value(), std::out_of_range); - CHECK_THROWS_AS(cit.key(), std::domain_error); + CHECK_THROWS_AS(cit.key(), json::invalid_iterator); CHECK_THROWS_AS(cit.value(), std::out_of_range); - CHECK_THROWS_WITH(it.key(), "cannot use key() for non-object iterators"); + CHECK_THROWS_WITH(it.key(), "[json.exception.invalid_iterator.207] cannot use key() for non-object iterators"); CHECK_THROWS_WITH(it.value(), "cannot get value"); - CHECK_THROWS_WITH(cit.key(), "cannot use key() for non-object iterators"); + CHECK_THROWS_WITH(cit.key(), "[json.exception.invalid_iterator.207] cannot use key() for non-object iterators"); CHECK_THROWS_WITH(cit.value(), "cannot get value"); auto rit = j.rend(); auto crit = j.crend(); - CHECK_THROWS_AS(rit.key(), std::domain_error); + CHECK_THROWS_AS(rit.key(), json::invalid_iterator); CHECK_THROWS_AS(rit.value(), std::out_of_range); - CHECK_THROWS_AS(crit.key(), std::domain_error); + CHECK_THROWS_AS(crit.key(), json::invalid_iterator); CHECK_THROWS_AS(crit.value(), std::out_of_range); - CHECK_THROWS_WITH(rit.key(), "cannot use key() for non-object iterators"); + CHECK_THROWS_WITH(rit.key(), "[json.exception.invalid_iterator.207] cannot use key() for non-object iterators"); CHECK_THROWS_WITH(rit.value(), "cannot get value"); - CHECK_THROWS_WITH(crit.key(), "cannot use key() for non-object iterators"); + CHECK_THROWS_WITH(crit.key(), "[json.exception.invalid_iterator.207] cannot use key() for non-object iterators"); CHECK_THROWS_WITH(crit.value(), "cannot get value"); } } diff --git a/test/src/unit-iterators2.cpp b/test/src/unit-iterators2.cpp index b2bc4a382..63242f1e8 100644 --- a/test/src/unit-iterators2.cpp +++ b/test/src/unit-iterators2.cpp @@ -380,17 +380,17 @@ TEST_CASE("iterators 2") { { auto it = j_object.begin(); - CHECK_THROWS_AS(it[0], std::domain_error); - CHECK_THROWS_AS(it[1], std::domain_error); - CHECK_THROWS_WITH(it[0], "cannot use operator[] for object iterators"); - CHECK_THROWS_WITH(it[1], "cannot use operator[] for object iterators"); + CHECK_THROWS_AS(it[0], json::invalid_iterator); + CHECK_THROWS_AS(it[1], json::invalid_iterator); + CHECK_THROWS_WITH(it[0], "[json.exception.invalid_iterator.208] cannot use operator[] for object iterators"); + CHECK_THROWS_WITH(it[1], "[json.exception.invalid_iterator.208] cannot use operator[] for object iterators"); } { auto it = j_object.cbegin(); - CHECK_THROWS_AS(it[0], std::domain_error); - CHECK_THROWS_AS(it[1], std::domain_error); - CHECK_THROWS_WITH(it[0], "cannot use operator[] for object iterators"); - CHECK_THROWS_WITH(it[1], "cannot use operator[] for object iterators"); + CHECK_THROWS_AS(it[0], json::invalid_iterator); + CHECK_THROWS_AS(it[1], json::invalid_iterator); + CHECK_THROWS_WITH(it[0], "[json.exception.invalid_iterator.208] cannot use operator[] for object iterators"); + CHECK_THROWS_WITH(it[1], "[json.exception.invalid_iterator.208] cannot use operator[] for object iterators"); } } From 0c40c8e3be75e0ebb74ec9394812f798eef8f7a8 Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Fri, 3 Mar 2017 14:34:57 +0100 Subject: [PATCH 08/52] :hammer: added user-defined exceptions 2xx --- src/json.hpp | 30 +- src/json.hpp.re2c | 30 +- test/src/unit-algorithms.cpp | 5 +- test/src/unit-class_const_iterator.cpp | 16 +- test/src/unit-class_iterator.cpp | 16 +- test/src/unit-element_access1.cpp | 16 +- test/src/unit-iterators1.cpp | 56 ++-- test/src/unit-iterators2.cpp | 432 ++++++++++++------------- test/src/unit-modifiers.cpp | 9 +- 9 files changed, 306 insertions(+), 304 deletions(-) diff --git a/src/json.hpp b/src/json.hpp index 039223dc0..59010a133 100644 --- a/src/json.hpp +++ b/src/json.hpp @@ -5755,9 +5755,9 @@ class basic_json example: `"cannot use insert() with string"` @throw invalid_iterator.202 if @a pos is not an iterator of *this; example: `"iterator does not fit current value"` - @throw std::domain_error if @a first and @a last do not belong to the same - JSON value; example: `"iterators do not fit"` - @throw std::domain_error if @a first or @a last are iterators into + @throw invalid_iterator.210 if @a first and @a last do not belong to the + same JSON value; example: `"iterators do not fit"` + @throw invalid_iterator.211 if @a first or @a last are iterators into container for which insert is called; example: `"passed iterators may not belong to container"` @@ -5788,12 +5788,12 @@ class basic_json // check if range iterators belong to the same JSON object if (first.m_object != last.m_object) { - JSON_THROW(std::domain_error("iterators do not fit")); + JSON_THROW(invalid_iterator(210, "iterators do not fit")); } if (first.m_object == this or last.m_object == this) { - JSON_THROW(std::domain_error("passed iterators may not belong to container")); + JSON_THROW(invalid_iterator(211, "passed iterators may not belong to container")); } // insert to array and return iterator @@ -9288,7 +9288,7 @@ class basic_json case basic_json::value_t::null: { - JSON_THROW(std::out_of_range("cannot get value")); + JSON_THROW(invalid_iterator(214, "cannot get value")); } default: @@ -9298,7 +9298,7 @@ class basic_json return *m_object; } - JSON_THROW(std::out_of_range("cannot get value")); + JSON_THROW(invalid_iterator(214, "cannot get value")); } } } @@ -9332,7 +9332,7 @@ class basic_json return m_object; } - JSON_THROW(std::out_of_range("cannot get value")); + JSON_THROW(invalid_iterator(214, "cannot get value")); } } } @@ -9432,7 +9432,7 @@ class basic_json // if objects are not the same, the comparison is undefined if (m_object != other.m_object) { - JSON_THROW(std::domain_error("cannot compare iterators of different containers")); + JSON_THROW(invalid_iterator(212, "cannot compare iterators of different containers")); } assert(m_object != nullptr); @@ -9474,7 +9474,7 @@ class basic_json // if objects are not the same, the comparison is undefined if (m_object != other.m_object) { - JSON_THROW(std::domain_error("cannot compare iterators of different containers")); + JSON_THROW(invalid_iterator(212, "cannot compare iterators of different containers")); } assert(m_object != nullptr); @@ -9483,7 +9483,7 @@ class basic_json { case basic_json::value_t::object: { - JSON_THROW(std::domain_error("cannot compare order of object iterators")); + JSON_THROW(invalid_iterator(213, "cannot compare order of object iterators")); } case basic_json::value_t::array: @@ -9537,7 +9537,7 @@ class basic_json { case basic_json::value_t::object: { - JSON_THROW(std::domain_error("cannot use offsets with object iterators")); + JSON_THROW(invalid_iterator(209, "cannot use offsets with object iterators")); } case basic_json::value_t::array: @@ -9599,7 +9599,7 @@ class basic_json { case basic_json::value_t::object: { - JSON_THROW(std::domain_error("cannot use offsets with object iterators")); + JSON_THROW(invalid_iterator(209, "cannot use offsets with object iterators")); } case basic_json::value_t::array: @@ -9636,7 +9636,7 @@ class basic_json case basic_json::value_t::null: { - JSON_THROW(std::out_of_range("cannot get value")); + JSON_THROW(invalid_iterator(214, "cannot get value")); } default: @@ -9646,7 +9646,7 @@ class basic_json return *m_object; } - JSON_THROW(std::out_of_range("cannot get value")); + JSON_THROW(invalid_iterator(214, "cannot get value")); } } } diff --git a/src/json.hpp.re2c b/src/json.hpp.re2c index b4e596a2f..e87feb486 100644 --- a/src/json.hpp.re2c +++ b/src/json.hpp.re2c @@ -5755,9 +5755,9 @@ class basic_json example: `"cannot use insert() with string"` @throw invalid_iterator.202 if @a pos is not an iterator of *this; example: `"iterator does not fit current value"` - @throw std::domain_error if @a first and @a last do not belong to the same - JSON value; example: `"iterators do not fit"` - @throw std::domain_error if @a first or @a last are iterators into + @throw invalid_iterator.210 if @a first and @a last do not belong to the + same JSON value; example: `"iterators do not fit"` + @throw invalid_iterator.211 if @a first or @a last are iterators into container for which insert is called; example: `"passed iterators may not belong to container"` @@ -5788,12 +5788,12 @@ class basic_json // check if range iterators belong to the same JSON object if (first.m_object != last.m_object) { - JSON_THROW(std::domain_error("iterators do not fit")); + JSON_THROW(invalid_iterator(210, "iterators do not fit")); } if (first.m_object == this or last.m_object == this) { - JSON_THROW(std::domain_error("passed iterators may not belong to container")); + JSON_THROW(invalid_iterator(211, "passed iterators may not belong to container")); } // insert to array and return iterator @@ -9288,7 +9288,7 @@ class basic_json case basic_json::value_t::null: { - JSON_THROW(std::out_of_range("cannot get value")); + JSON_THROW(invalid_iterator(214, "cannot get value")); } default: @@ -9298,7 +9298,7 @@ class basic_json return *m_object; } - JSON_THROW(std::out_of_range("cannot get value")); + JSON_THROW(invalid_iterator(214, "cannot get value")); } } } @@ -9332,7 +9332,7 @@ class basic_json return m_object; } - JSON_THROW(std::out_of_range("cannot get value")); + JSON_THROW(invalid_iterator(214, "cannot get value")); } } } @@ -9432,7 +9432,7 @@ class basic_json // if objects are not the same, the comparison is undefined if (m_object != other.m_object) { - JSON_THROW(std::domain_error("cannot compare iterators of different containers")); + JSON_THROW(invalid_iterator(212, "cannot compare iterators of different containers")); } assert(m_object != nullptr); @@ -9474,7 +9474,7 @@ class basic_json // if objects are not the same, the comparison is undefined if (m_object != other.m_object) { - JSON_THROW(std::domain_error("cannot compare iterators of different containers")); + JSON_THROW(invalid_iterator(212, "cannot compare iterators of different containers")); } assert(m_object != nullptr); @@ -9483,7 +9483,7 @@ class basic_json { case basic_json::value_t::object: { - JSON_THROW(std::domain_error("cannot compare order of object iterators")); + JSON_THROW(invalid_iterator(213, "cannot compare order of object iterators")); } case basic_json::value_t::array: @@ -9537,7 +9537,7 @@ class basic_json { case basic_json::value_t::object: { - JSON_THROW(std::domain_error("cannot use offsets with object iterators")); + JSON_THROW(invalid_iterator(209, "cannot use offsets with object iterators")); } case basic_json::value_t::array: @@ -9599,7 +9599,7 @@ class basic_json { case basic_json::value_t::object: { - JSON_THROW(std::domain_error("cannot use offsets with object iterators")); + JSON_THROW(invalid_iterator(209, "cannot use offsets with object iterators")); } case basic_json::value_t::array: @@ -9636,7 +9636,7 @@ class basic_json case basic_json::value_t::null: { - JSON_THROW(std::out_of_range("cannot get value")); + JSON_THROW(invalid_iterator(214, "cannot get value")); } default: @@ -9646,7 +9646,7 @@ class basic_json return *m_object; } - JSON_THROW(std::out_of_range("cannot get value")); + JSON_THROW(invalid_iterator(214, "cannot get value")); } } } diff --git a/test/src/unit-algorithms.cpp b/test/src/unit-algorithms.cpp index 8386238a1..494ea83eb 100644 --- a/test/src/unit-algorithms.cpp +++ b/test/src/unit-algorithms.cpp @@ -240,8 +240,9 @@ TEST_CASE("algorithms") SECTION("sorting an object") { json j({{"one", 1}, {"two", 2}}); - CHECK_THROWS_AS(std::sort(j.begin(), j.end()), std::domain_error); - CHECK_THROWS_WITH(std::sort(j.begin(), j.end()), "cannot use offsets with object iterators"); + CHECK_THROWS_AS(std::sort(j.begin(), j.end()), json::invalid_iterator); + CHECK_THROWS_WITH(std::sort(j.begin(), j.end()), + "[json.exception.invalid_iterator.209] cannot use offsets with object iterators"); } } diff --git a/test/src/unit-class_const_iterator.cpp b/test/src/unit-class_const_iterator.cpp index 840549a36..26b312659 100644 --- a/test/src/unit-class_const_iterator.cpp +++ b/test/src/unit-class_const_iterator.cpp @@ -147,8 +147,8 @@ TEST_CASE("const_iterator class") { json j(json::value_t::null); json::const_iterator it = j.cbegin(); - CHECK_THROWS_AS(*it, std::out_of_range); - CHECK_THROWS_WITH(*it, "cannot get value"); + CHECK_THROWS_AS(*it, json::invalid_iterator); + CHECK_THROWS_WITH(*it, "[json.exception.invalid_iterator.214] cannot get value"); } SECTION("number") @@ -157,8 +157,8 @@ TEST_CASE("const_iterator class") json::const_iterator it = j.cbegin(); CHECK(*it == json(17)); it = j.cend(); - CHECK_THROWS_AS(*it, std::out_of_range); - CHECK_THROWS_WITH(*it, "cannot get value"); + CHECK_THROWS_AS(*it, json::invalid_iterator); + CHECK_THROWS_WITH(*it, "[json.exception.invalid_iterator.214] cannot get value"); } SECTION("object") @@ -182,8 +182,8 @@ TEST_CASE("const_iterator class") { json j(json::value_t::null); json::const_iterator it = j.cbegin(); - CHECK_THROWS_AS(it->type_name(), std::out_of_range); - CHECK_THROWS_WITH(it->type_name(), "cannot get value"); + CHECK_THROWS_AS(it->type_name(), json::invalid_iterator); + CHECK_THROWS_WITH(it->type_name(), "[json.exception.invalid_iterator.214] cannot get value"); } SECTION("number") @@ -192,8 +192,8 @@ TEST_CASE("const_iterator class") json::const_iterator it = j.cbegin(); CHECK(it->type_name() == "number"); it = j.cend(); - CHECK_THROWS_AS(it->type_name(), std::out_of_range); - CHECK_THROWS_WITH(it->type_name(), "cannot get value"); + CHECK_THROWS_AS(it->type_name(), json::invalid_iterator); + CHECK_THROWS_WITH(it->type_name(), "[json.exception.invalid_iterator.214] cannot get value"); } SECTION("object") diff --git a/test/src/unit-class_iterator.cpp b/test/src/unit-class_iterator.cpp index 0238c3374..6ff3c369d 100644 --- a/test/src/unit-class_iterator.cpp +++ b/test/src/unit-class_iterator.cpp @@ -131,8 +131,8 @@ TEST_CASE("iterator class") { json j(json::value_t::null); json::iterator it = j.begin(); - CHECK_THROWS_AS(*it, std::out_of_range); - CHECK_THROWS_WITH(*it, "cannot get value"); + CHECK_THROWS_AS(*it, json::invalid_iterator); + CHECK_THROWS_WITH(*it, "[json.exception.invalid_iterator.214] cannot get value"); } SECTION("number") @@ -141,8 +141,8 @@ TEST_CASE("iterator class") json::iterator it = j.begin(); CHECK(*it == json(17)); it = j.end(); - CHECK_THROWS_AS(*it, std::out_of_range); - CHECK_THROWS_WITH(*it, "cannot get value"); + CHECK_THROWS_AS(*it, json::invalid_iterator); + CHECK_THROWS_WITH(*it, "[json.exception.invalid_iterator.214] cannot get value"); } SECTION("object") @@ -166,8 +166,8 @@ TEST_CASE("iterator class") { json j(json::value_t::null); json::iterator it = j.begin(); - CHECK_THROWS_AS(it->type_name(), std::out_of_range); - CHECK_THROWS_WITH(it->type_name(), "cannot get value"); + CHECK_THROWS_AS(it->type_name(), json::invalid_iterator); + CHECK_THROWS_WITH(it->type_name(), "[json.exception.invalid_iterator.214] cannot get value"); } SECTION("number") @@ -176,8 +176,8 @@ TEST_CASE("iterator class") json::iterator it = j.begin(); CHECK(it->type_name() == "number"); it = j.end(); - CHECK_THROWS_AS(it->type_name(), std::out_of_range); - CHECK_THROWS_WITH(it->type_name(), "cannot get value"); + CHECK_THROWS_AS(it->type_name(), json::invalid_iterator); + CHECK_THROWS_WITH(it->type_name(), "[json.exception.invalid_iterator.214] cannot get value"); } SECTION("object") diff --git a/test/src/unit-element_access1.cpp b/test/src/unit-element_access1.cpp index 265f28e11..a521e3c4e 100644 --- a/test/src/unit-element_access1.cpp +++ b/test/src/unit-element_access1.cpp @@ -501,17 +501,17 @@ TEST_CASE("element access 1") { { json j; - CHECK_THROWS_AS(j.front(), std::out_of_range); - CHECK_THROWS_AS(j.back(), std::out_of_range); - CHECK_THROWS_WITH(j.front(), "cannot get value"); - CHECK_THROWS_WITH(j.back(), "cannot get value"); + CHECK_THROWS_AS(j.front(), json::invalid_iterator); + CHECK_THROWS_AS(j.back(), json::invalid_iterator); + CHECK_THROWS_WITH(j.front(), "[json.exception.invalid_iterator.214] cannot get value"); + CHECK_THROWS_WITH(j.back(), "[json.exception.invalid_iterator.214] cannot get value"); } { const json j{}; - CHECK_THROWS_AS(j.front(), std::out_of_range); - CHECK_THROWS_AS(j.back(), std::out_of_range); - CHECK_THROWS_WITH(j.front(), "cannot get value"); - CHECK_THROWS_WITH(j.back(), "cannot get value"); + CHECK_THROWS_AS(j.front(), json::invalid_iterator); + CHECK_THROWS_AS(j.back(), json::invalid_iterator); + CHECK_THROWS_WITH(j.front(), "[json.exception.invalid_iterator.214] cannot get value"); + CHECK_THROWS_WITH(j.back(), "[json.exception.invalid_iterator.214] cannot get value"); } } diff --git a/test/src/unit-iterators1.cpp b/test/src/unit-iterators1.cpp index c1f179fd7..6605076ad 100644 --- a/test/src/unit-iterators1.cpp +++ b/test/src/unit-iterators1.cpp @@ -239,13 +239,13 @@ TEST_CASE("iterators 1") auto rit = j.rend(); auto crit = j.crend(); CHECK_THROWS_AS(rit.key(), json::invalid_iterator); - CHECK_THROWS_AS(rit.value(), std::out_of_range); + CHECK_THROWS_AS(rit.value(), json::invalid_iterator); CHECK_THROWS_AS(crit.key(), json::invalid_iterator); - CHECK_THROWS_AS(crit.value(), std::out_of_range); + CHECK_THROWS_AS(crit.value(), json::invalid_iterator); CHECK_THROWS_WITH(rit.key(), "[json.exception.invalid_iterator.207] cannot use key() for non-object iterators"); - CHECK_THROWS_WITH(rit.value(), "cannot get value"); + CHECK_THROWS_WITH(rit.value(), "[json.exception.invalid_iterator.214] cannot get value"); CHECK_THROWS_WITH(crit.key(), "[json.exception.invalid_iterator.207] cannot use key() for non-object iterators"); - CHECK_THROWS_WITH(crit.value(), "cannot get value"); + CHECK_THROWS_WITH(crit.value(), "[json.exception.invalid_iterator.214] cannot get value"); } } @@ -443,13 +443,13 @@ TEST_CASE("iterators 1") auto rit = j.rend(); auto crit = j.crend(); CHECK_THROWS_AS(rit.key(), json::invalid_iterator); - CHECK_THROWS_AS(rit.value(), std::out_of_range); + CHECK_THROWS_AS(rit.value(), json::invalid_iterator); CHECK_THROWS_AS(crit.key(), json::invalid_iterator); - CHECK_THROWS_AS(crit.value(), std::out_of_range); + CHECK_THROWS_AS(crit.value(), json::invalid_iterator); CHECK_THROWS_WITH(rit.key(), "[json.exception.invalid_iterator.207] cannot use key() for non-object iterators"); - CHECK_THROWS_WITH(rit.value(), "cannot get value"); + CHECK_THROWS_WITH(rit.value(), "[json.exception.invalid_iterator.214] cannot get value"); CHECK_THROWS_WITH(crit.key(), "[json.exception.invalid_iterator.207] cannot use key() for non-object iterators"); - CHECK_THROWS_WITH(crit.value(), "cannot get value"); + CHECK_THROWS_WITH(crit.value(), "[json.exception.invalid_iterator.214] cannot get value"); } } @@ -1017,13 +1017,13 @@ TEST_CASE("iterators 1") auto rit = j.rend(); auto crit = j.crend(); CHECK_THROWS_AS(rit.key(), json::invalid_iterator); - CHECK_THROWS_AS(rit.value(), std::out_of_range); + CHECK_THROWS_AS(rit.value(), json::invalid_iterator); CHECK_THROWS_AS(crit.key(), json::invalid_iterator); - CHECK_THROWS_AS(crit.value(), std::out_of_range); + CHECK_THROWS_AS(crit.value(), json::invalid_iterator); CHECK_THROWS_WITH(rit.key(), "[json.exception.invalid_iterator.207] cannot use key() for non-object iterators"); - CHECK_THROWS_WITH(rit.value(), "cannot get value"); + CHECK_THROWS_WITH(rit.value(), "[json.exception.invalid_iterator.214] cannot get value"); CHECK_THROWS_WITH(crit.key(), "[json.exception.invalid_iterator.207] cannot use key() for non-object iterators"); - CHECK_THROWS_WITH(crit.value(), "cannot get value"); + CHECK_THROWS_WITH(crit.value(), "[json.exception.invalid_iterator.214] cannot get value"); } } @@ -1221,13 +1221,13 @@ TEST_CASE("iterators 1") auto rit = j.rend(); auto crit = j.crend(); CHECK_THROWS_AS(rit.key(), json::invalid_iterator); - CHECK_THROWS_AS(rit.value(), std::out_of_range); + CHECK_THROWS_AS(rit.value(), json::invalid_iterator); CHECK_THROWS_AS(crit.key(), json::invalid_iterator); - CHECK_THROWS_AS(crit.value(), std::out_of_range); + CHECK_THROWS_AS(crit.value(), json::invalid_iterator); CHECK_THROWS_WITH(rit.key(), "[json.exception.invalid_iterator.207] cannot use key() for non-object iterators"); - CHECK_THROWS_WITH(rit.value(), "cannot get value"); + CHECK_THROWS_WITH(rit.value(), "[json.exception.invalid_iterator.214] cannot get value"); CHECK_THROWS_WITH(crit.key(), "[json.exception.invalid_iterator.207] cannot use key() for non-object iterators"); - CHECK_THROWS_WITH(crit.value(), "cannot get value"); + CHECK_THROWS_WITH(crit.value(), "[json.exception.invalid_iterator.214] cannot get value"); } } @@ -1425,13 +1425,13 @@ TEST_CASE("iterators 1") auto rit = j.rend(); auto crit = j.crend(); CHECK_THROWS_AS(rit.key(), json::invalid_iterator); - CHECK_THROWS_AS(rit.value(), std::out_of_range); + CHECK_THROWS_AS(rit.value(), json::invalid_iterator); CHECK_THROWS_AS(crit.key(), json::invalid_iterator); - CHECK_THROWS_AS(crit.value(), std::out_of_range); + CHECK_THROWS_AS(crit.value(), json::invalid_iterator); CHECK_THROWS_WITH(rit.key(), "[json.exception.invalid_iterator.207] cannot use key() for non-object iterators"); - CHECK_THROWS_WITH(rit.value(), "cannot get value"); + CHECK_THROWS_WITH(rit.value(), "[json.exception.invalid_iterator.214] cannot get value"); CHECK_THROWS_WITH(crit.key(), "[json.exception.invalid_iterator.207] cannot use key() for non-object iterators"); - CHECK_THROWS_WITH(crit.value(), "cannot get value"); + CHECK_THROWS_WITH(crit.value(), "[json.exception.invalid_iterator.214] cannot get value"); } } @@ -1490,24 +1490,24 @@ TEST_CASE("iterators 1") auto it = j.begin(); auto cit = j_const.cbegin(); CHECK_THROWS_AS(it.key(), json::invalid_iterator); - CHECK_THROWS_AS(it.value(), std::out_of_range); + CHECK_THROWS_AS(it.value(), json::invalid_iterator); CHECK_THROWS_AS(cit.key(), json::invalid_iterator); - CHECK_THROWS_AS(cit.value(), std::out_of_range); + CHECK_THROWS_AS(cit.value(), json::invalid_iterator); CHECK_THROWS_WITH(it.key(), "[json.exception.invalid_iterator.207] cannot use key() for non-object iterators"); - CHECK_THROWS_WITH(it.value(), "cannot get value"); + CHECK_THROWS_WITH(it.value(), "[json.exception.invalid_iterator.214] cannot get value"); CHECK_THROWS_WITH(cit.key(), "[json.exception.invalid_iterator.207] cannot use key() for non-object iterators"); - CHECK_THROWS_WITH(cit.value(), "cannot get value"); + CHECK_THROWS_WITH(cit.value(), "[json.exception.invalid_iterator.214] cannot get value"); auto rit = j.rend(); auto crit = j.crend(); CHECK_THROWS_AS(rit.key(), json::invalid_iterator); - CHECK_THROWS_AS(rit.value(), std::out_of_range); + CHECK_THROWS_AS(rit.value(), json::invalid_iterator); CHECK_THROWS_AS(crit.key(), json::invalid_iterator); - CHECK_THROWS_AS(crit.value(), std::out_of_range); + CHECK_THROWS_AS(crit.value(), json::invalid_iterator); CHECK_THROWS_WITH(rit.key(), "[json.exception.invalid_iterator.207] cannot use key() for non-object iterators"); - CHECK_THROWS_WITH(rit.value(), "cannot get value"); + CHECK_THROWS_WITH(rit.value(), "[json.exception.invalid_iterator.214] cannot get value"); CHECK_THROWS_WITH(crit.key(), "[json.exception.invalid_iterator.207] cannot use key() for non-object iterators"); - CHECK_THROWS_WITH(crit.value(), "cannot get value"); + CHECK_THROWS_WITH(crit.value(), "[json.exception.invalid_iterator.214] cannot get value"); } } } diff --git a/test/src/unit-iterators2.cpp b/test/src/unit-iterators2.cpp index 63242f1e8..e20417a17 100644 --- a/test/src/unit-iterators2.cpp +++ b/test/src/unit-iterators2.cpp @@ -81,22 +81,22 @@ TEST_CASE("iterators 2") { if (j.type() == json::value_t::object) { - CHECK_THROWS_AS(it1 < it1, std::domain_error); - CHECK_THROWS_AS(it1 < it2, std::domain_error); - CHECK_THROWS_AS(it2 < it3, std::domain_error); - CHECK_THROWS_AS(it1 < it3, std::domain_error); - CHECK_THROWS_AS(it1_c < it1_c, std::domain_error); - CHECK_THROWS_AS(it1_c < it2_c, std::domain_error); - CHECK_THROWS_AS(it2_c < it3_c, std::domain_error); - CHECK_THROWS_AS(it1_c < it3_c, std::domain_error); - CHECK_THROWS_WITH(it1 < it1, "cannot compare order of object iterators"); - CHECK_THROWS_WITH(it1 < it2, "cannot compare order of object iterators"); - CHECK_THROWS_WITH(it2 < it3, "cannot compare order of object iterators"); - CHECK_THROWS_WITH(it1 < it3, "cannot compare order of object iterators"); - CHECK_THROWS_WITH(it1_c < it1_c, "cannot compare order of object iterators"); - CHECK_THROWS_WITH(it1_c < it2_c, "cannot compare order of object iterators"); - CHECK_THROWS_WITH(it2_c < it3_c, "cannot compare order of object iterators"); - CHECK_THROWS_WITH(it1_c < it3_c, "cannot compare order of object iterators"); + CHECK_THROWS_AS(it1 < it1, json::invalid_iterator); + CHECK_THROWS_AS(it1 < it2, json::invalid_iterator); + CHECK_THROWS_AS(it2 < it3, json::invalid_iterator); + CHECK_THROWS_AS(it1 < it3, json::invalid_iterator); + CHECK_THROWS_AS(it1_c < it1_c, json::invalid_iterator); + CHECK_THROWS_AS(it1_c < it2_c, json::invalid_iterator); + CHECK_THROWS_AS(it2_c < it3_c, json::invalid_iterator); + CHECK_THROWS_AS(it1_c < it3_c, json::invalid_iterator); + CHECK_THROWS_WITH(it1 < it1, "[json.exception.invalid_iterator.213] cannot compare order of object iterators"); + CHECK_THROWS_WITH(it1 < it2, "[json.exception.invalid_iterator.213] cannot compare order of object iterators"); + CHECK_THROWS_WITH(it2 < it3, "[json.exception.invalid_iterator.213] cannot compare order of object iterators"); + CHECK_THROWS_WITH(it1 < it3, "[json.exception.invalid_iterator.213] cannot compare order of object iterators"); + CHECK_THROWS_WITH(it1_c < it1_c, "[json.exception.invalid_iterator.213] cannot compare order of object iterators"); + CHECK_THROWS_WITH(it1_c < it2_c, "[json.exception.invalid_iterator.213] cannot compare order of object iterators"); + CHECK_THROWS_WITH(it2_c < it3_c, "[json.exception.invalid_iterator.213] cannot compare order of object iterators"); + CHECK_THROWS_WITH(it1_c < it3_c, "[json.exception.invalid_iterator.213] cannot compare order of object iterators"); } else { @@ -115,22 +115,22 @@ TEST_CASE("iterators 2") { if (j.type() == json::value_t::object) { - CHECK_THROWS_AS(it1 <= it1, std::domain_error); - CHECK_THROWS_AS(it1 <= it2, std::domain_error); - CHECK_THROWS_AS(it2 <= it3, std::domain_error); - CHECK_THROWS_AS(it1 <= it3, std::domain_error); - CHECK_THROWS_AS(it1_c <= it1_c, std::domain_error); - CHECK_THROWS_AS(it1_c <= it2_c, std::domain_error); - CHECK_THROWS_AS(it2_c <= it3_c, std::domain_error); - CHECK_THROWS_AS(it1_c <= it3_c, std::domain_error); - CHECK_THROWS_WITH(it1 <= it1, "cannot compare order of object iterators"); - CHECK_THROWS_WITH(it1 <= it2, "cannot compare order of object iterators"); - CHECK_THROWS_WITH(it2 <= it3, "cannot compare order of object iterators"); - CHECK_THROWS_WITH(it1 <= it3, "cannot compare order of object iterators"); - CHECK_THROWS_WITH(it1_c <= it1_c, "cannot compare order of object iterators"); - CHECK_THROWS_WITH(it1_c <= it2_c, "cannot compare order of object iterators"); - CHECK_THROWS_WITH(it2_c <= it3_c, "cannot compare order of object iterators"); - CHECK_THROWS_WITH(it1_c <= it3_c, "cannot compare order of object iterators"); + CHECK_THROWS_AS(it1 <= it1, json::invalid_iterator); + CHECK_THROWS_AS(it1 <= it2, json::invalid_iterator); + CHECK_THROWS_AS(it2 <= it3, json::invalid_iterator); + CHECK_THROWS_AS(it1 <= it3, json::invalid_iterator); + CHECK_THROWS_AS(it1_c <= it1_c, json::invalid_iterator); + CHECK_THROWS_AS(it1_c <= it2_c, json::invalid_iterator); + CHECK_THROWS_AS(it2_c <= it3_c, json::invalid_iterator); + CHECK_THROWS_AS(it1_c <= it3_c, json::invalid_iterator); + CHECK_THROWS_WITH(it1 <= it1, "[json.exception.invalid_iterator.213] cannot compare order of object iterators"); + CHECK_THROWS_WITH(it1 <= it2, "[json.exception.invalid_iterator.213] cannot compare order of object iterators"); + CHECK_THROWS_WITH(it2 <= it3, "[json.exception.invalid_iterator.213] cannot compare order of object iterators"); + CHECK_THROWS_WITH(it1 <= it3, "[json.exception.invalid_iterator.213] cannot compare order of object iterators"); + CHECK_THROWS_WITH(it1_c <= it1_c, "[json.exception.invalid_iterator.213] cannot compare order of object iterators"); + CHECK_THROWS_WITH(it1_c <= it2_c, "[json.exception.invalid_iterator.213] cannot compare order of object iterators"); + CHECK_THROWS_WITH(it2_c <= it3_c, "[json.exception.invalid_iterator.213] cannot compare order of object iterators"); + CHECK_THROWS_WITH(it1_c <= it3_c, "[json.exception.invalid_iterator.213] cannot compare order of object iterators"); } else { @@ -150,22 +150,22 @@ TEST_CASE("iterators 2") { if (j.type() == json::value_t::object) { - CHECK_THROWS_AS(it1 > it1, std::domain_error); - CHECK_THROWS_AS(it1 > it2, std::domain_error); - CHECK_THROWS_AS(it2 > it3, std::domain_error); - CHECK_THROWS_AS(it1 > it3, std::domain_error); - CHECK_THROWS_AS(it1_c > it1_c, std::domain_error); - CHECK_THROWS_AS(it1_c > it2_c, std::domain_error); - CHECK_THROWS_AS(it2_c > it3_c, std::domain_error); - CHECK_THROWS_AS(it1_c > it3_c, std::domain_error); - CHECK_THROWS_WITH(it1 > it1, "cannot compare order of object iterators"); - CHECK_THROWS_WITH(it1 > it2, "cannot compare order of object iterators"); - CHECK_THROWS_WITH(it2 > it3, "cannot compare order of object iterators"); - CHECK_THROWS_WITH(it1 > it3, "cannot compare order of object iterators"); - CHECK_THROWS_WITH(it1_c > it1_c, "cannot compare order of object iterators"); - CHECK_THROWS_WITH(it1_c > it2_c, "cannot compare order of object iterators"); - CHECK_THROWS_WITH(it2_c > it3_c, "cannot compare order of object iterators"); - CHECK_THROWS_WITH(it1_c > it3_c, "cannot compare order of object iterators"); + CHECK_THROWS_AS(it1 > it1, json::invalid_iterator); + CHECK_THROWS_AS(it1 > it2, json::invalid_iterator); + CHECK_THROWS_AS(it2 > it3, json::invalid_iterator); + CHECK_THROWS_AS(it1 > it3, json::invalid_iterator); + CHECK_THROWS_AS(it1_c > it1_c, json::invalid_iterator); + CHECK_THROWS_AS(it1_c > it2_c, json::invalid_iterator); + CHECK_THROWS_AS(it2_c > it3_c, json::invalid_iterator); + CHECK_THROWS_AS(it1_c > it3_c, json::invalid_iterator); + CHECK_THROWS_WITH(it1 > it1, "[json.exception.invalid_iterator.213] cannot compare order of object iterators"); + CHECK_THROWS_WITH(it1 > it2, "[json.exception.invalid_iterator.213] cannot compare order of object iterators"); + CHECK_THROWS_WITH(it2 > it3, "[json.exception.invalid_iterator.213] cannot compare order of object iterators"); + CHECK_THROWS_WITH(it1 > it3, "[json.exception.invalid_iterator.213] cannot compare order of object iterators"); + CHECK_THROWS_WITH(it1_c > it1_c, "[json.exception.invalid_iterator.213] cannot compare order of object iterators"); + CHECK_THROWS_WITH(it1_c > it2_c, "[json.exception.invalid_iterator.213] cannot compare order of object iterators"); + CHECK_THROWS_WITH(it2_c > it3_c, "[json.exception.invalid_iterator.213] cannot compare order of object iterators"); + CHECK_THROWS_WITH(it1_c > it3_c, "[json.exception.invalid_iterator.213] cannot compare order of object iterators"); } else { @@ -185,22 +185,22 @@ TEST_CASE("iterators 2") { if (j.type() == json::value_t::object) { - CHECK_THROWS_AS(it1 >= it1, std::domain_error); - CHECK_THROWS_AS(it1 >= it2, std::domain_error); - CHECK_THROWS_AS(it2 >= it3, std::domain_error); - CHECK_THROWS_AS(it1 >= it3, std::domain_error); - CHECK_THROWS_AS(it1_c >= it1_c, std::domain_error); - CHECK_THROWS_AS(it1_c >= it2_c, std::domain_error); - CHECK_THROWS_AS(it2_c >= it3_c, std::domain_error); - CHECK_THROWS_AS(it1_c >= it3_c, std::domain_error); - CHECK_THROWS_WITH(it1 >= it1, "cannot compare order of object iterators"); - CHECK_THROWS_WITH(it1 >= it2, "cannot compare order of object iterators"); - CHECK_THROWS_WITH(it2 >= it3, "cannot compare order of object iterators"); - CHECK_THROWS_WITH(it1 >= it3, "cannot compare order of object iterators"); - CHECK_THROWS_WITH(it1_c >= it1_c, "cannot compare order of object iterators"); - CHECK_THROWS_WITH(it1_c >= it2_c, "cannot compare order of object iterators"); - CHECK_THROWS_WITH(it2_c >= it3_c, "cannot compare order of object iterators"); - CHECK_THROWS_WITH(it1_c >= it3_c, "cannot compare order of object iterators"); + CHECK_THROWS_AS(it1 >= it1, json::invalid_iterator); + CHECK_THROWS_AS(it1 >= it2, json::invalid_iterator); + CHECK_THROWS_AS(it2 >= it3, json::invalid_iterator); + CHECK_THROWS_AS(it1 >= it3, json::invalid_iterator); + CHECK_THROWS_AS(it1_c >= it1_c, json::invalid_iterator); + CHECK_THROWS_AS(it1_c >= it2_c, json::invalid_iterator); + CHECK_THROWS_AS(it2_c >= it3_c, json::invalid_iterator); + CHECK_THROWS_AS(it1_c >= it3_c, json::invalid_iterator); + CHECK_THROWS_WITH(it1 >= it1, "[json.exception.invalid_iterator.213] cannot compare order of object iterators"); + CHECK_THROWS_WITH(it1 >= it2, "[json.exception.invalid_iterator.213] cannot compare order of object iterators"); + CHECK_THROWS_WITH(it2 >= it3, "[json.exception.invalid_iterator.213] cannot compare order of object iterators"); + CHECK_THROWS_WITH(it1 >= it3, "[json.exception.invalid_iterator.213] cannot compare order of object iterators"); + CHECK_THROWS_WITH(it1_c >= it1_c, "[json.exception.invalid_iterator.213] cannot compare order of object iterators"); + CHECK_THROWS_WITH(it1_c >= it2_c, "[json.exception.invalid_iterator.213] cannot compare order of object iterators"); + CHECK_THROWS_WITH(it2_c >= it3_c, "[json.exception.invalid_iterator.213] cannot compare order of object iterators"); + CHECK_THROWS_WITH(it1_c >= it3_c, "[json.exception.invalid_iterator.213] cannot compare order of object iterators"); } else { @@ -224,15 +224,15 @@ TEST_CASE("iterators 2") { if (j != k) { - CHECK_THROWS_AS(j.begin() == k.begin(), std::domain_error); - CHECK_THROWS_AS(j.cbegin() == k.cbegin(), std::domain_error); - CHECK_THROWS_WITH(j.begin() == k.begin(), "cannot compare iterators of different containers"); - CHECK_THROWS_WITH(j.cbegin() == k.cbegin(), "cannot compare iterators of different containers"); + CHECK_THROWS_AS(j.begin() == k.begin(), json::invalid_iterator); + CHECK_THROWS_AS(j.cbegin() == k.cbegin(), json::invalid_iterator); + CHECK_THROWS_WITH(j.begin() == k.begin(), "[json.exception.invalid_iterator.212] cannot compare iterators of different containers"); + CHECK_THROWS_WITH(j.cbegin() == k.cbegin(), "[json.exception.invalid_iterator.212] cannot compare iterators of different containers"); - CHECK_THROWS_AS(j.begin() < k.begin(), std::domain_error); - CHECK_THROWS_AS(j.cbegin() < k.cbegin(), std::domain_error); - CHECK_THROWS_WITH(j.begin() < k.begin(), "cannot compare iterators of different containers"); - CHECK_THROWS_WITH(j.cbegin() < k.cbegin(), "cannot compare iterators of different containers"); + CHECK_THROWS_AS(j.begin() < k.begin(), json::invalid_iterator); + CHECK_THROWS_AS(j.cbegin() < k.cbegin(), json::invalid_iterator); + CHECK_THROWS_WITH(j.begin() < k.begin(), "[json.exception.invalid_iterator.212] cannot compare iterators of different containers"); + CHECK_THROWS_WITH(j.cbegin() < k.cbegin(), "[json.exception.invalid_iterator.212] cannot compare iterators of different containers"); } } } @@ -251,53 +251,53 @@ TEST_CASE("iterators 2") { { auto it = j_object.begin(); - CHECK_THROWS_AS(it += 1, std::domain_error); - CHECK_THROWS_WITH(it += 1, "cannot use offsets with object iterators"); + CHECK_THROWS_AS(it += 1, json::invalid_iterator); + CHECK_THROWS_WITH(it += 1, "[json.exception.invalid_iterator.209] cannot use offsets with object iterators"); } { auto it = j_object.cbegin(); - CHECK_THROWS_AS(it += 1, std::domain_error); - CHECK_THROWS_WITH(it += 1, "cannot use offsets with object iterators"); + CHECK_THROWS_AS(it += 1, json::invalid_iterator); + CHECK_THROWS_WITH(it += 1, "[json.exception.invalid_iterator.209] cannot use offsets with object iterators"); } { auto it = j_object.begin(); - CHECK_THROWS_AS(it + 1, std::domain_error); - CHECK_THROWS_WITH(it + 1, "cannot use offsets with object iterators"); + CHECK_THROWS_AS(it + 1, json::invalid_iterator); + CHECK_THROWS_WITH(it + 1, "[json.exception.invalid_iterator.209] cannot use offsets with object iterators"); } { auto it = j_object.cbegin(); - CHECK_THROWS_AS(it + 1, std::domain_error); - CHECK_THROWS_WITH(it + 1, "cannot use offsets with object iterators"); + CHECK_THROWS_AS(it + 1, json::invalid_iterator); + CHECK_THROWS_WITH(it + 1, "[json.exception.invalid_iterator.209] cannot use offsets with object iterators"); } { auto it = j_object.begin(); - CHECK_THROWS_AS(it -= 1, std::domain_error); - CHECK_THROWS_WITH(it -= 1, "cannot use offsets with object iterators"); + CHECK_THROWS_AS(it -= 1, json::invalid_iterator); + CHECK_THROWS_WITH(it -= 1, "[json.exception.invalid_iterator.209] cannot use offsets with object iterators"); } { auto it = j_object.cbegin(); - CHECK_THROWS_AS(it -= 1, std::domain_error); - CHECK_THROWS_WITH(it -= 1, "cannot use offsets with object iterators"); + CHECK_THROWS_AS(it -= 1, json::invalid_iterator); + CHECK_THROWS_WITH(it -= 1, "[json.exception.invalid_iterator.209] cannot use offsets with object iterators"); } { auto it = j_object.begin(); - CHECK_THROWS_AS(it - 1, std::domain_error); - CHECK_THROWS_WITH(it - 1, "cannot use offsets with object iterators"); + CHECK_THROWS_AS(it - 1, json::invalid_iterator); + CHECK_THROWS_WITH(it - 1, "[json.exception.invalid_iterator.209] cannot use offsets with object iterators"); } { auto it = j_object.cbegin(); - CHECK_THROWS_AS(it - 1, std::domain_error); - CHECK_THROWS_WITH(it - 1, "cannot use offsets with object iterators"); + CHECK_THROWS_AS(it - 1, json::invalid_iterator); + CHECK_THROWS_WITH(it - 1, "[json.exception.invalid_iterator.209] cannot use offsets with object iterators"); } { auto it = j_object.begin(); - CHECK_THROWS_AS(it - it, std::domain_error); - CHECK_THROWS_WITH(it - it, "cannot use offsets with object iterators"); + CHECK_THROWS_AS(it - it, json::invalid_iterator); + CHECK_THROWS_WITH(it - it, "[json.exception.invalid_iterator.209] cannot use offsets with object iterators"); } { auto it = j_object.cbegin(); - CHECK_THROWS_AS(it - it, std::domain_error); - CHECK_THROWS_WITH(it - it, "cannot use offsets with object iterators"); + CHECK_THROWS_AS(it - it, json::invalid_iterator); + CHECK_THROWS_WITH(it - it, "[json.exception.invalid_iterator.209] cannot use offsets with object iterators"); } } @@ -420,17 +420,17 @@ TEST_CASE("iterators 2") { { auto it = j_null.begin(); - CHECK_THROWS_AS(it[0], std::out_of_range); - CHECK_THROWS_AS(it[1], std::out_of_range); - CHECK_THROWS_WITH(it[0], "cannot get value"); - CHECK_THROWS_WITH(it[1], "cannot get value"); + CHECK_THROWS_AS(it[0], json::invalid_iterator); + CHECK_THROWS_AS(it[1], json::invalid_iterator); + CHECK_THROWS_WITH(it[0], "[json.exception.invalid_iterator.214] cannot get value"); + CHECK_THROWS_WITH(it[1], "[json.exception.invalid_iterator.214] cannot get value"); } { auto it = j_null.cbegin(); - CHECK_THROWS_AS(it[0], std::out_of_range); - CHECK_THROWS_AS(it[1], std::out_of_range); - CHECK_THROWS_WITH(it[0], "cannot get value"); - CHECK_THROWS_WITH(it[1], "cannot get value"); + CHECK_THROWS_AS(it[0], json::invalid_iterator); + CHECK_THROWS_AS(it[1], json::invalid_iterator); + CHECK_THROWS_WITH(it[0], "[json.exception.invalid_iterator.214] cannot get value"); + CHECK_THROWS_WITH(it[1], "[json.exception.invalid_iterator.214] cannot get value"); } } @@ -439,14 +439,14 @@ TEST_CASE("iterators 2") { auto it = j_value.begin(); CHECK(it[0] == json(42)); - CHECK_THROWS_AS(it[1], std::out_of_range); - CHECK_THROWS_WITH(it[1], "cannot get value"); + CHECK_THROWS_AS(it[1], json::invalid_iterator); + CHECK_THROWS_WITH(it[1], "[json.exception.invalid_iterator.214] cannot get value"); } { auto it = j_value.cbegin(); CHECK(it[0] == json(42)); - CHECK_THROWS_AS(it[1], std::out_of_range); - CHECK_THROWS_WITH(it[1], "cannot get value"); + CHECK_THROWS_AS(it[1], json::invalid_iterator); + CHECK_THROWS_WITH(it[1], "[json.exception.invalid_iterator.214] cannot get value"); } } } @@ -500,22 +500,22 @@ TEST_CASE("iterators 2") { if (j.type() == json::value_t::object) { - CHECK_THROWS_AS(it1 < it1, std::domain_error); - CHECK_THROWS_AS(it1 < it2, std::domain_error); - CHECK_THROWS_AS(it2 < it3, std::domain_error); - CHECK_THROWS_AS(it1 < it3, std::domain_error); - CHECK_THROWS_AS(it1_c < it1_c, std::domain_error); - CHECK_THROWS_AS(it1_c < it2_c, std::domain_error); - CHECK_THROWS_AS(it2_c < it3_c, std::domain_error); - CHECK_THROWS_AS(it1_c < it3_c, std::domain_error); - CHECK_THROWS_WITH(it1 < it1, "cannot compare order of object iterators"); - CHECK_THROWS_WITH(it1 < it2, "cannot compare order of object iterators"); - CHECK_THROWS_WITH(it2 < it3, "cannot compare order of object iterators"); - CHECK_THROWS_WITH(it1 < it3, "cannot compare order of object iterators"); - CHECK_THROWS_WITH(it1_c < it1_c, "cannot compare order of object iterators"); - CHECK_THROWS_WITH(it1_c < it2_c, "cannot compare order of object iterators"); - CHECK_THROWS_WITH(it2_c < it3_c, "cannot compare order of object iterators"); - CHECK_THROWS_WITH(it1_c < it3_c, "cannot compare order of object iterators"); + CHECK_THROWS_AS(it1 < it1, json::invalid_iterator); + CHECK_THROWS_AS(it1 < it2, json::invalid_iterator); + CHECK_THROWS_AS(it2 < it3, json::invalid_iterator); + CHECK_THROWS_AS(it1 < it3, json::invalid_iterator); + CHECK_THROWS_AS(it1_c < it1_c, json::invalid_iterator); + CHECK_THROWS_AS(it1_c < it2_c, json::invalid_iterator); + CHECK_THROWS_AS(it2_c < it3_c, json::invalid_iterator); + CHECK_THROWS_AS(it1_c < it3_c, json::invalid_iterator); + CHECK_THROWS_WITH(it1 < it1, "[json.exception.invalid_iterator.213] cannot compare order of object iterators"); + CHECK_THROWS_WITH(it1 < it2, "[json.exception.invalid_iterator.213] cannot compare order of object iterators"); + CHECK_THROWS_WITH(it2 < it3, "[json.exception.invalid_iterator.213] cannot compare order of object iterators"); + CHECK_THROWS_WITH(it1 < it3, "[json.exception.invalid_iterator.213] cannot compare order of object iterators"); + CHECK_THROWS_WITH(it1_c < it1_c, "[json.exception.invalid_iterator.213] cannot compare order of object iterators"); + CHECK_THROWS_WITH(it1_c < it2_c, "[json.exception.invalid_iterator.213] cannot compare order of object iterators"); + CHECK_THROWS_WITH(it2_c < it3_c, "[json.exception.invalid_iterator.213] cannot compare order of object iterators"); + CHECK_THROWS_WITH(it1_c < it3_c, "[json.exception.invalid_iterator.213] cannot compare order of object iterators"); } else { @@ -534,22 +534,22 @@ TEST_CASE("iterators 2") { if (j.type() == json::value_t::object) { - CHECK_THROWS_AS(it1 <= it1, std::domain_error); - CHECK_THROWS_AS(it1 <= it2, std::domain_error); - CHECK_THROWS_AS(it2 <= it3, std::domain_error); - CHECK_THROWS_AS(it1 <= it3, std::domain_error); - CHECK_THROWS_AS(it1_c <= it1_c, std::domain_error); - CHECK_THROWS_AS(it1_c <= it2_c, std::domain_error); - CHECK_THROWS_AS(it2_c <= it3_c, std::domain_error); - CHECK_THROWS_AS(it1_c <= it3_c, std::domain_error); - CHECK_THROWS_WITH(it1 <= it1, "cannot compare order of object iterators"); - CHECK_THROWS_WITH(it1 <= it2, "cannot compare order of object iterators"); - CHECK_THROWS_WITH(it2 <= it3, "cannot compare order of object iterators"); - CHECK_THROWS_WITH(it1 <= it3, "cannot compare order of object iterators"); - CHECK_THROWS_WITH(it1_c <= it1_c, "cannot compare order of object iterators"); - CHECK_THROWS_WITH(it1_c <= it2_c, "cannot compare order of object iterators"); - CHECK_THROWS_WITH(it2_c <= it3_c, "cannot compare order of object iterators"); - CHECK_THROWS_WITH(it1_c <= it3_c, "cannot compare order of object iterators"); + CHECK_THROWS_AS(it1 <= it1, json::invalid_iterator); + CHECK_THROWS_AS(it1 <= it2, json::invalid_iterator); + CHECK_THROWS_AS(it2 <= it3, json::invalid_iterator); + CHECK_THROWS_AS(it1 <= it3, json::invalid_iterator); + CHECK_THROWS_AS(it1_c <= it1_c, json::invalid_iterator); + CHECK_THROWS_AS(it1_c <= it2_c, json::invalid_iterator); + CHECK_THROWS_AS(it2_c <= it3_c, json::invalid_iterator); + CHECK_THROWS_AS(it1_c <= it3_c, json::invalid_iterator); + CHECK_THROWS_WITH(it1 <= it1, "[json.exception.invalid_iterator.213] cannot compare order of object iterators"); + CHECK_THROWS_WITH(it1 <= it2, "[json.exception.invalid_iterator.213] cannot compare order of object iterators"); + CHECK_THROWS_WITH(it2 <= it3, "[json.exception.invalid_iterator.213] cannot compare order of object iterators"); + CHECK_THROWS_WITH(it1 <= it3, "[json.exception.invalid_iterator.213] cannot compare order of object iterators"); + CHECK_THROWS_WITH(it1_c <= it1_c, "[json.exception.invalid_iterator.213] cannot compare order of object iterators"); + CHECK_THROWS_WITH(it1_c <= it2_c, "[json.exception.invalid_iterator.213] cannot compare order of object iterators"); + CHECK_THROWS_WITH(it2_c <= it3_c, "[json.exception.invalid_iterator.213] cannot compare order of object iterators"); + CHECK_THROWS_WITH(it1_c <= it3_c, "[json.exception.invalid_iterator.213] cannot compare order of object iterators"); } else { @@ -569,22 +569,22 @@ TEST_CASE("iterators 2") { if (j.type() == json::value_t::object) { - CHECK_THROWS_AS(it1 > it1, std::domain_error); - CHECK_THROWS_AS(it1 > it2, std::domain_error); - CHECK_THROWS_AS(it2 > it3, std::domain_error); - CHECK_THROWS_AS(it1 > it3, std::domain_error); - CHECK_THROWS_AS(it1_c > it1_c, std::domain_error); - CHECK_THROWS_AS(it1_c > it2_c, std::domain_error); - CHECK_THROWS_AS(it2_c > it3_c, std::domain_error); - CHECK_THROWS_AS(it1_c > it3_c, std::domain_error); - CHECK_THROWS_WITH(it1 > it1, "cannot compare order of object iterators"); - CHECK_THROWS_WITH(it1 > it2, "cannot compare order of object iterators"); - CHECK_THROWS_WITH(it2 > it3, "cannot compare order of object iterators"); - CHECK_THROWS_WITH(it1 > it3, "cannot compare order of object iterators"); - CHECK_THROWS_WITH(it1_c > it1_c, "cannot compare order of object iterators"); - CHECK_THROWS_WITH(it1_c > it2_c, "cannot compare order of object iterators"); - CHECK_THROWS_WITH(it2_c > it3_c, "cannot compare order of object iterators"); - CHECK_THROWS_WITH(it1_c > it3_c, "cannot compare order of object iterators"); + CHECK_THROWS_AS(it1 > it1, json::invalid_iterator); + CHECK_THROWS_AS(it1 > it2, json::invalid_iterator); + CHECK_THROWS_AS(it2 > it3, json::invalid_iterator); + CHECK_THROWS_AS(it1 > it3, json::invalid_iterator); + CHECK_THROWS_AS(it1_c > it1_c, json::invalid_iterator); + CHECK_THROWS_AS(it1_c > it2_c, json::invalid_iterator); + CHECK_THROWS_AS(it2_c > it3_c, json::invalid_iterator); + CHECK_THROWS_AS(it1_c > it3_c, json::invalid_iterator); + CHECK_THROWS_WITH(it1 > it1, "[json.exception.invalid_iterator.213] cannot compare order of object iterators"); + CHECK_THROWS_WITH(it1 > it2, "[json.exception.invalid_iterator.213] cannot compare order of object iterators"); + CHECK_THROWS_WITH(it2 > it3, "[json.exception.invalid_iterator.213] cannot compare order of object iterators"); + CHECK_THROWS_WITH(it1 > it3, "[json.exception.invalid_iterator.213] cannot compare order of object iterators"); + CHECK_THROWS_WITH(it1_c > it1_c, "[json.exception.invalid_iterator.213] cannot compare order of object iterators"); + CHECK_THROWS_WITH(it1_c > it2_c, "[json.exception.invalid_iterator.213] cannot compare order of object iterators"); + CHECK_THROWS_WITH(it2_c > it3_c, "[json.exception.invalid_iterator.213] cannot compare order of object iterators"); + CHECK_THROWS_WITH(it1_c > it3_c, "[json.exception.invalid_iterator.213] cannot compare order of object iterators"); } else { @@ -604,22 +604,22 @@ TEST_CASE("iterators 2") { if (j.type() == json::value_t::object) { - CHECK_THROWS_AS(it1 >= it1, std::domain_error); - CHECK_THROWS_AS(it1 >= it2, std::domain_error); - CHECK_THROWS_AS(it2 >= it3, std::domain_error); - CHECK_THROWS_AS(it1 >= it3, std::domain_error); - CHECK_THROWS_AS(it1_c >= it1_c, std::domain_error); - CHECK_THROWS_AS(it1_c >= it2_c, std::domain_error); - CHECK_THROWS_AS(it2_c >= it3_c, std::domain_error); - CHECK_THROWS_AS(it1_c >= it3_c, std::domain_error); - CHECK_THROWS_WITH(it1 >= it1, "cannot compare order of object iterators"); - CHECK_THROWS_WITH(it1 >= it2, "cannot compare order of object iterators"); - CHECK_THROWS_WITH(it2 >= it3, "cannot compare order of object iterators"); - CHECK_THROWS_WITH(it1 >= it3, "cannot compare order of object iterators"); - CHECK_THROWS_WITH(it1_c >= it1_c, "cannot compare order of object iterators"); - CHECK_THROWS_WITH(it1_c >= it2_c, "cannot compare order of object iterators"); - CHECK_THROWS_WITH(it2_c >= it3_c, "cannot compare order of object iterators"); - CHECK_THROWS_WITH(it1_c >= it3_c, "cannot compare order of object iterators"); + CHECK_THROWS_AS(it1 >= it1, json::invalid_iterator); + CHECK_THROWS_AS(it1 >= it2, json::invalid_iterator); + CHECK_THROWS_AS(it2 >= it3, json::invalid_iterator); + CHECK_THROWS_AS(it1 >= it3, json::invalid_iterator); + CHECK_THROWS_AS(it1_c >= it1_c, json::invalid_iterator); + CHECK_THROWS_AS(it1_c >= it2_c, json::invalid_iterator); + CHECK_THROWS_AS(it2_c >= it3_c, json::invalid_iterator); + CHECK_THROWS_AS(it1_c >= it3_c, json::invalid_iterator); + CHECK_THROWS_WITH(it1 >= it1, "[json.exception.invalid_iterator.213] cannot compare order of object iterators"); + CHECK_THROWS_WITH(it1 >= it2, "[json.exception.invalid_iterator.213] cannot compare order of object iterators"); + CHECK_THROWS_WITH(it2 >= it3, "[json.exception.invalid_iterator.213] cannot compare order of object iterators"); + CHECK_THROWS_WITH(it1 >= it3, "[json.exception.invalid_iterator.213] cannot compare order of object iterators"); + CHECK_THROWS_WITH(it1_c >= it1_c, "[json.exception.invalid_iterator.213] cannot compare order of object iterators"); + CHECK_THROWS_WITH(it1_c >= it2_c, "[json.exception.invalid_iterator.213] cannot compare order of object iterators"); + CHECK_THROWS_WITH(it2_c >= it3_c, "[json.exception.invalid_iterator.213] cannot compare order of object iterators"); + CHECK_THROWS_WITH(it1_c >= it3_c, "[json.exception.invalid_iterator.213] cannot compare order of object iterators"); } else { @@ -643,15 +643,15 @@ TEST_CASE("iterators 2") { if (j != k) { - CHECK_THROWS_AS(j.rbegin() == k.rbegin(), std::domain_error); - CHECK_THROWS_AS(j.crbegin() == k.crbegin(), std::domain_error); - CHECK_THROWS_WITH(j.rbegin() == k.rbegin(), "cannot compare iterators of different containers"); - CHECK_THROWS_WITH(j.crbegin() == k.crbegin(), "cannot compare iterators of different containers"); + CHECK_THROWS_AS(j.rbegin() == k.rbegin(), json::invalid_iterator); + CHECK_THROWS_AS(j.crbegin() == k.crbegin(), json::invalid_iterator); + CHECK_THROWS_WITH(j.rbegin() == k.rbegin(), "[json.exception.invalid_iterator.212] cannot compare iterators of different containers"); + CHECK_THROWS_WITH(j.crbegin() == k.crbegin(), "[json.exception.invalid_iterator.212] cannot compare iterators of different containers"); - CHECK_THROWS_AS(j.rbegin() < k.rbegin(), std::domain_error); - CHECK_THROWS_AS(j.crbegin() < k.crbegin(), std::domain_error); - CHECK_THROWS_WITH(j.rbegin() < k.rbegin(), "cannot compare iterators of different containers"); - CHECK_THROWS_WITH(j.crbegin() < k.crbegin(), "cannot compare iterators of different containers"); + CHECK_THROWS_AS(j.rbegin() < k.rbegin(), json::invalid_iterator); + CHECK_THROWS_AS(j.crbegin() < k.crbegin(), json::invalid_iterator); + CHECK_THROWS_WITH(j.rbegin() < k.rbegin(), "[json.exception.invalid_iterator.212] cannot compare iterators of different containers"); + CHECK_THROWS_WITH(j.crbegin() < k.crbegin(), "[json.exception.invalid_iterator.212] cannot compare iterators of different containers"); } } } @@ -670,53 +670,53 @@ TEST_CASE("iterators 2") { { auto it = j_object.rbegin(); - CHECK_THROWS_AS(it += 1, std::domain_error); - CHECK_THROWS_WITH(it += 1, "cannot use offsets with object iterators"); + CHECK_THROWS_AS(it += 1, json::invalid_iterator); + CHECK_THROWS_WITH(it += 1, "[json.exception.invalid_iterator.209] cannot use offsets with object iterators"); } { auto it = j_object.crbegin(); - CHECK_THROWS_AS(it += 1, std::domain_error); - CHECK_THROWS_WITH(it += 1, "cannot use offsets with object iterators"); + CHECK_THROWS_AS(it += 1, json::invalid_iterator); + CHECK_THROWS_WITH(it += 1, "[json.exception.invalid_iterator.209] cannot use offsets with object iterators"); } { auto it = j_object.rbegin(); - CHECK_THROWS_AS(it + 1, std::domain_error); - CHECK_THROWS_WITH(it + 1, "cannot use offsets with object iterators"); + CHECK_THROWS_AS(it + 1, json::invalid_iterator); + CHECK_THROWS_WITH(it + 1, "[json.exception.invalid_iterator.209] cannot use offsets with object iterators"); } { auto it = j_object.crbegin(); - CHECK_THROWS_AS(it + 1, std::domain_error); - CHECK_THROWS_WITH(it + 1, "cannot use offsets with object iterators"); + CHECK_THROWS_AS(it + 1, json::invalid_iterator); + CHECK_THROWS_WITH(it + 1, "[json.exception.invalid_iterator.209] cannot use offsets with object iterators"); } { auto it = j_object.rbegin(); - CHECK_THROWS_AS(it -= 1, std::domain_error); - CHECK_THROWS_WITH(it -= 1, "cannot use offsets with object iterators"); + CHECK_THROWS_AS(it -= 1, json::invalid_iterator); + CHECK_THROWS_WITH(it -= 1, "[json.exception.invalid_iterator.209] cannot use offsets with object iterators"); } { auto it = j_object.crbegin(); - CHECK_THROWS_AS(it -= 1, std::domain_error); - CHECK_THROWS_WITH(it -= 1, "cannot use offsets with object iterators"); + CHECK_THROWS_AS(it -= 1, json::invalid_iterator); + CHECK_THROWS_WITH(it -= 1, "[json.exception.invalid_iterator.209] cannot use offsets with object iterators"); } { auto it = j_object.rbegin(); - CHECK_THROWS_AS(it - 1, std::domain_error); - CHECK_THROWS_WITH(it - 1, "cannot use offsets with object iterators"); + CHECK_THROWS_AS(it - 1, json::invalid_iterator); + CHECK_THROWS_WITH(it - 1, "[json.exception.invalid_iterator.209] cannot use offsets with object iterators"); } { auto it = j_object.crbegin(); - CHECK_THROWS_AS(it - 1, std::domain_error); - CHECK_THROWS_WITH(it - 1, "cannot use offsets with object iterators"); + CHECK_THROWS_AS(it - 1, json::invalid_iterator); + CHECK_THROWS_WITH(it - 1, "[json.exception.invalid_iterator.209] cannot use offsets with object iterators"); } { auto it = j_object.rbegin(); - CHECK_THROWS_AS(it - it, std::domain_error); - CHECK_THROWS_WITH(it - it, "cannot use offsets with object iterators"); + CHECK_THROWS_AS(it - it, json::invalid_iterator); + CHECK_THROWS_WITH(it - it, "[json.exception.invalid_iterator.209] cannot use offsets with object iterators"); } { auto it = j_object.crbegin(); - CHECK_THROWS_AS(it - it, std::domain_error); - CHECK_THROWS_WITH(it - it, "cannot use offsets with object iterators"); + CHECK_THROWS_AS(it - it, json::invalid_iterator); + CHECK_THROWS_WITH(it - it, "[json.exception.invalid_iterator.209] cannot use offsets with object iterators"); } } @@ -799,17 +799,17 @@ TEST_CASE("iterators 2") { { auto it = j_object.rbegin(); - CHECK_THROWS_AS(it[0], std::domain_error); - CHECK_THROWS_AS(it[1], std::domain_error); - CHECK_THROWS_WITH(it[0], "cannot use offsets with object iterators"); - CHECK_THROWS_WITH(it[1], "cannot use offsets with object iterators"); + CHECK_THROWS_AS(it[0], json::invalid_iterator); + CHECK_THROWS_AS(it[1], json::invalid_iterator); + CHECK_THROWS_WITH(it[0], "[json.exception.invalid_iterator.209] cannot use offsets with object iterators"); + CHECK_THROWS_WITH(it[1], "[json.exception.invalid_iterator.209] cannot use offsets with object iterators"); } { auto it = j_object.crbegin(); - CHECK_THROWS_AS(it[0], std::domain_error); - CHECK_THROWS_AS(it[1], std::domain_error); - CHECK_THROWS_WITH(it[0], "cannot use offsets with object iterators"); - CHECK_THROWS_WITH(it[1], "cannot use offsets with object iterators"); + CHECK_THROWS_AS(it[0], json::invalid_iterator); + CHECK_THROWS_AS(it[1], json::invalid_iterator); + CHECK_THROWS_WITH(it[0], "[json.exception.invalid_iterator.209] cannot use offsets with object iterators"); + CHECK_THROWS_WITH(it[1], "[json.exception.invalid_iterator.209] cannot use offsets with object iterators"); } } @@ -839,17 +839,17 @@ TEST_CASE("iterators 2") { { auto it = j_null.rbegin(); - CHECK_THROWS_AS(it[0], std::out_of_range); - CHECK_THROWS_AS(it[1], std::out_of_range); - CHECK_THROWS_WITH(it[0], "cannot get value"); - CHECK_THROWS_WITH(it[1], "cannot get value"); + CHECK_THROWS_AS(it[0], json::invalid_iterator); + CHECK_THROWS_AS(it[1], json::invalid_iterator); + CHECK_THROWS_WITH(it[0], "[json.exception.invalid_iterator.214] cannot get value"); + CHECK_THROWS_WITH(it[1], "[json.exception.invalid_iterator.214] cannot get value"); } { auto it = j_null.crbegin(); - CHECK_THROWS_AS(it[0], std::out_of_range); - CHECK_THROWS_AS(it[1], std::out_of_range); - CHECK_THROWS_WITH(it[0], "cannot get value"); - CHECK_THROWS_WITH(it[1], "cannot get value"); + CHECK_THROWS_AS(it[0], json::invalid_iterator); + CHECK_THROWS_AS(it[1], json::invalid_iterator); + CHECK_THROWS_WITH(it[0], "[json.exception.invalid_iterator.214] cannot get value"); + CHECK_THROWS_WITH(it[1], "[json.exception.invalid_iterator.214] cannot get value"); } } @@ -858,14 +858,14 @@ TEST_CASE("iterators 2") { auto it = j_value.rbegin(); CHECK(it[0] == json(42)); - CHECK_THROWS_AS(it[1], std::out_of_range); - CHECK_THROWS_WITH(it[1], "cannot get value"); + CHECK_THROWS_AS(it[1], json::invalid_iterator); + CHECK_THROWS_WITH(it[1], "[json.exception.invalid_iterator.214] cannot get value"); } { auto it = j_value.crbegin(); CHECK(it[0] == json(42)); - CHECK_THROWS_AS(it[1], std::out_of_range); - CHECK_THROWS_WITH(it[1], "cannot get value"); + CHECK_THROWS_AS(it[1], json::invalid_iterator); + CHECK_THROWS_WITH(it[1], "[json.exception.invalid_iterator.214] cannot get value"); } } } diff --git a/test/src/unit-modifiers.cpp b/test/src/unit-modifiers.cpp index 005215353..2a3826c25 100644 --- a/test/src/unit-modifiers.cpp +++ b/test/src/unit-modifiers.cpp @@ -616,14 +616,15 @@ TEST_CASE("modifiers") { json j_other_array2 = {"first", "second"}; - CHECK_THROWS_AS(j_array.insert(j_array.end(), j_array.begin(), j_array.end()), std::domain_error); + CHECK_THROWS_AS(j_array.insert(j_array.end(), j_array.begin(), j_array.end()), + json::invalid_iterator); CHECK_THROWS_AS(j_array.insert(j_array.end(), j_other_array.begin(), j_other_array2.end()), - std::domain_error); + json::invalid_iterator); CHECK_THROWS_WITH(j_array.insert(j_array.end(), j_array.begin(), j_array.end()), - "passed iterators may not belong to container"); + "[json.exception.invalid_iterator.211] passed iterators may not belong to container"); CHECK_THROWS_WITH(j_array.insert(j_array.end(), j_other_array.begin(), j_other_array2.end()), - "iterators do not fit"); + "[json.exception.invalid_iterator.210] iterators do not fit"); } } From 068c7acda9822b8b32edeba09de1567303517ac0 Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Sun, 5 Mar 2017 18:40:09 +0100 Subject: [PATCH 09/52] :hammer: added user-defined exceptions 301 --- src/json.hpp | 8 ++++---- src/json.hpp.re2c | 8 ++++---- test/src/unit-constructor1.cpp | 4 ++-- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/json.hpp b/src/json.hpp index 59010a133..508dd805f 100644 --- a/src/json.hpp +++ b/src/json.hpp @@ -2223,8 +2223,8 @@ class basic_json value_t::array and @ref value_t::object are valid); when @a type_deduction is set to `true`, this parameter has no effect - @throw std::domain_error if @a type_deduction is `false`, @a manual_type - is `value_t::object`, but @a init contains an element which is not a pair + @throw type_error.301 if @a type_deduction is `false`, @a manual_type is + `value_t::object`, but @a init contains an element which is not a pair whose first element is a string; example: `"cannot create object from initializer list"` @@ -2264,7 +2264,7 @@ class basic_json // if object is wanted but impossible, throw an exception if (manual_type == value_t::object and not is_an_object) { - JSON_THROW(std::domain_error("cannot create object from initializer list")); + JSON_THROW(type_error(301, "cannot create object from initializer list")); } } @@ -2347,7 +2347,7 @@ class basic_json @return JSON object value - @throw std::domain_error if @a init is not a pair whose first elements are + @throw type_error.301 if @a init is not a pair whose first elements are strings; thrown by @ref basic_json(std::initializer_list, bool, value_t) diff --git a/src/json.hpp.re2c b/src/json.hpp.re2c index e87feb486..03d873af6 100644 --- a/src/json.hpp.re2c +++ b/src/json.hpp.re2c @@ -2223,8 +2223,8 @@ class basic_json value_t::array and @ref value_t::object are valid); when @a type_deduction is set to `true`, this parameter has no effect - @throw std::domain_error if @a type_deduction is `false`, @a manual_type - is `value_t::object`, but @a init contains an element which is not a pair + @throw type_error.301 if @a type_deduction is `false`, @a manual_type is + `value_t::object`, but @a init contains an element which is not a pair whose first element is a string; example: `"cannot create object from initializer list"` @@ -2264,7 +2264,7 @@ class basic_json // if object is wanted but impossible, throw an exception if (manual_type == value_t::object and not is_an_object) { - JSON_THROW(std::domain_error("cannot create object from initializer list")); + JSON_THROW(type_error(301, "cannot create object from initializer list")); } } @@ -2347,7 +2347,7 @@ class basic_json @return JSON object value - @throw std::domain_error if @a init is not a pair whose first elements are + @throw type_error.301 if @a init is not a pair whose first elements are strings; thrown by @ref basic_json(std::initializer_list, bool, value_t) diff --git a/test/src/unit-constructor1.cpp b/test/src/unit-constructor1.cpp index d99855d83..e71c2c460 100644 --- a/test/src/unit-constructor1.cpp +++ b/test/src/unit-constructor1.cpp @@ -943,9 +943,9 @@ TEST_CASE("constructors") SECTION("object with error") { CHECK_THROWS_AS(json::object({ {"one", 1}, {"two", 1u}, {"three", 2.2}, {"four", false}, 13 }), - std::logic_error); + json::type_error); CHECK_THROWS_WITH(json::object({ {"one", 1}, {"two", 1u}, {"three", 2.2}, {"four", false}, 13 }), - "cannot create object from initializer list"); + "[json.exception.type_error.301] cannot create object from initializer list"); } SECTION("empty array") From f473f74fb086a0a497c6ef24655ada1189649d1b Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Sun, 5 Mar 2017 18:56:35 +0100 Subject: [PATCH 10/52] :hammer: added user-defined exceptions 303-304 --- src/json.hpp | 29 ++++++++-------- src/json.hpp.re2c | 29 ++++++++-------- test/src/unit-element_access1.cpp | 56 +++++++++++++++---------------- test/src/unit-element_access2.cpp | 56 +++++++++++++++---------------- 4 files changed, 84 insertions(+), 86 deletions(-) diff --git a/src/json.hpp b/src/json.hpp index 508dd805f..f51c85ad8 100644 --- a/src/json.hpp +++ b/src/json.hpp @@ -3255,7 +3255,7 @@ class basic_json @tparam ThisType will be deduced as `basic_json` or `const basic_json` - @throw std::domain_error if ReferenceType does not match underlying value + @throw type_error.303 if ReferenceType does not match underlying value type of the current JSON */ template @@ -3272,8 +3272,7 @@ class basic_json return *ptr; } - JSON_THROW(std::domain_error("incompatible ReferenceType for get_ref, actual type is " + - obj.type_name())); + JSON_THROW(type_error(303, "incompatible ReferenceType for get_ref, actual type is " + obj.type_name())); } public: @@ -3554,8 +3553,8 @@ class basic_json reference type @a ReferenceType fits to the JSON value; throws std::domain_error otherwise - @throw std::domain_error in case passed type @a ReferenceType is - incompatible with the stored JSON value + @throw type_error.303 in case passed type @a ReferenceType is incompatible + with the stored JSON value @complexity Constant. @@ -3646,8 +3645,8 @@ class basic_json @return reference to the element at index @a idx - @throw std::domain_error if the JSON value is not an array; example: - `"cannot use at() with string"` + @throw type_error.304 if the JSON value is not an array; example: `"cannot + use at() with string"` @throw std::out_of_range if the index @a idx is out of range of the array; that is, `idx >= size()`; example: `"array index 7 is out of range"` @@ -3675,7 +3674,7 @@ class basic_json } else { - JSON_THROW(std::domain_error("cannot use at() with " + type_name())); + JSON_THROW(type_error(304, "cannot use at() with " + type_name())); } } @@ -3689,8 +3688,8 @@ class basic_json @return const reference to the element at index @a idx - @throw std::domain_error if the JSON value is not an array; example: - `"cannot use at() with string"` + @throw type_error.304 if the JSON value is not an array; example: `"cannot + use at() with string"` @throw std::out_of_range if the index @a idx is out of range of the array; that is, `idx >= size()`; example: `"array index 7 is out of range"` @@ -3718,7 +3717,7 @@ class basic_json } else { - JSON_THROW(std::domain_error("cannot use at() with " + type_name())); + JSON_THROW(type_error(304, "cannot use at() with " + type_name())); } } @@ -3732,7 +3731,7 @@ class basic_json @return reference to the element at key @a key - @throw std::domain_error if the JSON value is not an object; example: + @throw type_error.304 if the JSON value is not an object; example: `"cannot use at() with boolean"` @throw std::out_of_range if the key @a key is is not stored in the object; that is, `find(key) == end()`; example: `"key "the fast" not found"` @@ -3765,7 +3764,7 @@ class basic_json } else { - JSON_THROW(std::domain_error("cannot use at() with " + type_name())); + JSON_THROW(type_error(304, "cannot use at() with " + type_name())); } } @@ -3779,7 +3778,7 @@ class basic_json @return const reference to the element at key @a key - @throw std::domain_error if the JSON value is not an object; example: + @throw type_error.304 if the JSON value is not an object; example: `"cannot use at() with boolean"` @throw std::out_of_range if the key @a key is is not stored in the object; that is, `find(key) == end()`; example: `"key "the fast" not found"` @@ -3812,7 +3811,7 @@ class basic_json } else { - JSON_THROW(std::domain_error("cannot use at() with " + type_name())); + JSON_THROW(type_error(304, "cannot use at() with " + type_name())); } } diff --git a/src/json.hpp.re2c b/src/json.hpp.re2c index 03d873af6..1e136f2ce 100644 --- a/src/json.hpp.re2c +++ b/src/json.hpp.re2c @@ -3255,7 +3255,7 @@ class basic_json @tparam ThisType will be deduced as `basic_json` or `const basic_json` - @throw std::domain_error if ReferenceType does not match underlying value + @throw type_error.303 if ReferenceType does not match underlying value type of the current JSON */ template @@ -3272,8 +3272,7 @@ class basic_json return *ptr; } - JSON_THROW(std::domain_error("incompatible ReferenceType for get_ref, actual type is " + - obj.type_name())); + JSON_THROW(type_error(303, "incompatible ReferenceType for get_ref, actual type is " + obj.type_name())); } public: @@ -3554,8 +3553,8 @@ class basic_json reference type @a ReferenceType fits to the JSON value; throws std::domain_error otherwise - @throw std::domain_error in case passed type @a ReferenceType is - incompatible with the stored JSON value + @throw type_error.303 in case passed type @a ReferenceType is incompatible + with the stored JSON value @complexity Constant. @@ -3646,8 +3645,8 @@ class basic_json @return reference to the element at index @a idx - @throw std::domain_error if the JSON value is not an array; example: - `"cannot use at() with string"` + @throw type_error.304 if the JSON value is not an array; example: `"cannot + use at() with string"` @throw std::out_of_range if the index @a idx is out of range of the array; that is, `idx >= size()`; example: `"array index 7 is out of range"` @@ -3675,7 +3674,7 @@ class basic_json } else { - JSON_THROW(std::domain_error("cannot use at() with " + type_name())); + JSON_THROW(type_error(304, "cannot use at() with " + type_name())); } } @@ -3689,8 +3688,8 @@ class basic_json @return const reference to the element at index @a idx - @throw std::domain_error if the JSON value is not an array; example: - `"cannot use at() with string"` + @throw type_error.304 if the JSON value is not an array; example: `"cannot + use at() with string"` @throw std::out_of_range if the index @a idx is out of range of the array; that is, `idx >= size()`; example: `"array index 7 is out of range"` @@ -3718,7 +3717,7 @@ class basic_json } else { - JSON_THROW(std::domain_error("cannot use at() with " + type_name())); + JSON_THROW(type_error(304, "cannot use at() with " + type_name())); } } @@ -3732,7 +3731,7 @@ class basic_json @return reference to the element at key @a key - @throw std::domain_error if the JSON value is not an object; example: + @throw type_error.304 if the JSON value is not an object; example: `"cannot use at() with boolean"` @throw std::out_of_range if the key @a key is is not stored in the object; that is, `find(key) == end()`; example: `"key "the fast" not found"` @@ -3765,7 +3764,7 @@ class basic_json } else { - JSON_THROW(std::domain_error("cannot use at() with " + type_name())); + JSON_THROW(type_error(304, "cannot use at() with " + type_name())); } } @@ -3779,7 +3778,7 @@ class basic_json @return const reference to the element at key @a key - @throw std::domain_error if the JSON value is not an object; example: + @throw type_error.304 if the JSON value is not an object; example: `"cannot use at() with boolean"` @throw std::out_of_range if the key @a key is is not stored in the object; that is, `find(key) == end()`; example: `"key "the fast" not found"` @@ -3812,7 +3811,7 @@ class basic_json } else { - JSON_THROW(std::domain_error("cannot use at() with " + type_name())); + JSON_THROW(type_error(304, "cannot use at() with " + type_name())); } } diff --git a/test/src/unit-element_access1.cpp b/test/src/unit-element_access1.cpp index a521e3c4e..baea8f2a4 100644 --- a/test/src/unit-element_access1.cpp +++ b/test/src/unit-element_access1.cpp @@ -76,77 +76,77 @@ TEST_CASE("element access 1") { json j_nonarray(json::value_t::null); const json j_nonarray_const(j_nonarray); - CHECK_THROWS_AS(j_nonarray.at(0), std::domain_error); - CHECK_THROWS_AS(j_nonarray_const.at(0), std::domain_error); + CHECK_THROWS_AS(j_nonarray.at(0), json::type_error); + CHECK_THROWS_AS(j_nonarray_const.at(0), json::type_error); - CHECK_THROWS_WITH(j_nonarray.at(0), "cannot use at() with null"); - CHECK_THROWS_WITH(j_nonarray_const.at(0), "cannot use at() with null"); + CHECK_THROWS_WITH(j_nonarray.at(0), "[json.exception.type_error.304] cannot use at() with null"); + CHECK_THROWS_WITH(j_nonarray_const.at(0), "[json.exception.type_error.304] cannot use at() with null"); } SECTION("boolean") { json j_nonarray(json::value_t::boolean); const json j_nonarray_const(j_nonarray); - CHECK_THROWS_AS(j_nonarray.at(0), std::domain_error); - CHECK_THROWS_AS(j_nonarray_const.at(0), std::domain_error); + CHECK_THROWS_AS(j_nonarray.at(0), json::type_error); + CHECK_THROWS_AS(j_nonarray_const.at(0), json::type_error); - CHECK_THROWS_WITH(j_nonarray.at(0), "cannot use at() with boolean"); - CHECK_THROWS_WITH(j_nonarray_const.at(0), "cannot use at() with boolean"); + CHECK_THROWS_WITH(j_nonarray.at(0), "[json.exception.type_error.304] cannot use at() with boolean"); + CHECK_THROWS_WITH(j_nonarray_const.at(0), "[json.exception.type_error.304] cannot use at() with boolean"); } SECTION("string") { json j_nonarray(json::value_t::string); const json j_nonarray_const(j_nonarray); - CHECK_THROWS_AS(j_nonarray.at(0), std::domain_error); - CHECK_THROWS_AS(j_nonarray_const.at(0), std::domain_error); + CHECK_THROWS_AS(j_nonarray.at(0), json::type_error); + CHECK_THROWS_AS(j_nonarray_const.at(0), json::type_error); - CHECK_THROWS_WITH(j_nonarray.at(0), "cannot use at() with string"); - CHECK_THROWS_WITH(j_nonarray_const.at(0), "cannot use at() with string"); + CHECK_THROWS_WITH(j_nonarray.at(0), "[json.exception.type_error.304] cannot use at() with string"); + CHECK_THROWS_WITH(j_nonarray_const.at(0), "[json.exception.type_error.304] cannot use at() with string"); } SECTION("object") { json j_nonarray(json::value_t::object); const json j_nonarray_const(j_nonarray); - CHECK_THROWS_AS(j_nonarray.at(0), std::domain_error); - CHECK_THROWS_AS(j_nonarray_const.at(0), std::domain_error); + CHECK_THROWS_AS(j_nonarray.at(0), json::type_error); + CHECK_THROWS_AS(j_nonarray_const.at(0), json::type_error); - CHECK_THROWS_WITH(j_nonarray.at(0), "cannot use at() with object"); - CHECK_THROWS_WITH(j_nonarray_const.at(0), "cannot use at() with object"); + CHECK_THROWS_WITH(j_nonarray.at(0), "[json.exception.type_error.304] cannot use at() with object"); + CHECK_THROWS_WITH(j_nonarray_const.at(0), "[json.exception.type_error.304] cannot use at() with object"); } SECTION("number (integer)") { json j_nonarray(json::value_t::number_integer); const json j_nonarray_const(j_nonarray); - CHECK_THROWS_AS(j_nonarray.at(0), std::domain_error); - CHECK_THROWS_AS(j_nonarray_const.at(0), std::domain_error); + CHECK_THROWS_AS(j_nonarray.at(0), json::type_error); + CHECK_THROWS_AS(j_nonarray_const.at(0), json::type_error); - CHECK_THROWS_WITH(j_nonarray.at(0), "cannot use at() with number"); - CHECK_THROWS_WITH(j_nonarray_const.at(0), "cannot use at() with number"); + CHECK_THROWS_WITH(j_nonarray.at(0), "[json.exception.type_error.304] cannot use at() with number"); + CHECK_THROWS_WITH(j_nonarray_const.at(0), "[json.exception.type_error.304] cannot use at() with number"); } SECTION("number (unsigned)") { json j_nonarray(json::value_t::number_unsigned); const json j_nonarray_const(j_nonarray); - CHECK_THROWS_AS(j_nonarray.at(0), std::domain_error); - CHECK_THROWS_AS(j_nonarray_const.at(0), std::domain_error); + CHECK_THROWS_AS(j_nonarray.at(0), json::type_error); + CHECK_THROWS_AS(j_nonarray_const.at(0), json::type_error); - CHECK_THROWS_WITH(j_nonarray.at(0), "cannot use at() with number"); - CHECK_THROWS_WITH(j_nonarray_const.at(0), "cannot use at() with number"); + CHECK_THROWS_WITH(j_nonarray.at(0), "[json.exception.type_error.304] cannot use at() with number"); + CHECK_THROWS_WITH(j_nonarray_const.at(0), "[json.exception.type_error.304] cannot use at() with number"); } SECTION("number (floating-point)") { json j_nonarray(json::value_t::number_float); const json j_nonarray_const(j_nonarray); - CHECK_THROWS_AS(j_nonarray.at(0), std::domain_error); - CHECK_THROWS_AS(j_nonarray_const.at(0), std::domain_error); + CHECK_THROWS_AS(j_nonarray.at(0), json::type_error); + CHECK_THROWS_AS(j_nonarray_const.at(0), json::type_error); - CHECK_THROWS_WITH(j_nonarray.at(0), "cannot use at() with number"); - CHECK_THROWS_WITH(j_nonarray_const.at(0), "cannot use at() with number"); + CHECK_THROWS_WITH(j_nonarray.at(0), "[json.exception.type_error.304] cannot use at() with number"); + CHECK_THROWS_WITH(j_nonarray_const.at(0), "[json.exception.type_error.304] cannot use at() with number"); } } } diff --git a/test/src/unit-element_access2.cpp b/test/src/unit-element_access2.cpp index 3c3122f1c..c4de9d430 100644 --- a/test/src/unit-element_access2.cpp +++ b/test/src/unit-element_access2.cpp @@ -75,70 +75,70 @@ TEST_CASE("element access 2") { json j_nonobject(json::value_t::null); const json j_nonobject_const(j_nonobject); - CHECK_THROWS_AS(j_nonobject.at("foo"), std::domain_error); - CHECK_THROWS_AS(j_nonobject_const.at("foo"), std::domain_error); - CHECK_THROWS_WITH(j_nonobject.at("foo"), "cannot use at() with null"); - CHECK_THROWS_WITH(j_nonobject_const.at("foo"), "cannot use at() with null"); + CHECK_THROWS_AS(j_nonobject.at("foo"), json::type_error); + CHECK_THROWS_AS(j_nonobject_const.at("foo"), json::type_error); + CHECK_THROWS_WITH(j_nonobject.at("foo"), "[json.exception.type_error.304] cannot use at() with null"); + CHECK_THROWS_WITH(j_nonobject_const.at("foo"), "[json.exception.type_error.304] cannot use at() with null"); } SECTION("boolean") { json j_nonobject(json::value_t::boolean); const json j_nonobject_const(j_nonobject); - CHECK_THROWS_AS(j_nonobject.at("foo"), std::domain_error); - CHECK_THROWS_AS(j_nonobject_const.at("foo"), std::domain_error); - CHECK_THROWS_WITH(j_nonobject.at("foo"), "cannot use at() with boolean"); - CHECK_THROWS_WITH(j_nonobject_const.at("foo"), "cannot use at() with boolean"); + CHECK_THROWS_AS(j_nonobject.at("foo"), json::type_error); + CHECK_THROWS_AS(j_nonobject_const.at("foo"), json::type_error); + CHECK_THROWS_WITH(j_nonobject.at("foo"), "[json.exception.type_error.304] cannot use at() with boolean"); + CHECK_THROWS_WITH(j_nonobject_const.at("foo"), "[json.exception.type_error.304] cannot use at() with boolean"); } SECTION("string") { json j_nonobject(json::value_t::string); const json j_nonobject_const(j_nonobject); - CHECK_THROWS_AS(j_nonobject.at("foo"), std::domain_error); - CHECK_THROWS_AS(j_nonobject_const.at("foo"), std::domain_error); - CHECK_THROWS_WITH(j_nonobject.at("foo"), "cannot use at() with string"); - CHECK_THROWS_WITH(j_nonobject_const.at("foo"), "cannot use at() with string"); + CHECK_THROWS_AS(j_nonobject.at("foo"), json::type_error); + CHECK_THROWS_AS(j_nonobject_const.at("foo"), json::type_error); + CHECK_THROWS_WITH(j_nonobject.at("foo"), "[json.exception.type_error.304] cannot use at() with string"); + CHECK_THROWS_WITH(j_nonobject_const.at("foo"), "[json.exception.type_error.304] cannot use at() with string"); } SECTION("array") { json j_nonobject(json::value_t::array); const json j_nonobject_const(j_nonobject); - CHECK_THROWS_AS(j_nonobject.at("foo"), std::domain_error); - CHECK_THROWS_AS(j_nonobject_const.at("foo"), std::domain_error); - CHECK_THROWS_WITH(j_nonobject.at("foo"), "cannot use at() with array"); - CHECK_THROWS_WITH(j_nonobject_const.at("foo"), "cannot use at() with array"); + CHECK_THROWS_AS(j_nonobject.at("foo"), json::type_error); + CHECK_THROWS_AS(j_nonobject_const.at("foo"), json::type_error); + CHECK_THROWS_WITH(j_nonobject.at("foo"), "[json.exception.type_error.304] cannot use at() with array"); + CHECK_THROWS_WITH(j_nonobject_const.at("foo"), "[json.exception.type_error.304] cannot use at() with array"); } SECTION("number (integer)") { json j_nonobject(json::value_t::number_integer); const json j_nonobject_const(j_nonobject); - CHECK_THROWS_AS(j_nonobject.at("foo"), std::domain_error); - CHECK_THROWS_AS(j_nonobject_const.at("foo"), std::domain_error); - CHECK_THROWS_WITH(j_nonobject.at("foo"), "cannot use at() with number"); - CHECK_THROWS_WITH(j_nonobject_const.at("foo"), "cannot use at() with number"); + CHECK_THROWS_AS(j_nonobject.at("foo"), json::type_error); + CHECK_THROWS_AS(j_nonobject_const.at("foo"), json::type_error); + CHECK_THROWS_WITH(j_nonobject.at("foo"), "[json.exception.type_error.304] cannot use at() with number"); + CHECK_THROWS_WITH(j_nonobject_const.at("foo"), "[json.exception.type_error.304] cannot use at() with number"); } SECTION("number (unsigned)") { json j_nonobject(json::value_t::number_unsigned); const json j_nonobject_const(j_nonobject); - CHECK_THROWS_AS(j_nonobject.at("foo"), std::domain_error); - CHECK_THROWS_AS(j_nonobject_const.at("foo"), std::domain_error); - CHECK_THROWS_WITH(j_nonobject.at("foo"), "cannot use at() with number"); - CHECK_THROWS_WITH(j_nonobject_const.at("foo"), "cannot use at() with number"); + CHECK_THROWS_AS(j_nonobject.at("foo"), json::type_error); + CHECK_THROWS_AS(j_nonobject_const.at("foo"), json::type_error); + CHECK_THROWS_WITH(j_nonobject.at("foo"), "[json.exception.type_error.304] cannot use at() with number"); + CHECK_THROWS_WITH(j_nonobject_const.at("foo"), "[json.exception.type_error.304] cannot use at() with number"); } SECTION("number (floating-point)") { json j_nonobject(json::value_t::number_float); const json j_nonobject_const(j_nonobject); - CHECK_THROWS_AS(j_nonobject.at("foo"), std::domain_error); - CHECK_THROWS_AS(j_nonobject_const.at("foo"), std::domain_error); - CHECK_THROWS_WITH(j_nonobject.at("foo"), "cannot use at() with number"); - CHECK_THROWS_WITH(j_nonobject_const.at("foo"), "cannot use at() with number"); + CHECK_THROWS_AS(j_nonobject.at("foo"), json::type_error); + CHECK_THROWS_AS(j_nonobject_const.at("foo"), json::type_error); + CHECK_THROWS_WITH(j_nonobject.at("foo"), "[json.exception.type_error.304] cannot use at() with number"); + CHECK_THROWS_WITH(j_nonobject_const.at("foo"), "[json.exception.type_error.304] cannot use at() with number"); } } } From aa842b4a27e9db9e624d4eb8a6da69a27589b6cc Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Sun, 5 Mar 2017 19:08:12 +0100 Subject: [PATCH 11/52] :hammer: added user-defined exceptions 305 --- src/json.hpp | 34 ++++----- src/json.hpp.re2c | 34 ++++----- test/src/unit-element_access1.cpp | 52 +++++++------- test/src/unit-element_access2.cpp | 116 ++++++++++++++++-------------- 4 files changed, 124 insertions(+), 112 deletions(-) diff --git a/src/json.hpp b/src/json.hpp index f51c85ad8..f4bca23df 100644 --- a/src/json.hpp +++ b/src/json.hpp @@ -3828,8 +3828,8 @@ class basic_json @return reference to the element at index @a idx - @throw std::domain_error if JSON is not an array or null; example: - `"cannot use operator[] with string"` + @throw type_error.305 if JSON is not an array or null; example: `"cannot + use operator[] with string" @complexity Constant if @a idx is in the range of the array. Otherwise linear in `idx - size()`. @@ -3864,7 +3864,7 @@ class basic_json return m_value.array->operator[](idx); } - JSON_THROW(std::domain_error("cannot use operator[] with " + type_name())); + JSON_THROW(type_error(305, "cannot use operator[] with " + type_name())); } /*! @@ -3876,7 +3876,7 @@ class basic_json @return const reference to the element at index @a idx - @throw std::domain_error if JSON is not an array; example: `"cannot use + @throw type_error.305 if JSON is not an array; example: `"cannot use operator[] with null"` @complexity Constant. @@ -3894,7 +3894,7 @@ class basic_json return m_value.array->operator[](idx); } - JSON_THROW(std::domain_error("cannot use operator[] with " + type_name())); + JSON_THROW(type_error(305, "cannot use operator[] with " + type_name())); } /*! @@ -3910,8 +3910,8 @@ class basic_json @return reference to the element at key @a key - @throw std::domain_error if JSON is not an object or null; example: - `"cannot use operator[] with string"` + @throw type_error.305 if JSON is not an object or null; example: `"cannot + use operator[] with string"` @complexity Logarithmic in the size of the container. @@ -3940,7 +3940,7 @@ class basic_json return m_value.object->operator[](key); } - JSON_THROW(std::domain_error("cannot use operator[] with " + type_name())); + JSON_THROW(type_error(305, "cannot use operator[] with " + type_name())); } /*! @@ -3959,7 +3959,7 @@ class basic_json @pre The element with key @a key must exist. **This precondition is enforced with an assertion.** - @throw std::domain_error if JSON is not an object; example: `"cannot use + @throw type_error.305 if JSON is not an object; example: `"cannot use operator[] with null"` @complexity Logarithmic in the size of the container. @@ -3982,7 +3982,7 @@ class basic_json return m_value.object->find(key)->second; } - JSON_THROW(std::domain_error("cannot use operator[] with " + type_name())); + JSON_THROW(type_error(305, "cannot use operator[] with " + type_name())); } /*! @@ -3998,8 +3998,8 @@ class basic_json @return reference to the element at key @a key - @throw std::domain_error if JSON is not an object or null; example: - `"cannot use operator[] with string"` + @throw type_error.305 if JSON is not an object or null; example: `"cannot + use operator[] with string"` @complexity Logarithmic in the size of the container. @@ -4066,8 +4066,8 @@ class basic_json @return reference to the element at key @a key - @throw std::domain_error if JSON is not an object or null; example: - `"cannot use operator[] with string"` + @throw type_error.305 if JSON is not an object or null; example: `"cannot + use operator[] with string"` @complexity Logarithmic in the size of the container. @@ -4097,7 +4097,7 @@ class basic_json return m_value.object->operator[](key); } - JSON_THROW(std::domain_error("cannot use operator[] with " + type_name())); + JSON_THROW(type_error(305, "cannot use operator[] with " + type_name())); } /*! @@ -4116,7 +4116,7 @@ class basic_json @pre The element with key @a key must exist. **This precondition is enforced with an assertion.** - @throw std::domain_error if JSON is not an object; example: `"cannot use + @throw type_error.305 if JSON is not an object; example: `"cannot use operator[] with null"` @complexity Logarithmic in the size of the container. @@ -4140,7 +4140,7 @@ class basic_json return m_value.object->find(key)->second; } - JSON_THROW(std::domain_error("cannot use operator[] with " + type_name())); + JSON_THROW(type_error(305, "cannot use operator[] with " + type_name())); } /*! diff --git a/src/json.hpp.re2c b/src/json.hpp.re2c index 1e136f2ce..4ba097afd 100644 --- a/src/json.hpp.re2c +++ b/src/json.hpp.re2c @@ -3828,8 +3828,8 @@ class basic_json @return reference to the element at index @a idx - @throw std::domain_error if JSON is not an array or null; example: - `"cannot use operator[] with string"` + @throw type_error.305 if JSON is not an array or null; example: `"cannot + use operator[] with string" @complexity Constant if @a idx is in the range of the array. Otherwise linear in `idx - size()`. @@ -3864,7 +3864,7 @@ class basic_json return m_value.array->operator[](idx); } - JSON_THROW(std::domain_error("cannot use operator[] with " + type_name())); + JSON_THROW(type_error(305, "cannot use operator[] with " + type_name())); } /*! @@ -3876,7 +3876,7 @@ class basic_json @return const reference to the element at index @a idx - @throw std::domain_error if JSON is not an array; example: `"cannot use + @throw type_error.305 if JSON is not an array; example: `"cannot use operator[] with null"` @complexity Constant. @@ -3894,7 +3894,7 @@ class basic_json return m_value.array->operator[](idx); } - JSON_THROW(std::domain_error("cannot use operator[] with " + type_name())); + JSON_THROW(type_error(305, "cannot use operator[] with " + type_name())); } /*! @@ -3910,8 +3910,8 @@ class basic_json @return reference to the element at key @a key - @throw std::domain_error if JSON is not an object or null; example: - `"cannot use operator[] with string"` + @throw type_error.305 if JSON is not an object or null; example: `"cannot + use operator[] with string"` @complexity Logarithmic in the size of the container. @@ -3940,7 +3940,7 @@ class basic_json return m_value.object->operator[](key); } - JSON_THROW(std::domain_error("cannot use operator[] with " + type_name())); + JSON_THROW(type_error(305, "cannot use operator[] with " + type_name())); } /*! @@ -3959,7 +3959,7 @@ class basic_json @pre The element with key @a key must exist. **This precondition is enforced with an assertion.** - @throw std::domain_error if JSON is not an object; example: `"cannot use + @throw type_error.305 if JSON is not an object; example: `"cannot use operator[] with null"` @complexity Logarithmic in the size of the container. @@ -3982,7 +3982,7 @@ class basic_json return m_value.object->find(key)->second; } - JSON_THROW(std::domain_error("cannot use operator[] with " + type_name())); + JSON_THROW(type_error(305, "cannot use operator[] with " + type_name())); } /*! @@ -3998,8 +3998,8 @@ class basic_json @return reference to the element at key @a key - @throw std::domain_error if JSON is not an object or null; example: - `"cannot use operator[] with string"` + @throw type_error.305 if JSON is not an object or null; example: `"cannot + use operator[] with string"` @complexity Logarithmic in the size of the container. @@ -4066,8 +4066,8 @@ class basic_json @return reference to the element at key @a key - @throw std::domain_error if JSON is not an object or null; example: - `"cannot use operator[] with string"` + @throw type_error.305 if JSON is not an object or null; example: `"cannot + use operator[] with string"` @complexity Logarithmic in the size of the container. @@ -4097,7 +4097,7 @@ class basic_json return m_value.object->operator[](key); } - JSON_THROW(std::domain_error("cannot use operator[] with " + type_name())); + JSON_THROW(type_error(305, "cannot use operator[] with " + type_name())); } /*! @@ -4116,7 +4116,7 @@ class basic_json @pre The element with key @a key must exist. **This precondition is enforced with an assertion.** - @throw std::domain_error if JSON is not an object; example: `"cannot use + @throw type_error.305 if JSON is not an object; example: `"cannot use operator[] with null"` @complexity Logarithmic in the size of the container. @@ -4140,7 +4140,7 @@ class basic_json return m_value.object->find(key)->second; } - JSON_THROW(std::domain_error("cannot use operator[] with " + type_name())); + JSON_THROW(type_error(305, "cannot use operator[] with " + type_name())); } /*! diff --git a/test/src/unit-element_access1.cpp b/test/src/unit-element_access1.cpp index baea8f2a4..37c138bbb 100644 --- a/test/src/unit-element_access1.cpp +++ b/test/src/unit-element_access1.cpp @@ -191,8 +191,8 @@ TEST_CASE("element access 1") json j_nonarray(json::value_t::null); const json j_nonarray_const(j_nonarray); CHECK_NOTHROW(j_nonarray[0]); - CHECK_THROWS_AS(j_nonarray_const[0], std::domain_error); - CHECK_THROWS_WITH(j_nonarray_const[0], "cannot use operator[] with null"); + CHECK_THROWS_AS(j_nonarray_const[0], json::type_error); + CHECK_THROWS_WITH(j_nonarray_const[0], "[json.exception.type_error.305] cannot use operator[] with null"); } SECTION("implicit transformation to properly filled array") @@ -207,60 +207,60 @@ TEST_CASE("element access 1") { json j_nonarray(json::value_t::boolean); const json j_nonarray_const(j_nonarray); - CHECK_THROWS_AS(j_nonarray[0], std::domain_error); - CHECK_THROWS_AS(j_nonarray_const[0], std::domain_error); - CHECK_THROWS_WITH(j_nonarray[0], "cannot use operator[] with boolean"); - CHECK_THROWS_WITH(j_nonarray_const[0], "cannot use operator[] with boolean"); + CHECK_THROWS_AS(j_nonarray[0], json::type_error); + CHECK_THROWS_AS(j_nonarray_const[0], json::type_error); + CHECK_THROWS_WITH(j_nonarray[0], "[json.exception.type_error.305] cannot use operator[] with boolean"); + CHECK_THROWS_WITH(j_nonarray_const[0], "[json.exception.type_error.305] cannot use operator[] with boolean"); } SECTION("string") { json j_nonarray(json::value_t::string); const json j_nonarray_const(j_nonarray); - CHECK_THROWS_AS(j_nonarray[0], std::domain_error); - CHECK_THROWS_AS(j_nonarray_const[0], std::domain_error); - CHECK_THROWS_WITH(j_nonarray[0], "cannot use operator[] with string"); - CHECK_THROWS_WITH(j_nonarray_const[0], "cannot use operator[] with string"); + CHECK_THROWS_AS(j_nonarray[0], json::type_error); + CHECK_THROWS_AS(j_nonarray_const[0], json::type_error); + CHECK_THROWS_WITH(j_nonarray[0], "[json.exception.type_error.305] cannot use operator[] with string"); + CHECK_THROWS_WITH(j_nonarray_const[0], "[json.exception.type_error.305] cannot use operator[] with string"); } SECTION("object") { json j_nonarray(json::value_t::object); const json j_nonarray_const(j_nonarray); - CHECK_THROWS_AS(j_nonarray[0], std::domain_error); - CHECK_THROWS_AS(j_nonarray_const[0], std::domain_error); - CHECK_THROWS_WITH(j_nonarray[0], "cannot use operator[] with object"); - CHECK_THROWS_WITH(j_nonarray_const[0], "cannot use operator[] with object"); + CHECK_THROWS_AS(j_nonarray[0], json::type_error); + CHECK_THROWS_AS(j_nonarray_const[0], json::type_error); + CHECK_THROWS_WITH(j_nonarray[0], "[json.exception.type_error.305] cannot use operator[] with object"); + CHECK_THROWS_WITH(j_nonarray_const[0], "[json.exception.type_error.305] cannot use operator[] with object"); } SECTION("number (integer)") { json j_nonarray(json::value_t::number_integer); const json j_nonarray_const(j_nonarray); - CHECK_THROWS_AS(j_nonarray[0], std::domain_error); - CHECK_THROWS_AS(j_nonarray_const[0], std::domain_error); - CHECK_THROWS_WITH(j_nonarray[0], "cannot use operator[] with number"); - CHECK_THROWS_WITH(j_nonarray_const[0], "cannot use operator[] with number"); + CHECK_THROWS_AS(j_nonarray[0], json::type_error); + CHECK_THROWS_AS(j_nonarray_const[0], json::type_error); + CHECK_THROWS_WITH(j_nonarray[0], "[json.exception.type_error.305] cannot use operator[] with number"); + CHECK_THROWS_WITH(j_nonarray_const[0], "[json.exception.type_error.305] cannot use operator[] with number"); } SECTION("number (unsigned)") { json j_nonarray(json::value_t::number_unsigned); const json j_nonarray_const(j_nonarray); - CHECK_THROWS_AS(j_nonarray[0], std::domain_error); - CHECK_THROWS_AS(j_nonarray_const[0], std::domain_error); - CHECK_THROWS_WITH(j_nonarray[0], "cannot use operator[] with number"); - CHECK_THROWS_WITH(j_nonarray_const[0], "cannot use operator[] with number"); + CHECK_THROWS_AS(j_nonarray[0], json::type_error); + CHECK_THROWS_AS(j_nonarray_const[0], json::type_error); + CHECK_THROWS_WITH(j_nonarray[0], "[json.exception.type_error.305] cannot use operator[] with number"); + CHECK_THROWS_WITH(j_nonarray_const[0], "[json.exception.type_error.305] cannot use operator[] with number"); } SECTION("number (floating-point)") { json j_nonarray(json::value_t::number_float); const json j_nonarray_const(j_nonarray); - CHECK_THROWS_AS(j_nonarray[0], std::domain_error); - CHECK_THROWS_AS(j_nonarray_const[0], std::domain_error); - CHECK_THROWS_WITH(j_nonarray[0], "cannot use operator[] with number"); - CHECK_THROWS_WITH(j_nonarray_const[0], "cannot use operator[] with number"); + CHECK_THROWS_AS(j_nonarray[0], json::type_error); + CHECK_THROWS_AS(j_nonarray_const[0], json::type_error); + CHECK_THROWS_WITH(j_nonarray[0], "[json.exception.type_error.305] cannot use operator[] with number"); + CHECK_THROWS_WITH(j_nonarray_const[0], "[json.exception.type_error.305] cannot use operator[] with number"); } } } diff --git a/test/src/unit-element_access2.cpp b/test/src/unit-element_access2.cpp index c4de9d430..4e34ad924 100644 --- a/test/src/unit-element_access2.cpp +++ b/test/src/unit-element_access2.cpp @@ -447,106 +447,118 @@ TEST_CASE("element access 2") const json j_const_nonobject(j_nonobject); CHECK_NOTHROW(j_nonobject["foo"]); CHECK_NOTHROW(j_nonobject2[json::object_t::key_type("foo")]); - CHECK_THROWS_AS(j_const_nonobject["foo"], std::domain_error); - CHECK_THROWS_AS(j_const_nonobject[json::object_t::key_type("foo")], std::domain_error); - CHECK_THROWS_WITH(j_const_nonobject["foo"], "cannot use operator[] with null"); + CHECK_THROWS_AS(j_const_nonobject["foo"], json::type_error); + CHECK_THROWS_AS(j_const_nonobject[json::object_t::key_type("foo")], json::type_error); + CHECK_THROWS_WITH(j_const_nonobject["foo"], "[json.exception.type_error.305] cannot use operator[] with null"); CHECK_THROWS_WITH(j_const_nonobject[json::object_t::key_type("foo")], - "cannot use operator[] with null"); + "[json.exception.type_error.305] cannot use operator[] with null"); } SECTION("boolean") { json j_nonobject(json::value_t::boolean); const json j_const_nonobject(j_nonobject); - CHECK_THROWS_AS(j_nonobject["foo"], std::domain_error); - CHECK_THROWS_AS(j_nonobject[json::object_t::key_type("foo")], std::domain_error); - CHECK_THROWS_AS(j_const_nonobject["foo"], std::domain_error); - CHECK_THROWS_AS(j_const_nonobject[json::object_t::key_type("foo")], std::domain_error); - CHECK_THROWS_WITH(j_nonobject["foo"], "cannot use operator[] with boolean"); + CHECK_THROWS_AS(j_nonobject["foo"], json::type_error); + CHECK_THROWS_AS(j_nonobject[json::object_t::key_type("foo")], json::type_error); + CHECK_THROWS_AS(j_const_nonobject["foo"], json::type_error); + CHECK_THROWS_AS(j_const_nonobject[json::object_t::key_type("foo")], json::type_error); + CHECK_THROWS_WITH(j_nonobject["foo"], + "[json.exception.type_error.305] cannot use operator[] with boolean"); CHECK_THROWS_WITH(j_nonobject[json::object_t::key_type("foo")], - "cannot use operator[] with boolean"); - CHECK_THROWS_WITH(j_const_nonobject["foo"], "cannot use operator[] with boolean"); + "[json.exception.type_error.305] cannot use operator[] with boolean"); + CHECK_THROWS_WITH(j_const_nonobject["foo"], + "[json.exception.type_error.305] cannot use operator[] with boolean"); CHECK_THROWS_WITH(j_const_nonobject[json::object_t::key_type("foo")], - "cannot use operator[] with boolean"); + "[json.exception.type_error.305] cannot use operator[] with boolean"); } SECTION("string") { json j_nonobject(json::value_t::string); const json j_const_nonobject(j_nonobject); - CHECK_THROWS_AS(j_nonobject["foo"], std::domain_error); - CHECK_THROWS_AS(j_nonobject[json::object_t::key_type("foo")], std::domain_error); - CHECK_THROWS_AS(j_const_nonobject["foo"], std::domain_error); - CHECK_THROWS_AS(j_const_nonobject[json::object_t::key_type("foo")], std::domain_error); - CHECK_THROWS_WITH(j_nonobject["foo"], "cannot use operator[] with string"); + CHECK_THROWS_AS(j_nonobject["foo"], json::type_error); + CHECK_THROWS_AS(j_nonobject[json::object_t::key_type("foo")], json::type_error); + CHECK_THROWS_AS(j_const_nonobject["foo"], json::type_error); + CHECK_THROWS_AS(j_const_nonobject[json::object_t::key_type("foo")], json::type_error); + CHECK_THROWS_WITH(j_nonobject["foo"], + "[json.exception.type_error.305] cannot use operator[] with string"); CHECK_THROWS_WITH(j_nonobject[json::object_t::key_type("foo")], - "cannot use operator[] with string"); - CHECK_THROWS_WITH(j_const_nonobject["foo"], "cannot use operator[] with string"); + "[json.exception.type_error.305] cannot use operator[] with string"); + CHECK_THROWS_WITH(j_const_nonobject["foo"], + "[json.exception.type_error.305] cannot use operator[] with string"); CHECK_THROWS_WITH(j_const_nonobject[json::object_t::key_type("foo")], - "cannot use operator[] with string"); + "[json.exception.type_error.305] cannot use operator[] with string"); } SECTION("array") { json j_nonobject(json::value_t::array); const json j_const_nonobject(j_nonobject); - CHECK_THROWS_AS(j_nonobject["foo"], std::domain_error); - CHECK_THROWS_AS(j_nonobject[json::object_t::key_type("foo")], std::domain_error); - CHECK_THROWS_AS(j_const_nonobject["foo"], std::domain_error); - CHECK_THROWS_AS(j_const_nonobject[json::object_t::key_type("foo")], std::domain_error); - CHECK_THROWS_WITH(j_nonobject["foo"], "cannot use operator[] with array"); - CHECK_THROWS_WITH(j_nonobject[json::object_t::key_type("foo")], "cannot use operator[] with array"); - CHECK_THROWS_WITH(j_const_nonobject["foo"], "cannot use operator[] with array"); + CHECK_THROWS_AS(j_nonobject["foo"], json::type_error); + CHECK_THROWS_AS(j_nonobject[json::object_t::key_type("foo")], json::type_error); + CHECK_THROWS_AS(j_const_nonobject["foo"], json::type_error); + CHECK_THROWS_AS(j_const_nonobject[json::object_t::key_type("foo")], json::type_error); + CHECK_THROWS_WITH(j_nonobject["foo"], + "[json.exception.type_error.305] cannot use operator[] with array"); + CHECK_THROWS_WITH(j_nonobject[json::object_t::key_type("foo")], "[json.exception.type_error.305] cannot use operator[] with array"); + CHECK_THROWS_WITH(j_const_nonobject["foo"], + "[json.exception.type_error.305] cannot use operator[] with array"); CHECK_THROWS_WITH(j_const_nonobject[json::object_t::key_type("foo")], - "cannot use operator[] with array"); + "[json.exception.type_error.305] cannot use operator[] with array"); } SECTION("number (integer)") { json j_nonobject(json::value_t::number_integer); const json j_const_nonobject(j_nonobject); - CHECK_THROWS_AS(j_nonobject["foo"], std::domain_error); - CHECK_THROWS_AS(j_nonobject[json::object_t::key_type("foo")], std::domain_error); - CHECK_THROWS_AS(j_const_nonobject["foo"], std::domain_error); - CHECK_THROWS_AS(j_const_nonobject[json::object_t::key_type("foo")], std::domain_error); - CHECK_THROWS_WITH(j_nonobject["foo"], "cannot use operator[] with number"); + CHECK_THROWS_AS(j_nonobject["foo"], json::type_error); + CHECK_THROWS_AS(j_nonobject[json::object_t::key_type("foo")], json::type_error); + CHECK_THROWS_AS(j_const_nonobject["foo"], json::type_error); + CHECK_THROWS_AS(j_const_nonobject[json::object_t::key_type("foo")], json::type_error); + CHECK_THROWS_WITH(j_nonobject["foo"], + "[json.exception.type_error.305] cannot use operator[] with number"); CHECK_THROWS_WITH(j_nonobject[json::object_t::key_type("foo")], - "cannot use operator[] with number"); - CHECK_THROWS_WITH(j_const_nonobject["foo"], "cannot use operator[] with number"); + "[json.exception.type_error.305] cannot use operator[] with number"); + CHECK_THROWS_WITH(j_const_nonobject["foo"], + "[json.exception.type_error.305] cannot use operator[] with number"); CHECK_THROWS_WITH(j_const_nonobject[json::object_t::key_type("foo")], - "cannot use operator[] with number"); + "[json.exception.type_error.305] cannot use operator[] with number"); } SECTION("number (unsigned)") { json j_nonobject(json::value_t::number_unsigned); const json j_const_nonobject(j_nonobject); - CHECK_THROWS_AS(j_nonobject["foo"], std::domain_error); - CHECK_THROWS_AS(j_nonobject[json::object_t::key_type("foo")], std::domain_error); - CHECK_THROWS_AS(j_const_nonobject["foo"], std::domain_error); - CHECK_THROWS_AS(j_const_nonobject[json::object_t::key_type("foo")], std::domain_error); - CHECK_THROWS_WITH(j_nonobject["foo"], "cannot use operator[] with number"); + CHECK_THROWS_AS(j_nonobject["foo"], json::type_error); + CHECK_THROWS_AS(j_nonobject[json::object_t::key_type("foo")], json::type_error); + CHECK_THROWS_AS(j_const_nonobject["foo"], json::type_error); + CHECK_THROWS_AS(j_const_nonobject[json::object_t::key_type("foo")], json::type_error); + CHECK_THROWS_WITH(j_nonobject["foo"], + "[json.exception.type_error.305] cannot use operator[] with number"); CHECK_THROWS_WITH(j_nonobject[json::object_t::key_type("foo")], - "cannot use operator[] with number"); - CHECK_THROWS_WITH(j_const_nonobject["foo"], "cannot use operator[] with number"); + "[json.exception.type_error.305] cannot use operator[] with number"); + CHECK_THROWS_WITH(j_const_nonobject["foo"], + "[json.exception.type_error.305] cannot use operator[] with number"); CHECK_THROWS_WITH(j_const_nonobject[json::object_t::key_type("foo")], - "cannot use operator[] with number"); + "[json.exception.type_error.305] cannot use operator[] with number"); } SECTION("number (floating-point)") { json j_nonobject(json::value_t::number_float); const json j_const_nonobject(j_nonobject); - CHECK_THROWS_AS(j_nonobject["foo"], std::domain_error); - CHECK_THROWS_AS(j_nonobject[json::object_t::key_type("foo")], std::domain_error); - CHECK_THROWS_AS(j_const_nonobject["foo"], std::domain_error); - CHECK_THROWS_AS(j_const_nonobject[json::object_t::key_type("foo")], std::domain_error); - CHECK_THROWS_WITH(j_nonobject["foo"], "cannot use operator[] with number"); + CHECK_THROWS_AS(j_nonobject["foo"], json::type_error); + CHECK_THROWS_AS(j_nonobject[json::object_t::key_type("foo")], json::type_error); + CHECK_THROWS_AS(j_const_nonobject["foo"], json::type_error); + CHECK_THROWS_AS(j_const_nonobject[json::object_t::key_type("foo")], json::type_error); + CHECK_THROWS_WITH(j_nonobject["foo"], + "[json.exception.type_error.305] cannot use operator[] with number"); CHECK_THROWS_WITH(j_nonobject[json::object_t::key_type("foo")], - "cannot use operator[] with number"); - CHECK_THROWS_WITH(j_const_nonobject["foo"], "cannot use operator[] with number"); + "[json.exception.type_error.305] cannot use operator[] with number"); + CHECK_THROWS_WITH(j_const_nonobject["foo"], + "[json.exception.type_error.305] cannot use operator[] with number"); CHECK_THROWS_WITH(j_const_nonobject[json::object_t::key_type("foo")], - "cannot use operator[] with number"); + "[json.exception.type_error.305] cannot use operator[] with number"); } } } From bb740c43fba356cd68caee5e7c5a9611ec99de1c Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Sun, 5 Mar 2017 19:15:56 +0100 Subject: [PATCH 12/52] :hammer: added user-defined exceptions 306 --- src/json.hpp | 8 +- src/json.hpp.re2c | 8 +- test/src/unit-element_access2.cpp | 135 +++++++++++++++++------------- 3 files changed, 87 insertions(+), 64 deletions(-) diff --git a/src/json.hpp b/src/json.hpp index f4bca23df..e9654577e 100644 --- a/src/json.hpp +++ b/src/json.hpp @@ -4176,7 +4176,7 @@ class basic_json @return copy of the element at key @a key or @a default_value if @a key is not found - @throw std::domain_error if JSON is not an object; example: `"cannot use + @throw type_error.306 if JSON is not an object; example: `"cannot use value() with null"` @complexity Logarithmic in the size of the container. @@ -4209,7 +4209,7 @@ class basic_json } else { - JSON_THROW(std::domain_error("cannot use value() with " + type_name())); + JSON_THROW(type_error(306, "cannot use value() with " + type_name())); } } @@ -4251,7 +4251,7 @@ class basic_json @return copy of the element at key @a key or @a default_value if @a key is not found - @throw std::domain_error if JSON is not an object; example: `"cannot use + @throw type_error.306 if JSON is not an object; example: `"cannot use value() with null"` @complexity Logarithmic in the size of the container. @@ -4281,7 +4281,7 @@ class basic_json } } - JSON_THROW(std::domain_error("cannot use value() with " + type_name())); + JSON_THROW(type_error(306, "cannot use value() with " + type_name())); } /*! diff --git a/src/json.hpp.re2c b/src/json.hpp.re2c index 4ba097afd..d21dfdfa4 100644 --- a/src/json.hpp.re2c +++ b/src/json.hpp.re2c @@ -4176,7 +4176,7 @@ class basic_json @return copy of the element at key @a key or @a default_value if @a key is not found - @throw std::domain_error if JSON is not an object; example: `"cannot use + @throw type_error.306 if JSON is not an object; example: `"cannot use value() with null"` @complexity Logarithmic in the size of the container. @@ -4209,7 +4209,7 @@ class basic_json } else { - JSON_THROW(std::domain_error("cannot use value() with " + type_name())); + JSON_THROW(type_error(306, "cannot use value() with " + type_name())); } } @@ -4251,7 +4251,7 @@ class basic_json @return copy of the element at key @a key or @a default_value if @a key is not found - @throw std::domain_error if JSON is not an object; example: `"cannot use + @throw type_error.306 if JSON is not an object; example: `"cannot use value() with null"` @complexity Logarithmic in the size of the container. @@ -4281,7 +4281,7 @@ class basic_json } } - JSON_THROW(std::domain_error("cannot use value() with " + type_name())); + JSON_THROW(type_error(306, "cannot use value() with " + type_name())); } /*! diff --git a/test/src/unit-element_access2.cpp b/test/src/unit-element_access2.cpp index 4e34ad924..ec70d8dfc 100644 --- a/test/src/unit-element_access2.cpp +++ b/test/src/unit-element_access2.cpp @@ -200,70 +200,84 @@ TEST_CASE("element access 2") { json j_nonobject(json::value_t::null); const json j_nonobject_const(j_nonobject); - CHECK_THROWS_AS(j_nonobject.value("foo", 1), std::domain_error); - CHECK_THROWS_AS(j_nonobject_const.value("foo", 1), std::domain_error); - CHECK_THROWS_WITH(j_nonobject.value("foo", 1), "cannot use value() with null"); - CHECK_THROWS_WITH(j_nonobject_const.value("foo", 1), "cannot use value() with null"); + CHECK_THROWS_AS(j_nonobject.value("foo", 1), json::type_error); + CHECK_THROWS_AS(j_nonobject_const.value("foo", 1), json::type_error); + CHECK_THROWS_WITH(j_nonobject.value("foo", 1), + "[json.exception.type_error.306] cannot use value() with null"); + CHECK_THROWS_WITH(j_nonobject_const.value("foo", 1), + "[json.exception.type_error.306] cannot use value() with null"); } SECTION("boolean") { json j_nonobject(json::value_t::boolean); const json j_nonobject_const(j_nonobject); - CHECK_THROWS_AS(j_nonobject.value("foo", 1), std::domain_error); - CHECK_THROWS_AS(j_nonobject_const.value("foo", 1), std::domain_error); - CHECK_THROWS_WITH(j_nonobject.value("foo", 1), "cannot use value() with boolean"); - CHECK_THROWS_WITH(j_nonobject_const.value("foo", 1), "cannot use value() with boolean"); + CHECK_THROWS_AS(j_nonobject.value("foo", 1), json::type_error); + CHECK_THROWS_AS(j_nonobject_const.value("foo", 1), json::type_error); + CHECK_THROWS_WITH(j_nonobject.value("foo", 1), + "[json.exception.type_error.306] cannot use value() with boolean"); + CHECK_THROWS_WITH(j_nonobject_const.value("foo", 1), + "[json.exception.type_error.306] cannot use value() with boolean"); } SECTION("string") { json j_nonobject(json::value_t::string); const json j_nonobject_const(j_nonobject); - CHECK_THROWS_AS(j_nonobject.value("foo", 1), std::domain_error); - CHECK_THROWS_AS(j_nonobject_const.value("foo", 1), std::domain_error); - CHECK_THROWS_WITH(j_nonobject.value("foo", 1), "cannot use value() with string"); - CHECK_THROWS_WITH(j_nonobject_const.value("foo", 1), "cannot use value() with string"); + CHECK_THROWS_AS(j_nonobject.value("foo", 1), json::type_error); + CHECK_THROWS_AS(j_nonobject_const.value("foo", 1), json::type_error); + CHECK_THROWS_WITH(j_nonobject.value("foo", 1), + "[json.exception.type_error.306] cannot use value() with string"); + CHECK_THROWS_WITH(j_nonobject_const.value("foo", 1), + "[json.exception.type_error.306] cannot use value() with string"); } SECTION("array") { json j_nonobject(json::value_t::array); const json j_nonobject_const(j_nonobject); - CHECK_THROWS_AS(j_nonobject.value("foo", 1), std::domain_error); - CHECK_THROWS_AS(j_nonobject_const.value("foo", 1), std::domain_error); - CHECK_THROWS_WITH(j_nonobject.value("foo", 1), "cannot use value() with array"); - CHECK_THROWS_WITH(j_nonobject_const.value("foo", 1), "cannot use value() with array"); + CHECK_THROWS_AS(j_nonobject.value("foo", 1), json::type_error); + CHECK_THROWS_AS(j_nonobject_const.value("foo", 1), json::type_error); + CHECK_THROWS_WITH(j_nonobject.value("foo", 1), + "[json.exception.type_error.306] cannot use value() with array"); + CHECK_THROWS_WITH(j_nonobject_const.value("foo", 1), + "[json.exception.type_error.306] cannot use value() with array"); } SECTION("number (integer)") { json j_nonobject(json::value_t::number_integer); const json j_nonobject_const(j_nonobject); - CHECK_THROWS_AS(j_nonobject.value("foo", 1), std::domain_error); - CHECK_THROWS_AS(j_nonobject_const.value("foo", 1), std::domain_error); - CHECK_THROWS_WITH(j_nonobject.value("foo", 1), "cannot use value() with number"); - CHECK_THROWS_WITH(j_nonobject_const.value("foo", 1), "cannot use value() with number"); + CHECK_THROWS_AS(j_nonobject.value("foo", 1), json::type_error); + CHECK_THROWS_AS(j_nonobject_const.value("foo", 1), json::type_error); + CHECK_THROWS_WITH(j_nonobject.value("foo", 1), + "[json.exception.type_error.306] cannot use value() with number"); + CHECK_THROWS_WITH(j_nonobject_const.value("foo", 1), + "[json.exception.type_error.306] cannot use value() with number"); } SECTION("number (unsigned)") { json j_nonobject(json::value_t::number_unsigned); const json j_nonobject_const(j_nonobject); - CHECK_THROWS_AS(j_nonobject.value("foo", 1), std::domain_error); - CHECK_THROWS_AS(j_nonobject_const.value("foo", 1), std::domain_error); - CHECK_THROWS_WITH(j_nonobject.value("foo", 1), "cannot use value() with number"); - CHECK_THROWS_WITH(j_nonobject_const.value("foo", 1), "cannot use value() with number"); + CHECK_THROWS_AS(j_nonobject.value("foo", 1), json::type_error); + CHECK_THROWS_AS(j_nonobject_const.value("foo", 1), json::type_error); + CHECK_THROWS_WITH(j_nonobject.value("foo", 1), + "[json.exception.type_error.306] cannot use value() with number"); + CHECK_THROWS_WITH(j_nonobject_const.value("foo", 1), + "[json.exception.type_error.306] cannot use value() with number"); } SECTION("number (floating-point)") { json j_nonobject(json::value_t::number_float); const json j_nonobject_const(j_nonobject); - CHECK_THROWS_AS(j_nonobject.value("foo", 1), std::domain_error); - CHECK_THROWS_AS(j_nonobject_const.value("foo", 1), std::domain_error); - CHECK_THROWS_WITH(j_nonobject.value("foo", 1), "cannot use value() with number"); - CHECK_THROWS_WITH(j_nonobject_const.value("foo", 1), "cannot use value() with number"); + CHECK_THROWS_AS(j_nonobject.value("foo", 1), json::type_error); + CHECK_THROWS_AS(j_nonobject_const.value("foo", 1), json::type_error); + CHECK_THROWS_WITH(j_nonobject.value("foo", 1), + "[json.exception.type_error.306] cannot use value() with number"); + CHECK_THROWS_WITH(j_nonobject_const.value("foo", 1), + "[json.exception.type_error.306] cannot use value() with number"); } } } @@ -304,75 +318,84 @@ TEST_CASE("element access 2") { json j_nonobject(json::value_t::null); const json j_nonobject_const(j_nonobject); - CHECK_THROWS_AS(j_nonobject.value("/foo"_json_pointer, 1), std::domain_error); - CHECK_THROWS_AS(j_nonobject_const.value("/foo"_json_pointer, 1), std::domain_error); - CHECK_THROWS_WITH(j_nonobject.value("/foo"_json_pointer, 1), "cannot use value() with null"); - CHECK_THROWS_WITH(j_nonobject_const.value("/foo"_json_pointer, 1), "cannot use value() with null"); + CHECK_THROWS_AS(j_nonobject.value("/foo"_json_pointer, 1), json::type_error); + CHECK_THROWS_AS(j_nonobject_const.value("/foo"_json_pointer, 1), json::type_error); + CHECK_THROWS_WITH(j_nonobject.value("/foo"_json_pointer, 1), + "[json.exception.type_error.306] cannot use value() with null"); + CHECK_THROWS_WITH(j_nonobject_const.value("/foo"_json_pointer, 1), + "[json.exception.type_error.306] cannot use value() with null"); } SECTION("boolean") { json j_nonobject(json::value_t::boolean); const json j_nonobject_const(j_nonobject); - CHECK_THROWS_AS(j_nonobject.value("/foo"_json_pointer, 1), std::domain_error); - CHECK_THROWS_AS(j_nonobject_const.value("/foo"_json_pointer, 1), std::domain_error); - CHECK_THROWS_WITH(j_nonobject.value("/foo"_json_pointer, 1), "cannot use value() with boolean"); + CHECK_THROWS_AS(j_nonobject.value("/foo"_json_pointer, 1), json::type_error); + CHECK_THROWS_AS(j_nonobject_const.value("/foo"_json_pointer, 1), json::type_error); + CHECK_THROWS_WITH(j_nonobject.value("/foo"_json_pointer, 1), + "[json.exception.type_error.306] cannot use value() with boolean"); CHECK_THROWS_WITH(j_nonobject_const.value("/foo"_json_pointer, 1), - "cannot use value() with boolean"); + "[json.exception.type_error.306] cannot use value() with boolean"); } SECTION("string") { json j_nonobject(json::value_t::string); const json j_nonobject_const(j_nonobject); - CHECK_THROWS_AS(j_nonobject.value("/foo"_json_pointer, 1), std::domain_error); - CHECK_THROWS_AS(j_nonobject_const.value("/foo"_json_pointer, 1), std::domain_error); - CHECK_THROWS_WITH(j_nonobject.value("/foo"_json_pointer, 1), "cannot use value() with string"); + CHECK_THROWS_AS(j_nonobject.value("/foo"_json_pointer, 1), json::type_error); + CHECK_THROWS_AS(j_nonobject_const.value("/foo"_json_pointer, 1), json::type_error); + CHECK_THROWS_WITH(j_nonobject.value("/foo"_json_pointer, 1), + "[json.exception.type_error.306] cannot use value() with string"); CHECK_THROWS_WITH(j_nonobject_const.value("/foo"_json_pointer, 1), - "cannot use value() with string"); + "[json.exception.type_error.306] cannot use value() with string"); } SECTION("array") { json j_nonobject(json::value_t::array); const json j_nonobject_const(j_nonobject); - CHECK_THROWS_AS(j_nonobject.value("/foo"_json_pointer, 1), std::domain_error); - CHECK_THROWS_AS(j_nonobject_const.value("/foo"_json_pointer, 1), std::domain_error); - CHECK_THROWS_WITH(j_nonobject.value("/foo"_json_pointer, 1), "cannot use value() with array"); - CHECK_THROWS_WITH(j_nonobject_const.value("/foo"_json_pointer, 1), "cannot use value() with array"); + CHECK_THROWS_AS(j_nonobject.value("/foo"_json_pointer, 1), json::type_error); + CHECK_THROWS_AS(j_nonobject_const.value("/foo"_json_pointer, 1), json::type_error); + CHECK_THROWS_WITH(j_nonobject.value("/foo"_json_pointer, 1), + "[json.exception.type_error.306] cannot use value() with array"); + CHECK_THROWS_WITH(j_nonobject_const.value("/foo"_json_pointer, 1), + "[json.exception.type_error.306] cannot use value() with array"); } SECTION("number (integer)") { json j_nonobject(json::value_t::number_integer); const json j_nonobject_const(j_nonobject); - CHECK_THROWS_AS(j_nonobject.value("/foo"_json_pointer, 1), std::domain_error); - CHECK_THROWS_AS(j_nonobject_const.value("/foo"_json_pointer, 1), std::domain_error); - CHECK_THROWS_WITH(j_nonobject.value("/foo"_json_pointer, 1), "cannot use value() with number"); + CHECK_THROWS_AS(j_nonobject.value("/foo"_json_pointer, 1), json::type_error); + CHECK_THROWS_AS(j_nonobject_const.value("/foo"_json_pointer, 1), json::type_error); + CHECK_THROWS_WITH(j_nonobject.value("/foo"_json_pointer, 1), + "[json.exception.type_error.306] cannot use value() with number"); CHECK_THROWS_WITH(j_nonobject_const.value("/foo"_json_pointer, 1), - "cannot use value() with number"); + "[json.exception.type_error.306] cannot use value() with number"); } SECTION("number (unsigned)") { json j_nonobject(json::value_t::number_unsigned); const json j_nonobject_const(j_nonobject); - CHECK_THROWS_AS(j_nonobject.value("/foo"_json_pointer, 1), std::domain_error); - CHECK_THROWS_AS(j_nonobject_const.value("/foo"_json_pointer, 1), std::domain_error); - CHECK_THROWS_WITH(j_nonobject.value("/foo"_json_pointer, 1), "cannot use value() with number"); + CHECK_THROWS_AS(j_nonobject.value("/foo"_json_pointer, 1), json::type_error); + CHECK_THROWS_AS(j_nonobject_const.value("/foo"_json_pointer, 1), json::type_error); + CHECK_THROWS_WITH(j_nonobject.value("/foo"_json_pointer, 1), + "[json.exception.type_error.306] cannot use value() with number"); CHECK_THROWS_WITH(j_nonobject_const.value("/foo"_json_pointer, 1), - "cannot use value() with number"); + "[json.exception.type_error.306] cannot use value() with number"); } SECTION("number (floating-point)") { json j_nonobject(json::value_t::number_float); const json j_nonobject_const(j_nonobject); - CHECK_THROWS_AS(j_nonobject.value("/foo"_json_pointer, 1), std::domain_error); - CHECK_THROWS_AS(j_nonobject_const.value("/foo"_json_pointer, 1), std::domain_error); - CHECK_THROWS_WITH(j_nonobject.value("/foo"_json_pointer, 1), "cannot use value() with number"); + CHECK_THROWS_AS(j_nonobject.value("/foo"_json_pointer, 1), json::type_error); + CHECK_THROWS_AS(j_nonobject_const.value("/foo"_json_pointer, 1), json::type_error); + CHECK_THROWS_WITH(j_nonobject.value("/foo"_json_pointer, 1), + "[json.exception.type_error.306] cannot use value() with number"); CHECK_THROWS_WITH(j_nonobject_const.value("/foo"_json_pointer, 1), - "cannot use value() with number"); + "[json.exception.type_error.306] cannot use value() with number"); } } } From 2a9393af0063c291f837057ea605d9813edd6a32 Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Sun, 5 Mar 2017 19:26:44 +0100 Subject: [PATCH 13/52] :hammer: added user-defined exceptions 307 --- src/json.hpp | 20 ++++---- src/json.hpp.re2c | 20 ++++---- test/src/unit-element_access1.cpp | 85 +++++++++++++++++++------------ test/src/unit-element_access2.cpp | 30 ++++++----- 4 files changed, 91 insertions(+), 64 deletions(-) diff --git a/src/json.hpp b/src/json.hpp index e9654577e..48c826f15 100644 --- a/src/json.hpp +++ b/src/json.hpp @@ -4397,8 +4397,8 @@ class basic_json @post Invalidates iterators and references at or after the point of the erase, including the `end()` iterator. - @throw std::domain_error if called on a `null` value; example: `"cannot - use erase() with null"` + @throw type_error.307 if called on a `null` value; example: `"cannot use + erase() with null"` @throw invalid_iterator.202 if called on an iterator which does not belong to the current JSON value; example: `"iterator does not fit current value"` @@ -4478,7 +4478,7 @@ class basic_json default: { - JSON_THROW(std::domain_error("cannot use erase() with " + type_name())); + JSON_THROW(type_error(307, "cannot use erase() with " + type_name())); } } @@ -4505,8 +4505,8 @@ class basic_json @post Invalidates iterators and references at or after the point of the erase, including the `end()` iterator. - @throw std::domain_error if called on a `null` value; example: `"cannot - use erase() with null"` + @throw type_error.307 if called on a `null` value; example: `"cannot use + erase() with null"` @throw invalid_iterator.203 if called on iterators which does not belong to the current JSON value; example: `"iterators do not fit current value"` @throw invalid_iterator.204 if called on a primitive type with invalid @@ -4587,7 +4587,7 @@ class basic_json default: { - JSON_THROW(std::domain_error("cannot use erase() with " + type_name())); + JSON_THROW(type_error(307, "cannot use erase() with " + type_name())); } } @@ -4608,7 +4608,7 @@ class basic_json @post References and iterators to the erased elements are invalidated. Other references and iterators are not affected. - @throw std::domain_error when called on a type other than JSON object; + @throw type_error.307 when called on a type other than JSON object; example: `"cannot use erase() with null"` @complexity `log(size()) + count(key)` @@ -4631,7 +4631,7 @@ class basic_json return m_value.object->erase(key); } - JSON_THROW(std::domain_error("cannot use erase() with " + type_name())); + JSON_THROW(type_error(307, "cannot use erase() with " + type_name())); } /*! @@ -4641,7 +4641,7 @@ class basic_json @param[in] idx index of the element to remove - @throw std::domain_error when called on a type other than JSON array; + @throw type_error.307 when called on a type other than JSON object; example: `"cannot use erase() with null"` @throw std::out_of_range when `idx >= size()`; example: `"array index 17 is out of range"` @@ -4672,7 +4672,7 @@ class basic_json } else { - JSON_THROW(std::domain_error("cannot use erase() with " + type_name())); + JSON_THROW(type_error(307, "cannot use erase() with " + type_name())); } } diff --git a/src/json.hpp.re2c b/src/json.hpp.re2c index d21dfdfa4..c26717f73 100644 --- a/src/json.hpp.re2c +++ b/src/json.hpp.re2c @@ -4397,8 +4397,8 @@ class basic_json @post Invalidates iterators and references at or after the point of the erase, including the `end()` iterator. - @throw std::domain_error if called on a `null` value; example: `"cannot - use erase() with null"` + @throw type_error.307 if called on a `null` value; example: `"cannot use + erase() with null"` @throw invalid_iterator.202 if called on an iterator which does not belong to the current JSON value; example: `"iterator does not fit current value"` @@ -4478,7 +4478,7 @@ class basic_json default: { - JSON_THROW(std::domain_error("cannot use erase() with " + type_name())); + JSON_THROW(type_error(307, "cannot use erase() with " + type_name())); } } @@ -4505,8 +4505,8 @@ class basic_json @post Invalidates iterators and references at or after the point of the erase, including the `end()` iterator. - @throw std::domain_error if called on a `null` value; example: `"cannot - use erase() with null"` + @throw type_error.307 if called on a `null` value; example: `"cannot use + erase() with null"` @throw invalid_iterator.203 if called on iterators which does not belong to the current JSON value; example: `"iterators do not fit current value"` @throw invalid_iterator.204 if called on a primitive type with invalid @@ -4587,7 +4587,7 @@ class basic_json default: { - JSON_THROW(std::domain_error("cannot use erase() with " + type_name())); + JSON_THROW(type_error(307, "cannot use erase() with " + type_name())); } } @@ -4608,7 +4608,7 @@ class basic_json @post References and iterators to the erased elements are invalidated. Other references and iterators are not affected. - @throw std::domain_error when called on a type other than JSON object; + @throw type_error.307 when called on a type other than JSON object; example: `"cannot use erase() with null"` @complexity `log(size()) + count(key)` @@ -4631,7 +4631,7 @@ class basic_json return m_value.object->erase(key); } - JSON_THROW(std::domain_error("cannot use erase() with " + type_name())); + JSON_THROW(type_error(307, "cannot use erase() with " + type_name())); } /*! @@ -4641,7 +4641,7 @@ class basic_json @param[in] idx index of the element to remove - @throw std::domain_error when called on a type other than JSON array; + @throw type_error.307 when called on a type other than JSON object; example: `"cannot use erase() with null"` @throw std::out_of_range when `idx >= size()`; example: `"array index 17 is out of range"` @@ -4672,7 +4672,7 @@ class basic_json } else { - JSON_THROW(std::domain_error("cannot use erase() with " + type_name())); + JSON_THROW(type_error(307, "cannot use erase() with " + type_name())); } } diff --git a/test/src/unit-element_access1.cpp b/test/src/unit-element_access1.cpp index 37c138bbb..e0e3ee99a 100644 --- a/test/src/unit-element_access1.cpp +++ b/test/src/unit-element_access1.cpp @@ -444,50 +444,57 @@ TEST_CASE("element access 1") SECTION("null") { json j_nonobject(json::value_t::null); - CHECK_THROWS_AS(j_nonobject.erase(0), std::domain_error); - CHECK_THROWS_WITH(j_nonobject.erase(0), "cannot use erase() with null"); + CHECK_THROWS_AS(j_nonobject.erase(0), json::type_error); + CHECK_THROWS_WITH(j_nonobject.erase(0), + "[json.exception.type_error.307] cannot use erase() with null"); } SECTION("boolean") { json j_nonobject(json::value_t::boolean); - CHECK_THROWS_AS(j_nonobject.erase(0), std::domain_error); - CHECK_THROWS_WITH(j_nonobject.erase(0), "cannot use erase() with boolean"); + CHECK_THROWS_AS(j_nonobject.erase(0), json::type_error); + CHECK_THROWS_WITH(j_nonobject.erase(0), + "[json.exception.type_error.307] cannot use erase() with boolean"); } SECTION("string") { json j_nonobject(json::value_t::string); - CHECK_THROWS_AS(j_nonobject.erase(0), std::domain_error); - CHECK_THROWS_WITH(j_nonobject.erase(0), "cannot use erase() with string"); + CHECK_THROWS_AS(j_nonobject.erase(0), json::type_error); + CHECK_THROWS_WITH(j_nonobject.erase(0), + "[json.exception.type_error.307] cannot use erase() with string"); } SECTION("object") { json j_nonobject(json::value_t::object); - CHECK_THROWS_AS(j_nonobject.erase(0), std::domain_error); - CHECK_THROWS_WITH(j_nonobject.erase(0), "cannot use erase() with object"); + CHECK_THROWS_AS(j_nonobject.erase(0), json::type_error); + CHECK_THROWS_WITH(j_nonobject.erase(0), + "[json.exception.type_error.307] cannot use erase() with object"); } SECTION("number (integer)") { json j_nonobject(json::value_t::number_integer); - CHECK_THROWS_AS(j_nonobject.erase(0), std::domain_error); - CHECK_THROWS_WITH(j_nonobject.erase(0), "cannot use erase() with number"); + CHECK_THROWS_AS(j_nonobject.erase(0), json::type_error); + CHECK_THROWS_WITH(j_nonobject.erase(0), + "[json.exception.type_error.307] cannot use erase() with number"); } SECTION("number (unsigned)") { json j_nonobject(json::value_t::number_unsigned); - CHECK_THROWS_AS(j_nonobject.erase(0), std::domain_error); - CHECK_THROWS_WITH(j_nonobject.erase(0), "cannot use erase() with number"); + CHECK_THROWS_AS(j_nonobject.erase(0), json::type_error); + CHECK_THROWS_WITH(j_nonobject.erase(0), + "[json.exception.type_error.307] cannot use erase() with number"); } SECTION("number (floating-point)") { json j_nonobject(json::value_t::number_float); - CHECK_THROWS_AS(j_nonobject.erase(0), std::domain_error); - CHECK_THROWS_WITH(j_nonobject.erase(0), "cannot use erase() with number"); + CHECK_THROWS_AS(j_nonobject.erase(0), json::type_error); + CHECK_THROWS_WITH(j_nonobject.erase(0), + "[json.exception.type_error.307] cannot use erase() with number"); } } } @@ -592,13 +599,15 @@ TEST_CASE("element access 1") { { json j; - CHECK_THROWS_AS(j.erase(j.begin()), std::domain_error); - CHECK_THROWS_WITH(j.erase(j.begin()), "cannot use erase() with null"); + CHECK_THROWS_AS(j.erase(j.begin()), json::type_error); + CHECK_THROWS_WITH(j.erase(j.begin()), + "[json.exception.type_error.307] cannot use erase() with null"); } { json j; - CHECK_THROWS_AS(j.erase(j.cbegin()), std::domain_error); - CHECK_THROWS_WITH(j.erase(j.begin()), "cannot use erase() with null"); + CHECK_THROWS_AS(j.erase(j.cbegin()), json::type_error); + CHECK_THROWS_WITH(j.erase(j.begin()), + "[json.exception.type_error.307] cannot use erase() with null"); } } @@ -690,12 +699,14 @@ TEST_CASE("element access 1") { json j = "foo"; CHECK_THROWS_AS(j.erase(j.end()), json::invalid_iterator); - CHECK_THROWS_WITH(j.erase(j.end()), "[json.exception.invalid_iterator.205] iterator out of range"); + CHECK_THROWS_WITH(j.erase(j.end()), + "[json.exception.invalid_iterator.205] iterator out of range"); } { json j = "bar"; CHECK_THROWS_AS(j.erase(j.cend()), json::invalid_iterator); - CHECK_THROWS_WITH(j.erase(j.cend()), "[json.exception.invalid_iterator.205] iterator out of range"); + CHECK_THROWS_WITH(j.erase(j.cend()), + "[json.exception.invalid_iterator.205] iterator out of range"); } } @@ -704,12 +715,14 @@ TEST_CASE("element access 1") { json j = false; CHECK_THROWS_AS(j.erase(j.end()), json::invalid_iterator); - CHECK_THROWS_WITH(j.erase(j.end()), "[json.exception.invalid_iterator.205] iterator out of range"); + CHECK_THROWS_WITH(j.erase(j.end()), + "[json.exception.invalid_iterator.205] iterator out of range"); } { json j = true; CHECK_THROWS_AS(j.erase(j.cend()), json::invalid_iterator); - CHECK_THROWS_WITH(j.erase(j.cend()), "[json.exception.invalid_iterator.205] iterator out of range"); + CHECK_THROWS_WITH(j.erase(j.cend()), + "[json.exception.invalid_iterator.205] iterator out of range"); } } @@ -718,12 +731,14 @@ TEST_CASE("element access 1") { json j = 17; CHECK_THROWS_AS(j.erase(j.end()), json::invalid_iterator); - CHECK_THROWS_WITH(j.erase(j.end()), "[json.exception.invalid_iterator.205] iterator out of range"); + CHECK_THROWS_WITH(j.erase(j.end()), + "[json.exception.invalid_iterator.205] iterator out of range"); } { json j = 17; CHECK_THROWS_AS(j.erase(j.cend()), json::invalid_iterator); - CHECK_THROWS_WITH(j.erase(j.cend()), "[json.exception.invalid_iterator.205] iterator out of range"); + CHECK_THROWS_WITH(j.erase(j.cend()), + "[json.exception.invalid_iterator.205] iterator out of range"); } } @@ -732,12 +747,14 @@ TEST_CASE("element access 1") { json j = 17u; CHECK_THROWS_AS(j.erase(j.end()), json::invalid_iterator); - CHECK_THROWS_WITH(j.erase(j.end()), "[json.exception.invalid_iterator.205] iterator out of range"); + CHECK_THROWS_WITH(j.erase(j.end()), + "[json.exception.invalid_iterator.205] iterator out of range"); } { json j = 17u; CHECK_THROWS_AS(j.erase(j.cend()), json::invalid_iterator); - CHECK_THROWS_WITH(j.erase(j.cend()), "[json.exception.invalid_iterator.205] iterator out of range"); + CHECK_THROWS_WITH(j.erase(j.cend()), + "[json.exception.invalid_iterator.205] iterator out of range"); } } @@ -746,12 +763,14 @@ TEST_CASE("element access 1") { json j = 23.42; CHECK_THROWS_AS(j.erase(j.end()), json::invalid_iterator); - CHECK_THROWS_WITH(j.erase(j.end()), "[json.exception.invalid_iterator.205] iterator out of range"); + CHECK_THROWS_WITH(j.erase(j.end()), + "[json.exception.invalid_iterator.205] iterator out of range"); } { json j = 23.42; CHECK_THROWS_AS(j.erase(j.cend()), json::invalid_iterator); - CHECK_THROWS_WITH(j.erase(j.cend()), "[json.exception.invalid_iterator.205] iterator out of range"); + CHECK_THROWS_WITH(j.erase(j.cend()), + "[json.exception.invalid_iterator.205] iterator out of range"); } } } @@ -762,13 +781,15 @@ TEST_CASE("element access 1") { { json j; - CHECK_THROWS_AS(j.erase(j.begin(), j.end()), std::domain_error); - CHECK_THROWS_WITH(j.erase(j.begin(), j.end()), "cannot use erase() with null"); + CHECK_THROWS_AS(j.erase(j.begin(), j.end()), json::type_error); + CHECK_THROWS_WITH(j.erase(j.begin(), j.end()), + "[json.exception.type_error.307] cannot use erase() with null"); } { json j; - CHECK_THROWS_AS(j.erase(j.cbegin(), j.cend()), std::domain_error); - CHECK_THROWS_WITH(j.erase(j.cbegin(), j.cend()), "cannot use erase() with null"); + CHECK_THROWS_AS(j.erase(j.cbegin(), j.cend()), json::type_error); + CHECK_THROWS_WITH(j.erase(j.cbegin(), j.cend()), + "[json.exception.type_error.307] cannot use erase() with null"); } } diff --git a/test/src/unit-element_access2.cpp b/test/src/unit-element_access2.cpp index ec70d8dfc..4a066e709 100644 --- a/test/src/unit-element_access2.cpp +++ b/test/src/unit-element_access2.cpp @@ -757,43 +757,49 @@ TEST_CASE("element access 2") SECTION("null") { json j_nonobject(json::value_t::null); - CHECK_THROWS_AS(j_nonobject.erase("foo"), std::domain_error); - CHECK_THROWS_WITH(j_nonobject.erase("foo"), "cannot use erase() with null"); + CHECK_THROWS_AS(j_nonobject.erase("foo"), json::type_error); + CHECK_THROWS_WITH(j_nonobject.erase("foo"), + "[json.exception.type_error.307] cannot use erase() with null"); } SECTION("boolean") { json j_nonobject(json::value_t::boolean); - CHECK_THROWS_AS(j_nonobject.erase("foo"), std::domain_error); - CHECK_THROWS_WITH(j_nonobject.erase("foo"), "cannot use erase() with boolean"); + CHECK_THROWS_AS(j_nonobject.erase("foo"), json::type_error); + CHECK_THROWS_WITH(j_nonobject.erase("foo"), + "[json.exception.type_error.307] cannot use erase() with boolean"); } SECTION("string") { json j_nonobject(json::value_t::string); - CHECK_THROWS_AS(j_nonobject.erase("foo"), std::domain_error); - CHECK_THROWS_WITH(j_nonobject.erase("foo"), "cannot use erase() with string"); + CHECK_THROWS_AS(j_nonobject.erase("foo"), json::type_error); + CHECK_THROWS_WITH(j_nonobject.erase("foo"), + "[json.exception.type_error.307] cannot use erase() with string"); } SECTION("array") { json j_nonobject(json::value_t::array); - CHECK_THROWS_AS(j_nonobject.erase("foo"), std::domain_error); - CHECK_THROWS_WITH(j_nonobject.erase("foo"), "cannot use erase() with array"); + CHECK_THROWS_AS(j_nonobject.erase("foo"), json::type_error); + CHECK_THROWS_WITH(j_nonobject.erase("foo"), + "[json.exception.type_error.307] cannot use erase() with array"); } SECTION("number (integer)") { json j_nonobject(json::value_t::number_integer); - CHECK_THROWS_AS(j_nonobject.erase("foo"), std::domain_error); - CHECK_THROWS_WITH(j_nonobject.erase("foo"), "cannot use erase() with number"); + CHECK_THROWS_AS(j_nonobject.erase("foo"), json::type_error); + CHECK_THROWS_WITH(j_nonobject.erase("foo"), + "[json.exception.type_error.307] cannot use erase() with number"); } SECTION("number (floating-point)") { json j_nonobject(json::value_t::number_float); - CHECK_THROWS_AS(j_nonobject.erase("foo"), std::domain_error); - CHECK_THROWS_WITH(j_nonobject.erase("foo"), "cannot use erase() with number"); + CHECK_THROWS_AS(j_nonobject.erase("foo"), json::type_error); + CHECK_THROWS_WITH(j_nonobject.erase("foo"), + "[json.exception.type_error.307] cannot use erase() with number"); } } } From 70b2c3f45e23e51fd658f2e5457159463be70d0e Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Sun, 5 Mar 2017 19:35:24 +0100 Subject: [PATCH 14/52] :hammer: added user-defined exceptions 308 --- src/json.hpp | 10 +++++----- src/json.hpp.re2c | 10 +++++----- test/src/unit-modifiers.cpp | 32 ++++++++++++++++---------------- 3 files changed, 26 insertions(+), 26 deletions(-) diff --git a/src/json.hpp b/src/json.hpp index 48c826f15..4a4222091 100644 --- a/src/json.hpp +++ b/src/json.hpp @@ -5374,7 +5374,7 @@ class basic_json @param[in] val the value to add to the JSON array - @throw std::domain_error when called on a type other than JSON array or + @throw type_error.308 when called on a type other than JSON array or null; example: `"cannot use push_back() with number"` @complexity Amortized constant. @@ -5390,7 +5390,7 @@ class basic_json // push_back only works for null objects or arrays if (not(is_null() or is_array())) { - JSON_THROW(std::domain_error("cannot use push_back() with " + type_name())); + JSON_THROW(type_error(308, "cannot use push_back() with " + type_name())); } // transform null object into an array @@ -5426,7 +5426,7 @@ class basic_json // push_back only works for null objects or arrays if (not(is_null() or is_array())) { - JSON_THROW(std::domain_error("cannot use push_back() with " + type_name())); + JSON_THROW(type_error(308, "cannot use push_back() with " + type_name())); } // transform null object into an array @@ -5460,7 +5460,7 @@ class basic_json @param[in] val the value to add to the JSON object - @throw std::domain_error when called on a type other than JSON object or + @throw type_error.308 when called on a type other than JSON object or null; example: `"cannot use push_back() with number"` @complexity Logarithmic in the size of the container, O(log(`size()`)). @@ -5476,7 +5476,7 @@ class basic_json // push_back only works for null objects or objects if (not(is_null() or is_object())) { - JSON_THROW(std::domain_error("cannot use push_back() with " + type_name())); + JSON_THROW(type_error(308, "cannot use push_back() with " + type_name())); } // transform null object into an object diff --git a/src/json.hpp.re2c b/src/json.hpp.re2c index c26717f73..69fef9767 100644 --- a/src/json.hpp.re2c +++ b/src/json.hpp.re2c @@ -5374,7 +5374,7 @@ class basic_json @param[in] val the value to add to the JSON array - @throw std::domain_error when called on a type other than JSON array or + @throw type_error.308 when called on a type other than JSON array or null; example: `"cannot use push_back() with number"` @complexity Amortized constant. @@ -5390,7 +5390,7 @@ class basic_json // push_back only works for null objects or arrays if (not(is_null() or is_array())) { - JSON_THROW(std::domain_error("cannot use push_back() with " + type_name())); + JSON_THROW(type_error(308, "cannot use push_back() with " + type_name())); } // transform null object into an array @@ -5426,7 +5426,7 @@ class basic_json // push_back only works for null objects or arrays if (not(is_null() or is_array())) { - JSON_THROW(std::domain_error("cannot use push_back() with " + type_name())); + JSON_THROW(type_error(308, "cannot use push_back() with " + type_name())); } // transform null object into an array @@ -5460,7 +5460,7 @@ class basic_json @param[in] val the value to add to the JSON object - @throw std::domain_error when called on a type other than JSON object or + @throw type_error.308 when called on a type other than JSON object or null; example: `"cannot use push_back() with number"` @complexity Logarithmic in the size of the container, O(log(`size()`)). @@ -5476,7 +5476,7 @@ class basic_json // push_back only works for null objects or objects if (not(is_null() or is_object())) { - JSON_THROW(std::domain_error("cannot use push_back() with " + type_name())); + JSON_THROW(type_error(308, "cannot use push_back() with " + type_name())); } // transform null object into an object diff --git a/test/src/unit-modifiers.cpp b/test/src/unit-modifiers.cpp index 2a3826c25..dc84a930c 100644 --- a/test/src/unit-modifiers.cpp +++ b/test/src/unit-modifiers.cpp @@ -152,8 +152,8 @@ TEST_CASE("modifiers") SECTION("other type") { json j = 1; - CHECK_THROWS_AS(j.push_back("Hello"), std::domain_error); - CHECK_THROWS_WITH(j.push_back("Hello"), "cannot use push_back() with number"); + CHECK_THROWS_AS(j.push_back("Hello"), json::type_error); + CHECK_THROWS_WITH(j.push_back("Hello"), "[json.exception.type_error.308] cannot use push_back() with number"); } } @@ -182,8 +182,8 @@ TEST_CASE("modifiers") { json j = 1; json k("Hello"); - CHECK_THROWS_AS(j.push_back(k), std::domain_error); - CHECK_THROWS_WITH(j.push_back(k), "cannot use push_back() with number"); + CHECK_THROWS_AS(j.push_back(k), json::type_error); + CHECK_THROWS_WITH(j.push_back(k), "[json.exception.type_error.308] cannot use push_back() with number"); } } } @@ -215,9 +215,9 @@ TEST_CASE("modifiers") { json j = 1; json k("Hello"); - CHECK_THROWS_AS(j.push_back(json::object_t::value_type({"one", 1})), std::domain_error); + CHECK_THROWS_AS(j.push_back(json::object_t::value_type({"one", 1})), json::type_error); CHECK_THROWS_WITH(j.push_back(json::object_t::value_type({"one", 1})), - "cannot use push_back() with number"); + "[json.exception.type_error.308] cannot use push_back() with number"); } } @@ -252,8 +252,8 @@ TEST_CASE("modifiers") CHECK(j == json({{"key1", 1}, {"key2", "bar"}})); json k = {{"key1", 1}}; - CHECK_THROWS_AS(k.push_back({1, 2, 3, 4}), std::domain_error); - CHECK_THROWS_WITH(k.push_back({1, 2, 3, 4}), "cannot use push_back() with object"); + CHECK_THROWS_AS(k.push_back({1, 2, 3, 4}), json::type_error); + CHECK_THROWS_WITH(k.push_back({1, 2, 3, 4}), "[json.exception.type_error.308] cannot use push_back() with object"); } } } @@ -381,8 +381,8 @@ TEST_CASE("modifiers") SECTION("other type") { json j = 1; - CHECK_THROWS_AS(j += "Hello", std::domain_error); - CHECK_THROWS_WITH(j += "Hello", "cannot use push_back() with number"); + CHECK_THROWS_AS(j += "Hello", json::type_error); + CHECK_THROWS_WITH(j += "Hello", "[json.exception.type_error.308] cannot use push_back() with number"); } } @@ -411,8 +411,8 @@ TEST_CASE("modifiers") { json j = 1; json k("Hello"); - CHECK_THROWS_AS(j += k, std::domain_error); - CHECK_THROWS_WITH(j += k, "cannot use push_back() with number"); + CHECK_THROWS_AS(j += k, json::type_error); + CHECK_THROWS_WITH(j += k, "[json.exception.type_error.308] cannot use push_back() with number"); } } } @@ -444,9 +444,9 @@ TEST_CASE("modifiers") { json j = 1; json k("Hello"); - CHECK_THROWS_AS(j += json::object_t::value_type({"one", 1}), std::domain_error); + CHECK_THROWS_AS(j += json::object_t::value_type({"one", 1}), json::type_error); CHECK_THROWS_WITH(j += json::object_t::value_type({"one", 1}), - "cannot use push_back() with number"); + "[json.exception.type_error.308] cannot use push_back() with number"); } } @@ -481,8 +481,8 @@ TEST_CASE("modifiers") CHECK(j == json({{"key1", 1}, {"key2", "bar"}})); json k = {{"key1", 1}}; - CHECK_THROWS_AS((k += {1, 2, 3, 4}), std::domain_error); - CHECK_THROWS_WITH((k += {1, 2, 3, 4}), "cannot use push_back() with object"); + CHECK_THROWS_AS((k += {1, 2, 3, 4}), json::type_error); + CHECK_THROWS_WITH((k += {1, 2, 3, 4}), "[json.exception.type_error.308] cannot use push_back() with object"); } } } From 5cca44c1611f50078b08490a276e1aee48f8f38e Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Sun, 5 Mar 2017 19:42:05 +0100 Subject: [PATCH 15/52] :hammer: added user-defined exceptions 309 --- src/json.hpp | 22 +++++++++++----------- src/json.hpp.re2c | 22 +++++++++++----------- test/src/unit-modifiers.cpp | 20 ++++++++++---------- 3 files changed, 32 insertions(+), 32 deletions(-) diff --git a/src/json.hpp b/src/json.hpp index 4a4222091..4753b0328 100644 --- a/src/json.hpp +++ b/src/json.hpp @@ -5655,7 +5655,7 @@ class basic_json @param[in] val element to insert @return iterator pointing to the inserted @a val. - @throw std::domain_error if called on JSON values other than arrays; + @throw type_error.309 if called on JSON values other than arrays; example: `"cannot use insert() with string"` @throw invalid_iterator.202 if @a pos is not an iterator of *this; example: `"iterator does not fit current value"` @@ -5684,7 +5684,7 @@ class basic_json return result; } - JSON_THROW(std::domain_error("cannot use insert() with " + type_name())); + JSON_THROW(type_error(309, "cannot use insert() with " + type_name())); } /*! @@ -5708,8 +5708,8 @@ class basic_json @return iterator pointing to the first element inserted, or @a pos if `cnt==0` - @throw std::domain_error if called on JSON values other than arrays; - example: `"cannot use insert() with string"` + @throw type_error.309 if called on JSON values other than arrays; example: + `"cannot use insert() with string"` @throw invalid_iterator.202 if @a pos is not an iterator of *this; example: `"iterator does not fit current value"` @@ -5737,7 +5737,7 @@ class basic_json return result; } - JSON_THROW(std::domain_error("cannot use insert() with " + type_name())); + JSON_THROW(type_error(309, "cannot use insert() with " + type_name())); } /*! @@ -5750,8 +5750,8 @@ class basic_json @param[in] first begin of the range of elements to insert @param[in] last end of the range of elements to insert - @throw std::domain_error if called on JSON values other than arrays; - example: `"cannot use insert() with string"` + @throw type_error.309 if called on JSON values other than arrays; example: + `"cannot use insert() with string"` @throw invalid_iterator.202 if @a pos is not an iterator of *this; example: `"iterator does not fit current value"` @throw invalid_iterator.210 if @a first and @a last do not belong to the @@ -5775,7 +5775,7 @@ class basic_json // insert only works for arrays if (not is_array()) { - JSON_THROW(std::domain_error("cannot use insert() with " + type_name())); + JSON_THROW(type_error(309, "cannot use insert() with " + type_name())); } // check if iterator pos fits to this JSON value @@ -5813,8 +5813,8 @@ class basic_json the end() iterator @param[in] ilist initializer list to insert the values from - @throw std::domain_error if called on JSON values other than arrays; - example: `"cannot use insert() with string"` + @throw type_error.309 if called on JSON values other than arrays; example: + `"cannot use insert() with string"` @throw invalid_iterator.202 if @a pos is not an iterator of *this; example: `"iterator does not fit current value"` @@ -5833,7 +5833,7 @@ class basic_json // insert only works for arrays if (not is_array()) { - JSON_THROW(std::domain_error("cannot use insert() with " + type_name())); + JSON_THROW(type_error(309, "cannot use insert() with " + type_name())); } // check if iterator pos fits to this JSON value diff --git a/src/json.hpp.re2c b/src/json.hpp.re2c index 69fef9767..8f12b9e24 100644 --- a/src/json.hpp.re2c +++ b/src/json.hpp.re2c @@ -5655,7 +5655,7 @@ class basic_json @param[in] val element to insert @return iterator pointing to the inserted @a val. - @throw std::domain_error if called on JSON values other than arrays; + @throw type_error.309 if called on JSON values other than arrays; example: `"cannot use insert() with string"` @throw invalid_iterator.202 if @a pos is not an iterator of *this; example: `"iterator does not fit current value"` @@ -5684,7 +5684,7 @@ class basic_json return result; } - JSON_THROW(std::domain_error("cannot use insert() with " + type_name())); + JSON_THROW(type_error(309, "cannot use insert() with " + type_name())); } /*! @@ -5708,8 +5708,8 @@ class basic_json @return iterator pointing to the first element inserted, or @a pos if `cnt==0` - @throw std::domain_error if called on JSON values other than arrays; - example: `"cannot use insert() with string"` + @throw type_error.309 if called on JSON values other than arrays; example: + `"cannot use insert() with string"` @throw invalid_iterator.202 if @a pos is not an iterator of *this; example: `"iterator does not fit current value"` @@ -5737,7 +5737,7 @@ class basic_json return result; } - JSON_THROW(std::domain_error("cannot use insert() with " + type_name())); + JSON_THROW(type_error(309, "cannot use insert() with " + type_name())); } /*! @@ -5750,8 +5750,8 @@ class basic_json @param[in] first begin of the range of elements to insert @param[in] last end of the range of elements to insert - @throw std::domain_error if called on JSON values other than arrays; - example: `"cannot use insert() with string"` + @throw type_error.309 if called on JSON values other than arrays; example: + `"cannot use insert() with string"` @throw invalid_iterator.202 if @a pos is not an iterator of *this; example: `"iterator does not fit current value"` @throw invalid_iterator.210 if @a first and @a last do not belong to the @@ -5775,7 +5775,7 @@ class basic_json // insert only works for arrays if (not is_array()) { - JSON_THROW(std::domain_error("cannot use insert() with " + type_name())); + JSON_THROW(type_error(309, "cannot use insert() with " + type_name())); } // check if iterator pos fits to this JSON value @@ -5813,8 +5813,8 @@ class basic_json the end() iterator @param[in] ilist initializer list to insert the values from - @throw std::domain_error if called on JSON values other than arrays; - example: `"cannot use insert() with string"` + @throw type_error.309 if called on JSON values other than arrays; example: + `"cannot use insert() with string"` @throw invalid_iterator.202 if @a pos is not an iterator of *this; example: `"iterator does not fit current value"` @@ -5833,7 +5833,7 @@ class basic_json // insert only works for arrays if (not is_array()) { - JSON_THROW(std::domain_error("cannot use insert() with " + type_name())); + JSON_THROW(type_error(309, "cannot use insert() with " + type_name())); } // check if iterator pos fits to this JSON value diff --git a/test/src/unit-modifiers.cpp b/test/src/unit-modifiers.cpp index dc84a930c..029dc996d 100644 --- a/test/src/unit-modifiers.cpp +++ b/test/src/unit-modifiers.cpp @@ -686,20 +686,20 @@ TEST_CASE("modifiers") // call insert on a non-array type json j_nonarray = 3; json j_yet_another_array = {"first", "second"}; - CHECK_THROWS_AS(j_nonarray.insert(j_nonarray.end(), 10), std::domain_error); - CHECK_THROWS_AS(j_nonarray.insert(j_nonarray.end(), j_value), std::domain_error); - CHECK_THROWS_AS(j_nonarray.insert(j_nonarray.end(), 10, 11), std::domain_error); + CHECK_THROWS_AS(j_nonarray.insert(j_nonarray.end(), 10), json::type_error); + CHECK_THROWS_AS(j_nonarray.insert(j_nonarray.end(), j_value), json::type_error); + CHECK_THROWS_AS(j_nonarray.insert(j_nonarray.end(), 10, 11), json::type_error); CHECK_THROWS_AS(j_nonarray.insert(j_nonarray.end(), j_yet_another_array.begin(), - j_yet_another_array.end()), std::domain_error); - CHECK_THROWS_AS(j_nonarray.insert(j_nonarray.end(), {1, 2, 3, 4}), std::domain_error); + j_yet_another_array.end()), json::type_error); + CHECK_THROWS_AS(j_nonarray.insert(j_nonarray.end(), {1, 2, 3, 4}), json::type_error); - CHECK_THROWS_WITH(j_nonarray.insert(j_nonarray.end(), 10), "cannot use insert() with number"); - CHECK_THROWS_WITH(j_nonarray.insert(j_nonarray.end(), j_value), "cannot use insert() with number"); - CHECK_THROWS_WITH(j_nonarray.insert(j_nonarray.end(), 10, 11), "cannot use insert() with number"); + CHECK_THROWS_WITH(j_nonarray.insert(j_nonarray.end(), 10), "[json.exception.type_error.309] cannot use insert() with number"); + CHECK_THROWS_WITH(j_nonarray.insert(j_nonarray.end(), j_value), "[json.exception.type_error.309] cannot use insert() with number"); + CHECK_THROWS_WITH(j_nonarray.insert(j_nonarray.end(), 10, 11), "[json.exception.type_error.309] cannot use insert() with number"); CHECK_THROWS_WITH(j_nonarray.insert(j_nonarray.end(), j_yet_another_array.begin(), - j_yet_another_array.end()), "cannot use insert() with number"); + j_yet_another_array.end()), "[json.exception.type_error.309] cannot use insert() with number"); CHECK_THROWS_WITH(j_nonarray.insert(j_nonarray.end(), {1, 2, 3, 4}), - "cannot use insert() with number"); + "[json.exception.type_error.309] cannot use insert() with number"); } } From 144cf6a4c7eae74eabf4123429a1e985d0a5b656 Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Sun, 5 Mar 2017 19:48:11 +0100 Subject: [PATCH 16/52] :hammer: added user-defined exceptions 310 --- src/json.hpp | 14 +++++++------- src/json.hpp.re2c | 14 +++++++------- test/src/unit-modifiers.cpp | 12 ++++++------ 3 files changed, 20 insertions(+), 20 deletions(-) diff --git a/src/json.hpp b/src/json.hpp index 4753b0328..8d78430a2 100644 --- a/src/json.hpp +++ b/src/json.hpp @@ -5887,8 +5887,8 @@ class basic_json @param[in,out] other array to exchange the contents with - @throw std::domain_error when JSON value is not an array; example: - `"cannot use swap() with string"` + @throw type_error.310 when JSON value is not an array; example: `"cannot + use swap() with string"` @complexity Constant. @@ -5906,7 +5906,7 @@ class basic_json } else { - JSON_THROW(std::domain_error("cannot use swap() with " + type_name())); + JSON_THROW(type_error(310, "cannot use swap() with " + type_name())); } } @@ -5920,7 +5920,7 @@ class basic_json @param[in,out] other object to exchange the contents with - @throw std::domain_error when JSON value is not an object; example: + @throw type_error.310 when JSON value is not an object; example: `"cannot use swap() with string"` @complexity Constant. @@ -5939,7 +5939,7 @@ class basic_json } else { - JSON_THROW(std::domain_error("cannot use swap() with " + type_name())); + JSON_THROW(type_error(310, "cannot use swap() with " + type_name())); } } @@ -5953,7 +5953,7 @@ class basic_json @param[in,out] other string to exchange the contents with - @throw std::domain_error when JSON value is not a string; example: `"cannot + @throw type_error.310 when JSON value is not a string; example: `"cannot use swap() with boolean"` @complexity Constant. @@ -5972,7 +5972,7 @@ class basic_json } else { - JSON_THROW(std::domain_error("cannot use swap() with " + type_name())); + JSON_THROW(type_error(310, "cannot use swap() with " + type_name())); } } diff --git a/src/json.hpp.re2c b/src/json.hpp.re2c index 8f12b9e24..2f03506cb 100644 --- a/src/json.hpp.re2c +++ b/src/json.hpp.re2c @@ -5887,8 +5887,8 @@ class basic_json @param[in,out] other array to exchange the contents with - @throw std::domain_error when JSON value is not an array; example: - `"cannot use swap() with string"` + @throw type_error.310 when JSON value is not an array; example: `"cannot + use swap() with string"` @complexity Constant. @@ -5906,7 +5906,7 @@ class basic_json } else { - JSON_THROW(std::domain_error("cannot use swap() with " + type_name())); + JSON_THROW(type_error(310, "cannot use swap() with " + type_name())); } } @@ -5920,7 +5920,7 @@ class basic_json @param[in,out] other object to exchange the contents with - @throw std::domain_error when JSON value is not an object; example: + @throw type_error.310 when JSON value is not an object; example: `"cannot use swap() with string"` @complexity Constant. @@ -5939,7 +5939,7 @@ class basic_json } else { - JSON_THROW(std::domain_error("cannot use swap() with " + type_name())); + JSON_THROW(type_error(310, "cannot use swap() with " + type_name())); } } @@ -5953,7 +5953,7 @@ class basic_json @param[in,out] other string to exchange the contents with - @throw std::domain_error when JSON value is not a string; example: `"cannot + @throw type_error.310 when JSON value is not a string; example: `"cannot use swap() with boolean"` @complexity Constant. @@ -5972,7 +5972,7 @@ class basic_json } else { - JSON_THROW(std::domain_error("cannot use swap() with " + type_name())); + JSON_THROW(type_error(310, "cannot use swap() with " + type_name())); } } diff --git a/test/src/unit-modifiers.cpp b/test/src/unit-modifiers.cpp index 029dc996d..d3c03094d 100644 --- a/test/src/unit-modifiers.cpp +++ b/test/src/unit-modifiers.cpp @@ -751,8 +751,8 @@ TEST_CASE("modifiers") json j = 17; json::array_t a = {"foo", "bar", "baz"}; - CHECK_THROWS_AS(j.swap(a), std::domain_error); - CHECK_THROWS_WITH(j.swap(a), "cannot use swap() with number"); + CHECK_THROWS_AS(j.swap(a), json::type_error); + CHECK_THROWS_WITH(j.swap(a), "[json.exception.type_error.310] cannot use swap() with number"); } } @@ -777,8 +777,8 @@ TEST_CASE("modifiers") json j = 17; json::object_t o = {{"cow", "Kuh"}, {"chicken", "Huhn"}}; - CHECK_THROWS_AS(j.swap(o), std::domain_error); - CHECK_THROWS_WITH(j.swap(o), "cannot use swap() with number"); + CHECK_THROWS_AS(j.swap(o), json::type_error); + CHECK_THROWS_WITH(j.swap(o), "[json.exception.type_error.310] cannot use swap() with number"); } } @@ -803,8 +803,8 @@ TEST_CASE("modifiers") json j = 17; json::string_t s = "Hallo Welt"; - CHECK_THROWS_AS(j.swap(s), std::domain_error); - CHECK_THROWS_WITH(j.swap(s), "cannot use swap() with number"); + CHECK_THROWS_AS(j.swap(s), json::type_error); + CHECK_THROWS_WITH(j.swap(s), "[json.exception.type_error.310] cannot use swap() with number"); } } } From 9e560ca40ce443b9d14e2889a5bb988cfbb900e3 Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Sun, 5 Mar 2017 19:58:26 +0100 Subject: [PATCH 17/52] :hammer: added user-defined exceptions 313-315 --- src/json.hpp | 6 +++--- src/json.hpp.re2c | 6 +++--- test/src/unit-json_pointer.cpp | 15 +++++++++------ 3 files changed, 15 insertions(+), 12 deletions(-) diff --git a/src/json.hpp b/src/json.hpp index 8d78430a2..54aaab56b 100644 --- a/src/json.hpp +++ b/src/json.hpp @@ -12059,7 +12059,7 @@ basic_json_parser_74: */ default: { - JSON_THROW(std::domain_error("invalid value to unflatten")); + JSON_THROW(type_error(313, "invalid value to unflatten")); } } } @@ -12496,7 +12496,7 @@ basic_json_parser_74: { if (not value.is_object()) { - JSON_THROW(std::domain_error("only objects can be unflattened")); + JSON_THROW(type_error(314, "only objects can be unflattened")); } basic_json result; @@ -12506,7 +12506,7 @@ basic_json_parser_74: { if (not element.second.is_primitive()) { - JSON_THROW(std::domain_error("values in object must be primitive")); + JSON_THROW(type_error(315, "values in object must be primitive")); } // assign value to reference pointed to by JSON pointer; Note diff --git a/src/json.hpp.re2c b/src/json.hpp.re2c index 2f03506cb..af91aa36c 100644 --- a/src/json.hpp.re2c +++ b/src/json.hpp.re2c @@ -11092,7 +11092,7 @@ class basic_json */ default: { - JSON_THROW(std::domain_error("invalid value to unflatten")); + JSON_THROW(type_error(313, "invalid value to unflatten")); } } } @@ -11529,7 +11529,7 @@ class basic_json { if (not value.is_object()) { - JSON_THROW(std::domain_error("only objects can be unflattened")); + JSON_THROW(type_error(314, "only objects can be unflattened")); } basic_json result; @@ -11539,7 +11539,7 @@ class basic_json { if (not element.second.is_primitive()) { - JSON_THROW(std::domain_error("values in object must be primitive")); + JSON_THROW(type_error(315, "values in object must be primitive")); } // assign value to reference pointed to by JSON pointer; Note diff --git a/test/src/unit-json_pointer.cpp b/test/src/unit-json_pointer.cpp index 3c05a2783..995196754 100644 --- a/test/src/unit-json_pointer.cpp +++ b/test/src/unit-json_pointer.cpp @@ -358,17 +358,20 @@ TEST_CASE("JSON pointers") CHECK(j_flatten.unflatten() == j); // error for nonobjects - CHECK_THROWS_AS(json(1).unflatten(), std::domain_error); - CHECK_THROWS_WITH(json(1).unflatten(), "only objects can be unflattened"); + CHECK_THROWS_AS(json(1).unflatten(), json::type_error); + CHECK_THROWS_WITH(json(1).unflatten(), + "[json.exception.type_error.314] only objects can be unflattened"); // error for nonprimitve values - CHECK_THROWS_AS(json({{"/1", {1, 2, 3}}}).unflatten(), std::domain_error); - CHECK_THROWS_WITH(json({{"/1", {1, 2, 3}}}).unflatten(), "values in object must be primitive"); + CHECK_THROWS_AS(json({{"/1", {1, 2, 3}}}).unflatten(), json::type_error); + CHECK_THROWS_WITH(json({{"/1", {1, 2, 3}}}).unflatten(), + "[json.exception.type_error.315] values in object must be primitive"); // error for conflicting values json j_error = {{"", 42}, {"/foo", 17}}; - CHECK_THROWS_AS(j_error.unflatten(), std::domain_error); - CHECK_THROWS_WITH(j_error.unflatten(), "invalid value to unflatten"); + CHECK_THROWS_AS(j_error.unflatten(), json::type_error); + CHECK_THROWS_WITH(j_error.unflatten(), + "[json.exception.type_error.313] invalid value to unflatten"); // explicit roundtrip check CHECK(j.flatten().unflatten() == j); From 6751d650be02a84651f6d0b0eec9650e480069e8 Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Sun, 5 Mar 2017 22:31:08 +0100 Subject: [PATCH 18/52] :hammer: added user-defined exception 311 --- src/json.hpp | 5 +++-- src/json.hpp.re2c | 5 +++-- test/src/unit-modifiers.cpp | 5 +++-- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/src/json.hpp b/src/json.hpp index 54aaab56b..b8ef59991 100644 --- a/src/json.hpp +++ b/src/json.hpp @@ -1137,6 +1137,7 @@ class basic_json json.exception.[type_error](@ref type_error).308 | "cannot use push_back() with string" | The @ref push_back() and @ref operator+= member functions can only be executed for certain JSON types. json.exception.[type_error](@ref type_error).309 | "cannot use insert() with" | The @ref insert() member functions can only be executed for certain JSON types. json.exception.[type_error](@ref type_error).310 | "cannot use swap() with number" | The @ref swap() member functions can only be executed for certain JSON types. + json.exception.[type_error](@ref type_error).311 | "cannot use emplace_back() with string" | The @ref emplace_back() member function can only be executed for certain JSON types. json.exception.[type_error](@ref type_error).313 | "invalid value to unflatten" | The @ref unflatten function converts an object whose keys are JSON Pointers back into an arbitrary nested JSON value. The JSON Pointers must not overlap, because then the resulting value would not be well defined. json.exception.[type_error](@ref type_error).314 | "only objects can be unflattened" | The @ref unflatten function only works for an object whose keys are JSON Pointers. json.exception.[type_error](@ref type_error).315 | "values in object must be primitive" | The @ref unflatten function only works for an object whose keys are JSON Pointers and whose values are primitive. @@ -5559,7 +5560,7 @@ class basic_json @param[in] args arguments to forward to a constructor of @ref basic_json @tparam Args compatible types to create a @ref basic_json object - @throw std::domain_error when called on a type other than JSON array or + @throw type_error.311 when called on a type other than JSON array or null; example: `"cannot use emplace_back() with number"` @complexity Amortized constant. @@ -5576,7 +5577,7 @@ class basic_json // emplace_back only works for null objects or arrays if (not(is_null() or is_array())) { - JSON_THROW(std::domain_error("cannot use emplace_back() with " + type_name())); + JSON_THROW(type_error(311, "cannot use emplace_back() with " + type_name())); } // transform null object into an array diff --git a/src/json.hpp.re2c b/src/json.hpp.re2c index af91aa36c..1026ad79b 100644 --- a/src/json.hpp.re2c +++ b/src/json.hpp.re2c @@ -1137,6 +1137,7 @@ class basic_json json.exception.[type_error](@ref type_error).308 | "cannot use push_back() with string" | The @ref push_back() and @ref operator+= member functions can only be executed for certain JSON types. json.exception.[type_error](@ref type_error).309 | "cannot use insert() with" | The @ref insert() member functions can only be executed for certain JSON types. json.exception.[type_error](@ref type_error).310 | "cannot use swap() with number" | The @ref swap() member functions can only be executed for certain JSON types. + json.exception.[type_error](@ref type_error).311 | "cannot use emplace_back() with string" | The @ref emplace_back() member function can only be executed for certain JSON types. json.exception.[type_error](@ref type_error).313 | "invalid value to unflatten" | The @ref unflatten function converts an object whose keys are JSON Pointers back into an arbitrary nested JSON value. The JSON Pointers must not overlap, because then the resulting value would not be well defined. json.exception.[type_error](@ref type_error).314 | "only objects can be unflattened" | The @ref unflatten function only works for an object whose keys are JSON Pointers. json.exception.[type_error](@ref type_error).315 | "values in object must be primitive" | The @ref unflatten function only works for an object whose keys are JSON Pointers and whose values are primitive. @@ -5559,7 +5560,7 @@ class basic_json @param[in] args arguments to forward to a constructor of @ref basic_json @tparam Args compatible types to create a @ref basic_json object - @throw std::domain_error when called on a type other than JSON array or + @throw type_error.311 when called on a type other than JSON array or null; example: `"cannot use emplace_back() with number"` @complexity Amortized constant. @@ -5576,7 +5577,7 @@ class basic_json // emplace_back only works for null objects or arrays if (not(is_null() or is_array())) { - JSON_THROW(std::domain_error("cannot use emplace_back() with " + type_name())); + JSON_THROW(type_error(311, "cannot use emplace_back() with " + type_name())); } // transform null object into an array diff --git a/test/src/unit-modifiers.cpp b/test/src/unit-modifiers.cpp index d3c03094d..c1a769092 100644 --- a/test/src/unit-modifiers.cpp +++ b/test/src/unit-modifiers.cpp @@ -291,8 +291,9 @@ TEST_CASE("modifiers") SECTION("other type") { json j = 1; - CHECK_THROWS_AS(j.emplace_back("Hello"), std::domain_error); - CHECK_THROWS_WITH(j.emplace_back("Hello"), "cannot use emplace_back() with number"); + CHECK_THROWS_AS(j.emplace_back("Hello"), json::type_error); + CHECK_THROWS_WITH(j.emplace_back("Hello"), + "[json.exception.type_error.311] cannot use emplace_back() with number"); } } From 491c9780a7063e0a39c2adcb0aa9a8f3b2016a5e Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Sun, 5 Mar 2017 22:39:21 +0100 Subject: [PATCH 19/52] :hammer: added user-defined exception 311 --- src/json.hpp | 4 ++-- src/json.hpp.re2c | 4 ++-- test/src/unit-modifiers.cpp | 7 ++++--- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/json.hpp b/src/json.hpp index b8ef59991..00e3fe246 100644 --- a/src/json.hpp +++ b/src/json.hpp @@ -5607,7 +5607,7 @@ class basic_json already-existing element if no insertion happened, and a bool denoting whether the insertion took place. - @throw std::domain_error when called on a type other than JSON object or + @throw type_error.311 when called on a type other than JSON object or null; example: `"cannot use emplace() with number"` @complexity Logarithmic in the size of the container, O(log(`size()`)). @@ -5625,7 +5625,7 @@ class basic_json // emplace only works for null objects or arrays if (not(is_null() or is_object())) { - JSON_THROW(std::domain_error("cannot use emplace() with " + type_name())); + JSON_THROW(type_error(311, "cannot use emplace() with " + type_name())); } // transform null object into an object diff --git a/src/json.hpp.re2c b/src/json.hpp.re2c index 1026ad79b..8de7e16fb 100644 --- a/src/json.hpp.re2c +++ b/src/json.hpp.re2c @@ -5607,7 +5607,7 @@ class basic_json already-existing element if no insertion happened, and a bool denoting whether the insertion took place. - @throw std::domain_error when called on a type other than JSON object or + @throw type_error.311 when called on a type other than JSON object or null; example: `"cannot use emplace() with number"` @complexity Logarithmic in the size of the container, O(log(`size()`)). @@ -5625,7 +5625,7 @@ class basic_json // emplace only works for null objects or arrays if (not(is_null() or is_object())) { - JSON_THROW(std::domain_error("cannot use emplace() with " + type_name())); + JSON_THROW(type_error(311, "cannot use emplace() with " + type_name())); } // transform null object into an object diff --git a/test/src/unit-modifiers.cpp b/test/src/unit-modifiers.cpp index c1a769092..ad0554200 100644 --- a/test/src/unit-modifiers.cpp +++ b/test/src/unit-modifiers.cpp @@ -293,7 +293,7 @@ TEST_CASE("modifiers") json j = 1; CHECK_THROWS_AS(j.emplace_back("Hello"), json::type_error); CHECK_THROWS_WITH(j.emplace_back("Hello"), - "[json.exception.type_error.311] cannot use emplace_back() with number"); + "[json.exception.type_error.311] cannot use emplace_back() with number"); } } @@ -351,8 +351,9 @@ TEST_CASE("modifiers") SECTION("other type") { json j = 1; - CHECK_THROWS_AS(j.emplace("foo", "bar"), std::domain_error); - CHECK_THROWS_WITH(j.emplace("foo", "bar"), "cannot use emplace() with number"); + CHECK_THROWS_AS(j.emplace("foo", "bar"), json::type_error); + CHECK_THROWS_WITH(j.emplace("foo", "bar"), + "[json.exception.type_error.311] cannot use emplace() with number"); } } From 60da36aee214c1711edb87062a152bce3ca965a2 Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Sun, 5 Mar 2017 22:56:39 +0100 Subject: [PATCH 20/52] :hammer: added user-defined exceptions 401-402 --- src/json.hpp | 30 +++++++++++++------------- src/json.hpp.re2c | 30 +++++++++++++------------- test/src/unit-element_access1.cpp | 15 +++++++------ test/src/unit-json_patch.cpp | 25 +++++++++++++--------- test/src/unit-json_pointer.cpp | 35 ++++++++++++++++++------------- 5 files changed, 75 insertions(+), 60 deletions(-) diff --git a/src/json.hpp b/src/json.hpp index 00e3fe246..3ee57f6e9 100644 --- a/src/json.hpp +++ b/src/json.hpp @@ -3648,7 +3648,7 @@ class basic_json @throw type_error.304 if the JSON value is not an array; example: `"cannot use at() with string"` - @throw std::out_of_range if the index @a idx is out of range of the array; + @throw out_of_range.401 if the index @a idx is out of range of the array; that is, `idx >= size()`; example: `"array index 7 is out of range"` @complexity Constant. @@ -3670,7 +3670,7 @@ class basic_json JSON_CATCH (std::out_of_range&) { // create better exception explanation - JSON_THROW(std::out_of_range("array index " + std::to_string(idx) + " is out of range")); + JSON_THROW(out_of_range(401, "array index " + std::to_string(idx) + " is out of range")); } } else @@ -3691,7 +3691,7 @@ class basic_json @throw type_error.304 if the JSON value is not an array; example: `"cannot use at() with string"` - @throw std::out_of_range if the index @a idx is out of range of the array; + @throw out_of_range.401 if the index @a idx is out of range of the array; that is, `idx >= size()`; example: `"array index 7 is out of range"` @complexity Constant. @@ -3713,7 +3713,7 @@ class basic_json JSON_CATCH (std::out_of_range&) { // create better exception explanation - JSON_THROW(std::out_of_range("array index " + std::to_string(idx) + " is out of range")); + JSON_THROW(out_of_range(401, "array index " + std::to_string(idx) + " is out of range")); } } else @@ -4666,7 +4666,7 @@ class basic_json { if (idx >= size()) { - JSON_THROW(std::out_of_range("array index " + std::to_string(idx) + " is out of range")); + JSON_THROW(out_of_range(401, "array index " + std::to_string(idx) + " is out of range")); } m_value.array->erase(m_value.array->begin() + static_cast(idx)); @@ -12179,9 +12179,9 @@ basic_json_parser_74: if (reference_token == "-") { // "-" always fails the range check - JSON_THROW(std::out_of_range("array index '-' (" + - std::to_string(ptr->m_value.array->size()) + - ") is out of range")); + JSON_THROW(out_of_range(402, "array index '-' (" + + std::to_string(ptr->m_value.array->size()) + + ") is out of range")); } // error condition (cf. RFC 6901, Sect. 4) @@ -12238,9 +12238,9 @@ basic_json_parser_74: if (reference_token == "-") { // "-" cannot be used for const access - JSON_THROW(std::out_of_range("array index '-' (" + - std::to_string(ptr->m_value.array->size()) + - ") is out of range")); + JSON_THROW(out_of_range(402, "array index '-' (" + + std::to_string(ptr->m_value.array->size()) + + ") is out of range")); } // error condition (cf. RFC 6901, Sect. 4) @@ -12289,9 +12289,9 @@ basic_json_parser_74: if (reference_token == "-") { // "-" always fails the range check - JSON_THROW(std::out_of_range("array index '-' (" + - std::to_string(ptr->m_value.array->size()) + - ") is out of range")); + JSON_THROW(out_of_range(402, "array index '-' (" + + std::to_string(ptr->m_value.array->size()) + + ") is out of range")); } // error condition (cf. RFC 6901, Sect. 4) @@ -12850,7 +12850,7 @@ basic_json_parser_74: if (static_cast(idx) > parent.size()) { // avoid undefined behavior - JSON_THROW(std::out_of_range("array index " + std::to_string(idx) + " is out of range")); + JSON_THROW(out_of_range(401, "array index " + std::to_string(idx) + " is out of range")); } else { diff --git a/src/json.hpp.re2c b/src/json.hpp.re2c index 8de7e16fb..c02f6bf88 100644 --- a/src/json.hpp.re2c +++ b/src/json.hpp.re2c @@ -3648,7 +3648,7 @@ class basic_json @throw type_error.304 if the JSON value is not an array; example: `"cannot use at() with string"` - @throw std::out_of_range if the index @a idx is out of range of the array; + @throw out_of_range.401 if the index @a idx is out of range of the array; that is, `idx >= size()`; example: `"array index 7 is out of range"` @complexity Constant. @@ -3670,7 +3670,7 @@ class basic_json JSON_CATCH (std::out_of_range&) { // create better exception explanation - JSON_THROW(std::out_of_range("array index " + std::to_string(idx) + " is out of range")); + JSON_THROW(out_of_range(401, "array index " + std::to_string(idx) + " is out of range")); } } else @@ -3691,7 +3691,7 @@ class basic_json @throw type_error.304 if the JSON value is not an array; example: `"cannot use at() with string"` - @throw std::out_of_range if the index @a idx is out of range of the array; + @throw out_of_range.401 if the index @a idx is out of range of the array; that is, `idx >= size()`; example: `"array index 7 is out of range"` @complexity Constant. @@ -3713,7 +3713,7 @@ class basic_json JSON_CATCH (std::out_of_range&) { // create better exception explanation - JSON_THROW(std::out_of_range("array index " + std::to_string(idx) + " is out of range")); + JSON_THROW(out_of_range(401, "array index " + std::to_string(idx) + " is out of range")); } } else @@ -4666,7 +4666,7 @@ class basic_json { if (idx >= size()) { - JSON_THROW(std::out_of_range("array index " + std::to_string(idx) + " is out of range")); + JSON_THROW(out_of_range(401, "array index " + std::to_string(idx) + " is out of range")); } m_value.array->erase(m_value.array->begin() + static_cast(idx)); @@ -11212,9 +11212,9 @@ class basic_json if (reference_token == "-") { // "-" always fails the range check - JSON_THROW(std::out_of_range("array index '-' (" + - std::to_string(ptr->m_value.array->size()) + - ") is out of range")); + JSON_THROW(out_of_range(402, "array index '-' (" + + std::to_string(ptr->m_value.array->size()) + + ") is out of range")); } // error condition (cf. RFC 6901, Sect. 4) @@ -11271,9 +11271,9 @@ class basic_json if (reference_token == "-") { // "-" cannot be used for const access - JSON_THROW(std::out_of_range("array index '-' (" + - std::to_string(ptr->m_value.array->size()) + - ") is out of range")); + JSON_THROW(out_of_range(402, "array index '-' (" + + std::to_string(ptr->m_value.array->size()) + + ") is out of range")); } // error condition (cf. RFC 6901, Sect. 4) @@ -11322,9 +11322,9 @@ class basic_json if (reference_token == "-") { // "-" always fails the range check - JSON_THROW(std::out_of_range("array index '-' (" + - std::to_string(ptr->m_value.array->size()) + - ") is out of range")); + JSON_THROW(out_of_range(402, "array index '-' (" + + std::to_string(ptr->m_value.array->size()) + + ") is out of range")); } // error condition (cf. RFC 6901, Sect. 4) @@ -11883,7 +11883,7 @@ class basic_json if (static_cast(idx) > parent.size()) { // avoid undefined behavior - JSON_THROW(std::out_of_range("array index " + std::to_string(idx) + " is out of range")); + JSON_THROW(out_of_range(401, "array index " + std::to_string(idx) + " is out of range")); } else { diff --git a/test/src/unit-element_access1.cpp b/test/src/unit-element_access1.cpp index e0e3ee99a..b8a57af43 100644 --- a/test/src/unit-element_access1.cpp +++ b/test/src/unit-element_access1.cpp @@ -63,11 +63,13 @@ TEST_CASE("element access 1") SECTION("access outside bounds") { - CHECK_THROWS_AS(j.at(8), std::out_of_range); - CHECK_THROWS_AS(j_const.at(8), std::out_of_range); + CHECK_THROWS_AS(j.at(8), json::out_of_range); + CHECK_THROWS_AS(j_const.at(8), json::out_of_range); - CHECK_THROWS_WITH(j.at(8), "array index 8 is out of range"); - CHECK_THROWS_WITH(j_const.at(8), "array index 8 is out of range"); + CHECK_THROWS_WITH(j.at(8), + "[json.exception.out_of_range.401] array index 8 is out of range"); + CHECK_THROWS_WITH(j_const.at(8), + "[json.exception.out_of_range.401] array index 8 is out of range"); } SECTION("access on non-array type") @@ -311,8 +313,9 @@ TEST_CASE("element access 1") } { json jarray = {1, 1u, true, nullptr, "string", 42.23, json::object(), {1, 2, 3}}; - CHECK_THROWS_AS(jarray.erase(8), std::out_of_range); - CHECK_THROWS_WITH(jarray.erase(8), "array index 8 is out of range"); + CHECK_THROWS_AS(jarray.erase(8), json::out_of_range); + CHECK_THROWS_WITH(jarray.erase(8), + "[json.exception.out_of_range.401] array index 8 is out of range"); } } diff --git a/test/src/unit-json_patch.cpp b/test/src/unit-json_patch.cpp index 1d905bb5e..feb7a154f 100644 --- a/test/src/unit-json_patch.cpp +++ b/test/src/unit-json_patch.cpp @@ -741,8 +741,9 @@ TEST_CASE("JSON patch") { json j = {1, 2}; json patch = {{{"op", "add"}, {"path", "/4"}, {"value", 4}}}; - CHECK_THROWS_AS(j.patch(patch), std::out_of_range); - CHECK_THROWS_WITH(j.patch(patch), "array index 4 is out of range"); + CHECK_THROWS_AS(j.patch(patch), json::out_of_range); + CHECK_THROWS_WITH(j.patch(patch), + "[json.exception.out_of_range.401] array index 4 is out of range"); } } @@ -770,8 +771,9 @@ TEST_CASE("JSON patch") { json j = {1, 2, 3}; json patch = {{{"op", "remove"}, {"path", "/17"}}}; - CHECK_THROWS_AS(j.patch(patch), std::out_of_range); - CHECK_THROWS_WITH(j.patch(patch), "array index 17 is out of range"); + CHECK_THROWS_AS(j.patch(patch), json::out_of_range); + CHECK_THROWS_WITH(j.patch(patch), + "[json.exception.out_of_range.401] array index 17 is out of range"); } SECTION("nonexisting target location (object)") @@ -824,8 +826,9 @@ TEST_CASE("JSON patch") { json j = {1, 2, 3}; json patch = {{{"op", "replace"}, {"path", "/17"}, {"value", 19}}}; - CHECK_THROWS_AS(j.patch(patch), std::out_of_range); - CHECK_THROWS_WITH(j.patch(patch), "array index 17 is out of range"); + CHECK_THROWS_AS(j.patch(patch), json::out_of_range); + CHECK_THROWS_WITH(j.patch(patch), + "[json.exception.out_of_range.401] array index 17 is out of range"); } SECTION("nonexisting target location (object)") @@ -879,8 +882,9 @@ TEST_CASE("JSON patch") { json j = {1, 2, 3}; json patch = {{{"op", "move"}, {"path", "/0"}, {"from", "/5"}}}; - CHECK_THROWS_AS(j.patch(patch), std::out_of_range); - CHECK_THROWS_WITH(j.patch(patch), "array index 5 is out of range"); + CHECK_THROWS_AS(j.patch(patch), json::out_of_range); + CHECK_THROWS_WITH(j.patch(patch), + "[json.exception.out_of_range.401] array index 5 is out of range"); } SECTION("nonexisting from location (object)") @@ -934,8 +938,9 @@ TEST_CASE("JSON patch") { json j = {1, 2, 3}; json patch = {{{"op", "copy"}, {"path", "/0"}, {"from", "/5"}}}; - CHECK_THROWS_AS(j.patch(patch), std::out_of_range); - CHECK_THROWS_WITH(j.patch(patch), "array index 5 is out of range"); + CHECK_THROWS_AS(j.patch(patch), json::out_of_range); + CHECK_THROWS_WITH(j.patch(patch), + "[json.exception.out_of_range.401] array index 5 is out of range"); } SECTION("nonexisting from location (object)") diff --git a/test/src/unit-json_pointer.cpp b/test/src/unit-json_pointer.cpp index 995196754..db45a9666 100644 --- a/test/src/unit-json_pointer.cpp +++ b/test/src/unit-json_pointer.cpp @@ -271,14 +271,17 @@ TEST_CASE("JSON pointers") CHECK(j == json({1, 13, 3, 33, nullptr, 55, 99})); // error when using "-" in const object - CHECK_THROWS_AS(j_const["/-"_json_pointer], std::out_of_range); - CHECK_THROWS_WITH(j_const["/-"_json_pointer], "array index '-' (3) is out of range"); + CHECK_THROWS_AS(j_const["/-"_json_pointer], json::out_of_range); + CHECK_THROWS_WITH(j_const["/-"_json_pointer], + "[json.exception.out_of_range.402] array index '-' (3) is out of range"); // error when using "-" with at - CHECK_THROWS_AS(j.at("/-"_json_pointer), std::out_of_range); - CHECK_THROWS_WITH(j.at("/-"_json_pointer), "array index '-' (7) is out of range"); - CHECK_THROWS_AS(j_const.at("/-"_json_pointer), std::out_of_range); - CHECK_THROWS_WITH(j_const.at("/-"_json_pointer), "array index '-' (3) is out of range"); + CHECK_THROWS_AS(j.at("/-"_json_pointer), json::out_of_range); + CHECK_THROWS_WITH(j.at("/-"_json_pointer), + "[json.exception.out_of_range.402] array index '-' (7) is out of range"); + CHECK_THROWS_AS(j_const.at("/-"_json_pointer), json::out_of_range); + CHECK_THROWS_WITH(j_const.at("/-"_json_pointer), + "[json.exception.out_of_range.402] array index '-' (3) is out of range"); } SECTION("const access") @@ -291,18 +294,22 @@ TEST_CASE("JSON pointers") CHECK(j["/2"_json_pointer] == j[2]); // assign to nonexisting index - CHECK_THROWS_AS(j.at("/3"_json_pointer), std::out_of_range); - CHECK_THROWS_WITH(j.at("/3"_json_pointer), "array index 3 is out of range"); + CHECK_THROWS_AS(j.at("/3"_json_pointer), json::out_of_range); + CHECK_THROWS_WITH(j.at("/3"_json_pointer), + "[json.exception.out_of_range.401] array index 3 is out of range"); // assign to nonexisting index (with gap) - CHECK_THROWS_AS(j.at("/5"_json_pointer), std::out_of_range); - CHECK_THROWS_WITH(j.at("/5"_json_pointer), "array index 5 is out of range"); + CHECK_THROWS_AS(j.at("/5"_json_pointer), json::out_of_range); + CHECK_THROWS_WITH(j.at("/5"_json_pointer), + "[json.exception.out_of_range.401] array index 5 is out of range"); // assign to "-" - CHECK_THROWS_AS(j["/-"_json_pointer], std::out_of_range); - CHECK_THROWS_WITH(j["/-"_json_pointer], "array index '-' (3) is out of range"); - CHECK_THROWS_AS(j.at("/-"_json_pointer), std::out_of_range); - CHECK_THROWS_WITH(j.at("/-"_json_pointer), "array index '-' (3) is out of range"); + CHECK_THROWS_AS(j["/-"_json_pointer], json::out_of_range); + CHECK_THROWS_WITH(j["/-"_json_pointer], + "[json.exception.out_of_range.402] array index '-' (3) is out of range"); + CHECK_THROWS_AS(j.at("/-"_json_pointer), json::out_of_range); + CHECK_THROWS_WITH(j.at("/-"_json_pointer), + "[json.exception.out_of_range.402] array index '-' (3) is out of range"); } } From 30331fa21fc89c962756912a9f69d565dd3209fb Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Sun, 5 Mar 2017 23:16:17 +0100 Subject: [PATCH 21/52] :hammer: added user-defined exception 403 --- src/json.hpp | 24 ++++++++++++------------ src/json.hpp.re2c | 24 ++++++++++++------------ test/src/unit-element_access2.cpp | 10 ++++++---- test/src/unit-json_patch.cpp | 30 ++++++++++++++++++------------ test/src/unit-json_pointer.cpp | 5 +++-- 5 files changed, 51 insertions(+), 42 deletions(-) diff --git a/src/json.hpp b/src/json.hpp index 3ee57f6e9..54528175b 100644 --- a/src/json.hpp +++ b/src/json.hpp @@ -3734,7 +3734,7 @@ class basic_json @throw type_error.304 if the JSON value is not an object; example: `"cannot use at() with boolean"` - @throw std::out_of_range if the key @a key is is not stored in the object; + @throw out_of_range.403 if the key @a key is is not stored in the object; that is, `find(key) == end()`; example: `"key "the fast" not found"` @complexity Logarithmic in the size of the container. @@ -3760,7 +3760,7 @@ class basic_json JSON_CATCH (std::out_of_range&) { // create better exception explanation - JSON_THROW(std::out_of_range("key '" + key + "' not found")); + JSON_THROW(out_of_range(403, "key '" + key + "' not found")); } } else @@ -3781,7 +3781,7 @@ class basic_json @throw type_error.304 if the JSON value is not an object; example: `"cannot use at() with boolean"` - @throw std::out_of_range if the key @a key is is not stored in the object; + @throw out_of_range.403 if the key @a key is is not stored in the object; that is, `find(key) == end()`; example: `"key "the fast" not found"` @complexity Logarithmic in the size of the container. @@ -3807,7 +3807,7 @@ class basic_json JSON_CATCH (std::out_of_range&) { // create better exception explanation - JSON_THROW(std::out_of_range("key '" + key + "' not found")); + JSON_THROW(out_of_range(403, "key '" + key + "' not found")); } } else @@ -4154,7 +4154,7 @@ class basic_json @code {.cpp} try { return at(key); - } catch(std::out_of_range) { + } catch(out_of_range) { return default_value; } @endcode @@ -4233,7 +4233,7 @@ class basic_json @code {.cpp} try { return at(ptr); - } catch(std::out_of_range) { + } catch(out_of_range) { return default_value; } @endcode @@ -4276,7 +4276,7 @@ class basic_json { return ptr.get_checked(this); } - JSON_CATCH (std::out_of_range&) + JSON_CATCH (out_of_range&) { return default_value; } @@ -12746,9 +12746,9 @@ basic_json_parser_74: any case, the original value is not changed: the patch is applied to a copy of the value. - @throw std::out_of_range if a JSON pointer inside the patch could not - be resolved successfully in the current JSON value; example: `"key baz - not found"` + @throw out_of_range.403 if a JSON pointer inside the patch could not be + resolved successfully in the current JSON value; example: `"key baz not + found"` @throw invalid_argument if the JSON patch is malformed (e.g., mandatory attributes are missing); example: `"operation add must have member path"` @throw parse_error.104 if the JSON patch does not consist of an array of @@ -12888,7 +12888,7 @@ basic_json_parser_74: } else { - JSON_THROW(std::out_of_range("key '" + last_path + "' not found")); + JSON_THROW(out_of_range(403, "key '" + last_path + "' not found")); } } else if (parent.is_array()) @@ -13002,7 +13002,7 @@ basic_json_parser_74: // the "path" location must exist - use at() success = (result.at(ptr) == get_value("test", "value", false)); } - JSON_CATCH (std::out_of_range&) + JSON_CATCH (out_of_range&) { // ignore out of range errors: success remains false } diff --git a/src/json.hpp.re2c b/src/json.hpp.re2c index c02f6bf88..2bbff0fbf 100644 --- a/src/json.hpp.re2c +++ b/src/json.hpp.re2c @@ -3734,7 +3734,7 @@ class basic_json @throw type_error.304 if the JSON value is not an object; example: `"cannot use at() with boolean"` - @throw std::out_of_range if the key @a key is is not stored in the object; + @throw out_of_range.403 if the key @a key is is not stored in the object; that is, `find(key) == end()`; example: `"key "the fast" not found"` @complexity Logarithmic in the size of the container. @@ -3760,7 +3760,7 @@ class basic_json JSON_CATCH (std::out_of_range&) { // create better exception explanation - JSON_THROW(std::out_of_range("key '" + key + "' not found")); + JSON_THROW(out_of_range(403, "key '" + key + "' not found")); } } else @@ -3781,7 +3781,7 @@ class basic_json @throw type_error.304 if the JSON value is not an object; example: `"cannot use at() with boolean"` - @throw std::out_of_range if the key @a key is is not stored in the object; + @throw out_of_range.403 if the key @a key is is not stored in the object; that is, `find(key) == end()`; example: `"key "the fast" not found"` @complexity Logarithmic in the size of the container. @@ -3807,7 +3807,7 @@ class basic_json JSON_CATCH (std::out_of_range&) { // create better exception explanation - JSON_THROW(std::out_of_range("key '" + key + "' not found")); + JSON_THROW(out_of_range(403, "key '" + key + "' not found")); } } else @@ -4154,7 +4154,7 @@ class basic_json @code {.cpp} try { return at(key); - } catch(std::out_of_range) { + } catch(out_of_range) { return default_value; } @endcode @@ -4233,7 +4233,7 @@ class basic_json @code {.cpp} try { return at(ptr); - } catch(std::out_of_range) { + } catch(out_of_range) { return default_value; } @endcode @@ -4276,7 +4276,7 @@ class basic_json { return ptr.get_checked(this); } - JSON_CATCH (std::out_of_range&) + JSON_CATCH (out_of_range&) { return default_value; } @@ -11779,9 +11779,9 @@ class basic_json any case, the original value is not changed: the patch is applied to a copy of the value. - @throw std::out_of_range if a JSON pointer inside the patch could not - be resolved successfully in the current JSON value; example: `"key baz - not found"` + @throw out_of_range.403 if a JSON pointer inside the patch could not be + resolved successfully in the current JSON value; example: `"key baz not + found"` @throw invalid_argument if the JSON patch is malformed (e.g., mandatory attributes are missing); example: `"operation add must have member path"` @throw parse_error.104 if the JSON patch does not consist of an array of @@ -11921,7 +11921,7 @@ class basic_json } else { - JSON_THROW(std::out_of_range("key '" + last_path + "' not found")); + JSON_THROW(out_of_range(403, "key '" + last_path + "' not found")); } } else if (parent.is_array()) @@ -12035,7 +12035,7 @@ class basic_json // the "path" location must exist - use at() success = (result.at(ptr) == get_value("test", "value", false)); } - JSON_CATCH (std::out_of_range&) + JSON_CATCH (out_of_range&) { // ignore out of range errors: success remains false } diff --git a/test/src/unit-element_access2.cpp b/test/src/unit-element_access2.cpp index 4a066e709..3533bdcd9 100644 --- a/test/src/unit-element_access2.cpp +++ b/test/src/unit-element_access2.cpp @@ -63,10 +63,12 @@ TEST_CASE("element access 2") SECTION("access outside bounds") { - CHECK_THROWS_AS(j.at("foo"), std::out_of_range); - CHECK_THROWS_AS(j_const.at("foo"), std::out_of_range); - CHECK_THROWS_WITH(j.at("foo"), "key 'foo' not found"); - CHECK_THROWS_WITH(j_const.at("foo"), "key 'foo' not found"); + CHECK_THROWS_AS(j.at("foo"), json::out_of_range); + CHECK_THROWS_AS(j_const.at("foo"), json::out_of_range); + CHECK_THROWS_WITH(j.at("foo"), + "[json.exception.out_of_range.403] key 'foo' not found"); + CHECK_THROWS_WITH(j_const.at("foo"), + "[json.exception.out_of_range.403] key 'foo' not found"); } SECTION("access on non-object type") diff --git a/test/src/unit-json_patch.cpp b/test/src/unit-json_patch.cpp index feb7a154f..9c07aae61 100644 --- a/test/src/unit-json_patch.cpp +++ b/test/src/unit-json_patch.cpp @@ -75,8 +75,9 @@ TEST_CASE("JSON patch") json doc2 = R"({ "q": { "bar": 2 } })"_json; // because "a" does not exist. - CHECK_THROWS_AS(doc2.patch(patch), std::out_of_range); - CHECK_THROWS_WITH(doc2.patch(patch), "key 'a' not found"); + CHECK_THROWS_AS(doc2.patch(patch), json::out_of_range); + CHECK_THROWS_WITH(doc2.patch(patch), + "[json.exception.out_of_range.403] key 'a' not found"); } SECTION("4.2 remove") @@ -420,8 +421,9 @@ TEST_CASE("JSON patch") // references neither the root of the document, nor a member of // an existing object, nor a member of an existing array. - CHECK_THROWS_AS(doc.patch(patch), std::out_of_range); - CHECK_THROWS_WITH(doc.patch(patch), "key 'baz' not found"); + CHECK_THROWS_AS(doc.patch(patch), json::out_of_range); + CHECK_THROWS_WITH(doc.patch(patch), + "[json.exception.out_of_range.403] key 'baz' not found"); } // A.13. Invalid JSON Patch Document @@ -780,8 +782,9 @@ TEST_CASE("JSON patch") { json j = {{"foo", 1}, {"bar", 2}}; json patch = {{{"op", "remove"}, {"path", "/baz"}}}; - CHECK_THROWS_AS(j.patch(patch), std::out_of_range); - CHECK_THROWS_WITH(j.patch(patch), "key 'baz' not found"); + CHECK_THROWS_AS(j.patch(patch), json::out_of_range); + CHECK_THROWS_WITH(j.patch(patch), + "[json.exception.out_of_range.403] key 'baz' not found"); } SECTION("root element as target location") @@ -835,8 +838,9 @@ TEST_CASE("JSON patch") { json j = {{"foo", 1}, {"bar", 2}}; json patch = {{{"op", "replace"}, {"path", "/baz"}, {"value", 3}}}; - CHECK_THROWS_AS(j.patch(patch), std::out_of_range); - CHECK_THROWS_WITH(j.patch(patch), "key 'baz' not found"); + CHECK_THROWS_AS(j.patch(patch), json::out_of_range); + CHECK_THROWS_WITH(j.patch(patch), + "[json.exception.out_of_range.403] key 'baz' not found"); } } @@ -891,8 +895,9 @@ TEST_CASE("JSON patch") { json j = {{"foo", 1}, {"bar", 2}}; json patch = {{{"op", "move"}, {"path", "/baz"}, {"from", "/baz"}}}; - CHECK_THROWS_AS(j.patch(patch), std::out_of_range); - CHECK_THROWS_WITH(j.patch(patch), "key 'baz' not found"); + CHECK_THROWS_AS(j.patch(patch), json::out_of_range); + CHECK_THROWS_WITH(j.patch(patch), + "[json.exception.out_of_range.403] key 'baz' not found"); } } @@ -947,8 +952,9 @@ TEST_CASE("JSON patch") { json j = {{"foo", 1}, {"bar", 2}}; json patch = {{{"op", "copy"}, {"path", "/fob"}, {"from", "/baz"}}}; - CHECK_THROWS_AS(j.patch(patch), std::out_of_range); - CHECK_THROWS_WITH(j.patch(patch), "key 'baz' not found"); + CHECK_THROWS_AS(j.patch(patch), json::out_of_range); + CHECK_THROWS_WITH(j.patch(patch), + "[json.exception.out_of_range.403] key 'baz' not found"); } } diff --git a/test/src/unit-json_pointer.cpp b/test/src/unit-json_pointer.cpp index db45a9666..c12a56adf 100644 --- a/test/src/unit-json_pointer.cpp +++ b/test/src/unit-json_pointer.cpp @@ -185,8 +185,9 @@ TEST_CASE("JSON pointers") CHECK(j[json::json_pointer("/m~0n")] == j["m~n"]); // unescaped access - CHECK_THROWS_AS(j.at(json::json_pointer("/a/b")), std::out_of_range); - CHECK_THROWS_WITH(j.at(json::json_pointer("/a/b")), "key 'a' not found"); + CHECK_THROWS_AS(j.at(json::json_pointer("/a/b")), json::out_of_range); + CHECK_THROWS_WITH(j.at(json::json_pointer("/a/b")), + "[json.exception.out_of_range.403] key 'a' not found"); // unresolved access const json j_primitive = 1; From 38c2e20ce8ceee95077f3adba1bbb402b1192022 Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Sun, 5 Mar 2017 23:25:22 +0100 Subject: [PATCH 22/52] added user-defined exceptions 404-405 --- src/json.hpp | 14 +++++++------- src/json.hpp.re2c | 14 +++++++------- test/src/unit-json_patch.cpp | 5 +++-- test/src/unit-json_pointer.cpp | 30 ++++++++++++++++++------------ 4 files changed, 35 insertions(+), 28 deletions(-) diff --git a/src/json.hpp b/src/json.hpp index 54528175b..3de94bcee 100644 --- a/src/json.hpp +++ b/src/json.hpp @@ -11974,7 +11974,7 @@ basic_json_parser_74: { if (is_root()) { - JSON_THROW(std::domain_error("JSON pointer has no parent")); + JSON_THROW(out_of_range(405, "JSON pointer has no parent")); } auto last = reference_tokens.back(); @@ -11992,7 +11992,7 @@ basic_json_parser_74: { if (is_root()) { - JSON_THROW(std::domain_error("JSON pointer has no parent")); + JSON_THROW(out_of_range(405, "JSON pointer has no parent")); } json_pointer result = *this; @@ -12083,7 +12083,7 @@ basic_json_parser_74: @complexity Linear in the length of the JSON pointer. - @throw std::out_of_range if the JSON pointer can not be resolved + @throw out_of_range.404 if the JSON pointer can not be resolved @throw parse_error.106 if an array index begins with '0' @throw std::invalid_argument if an array index was not a number */ @@ -12153,7 +12153,7 @@ basic_json_parser_74: default: { - JSON_THROW(std::out_of_range("unresolved reference token '" + reference_token + "'")); + JSON_THROW(out_of_range(404, "unresolved reference token '" + reference_token + "'")); } } } @@ -12204,7 +12204,7 @@ basic_json_parser_74: default: { - JSON_THROW(std::out_of_range("unresolved reference token '" + reference_token + "'")); + JSON_THROW(out_of_range(404, "unresolved reference token '" + reference_token + "'")); } } } @@ -12263,7 +12263,7 @@ basic_json_parser_74: default: { - JSON_THROW(std::out_of_range("unresolved reference token '" + reference_token + "'")); + JSON_THROW(out_of_range(404, "unresolved reference token '" + reference_token + "'")); } } } @@ -12314,7 +12314,7 @@ basic_json_parser_74: default: { - JSON_THROW(std::out_of_range("unresolved reference token '" + reference_token + "'")); + JSON_THROW(out_of_range(404, "unresolved reference token '" + reference_token + "'")); } } } diff --git a/src/json.hpp.re2c b/src/json.hpp.re2c index 2bbff0fbf..b47a48cfa 100644 --- a/src/json.hpp.re2c +++ b/src/json.hpp.re2c @@ -11007,7 +11007,7 @@ class basic_json { if (is_root()) { - JSON_THROW(std::domain_error("JSON pointer has no parent")); + JSON_THROW(out_of_range(405, "JSON pointer has no parent")); } auto last = reference_tokens.back(); @@ -11025,7 +11025,7 @@ class basic_json { if (is_root()) { - JSON_THROW(std::domain_error("JSON pointer has no parent")); + JSON_THROW(out_of_range(405, "JSON pointer has no parent")); } json_pointer result = *this; @@ -11116,7 +11116,7 @@ class basic_json @complexity Linear in the length of the JSON pointer. - @throw std::out_of_range if the JSON pointer can not be resolved + @throw out_of_range.404 if the JSON pointer can not be resolved @throw parse_error.106 if an array index begins with '0' @throw std::invalid_argument if an array index was not a number */ @@ -11186,7 +11186,7 @@ class basic_json default: { - JSON_THROW(std::out_of_range("unresolved reference token '" + reference_token + "'")); + JSON_THROW(out_of_range(404, "unresolved reference token '" + reference_token + "'")); } } } @@ -11237,7 +11237,7 @@ class basic_json default: { - JSON_THROW(std::out_of_range("unresolved reference token '" + reference_token + "'")); + JSON_THROW(out_of_range(404, "unresolved reference token '" + reference_token + "'")); } } } @@ -11296,7 +11296,7 @@ class basic_json default: { - JSON_THROW(std::out_of_range("unresolved reference token '" + reference_token + "'")); + JSON_THROW(out_of_range(404, "unresolved reference token '" + reference_token + "'")); } } } @@ -11347,7 +11347,7 @@ class basic_json default: { - JSON_THROW(std::out_of_range("unresolved reference token '" + reference_token + "'")); + JSON_THROW(out_of_range(404, "unresolved reference token '" + reference_token + "'")); } } } diff --git a/test/src/unit-json_patch.cpp b/test/src/unit-json_patch.cpp index 9c07aae61..c021450bc 100644 --- a/test/src/unit-json_patch.cpp +++ b/test/src/unit-json_patch.cpp @@ -791,8 +791,9 @@ TEST_CASE("JSON patch") { json j = "string"; json patch = {{{"op", "remove"}, {"path", ""}}}; - CHECK_THROWS_AS(j.patch(patch), std::domain_error); - CHECK_THROWS_WITH(j.patch(patch), "JSON pointer has no parent"); + CHECK_THROWS_AS(j.patch(patch), json::out_of_range); + CHECK_THROWS_WITH(j.patch(patch), + "[json.exception.out_of_range.405] JSON pointer has no parent"); } } diff --git a/test/src/unit-json_pointer.cpp b/test/src/unit-json_pointer.cpp index c12a56adf..a6f811eb9 100644 --- a/test/src/unit-json_pointer.cpp +++ b/test/src/unit-json_pointer.cpp @@ -49,10 +49,12 @@ TEST_CASE("JSON pointers") "[json.exception.parse_error.108] parse error: escape character '~' must be followed with '0' or '1'"); json::json_pointer p; - CHECK_THROWS_AS(p.top(), std::domain_error); - CHECK_THROWS_WITH(p.top(), "JSON pointer has no parent"); - CHECK_THROWS_AS(p.pop_back(), std::domain_error); - CHECK_THROWS_WITH(p.pop_back(), "JSON pointer has no parent"); + CHECK_THROWS_AS(p.top(), json::out_of_range); + CHECK_THROWS_WITH(p.top(), + "[json.exception.out_of_range.405] JSON pointer has no parent"); + CHECK_THROWS_AS(p.pop_back(), json::out_of_range); + CHECK_THROWS_WITH(p.pop_back(), + "[json.exception.out_of_range.405] JSON pointer has no parent"); } SECTION("examples from RFC 6901") @@ -124,10 +126,12 @@ TEST_CASE("JSON pointers") // unresolved access json j_primitive = 1; - CHECK_THROWS_AS(j_primitive["/foo"_json_pointer], std::out_of_range); - CHECK_THROWS_WITH(j_primitive["/foo"_json_pointer], "unresolved reference token 'foo'"); - CHECK_THROWS_AS(j_primitive.at("/foo"_json_pointer), std::out_of_range); - CHECK_THROWS_WITH(j_primitive.at("/foo"_json_pointer), "unresolved reference token 'foo'"); + CHECK_THROWS_AS(j_primitive["/foo"_json_pointer], json::out_of_range); + CHECK_THROWS_WITH(j_primitive["/foo"_json_pointer], + "[json.exception.out_of_range.404] unresolved reference token 'foo'"); + CHECK_THROWS_AS(j_primitive.at("/foo"_json_pointer), json::out_of_range); + CHECK_THROWS_WITH(j_primitive.at("/foo"_json_pointer), + "[json.exception.out_of_range.404] unresolved reference token 'foo'"); } SECTION("const access") @@ -191,10 +195,12 @@ TEST_CASE("JSON pointers") // unresolved access const json j_primitive = 1; - CHECK_THROWS_AS(j_primitive["/foo"_json_pointer], std::out_of_range); - CHECK_THROWS_WITH(j_primitive["/foo"_json_pointer], "unresolved reference token 'foo'"); - CHECK_THROWS_AS(j_primitive.at("/foo"_json_pointer), std::out_of_range); - CHECK_THROWS_WITH(j_primitive.at("/foo"_json_pointer), "unresolved reference token 'foo'"); + CHECK_THROWS_AS(j_primitive["/foo"_json_pointer], json::out_of_range); + CHECK_THROWS_WITH(j_primitive["/foo"_json_pointer], + "[json.exception.out_of_range.404] unresolved reference token 'foo'"); + CHECK_THROWS_AS(j_primitive.at("/foo"_json_pointer), json::out_of_range); + CHECK_THROWS_WITH(j_primitive.at("/foo"_json_pointer), + "[json.exception.out_of_range.404] unresolved reference token 'foo'"); } SECTION("user-defined string literal") From a186106bde35032d813b82897a73efbcfbda230c Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Mon, 6 Mar 2017 19:34:44 +0100 Subject: [PATCH 23/52] :hammer: user-defined exception 302 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Also moved all exception classes into the detail namespace and introduced them via “using” into basic_json. --- src/json.hpp | 404 ++++++++++++++++++---------------- src/json.hpp.re2c | 404 ++++++++++++++++++---------------- test/src/unit-conversions.cpp | 184 ++++++++-------- 3 files changed, 530 insertions(+), 462 deletions(-) diff --git a/src/json.hpp b/src/json.hpp index 3de94bcee..d7108ed60 100644 --- a/src/json.hpp +++ b/src/json.hpp @@ -110,6 +110,187 @@ This namespace collects some functions that could not be defined inside the */ namespace detail { +//////////////// +// exceptions // +//////////////// + +/*! +@brief general exception of the @ref basic_json class + +Extension of std::exception objects with a member @a id for exception ids. + +@since version 3.0.0 +*/ +class exception : public std::exception +{ + public: + /// create exception with id an explanatory string + exception(int id_, const std::string& ename, const std::string& what_arg_) + : id(id_), + what_arg("[json.exception." + ename + "." + std::to_string(id_) + "] " + what_arg_) + {} + + /// returns the explanatory string + virtual const char* what() const noexcept + { + return what_arg.c_str(); + } + + /// the id of the exception + const int id; + + private: + /// the explanatory string + const std::string what_arg; +}; + +/*! +@brief exception indicating a parse error + +This excpetion is thrown by the library when a parse error occurs. Parse +errors can occur during the deserialization of JSON text as well as when +using JSON Patch. + +Member @a byte holds the byte index of the last read character in the input +file. + +@note For an input with n bytes, 1 is the index of the first character + and n+1 is the index of the terminating null byte or the end of + file. + +Exceptions have ids 1xx. + +name / id | example massage | description +------------------------------ | --------------- | ------------------------- +json.exception.[parse_error](@ref parse_error).101 | "parse error at 2: unexpected end of input; expected string literal" | This error indicates a syntax error while deserializing a JSON text. The error message describes that an unexpected token (character) was encountered, and the member @ref parse_error::byte indicates the error position. +json.exception.[parse_error](@ref parse_error).102 | "parse error at 14: missing or wrong low surrogate" | JSON uses the `\uxxxx` format to describe Unicode characters. Code points above above 0xFFFF are split into two `\uxxxx` entries ("surrogate pairs"). This error indicates that the surrogate pair is incomplete or contains an invalid code point. +json.exception.[parse_error](@ref parse_error).103 | "parse error: code points above 0x10FFFF are invalid" | Unicode supports code points up to 0x10FFFF. Code points above 0x10FFFF are invalid. +json.exception.[parse_error](@ref parse_error).104 | "parse error: JSON patch must be an array of objects" | [RFC 6902](https://tools.ietf.org/html/rfc6902) requires a JSON Patch document to be a JSON document that represents an array of objects. +json.exception.[parse_error](@ref parse_error).105 | "parse error: operation must have string member 'op'" | An operation of a JSON Patch document must contain exactly one "op" member, whose value indicates the operation to perform. Its value must be one of "add", "remove", "replace", "move", "copy", or "test"; other values are errors. +json.exception.[parse_error](@ref parse_error).106 | "parse error: array index '01' must not begin with '0'" | An array index in a JSON Pointer ([RFC 6901](https://tools.ietf.org/html/rfc6901)) may be `0` or any number wihtout a leading `0`. +json.exception.[parse_error](@ref parse_error).107 | "parse error: JSON pointer must be empty or begin with '/' - was: 'foo'" | A JSON Pointer must be a Unicode string containing a sequence of zero or more reference tokens, each prefixed by a `/` character. +json.exception.[parse_error](@ref parse_error).108 | "parse error: escape character '~' must be followed with '0' or '1'" | In a JSON Pointer, only `~0` and `~1` are valid escape sequences. +json.exception.[parse_error](@ref parse_error).109 | "parse error: array index 'one' is not a number" | A JSON Pointer array index must be a number. + +@since version 3.0.0 +*/ +class parse_error : public exception +{ + public: + /*! + @brief create a parse error exception + @param[in] id_ the id of the exception + @param[in] byte_ the byte index where the error occured (or 0 if + the position cannot be determined) + @param[in] what_arg_ the explanatory string + */ + parse_error(int id_, size_t byte_, const std::string& what_arg_) + : exception(id_, "parse_error", "parse error" + + (byte_ != 0 ? (" at " + std::to_string(byte_)) : "") + + ": " + what_arg_), + byte(byte_) + {} + + /*! + @brief byte index of the parse error + + The byte index of the last read character in the input file. + + @note For an input with n bytes, 1 is the index of the first character + and n+1 is the index of the terminating null byte or the end of + file. + */ + const size_t byte; +}; + +/*! +@brief exception indicating errors with iterators + +Exceptions have ids 2xx. + +name / id | example massage | description +------------------------------ | --------------- | ------------------------- +json.exception.[invalid_iterator](@ref invalid_iterator).201 | "iterators are not compatible" | The iterators passed to constructor @ref basic_json(InputIT first, InputIT last) are not compatible, meaning they do not belong to the same container. Therefore, the range (@a first, @a last) is invalid. +json.exception.[invalid_iterator](@ref invalid_iterator).202 | "iterator does not fit current value" | In an erase or insert function, the passed iterator @a pos does not belong to the JSON value for which the function was called. It hence does not define a valid position for the deletion/insertion. +json.exception.[invalid_iterator](@ref invalid_iterator).203 | "iterators do not fit current value" | Either iterator passed to function @ref erase(IteratorType first, IteratorType last) does not belong to the JSON value from which values shall be erased. It hence does not define a valid range to delete values from. +json.exception.[invalid_iterator](@ref invalid_iterator).204 | "iterators out of range" | When an iterator range for a primitive type (number, boolean, or string) is passed to a constructor or an erase function, this range has to be exactly (@ref begin(), @ref end()), because this is the only way the single stored value is expressed. All other ranges are invalid. +json.exception.[invalid_iterator](@ref invalid_iterator).205 | "iterator out of range" | When an iterator for a primitive type (number, boolean, or string) is passed to an erase function, the iterator has to be the @ref begin() iterator, because it is the only way to address the stored value. All other iterators are invalid. +json.exception.[invalid_iterator](@ref invalid_iterator).206 | "cannot construct with iterators from null" | The iterators passed to constructor @ref basic_json(InputIT first, InputIT last) belong to a JSON null value and hence to not define a valid range. +json.exception.[invalid_iterator](@ref invalid_iterator).207 | "cannot use key() for non-object iterators" | The key() member function can only be used on iterators belonging to a JSON object, because other types do not have a concept of a key. +json.exception.[invalid_iterator](@ref invalid_iterator).208 | "cannot use operator[] for object iterators" | The operator[] to specify a concrete offset cannot be used on iterators belonging to a JSON object, because JSON objects are unordered. +json.exception.[invalid_iterator](@ref invalid_iterator).209 | "cannot use offsets with object iterators" | The offset operators (+, -, +=, -=) cannot be used on iterators belonging to a JSON object, because JSON objects are unordered. +json.exception.[invalid_iterator](@ref invalid_iterator).210 | "iterators do not fit" | The iterator range passed to the insert function are not compatible, meaning they do not belong to the same container. Therefore, the range (@a first, @a last) is invalid. +json.exception.[invalid_iterator](@ref invalid_iterator).211 | "passed iterators may not belong to container" | The iterator range passed to the insert function must not be a subrange of the container to insert to. +json.exception.[invalid_iterator](@ref invalid_iterator).212 | "cannot compare iterators of different containers" | When two iterators are compared, they must belong to the same container. +json.exception.[invalid_iterator](@ref invalid_iterator).213 | "cannot compare order of object iterators" | The order of object iterators cannot be compated, because JSON objects are unordered. +json.exception.[invalid_iterator](@ref invalid_iterator).214 | "cannot get value" | Cannot get value for iterator: Either the iterator belongs to a null value or it is an iterator to a primitive type (number, boolean, or string), but the iterator is different to @ref begin(). + +@since version 3.0.0 +*/ +class invalid_iterator : public exception +{ + public: + invalid_iterator(int id_, const std::string& what_arg_) + : exception(id_, "invalid_iterator", what_arg_) + {} +}; + +/*! +@brief exception indicating executing a member function with a wrong type + +Exceptions have ids 3xx. + +name / id | example massage | description +------------------------------ | --------------- | ------------------------- +json.exception.[type_error](@ref type_error).301 | "cannot create object from initializer list" | To create an object from an initializer list, the initializer list must consist only of a list of pairs whose first element is a string. When this constraint is violated, an array is created instead. +json.exception.[type_error](@ref type_error).302 | "type must be object, but is array" | During implicit or explicit value conversion, the JSON type must be compatible to the target type. For instance, a JSON string can only be converted into string types, but not into numbers or boolean types. +json.exception.[type_error](@ref type_error).303 | "incompatible ReferenceType for get_ref, actual type is object" | To retrieve a reference to a value stored in a @ref basic_json object with @ref get_ref, the type of the reference must match the value type. For instance, for a JSON array, the @a ReferenceType must be @ref array_t&. +json.exception.[type_error](@ref type_error).304 | "cannot use at() with string" | The @ref at() member functions can only be executed for certain JSON types. +json.exception.[type_error](@ref type_error).305 | "cannot use operator[] with string" | The @ref operator[] member functions can only be executed for certain JSON types. +json.exception.[type_error](@ref type_error).306 | "cannot use value() with string" | The @ref value() member functions can only be executed for certain JSON types. +json.exception.[type_error](@ref type_error).307 | "cannot use erase() with string" | The @ref erase() member functions can only be executed for certain JSON types. +json.exception.[type_error](@ref type_error).308 | "cannot use push_back() with string" | The @ref push_back() and @ref operator+= member functions can only be executed for certain JSON types. +json.exception.[type_error](@ref type_error).309 | "cannot use insert() with" | The @ref insert() member functions can only be executed for certain JSON types. +json.exception.[type_error](@ref type_error).310 | "cannot use swap() with number" | The @ref swap() member functions can only be executed for certain JSON types. +json.exception.[type_error](@ref type_error).311 | "cannot use emplace_back() with string" | The @ref emplace_back() member function can only be executed for certain JSON types. +json.exception.[type_error](@ref type_error).313 | "invalid value to unflatten" | The @ref unflatten function converts an object whose keys are JSON Pointers back into an arbitrary nested JSON value. The JSON Pointers must not overlap, because then the resulting value would not be well defined. +json.exception.[type_error](@ref type_error).314 | "only objects can be unflattened" | The @ref unflatten function only works for an object whose keys are JSON Pointers. +json.exception.[type_error](@ref type_error).315 | "values in object must be primitive" | The @ref unflatten function only works for an object whose keys are JSON Pointers and whose values are primitive. + +@since version 3.0.0 +*/ +class type_error : public exception +{ + public: + type_error(int id_, const std::string& what_arg_) + : exception(id_, "type_error", what_arg_) + {} +}; + +/*! +@brief exception indicating access out of the defined range + +Exceptions have ids 4xx. + +name / id | example massage | description +------------------------------ | --------------- | ------------------------- +json.exception.[out_of_range](@ref out_of_range).401 | "array index 3 is out of range" | The provided array index @a i is larger than @a size-1. +json.exception.[out_of_range](@ref out_of_range).402 | "array index '-' (3) is out of range" | The special array index `-` in a JSON Pointer never describes a valid element of the array, but the index past the end. +json.exception.[out_of_range](@ref out_of_range).403 | "key 'foo' not found" | The provided key was not found in the JSON object. +json.exception.[out_of_range](@ref out_of_range).404 | "unresolved reference token 'foo'" | A reference token in a JSON Pointer could not be resolved. +json.exception.[out_of_range](@ref out_of_range).405 | "JSON pointer has no parent" | The JSON Patch operations 'remove' and 'add' can not be applied to the root element of the JSON value. + +@since version 3.0.0 +*/ +class out_of_range : public exception +{ + public: + out_of_range(int id_, const std::string& what_arg_) + : exception(id_, "out_of_range", what_arg_) + {} +}; + + /////////////////////////// // JSON type enumeration // /////////////////////////// @@ -617,8 +798,7 @@ void get_arithmetic_value(const BasicJsonType& j, ArithmeticType& val) } default: { - JSON_THROW( - std::domain_error("type must be number, but is " + j.type_name())); + JSON_THROW(type_error(302, "type must be number, but is " + j.type_name())); } } } @@ -628,7 +808,7 @@ void from_json(const BasicJsonType& j, typename BasicJsonType::boolean_t& b) { if (not j.is_boolean()) { - JSON_THROW(std::domain_error("type must be boolean, but is " + j.type_name())); + JSON_THROW(type_error(302, "type must be boolean, but is " + j.type_name())); } b = *j.template get_ptr(); } @@ -638,7 +818,7 @@ void from_json(const BasicJsonType& j, typename BasicJsonType::string_t& s) { if (not j.is_string()) { - JSON_THROW(std::domain_error("type must be string, but is " + j.type_name())); + JSON_THROW(type_error(302, "type must be string, but is " + j.type_name())); } s = *j.template get_ptr(); } @@ -675,7 +855,7 @@ void from_json(const BasicJsonType& j, typename BasicJsonType::array_t& arr) { if (not j.is_array()) { - JSON_THROW(std::domain_error("type must be array, but is " + j.type_name())); + JSON_THROW(type_error(302, "type must be array, but is " + j.type_name())); } arr = *j.template get_ptr(); } @@ -688,13 +868,13 @@ void from_json(const BasicJsonType& j, std::forward_list& l) // (except when it's null.. ?) if (j.is_null()) { - JSON_THROW(std::domain_error("type must be array, but is " + j.type_name())); + JSON_THROW(type_error(302, "type must be array, but is " + j.type_name())); } if (not std::is_same::value) { if (not j.is_array()) { - JSON_THROW(std::domain_error("type must be array, but is " + j.type_name())); + JSON_THROW(type_error(302, "type must be array, but is " + j.type_name())); } } for (auto it = j.rbegin(), end = j.rend(); it != end; ++it) @@ -744,7 +924,7 @@ void from_json(const BasicJsonType& j, CompatibleArrayType& arr) { if (j.is_null()) { - JSON_THROW(std::domain_error("type must be array, but is " + j.type_name())); + JSON_THROW(type_error(302, "type must be array, but is " + j.type_name())); } // when T == BasicJsonType, do not check if value_t is correct @@ -752,7 +932,7 @@ void from_json(const BasicJsonType& j, CompatibleArrayType& arr) { if (not j.is_array()) { - JSON_THROW(std::domain_error("type must be array, but is " + j.type_name())); + JSON_THROW(type_error(302, "type must be array, but is " + j.type_name())); } } from_json_array_impl(j, arr, priority_tag<1> {}); @@ -764,7 +944,7 @@ void from_json(const BasicJsonType& j, CompatibleObjectType& obj) { if (not j.is_object()) { - JSON_THROW(std::domain_error("type must be object, but is " + j.type_name())); + JSON_THROW(type_error(302, "type must be object, but is " + j.type_name())); } auto inner_object = j.template get_ptr(); @@ -814,7 +994,7 @@ void from_json(const BasicJsonType& j, ArithmeticType& val) } default: { - JSON_THROW(std::domain_error("type must be number, but is " + j.type_name())); + JSON_THROW(type_error(302, "type must be number, but is " + j.type_name())); } } } @@ -1046,6 +1226,33 @@ class basic_json template using json_serializer = JSONSerializer; + + //////////////// + // exceptions // + //////////////// + + /// @name exceptions + /// Classes to implement user-defined exceptions. + /// @{ + + /* + name / id | example massage | description + ------------------------------ | --------------- | ------------------------- + json.exception.other.500 | "unsuccessful" | A JSON Patch operation 'test' failed. + */ + + /// @copydoc detail::parse_error + using parse_error = detail::parse_error; + /// @copydoc detail::invalid_iterator + using invalid_iterator = detail::invalid_iterator; + /// @copydoc detail::type_error + using type_error = detail::type_error; + /// @copydoc detail::out_of_range + using out_of_range = detail::out_of_range; + + /// @} + + ///////////////////// // container types // ///////////////////// @@ -1088,179 +1295,6 @@ class basic_json /// @} - public: - //////////////// - // exceptions // - //////////////// - - /// @name exceptions - /// Classes to implement user-defined exceptions. - /// @{ - - /*! - @brief general exception of the @ref basic_json class - - Extension of std::exception objects with a member @a id for exception ids. - - name / id | example massage | description - ------------------------------ | --------------- | ------------------------- - json.exception.[parse_error](@ref parse_error).101 | "parse error at 2: unexpected end of input; expected string literal" | This error indicates a syntax error while deserializing a JSON text. The error message describes that an unexpected token (character) was encountered, and the member @ref parse_error::byte indicates the error position. - json.exception.[parse_error](@ref parse_error).102 | "parse error at 14: missing or wrong low surrogate" | JSON uses the `\uxxxx` format to describe Unicode characters. Code points above above 0xFFFF are split into two `\uxxxx` entries ("surrogate pairs"). This error indicates that the surrogate pair is incomplete or contains an invalid code point. - json.exception.[parse_error](@ref parse_error).103 | "parse error: code points above 0x10FFFF are invalid" | Unicode supports code points up to 0x10FFFF. Code points above 0x10FFFF are invalid. - json.exception.[parse_error](@ref parse_error).104 | "parse error: JSON patch must be an array of objects" | [RFC 6902](https://tools.ietf.org/html/rfc6902) requires a JSON Patch document to be a JSON document that represents an array of objects. - json.exception.[parse_error](@ref parse_error).105 | "parse error: operation must have string member 'op'" | An operation of a JSON Patch document must contain exactly one "op" member, whose value indicates the operation to perform. Its value must be one of "add", "remove", "replace", "move", "copy", or "test"; other values are errors. - json.exception.[parse_error](@ref parse_error).106 | "parse error: array index '01' must not begin with '0'" | An array index in a JSON Pointer ([RFC 6901](https://tools.ietf.org/html/rfc6901)) may be `0` or any number wihtout a leading `0`. - json.exception.[parse_error](@ref parse_error).107 | "parse error: JSON pointer must be empty or begin with '/' - was: 'foo'" | A JSON Pointer must be a Unicode string containing a sequence of zero or more reference tokens, each prefixed by a `/` character. - json.exception.[parse_error](@ref parse_error).108 | "parse error: escape character '~' must be followed with '0' or '1'" | In a JSON Pointer, only `~0` and `~1` are valid escape sequences. - json.exception.[parse_error](@ref parse_error).109 | "parse error: array index 'one' is not a number" | A JSON Pointer array index must be a number. - json.exception.[invalid_iterator](@ref invalid_iterator).201 | "iterators are not compatible" | The iterators passed to constructor @ref basic_json(InputIT first, InputIT last) are not compatible, meaning they do not belong to the same container. Therefore, the range (@a first, @a last) is invalid. - json.exception.[invalid_iterator](@ref invalid_iterator).202 | "iterator does not fit current value" | In an erase or insert function, the passed iterator @a pos does not belong to the JSON value for which the function was called. It hence does not define a valid position for the deletion/insertion. - json.exception.[invalid_iterator](@ref invalid_iterator).203 | "iterators do not fit current value" | Either iterator passed to function @ref erase(IteratorType first, IteratorType last) does not belong to the JSON value from which values shall be erased. It hence does not define a valid range to delete values from. - json.exception.[invalid_iterator](@ref invalid_iterator).204 | "iterators out of range" | When an iterator range for a primitive type (number, boolean, or string) is passed to a constructor or an erase function, this range has to be exactly (@ref begin(), @ref end()), because this is the only way the single stored value is expressed. All other ranges are invalid. - json.exception.[invalid_iterator](@ref invalid_iterator).205 | "iterator out of range" | When an iterator for a primitive type (number, boolean, or string) is passed to an erase function, the iterator has to be the @ref begin() iterator, because it is the only way to address the stored value. All other iterators are invalid. - json.exception.[invalid_iterator](@ref invalid_iterator).206 | "cannot construct with iterators from null" | The iterators passed to constructor @ref basic_json(InputIT first, InputIT last) belong to a JSON null value and hence to not define a valid range. - json.exception.[invalid_iterator](@ref invalid_iterator).207 | "cannot use key() for non-object iterators" | The key() member function can only be used on iterators belonging to a JSON object, because other types do not have a concept of a key. - json.exception.[invalid_iterator](@ref invalid_iterator).208 | "cannot use operator[] for object iterators" | The operator[] to specify a concrete offset cannot be used on iterators belonging to a JSON object, because JSON objects are unordered. - json.exception.[invalid_iterator](@ref invalid_iterator).209 | "cannot use offsets with object iterators" | The offset operators (+, -, +=, -=) cannot be used on iterators belonging to a JSON object, because JSON objects are unordered. - json.exception.[invalid_iterator](@ref invalid_iterator).210 | "iterators do not fit" | The iterator range passed to the insert function are not compatible, meaning they do not belong to the same container. Therefore, the range (@a first, @a last) is invalid. - json.exception.[invalid_iterator](@ref invalid_iterator).211 | "passed iterators may not belong to container" | The iterator range passed to the insert function must not be a subrange of the container to insert to. - json.exception.[invalid_iterator](@ref invalid_iterator).212 | "cannot compare iterators of different containers" | When two iterators are compared, they must belong to the same container. - json.exception.[invalid_iterator](@ref invalid_iterator).213 | "cannot compare order of object iterators" | The order of object iterators cannot be compated, because JSON objects are unordered. - json.exception.[invalid_iterator](@ref invalid_iterator).214 | "cannot get value" | Cannot get value for iterator: Either the iterator belongs to a null value or it is an iterator to a primitive type (number, boolean, or string), but the iterator is different to @ref begin(). - json.exception.[type_error](@ref type_error).301 | "cannot create object from initializer list" | To create an object from an initializer list, the initializer list must consist only of a list of pairs whose first element is a string. When this constraint is violated, an array is created instead. - json.exception.[type_error](@ref type_error).302 | "type must be object, but is array" | During implicit or explicit value conversion, the JSON type must be compatible to the target type. For instance, a JSON string can only be converted into string types, but not into numbers or boolean types. - json.exception.[type_error](@ref type_error).303 | "incompatible ReferenceType for get_ref, actual type is object" | To retrieve a reference to a value stored in a @ref basic_json object with @ref get_ref, the type of the reference must match the value type. For instance, for a JSON array, the @a ReferenceType must be @ref array_t&. - json.exception.[type_error](@ref type_error).304 | "cannot use at() with string" | The @ref at() member functions can only be executed for certain JSON types. - json.exception.[type_error](@ref type_error).305 | "cannot use operator[] with string" | The @ref operator[] member functions can only be executed for certain JSON types. - json.exception.[type_error](@ref type_error).306 | "cannot use value() with string" | The @ref value() member functions can only be executed for certain JSON types. - json.exception.[type_error](@ref type_error).307 | "cannot use erase() with string" | The @ref erase() member functions can only be executed for certain JSON types. - json.exception.[type_error](@ref type_error).308 | "cannot use push_back() with string" | The @ref push_back() and @ref operator+= member functions can only be executed for certain JSON types. - json.exception.[type_error](@ref type_error).309 | "cannot use insert() with" | The @ref insert() member functions can only be executed for certain JSON types. - json.exception.[type_error](@ref type_error).310 | "cannot use swap() with number" | The @ref swap() member functions can only be executed for certain JSON types. - json.exception.[type_error](@ref type_error).311 | "cannot use emplace_back() with string" | The @ref emplace_back() member function can only be executed for certain JSON types. - json.exception.[type_error](@ref type_error).313 | "invalid value to unflatten" | The @ref unflatten function converts an object whose keys are JSON Pointers back into an arbitrary nested JSON value. The JSON Pointers must not overlap, because then the resulting value would not be well defined. - json.exception.[type_error](@ref type_error).314 | "only objects can be unflattened" | The @ref unflatten function only works for an object whose keys are JSON Pointers. - json.exception.[type_error](@ref type_error).315 | "values in object must be primitive" | The @ref unflatten function only works for an object whose keys are JSON Pointers and whose values are primitive. - json.exception.[out_of_range](@ref out_of_range).401 | "array index 3 is out of range" | The provided array index @a i is larger than @a size-1. - json.exception.[out_of_range](@ref out_of_range).402 | "array index '-' (3) is out of range" | The special array index `-` in a JSON Pointer never describes a valid element of the array, but the index past the end. - json.exception.[out_of_range](@ref out_of_range).403 | "key 'foo' not found" | The provided key was not found in the JSON object. - json.exception.[out_of_range](@ref out_of_range).404 | "unresolved reference token 'foo'" | A reference token in a JSON Pointer could not be resolved. - json.exception.[out_of_range](@ref out_of_range).405 | "JSON pointer has no parent" | The JSON Patch operations 'remove' and 'add' can not be applied to the root element of the JSON value. - json.exception.other.500 | "unsuccessful" | A JSON Patch operation 'test' failed. - - @since version 3.0.0 - */ - class exception : public std::exception - { - public: - /// create exception with id an explanatory string - exception(int id_, const std::string& ename, const std::string& what_arg_) - : id(id_), - what_arg("[json.exception." + ename + "." + std::to_string(id_) + "] " + what_arg_) - {} - - /// returns the explanatory string - virtual const char* what() const noexcept - { - return what_arg.c_str(); - } - - /// the id of the exception - const int id; - - private: - /// the explanatory string - const std::string what_arg; - }; - - /*! - @brief exception indicating a parse error - - This excpetion is thrown by the library when a parse error occurs. Parse - errors can occur during the deserialization of JSON text as well as when - using JSON Patch. - - Exceptions have ids 1xx. - - @since version 3.0.0 - */ - class parse_error : public exception - { - public: - /*! - @brief create a parse error exception - @param[in] id_ the id of the exception - @param[in] byte_ the byte index where the error occured (or 0 if - the position cannot be determined) - @param[in] what_arg_ the explanatory string - */ - parse_error(int id_, size_t byte_, const std::string& what_arg_) - : exception(id_, "parse_error", "parse error" + - (byte_ != 0 ? (" at " + std::to_string(byte_)) : "") + - ": " + what_arg_), - byte(byte_) - {} - - /*! - @brief byte index of the parse error - - The byte index of the last read character in the input file. - - @note For an input with n bytes, 1 is the index of the first character - and n+1 is the index of the terminating null byte or the end of - file. - */ - const size_t byte; - }; - - /*! - @brief exception indicating errors with iterators - - Exceptions have ids 2xx. - - @since version 3.0.0 - */ - class invalid_iterator : public exception - { - public: - invalid_iterator(int id_, const std::string& what_arg_) - : exception(id_, "invalid_iterator", what_arg_) - {} - }; - - /*! - @brief exception indicating executing a member function with a wrong type - - Exceptions have ids 3xx. - - @since version 3.0.0 - */ - class type_error : public exception - { - public: - type_error(int id_, const std::string& what_arg_) - : exception(id_, "type_error", what_arg_) - {} - }; - - /*! - @brief exception indicating access out of the defined range - - Exceptions have ids 4xx. - - @since version 3.0.0 - */ - class out_of_range : public exception - { - public: - out_of_range(int id_, const std::string& what_arg_) - : exception(id_, "out_of_range", what_arg_) - {} - }; - - /// @} - - /*! @brief returns the allocator associated with the container */ @@ -3161,7 +3195,7 @@ class basic_json return m_value.boolean; } - JSON_THROW(std::domain_error("type must be boolean, but is " + type_name())); + JSON_THROW(type_error(302, "type must be boolean, but is " + type_name())); } /// get a pointer to the value (object) diff --git a/src/json.hpp.re2c b/src/json.hpp.re2c index b47a48cfa..4466a5096 100644 --- a/src/json.hpp.re2c +++ b/src/json.hpp.re2c @@ -110,6 +110,187 @@ This namespace collects some functions that could not be defined inside the */ namespace detail { +//////////////// +// exceptions // +//////////////// + +/*! +@brief general exception of the @ref basic_json class + +Extension of std::exception objects with a member @a id for exception ids. + +@since version 3.0.0 +*/ +class exception : public std::exception +{ + public: + /// create exception with id an explanatory string + exception(int id_, const std::string& ename, const std::string& what_arg_) + : id(id_), + what_arg("[json.exception." + ename + "." + std::to_string(id_) + "] " + what_arg_) + {} + + /// returns the explanatory string + virtual const char* what() const noexcept + { + return what_arg.c_str(); + } + + /// the id of the exception + const int id; + + private: + /// the explanatory string + const std::string what_arg; +}; + +/*! +@brief exception indicating a parse error + +This excpetion is thrown by the library when a parse error occurs. Parse +errors can occur during the deserialization of JSON text as well as when +using JSON Patch. + +Member @a byte holds the byte index of the last read character in the input +file. + +@note For an input with n bytes, 1 is the index of the first character + and n+1 is the index of the terminating null byte or the end of + file. + +Exceptions have ids 1xx. + +name / id | example massage | description +------------------------------ | --------------- | ------------------------- +json.exception.[parse_error](@ref parse_error).101 | "parse error at 2: unexpected end of input; expected string literal" | This error indicates a syntax error while deserializing a JSON text. The error message describes that an unexpected token (character) was encountered, and the member @ref parse_error::byte indicates the error position. +json.exception.[parse_error](@ref parse_error).102 | "parse error at 14: missing or wrong low surrogate" | JSON uses the `\uxxxx` format to describe Unicode characters. Code points above above 0xFFFF are split into two `\uxxxx` entries ("surrogate pairs"). This error indicates that the surrogate pair is incomplete or contains an invalid code point. +json.exception.[parse_error](@ref parse_error).103 | "parse error: code points above 0x10FFFF are invalid" | Unicode supports code points up to 0x10FFFF. Code points above 0x10FFFF are invalid. +json.exception.[parse_error](@ref parse_error).104 | "parse error: JSON patch must be an array of objects" | [RFC 6902](https://tools.ietf.org/html/rfc6902) requires a JSON Patch document to be a JSON document that represents an array of objects. +json.exception.[parse_error](@ref parse_error).105 | "parse error: operation must have string member 'op'" | An operation of a JSON Patch document must contain exactly one "op" member, whose value indicates the operation to perform. Its value must be one of "add", "remove", "replace", "move", "copy", or "test"; other values are errors. +json.exception.[parse_error](@ref parse_error).106 | "parse error: array index '01' must not begin with '0'" | An array index in a JSON Pointer ([RFC 6901](https://tools.ietf.org/html/rfc6901)) may be `0` or any number wihtout a leading `0`. +json.exception.[parse_error](@ref parse_error).107 | "parse error: JSON pointer must be empty or begin with '/' - was: 'foo'" | A JSON Pointer must be a Unicode string containing a sequence of zero or more reference tokens, each prefixed by a `/` character. +json.exception.[parse_error](@ref parse_error).108 | "parse error: escape character '~' must be followed with '0' or '1'" | In a JSON Pointer, only `~0` and `~1` are valid escape sequences. +json.exception.[parse_error](@ref parse_error).109 | "parse error: array index 'one' is not a number" | A JSON Pointer array index must be a number. + +@since version 3.0.0 +*/ +class parse_error : public exception +{ + public: + /*! + @brief create a parse error exception + @param[in] id_ the id of the exception + @param[in] byte_ the byte index where the error occured (or 0 if + the position cannot be determined) + @param[in] what_arg_ the explanatory string + */ + parse_error(int id_, size_t byte_, const std::string& what_arg_) + : exception(id_, "parse_error", "parse error" + + (byte_ != 0 ? (" at " + std::to_string(byte_)) : "") + + ": " + what_arg_), + byte(byte_) + {} + + /*! + @brief byte index of the parse error + + The byte index of the last read character in the input file. + + @note For an input with n bytes, 1 is the index of the first character + and n+1 is the index of the terminating null byte or the end of + file. + */ + const size_t byte; +}; + +/*! +@brief exception indicating errors with iterators + +Exceptions have ids 2xx. + +name / id | example massage | description +------------------------------ | --------------- | ------------------------- +json.exception.[invalid_iterator](@ref invalid_iterator).201 | "iterators are not compatible" | The iterators passed to constructor @ref basic_json(InputIT first, InputIT last) are not compatible, meaning they do not belong to the same container. Therefore, the range (@a first, @a last) is invalid. +json.exception.[invalid_iterator](@ref invalid_iterator).202 | "iterator does not fit current value" | In an erase or insert function, the passed iterator @a pos does not belong to the JSON value for which the function was called. It hence does not define a valid position for the deletion/insertion. +json.exception.[invalid_iterator](@ref invalid_iterator).203 | "iterators do not fit current value" | Either iterator passed to function @ref erase(IteratorType first, IteratorType last) does not belong to the JSON value from which values shall be erased. It hence does not define a valid range to delete values from. +json.exception.[invalid_iterator](@ref invalid_iterator).204 | "iterators out of range" | When an iterator range for a primitive type (number, boolean, or string) is passed to a constructor or an erase function, this range has to be exactly (@ref begin(), @ref end()), because this is the only way the single stored value is expressed. All other ranges are invalid. +json.exception.[invalid_iterator](@ref invalid_iterator).205 | "iterator out of range" | When an iterator for a primitive type (number, boolean, or string) is passed to an erase function, the iterator has to be the @ref begin() iterator, because it is the only way to address the stored value. All other iterators are invalid. +json.exception.[invalid_iterator](@ref invalid_iterator).206 | "cannot construct with iterators from null" | The iterators passed to constructor @ref basic_json(InputIT first, InputIT last) belong to a JSON null value and hence to not define a valid range. +json.exception.[invalid_iterator](@ref invalid_iterator).207 | "cannot use key() for non-object iterators" | The key() member function can only be used on iterators belonging to a JSON object, because other types do not have a concept of a key. +json.exception.[invalid_iterator](@ref invalid_iterator).208 | "cannot use operator[] for object iterators" | The operator[] to specify a concrete offset cannot be used on iterators belonging to a JSON object, because JSON objects are unordered. +json.exception.[invalid_iterator](@ref invalid_iterator).209 | "cannot use offsets with object iterators" | The offset operators (+, -, +=, -=) cannot be used on iterators belonging to a JSON object, because JSON objects are unordered. +json.exception.[invalid_iterator](@ref invalid_iterator).210 | "iterators do not fit" | The iterator range passed to the insert function are not compatible, meaning they do not belong to the same container. Therefore, the range (@a first, @a last) is invalid. +json.exception.[invalid_iterator](@ref invalid_iterator).211 | "passed iterators may not belong to container" | The iterator range passed to the insert function must not be a subrange of the container to insert to. +json.exception.[invalid_iterator](@ref invalid_iterator).212 | "cannot compare iterators of different containers" | When two iterators are compared, they must belong to the same container. +json.exception.[invalid_iterator](@ref invalid_iterator).213 | "cannot compare order of object iterators" | The order of object iterators cannot be compated, because JSON objects are unordered. +json.exception.[invalid_iterator](@ref invalid_iterator).214 | "cannot get value" | Cannot get value for iterator: Either the iterator belongs to a null value or it is an iterator to a primitive type (number, boolean, or string), but the iterator is different to @ref begin(). + +@since version 3.0.0 +*/ +class invalid_iterator : public exception +{ + public: + invalid_iterator(int id_, const std::string& what_arg_) + : exception(id_, "invalid_iterator", what_arg_) + {} +}; + +/*! +@brief exception indicating executing a member function with a wrong type + +Exceptions have ids 3xx. + +name / id | example massage | description +------------------------------ | --------------- | ------------------------- +json.exception.[type_error](@ref type_error).301 | "cannot create object from initializer list" | To create an object from an initializer list, the initializer list must consist only of a list of pairs whose first element is a string. When this constraint is violated, an array is created instead. +json.exception.[type_error](@ref type_error).302 | "type must be object, but is array" | During implicit or explicit value conversion, the JSON type must be compatible to the target type. For instance, a JSON string can only be converted into string types, but not into numbers or boolean types. +json.exception.[type_error](@ref type_error).303 | "incompatible ReferenceType for get_ref, actual type is object" | To retrieve a reference to a value stored in a @ref basic_json object with @ref get_ref, the type of the reference must match the value type. For instance, for a JSON array, the @a ReferenceType must be @ref array_t&. +json.exception.[type_error](@ref type_error).304 | "cannot use at() with string" | The @ref at() member functions can only be executed for certain JSON types. +json.exception.[type_error](@ref type_error).305 | "cannot use operator[] with string" | The @ref operator[] member functions can only be executed for certain JSON types. +json.exception.[type_error](@ref type_error).306 | "cannot use value() with string" | The @ref value() member functions can only be executed for certain JSON types. +json.exception.[type_error](@ref type_error).307 | "cannot use erase() with string" | The @ref erase() member functions can only be executed for certain JSON types. +json.exception.[type_error](@ref type_error).308 | "cannot use push_back() with string" | The @ref push_back() and @ref operator+= member functions can only be executed for certain JSON types. +json.exception.[type_error](@ref type_error).309 | "cannot use insert() with" | The @ref insert() member functions can only be executed for certain JSON types. +json.exception.[type_error](@ref type_error).310 | "cannot use swap() with number" | The @ref swap() member functions can only be executed for certain JSON types. +json.exception.[type_error](@ref type_error).311 | "cannot use emplace_back() with string" | The @ref emplace_back() member function can only be executed for certain JSON types. +json.exception.[type_error](@ref type_error).313 | "invalid value to unflatten" | The @ref unflatten function converts an object whose keys are JSON Pointers back into an arbitrary nested JSON value. The JSON Pointers must not overlap, because then the resulting value would not be well defined. +json.exception.[type_error](@ref type_error).314 | "only objects can be unflattened" | The @ref unflatten function only works for an object whose keys are JSON Pointers. +json.exception.[type_error](@ref type_error).315 | "values in object must be primitive" | The @ref unflatten function only works for an object whose keys are JSON Pointers and whose values are primitive. + +@since version 3.0.0 +*/ +class type_error : public exception +{ + public: + type_error(int id_, const std::string& what_arg_) + : exception(id_, "type_error", what_arg_) + {} +}; + +/*! +@brief exception indicating access out of the defined range + +Exceptions have ids 4xx. + +name / id | example massage | description +------------------------------ | --------------- | ------------------------- +json.exception.[out_of_range](@ref out_of_range).401 | "array index 3 is out of range" | The provided array index @a i is larger than @a size-1. +json.exception.[out_of_range](@ref out_of_range).402 | "array index '-' (3) is out of range" | The special array index `-` in a JSON Pointer never describes a valid element of the array, but the index past the end. +json.exception.[out_of_range](@ref out_of_range).403 | "key 'foo' not found" | The provided key was not found in the JSON object. +json.exception.[out_of_range](@ref out_of_range).404 | "unresolved reference token 'foo'" | A reference token in a JSON Pointer could not be resolved. +json.exception.[out_of_range](@ref out_of_range).405 | "JSON pointer has no parent" | The JSON Patch operations 'remove' and 'add' can not be applied to the root element of the JSON value. + +@since version 3.0.0 +*/ +class out_of_range : public exception +{ + public: + out_of_range(int id_, const std::string& what_arg_) + : exception(id_, "out_of_range", what_arg_) + {} +}; + + /////////////////////////// // JSON type enumeration // /////////////////////////// @@ -617,8 +798,7 @@ void get_arithmetic_value(const BasicJsonType& j, ArithmeticType& val) } default: { - JSON_THROW( - std::domain_error("type must be number, but is " + j.type_name())); + JSON_THROW(type_error(302, "type must be number, but is " + j.type_name())); } } } @@ -628,7 +808,7 @@ void from_json(const BasicJsonType& j, typename BasicJsonType::boolean_t& b) { if (not j.is_boolean()) { - JSON_THROW(std::domain_error("type must be boolean, but is " + j.type_name())); + JSON_THROW(type_error(302, "type must be boolean, but is " + j.type_name())); } b = *j.template get_ptr(); } @@ -638,7 +818,7 @@ void from_json(const BasicJsonType& j, typename BasicJsonType::string_t& s) { if (not j.is_string()) { - JSON_THROW(std::domain_error("type must be string, but is " + j.type_name())); + JSON_THROW(type_error(302, "type must be string, but is " + j.type_name())); } s = *j.template get_ptr(); } @@ -675,7 +855,7 @@ void from_json(const BasicJsonType& j, typename BasicJsonType::array_t& arr) { if (not j.is_array()) { - JSON_THROW(std::domain_error("type must be array, but is " + j.type_name())); + JSON_THROW(type_error(302, "type must be array, but is " + j.type_name())); } arr = *j.template get_ptr(); } @@ -688,13 +868,13 @@ void from_json(const BasicJsonType& j, std::forward_list& l) // (except when it's null.. ?) if (j.is_null()) { - JSON_THROW(std::domain_error("type must be array, but is " + j.type_name())); + JSON_THROW(type_error(302, "type must be array, but is " + j.type_name())); } if (not std::is_same::value) { if (not j.is_array()) { - JSON_THROW(std::domain_error("type must be array, but is " + j.type_name())); + JSON_THROW(type_error(302, "type must be array, but is " + j.type_name())); } } for (auto it = j.rbegin(), end = j.rend(); it != end; ++it) @@ -744,7 +924,7 @@ void from_json(const BasicJsonType& j, CompatibleArrayType& arr) { if (j.is_null()) { - JSON_THROW(std::domain_error("type must be array, but is " + j.type_name())); + JSON_THROW(type_error(302, "type must be array, but is " + j.type_name())); } // when T == BasicJsonType, do not check if value_t is correct @@ -752,7 +932,7 @@ void from_json(const BasicJsonType& j, CompatibleArrayType& arr) { if (not j.is_array()) { - JSON_THROW(std::domain_error("type must be array, but is " + j.type_name())); + JSON_THROW(type_error(302, "type must be array, but is " + j.type_name())); } } from_json_array_impl(j, arr, priority_tag<1> {}); @@ -764,7 +944,7 @@ void from_json(const BasicJsonType& j, CompatibleObjectType& obj) { if (not j.is_object()) { - JSON_THROW(std::domain_error("type must be object, but is " + j.type_name())); + JSON_THROW(type_error(302, "type must be object, but is " + j.type_name())); } auto inner_object = j.template get_ptr(); @@ -814,7 +994,7 @@ void from_json(const BasicJsonType& j, ArithmeticType& val) } default: { - JSON_THROW(std::domain_error("type must be number, but is " + j.type_name())); + JSON_THROW(type_error(302, "type must be number, but is " + j.type_name())); } } } @@ -1046,6 +1226,33 @@ class basic_json template using json_serializer = JSONSerializer; + + //////////////// + // exceptions // + //////////////// + + /// @name exceptions + /// Classes to implement user-defined exceptions. + /// @{ + + /* + name / id | example massage | description + ------------------------------ | --------------- | ------------------------- + json.exception.other.500 | "unsuccessful" | A JSON Patch operation 'test' failed. + */ + + /// @copydoc detail::parse_error + using parse_error = detail::parse_error; + /// @copydoc detail::invalid_iterator + using invalid_iterator = detail::invalid_iterator; + /// @copydoc detail::type_error + using type_error = detail::type_error; + /// @copydoc detail::out_of_range + using out_of_range = detail::out_of_range; + + /// @} + + ///////////////////// // container types // ///////////////////// @@ -1088,179 +1295,6 @@ class basic_json /// @} - public: - //////////////// - // exceptions // - //////////////// - - /// @name exceptions - /// Classes to implement user-defined exceptions. - /// @{ - - /*! - @brief general exception of the @ref basic_json class - - Extension of std::exception objects with a member @a id for exception ids. - - name / id | example massage | description - ------------------------------ | --------------- | ------------------------- - json.exception.[parse_error](@ref parse_error).101 | "parse error at 2: unexpected end of input; expected string literal" | This error indicates a syntax error while deserializing a JSON text. The error message describes that an unexpected token (character) was encountered, and the member @ref parse_error::byte indicates the error position. - json.exception.[parse_error](@ref parse_error).102 | "parse error at 14: missing or wrong low surrogate" | JSON uses the `\uxxxx` format to describe Unicode characters. Code points above above 0xFFFF are split into two `\uxxxx` entries ("surrogate pairs"). This error indicates that the surrogate pair is incomplete or contains an invalid code point. - json.exception.[parse_error](@ref parse_error).103 | "parse error: code points above 0x10FFFF are invalid" | Unicode supports code points up to 0x10FFFF. Code points above 0x10FFFF are invalid. - json.exception.[parse_error](@ref parse_error).104 | "parse error: JSON patch must be an array of objects" | [RFC 6902](https://tools.ietf.org/html/rfc6902) requires a JSON Patch document to be a JSON document that represents an array of objects. - json.exception.[parse_error](@ref parse_error).105 | "parse error: operation must have string member 'op'" | An operation of a JSON Patch document must contain exactly one "op" member, whose value indicates the operation to perform. Its value must be one of "add", "remove", "replace", "move", "copy", or "test"; other values are errors. - json.exception.[parse_error](@ref parse_error).106 | "parse error: array index '01' must not begin with '0'" | An array index in a JSON Pointer ([RFC 6901](https://tools.ietf.org/html/rfc6901)) may be `0` or any number wihtout a leading `0`. - json.exception.[parse_error](@ref parse_error).107 | "parse error: JSON pointer must be empty or begin with '/' - was: 'foo'" | A JSON Pointer must be a Unicode string containing a sequence of zero or more reference tokens, each prefixed by a `/` character. - json.exception.[parse_error](@ref parse_error).108 | "parse error: escape character '~' must be followed with '0' or '1'" | In a JSON Pointer, only `~0` and `~1` are valid escape sequences. - json.exception.[parse_error](@ref parse_error).109 | "parse error: array index 'one' is not a number" | A JSON Pointer array index must be a number. - json.exception.[invalid_iterator](@ref invalid_iterator).201 | "iterators are not compatible" | The iterators passed to constructor @ref basic_json(InputIT first, InputIT last) are not compatible, meaning they do not belong to the same container. Therefore, the range (@a first, @a last) is invalid. - json.exception.[invalid_iterator](@ref invalid_iterator).202 | "iterator does not fit current value" | In an erase or insert function, the passed iterator @a pos does not belong to the JSON value for which the function was called. It hence does not define a valid position for the deletion/insertion. - json.exception.[invalid_iterator](@ref invalid_iterator).203 | "iterators do not fit current value" | Either iterator passed to function @ref erase(IteratorType first, IteratorType last) does not belong to the JSON value from which values shall be erased. It hence does not define a valid range to delete values from. - json.exception.[invalid_iterator](@ref invalid_iterator).204 | "iterators out of range" | When an iterator range for a primitive type (number, boolean, or string) is passed to a constructor or an erase function, this range has to be exactly (@ref begin(), @ref end()), because this is the only way the single stored value is expressed. All other ranges are invalid. - json.exception.[invalid_iterator](@ref invalid_iterator).205 | "iterator out of range" | When an iterator for a primitive type (number, boolean, or string) is passed to an erase function, the iterator has to be the @ref begin() iterator, because it is the only way to address the stored value. All other iterators are invalid. - json.exception.[invalid_iterator](@ref invalid_iterator).206 | "cannot construct with iterators from null" | The iterators passed to constructor @ref basic_json(InputIT first, InputIT last) belong to a JSON null value and hence to not define a valid range. - json.exception.[invalid_iterator](@ref invalid_iterator).207 | "cannot use key() for non-object iterators" | The key() member function can only be used on iterators belonging to a JSON object, because other types do not have a concept of a key. - json.exception.[invalid_iterator](@ref invalid_iterator).208 | "cannot use operator[] for object iterators" | The operator[] to specify a concrete offset cannot be used on iterators belonging to a JSON object, because JSON objects are unordered. - json.exception.[invalid_iterator](@ref invalid_iterator).209 | "cannot use offsets with object iterators" | The offset operators (+, -, +=, -=) cannot be used on iterators belonging to a JSON object, because JSON objects are unordered. - json.exception.[invalid_iterator](@ref invalid_iterator).210 | "iterators do not fit" | The iterator range passed to the insert function are not compatible, meaning they do not belong to the same container. Therefore, the range (@a first, @a last) is invalid. - json.exception.[invalid_iterator](@ref invalid_iterator).211 | "passed iterators may not belong to container" | The iterator range passed to the insert function must not be a subrange of the container to insert to. - json.exception.[invalid_iterator](@ref invalid_iterator).212 | "cannot compare iterators of different containers" | When two iterators are compared, they must belong to the same container. - json.exception.[invalid_iterator](@ref invalid_iterator).213 | "cannot compare order of object iterators" | The order of object iterators cannot be compated, because JSON objects are unordered. - json.exception.[invalid_iterator](@ref invalid_iterator).214 | "cannot get value" | Cannot get value for iterator: Either the iterator belongs to a null value or it is an iterator to a primitive type (number, boolean, or string), but the iterator is different to @ref begin(). - json.exception.[type_error](@ref type_error).301 | "cannot create object from initializer list" | To create an object from an initializer list, the initializer list must consist only of a list of pairs whose first element is a string. When this constraint is violated, an array is created instead. - json.exception.[type_error](@ref type_error).302 | "type must be object, but is array" | During implicit or explicit value conversion, the JSON type must be compatible to the target type. For instance, a JSON string can only be converted into string types, but not into numbers or boolean types. - json.exception.[type_error](@ref type_error).303 | "incompatible ReferenceType for get_ref, actual type is object" | To retrieve a reference to a value stored in a @ref basic_json object with @ref get_ref, the type of the reference must match the value type. For instance, for a JSON array, the @a ReferenceType must be @ref array_t&. - json.exception.[type_error](@ref type_error).304 | "cannot use at() with string" | The @ref at() member functions can only be executed for certain JSON types. - json.exception.[type_error](@ref type_error).305 | "cannot use operator[] with string" | The @ref operator[] member functions can only be executed for certain JSON types. - json.exception.[type_error](@ref type_error).306 | "cannot use value() with string" | The @ref value() member functions can only be executed for certain JSON types. - json.exception.[type_error](@ref type_error).307 | "cannot use erase() with string" | The @ref erase() member functions can only be executed for certain JSON types. - json.exception.[type_error](@ref type_error).308 | "cannot use push_back() with string" | The @ref push_back() and @ref operator+= member functions can only be executed for certain JSON types. - json.exception.[type_error](@ref type_error).309 | "cannot use insert() with" | The @ref insert() member functions can only be executed for certain JSON types. - json.exception.[type_error](@ref type_error).310 | "cannot use swap() with number" | The @ref swap() member functions can only be executed for certain JSON types. - json.exception.[type_error](@ref type_error).311 | "cannot use emplace_back() with string" | The @ref emplace_back() member function can only be executed for certain JSON types. - json.exception.[type_error](@ref type_error).313 | "invalid value to unflatten" | The @ref unflatten function converts an object whose keys are JSON Pointers back into an arbitrary nested JSON value. The JSON Pointers must not overlap, because then the resulting value would not be well defined. - json.exception.[type_error](@ref type_error).314 | "only objects can be unflattened" | The @ref unflatten function only works for an object whose keys are JSON Pointers. - json.exception.[type_error](@ref type_error).315 | "values in object must be primitive" | The @ref unflatten function only works for an object whose keys are JSON Pointers and whose values are primitive. - json.exception.[out_of_range](@ref out_of_range).401 | "array index 3 is out of range" | The provided array index @a i is larger than @a size-1. - json.exception.[out_of_range](@ref out_of_range).402 | "array index '-' (3) is out of range" | The special array index `-` in a JSON Pointer never describes a valid element of the array, but the index past the end. - json.exception.[out_of_range](@ref out_of_range).403 | "key 'foo' not found" | The provided key was not found in the JSON object. - json.exception.[out_of_range](@ref out_of_range).404 | "unresolved reference token 'foo'" | A reference token in a JSON Pointer could not be resolved. - json.exception.[out_of_range](@ref out_of_range).405 | "JSON pointer has no parent" | The JSON Patch operations 'remove' and 'add' can not be applied to the root element of the JSON value. - json.exception.other.500 | "unsuccessful" | A JSON Patch operation 'test' failed. - - @since version 3.0.0 - */ - class exception : public std::exception - { - public: - /// create exception with id an explanatory string - exception(int id_, const std::string& ename, const std::string& what_arg_) - : id(id_), - what_arg("[json.exception." + ename + "." + std::to_string(id_) + "] " + what_arg_) - {} - - /// returns the explanatory string - virtual const char* what() const noexcept - { - return what_arg.c_str(); - } - - /// the id of the exception - const int id; - - private: - /// the explanatory string - const std::string what_arg; - }; - - /*! - @brief exception indicating a parse error - - This excpetion is thrown by the library when a parse error occurs. Parse - errors can occur during the deserialization of JSON text as well as when - using JSON Patch. - - Exceptions have ids 1xx. - - @since version 3.0.0 - */ - class parse_error : public exception - { - public: - /*! - @brief create a parse error exception - @param[in] id_ the id of the exception - @param[in] byte_ the byte index where the error occured (or 0 if - the position cannot be determined) - @param[in] what_arg_ the explanatory string - */ - parse_error(int id_, size_t byte_, const std::string& what_arg_) - : exception(id_, "parse_error", "parse error" + - (byte_ != 0 ? (" at " + std::to_string(byte_)) : "") + - ": " + what_arg_), - byte(byte_) - {} - - /*! - @brief byte index of the parse error - - The byte index of the last read character in the input file. - - @note For an input with n bytes, 1 is the index of the first character - and n+1 is the index of the terminating null byte or the end of - file. - */ - const size_t byte; - }; - - /*! - @brief exception indicating errors with iterators - - Exceptions have ids 2xx. - - @since version 3.0.0 - */ - class invalid_iterator : public exception - { - public: - invalid_iterator(int id_, const std::string& what_arg_) - : exception(id_, "invalid_iterator", what_arg_) - {} - }; - - /*! - @brief exception indicating executing a member function with a wrong type - - Exceptions have ids 3xx. - - @since version 3.0.0 - */ - class type_error : public exception - { - public: - type_error(int id_, const std::string& what_arg_) - : exception(id_, "type_error", what_arg_) - {} - }; - - /*! - @brief exception indicating access out of the defined range - - Exceptions have ids 4xx. - - @since version 3.0.0 - */ - class out_of_range : public exception - { - public: - out_of_range(int id_, const std::string& what_arg_) - : exception(id_, "out_of_range", what_arg_) - {} - }; - - /// @} - - /*! @brief returns the allocator associated with the container */ @@ -3161,7 +3195,7 @@ class basic_json return m_value.boolean; } - JSON_THROW(std::domain_error("type must be boolean, but is " + type_name())); + JSON_THROW(type_error(302, "type must be boolean, but is " + type_name())); } /// get a pointer to the value (object) diff --git a/test/src/unit-conversions.cpp b/test/src/unit-conversions.cpp index e4545fbe7..3a83aef3c 100644 --- a/test/src/unit-conversions.cpp +++ b/test/src/unit-conversions.cpp @@ -78,28 +78,28 @@ TEST_CASE("value conversion") SECTION("exception in case of a non-object type") { - CHECK_THROWS_AS(json(json::value_t::null).get(), std::logic_error); - CHECK_THROWS_AS(json(json::value_t::array).get(), std::logic_error); - CHECK_THROWS_AS(json(json::value_t::string).get(), std::logic_error); - CHECK_THROWS_AS(json(json::value_t::boolean).get(), std::logic_error); - CHECK_THROWS_AS(json(json::value_t::number_integer).get(), std::logic_error); - CHECK_THROWS_AS(json(json::value_t::number_unsigned).get(), std::logic_error); - CHECK_THROWS_AS(json(json::value_t::number_float).get(), std::logic_error); + CHECK_THROWS_AS(json(json::value_t::null).get(), json::type_error); + CHECK_THROWS_AS(json(json::value_t::array).get(), json::type_error); + CHECK_THROWS_AS(json(json::value_t::string).get(), json::type_error); + CHECK_THROWS_AS(json(json::value_t::boolean).get(), json::type_error); + CHECK_THROWS_AS(json(json::value_t::number_integer).get(), json::type_error); + CHECK_THROWS_AS(json(json::value_t::number_unsigned).get(), json::type_error); + CHECK_THROWS_AS(json(json::value_t::number_float).get(), json::type_error); CHECK_THROWS_WITH(json(json::value_t::null).get(), - "type must be object, but is null"); + "[json.exception.type_error.302] type must be object, but is null"); CHECK_THROWS_WITH(json(json::value_t::array).get(), - "type must be object, but is array"); + "[json.exception.type_error.302] type must be object, but is array"); CHECK_THROWS_WITH(json(json::value_t::string).get(), - "type must be object, but is string"); + "[json.exception.type_error.302] type must be object, but is string"); CHECK_THROWS_WITH(json(json::value_t::boolean).get(), - "type must be object, but is boolean"); + "[json.exception.type_error.302] type must be object, but is boolean"); CHECK_THROWS_WITH(json(json::value_t::number_integer).get(), - "type must be object, but is number"); + "[json.exception.type_error.302] type must be object, but is number"); CHECK_THROWS_WITH(json(json::value_t::number_unsigned).get(), - "type must be object, but is number"); + "[json.exception.type_error.302] type must be object, but is number"); CHECK_THROWS_WITH(json(json::value_t::number_float).get(), - "type must be object, but is number"); + "[json.exception.type_error.302] type must be object, but is number"); } } @@ -161,9 +161,9 @@ TEST_CASE("value conversion") std::forward_list a = j.get>(); CHECK(json(a) == j); - CHECK_THROWS_AS(json(json::value_t::null).get>(), std::logic_error); + CHECK_THROWS_AS(json(json::value_t::null).get>(), json::type_error); CHECK_THROWS_WITH(json(json::value_t::null).get>(), - "type must be array, but is null"); + "[json.exception.type_error.302] type must be array, but is null"); } SECTION("std::vector") @@ -171,16 +171,16 @@ TEST_CASE("value conversion") std::vector a = j.get>(); CHECK(json(a) == j); - CHECK_THROWS_AS(json(json::value_t::null).get>(), std::logic_error); + CHECK_THROWS_AS(json(json::value_t::null).get>(), json::type_error); CHECK_THROWS_WITH(json(json::value_t::null).get>(), - "type must be array, but is null"); + "[json.exception.type_error.302] type must be array, but is null"); #if not defined(JSON_NOEXCEPTION) SECTION("reserve is called on containers that supports it") { // making the call to from_json throw in order to check capacity std::vector v; - CHECK_THROWS_AS(nlohmann::from_json(j, v), std::logic_error); + CHECK_THROWS_AS(nlohmann::from_json(j, v), json::type_error); CHECK(v.capacity() == j.size()); // make sure all values are properly copied @@ -198,30 +198,30 @@ TEST_CASE("value conversion") SECTION("exception in case of a non-array type") { - CHECK_THROWS_AS(json(json::value_t::null).get(), std::logic_error); - CHECK_THROWS_AS(json(json::value_t::object).get(), std::logic_error); - CHECK_THROWS_AS(json(json::value_t::string).get(), std::logic_error); - CHECK_THROWS_AS(json(json::value_t::boolean).get(), std::logic_error); - CHECK_THROWS_AS(json(json::value_t::number_integer).get(), std::logic_error); - CHECK_THROWS_AS(json(json::value_t::number_unsigned).get(), std::logic_error); - CHECK_THROWS_AS(json(json::value_t::number_float).get(), std::logic_error); + CHECK_THROWS_AS(json(json::value_t::null).get(), json::type_error); + CHECK_THROWS_AS(json(json::value_t::object).get(), json::type_error); + CHECK_THROWS_AS(json(json::value_t::string).get(), json::type_error); + CHECK_THROWS_AS(json(json::value_t::boolean).get(), json::type_error); + CHECK_THROWS_AS(json(json::value_t::number_integer).get(), json::type_error); + CHECK_THROWS_AS(json(json::value_t::number_unsigned).get(), json::type_error); + CHECK_THROWS_AS(json(json::value_t::number_float).get(), json::type_error); CHECK_THROWS_WITH(json(json::value_t::object).get>(), - "type must be array, but is object"); + "[json.exception.type_error.302] type must be array, but is object"); CHECK_THROWS_WITH(json(json::value_t::null).get(), - "type must be array, but is null"); + "[json.exception.type_error.302] type must be array, but is null"); CHECK_THROWS_WITH(json(json::value_t::object).get(), - "type must be array, but is object"); + "[json.exception.type_error.302] type must be array, but is object"); CHECK_THROWS_WITH(json(json::value_t::string).get(), - "type must be array, but is string"); + "[json.exception.type_error.302] type must be array, but is string"); CHECK_THROWS_WITH(json(json::value_t::boolean).get(), - "type must be array, but is boolean"); + "[json.exception.type_error.302] type must be array, but is boolean"); CHECK_THROWS_WITH(json(json::value_t::number_integer).get(), - "type must be array, but is number"); + "[json.exception.type_error.302] type must be array, but is number"); CHECK_THROWS_WITH(json(json::value_t::number_unsigned).get(), - "type must be array, but is number"); + "[json.exception.type_error.302] type must be array, but is number"); CHECK_THROWS_WITH(json(json::value_t::number_float).get(), - "type must be array, but is number"); + "[json.exception.type_error.302] type must be array, but is number"); } } @@ -280,28 +280,28 @@ TEST_CASE("value conversion") SECTION("exception in case of a non-string type") { - CHECK_THROWS_AS(json(json::value_t::null).get(), std::logic_error); - CHECK_THROWS_AS(json(json::value_t::object).get(), std::logic_error); - CHECK_THROWS_AS(json(json::value_t::array).get(), std::logic_error); - CHECK_THROWS_AS(json(json::value_t::boolean).get(), std::logic_error); - CHECK_THROWS_AS(json(json::value_t::number_integer).get(), std::logic_error); - CHECK_THROWS_AS(json(json::value_t::number_unsigned).get(), std::logic_error); - CHECK_THROWS_AS(json(json::value_t::number_float).get(), std::logic_error); + CHECK_THROWS_AS(json(json::value_t::null).get(), json::type_error); + CHECK_THROWS_AS(json(json::value_t::object).get(), json::type_error); + CHECK_THROWS_AS(json(json::value_t::array).get(), json::type_error); + CHECK_THROWS_AS(json(json::value_t::boolean).get(), json::type_error); + CHECK_THROWS_AS(json(json::value_t::number_integer).get(), json::type_error); + CHECK_THROWS_AS(json(json::value_t::number_unsigned).get(), json::type_error); + CHECK_THROWS_AS(json(json::value_t::number_float).get(), json::type_error); CHECK_THROWS_WITH(json(json::value_t::null).get(), - "type must be string, but is null"); + "[json.exception.type_error.302] type must be string, but is null"); CHECK_THROWS_WITH(json(json::value_t::object).get(), - "type must be string, but is object"); + "[json.exception.type_error.302] type must be string, but is object"); CHECK_THROWS_WITH(json(json::value_t::array).get(), - "type must be string, but is array"); + "[json.exception.type_error.302] type must be string, but is array"); CHECK_THROWS_WITH(json(json::value_t::boolean).get(), - "type must be string, but is boolean"); + "[json.exception.type_error.302] type must be string, but is boolean"); CHECK_THROWS_WITH(json(json::value_t::number_integer).get(), - "type must be string, but is number"); + "[json.exception.type_error.302] type must be string, but is number"); CHECK_THROWS_WITH(json(json::value_t::number_unsigned).get(), - "type must be string, but is number"); + "[json.exception.type_error.302] type must be string, but is number"); CHECK_THROWS_WITH(json(json::value_t::number_float).get(), - "type must be string, but is number"); + "[json.exception.type_error.302] type must be string, but is number"); } } @@ -342,28 +342,28 @@ TEST_CASE("value conversion") SECTION("exception in case of a non-string type") { - CHECK_THROWS_AS(json(json::value_t::null).get(), std::logic_error); - CHECK_THROWS_AS(json(json::value_t::object).get(), std::logic_error); - CHECK_THROWS_AS(json(json::value_t::array).get(), std::logic_error); - CHECK_THROWS_AS(json(json::value_t::string).get(), std::logic_error); - CHECK_THROWS_AS(json(json::value_t::number_integer).get(), std::logic_error); - CHECK_THROWS_AS(json(json::value_t::number_unsigned).get(), std::logic_error); - CHECK_THROWS_AS(json(json::value_t::number_float).get(), std::logic_error); + CHECK_THROWS_AS(json(json::value_t::null).get(), json::type_error); + CHECK_THROWS_AS(json(json::value_t::object).get(), json::type_error); + CHECK_THROWS_AS(json(json::value_t::array).get(), json::type_error); + CHECK_THROWS_AS(json(json::value_t::string).get(), json::type_error); + CHECK_THROWS_AS(json(json::value_t::number_integer).get(), json::type_error); + CHECK_THROWS_AS(json(json::value_t::number_unsigned).get(), json::type_error); + CHECK_THROWS_AS(json(json::value_t::number_float).get(), json::type_error); CHECK_THROWS_WITH(json(json::value_t::null).get(), - "type must be boolean, but is null"); + "[json.exception.type_error.302] type must be boolean, but is null"); CHECK_THROWS_WITH(json(json::value_t::object).get(), - "type must be boolean, but is object"); + "[json.exception.type_error.302] type must be boolean, but is object"); CHECK_THROWS_WITH(json(json::value_t::array).get(), - "type must be boolean, but is array"); + "[json.exception.type_error.302] type must be boolean, but is array"); CHECK_THROWS_WITH(json(json::value_t::string).get(), - "type must be boolean, but is string"); + "[json.exception.type_error.302] type must be boolean, but is string"); CHECK_THROWS_WITH(json(json::value_t::number_integer).get(), - "type must be boolean, but is number"); + "[json.exception.type_error.302] type must be boolean, but is number"); CHECK_THROWS_WITH(json(json::value_t::number_unsigned).get(), - "type must be boolean, but is number"); + "[json.exception.type_error.302] type must be boolean, but is number"); CHECK_THROWS_WITH(json(json::value_t::number_float).get(), - "type must be boolean, but is number"); + "[json.exception.type_error.302] type must be boolean, but is number"); } } @@ -598,22 +598,22 @@ TEST_CASE("value conversion") SECTION("exception in case of a non-number type") { - CHECK_THROWS_AS(json(json::value_t::null).get(), std::logic_error); - CHECK_THROWS_AS(json(json::value_t::object).get(), std::logic_error); - CHECK_THROWS_AS(json(json::value_t::array).get(), std::logic_error); - CHECK_THROWS_AS(json(json::value_t::string).get(), std::logic_error); - CHECK_THROWS_AS(json(json::value_t::boolean).get(), std::logic_error); + CHECK_THROWS_AS(json(json::value_t::null).get(), json::type_error); + CHECK_THROWS_AS(json(json::value_t::object).get(), json::type_error); + CHECK_THROWS_AS(json(json::value_t::array).get(), json::type_error); + CHECK_THROWS_AS(json(json::value_t::string).get(), json::type_error); + CHECK_THROWS_AS(json(json::value_t::boolean).get(), json::type_error); CHECK_THROWS_WITH(json(json::value_t::null).get(), - "type must be number, but is null"); + "[json.exception.type_error.302] type must be number, but is null"); CHECK_THROWS_WITH(json(json::value_t::object).get(), - "type must be number, but is object"); + "[json.exception.type_error.302] type must be number, but is object"); CHECK_THROWS_WITH(json(json::value_t::array).get(), - "type must be number, but is array"); + "[json.exception.type_error.302] type must be number, but is array"); CHECK_THROWS_WITH(json(json::value_t::string).get(), - "type must be number, but is string"); + "[json.exception.type_error.302] type must be number, but is string"); CHECK_THROWS_WITH(json(json::value_t::boolean).get(), - "type must be number, but is boolean"); + "[json.exception.type_error.302] type must be number, but is boolean"); CHECK_NOTHROW(json(json::value_t::number_float).get()); CHECK_NOTHROW(json(json::value_t::number_float).get()); @@ -857,22 +857,22 @@ TEST_CASE("value conversion") SECTION("exception in case of a non-string type") { - CHECK_THROWS_AS(json(json::value_t::null).get(), std::logic_error); - CHECK_THROWS_AS(json(json::value_t::object).get(), std::logic_error); - CHECK_THROWS_AS(json(json::value_t::array).get(), std::logic_error); - CHECK_THROWS_AS(json(json::value_t::string).get(), std::logic_error); - CHECK_THROWS_AS(json(json::value_t::boolean).get(), std::logic_error); + CHECK_THROWS_AS(json(json::value_t::null).get(), json::type_error); + CHECK_THROWS_AS(json(json::value_t::object).get(), json::type_error); + CHECK_THROWS_AS(json(json::value_t::array).get(), json::type_error); + CHECK_THROWS_AS(json(json::value_t::string).get(), json::type_error); + CHECK_THROWS_AS(json(json::value_t::boolean).get(), json::type_error); CHECK_THROWS_WITH(json(json::value_t::null).get(), - "type must be number, but is null"); + "[json.exception.type_error.302] type must be number, but is null"); CHECK_THROWS_WITH(json(json::value_t::object).get(), - "type must be number, but is object"); + "[json.exception.type_error.302] type must be number, but is object"); CHECK_THROWS_WITH(json(json::value_t::array).get(), - "type must be number, but is array"); + "[json.exception.type_error.302] type must be number, but is array"); CHECK_THROWS_WITH(json(json::value_t::string).get(), - "type must be number, but is string"); + "[json.exception.type_error.302] type must be number, but is string"); CHECK_THROWS_WITH(json(json::value_t::boolean).get(), - "type must be number, but is boolean"); + "[json.exception.type_error.302] type must be number, but is boolean"); CHECK_NOTHROW(json(json::value_t::number_integer).get()); CHECK_NOTHROW(json(json::value_t::number_unsigned).get()); @@ -954,8 +954,8 @@ TEST_CASE("value conversion") SECTION("exception in case of a non-object type") { - CHECK_THROWS_AS((json().get>()), std::logic_error); - CHECK_THROWS_WITH((json().get>()), "type must be object, but is null"); + CHECK_THROWS_AS((json().get>()), json::type_error); + CHECK_THROWS_WITH((json().get>()), "[json.exception.type_error.302] type must be object, but is null"); } } @@ -1023,17 +1023,17 @@ TEST_CASE("value conversion") SECTION("exception in case of a non-object type") { - CHECK_THROWS_AS((json().get>()), std::logic_error); - CHECK_THROWS_AS((json().get>()), std::logic_error); - CHECK_THROWS_AS((json().get>()), std::logic_error); - CHECK_THROWS_AS((json().get>()), std::logic_error); + CHECK_THROWS_AS((json().get>()), json::type_error); + CHECK_THROWS_AS((json().get>()), json::type_error); + CHECK_THROWS_AS((json().get>()), json::type_error); + CHECK_THROWS_AS((json().get>()), json::type_error); // does type really must be an array? or it rather must not be null? // that's what I thought when other test like this one broke - CHECK_THROWS_WITH((json().get>()), "type must be array, but is null"); - CHECK_THROWS_WITH((json().get>()), "type must be array, but is null"); - CHECK_THROWS_WITH((json().get>()), "type must be array, but is null"); - CHECK_THROWS_WITH((json().get>()), "type must be array, but is null"); + CHECK_THROWS_WITH((json().get>()), "[json.exception.type_error.302] type must be array, but is null"); + CHECK_THROWS_WITH((json().get>()), "[json.exception.type_error.302] type must be array, but is null"); + CHECK_THROWS_WITH((json().get>()), "[json.exception.type_error.302] type must be array, but is null"); + CHECK_THROWS_WITH((json().get>()), "[json.exception.type_error.302] type must be array, but is null"); } } } From 21ec0e78069154d09c65a9b4c883abf735ba3be8 Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Mon, 6 Mar 2017 21:00:13 +0100 Subject: [PATCH 24/52] :hammer: added user-defined exception 110 --- Makefile | 2 ++ src/json.hpp | 12 ++++++--- src/json.hpp.re2c | 12 ++++++--- test/src/unit-cbor.cpp | 61 +++++++++++++++++++++++++++++++----------- 4 files changed, 64 insertions(+), 23 deletions(-) diff --git a/Makefile b/Makefile index 1b7cf8c17..f52511c60 100644 --- a/Makefile +++ b/Makefile @@ -49,6 +49,7 @@ doctest: # -Wno-documentation-unknown-command: code uses user-defined commands like @complexity # -Wno-exit-time-destructors: warning in Catch code # -Wno-keyword-macro: unit-tests use "#define private public" +# -Wno-weak-vtables: exception class is defined inline, but has virtual method # -Wno-range-loop-analysis: iterator_wrapper tests tests "for(const auto i...)" pedantic: $(MAKE) json_unit CXXFLAGS="\ @@ -58,6 +59,7 @@ pedantic: -Wno-documentation-unknown-command \ -Wno-exit-time-destructors \ -Wno-keyword-macro \ + -Wno-weak-vtables \ -Wno-range-loop-analysis" diff --git a/src/json.hpp b/src/json.hpp index d7108ed60..6a36b85d6 100644 --- a/src/json.hpp +++ b/src/json.hpp @@ -156,7 +156,8 @@ file. @note For an input with n bytes, 1 is the index of the first character and n+1 is the index of the terminating null byte or the end of - file. + file. This also holds true when reading a byte vector (CBOR or + MessagePack). Exceptions have ids 1xx. @@ -171,6 +172,8 @@ json.exception.[parse_error](@ref parse_error).106 | "parse error: array index ' json.exception.[parse_error](@ref parse_error).107 | "parse error: JSON pointer must be empty or begin with '/' - was: 'foo'" | A JSON Pointer must be a Unicode string containing a sequence of zero or more reference tokens, each prefixed by a `/` character. json.exception.[parse_error](@ref parse_error).108 | "parse error: escape character '~' must be followed with '0' or '1'" | In a JSON Pointer, only `~0` and `~1` are valid escape sequences. json.exception.[parse_error](@ref parse_error).109 | "parse error: array index 'one' is not a number" | A JSON Pointer array index must be a number. +json.exception.[parse_error](@ref parse_error).110 | "parse error at 1: cannot read 2 bytes from vector" | When parsing CBOR or MessagePack, the byte vector ends before the complete value has been read. + @since version 3.0.0 */ @@ -198,7 +201,8 @@ class parse_error : public exception @note For an input with n bytes, 1 is the index of the first character and n+1 is the index of the terminating null byte or the end of - file. + file. This also holds true when reading a byte vector (CBOR or + MessagePack). */ const size_t byte; }; @@ -7344,7 +7348,7 @@ class basic_json @tparam T the integral return type - @throw std::out_of_range if there are less than sizeof(T)+1 bytes in the + @throw parse_error.110 if there are less than sizeof(T)+1 bytes in the vector @a vec to read In the for loop, the bytes from the vector are copied in reverse order into @@ -7371,7 +7375,7 @@ class basic_json { if (current_index + sizeof(T) + 1 > vec.size()) { - JSON_THROW(std::out_of_range("cannot read " + std::to_string(sizeof(T)) + " bytes from vector")); + JSON_THROW(parse_error(110, current_index + 1, "cannot read " + std::to_string(sizeof(T)) + " bytes from vector")); } T result; diff --git a/src/json.hpp.re2c b/src/json.hpp.re2c index 4466a5096..4ee6cced6 100644 --- a/src/json.hpp.re2c +++ b/src/json.hpp.re2c @@ -156,7 +156,8 @@ file. @note For an input with n bytes, 1 is the index of the first character and n+1 is the index of the terminating null byte or the end of - file. + file. This also holds true when reading a byte vector (CBOR or + MessagePack). Exceptions have ids 1xx. @@ -171,6 +172,8 @@ json.exception.[parse_error](@ref parse_error).106 | "parse error: array index ' json.exception.[parse_error](@ref parse_error).107 | "parse error: JSON pointer must be empty or begin with '/' - was: 'foo'" | A JSON Pointer must be a Unicode string containing a sequence of zero or more reference tokens, each prefixed by a `/` character. json.exception.[parse_error](@ref parse_error).108 | "parse error: escape character '~' must be followed with '0' or '1'" | In a JSON Pointer, only `~0` and `~1` are valid escape sequences. json.exception.[parse_error](@ref parse_error).109 | "parse error: array index 'one' is not a number" | A JSON Pointer array index must be a number. +json.exception.[parse_error](@ref parse_error).110 | "parse error at 1: cannot read 2 bytes from vector" | When parsing CBOR or MessagePack, the byte vector ends before the complete value has been read. + @since version 3.0.0 */ @@ -198,7 +201,8 @@ class parse_error : public exception @note For an input with n bytes, 1 is the index of the first character and n+1 is the index of the terminating null byte or the end of - file. + file. This also holds true when reading a byte vector (CBOR or + MessagePack). */ const size_t byte; }; @@ -7344,7 +7348,7 @@ class basic_json @tparam T the integral return type - @throw std::out_of_range if there are less than sizeof(T)+1 bytes in the + @throw parse_error.110 if there are less than sizeof(T)+1 bytes in the vector @a vec to read In the for loop, the bytes from the vector are copied in reverse order into @@ -7371,7 +7375,7 @@ class basic_json { if (current_index + sizeof(T) + 1 > vec.size()) { - JSON_THROW(std::out_of_range("cannot read " + std::to_string(sizeof(T)) + " bytes from vector")); + JSON_THROW(parse_error(110, current_index + 1, "cannot read " + std::to_string(sizeof(T)) + " bytes from vector")); } T result; diff --git a/test/src/unit-cbor.cpp b/test/src/unit-cbor.cpp index 84b280bc9..9525c7220 100644 --- a/test/src/unit-cbor.cpp +++ b/test/src/unit-cbor.cpp @@ -1145,21 +1145,52 @@ TEST_CASE("CBOR") { SECTION("too short byte vector") { - CHECK_THROWS_AS(json::from_cbor(std::vector({0x18})), std::out_of_range); - CHECK_THROWS_AS(json::from_cbor(std::vector({0x19})), std::out_of_range); - CHECK_THROWS_AS(json::from_cbor(std::vector({0x19, 0x00})), std::out_of_range); - CHECK_THROWS_AS(json::from_cbor(std::vector({0x1a})), std::out_of_range); - CHECK_THROWS_AS(json::from_cbor(std::vector({0x1a, 0x00})), std::out_of_range); - CHECK_THROWS_AS(json::from_cbor(std::vector({0x1a, 0x00, 0x00})), std::out_of_range); - CHECK_THROWS_AS(json::from_cbor(std::vector({0x1a, 0x00, 0x00, 0x00})), std::out_of_range); - CHECK_THROWS_AS(json::from_cbor(std::vector({0x1b})), std::out_of_range); - CHECK_THROWS_AS(json::from_cbor(std::vector({0x1b, 0x00})), std::out_of_range); - CHECK_THROWS_AS(json::from_cbor(std::vector({0x1b, 0x00, 0x00})), std::out_of_range); - CHECK_THROWS_AS(json::from_cbor(std::vector({0x1b, 0x00, 0x00, 0x00})), std::out_of_range); - CHECK_THROWS_AS(json::from_cbor(std::vector({0x1b, 0x00, 0x00, 0x00, 0x00})), std::out_of_range); - CHECK_THROWS_AS(json::from_cbor(std::vector({0x1b, 0x00, 0x00, 0x00, 0x00, 0x00})), std::out_of_range); - CHECK_THROWS_AS(json::from_cbor(std::vector({0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00})), std::out_of_range); - CHECK_THROWS_AS(json::from_cbor(std::vector({0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00})), std::out_of_range); + CHECK_THROWS_AS(json::from_cbor(std::vector({0x18})), json::parse_error); + CHECK_THROWS_AS(json::from_cbor(std::vector({0x19})), json::parse_error); + CHECK_THROWS_AS(json::from_cbor(std::vector({0x19, 0x00})), json::parse_error); + CHECK_THROWS_AS(json::from_cbor(std::vector({0x1a})), json::parse_error); + CHECK_THROWS_AS(json::from_cbor(std::vector({0x1a, 0x00})), json::parse_error); + CHECK_THROWS_AS(json::from_cbor(std::vector({0x1a, 0x00, 0x00})), json::parse_error); + CHECK_THROWS_AS(json::from_cbor(std::vector({0x1a, 0x00, 0x00, 0x00})), json::parse_error); + CHECK_THROWS_AS(json::from_cbor(std::vector({0x1b})), json::parse_error); + CHECK_THROWS_AS(json::from_cbor(std::vector({0x1b, 0x00})), json::parse_error); + CHECK_THROWS_AS(json::from_cbor(std::vector({0x1b, 0x00, 0x00})), json::parse_error); + CHECK_THROWS_AS(json::from_cbor(std::vector({0x1b, 0x00, 0x00, 0x00})), json::parse_error); + CHECK_THROWS_AS(json::from_cbor(std::vector({0x1b, 0x00, 0x00, 0x00, 0x00})), json::parse_error); + CHECK_THROWS_AS(json::from_cbor(std::vector({0x1b, 0x00, 0x00, 0x00, 0x00, 0x00})), json::parse_error); + CHECK_THROWS_AS(json::from_cbor(std::vector({0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00})), json::parse_error); + CHECK_THROWS_AS(json::from_cbor(std::vector({0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00})), json::parse_error); + + CHECK_THROWS_WITH(json::from_cbor(std::vector({0x18})), + "[json.exception.parse_error.110] parse error at 1: cannot read 1 bytes from vector"); + CHECK_THROWS_WITH(json::from_cbor(std::vector({0x19})), + "[json.exception.parse_error.110] parse error at 1: cannot read 2 bytes from vector"); + CHECK_THROWS_WITH(json::from_cbor(std::vector({0x19, 0x00})), + "[json.exception.parse_error.110] parse error at 1: cannot read 2 bytes from vector"); + CHECK_THROWS_WITH(json::from_cbor(std::vector({0x1a})), + "[json.exception.parse_error.110] parse error at 1: cannot read 4 bytes from vector"); + CHECK_THROWS_WITH(json::from_cbor(std::vector({0x1a, 0x00})), + "[json.exception.parse_error.110] parse error at 1: cannot read 4 bytes from vector"); + CHECK_THROWS_WITH(json::from_cbor(std::vector({0x1a, 0x00, 0x00})), + "[json.exception.parse_error.110] parse error at 1: cannot read 4 bytes from vector"); + CHECK_THROWS_WITH(json::from_cbor(std::vector({0x1a, 0x00, 0x00, 0x00})), + "[json.exception.parse_error.110] parse error at 1: cannot read 4 bytes from vector"); + CHECK_THROWS_WITH(json::from_cbor(std::vector({0x1b})), + "[json.exception.parse_error.110] parse error at 1: cannot read 8 bytes from vector"); + CHECK_THROWS_WITH(json::from_cbor(std::vector({0x1b, 0x00})), + "[json.exception.parse_error.110] parse error at 1: cannot read 8 bytes from vector"); + CHECK_THROWS_WITH(json::from_cbor(std::vector({0x1b, 0x00, 0x00})), + "[json.exception.parse_error.110] parse error at 1: cannot read 8 bytes from vector"); + CHECK_THROWS_WITH(json::from_cbor(std::vector({0x1b, 0x00, 0x00, 0x00})), + "[json.exception.parse_error.110] parse error at 1: cannot read 8 bytes from vector"); + CHECK_THROWS_WITH(json::from_cbor(std::vector({0x1b, 0x00, 0x00, 0x00, 0x00})), + "[json.exception.parse_error.110] parse error at 1: cannot read 8 bytes from vector"); + CHECK_THROWS_WITH(json::from_cbor(std::vector({0x1b, 0x00, 0x00, 0x00, 0x00, 0x00})), + "[json.exception.parse_error.110] parse error at 1: cannot read 8 bytes from vector"); + CHECK_THROWS_WITH(json::from_cbor(std::vector({0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00})), + "[json.exception.parse_error.110] parse error at 1: cannot read 8 bytes from vector"); + CHECK_THROWS_WITH(json::from_cbor(std::vector({0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00})), + "[json.exception.parse_error.110] parse error at 1: cannot read 8 bytes from vector"); } } } From 54073332248e90de6b08ff7c5a3f1288205fc8f4 Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Mon, 6 Mar 2017 22:37:46 +0100 Subject: [PATCH 25/52] :hammer: added user-defined exception 111 --- src/json.hpp | 4 ++-- src/json.hpp.re2c | 4 ++-- test/src/unit-regression.cpp | 3 ++- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/json.hpp b/src/json.hpp index 6a36b85d6..5fc66dc56 100644 --- a/src/json.hpp +++ b/src/json.hpp @@ -173,7 +173,7 @@ json.exception.[parse_error](@ref parse_error).107 | "parse error: JSON pointer json.exception.[parse_error](@ref parse_error).108 | "parse error: escape character '~' must be followed with '0' or '1'" | In a JSON Pointer, only `~0` and `~1` are valid escape sequences. json.exception.[parse_error](@ref parse_error).109 | "parse error: array index 'one' is not a number" | A JSON Pointer array index must be a number. json.exception.[parse_error](@ref parse_error).110 | "parse error at 1: cannot read 2 bytes from vector" | When parsing CBOR or MessagePack, the byte vector ends before the complete value has been read. - +json.exception.[parse_error](@ref parse_error).111 | "parse error: bad input stream" | Parsing CBOR or MessagePack from an input stream where the `badbit` or `failbit` is set. @since version 3.0.0 */ @@ -9889,7 +9889,7 @@ class basic_json // immediately abort if stream is erroneous if (s.fail()) { - JSON_THROW(std::invalid_argument("stream error")); + JSON_THROW(parse_error(111, 0, "bad input stream")); } // fill buffer diff --git a/src/json.hpp.re2c b/src/json.hpp.re2c index 4ee6cced6..d022375b8 100644 --- a/src/json.hpp.re2c +++ b/src/json.hpp.re2c @@ -173,7 +173,7 @@ json.exception.[parse_error](@ref parse_error).107 | "parse error: JSON pointer json.exception.[parse_error](@ref parse_error).108 | "parse error: escape character '~' must be followed with '0' or '1'" | In a JSON Pointer, only `~0` and `~1` are valid escape sequences. json.exception.[parse_error](@ref parse_error).109 | "parse error: array index 'one' is not a number" | A JSON Pointer array index must be a number. json.exception.[parse_error](@ref parse_error).110 | "parse error at 1: cannot read 2 bytes from vector" | When parsing CBOR or MessagePack, the byte vector ends before the complete value has been read. - +json.exception.[parse_error](@ref parse_error).111 | "parse error: bad input stream" | Parsing CBOR or MessagePack from an input stream where the `badbit` or `failbit` is set. @since version 3.0.0 */ @@ -9889,7 +9889,7 @@ class basic_json // immediately abort if stream is erroneous if (s.fail()) { - JSON_THROW(std::invalid_argument("stream error")); + JSON_THROW(parse_error(111, 0, "bad input stream")); } // fill buffer diff --git a/test/src/unit-regression.cpp b/test/src/unit-regression.cpp index 9dea8083b..2d7990676 100644 --- a/test/src/unit-regression.cpp +++ b/test/src/unit-regression.cpp @@ -565,7 +565,8 @@ TEST_CASE("regression tests") SECTION("issue #366 - json::parse on failed stream gets stuck") { std::ifstream f("file_not_found.json"); - CHECK_THROWS_AS(json::parse(f), std::invalid_argument); + CHECK_THROWS_AS(json::parse(f), json::parse_error); + CHECK_THROWS_WITH(json::parse(f), "[json.exception.parse_error.111] parse error: bad input stream"); } SECTION("issue #367 - calling stream at EOF") From 757d2c6c7aa4af0d2df46f3f5bb8562592892226 Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Mon, 6 Mar 2017 23:45:08 +0100 Subject: [PATCH 26/52] :hammer: replaced at() calls in msgpack/cbor --- src/json.hpp | 32 ++++++++++++++++++++------------ src/json.hpp.re2c | 32 ++++++++++++++++++++------------ 2 files changed, 40 insertions(+), 24 deletions(-) diff --git a/src/json.hpp b/src/json.hpp index 5fc66dc56..9a2c2c018 100644 --- a/src/json.hpp +++ b/src/json.hpp @@ -7957,12 +7957,12 @@ class basic_json */ static basic_json from_msgpack_internal(const std::vector& v, size_t& idx) { - // make sure reading 1 byte is safe - check_length(v.size(), 1, idx); - // store and increment index const size_t current_idx = idx++; + // make sure reading 1 byte is safe + check_length(v.size(), 1, current_idx); + if (v[current_idx] <= 0xbf) { if (v[current_idx] <= 0x7f) // positive fixint @@ -8026,9 +8026,10 @@ class basic_json { // copy bytes in reverse order into the double variable float res; + check_length(v.size(), sizeof(float), current_idx + 1); for (size_t byte = 0; byte < sizeof(float); ++byte) { - reinterpret_cast(&res)[sizeof(float) - byte - 1] = v.at(current_idx + 1 + byte); + reinterpret_cast(&res)[sizeof(float) - byte - 1] = v[current_idx + 1 + byte]; } idx += sizeof(float); // skip content bytes return res; @@ -8038,9 +8039,10 @@ class basic_json { // copy bytes in reverse order into the double variable double res; + check_length(v.size(), sizeof(double), current_idx + 1); for (size_t byte = 0; byte < sizeof(double); ++byte) { - reinterpret_cast(&res)[sizeof(double) - byte - 1] = v.at(current_idx + 1 + byte); + reinterpret_cast(&res)[sizeof(double) - byte - 1] = v[current_idx + 1 + byte]; } idx += sizeof(double); // skip content bytes return res; @@ -8198,7 +8200,10 @@ class basic_json // store and increment index const size_t current_idx = idx++; - switch (v.at(current_idx)) + // make sure reading 1 byte is safe + check_length(v.size(), 1, current_idx); + + switch (v[current_idx]) { // Integer 0x00..0x17 (0..23) case 0x00: @@ -8379,7 +8384,7 @@ class basic_json case 0x7f: // UTF-8 string (indefinite length) { std::string result; - while (v.at(idx) != 0xff) + while (check_length(v.size(), 1, idx), v[idx] != 0xff) { string_t s = from_cbor_internal(v, idx); result += s; @@ -8475,7 +8480,7 @@ class basic_json case 0x9f: // array (indefinite length) { basic_json result = value_t::array; - while (v.at(idx) != 0xff) + while (check_length(v.size(), 1, idx), v[idx] != 0xff) { result.push_back(from_cbor_internal(v, idx)); } @@ -8575,7 +8580,7 @@ class basic_json case 0xbf: // map (indefinite length) { basic_json result = value_t::object; - while (v.at(idx) != 0xff) + while (check_length(v.size(), 1, idx), v[idx] != 0xff) { std::string key = from_cbor_internal(v, idx); result[key] = from_cbor_internal(v, idx); @@ -8611,7 +8616,8 @@ class basic_json // include at least decoding support for them even without such // support. An example of a small decoder for half-precision // floating-point numbers in the C language is shown in Fig. 3. - const int half = (v.at(current_idx + 1) << 8) + v.at(current_idx + 2); + check_length(v.size(), 2, current_idx + 1); + const int half = (v[current_idx + 1] << 8) + v[current_idx + 2]; const int exp = (half >> 10) & 0x1f; const int mant = half & 0x3ff; double val; @@ -8636,9 +8642,10 @@ class basic_json { // copy bytes in reverse order into the float variable float res; + check_length(v.size(), sizeof(float), current_idx + 1); for (size_t byte = 0; byte < sizeof(float); ++byte) { - reinterpret_cast(&res)[sizeof(float) - byte - 1] = v.at(current_idx + 1 + byte); + reinterpret_cast(&res)[sizeof(float) - byte - 1] = v[current_idx + 1 + byte]; } idx += sizeof(float); // skip content bytes return res; @@ -8648,9 +8655,10 @@ class basic_json { // copy bytes in reverse order into the double variable double res; + check_length(v.size(), sizeof(double), current_idx + 1); for (size_t byte = 0; byte < sizeof(double); ++byte) { - reinterpret_cast(&res)[sizeof(double) - byte - 1] = v.at(current_idx + 1 + byte); + reinterpret_cast(&res)[sizeof(double) - byte - 1] = v[current_idx + 1 + byte]; } idx += sizeof(double); // skip content bytes return res; diff --git a/src/json.hpp.re2c b/src/json.hpp.re2c index d022375b8..8d8f11b80 100644 --- a/src/json.hpp.re2c +++ b/src/json.hpp.re2c @@ -7957,12 +7957,12 @@ class basic_json */ static basic_json from_msgpack_internal(const std::vector& v, size_t& idx) { - // make sure reading 1 byte is safe - check_length(v.size(), 1, idx); - // store and increment index const size_t current_idx = idx++; + // make sure reading 1 byte is safe + check_length(v.size(), 1, current_idx); + if (v[current_idx] <= 0xbf) { if (v[current_idx] <= 0x7f) // positive fixint @@ -8026,9 +8026,10 @@ class basic_json { // copy bytes in reverse order into the double variable float res; + check_length(v.size(), sizeof(float), current_idx + 1); for (size_t byte = 0; byte < sizeof(float); ++byte) { - reinterpret_cast(&res)[sizeof(float) - byte - 1] = v.at(current_idx + 1 + byte); + reinterpret_cast(&res)[sizeof(float) - byte - 1] = v[current_idx + 1 + byte]; } idx += sizeof(float); // skip content bytes return res; @@ -8038,9 +8039,10 @@ class basic_json { // copy bytes in reverse order into the double variable double res; + check_length(v.size(), sizeof(double), current_idx + 1); for (size_t byte = 0; byte < sizeof(double); ++byte) { - reinterpret_cast(&res)[sizeof(double) - byte - 1] = v.at(current_idx + 1 + byte); + reinterpret_cast(&res)[sizeof(double) - byte - 1] = v[current_idx + 1 + byte]; } idx += sizeof(double); // skip content bytes return res; @@ -8198,7 +8200,10 @@ class basic_json // store and increment index const size_t current_idx = idx++; - switch (v.at(current_idx)) + // make sure reading 1 byte is safe + check_length(v.size(), 1, current_idx); + + switch (v[current_idx]) { // Integer 0x00..0x17 (0..23) case 0x00: @@ -8379,7 +8384,7 @@ class basic_json case 0x7f: // UTF-8 string (indefinite length) { std::string result; - while (v.at(idx) != 0xff) + while (check_length(v.size(), 1, idx), v[idx] != 0xff) { string_t s = from_cbor_internal(v, idx); result += s; @@ -8475,7 +8480,7 @@ class basic_json case 0x9f: // array (indefinite length) { basic_json result = value_t::array; - while (v.at(idx) != 0xff) + while (check_length(v.size(), 1, idx), v[idx] != 0xff) { result.push_back(from_cbor_internal(v, idx)); } @@ -8575,7 +8580,7 @@ class basic_json case 0xbf: // map (indefinite length) { basic_json result = value_t::object; - while (v.at(idx) != 0xff) + while (check_length(v.size(), 1, idx), v[idx] != 0xff) { std::string key = from_cbor_internal(v, idx); result[key] = from_cbor_internal(v, idx); @@ -8611,7 +8616,8 @@ class basic_json // include at least decoding support for them even without such // support. An example of a small decoder for half-precision // floating-point numbers in the C language is shown in Fig. 3. - const int half = (v.at(current_idx + 1) << 8) + v.at(current_idx + 2); + check_length(v.size(), 2, current_idx + 1); + const int half = (v[current_idx + 1] << 8) + v[current_idx + 2]; const int exp = (half >> 10) & 0x1f; const int mant = half & 0x3ff; double val; @@ -8636,9 +8642,10 @@ class basic_json { // copy bytes in reverse order into the float variable float res; + check_length(v.size(), sizeof(float), current_idx + 1); for (size_t byte = 0; byte < sizeof(float); ++byte) { - reinterpret_cast(&res)[sizeof(float) - byte - 1] = v.at(current_idx + 1 + byte); + reinterpret_cast(&res)[sizeof(float) - byte - 1] = v[current_idx + 1 + byte]; } idx += sizeof(float); // skip content bytes return res; @@ -8648,9 +8655,10 @@ class basic_json { // copy bytes in reverse order into the double variable double res; + check_length(v.size(), sizeof(double), current_idx + 1); for (size_t byte = 0; byte < sizeof(double); ++byte) { - reinterpret_cast(&res)[sizeof(double) - byte - 1] = v.at(current_idx + 1 + byte); + reinterpret_cast(&res)[sizeof(double) - byte - 1] = v[current_idx + 1 + byte]; } idx += sizeof(double); // skip content bytes return res; From 625cf7e3f7b227c48b235e6b34c1198a35c0614f Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Tue, 7 Mar 2017 20:05:34 +0100 Subject: [PATCH 27/52] :hammer: added user-defined exception 112 --- src/json.hpp | 9 ++++- src/json.hpp.re2c | 9 ++++- test/src/unit-cbor.cpp | 63 +++++++++++++++++++++++++++++ test/src/unit-msgpack.cpp | 84 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 161 insertions(+), 4 deletions(-) diff --git a/src/json.hpp b/src/json.hpp index 9a2c2c018..68bb3cd70 100644 --- a/src/json.hpp +++ b/src/json.hpp @@ -174,6 +174,7 @@ json.exception.[parse_error](@ref parse_error).108 | "parse error: escape charac json.exception.[parse_error](@ref parse_error).109 | "parse error: array index 'one' is not a number" | A JSON Pointer array index must be a number. json.exception.[parse_error](@ref parse_error).110 | "parse error at 1: cannot read 2 bytes from vector" | When parsing CBOR or MessagePack, the byte vector ends before the complete value has been read. json.exception.[parse_error](@ref parse_error).111 | "parse error: bad input stream" | Parsing CBOR or MessagePack from an input stream where the `badbit` or `failbit` is set. +json.exception.[parse_error](@ref parse_error).112 | "parse error at 1: error reading CBOR; last byte: 0xf8" | Not all types of CBOR or MessagePack are supported. This exception occurs if an unsupported byte was read. @since version 3.0.0 */ @@ -8175,7 +8176,9 @@ class basic_json default: { - JSON_THROW(std::invalid_argument("error parsing a msgpack @ " + std::to_string(current_idx) + ": " + std::to_string(static_cast(v[current_idx])))); + std::stringstream ss; + ss << std::hex << static_cast(v[current_idx]); + JSON_THROW(parse_error(112, current_idx + 1, "error reading MessagePack; last byte: 0x" + ss.str())); } } } @@ -8666,7 +8669,9 @@ class basic_json default: // anything else (0xFF is handled inside the other types) { - JSON_THROW(std::invalid_argument("error parsing a CBOR @ " + std::to_string(current_idx) + ": " + std::to_string(static_cast(v[current_idx])))); + std::stringstream ss; + ss << std::hex << static_cast(v[current_idx]); + JSON_THROW(parse_error(112, current_idx + 1, "error reading CBOR; last byte: 0x" + ss.str())); } } } diff --git a/src/json.hpp.re2c b/src/json.hpp.re2c index 8d8f11b80..60a1042cf 100644 --- a/src/json.hpp.re2c +++ b/src/json.hpp.re2c @@ -174,6 +174,7 @@ json.exception.[parse_error](@ref parse_error).108 | "parse error: escape charac json.exception.[parse_error](@ref parse_error).109 | "parse error: array index 'one' is not a number" | A JSON Pointer array index must be a number. json.exception.[parse_error](@ref parse_error).110 | "parse error at 1: cannot read 2 bytes from vector" | When parsing CBOR or MessagePack, the byte vector ends before the complete value has been read. json.exception.[parse_error](@ref parse_error).111 | "parse error: bad input stream" | Parsing CBOR or MessagePack from an input stream where the `badbit` or `failbit` is set. +json.exception.[parse_error](@ref parse_error).112 | "parse error at 1: error reading CBOR; last byte: 0xf8" | Not all types of CBOR or MessagePack are supported. This exception occurs if an unsupported byte was read. @since version 3.0.0 */ @@ -8175,7 +8176,9 @@ class basic_json default: { - JSON_THROW(std::invalid_argument("error parsing a msgpack @ " + std::to_string(current_idx) + ": " + std::to_string(static_cast(v[current_idx])))); + std::stringstream ss; + ss << std::hex << static_cast(v[current_idx]); + JSON_THROW(parse_error(112, current_idx + 1, "error reading MessagePack; last byte: 0x" + ss.str())); } } } @@ -8666,7 +8669,9 @@ class basic_json default: // anything else (0xFF is handled inside the other types) { - JSON_THROW(std::invalid_argument("error parsing a CBOR @ " + std::to_string(current_idx) + ": " + std::to_string(static_cast(v[current_idx])))); + std::stringstream ss; + ss << std::hex << static_cast(v[current_idx]); + JSON_THROW(parse_error(112, current_idx + 1, "error reading CBOR; last byte: 0x" + ss.str())); } } } diff --git a/test/src/unit-cbor.cpp b/test/src/unit-cbor.cpp index 9525c7220..5667196a6 100644 --- a/test/src/unit-cbor.cpp +++ b/test/src/unit-cbor.cpp @@ -1192,6 +1192,69 @@ TEST_CASE("CBOR") CHECK_THROWS_WITH(json::from_cbor(std::vector({0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00})), "[json.exception.parse_error.110] parse error at 1: cannot read 8 bytes from vector"); } + + SECTION("unsupported bytes") + { + SECTION("concrete examples") + { + CHECK_THROWS_AS(json::from_cbor(std::vector({0x1c})), json::parse_error); + CHECK_THROWS_WITH(json::from_cbor(std::vector({0x1c})), + "[json.exception.parse_error.112] parse error at 1: error reading CBOR; last byte: 0x1c"); + CHECK_THROWS_AS(json::from_cbor(std::vector({0xf8})), json::parse_error); + CHECK_THROWS_WITH(json::from_cbor(std::vector({0xf8})), + "[json.exception.parse_error.112] parse error at 1: error reading CBOR; last byte: 0xf8"); + } + + SECTION("all unsupported bytes") + { + for (auto byte : + { + // ? + 0x1c, 0x1d, 0x1e, 0x1f, + // ? + 0x3c, 0x3d, 0x3e, 0x3f, + // byte strings + 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, + // byte strings + 0x58, 0x59, 0x5a, 0x5b, + // ? + 0x5c, 0x5d, 0x5e, + // byte string + 0x5f, + // ? + 0x7c, 0x7d, 0x7e, + // ? + 0x9c, 0x9d, 0x9e, + // ? + 0xbc, 0xbd, 0xbe, + // date/time + 0xc0, 0xc1, + // bignum + 0xc2, 0xc3, + // fraction + 0xc4, + // bigfloat + 0xc5, + // tagged item + 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, + // expected conversion + 0xd5, 0xd6, 0xd7, + // more tagged items + 0xd8, 0xd9, 0xda, 0xdb, + // ? + 0xdc, 0xdd, 0xde, 0xdf, + // (simple value) + 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1, 0xf2, 0xf3, + // undefined + 0xf7, + // simple value + 0xf8 + }) + { + CHECK_THROWS_AS(json::from_cbor(std::vector({static_cast(byte)})), json::parse_error); + } + } + } } } diff --git a/test/src/unit-msgpack.cpp b/test/src/unit-msgpack.cpp index 3a2ae5b15..04428dfff 100644 --- a/test/src/unit-msgpack.cpp +++ b/test/src/unit-msgpack.cpp @@ -1016,6 +1016,90 @@ TEST_CASE("MessagePack") json j = json::from_msgpack(given); CHECK(j.get() == Approx(25.0000019073486)); } + + SECTION("errors") + { + SECTION("too short byte vector") + { + CHECK_THROWS_AS(json::from_msgpack(std::vector({0xcc})), json::parse_error); + CHECK_THROWS_AS(json::from_msgpack(std::vector({0xcd})), json::parse_error); + CHECK_THROWS_AS(json::from_msgpack(std::vector({0xcd, 0x00})), json::parse_error); + CHECK_THROWS_AS(json::from_msgpack(std::vector({0xce})), json::parse_error); + CHECK_THROWS_AS(json::from_msgpack(std::vector({0xce, 0x00})), json::parse_error); + CHECK_THROWS_AS(json::from_msgpack(std::vector({0xce, 0x00, 0x00})), json::parse_error); + CHECK_THROWS_AS(json::from_msgpack(std::vector({0xce, 0x00, 0x00, 0x00})), json::parse_error); + CHECK_THROWS_AS(json::from_msgpack(std::vector({0xcf})), json::parse_error); + CHECK_THROWS_AS(json::from_msgpack(std::vector({0xcf, 0x00})), json::parse_error); + CHECK_THROWS_AS(json::from_msgpack(std::vector({0xcf, 0x00, 0x00})), json::parse_error); + CHECK_THROWS_AS(json::from_msgpack(std::vector({0xcf, 0x00, 0x00, 0x00})), json::parse_error); + CHECK_THROWS_AS(json::from_msgpack(std::vector({0xcf, 0x00, 0x00, 0x00, 0x00})), json::parse_error); + CHECK_THROWS_AS(json::from_msgpack(std::vector({0xcf, 0x00, 0x00, 0x00, 0x00, 0x00})), json::parse_error); + CHECK_THROWS_AS(json::from_msgpack(std::vector({0xcf, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00})), json::parse_error); + CHECK_THROWS_AS(json::from_msgpack(std::vector({0xcf, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00})), json::parse_error); + + CHECK_THROWS_WITH(json::from_msgpack(std::vector({0xcc})), + "[json.exception.parse_error.110] parse error at 1: cannot read 1 bytes from vector"); + CHECK_THROWS_WITH(json::from_msgpack(std::vector({0xcd})), + "[json.exception.parse_error.110] parse error at 1: cannot read 2 bytes from vector"); + CHECK_THROWS_WITH(json::from_msgpack(std::vector({0xcd, 0x00})), + "[json.exception.parse_error.110] parse error at 1: cannot read 2 bytes from vector"); + CHECK_THROWS_WITH(json::from_msgpack(std::vector({0xce})), + "[json.exception.parse_error.110] parse error at 1: cannot read 4 bytes from vector"); + CHECK_THROWS_WITH(json::from_msgpack(std::vector({0xce, 0x00})), + "[json.exception.parse_error.110] parse error at 1: cannot read 4 bytes from vector"); + CHECK_THROWS_WITH(json::from_msgpack(std::vector({0xce, 0x00, 0x00})), + "[json.exception.parse_error.110] parse error at 1: cannot read 4 bytes from vector"); + CHECK_THROWS_WITH(json::from_msgpack(std::vector({0xce, 0x00, 0x00, 0x00})), + "[json.exception.parse_error.110] parse error at 1: cannot read 4 bytes from vector"); + CHECK_THROWS_WITH(json::from_msgpack(std::vector({0xcf})), + "[json.exception.parse_error.110] parse error at 1: cannot read 8 bytes from vector"); + CHECK_THROWS_WITH(json::from_msgpack(std::vector({0xcf, 0x00})), + "[json.exception.parse_error.110] parse error at 1: cannot read 8 bytes from vector"); + CHECK_THROWS_WITH(json::from_msgpack(std::vector({0xcf, 0x00, 0x00})), + "[json.exception.parse_error.110] parse error at 1: cannot read 8 bytes from vector"); + CHECK_THROWS_WITH(json::from_msgpack(std::vector({0xcf, 0x00, 0x00, 0x00})), + "[json.exception.parse_error.110] parse error at 1: cannot read 8 bytes from vector"); + CHECK_THROWS_WITH(json::from_msgpack(std::vector({0xcf, 0x00, 0x00, 0x00, 0x00})), + "[json.exception.parse_error.110] parse error at 1: cannot read 8 bytes from vector"); + CHECK_THROWS_WITH(json::from_msgpack(std::vector({0xcf, 0x00, 0x00, 0x00, 0x00, 0x00})), + "[json.exception.parse_error.110] parse error at 1: cannot read 8 bytes from vector"); + CHECK_THROWS_WITH(json::from_msgpack(std::vector({0xcf, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00})), + "[json.exception.parse_error.110] parse error at 1: cannot read 8 bytes from vector"); + CHECK_THROWS_WITH(json::from_msgpack(std::vector({0xcf, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00})), + "[json.exception.parse_error.110] parse error at 1: cannot read 8 bytes from vector"); + } + + SECTION("unsupported bytes") + { + SECTION("concrete examples") + { + CHECK_THROWS_AS(json::from_msgpack(std::vector({0xc1})), json::parse_error); + CHECK_THROWS_WITH(json::from_msgpack(std::vector({0xc1})), + "[json.exception.parse_error.112] parse error at 1: error reading MessagePack; last byte: 0xc1"); + CHECK_THROWS_AS(json::from_msgpack(std::vector({0xc6})), json::parse_error); + CHECK_THROWS_WITH(json::from_msgpack(std::vector({0xc6})), + "[json.exception.parse_error.112] parse error at 1: error reading MessagePack; last byte: 0xc6"); + } + + SECTION("all unsupported bytes") + { + for (auto byte : + { + // never used + 0xc1, + // bin + 0xc4, 0xc5, 0xc6, + // ext + 0xc7, 0xc8, 0xc9, + // fixext + 0xd4, 0xd5, 0xd6, 0xd7, 0xd8 + }) + { + CHECK_THROWS_AS(json::from_msgpack(std::vector({static_cast(byte)})), json::parse_error); + } + } + } + } } From 8fcd01631f9383c6a8a2ff6a6286e78b2a96b5f4 Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Wed, 8 Mar 2017 16:39:17 +0100 Subject: [PATCH 28/52] :white_check_mark: improved test coverage Tests for parse_error.109 were missing. --- test/src/unit-json_pointer.cpp | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/test/src/unit-json_pointer.cpp b/test/src/unit-json_pointer.cpp index a6f811eb9..d14261a0f 100644 --- a/test/src/unit-json_pointer.cpp +++ b/test/src/unit-json_pointer.cpp @@ -272,6 +272,20 @@ TEST_CASE("JSON pointers") CHECK_THROWS_AS(j["/one"_json_pointer] = 1, json::parse_error); CHECK_THROWS_WITH(j["/one"_json_pointer] = 1, "[json.exception.parse_error.109] parse error: array index 'one' is not a number"); + CHECK_THROWS_AS(j_const["/one"_json_pointer] == 1, json::parse_error); + CHECK_THROWS_WITH(j_const["/one"_json_pointer] == 1, + "[json.exception.parse_error.109] parse error: array index 'one' is not a number"); + + CHECK_THROWS_AS(j.at("/one"_json_pointer) = 1, json::parse_error); + CHECK_THROWS_WITH(j.at("/one"_json_pointer) = 1, + "[json.exception.parse_error.109] parse error: array index 'one' is not a number"); + CHECK_THROWS_AS(j_const.at("/one"_json_pointer) == 1, json::parse_error); + CHECK_THROWS_WITH(j_const.at("/one"_json_pointer) == 1, + "[json.exception.parse_error.109] parse error: array index 'one' is not a number"); + + CHECK_THROWS_AS(json({{"/list/0", 1}, {"/list/1", 2}, {"/list/three", 3}}).unflatten(), json::parse_error); + CHECK_THROWS_WITH(json({{"/list/0", 1}, {"/list/1", 2}, {"/list/three", 3}}).unflatten(), + "[json.exception.parse_error.109] parse error: array index 'three' is not a number"); // assign to "-" j["/-"_json_pointer] = 99; From fc9b528ec9e48a1e02c861b527fe508aec5a4107 Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Wed, 8 Mar 2017 18:07:21 +0100 Subject: [PATCH 29/52] :hammer: changed an exception --- src/json.hpp | 15 +++---- src/json.hpp.re2c | 12 +++--- test/src/fuzzer-parse_json.cpp | 4 +- test/src/unit-cbor.cpp | 46 +++++++++----------- test/src/unit-msgpack.cpp | 30 +++++++------- test/src/unit-regression.cpp | 76 +++++++++++++++++++++++++--------- 6 files changed, 106 insertions(+), 77 deletions(-) diff --git a/src/json.hpp b/src/json.hpp index 68bb3cd70..ffe64d1a4 100644 --- a/src/json.hpp +++ b/src/json.hpp @@ -7374,10 +7374,11 @@ class basic_json template static T get_from_vector(const std::vector& vec, const size_t current_index) { - if (current_index + sizeof(T) + 1 > vec.size()) - { - JSON_THROW(parse_error(110, current_index + 1, "cannot read " + std::to_string(sizeof(T)) + " bytes from vector")); - } + check_length(vec.size(), sizeof(T), current_index + 1); + //if (current_index + sizeof(T) + 1 > vec.size()) + //{ + // JSON_THROW(parse_error(110, current_index + 1, "cannot read " + std::to_string(sizeof(T)) + " bytes from vector")); + //} T result; auto* ptr = reinterpret_cast(&result); @@ -7926,19 +7927,19 @@ class basic_json // simple case: requested length is greater than the vector's length if (len > size or offset > size) { - JSON_THROW(std::out_of_range("len out of range")); + JSON_THROW(parse_error(110, offset + 1, "cannot read " + std::to_string(len) + " bytes from vector")); } // second case: adding offset would result in overflow if ((size > (std::numeric_limits::max() - offset))) { - JSON_THROW(std::out_of_range("len+offset out of range")); + JSON_THROW(parse_error(110, offset + 1, "cannot read " + std::to_string(len) + " bytes from vector")); } // last case: reading past the end of the vector if (len + offset > size) { - JSON_THROW(std::out_of_range("len+offset out of range")); + JSON_THROW(parse_error(110, offset + 1, "cannot read " + std::to_string(len) + " bytes from vector")); } } diff --git a/src/json.hpp.re2c b/src/json.hpp.re2c index 60a1042cf..300a6219b 100644 --- a/src/json.hpp.re2c +++ b/src/json.hpp.re2c @@ -7374,10 +7374,8 @@ class basic_json template static T get_from_vector(const std::vector& vec, const size_t current_index) { - if (current_index + sizeof(T) + 1 > vec.size()) - { - JSON_THROW(parse_error(110, current_index + 1, "cannot read " + std::to_string(sizeof(T)) + " bytes from vector")); - } + // check if we can read sizeof(T) bytes starting the next index + check_length(vec.size(), sizeof(T), current_index + 1); T result; auto* ptr = reinterpret_cast(&result); @@ -7926,19 +7924,19 @@ class basic_json // simple case: requested length is greater than the vector's length if (len > size or offset > size) { - JSON_THROW(std::out_of_range("len out of range")); + JSON_THROW(parse_error(110, offset + 1, "cannot read " + std::to_string(len) + " bytes from vector")); } // second case: adding offset would result in overflow if ((size > (std::numeric_limits::max() - offset))) { - JSON_THROW(std::out_of_range("len+offset out of range")); + JSON_THROW(parse_error(110, offset + 1, "cannot read " + std::to_string(len) + " bytes from vector")); } // last case: reading past the end of the vector if (len + offset > size) { - JSON_THROW(std::out_of_range("len+offset out of range")); + JSON_THROW(parse_error(110, offset + 1, "cannot read " + std::to_string(len) + " bytes from vector")); } } diff --git a/test/src/fuzzer-parse_json.cpp b/test/src/fuzzer-parse_json.cpp index bd2e5e391..ff5850665 100644 --- a/test/src/fuzzer-parse_json.cpp +++ b/test/src/fuzzer-parse_json.cpp @@ -49,13 +49,13 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) // serializations must match assert(s1 == s2); } - catch (const std::invalid_argument&) + catch (const json::parse_error&) { // parsing a JSON serialization must not fail assert(false); } } - catch (const std::invalid_argument&) + catch (const json::parse_error&) { // parse errors are ok, because input may be random bytes } diff --git a/test/src/unit-cbor.cpp b/test/src/unit-cbor.cpp index 5667196a6..32464ae71 100644 --- a/test/src/unit-cbor.cpp +++ b/test/src/unit-cbor.cpp @@ -1162,35 +1162,35 @@ TEST_CASE("CBOR") CHECK_THROWS_AS(json::from_cbor(std::vector({0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00})), json::parse_error); CHECK_THROWS_WITH(json::from_cbor(std::vector({0x18})), - "[json.exception.parse_error.110] parse error at 1: cannot read 1 bytes from vector"); + "[json.exception.parse_error.110] parse error at 2: cannot read 1 bytes from vector"); CHECK_THROWS_WITH(json::from_cbor(std::vector({0x19})), - "[json.exception.parse_error.110] parse error at 1: cannot read 2 bytes from vector"); + "[json.exception.parse_error.110] parse error at 2: cannot read 2 bytes from vector"); CHECK_THROWS_WITH(json::from_cbor(std::vector({0x19, 0x00})), - "[json.exception.parse_error.110] parse error at 1: cannot read 2 bytes from vector"); + "[json.exception.parse_error.110] parse error at 2: cannot read 2 bytes from vector"); CHECK_THROWS_WITH(json::from_cbor(std::vector({0x1a})), - "[json.exception.parse_error.110] parse error at 1: cannot read 4 bytes from vector"); + "[json.exception.parse_error.110] parse error at 2: cannot read 4 bytes from vector"); CHECK_THROWS_WITH(json::from_cbor(std::vector({0x1a, 0x00})), - "[json.exception.parse_error.110] parse error at 1: cannot read 4 bytes from vector"); + "[json.exception.parse_error.110] parse error at 2: cannot read 4 bytes from vector"); CHECK_THROWS_WITH(json::from_cbor(std::vector({0x1a, 0x00, 0x00})), - "[json.exception.parse_error.110] parse error at 1: cannot read 4 bytes from vector"); + "[json.exception.parse_error.110] parse error at 2: cannot read 4 bytes from vector"); CHECK_THROWS_WITH(json::from_cbor(std::vector({0x1a, 0x00, 0x00, 0x00})), - "[json.exception.parse_error.110] parse error at 1: cannot read 4 bytes from vector"); + "[json.exception.parse_error.110] parse error at 2: cannot read 4 bytes from vector"); CHECK_THROWS_WITH(json::from_cbor(std::vector({0x1b})), - "[json.exception.parse_error.110] parse error at 1: cannot read 8 bytes from vector"); + "[json.exception.parse_error.110] parse error at 2: cannot read 8 bytes from vector"); CHECK_THROWS_WITH(json::from_cbor(std::vector({0x1b, 0x00})), - "[json.exception.parse_error.110] parse error at 1: cannot read 8 bytes from vector"); + "[json.exception.parse_error.110] parse error at 2: cannot read 8 bytes from vector"); CHECK_THROWS_WITH(json::from_cbor(std::vector({0x1b, 0x00, 0x00})), - "[json.exception.parse_error.110] parse error at 1: cannot read 8 bytes from vector"); + "[json.exception.parse_error.110] parse error at 2: cannot read 8 bytes from vector"); CHECK_THROWS_WITH(json::from_cbor(std::vector({0x1b, 0x00, 0x00, 0x00})), - "[json.exception.parse_error.110] parse error at 1: cannot read 8 bytes from vector"); + "[json.exception.parse_error.110] parse error at 2: cannot read 8 bytes from vector"); CHECK_THROWS_WITH(json::from_cbor(std::vector({0x1b, 0x00, 0x00, 0x00, 0x00})), - "[json.exception.parse_error.110] parse error at 1: cannot read 8 bytes from vector"); + "[json.exception.parse_error.110] parse error at 2: cannot read 8 bytes from vector"); CHECK_THROWS_WITH(json::from_cbor(std::vector({0x1b, 0x00, 0x00, 0x00, 0x00, 0x00})), - "[json.exception.parse_error.110] parse error at 1: cannot read 8 bytes from vector"); + "[json.exception.parse_error.110] parse error at 2: cannot read 8 bytes from vector"); CHECK_THROWS_WITH(json::from_cbor(std::vector({0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00})), - "[json.exception.parse_error.110] parse error at 1: cannot read 8 bytes from vector"); + "[json.exception.parse_error.110] parse error at 2: cannot read 8 bytes from vector"); CHECK_THROWS_WITH(json::from_cbor(std::vector({0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00})), - "[json.exception.parse_error.110] parse error at 1: cannot read 8 bytes from vector"); + "[json.exception.parse_error.110] parse error at 2: cannot read 8 bytes from vector"); } SECTION("unsupported bytes") @@ -1341,21 +1341,13 @@ TEST_CASE("CBOR regressions", "[!throws]") // deserializations must match CHECK(j1 == j2); } - catch (const std::invalid_argument&) + catch (const json::parse_error&) { // parsing a CBOR serialization must not fail CHECK(false); } } - catch (const std::invalid_argument&) - { - // parse errors are ok, because input may be random bytes - } - catch (const std::out_of_range&) - { - // parse errors are ok, because input may be random bytes - } - catch (const std::domain_error&) + catch (const json::parse_error&) { // parse errors are ok, because input may be random bytes } @@ -1365,7 +1357,9 @@ TEST_CASE("CBOR regressions", "[!throws]") SECTION("improve code coverage") { // exotic edge case - CHECK_THROWS_AS(json::check_length(0xffffffffffffffffull, 0xfffffffffffffff0ull, 0xff), std::out_of_range); + CHECK_THROWS_AS(json::check_length(0xffffffffffffffffull, 0xfffffffffffffff0ull, 0xff), json::parse_error); + CHECK_THROWS_WITH(json::check_length(0xffffffffffffffffull, 0xfffffffffffffff0ull, 0xff), + "[json.exception.parse_error.110] parse error at 256: cannot read 18446744073709551600 bytes from vector"); } } diff --git a/test/src/unit-msgpack.cpp b/test/src/unit-msgpack.cpp index 04428dfff..de1a7bca4 100644 --- a/test/src/unit-msgpack.cpp +++ b/test/src/unit-msgpack.cpp @@ -1038,35 +1038,35 @@ TEST_CASE("MessagePack") CHECK_THROWS_AS(json::from_msgpack(std::vector({0xcf, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00})), json::parse_error); CHECK_THROWS_WITH(json::from_msgpack(std::vector({0xcc})), - "[json.exception.parse_error.110] parse error at 1: cannot read 1 bytes from vector"); + "[json.exception.parse_error.110] parse error at 2: cannot read 1 bytes from vector"); CHECK_THROWS_WITH(json::from_msgpack(std::vector({0xcd})), - "[json.exception.parse_error.110] parse error at 1: cannot read 2 bytes from vector"); + "[json.exception.parse_error.110] parse error at 2: cannot read 2 bytes from vector"); CHECK_THROWS_WITH(json::from_msgpack(std::vector({0xcd, 0x00})), - "[json.exception.parse_error.110] parse error at 1: cannot read 2 bytes from vector"); + "[json.exception.parse_error.110] parse error at 2: cannot read 2 bytes from vector"); CHECK_THROWS_WITH(json::from_msgpack(std::vector({0xce})), - "[json.exception.parse_error.110] parse error at 1: cannot read 4 bytes from vector"); + "[json.exception.parse_error.110] parse error at 2: cannot read 4 bytes from vector"); CHECK_THROWS_WITH(json::from_msgpack(std::vector({0xce, 0x00})), - "[json.exception.parse_error.110] parse error at 1: cannot read 4 bytes from vector"); + "[json.exception.parse_error.110] parse error at 2: cannot read 4 bytes from vector"); CHECK_THROWS_WITH(json::from_msgpack(std::vector({0xce, 0x00, 0x00})), - "[json.exception.parse_error.110] parse error at 1: cannot read 4 bytes from vector"); + "[json.exception.parse_error.110] parse error at 2: cannot read 4 bytes from vector"); CHECK_THROWS_WITH(json::from_msgpack(std::vector({0xce, 0x00, 0x00, 0x00})), - "[json.exception.parse_error.110] parse error at 1: cannot read 4 bytes from vector"); + "[json.exception.parse_error.110] parse error at 2: cannot read 4 bytes from vector"); CHECK_THROWS_WITH(json::from_msgpack(std::vector({0xcf})), - "[json.exception.parse_error.110] parse error at 1: cannot read 8 bytes from vector"); + "[json.exception.parse_error.110] parse error at 2: cannot read 8 bytes from vector"); CHECK_THROWS_WITH(json::from_msgpack(std::vector({0xcf, 0x00})), - "[json.exception.parse_error.110] parse error at 1: cannot read 8 bytes from vector"); + "[json.exception.parse_error.110] parse error at 2: cannot read 8 bytes from vector"); CHECK_THROWS_WITH(json::from_msgpack(std::vector({0xcf, 0x00, 0x00})), - "[json.exception.parse_error.110] parse error at 1: cannot read 8 bytes from vector"); + "[json.exception.parse_error.110] parse error at 2: cannot read 8 bytes from vector"); CHECK_THROWS_WITH(json::from_msgpack(std::vector({0xcf, 0x00, 0x00, 0x00})), - "[json.exception.parse_error.110] parse error at 1: cannot read 8 bytes from vector"); + "[json.exception.parse_error.110] parse error at 2: cannot read 8 bytes from vector"); CHECK_THROWS_WITH(json::from_msgpack(std::vector({0xcf, 0x00, 0x00, 0x00, 0x00})), - "[json.exception.parse_error.110] parse error at 1: cannot read 8 bytes from vector"); + "[json.exception.parse_error.110] parse error at 2: cannot read 8 bytes from vector"); CHECK_THROWS_WITH(json::from_msgpack(std::vector({0xcf, 0x00, 0x00, 0x00, 0x00, 0x00})), - "[json.exception.parse_error.110] parse error at 1: cannot read 8 bytes from vector"); + "[json.exception.parse_error.110] parse error at 2: cannot read 8 bytes from vector"); CHECK_THROWS_WITH(json::from_msgpack(std::vector({0xcf, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00})), - "[json.exception.parse_error.110] parse error at 1: cannot read 8 bytes from vector"); + "[json.exception.parse_error.110] parse error at 2: cannot read 8 bytes from vector"); CHECK_THROWS_WITH(json::from_msgpack(std::vector({0xcf, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00})), - "[json.exception.parse_error.110] parse error at 1: cannot read 8 bytes from vector"); + "[json.exception.parse_error.110] parse error at 2: cannot read 8 bytes from vector"); } SECTION("unsupported bytes") diff --git a/test/src/unit-regression.cpp b/test/src/unit-regression.cpp index 2d7990676..324ab769d 100644 --- a/test/src/unit-regression.cpp +++ b/test/src/unit-regression.cpp @@ -613,37 +613,51 @@ TEST_CASE("regression tests") { // original test case std::vector vec {0x65, 0xf5, 0x0a, 0x48, 0x21}; - CHECK_THROWS_AS(json::from_cbor(vec), std::out_of_range); + CHECK_THROWS_AS(json::from_cbor(vec), json::parse_error); + CHECK_THROWS_WITH(json::from_cbor(vec), + "[json.exception.parse_error.110] parse error at 2: cannot read 5 bytes from vector"); } SECTION("issue #407 - Heap-buffer-overflow (OSS-Fuzz issue 343)") { // original test case: incomplete float64 std::vector vec1 {0xcb, 0x8f, 0x0a}; - CHECK_THROWS_AS(json::from_msgpack(vec1), std::out_of_range); + CHECK_THROWS_AS(json::from_msgpack(vec1), json::parse_error); + CHECK_THROWS_WITH(json::from_msgpack(vec1), + "[json.exception.parse_error.110] parse error at 2: cannot read 8 bytes from vector"); // related test case: incomplete float32 std::vector vec2 {0xca, 0x8f, 0x0a}; - CHECK_THROWS_AS(json::from_msgpack(vec2), std::out_of_range); + CHECK_THROWS_AS(json::from_msgpack(vec2), json::parse_error); + CHECK_THROWS_WITH(json::from_msgpack(vec2), + "[json.exception.parse_error.110] parse error at 2: cannot read 4 bytes from vector"); // related test case: incomplete Half-Precision Float (CBOR) std::vector vec3 {0xf9, 0x8f}; - CHECK_THROWS_AS(json::from_cbor(vec3), std::out_of_range); + CHECK_THROWS_AS(json::from_cbor(vec3), json::parse_error); + CHECK_THROWS_WITH(json::from_cbor(vec3), + "[json.exception.parse_error.110] parse error at 2: cannot read 2 bytes from vector"); // related test case: incomplete Single-Precision Float (CBOR) std::vector vec4 {0xfa, 0x8f, 0x0a}; - CHECK_THROWS_AS(json::from_cbor(vec4), std::out_of_range); + CHECK_THROWS_AS(json::from_cbor(vec4), json::parse_error); + CHECK_THROWS_WITH(json::from_cbor(vec4), + "[json.exception.parse_error.110] parse error at 2: cannot read 4 bytes from vector"); // related test case: incomplete Double-Precision Float (CBOR) std::vector vec5 {0xfb, 0x8f, 0x0a}; - CHECK_THROWS_AS(json::from_cbor(vec5), std::out_of_range); + CHECK_THROWS_AS(json::from_cbor(vec5), json::parse_error); + CHECK_THROWS_WITH(json::from_cbor(vec5), + "[json.exception.parse_error.110] parse error at 2: cannot read 8 bytes from vector"); } SECTION("issue #408 - Heap-buffer-overflow (OSS-Fuzz issue 344)") { // original test case std::vector vec1 {0x87}; - CHECK_THROWS_AS(json::from_msgpack(vec1), std::out_of_range); + CHECK_THROWS_AS(json::from_msgpack(vec1), json::parse_error); + CHECK_THROWS_WITH(json::from_msgpack(vec1), + "[json.exception.parse_error.110] parse error at 2: cannot read 1 bytes from vector"); // more test cases for MessagePack for (auto b : @@ -655,7 +669,7 @@ TEST_CASE("regression tests") }) { std::vector vec(1, static_cast(b)); - CHECK_THROWS_AS(json::from_msgpack(vec), std::out_of_range); + CHECK_THROWS_AS(json::from_msgpack(vec), json::parse_error); } // more test cases for CBOR @@ -670,28 +684,38 @@ TEST_CASE("regression tests") }) { std::vector vec(1, static_cast(b)); - CHECK_THROWS_AS(json::from_cbor(vec), std::out_of_range); + CHECK_THROWS_AS(json::from_cbor(vec), json::parse_error); } // special case: empty input std::vector vec2; - CHECK_THROWS_AS(json::from_cbor(vec2), std::out_of_range); - CHECK_THROWS_AS(json::from_msgpack(vec2), std::out_of_range); + CHECK_THROWS_AS(json::from_cbor(vec2), json::parse_error); + CHECK_THROWS_WITH(json::from_cbor(vec2), + "[json.exception.parse_error.110] parse error at 1: cannot read 1 bytes from vector"); + CHECK_THROWS_AS(json::from_msgpack(vec2), json::parse_error); + CHECK_THROWS_WITH(json::from_msgpack(vec2), + "[json.exception.parse_error.110] parse error at 1: cannot read 1 bytes from vector"); } SECTION("issue #411 - Heap-buffer-overflow (OSS-Fuzz issue 366)") { // original test case: empty UTF-8 string (indefinite length) std::vector vec1 {0x7f}; - CHECK_THROWS_AS(json::from_cbor(vec1), std::out_of_range); + CHECK_THROWS_AS(json::from_cbor(vec1), json::parse_error); + CHECK_THROWS_WITH(json::from_cbor(vec1), + "[json.exception.parse_error.110] parse error at 2: cannot read 1 bytes from vector"); // related test case: empty array (indefinite length) std::vector vec2 {0x9f}; - CHECK_THROWS_AS(json::from_cbor(vec2), std::out_of_range); + CHECK_THROWS_AS(json::from_cbor(vec2), json::parse_error); + CHECK_THROWS_WITH(json::from_cbor(vec2), + "[json.exception.parse_error.110] parse error at 2: cannot read 1 bytes from vector"); // related test case: empty map (indefinite length) std::vector vec3 {0xbf}; - CHECK_THROWS_AS(json::from_cbor(vec3), std::out_of_range); + CHECK_THROWS_AS(json::from_cbor(vec3), json::parse_error); + CHECK_THROWS_WITH(json::from_cbor(vec3), + "[json.exception.parse_error.110] parse error at 2: cannot read 1 bytes from vector"); } SECTION("issue #412 - Heap-buffer-overflow (OSS-Fuzz issue 367)") @@ -717,19 +741,27 @@ TEST_CASE("regression tests") 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60 }; - CHECK_THROWS_AS(json::from_cbor(vec), std::out_of_range); + CHECK_THROWS_AS(json::from_cbor(vec), json::parse_error); + CHECK_THROWS_WITH(json::from_cbor(vec), + "[json.exception.parse_error.110] parse error at 137: cannot read 1 bytes from vector"); // related test case: nonempty UTF-8 string (indefinite length) std::vector vec1 {0x7f, 0x61, 0x61}; - CHECK_THROWS_AS(json::from_cbor(vec1), std::out_of_range); + CHECK_THROWS_AS(json::from_cbor(vec1), json::parse_error); + CHECK_THROWS_WITH(json::from_cbor(vec1), + "[json.exception.parse_error.110] parse error at 4: cannot read 1 bytes from vector"); // related test case: nonempty array (indefinite length) std::vector vec2 {0x9f, 0x01}; - CHECK_THROWS_AS(json::from_cbor(vec2), std::out_of_range); + CHECK_THROWS_AS(json::from_cbor(vec2), json::parse_error); + CHECK_THROWS_WITH(json::from_cbor(vec2), + "[json.exception.parse_error.110] parse error at 3: cannot read 1 bytes from vector"); // related test case: nonempty map (indefinite length) std::vector vec3 {0xbf, 0x61, 0x61, 0x01}; - CHECK_THROWS_AS(json::from_cbor(vec3), std::out_of_range); + CHECK_THROWS_AS(json::from_cbor(vec3), json::parse_error); + CHECK_THROWS_WITH(json::from_cbor(vec3), + "[json.exception.parse_error.110] parse error at 5: cannot read 1 bytes from vector"); } SECTION("issue #414 - compare with literal 0)") @@ -762,7 +794,9 @@ TEST_CASE("regression tests") 0x96, 0x96, 0xb4, 0xb4, 0xfa, 0x94, 0x94, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0xfa }; - CHECK_THROWS_AS(json::from_cbor(vec1), std::out_of_range); + CHECK_THROWS_AS(json::from_cbor(vec1), json::parse_error); + CHECK_THROWS_WITH(json::from_cbor(vec1), + "[json.exception.parse_error.110] parse error at 49: cannot read 4 bytes from vector"); // related test case: double-precision std::vector vec2 @@ -774,7 +808,9 @@ TEST_CASE("regression tests") 0x96, 0x96, 0xb4, 0xb4, 0xfa, 0x94, 0x94, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0xfb }; - CHECK_THROWS_AS(json::from_cbor(vec2), std::out_of_range); + CHECK_THROWS_AS(json::from_cbor(vec2), json::parse_error); + CHECK_THROWS_WITH(json::from_cbor(vec2), + "[json.exception.parse_error.110] parse error at 49: cannot read 8 bytes from vector"); } SECTION("issue #452 - Heap-buffer-overflow (OSS-Fuzz issue 585)") From c8a6ce79ea52e616a32d1c96d1682ddf2545e213 Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Wed, 8 Mar 2017 18:37:03 +0100 Subject: [PATCH 30/52] :ambulance: fixing fuzzers to work with new exceptions --- test/src/fuzzer-parse_cbor.cpp | 12 ++++-------- test/src/fuzzer-parse_msgpack.cpp | 12 ++++-------- test/src/unit-cbor.cpp | 2 -- 3 files changed, 8 insertions(+), 18 deletions(-) diff --git a/test/src/fuzzer-parse_cbor.cpp b/test/src/fuzzer-parse_cbor.cpp index 30fa69779..6e7ae6362 100644 --- a/test/src/fuzzer-parse_cbor.cpp +++ b/test/src/fuzzer-parse_cbor.cpp @@ -44,23 +44,19 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) // deserializations must match assert(j1 == j2); } - catch (const std::invalid_argument&) + catch (const json::parse_error&) { // parsing a CBOR serialization must not fail assert(false); } } - catch (const std::invalid_argument&) + catch (const json::parse_error&) { // parse errors are ok, because input may be random bytes } - catch (const std::out_of_range&) + catch (const json::type_error&) { - // parse errors are ok, because input may be random bytes - } - catch (const std::domain_error&) - { - // parse errors are ok, because input may be random bytes + // type errors can occur during parsing, too } // return 0 - non-zero return values are reserved for future use diff --git a/test/src/fuzzer-parse_msgpack.cpp b/test/src/fuzzer-parse_msgpack.cpp index bf2fcab07..420283a40 100644 --- a/test/src/fuzzer-parse_msgpack.cpp +++ b/test/src/fuzzer-parse_msgpack.cpp @@ -44,23 +44,19 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) // deserializations must match assert(j1 == j2); } - catch (const std::invalid_argument&) + catch (const json::parse_error&) { // parsing a MessagePack serialization must not fail assert(false); } } - catch (const std::invalid_argument&) + catch (const json::parse_error&) { // parse errors are ok, because input may be random bytes } - catch (const std::out_of_range&) + catch (const json::type_error&) { - // parse errors are ok, because input may be random bytes - } - catch (const std::domain_error&) - { - // parse errors are ok, because input may be random bytes + // type errors can occur during parsing, too } // return 0 - non-zero return values are reserved for future use diff --git a/test/src/unit-cbor.cpp b/test/src/unit-cbor.cpp index 32464ae71..87cbadc20 100644 --- a/test/src/unit-cbor.cpp +++ b/test/src/unit-cbor.cpp @@ -1358,8 +1358,6 @@ TEST_CASE("CBOR regressions", "[!throws]") { // exotic edge case CHECK_THROWS_AS(json::check_length(0xffffffffffffffffull, 0xfffffffffffffff0ull, 0xff), json::parse_error); - CHECK_THROWS_WITH(json::check_length(0xffffffffffffffffull, 0xfffffffffffffff0ull, 0xff), - "[json.exception.parse_error.110] parse error at 256: cannot read 18446744073709551600 bytes from vector"); } } From 9374eaa013fd5f080d4c70afde83311d493394e4 Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Wed, 8 Mar 2017 19:16:53 +0100 Subject: [PATCH 31/52] :hammer: added user-defined exception 501 --- src/json.hpp | 38 ++++++++++++++++++++++++------------ src/json.hpp.re2c | 34 +++++++++++++++++++++++--------- test/src/unit-json_patch.cpp | 12 ++++++------ 3 files changed, 56 insertions(+), 28 deletions(-) diff --git a/src/json.hpp b/src/json.hpp index ffe64d1a4..f1462db89 100644 --- a/src/json.hpp +++ b/src/json.hpp @@ -52,7 +52,6 @@ SOFTWARE. #include // addressof, allocator, allocator_traits, unique_ptr #include // accumulate #include // stringstream -#include // domain_error, invalid_argument, out_of_range #include // getline, stoi, string, to_string #include // add_pointer, conditional, decay, enable_if, false_type, integral_constant, is_arithmetic, is_base_of, is_const, is_constructible, is_convertible, is_default_constructible, is_enum, is_floating_point, is_integral, is_nothrow_move_assignable, is_nothrow_move_constructible, is_pointer, is_reference, is_same, is_scalar, is_signed, remove_const, remove_cv, remove_pointer, remove_reference, true_type, underlying_type #include // declval, forward, make_pair, move, pair, swap @@ -295,6 +294,26 @@ class out_of_range : public exception {} }; +/*! +@brief exception indicating other errors + +Exceptions have ids 5xx. + +name / id | example massage | description +------------------------------ | --------------- | ------------------------- +json.exception.[other_error](@ref other_error).501 | "unsuccessful" | A JSON Patch operation 'test' failed. + +@since version 3.0.0 +*/ +class other_error : public exception +{ + public: + other_error(int id_, const std::string& what_arg_) + : exception(id_, "other_error", what_arg_) + {} +}; + + /////////////////////////// // JSON type enumeration // @@ -1240,12 +1259,6 @@ class basic_json /// Classes to implement user-defined exceptions. /// @{ - /* - name / id | example massage | description - ------------------------------ | --------------- | ------------------------- - json.exception.other.500 | "unsuccessful" | A JSON Patch operation 'test' failed. - */ - /// @copydoc detail::parse_error using parse_error = detail::parse_error; /// @copydoc detail::invalid_iterator @@ -1254,6 +1267,8 @@ class basic_json using type_error = detail::type_error; /// @copydoc detail::out_of_range using out_of_range = detail::out_of_range; + /// @copydoc detail::other_error + using other_error = detail::other_error; /// @} @@ -1948,7 +1963,7 @@ class basic_json { if (t == value_t::null) { - JSON_THROW(std::domain_error("961c151d2e87f2686a955a9be24d316f1362bf21 2.1.1")); // LCOV_EXCL_LINE + JSON_THROW(other_error(500, "961c151d2e87f2686a955a9be24d316f1362bf21 2.1.1")); // LCOV_EXCL_LINE } break; } @@ -7374,11 +7389,8 @@ class basic_json template static T get_from_vector(const std::vector& vec, const size_t current_index) { + // check if we can read sizeof(T) bytes starting the next index check_length(vec.size(), sizeof(T), current_index + 1); - //if (current_index + sizeof(T) + 1 > vec.size()) - //{ - // JSON_THROW(parse_error(110, current_index + 1, "cannot read " + std::to_string(sizeof(T)) + " bytes from vector")); - //} T result; auto* ptr = reinterpret_cast(&result); @@ -13062,7 +13074,7 @@ basic_json_parser_74: // throw an exception if test fails if (not success) { - JSON_THROW(std::domain_error("unsuccessful: " + val.dump())); + JSON_THROW(other_error(501, "unsuccessful: " + val.dump())); } break; diff --git a/src/json.hpp.re2c b/src/json.hpp.re2c index 300a6219b..3044cf6b4 100644 --- a/src/json.hpp.re2c +++ b/src/json.hpp.re2c @@ -52,7 +52,6 @@ SOFTWARE. #include // addressof, allocator, allocator_traits, unique_ptr #include // accumulate #include // stringstream -#include // domain_error, invalid_argument, out_of_range #include // getline, stoi, string, to_string #include // add_pointer, conditional, decay, enable_if, false_type, integral_constant, is_arithmetic, is_base_of, is_const, is_constructible, is_convertible, is_default_constructible, is_enum, is_floating_point, is_integral, is_nothrow_move_assignable, is_nothrow_move_constructible, is_pointer, is_reference, is_same, is_scalar, is_signed, remove_const, remove_cv, remove_pointer, remove_reference, true_type, underlying_type #include // declval, forward, make_pair, move, pair, swap @@ -295,6 +294,27 @@ class out_of_range : public exception {} }; +/*! +@brief exception indicating other errors + +Exceptions have ids 5xx. + +name / id | example massage | description +------------------------------ | --------------- | ------------------------- +json.exception.[other_error](@ref other_error).501 | "unsuccessful: {"op":"test","path":"/baz", + "value":"bar"}" | A JSON Patch operation 'test' failed. + +@since version 3.0.0 +*/ +class other_error : public exception +{ + public: + other_error(int id_, const std::string& what_arg_) + : exception(id_, "other_error", what_arg_) + {} +}; + + /////////////////////////// // JSON type enumeration // @@ -1240,12 +1260,6 @@ class basic_json /// Classes to implement user-defined exceptions. /// @{ - /* - name / id | example massage | description - ------------------------------ | --------------- | ------------------------- - json.exception.other.500 | "unsuccessful" | A JSON Patch operation 'test' failed. - */ - /// @copydoc detail::parse_error using parse_error = detail::parse_error; /// @copydoc detail::invalid_iterator @@ -1254,6 +1268,8 @@ class basic_json using type_error = detail::type_error; /// @copydoc detail::out_of_range using out_of_range = detail::out_of_range; + /// @copydoc detail::other_error + using other_error = detail::other_error; /// @} @@ -1948,7 +1964,7 @@ class basic_json { if (t == value_t::null) { - JSON_THROW(std::domain_error("961c151d2e87f2686a955a9be24d316f1362bf21 2.1.1")); // LCOV_EXCL_LINE + JSON_THROW(other_error(500, "961c151d2e87f2686a955a9be24d316f1362bf21 2.1.1")); // LCOV_EXCL_LINE } break; } @@ -12092,7 +12108,7 @@ class basic_json // throw an exception if test fails if (not success) { - JSON_THROW(std::domain_error("unsuccessful: " + val.dump())); + JSON_THROW(other_error(501, "unsuccessful: " + val.dump())); } break; diff --git a/test/src/unit-json_patch.cpp b/test/src/unit-json_patch.cpp index c021450bc..9ab86ea42 100644 --- a/test/src/unit-json_patch.cpp +++ b/test/src/unit-json_patch.cpp @@ -337,8 +337,8 @@ TEST_CASE("JSON patch") )"_json; // check that evaluation throws - CHECK_THROWS_AS(doc.patch(patch), std::domain_error); - CHECK_THROWS_WITH(doc.patch(patch), "unsuccessful: " + patch[0].dump()); + CHECK_THROWS_AS(doc.patch(patch), json::other_error); + CHECK_THROWS_WITH(doc.patch(patch), "[json.exception.other_error.501] unsuccessful: " + patch[0].dump()); } SECTION("A.10. Adding a Nested Member Object") @@ -478,8 +478,8 @@ TEST_CASE("JSON patch") )"_json; // check that evaluation throws - CHECK_THROWS_AS(doc.patch(patch), std::domain_error); - CHECK_THROWS_WITH(doc.patch(patch), "unsuccessful: " + patch[0].dump()); + CHECK_THROWS_AS(doc.patch(patch), json::other_error); + CHECK_THROWS_WITH(doc.patch(patch), "[json.exception.other_error.501] unsuccessful: " + patch[0].dump()); } SECTION("A.16. Adding an Array Value") @@ -1177,8 +1177,8 @@ TEST_CASE("JSON patch") )"_json; // the test will fail - CHECK_THROWS_AS(doc.patch(patch), std::domain_error); - CHECK_THROWS_WITH(doc.patch(patch), "unsuccessful: " + patch[0].dump()); + CHECK_THROWS_AS(doc.patch(patch), json::other_error); + CHECK_THROWS_WITH(doc.patch(patch), "[json.exception.other_error.501] unsuccessful: " + patch[0].dump()); } } } From fe71e7df1f06afbac4b3312194e0755ee21efa36 Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Wed, 8 Mar 2017 21:03:19 +0100 Subject: [PATCH 32/52] :memo: overworked documentation Replacing references to std exceptions with user-defined exceptions. Also changed some examples to the new exceptions. --- doc/examples/at__object_t_key_type | Bin 0 -> 130960 bytes doc/examples/at__object_t_key_type.cpp | 4 +- doc/examples/at__object_t_key_type.link | 2 +- doc/examples/at__object_t_key_type.output | 2 +- doc/examples/at__object_t_key_type.test | 3 + doc/examples/at__object_t_key_type_const.cpp | 2 +- doc/examples/at__object_t_key_type_const.link | 2 +- doc/examples/at__size_type.cpp | 4 +- doc/examples/at__size_type.link | 2 +- doc/examples/at__size_type.output | 2 +- doc/examples/at__size_type_const.cpp | 2 +- doc/examples/at__size_type_const.link | 2 +- doc/examples/get_ref | Bin 0 -> 38132 bytes doc/examples/get_ref.cpp | 2 +- doc/examples/get_ref.link | 2 +- doc/examples/get_ref.output | 2 +- doc/examples/get_ref.test | 2 + doc/examples/json_pointer | Bin 0 -> 47612 bytes doc/examples/json_pointer.cpp | 12 +- doc/examples/json_pointer.link | 2 +- doc/examples/json_pointer.output | 6 +- doc/examples/json_pointer.test | 3 + src/json.hpp | 199 +++++++++++++----- src/json.hpp.re2c | 196 ++++++++++++----- 24 files changed, 325 insertions(+), 128 deletions(-) create mode 100755 doc/examples/at__object_t_key_type create mode 100644 doc/examples/at__object_t_key_type.test create mode 100755 doc/examples/get_ref create mode 100644 doc/examples/get_ref.test create mode 100755 doc/examples/json_pointer create mode 100644 doc/examples/json_pointer.test diff --git a/doc/examples/at__object_t_key_type b/doc/examples/at__object_t_key_type new file mode 100755 index 0000000000000000000000000000000000000000..03f48e68ca3efe94e36855f9d69bd72b6854b4ff GIT binary patch literal 130960 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 JywMTA{}1@W;O+nb literal 0 HcmV?d00001 diff --git a/doc/examples/at__object_t_key_type.cpp b/doc/examples/at__object_t_key_type.cpp index 83646f155..a66bd9a3d 100644 --- a/doc/examples/at__object_t_key_type.cpp +++ b/doc/examples/at__object_t_key_type.cpp @@ -26,8 +26,8 @@ int main() { object.at("the fast") = "il rapido"; } - catch (std::out_of_range& e) + catch (json::out_of_range& e) { - std::cout << "out of range: " << e.what() << '\n'; + std::cout << e.what() << '\n'; } } diff --git a/doc/examples/at__object_t_key_type.link b/doc/examples/at__object_t_key_type.link index 4a050ecfd..1cb99d461 100644 --- a/doc/examples/at__object_t_key_type.link +++ b/doc/examples/at__object_t_key_type.link @@ -1 +1 @@ -online \ No newline at end of file +online \ No newline at end of file diff --git a/doc/examples/at__object_t_key_type.output b/doc/examples/at__object_t_key_type.output index 79cff2d7f..654b9eb63 100644 --- a/doc/examples/at__object_t_key_type.output +++ b/doc/examples/at__object_t_key_type.output @@ -1,3 +1,3 @@ "il brutto" {"the bad":"il cattivo","the good":"il buono","the ugly":"il brutto"} -out of range: key 'the fast' not found +[json.exception.out_of_range.403] key 'the fast' not found diff --git a/doc/examples/at__object_t_key_type.test b/doc/examples/at__object_t_key_type.test new file mode 100644 index 000000000..654b9eb63 --- /dev/null +++ b/doc/examples/at__object_t_key_type.test @@ -0,0 +1,3 @@ +"il brutto" +{"the bad":"il cattivo","the good":"il buono","the ugly":"il brutto"} +[json.exception.out_of_range.403] key 'the fast' not found diff --git a/doc/examples/at__object_t_key_type_const.cpp b/doc/examples/at__object_t_key_type_const.cpp index 0e8d9d728..99eb6f013 100644 --- a/doc/examples/at__object_t_key_type_const.cpp +++ b/doc/examples/at__object_t_key_type_const.cpp @@ -20,7 +20,7 @@ int main() { std::cout << object.at("the fast") << '\n'; } - catch (std::out_of_range) + catch (json::out_of_range) { std::cout << "out of range" << '\n'; } diff --git a/doc/examples/at__object_t_key_type_const.link b/doc/examples/at__object_t_key_type_const.link index 1ad9c07d9..a07dbd594 100644 --- a/doc/examples/at__object_t_key_type_const.link +++ b/doc/examples/at__object_t_key_type_const.link @@ -1 +1 @@ -online \ No newline at end of file +online \ No newline at end of file diff --git a/doc/examples/at__size_type.cpp b/doc/examples/at__size_type.cpp index e31d61d35..07e363ab3 100644 --- a/doc/examples/at__size_type.cpp +++ b/doc/examples/at__size_type.cpp @@ -21,8 +21,8 @@ int main() { array.at(5) = "sixth"; } - catch (std::out_of_range& e) + catch (json::out_of_range& e) { - std::cout << "out of range: " << e.what() << '\n'; + std::cout << e.what() << '\n'; } } diff --git a/doc/examples/at__size_type.link b/doc/examples/at__size_type.link index 00e42d300..78ec0ca02 100644 --- a/doc/examples/at__size_type.link +++ b/doc/examples/at__size_type.link @@ -1 +1 @@ -online \ No newline at end of file +online \ No newline at end of file diff --git a/doc/examples/at__size_type.output b/doc/examples/at__size_type.output index d1f68bdb8..4f0c9e54f 100644 --- a/doc/examples/at__size_type.output +++ b/doc/examples/at__size_type.output @@ -1,3 +1,3 @@ "third" ["first","second","third","fourth"] -out of range: array index 5 is out of range +[json.exception.out_of_range.401] array index 5 is out of range diff --git a/doc/examples/at__size_type_const.cpp b/doc/examples/at__size_type_const.cpp index a8a43ed8f..c29db4fb2 100644 --- a/doc/examples/at__size_type_const.cpp +++ b/doc/examples/at__size_type_const.cpp @@ -15,7 +15,7 @@ int main() { std::cout << array.at(5) << '\n'; } - catch (std::out_of_range) + catch (json::out_of_range) { std::cout << "out of range" << '\n'; } diff --git a/doc/examples/at__size_type_const.link b/doc/examples/at__size_type_const.link index 0fefb628c..c5f66fe0a 100644 --- a/doc/examples/at__size_type_const.link +++ b/doc/examples/at__size_type_const.link @@ -1 +1 @@ -online \ No newline at end of file +online \ No newline at end of file diff --git a/doc/examples/get_ref b/doc/examples/get_ref new file mode 100755 index 0000000000000000000000000000000000000000..d2dda9ba81796fd46a0b3d8cb861339285e07f15 GIT binary patch literal 38132 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 YQ}lEPF-EoUdQKrtW|j%#ZWEvX1IimE#Q*>R literal 0 HcmV?d00001 diff --git a/doc/examples/get_ref.cpp b/doc/examples/get_ref.cpp index d0ddb2d27..a152d3471 100644 --- a/doc/examples/get_ref.cpp +++ b/doc/examples/get_ref.cpp @@ -19,7 +19,7 @@ int main() { auto r3 = value.get_ref(); } - catch (std::domain_error& ex) + catch (json::type_error& ex) { std::cout << ex.what() << '\n'; } diff --git a/doc/examples/get_ref.link b/doc/examples/get_ref.link index ef560c42c..c5bd9c03b 100644 --- a/doc/examples/get_ref.link +++ b/doc/examples/get_ref.link @@ -1 +1 @@ -online \ No newline at end of file +online \ No newline at end of file diff --git a/doc/examples/get_ref.output b/doc/examples/get_ref.output index 50bc0df69..3811afa2f 100644 --- a/doc/examples/get_ref.output +++ b/doc/examples/get_ref.output @@ -1,2 +1,2 @@ 17 17 -incompatible ReferenceType for get_ref, actual type is number +[json.exception.type_error.303] incompatible ReferenceType for get_ref, actual type is number diff --git a/doc/examples/get_ref.test b/doc/examples/get_ref.test new file mode 100644 index 000000000..3811afa2f --- /dev/null +++ b/doc/examples/get_ref.test @@ -0,0 +1,2 @@ +17 17 +[json.exception.type_error.303] incompatible ReferenceType for get_ref, actual type is number diff --git a/doc/examples/json_pointer b/doc/examples/json_pointer new file mode 100755 index 0000000000000000000000000000000000000000..83f8491caf97ba3c05ab47ff0005c6be85579bdc GIT binary patch literal 47612 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 T?I}{RMEETcDX$x0Bj(=$@v}rg literal 0 HcmV?d00001 diff --git a/doc/examples/json_pointer.cpp b/doc/examples/json_pointer.cpp index 140eac3b6..3b23dfb2f 100644 --- a/doc/examples/json_pointer.cpp +++ b/doc/examples/json_pointer.cpp @@ -19,9 +19,9 @@ int main() { json::json_pointer p9("foo"); } - catch (std::domain_error& e) + catch (json::parse_error& e) { - std::cout << "domain_error: " << e.what() << '\n'; + std::cout << e.what() << '\n'; } // error: JSON pointer uses escape symbol ~ not followed by 0 or 1 @@ -29,9 +29,9 @@ int main() { json::json_pointer p10("/foo/~"); } - catch (std::domain_error& e) + catch (json::parse_error& e) { - std::cout << "domain_error: " << e.what() << '\n'; + std::cout << e.what() << '\n'; } // error: JSON pointer uses escape symbol ~ not followed by 0 or 1 @@ -39,8 +39,8 @@ int main() { json::json_pointer p11("/foo/~3"); } - catch (std::domain_error& e) + catch (json::parse_error& e) { - std::cout << "domain_error: " << e.what() << '\n'; + std::cout << e.what() << '\n'; } } diff --git a/doc/examples/json_pointer.link b/doc/examples/json_pointer.link index 6602f0cf4..78881dd96 100644 --- a/doc/examples/json_pointer.link +++ b/doc/examples/json_pointer.link @@ -1 +1 @@ -online \ No newline at end of file +online \ No newline at end of file diff --git a/doc/examples/json_pointer.output b/doc/examples/json_pointer.output index b81c8a201..33e2cc683 100644 --- a/doc/examples/json_pointer.output +++ b/doc/examples/json_pointer.output @@ -1,3 +1,3 @@ -domain_error: JSON pointer must be empty or begin with '/' -domain_error: escape error: '~' must be followed with '0' or '1' -domain_error: escape error: '~' must be followed with '0' or '1' +[json.exception.parse_error.107] parse error at 1: JSON pointer must be empty or begin with '/' - was: 'foo' +[json.exception.parse_error.108] parse error: escape character '~' must be followed with '0' or '1' +[json.exception.parse_error.108] parse error: escape character '~' must be followed with '0' or '1' diff --git a/doc/examples/json_pointer.test b/doc/examples/json_pointer.test new file mode 100644 index 000000000..33e2cc683 --- /dev/null +++ b/doc/examples/json_pointer.test @@ -0,0 +1,3 @@ +[json.exception.parse_error.107] parse error at 1: JSON pointer must be empty or begin with '/' - was: 'foo' +[json.exception.parse_error.108] parse error: escape character '~' must be followed with '0' or '1' +[json.exception.parse_error.108] parse error: escape character '~' must be followed with '0' or '1' diff --git a/src/json.hpp b/src/json.hpp index f1462db89..4b2af7326 100644 --- a/src/json.hpp +++ b/src/json.hpp @@ -301,7 +301,8 @@ Exceptions have ids 5xx. name / id | example massage | description ------------------------------ | --------------- | ------------------------- -json.exception.[other_error](@ref other_error).501 | "unsuccessful" | A JSON Patch operation 'test' failed. +json.exception.[other_error](@ref other_error).501 | "unsuccessful: {"op":"test","path":"/baz", + "value":"bar"}" | A JSON Patch operation 'test' failed. @since version 3.0.0 */ @@ -3652,7 +3653,7 @@ class basic_json @return copy of the JSON value, converted to type @a ValueType - @throw std::domain_error in case passed type @a ValueType is incompatible + @throw type_error.302 in case passed type @a ValueType is incompatible to JSON, thrown by @ref get() const @complexity Linear in the size of the JSON value. @@ -4088,7 +4089,7 @@ class basic_json @return const reference to the element at key @a key - @throw std::domain_error if JSON is not an object; example: `"cannot use + @throw type_error.305 if JSON is not an object; example: `"cannot use operator[] with null"` @complexity Logarithmic in the size of the container. @@ -4365,7 +4366,7 @@ class basic_json assertions**). @post The JSON value remains unchanged. - @throw std::out_of_range when called on `null` value + @throw invalid_iterator.214 when called on `null` value @liveexample{The following code shows an example for `front()`.,front} @@ -4408,7 +4409,7 @@ class basic_json assertions**). @post The JSON value remains unchanged. - @throw std::out_of_range when called on `null` value. + @throw invalid_iterator.214 when called on `null` value. @liveexample{The following code shows an example for `back()`.,back} @@ -4698,7 +4699,7 @@ class basic_json @throw type_error.307 when called on a type other than JSON object; example: `"cannot use erase() with null"` - @throw std::out_of_range when `idx >= size()`; example: `"array index 17 + @throw out_of_range.401 when `idx >= size()`; example: `"array index 17 is out of range"` @complexity Linear in distance between @a idx and the end of the container. @@ -7032,6 +7033,8 @@ class basic_json @throw parse_error.101 if a parse error occurs; example: `""unexpected end of input; expected string literal""` + @throw parse_error.102 if to_unicode fails or surrogate error + @throw parse_error.103 if to_unicode fails @complexity Linear in the length of the input. The parser is a predictive LL(1) parser. The complexity can be higher if the parser callback function @@ -7063,6 +7066,10 @@ class basic_json @return result of the deserialization + @throw parse_error.101 in case of an unexpected token + @throw parse_error.102 if to_unicode fails or surrogate error + @throw parse_error.103 if to_unicode fails + @complexity Linear in the length of the input. The parser is a predictive LL(1) parser. The complexity can be higher if the parser callback function @a cb has a super-linear complexity. @@ -7099,6 +7106,11 @@ class basic_json @return result of the deserialization + @throw parse_error.101 in case of an unexpected token + @throw parse_error.102 if to_unicode fails or surrogate error + @throw parse_error.103 if to_unicode fails + @throw parse_error.111 if input stream is in a bad state + @complexity Linear in the length of the input. The parser is a predictive LL(1) parser. The complexity can be higher if the parser callback function @a cb has a super-linear complexity. @@ -7158,6 +7170,10 @@ class basic_json @return result of the deserialization + @throw parse_error.101 in case of an unexpected token + @throw parse_error.102 if to_unicode fails or surrogate error + @throw parse_error.103 if to_unicode fails + @complexity Linear in the length of the input. The parser is a predictive LL(1) parser. The complexity can be higher if the parser callback function @a cb has a super-linear complexity. @@ -7228,6 +7244,10 @@ class basic_json @return result of the deserialization + @throw parse_error.101 in case of an unexpected token + @throw parse_error.102 if to_unicode fails or surrogate error + @throw parse_error.103 if to_unicode fails + @complexity Linear in the length of the input. The parser is a predictive LL(1) parser. The complexity can be higher if the parser callback function @a cb has a super-linear complexity. @@ -7260,7 +7280,10 @@ class basic_json @param[in,out] i input stream to read a serialized JSON value from @param[in,out] j JSON value to write the deserialized input to - @throw std::invalid_argument in case of parse errors + @throw parse_error.101 in case of an unexpected token + @throw parse_error.102 if to_unicode fails or surrogate error + @throw parse_error.103 if to_unicode fails + @throw parse_error.111 if input stream is in a bad state @complexity Linear in the length of the input. The parser is a predictive LL(1) parser. @@ -7963,9 +7986,9 @@ class basic_json @return deserialized JSON value - @throw std::invalid_argument if unsupported features from MessagePack were + @throw parse_error.110 if the given vector ends prematurely + @throw parse_error.112 if unsupported features from MessagePack were used in the given vector @a v or if the input is not valid MessagePack - @throw std::out_of_range if the given vector ends prematurely @sa https://github.com/msgpack/msgpack/blob/master/spec.md */ @@ -8205,9 +8228,9 @@ class basic_json @return deserialized JSON value - @throw std::invalid_argument if unsupported features from CBOR were used in - the given vector @a v or if the input is not valid CBOR - @throw std::out_of_range if the given vector ends prematurely + @throw parse_error.110 if the given vector ends prematurely + @throw parse_error.112 if unsupported features from CBOR were + used in the given vector @a v or if the input is not valid CBOR @sa https://tools.ietf.org/html/rfc7049 */ @@ -8729,9 +8752,9 @@ class basic_json @param[in] start_index the index to start reading from @a v (0 by default) @return deserialized JSON value - @throw std::invalid_argument if unsupported features from MessagePack were + @throw parse_error.110 if the given vector ends prematurely + @throw parse_error.112 if unsupported features from MessagePack were used in the given vector @a v or if the input is not valid MessagePack - @throw std::out_of_range if the given vector ends prematurely @complexity Linear in the size of the byte vector @a v. @@ -8792,9 +8815,9 @@ class basic_json @param[in] start_index the index to start reading from @a v (0 by default) @return deserialized JSON value - @throw std::invalid_argument if unsupported features from CBOR were used in - the given vector @a v or if the input is not valid MessagePack - @throw std::out_of_range if the given vector ends prematurely + @throw parse_error.110 if the given vector ends prematurely + @throw parse_error.112 if unsupported features from CBOR were + used in the given vector @a v or if the input is not valid CBOR @complexity Linear in the size of the byte vector @a v. @@ -9908,7 +9931,10 @@ class basic_json m_limit = m_content + len; } - /// a lexer from an input stream + /*! + @brief a lexer from an input stream + @throw parse_error.111 if input stream is in a bad state + */ explicit lexer(std::istream& s) : m_stream(&s), m_line_buffer() { @@ -11288,7 +11314,7 @@ basic_json_parser_74: @return string value of current token without opening and closing quotes - @throw parse_error.102 if to_unicode fails + @throw parse_error.102 if to_unicode fails or surrogate error @throw parse_error.103 if to_unicode fails */ string_t get_string() const @@ -11685,7 +11711,10 @@ basic_json_parser_74: m_lexer(reinterpret_cast(buff), std::strlen(buff)) {} - /// a parser reading from an input stream + /*! + @brief a parser reading from an input stream + @throw parse_error.111 if input stream is in a bad state + */ parser(std::istream& is, const parser_callback_t cb = nullptr) : callback(cb), m_lexer(is) {} @@ -11701,7 +11730,12 @@ basic_json_parser_74: static_cast(std::distance(first, last))) {} - /// public parser interface + /*! + @brief public parser interface + @throw parse_error.101 in case of an unexpected token + @throw parse_error.102 if to_unicode fails or surrogate error + @throw parse_error.103 if to_unicode fails + */ basic_json parse() { // read first token @@ -11718,7 +11752,12 @@ basic_json_parser_74: } private: - /// the actual parser + /*! + @brief the actual parser + @throw parse_error.101 in case of an unexpected token + @throw parse_error.102 if to_unicode fails or surrogate error + @throw parse_error.103 if to_unicode fails + */ basic_json parse_internal(bool keep) { auto result = basic_json(value_t::discarded); @@ -11921,6 +11960,9 @@ basic_json_parser_74: return last_token; } + /*! + @throw parse_error.101 if expected token did not occur + */ void expect(typename lexer::token_type t) const { if (t != last_token) @@ -11934,6 +11976,9 @@ basic_json_parser_74: } } + /*! + @throw parse_error.101 if unexpected token occurred + */ void unexpect(typename lexer::token_type t) const { if (t == last_token) @@ -11985,12 +12030,12 @@ basic_json_parser_74: empty string is assumed which references the whole JSON value - @throw parse_error.107 if reference token is nonempty and does not - begin with a slash (`/`); example: `"JSON pointer must be empty or - begin with / - was: 'foo'"` - @throw parse_error.108 if a tilde (`~`) is not followed by `0` - (representing `~`) or `1` (representing `/`); example: `"escape - character '~' must be followed with '0' or '1'"` + @throw parse_error.107 if the given JSON pointer @a s is nonempty and + does not begin with a slash (`/`); see example below + + @throw parse_error.108 if a tilde (`~`) in the given JSON pointer @a s + is not followed by `0` (representing `~`) or `1` (representing `/`); + see example below @liveexample{The example shows the construction several valid JSON pointers as well as the exceptional behavior.,json_pointer} @@ -12033,7 +12078,10 @@ basic_json_parser_74: } private: - /// remove and return last reference pointer + /*! + @brief remove and return last reference pointer + @throw out_of_range.405 if JSON pointer has no parent + */ std::string pop_back() { if (is_root()) @@ -12068,6 +12116,9 @@ basic_json_parser_74: @brief create and return a reference to the pointed to value @complexity Linear in the number of reference tokens. + + @throw parse_error.109 if array index is not a number + @throw type_error.313 if value cannot be unflattened */ reference get_and_create(reference j) const { @@ -12147,9 +12198,9 @@ basic_json_parser_74: @complexity Linear in the length of the JSON pointer. - @throw out_of_range.404 if the JSON pointer can not be resolved - @throw parse_error.106 if an array index begins with '0' - @throw std::invalid_argument if an array index was not a number + @throw parse_error.106 if an array index begins with '0' + @throw parse_error.109 if an array index was not a number + @throw out_of_range.404 if the JSON pointer can not be resolved */ reference get_unchecked(pointer ptr) const { @@ -12225,6 +12276,12 @@ basic_json_parser_74: return *ptr; } + /*! + @throw parse_error.106 if an array index begins with '0' + @throw parse_error.109 if an array index was not a number + @throw out_of_range.402 if the array index '-' is used + @throw out_of_range.404 if the JSON pointer can not be resolved + */ reference get_checked(pointer ptr) const { for (const auto& reference_token : reference_tokens) @@ -12283,6 +12340,11 @@ basic_json_parser_74: @return const reference to the JSON value pointed to by the JSON pointer + + @throw parse_error.106 if an array index begins with '0' + @throw parse_error.109 if an array index was not a number + @throw out_of_range.402 if the array index '-' is used + @throw out_of_range.404 if the JSON pointer can not be resolved */ const_reference get_unchecked(const_pointer ptr) const { @@ -12335,6 +12397,12 @@ basic_json_parser_74: return *ptr; } + /*! + @throw parse_error.106 if an array index begins with '0' + @throw parse_error.109 if an array index was not a number + @throw out_of_range.402 if the array index '-' is used + @throw out_of_range.404 if the JSON pointer can not be resolved + */ const_reference get_checked(const_pointer ptr) const { for (const auto& reference_token : reference_tokens) @@ -12386,7 +12454,15 @@ basic_json_parser_74: return *ptr; } - /// split the string input to reference tokens + /*! + @brief split the string input to reference tokens + + @note This function is only called by the json_pointer constructor. + All exceptions below are documented there. + + @throw parse_error.107 if the pointer is not empty or begins with '/' + @throw parse_error.108 if character '~' is not followed by '0' or '1' + */ static std::vector split(const std::string& reference_string) { std::vector result; @@ -12447,7 +12523,6 @@ basic_json_parser_74: return result; } - private: /*! @brief replace all occurrences of a substring by another string @@ -12456,7 +12531,8 @@ basic_json_parser_74: @param[in] f the substring to replace with @a t @param[in] t the string to replace @a f - @pre The search string @a f must not be empty. + @pre The search string @a f must not be empty. **This precondition is + enforced with an assertion.** @since version 2.0.0 */ @@ -12556,6 +12632,11 @@ basic_json_parser_74: @param[in] value flattened JSON @return unflattened JSON + + @throw parse_error.109 if array index is not a number + @throw type_error.314 if value is not an object + @throw type_error.315 if object values are not primitive + @throw type_error.313 if value cannot be unflattened */ static basic_json unflatten(const basic_json& value) { @@ -12585,7 +12666,6 @@ basic_json_parser_74: return result; } - private: friend bool operator==(json_pointer const& lhs, json_pointer const& rhs) noexcept { @@ -12634,9 +12714,9 @@ basic_json_parser_74: @complexity Constant. - @throw std::out_of_range if the JSON pointer can not be resolved - @throw std::domain_error if an array index begins with '0' - @throw std::invalid_argument if an array index was not a number + @throw parse_error.106 if an array index begins with '0' + @throw parse_error.109 if an array index was not a number + @throw out_of_range.404 if the JSON pointer can not be resolved @liveexample{The behavior is shown in the example.,operatorjson_pointer} @@ -12661,9 +12741,10 @@ basic_json_parser_74: @complexity Constant. - @throw std::out_of_range if the JSON pointer can not be resolved - @throw std::domain_error if an array index begins with '0' - @throw std::invalid_argument if an array index was not a number + @throw parse_error.106 if an array index begins with '0' + @throw parse_error.109 if an array index was not a number + @throw out_of_range.402 if the array index '-' is used + @throw out_of_range.404 if the JSON pointer can not be resolved @liveexample{The behavior is shown in the example.,operatorjson_pointer_const} @@ -12686,9 +12767,10 @@ basic_json_parser_74: @complexity Constant. - @throw std::out_of_range if the JSON pointer can not be resolved - @throw std::domain_error if an array index begins with '0' - @throw std::invalid_argument if an array index was not a number + @throw parse_error.106 if an array index begins with '0' + @throw parse_error.109 if an array index was not a number + @throw out_of_range.402 if the array index '-' is used + @throw out_of_range.404 if the JSON pointer can not be resolved @liveexample{The behavior is shown in the example.,at_json_pointer} @@ -12711,9 +12793,10 @@ basic_json_parser_74: @complexity Constant. - @throw std::out_of_range if the JSON pointer can not be resolved - @throw std::domain_error if an array index begins with '0' - @throw std::invalid_argument if an array index was not a number + @throw parse_error.106 if an array index begins with '0' + @throw parse_error.109 if an array index was not a number + @throw out_of_range.402 if the array index '-' is used + @throw out_of_range.404 if the JSON pointer can not be resolved @liveexample{The behavior is shown in the example.,at_json_pointer_const} @@ -12773,6 +12856,9 @@ basic_json_parser_74: @complexity Linear in the size the JSON value. + @throw type_error.314 if value is not an object + @throw type_error.315 if object values are not primitve + @liveexample{The following code shows how a flattened JSON object is unflattened into the original nested JSON object.,unflatten} @@ -12810,13 +12896,22 @@ basic_json_parser_74: any case, the original value is not changed: the patch is applied to a copy of the value. + @throw parse_error.104 if the JSON patch does not consist of an array of + objects + + @throw parse_error.105 if the JSON patch is malformed (e.g., mandatory + attributes are missing); example: `"operation add must have member path"` + + @throw out_of_range.401 if an array index is out of range. + @throw out_of_range.403 if a JSON pointer inside the patch could not be resolved successfully in the current JSON value; example: `"key baz not found"` - @throw invalid_argument if the JSON patch is malformed (e.g., mandatory - attributes are missing); example: `"operation add must have member path"` - @throw parse_error.104 if the JSON patch does not consist of an array of - objects + + @throw out_of_range.405 if JSON pointer has no parent ("add", "remove", + "move") + + @throw other_error.501 if "test" operation was unsuccessful @complexity Linear in the size of the JSON value and the length of the JSON patch. As usually only a fraction of the JSON value is affected by diff --git a/src/json.hpp.re2c b/src/json.hpp.re2c index 3044cf6b4..d2f6346f8 100644 --- a/src/json.hpp.re2c +++ b/src/json.hpp.re2c @@ -3653,7 +3653,7 @@ class basic_json @return copy of the JSON value, converted to type @a ValueType - @throw std::domain_error in case passed type @a ValueType is incompatible + @throw type_error.302 in case passed type @a ValueType is incompatible to JSON, thrown by @ref get() const @complexity Linear in the size of the JSON value. @@ -4089,7 +4089,7 @@ class basic_json @return const reference to the element at key @a key - @throw std::domain_error if JSON is not an object; example: `"cannot use + @throw type_error.305 if JSON is not an object; example: `"cannot use operator[] with null"` @complexity Logarithmic in the size of the container. @@ -4366,7 +4366,7 @@ class basic_json assertions**). @post The JSON value remains unchanged. - @throw std::out_of_range when called on `null` value + @throw invalid_iterator.214 when called on `null` value @liveexample{The following code shows an example for `front()`.,front} @@ -4409,7 +4409,7 @@ class basic_json assertions**). @post The JSON value remains unchanged. - @throw std::out_of_range when called on `null` value. + @throw invalid_iterator.214 when called on `null` value. @liveexample{The following code shows an example for `back()`.,back} @@ -4699,7 +4699,7 @@ class basic_json @throw type_error.307 when called on a type other than JSON object; example: `"cannot use erase() with null"` - @throw std::out_of_range when `idx >= size()`; example: `"array index 17 + @throw out_of_range.401 when `idx >= size()`; example: `"array index 17 is out of range"` @complexity Linear in distance between @a idx and the end of the container. @@ -7033,6 +7033,8 @@ class basic_json @throw parse_error.101 if a parse error occurs; example: `""unexpected end of input; expected string literal""` + @throw parse_error.102 if to_unicode fails or surrogate error + @throw parse_error.103 if to_unicode fails @complexity Linear in the length of the input. The parser is a predictive LL(1) parser. The complexity can be higher if the parser callback function @@ -7064,6 +7066,10 @@ class basic_json @return result of the deserialization + @throw parse_error.101 in case of an unexpected token + @throw parse_error.102 if to_unicode fails or surrogate error + @throw parse_error.103 if to_unicode fails + @complexity Linear in the length of the input. The parser is a predictive LL(1) parser. The complexity can be higher if the parser callback function @a cb has a super-linear complexity. @@ -7100,6 +7106,11 @@ class basic_json @return result of the deserialization + @throw parse_error.101 in case of an unexpected token + @throw parse_error.102 if to_unicode fails or surrogate error + @throw parse_error.103 if to_unicode fails + @throw parse_error.111 if input stream is in a bad state + @complexity Linear in the length of the input. The parser is a predictive LL(1) parser. The complexity can be higher if the parser callback function @a cb has a super-linear complexity. @@ -7159,6 +7170,10 @@ class basic_json @return result of the deserialization + @throw parse_error.101 in case of an unexpected token + @throw parse_error.102 if to_unicode fails or surrogate error + @throw parse_error.103 if to_unicode fails + @complexity Linear in the length of the input. The parser is a predictive LL(1) parser. The complexity can be higher if the parser callback function @a cb has a super-linear complexity. @@ -7229,6 +7244,10 @@ class basic_json @return result of the deserialization + @throw parse_error.101 in case of an unexpected token + @throw parse_error.102 if to_unicode fails or surrogate error + @throw parse_error.103 if to_unicode fails + @complexity Linear in the length of the input. The parser is a predictive LL(1) parser. The complexity can be higher if the parser callback function @a cb has a super-linear complexity. @@ -7261,7 +7280,10 @@ class basic_json @param[in,out] i input stream to read a serialized JSON value from @param[in,out] j JSON value to write the deserialized input to - @throw std::invalid_argument in case of parse errors + @throw parse_error.101 in case of an unexpected token + @throw parse_error.102 if to_unicode fails or surrogate error + @throw parse_error.103 if to_unicode fails + @throw parse_error.111 if input stream is in a bad state @complexity Linear in the length of the input. The parser is a predictive LL(1) parser. @@ -7964,9 +7986,9 @@ class basic_json @return deserialized JSON value - @throw std::invalid_argument if unsupported features from MessagePack were + @throw parse_error.110 if the given vector ends prematurely + @throw parse_error.112 if unsupported features from MessagePack were used in the given vector @a v or if the input is not valid MessagePack - @throw std::out_of_range if the given vector ends prematurely @sa https://github.com/msgpack/msgpack/blob/master/spec.md */ @@ -8206,9 +8228,9 @@ class basic_json @return deserialized JSON value - @throw std::invalid_argument if unsupported features from CBOR were used in - the given vector @a v or if the input is not valid CBOR - @throw std::out_of_range if the given vector ends prematurely + @throw parse_error.110 if the given vector ends prematurely + @throw parse_error.112 if unsupported features from CBOR were + used in the given vector @a v or if the input is not valid CBOR @sa https://tools.ietf.org/html/rfc7049 */ @@ -8730,9 +8752,9 @@ class basic_json @param[in] start_index the index to start reading from @a v (0 by default) @return deserialized JSON value - @throw std::invalid_argument if unsupported features from MessagePack were + @throw parse_error.110 if the given vector ends prematurely + @throw parse_error.112 if unsupported features from MessagePack were used in the given vector @a v or if the input is not valid MessagePack - @throw std::out_of_range if the given vector ends prematurely @complexity Linear in the size of the byte vector @a v. @@ -8793,9 +8815,9 @@ class basic_json @param[in] start_index the index to start reading from @a v (0 by default) @return deserialized JSON value - @throw std::invalid_argument if unsupported features from CBOR were used in - the given vector @a v or if the input is not valid MessagePack - @throw std::out_of_range if the given vector ends prematurely + @throw parse_error.110 if the given vector ends prematurely + @throw parse_error.112 if unsupported features from CBOR were + used in the given vector @a v or if the input is not valid CBOR @complexity Linear in the size of the byte vector @a v. @@ -9909,7 +9931,10 @@ class basic_json m_limit = m_content + len; } - /// a lexer from an input stream + /*! + @brief a lexer from an input stream + @throw parse_error.111 if input stream is in a bad state + */ explicit lexer(std::istream& s) : m_stream(&s), m_line_buffer() { @@ -10322,7 +10347,7 @@ class basic_json @return string value of current token without opening and closing quotes - @throw parse_error.102 if to_unicode fails + @throw parse_error.102 if to_unicode fails or surrogate error @throw parse_error.103 if to_unicode fails */ string_t get_string() const @@ -10719,7 +10744,10 @@ class basic_json m_lexer(reinterpret_cast(buff), std::strlen(buff)) {} - /// a parser reading from an input stream + /*! + @brief a parser reading from an input stream + @throw parse_error.111 if input stream is in a bad state + */ parser(std::istream& is, const parser_callback_t cb = nullptr) : callback(cb), m_lexer(is) {} @@ -10735,7 +10763,12 @@ class basic_json static_cast(std::distance(first, last))) {} - /// public parser interface + /*! + @brief public parser interface + @throw parse_error.101 in case of an unexpected token + @throw parse_error.102 if to_unicode fails or surrogate error + @throw parse_error.103 if to_unicode fails + */ basic_json parse() { // read first token @@ -10752,7 +10785,12 @@ class basic_json } private: - /// the actual parser + /*! + @brief the actual parser + @throw parse_error.101 in case of an unexpected token + @throw parse_error.102 if to_unicode fails or surrogate error + @throw parse_error.103 if to_unicode fails + */ basic_json parse_internal(bool keep) { auto result = basic_json(value_t::discarded); @@ -10955,6 +10993,9 @@ class basic_json return last_token; } + /*! + @throw parse_error.101 if expected token did not occur + */ void expect(typename lexer::token_type t) const { if (t != last_token) @@ -10968,6 +11009,9 @@ class basic_json } } + /*! + @throw parse_error.101 if unexpected token occurred + */ void unexpect(typename lexer::token_type t) const { if (t == last_token) @@ -11019,12 +11063,12 @@ class basic_json empty string is assumed which references the whole JSON value - @throw parse_error.107 if reference token is nonempty and does not - begin with a slash (`/`); example: `"JSON pointer must be empty or - begin with / - was: 'foo'"` - @throw parse_error.108 if a tilde (`~`) is not followed by `0` - (representing `~`) or `1` (representing `/`); example: `"escape - character '~' must be followed with '0' or '1'"` + @throw parse_error.107 if the given JSON pointer @a s is nonempty and + does not begin with a slash (`/`); see example below + + @throw parse_error.108 if a tilde (`~`) in the given JSON pointer @a s + is not followed by `0` (representing `~`) or `1` (representing `/`); + see example below @liveexample{The example shows the construction several valid JSON pointers as well as the exceptional behavior.,json_pointer} @@ -11067,7 +11111,10 @@ class basic_json } private: - /// remove and return last reference pointer + /*! + @brief remove and return last reference pointer + @throw out_of_range.405 if JSON pointer has no parent + */ std::string pop_back() { if (is_root()) @@ -11102,6 +11149,9 @@ class basic_json @brief create and return a reference to the pointed to value @complexity Linear in the number of reference tokens. + + @throw parse_error.109 if array index is not a number + @throw type_error.313 if value cannot be unflattened */ reference get_and_create(reference j) const { @@ -11181,9 +11231,9 @@ class basic_json @complexity Linear in the length of the JSON pointer. - @throw out_of_range.404 if the JSON pointer can not be resolved - @throw parse_error.106 if an array index begins with '0' - @throw std::invalid_argument if an array index was not a number + @throw parse_error.106 if an array index begins with '0' + @throw parse_error.109 if an array index was not a number + @throw out_of_range.404 if the JSON pointer can not be resolved */ reference get_unchecked(pointer ptr) const { @@ -11259,6 +11309,12 @@ class basic_json return *ptr; } + /*! + @throw parse_error.106 if an array index begins with '0' + @throw parse_error.109 if an array index was not a number + @throw out_of_range.402 if the array index '-' is used + @throw out_of_range.404 if the JSON pointer can not be resolved + */ reference get_checked(pointer ptr) const { for (const auto& reference_token : reference_tokens) @@ -11317,6 +11373,11 @@ class basic_json @return const reference to the JSON value pointed to by the JSON pointer + + @throw parse_error.106 if an array index begins with '0' + @throw parse_error.109 if an array index was not a number + @throw out_of_range.402 if the array index '-' is used + @throw out_of_range.404 if the JSON pointer can not be resolved */ const_reference get_unchecked(const_pointer ptr) const { @@ -11369,6 +11430,12 @@ class basic_json return *ptr; } + /*! + @throw parse_error.106 if an array index begins with '0' + @throw parse_error.109 if an array index was not a number + @throw out_of_range.402 if the array index '-' is used + @throw out_of_range.404 if the JSON pointer can not be resolved + */ const_reference get_checked(const_pointer ptr) const { for (const auto& reference_token : reference_tokens) @@ -11420,7 +11487,15 @@ class basic_json return *ptr; } - /// split the string input to reference tokens + /*! + @brief split the string input to reference tokens + + @note This function is only called by the json_pointer constructor. + All exceptions below are documented there. + + @throw parse_error.107 if the pointer is not empty or begins with '/' + @throw parse_error.108 if character '~' is not followed by '0' or '1' + */ static std::vector split(const std::string& reference_string) { std::vector result; @@ -11481,7 +11556,6 @@ class basic_json return result; } - private: /*! @brief replace all occurrences of a substring by another string @@ -11490,7 +11564,8 @@ class basic_json @param[in] f the substring to replace with @a t @param[in] t the string to replace @a f - @pre The search string @a f must not be empty. + @pre The search string @a f must not be empty. **This precondition is + enforced with an assertion.** @since version 2.0.0 */ @@ -11590,6 +11665,11 @@ class basic_json @param[in] value flattened JSON @return unflattened JSON + + @throw parse_error.109 if array index is not a number + @throw type_error.314 if value is not an object + @throw type_error.315 if object values are not primitive + @throw type_error.313 if value cannot be unflattened */ static basic_json unflatten(const basic_json& value) { @@ -11619,7 +11699,6 @@ class basic_json return result; } - private: friend bool operator==(json_pointer const& lhs, json_pointer const& rhs) noexcept { @@ -11668,9 +11747,9 @@ class basic_json @complexity Constant. - @throw std::out_of_range if the JSON pointer can not be resolved - @throw std::domain_error if an array index begins with '0' - @throw std::invalid_argument if an array index was not a number + @throw parse_error.106 if an array index begins with '0' + @throw parse_error.109 if an array index was not a number + @throw out_of_range.404 if the JSON pointer can not be resolved @liveexample{The behavior is shown in the example.,operatorjson_pointer} @@ -11695,9 +11774,10 @@ class basic_json @complexity Constant. - @throw std::out_of_range if the JSON pointer can not be resolved - @throw std::domain_error if an array index begins with '0' - @throw std::invalid_argument if an array index was not a number + @throw parse_error.106 if an array index begins with '0' + @throw parse_error.109 if an array index was not a number + @throw out_of_range.402 if the array index '-' is used + @throw out_of_range.404 if the JSON pointer can not be resolved @liveexample{The behavior is shown in the example.,operatorjson_pointer_const} @@ -11720,9 +11800,10 @@ class basic_json @complexity Constant. - @throw std::out_of_range if the JSON pointer can not be resolved - @throw std::domain_error if an array index begins with '0' - @throw std::invalid_argument if an array index was not a number + @throw parse_error.106 if an array index begins with '0' + @throw parse_error.109 if an array index was not a number + @throw out_of_range.402 if the array index '-' is used + @throw out_of_range.404 if the JSON pointer can not be resolved @liveexample{The behavior is shown in the example.,at_json_pointer} @@ -11745,9 +11826,10 @@ class basic_json @complexity Constant. - @throw std::out_of_range if the JSON pointer can not be resolved - @throw std::domain_error if an array index begins with '0' - @throw std::invalid_argument if an array index was not a number + @throw parse_error.106 if an array index begins with '0' + @throw parse_error.109 if an array index was not a number + @throw out_of_range.402 if the array index '-' is used + @throw out_of_range.404 if the JSON pointer can not be resolved @liveexample{The behavior is shown in the example.,at_json_pointer_const} @@ -11807,6 +11889,9 @@ class basic_json @complexity Linear in the size the JSON value. + @throw type_error.314 if value is not an object + @throw type_error.315 if object values are not primitve + @liveexample{The following code shows how a flattened JSON object is unflattened into the original nested JSON object.,unflatten} @@ -11844,13 +11929,22 @@ class basic_json any case, the original value is not changed: the patch is applied to a copy of the value. + @throw parse_error.104 if the JSON patch does not consist of an array of + objects + + @throw parse_error.105 if the JSON patch is malformed (e.g., mandatory + attributes are missing); example: `"operation add must have member path"` + + @throw out_of_range.401 if an array index is out of range. + @throw out_of_range.403 if a JSON pointer inside the patch could not be resolved successfully in the current JSON value; example: `"key baz not found"` - @throw invalid_argument if the JSON patch is malformed (e.g., mandatory - attributes are missing); example: `"operation add must have member path"` - @throw parse_error.104 if the JSON patch does not consist of an array of - objects + + @throw out_of_range.405 if JSON pointer has no parent ("add", "remove", + "move") + + @throw other_error.501 if "test" operation was unsuccessful @complexity Linear in the size of the JSON value and the length of the JSON patch. As usually only a fraction of the JSON value is affected by From 1ab580d6e99aab3b3c8162354a6faf340db5ee96 Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Wed, 8 Mar 2017 23:12:13 +0100 Subject: [PATCH 33/52] :memo: more documentation for the new exceptions --- doc/Makefile | 2 + doc/examples/at__size_type_const.cpp | 4 +- doc/examples/at__size_type_const.link | 2 +- doc/examples/at__size_type_const.output | 2 +- doc/examples/basic_json__InputIt_InputIt.cpp | 10 + doc/examples/basic_json__InputIt_InputIt.link | 2 +- .../basic_json__InputIt_InputIt.output | 1 + doc/examples/object.cpp | 12 +- doc/examples/object.link | 2 +- doc/examples/object.output | 1 + doc/examples/operator__ValueType.cpp | 10 + doc/examples/operator__ValueType.link | 2 +- doc/examples/operator__ValueType.output | 1 + src/json.hpp | 224 +++++++++--------- src/json.hpp.re2c | 224 +++++++++--------- 15 files changed, 269 insertions(+), 230 deletions(-) diff --git a/doc/Makefile b/doc/Makefile index cd23a9f77..c900bdea3 100644 --- a/doc/Makefile +++ b/doc/Makefile @@ -59,6 +59,8 @@ doxygen: create_output create_links $(SED) -i 's@< ObjectType, ArrayType, StringType, BooleanType, NumberIntegerType, NumberUnsignedType, NumberFloatType, AllocatorType, JSONSerializer >@@g' html/*.html $(SED) -i 's@< ObjectType, ArrayType, StringType, BooleanType, NumberIntegerType, NumberUnsignedType, NumberFloatType, AllocatorType JSONSerializer >@@g' html/*.html $(SED) -i 's@template<template< typename U, typename V, typename... Args > class ObjectType = std::map, template< typename U, typename... Args > class ArrayType = std::vector, class StringType = std::string, class BooleanType = bool, class NumberIntegerType = std::int64_t, class NumberUnsignedType = std::uint64_t, class NumberFloatType = double, template< typename U > class AllocatorType = std::allocator, template< typename T, typename SFINAE=void > class JSONSerializer = adl_serializer>@@g' html/*.html + $(SED) -i 's@< ObjectType, ArrayType, StringType, BooleanType, NumberIntegerType, NumberUnsignedType, NumberFloatType, AllocatorType, JSONSerializer >@@g' html/*.html + $(SED) -i 's@< ObjectType, ArrayType, StringType, BooleanType, NumberIntegerType, NumberUnsignedType, NumberFloatType, AllocatorType, JSONSerializer >@@g' html/*.html upload: clean doxygen check_output cd html ; ../scripts/git-update-ghpages nlohmann/json diff --git a/doc/examples/at__size_type_const.cpp b/doc/examples/at__size_type_const.cpp index c29db4fb2..88d28be6f 100644 --- a/doc/examples/at__size_type_const.cpp +++ b/doc/examples/at__size_type_const.cpp @@ -15,8 +15,8 @@ int main() { std::cout << array.at(5) << '\n'; } - catch (json::out_of_range) + catch (const json::out_of_range& e) { - std::cout << "out of range" << '\n'; + std::cout << e.what() << '\n'; } } diff --git a/doc/examples/at__size_type_const.link b/doc/examples/at__size_type_const.link index c5f66fe0a..c703c5d97 100644 --- a/doc/examples/at__size_type_const.link +++ b/doc/examples/at__size_type_const.link @@ -1 +1 @@ -online \ No newline at end of file +online \ No newline at end of file diff --git a/doc/examples/at__size_type_const.output b/doc/examples/at__size_type_const.output index d0b7a66a8..e52b6cc0b 100644 --- a/doc/examples/at__size_type_const.output +++ b/doc/examples/at__size_type_const.output @@ -1,2 +1,2 @@ "third" -out of range +[json.exception.out_of_range.401] array index 5 is out of range diff --git a/doc/examples/basic_json__InputIt_InputIt.cpp b/doc/examples/basic_json__InputIt_InputIt.cpp index 86a0faf8c..ce07e07bb 100644 --- a/doc/examples/basic_json__InputIt_InputIt.cpp +++ b/doc/examples/basic_json__InputIt_InputIt.cpp @@ -18,4 +18,14 @@ int main() std::cout << j_array_range << '\n'; std::cout << j_number_range << '\n'; std::cout << j_object_range << '\n'; + + // example for an exception + try + { + json j_invalid(j_number.begin() + 1, j_number.end()); + } + catch (json::invalid_iterator& e) + { + std::cout << e.what() << '\n'; + } } diff --git a/doc/examples/basic_json__InputIt_InputIt.link b/doc/examples/basic_json__InputIt_InputIt.link index ae46528cc..d360496a5 100644 --- a/doc/examples/basic_json__InputIt_InputIt.link +++ b/doc/examples/basic_json__InputIt_InputIt.link @@ -1 +1 @@ -online \ No newline at end of file +online \ No newline at end of file diff --git a/doc/examples/basic_json__InputIt_InputIt.output b/doc/examples/basic_json__InputIt_InputIt.output index 367142004..bfb017785 100644 --- a/doc/examples/basic_json__InputIt_InputIt.output +++ b/doc/examples/basic_json__InputIt_InputIt.output @@ -1,3 +1,4 @@ ["bravo","charly"] 42 {"one":"eins"} +[json.exception.invalid_iterator.204] iterators out of range diff --git a/doc/examples/object.cpp b/doc/examples/object.cpp index 54f3ca3b8..5b8ba5898 100644 --- a/doc/examples/object.cpp +++ b/doc/examples/object.cpp @@ -8,10 +8,20 @@ int main() json j_no_init_list = json::object(); json j_empty_init_list = json::object({}); json j_list_of_pairs = json::object({ {"one", 1}, {"two", 2} }); - //json j_invalid_list = json::object({ "one", 1 }); // would throw // serialize the JSON objects std::cout << j_no_init_list << '\n'; std::cout << j_empty_init_list << '\n'; std::cout << j_list_of_pairs << '\n'; + + // example for an exception + try + { + // can only create an object from a list of pairs + json j_invalid_object = json::object({{ "one", 1, 2 }}); + } + catch (json::type_error& e) + { + std::cout << e.what() << '\n'; + } } diff --git a/doc/examples/object.link b/doc/examples/object.link index fd0f424b9..d9e63e536 100644 --- a/doc/examples/object.link +++ b/doc/examples/object.link @@ -1 +1 @@ -online \ No newline at end of file +online \ No newline at end of file diff --git a/doc/examples/object.output b/doc/examples/object.output index f6c27ee8f..1a1d8140e 100644 --- a/doc/examples/object.output +++ b/doc/examples/object.output @@ -1,3 +1,4 @@ {} {} {"one":1,"two":2} +[json.exception.type_error.301] cannot create object from initializer list diff --git a/doc/examples/operator__ValueType.cpp b/doc/examples/operator__ValueType.cpp index 9307e69bb..77af700fb 100644 --- a/doc/examples/operator__ValueType.cpp +++ b/doc/examples/operator__ValueType.cpp @@ -46,4 +46,14 @@ int main() { std::cout << i.first << ": " << i.second << '\n'; } + + // example for an exception + try + { + bool v1 = json_types["string"]; + } + catch (json::type_error& e) + { + std::cout << e.what() << '\n'; + } } diff --git a/doc/examples/operator__ValueType.link b/doc/examples/operator__ValueType.link index 1428a679c..9a689f828 100644 --- a/doc/examples/operator__ValueType.link +++ b/doc/examples/operator__ValueType.link @@ -1 +1 @@ -online \ No newline at end of file +online \ No newline at end of file diff --git a/doc/examples/operator__ValueType.output b/doc/examples/operator__ValueType.output index 5cd9cd3aa..a3bd9fff4 100644 --- a/doc/examples/operator__ValueType.output +++ b/doc/examples/operator__ValueType.output @@ -9,3 +9,4 @@ number: {"floating-point":17.23,"integer":42} null: null boolean: true array: [1,2,3,4,5] +[json.exception.type_error.302] type must be boolean, but is string diff --git a/src/json.hpp b/src/json.hpp index 4b2af7326..9fb7690f3 100644 --- a/src/json.hpp +++ b/src/json.hpp @@ -162,18 +162,18 @@ Exceptions have ids 1xx. name / id | example massage | description ------------------------------ | --------------- | ------------------------- -json.exception.[parse_error](@ref parse_error).101 | "parse error at 2: unexpected end of input; expected string literal" | This error indicates a syntax error while deserializing a JSON text. The error message describes that an unexpected token (character) was encountered, and the member @ref parse_error::byte indicates the error position. -json.exception.[parse_error](@ref parse_error).102 | "parse error at 14: missing or wrong low surrogate" | JSON uses the `\uxxxx` format to describe Unicode characters. Code points above above 0xFFFF are split into two `\uxxxx` entries ("surrogate pairs"). This error indicates that the surrogate pair is incomplete or contains an invalid code point. -json.exception.[parse_error](@ref parse_error).103 | "parse error: code points above 0x10FFFF are invalid" | Unicode supports code points up to 0x10FFFF. Code points above 0x10FFFF are invalid. -json.exception.[parse_error](@ref parse_error).104 | "parse error: JSON patch must be an array of objects" | [RFC 6902](https://tools.ietf.org/html/rfc6902) requires a JSON Patch document to be a JSON document that represents an array of objects. -json.exception.[parse_error](@ref parse_error).105 | "parse error: operation must have string member 'op'" | An operation of a JSON Patch document must contain exactly one "op" member, whose value indicates the operation to perform. Its value must be one of "add", "remove", "replace", "move", "copy", or "test"; other values are errors. -json.exception.[parse_error](@ref parse_error).106 | "parse error: array index '01' must not begin with '0'" | An array index in a JSON Pointer ([RFC 6901](https://tools.ietf.org/html/rfc6901)) may be `0` or any number wihtout a leading `0`. -json.exception.[parse_error](@ref parse_error).107 | "parse error: JSON pointer must be empty or begin with '/' - was: 'foo'" | A JSON Pointer must be a Unicode string containing a sequence of zero or more reference tokens, each prefixed by a `/` character. -json.exception.[parse_error](@ref parse_error).108 | "parse error: escape character '~' must be followed with '0' or '1'" | In a JSON Pointer, only `~0` and `~1` are valid escape sequences. -json.exception.[parse_error](@ref parse_error).109 | "parse error: array index 'one' is not a number" | A JSON Pointer array index must be a number. -json.exception.[parse_error](@ref parse_error).110 | "parse error at 1: cannot read 2 bytes from vector" | When parsing CBOR or MessagePack, the byte vector ends before the complete value has been read. -json.exception.[parse_error](@ref parse_error).111 | "parse error: bad input stream" | Parsing CBOR or MessagePack from an input stream where the `badbit` or `failbit` is set. -json.exception.[parse_error](@ref parse_error).112 | "parse error at 1: error reading CBOR; last byte: 0xf8" | Not all types of CBOR or MessagePack are supported. This exception occurs if an unsupported byte was read. +json.exception.parse_error.101 | parse error at 2: unexpected end of input; expected string literal | This error indicates a syntax error while deserializing a JSON text. The error message describes that an unexpected token (character) was encountered, and the member @a byte indicates the error position. +json.exception.parse_error.102 | parse error at 14: missing or wrong low surrogate | JSON uses the `\uxxxx` format to describe Unicode characters. Code points above above 0xFFFF are split into two `\uxxxx` entries ("surrogate pairs"). This error indicates that the surrogate pair is incomplete or contains an invalid code point. +json.exception.parse_error.103 | parse error: code points above 0x10FFFF are invalid | Unicode supports code points up to 0x10FFFF. Code points above 0x10FFFF are invalid. +json.exception.parse_error.104 | parse error: JSON patch must be an array of objects | [RFC 6902](https://tools.ietf.org/html/rfc6902) requires a JSON Patch document to be a JSON document that represents an array of objects. +json.exception.parse_error.105 | parse error: operation must have string member 'op' | An operation of a JSON Patch document must contain exactly one "op" member, whose value indicates the operation to perform. Its value must be one of "add", "remove", "replace", "move", "copy", or "test"; other values are errors. +json.exception.parse_error.106 | parse error: array index '01' must not begin with '0' | An array index in a JSON Pointer ([RFC 6901](https://tools.ietf.org/html/rfc6901)) may be `0` or any number wihtout a leading `0`. +json.exception.parse_error.107 | parse error: JSON pointer must be empty or begin with '/' - was: 'foo' | A JSON Pointer must be a Unicode string containing a sequence of zero or more reference tokens, each prefixed by a `/` character. +json.exception.parse_error.108 | parse error: escape character '~' must be followed with '0' or '1' | In a JSON Pointer, only `~0` and `~1` are valid escape sequences. +json.exception.parse_error.109 | parse error: array index 'one' is not a number | A JSON Pointer array index must be a number. +json.exception.parse_error.110 | parse error at 1: cannot read 2 bytes from vector | When parsing CBOR or MessagePack, the byte vector ends before the complete value has been read. +json.exception.parse_error.111 | parse error: bad input stream | Parsing CBOR or MessagePack from an input stream where the [`badbit` or `failbit`](http://en.cppreference.com/w/cpp/io/ios_base/iostate) is set. +json.exception.parse_error.112 | parse error at 1: error reading CBOR; last byte: 0xf8 | Not all types of CBOR or MessagePack are supported. This exception occurs if an unsupported byte was read. @since version 3.0.0 */ @@ -212,22 +212,22 @@ class parse_error : public exception Exceptions have ids 2xx. -name / id | example massage | description ------------------------------- | --------------- | ------------------------- -json.exception.[invalid_iterator](@ref invalid_iterator).201 | "iterators are not compatible" | The iterators passed to constructor @ref basic_json(InputIT first, InputIT last) are not compatible, meaning they do not belong to the same container. Therefore, the range (@a first, @a last) is invalid. -json.exception.[invalid_iterator](@ref invalid_iterator).202 | "iterator does not fit current value" | In an erase or insert function, the passed iterator @a pos does not belong to the JSON value for which the function was called. It hence does not define a valid position for the deletion/insertion. -json.exception.[invalid_iterator](@ref invalid_iterator).203 | "iterators do not fit current value" | Either iterator passed to function @ref erase(IteratorType first, IteratorType last) does not belong to the JSON value from which values shall be erased. It hence does not define a valid range to delete values from. -json.exception.[invalid_iterator](@ref invalid_iterator).204 | "iterators out of range" | When an iterator range for a primitive type (number, boolean, or string) is passed to a constructor or an erase function, this range has to be exactly (@ref begin(), @ref end()), because this is the only way the single stored value is expressed. All other ranges are invalid. -json.exception.[invalid_iterator](@ref invalid_iterator).205 | "iterator out of range" | When an iterator for a primitive type (number, boolean, or string) is passed to an erase function, the iterator has to be the @ref begin() iterator, because it is the only way to address the stored value. All other iterators are invalid. -json.exception.[invalid_iterator](@ref invalid_iterator).206 | "cannot construct with iterators from null" | The iterators passed to constructor @ref basic_json(InputIT first, InputIT last) belong to a JSON null value and hence to not define a valid range. -json.exception.[invalid_iterator](@ref invalid_iterator).207 | "cannot use key() for non-object iterators" | The key() member function can only be used on iterators belonging to a JSON object, because other types do not have a concept of a key. -json.exception.[invalid_iterator](@ref invalid_iterator).208 | "cannot use operator[] for object iterators" | The operator[] to specify a concrete offset cannot be used on iterators belonging to a JSON object, because JSON objects are unordered. -json.exception.[invalid_iterator](@ref invalid_iterator).209 | "cannot use offsets with object iterators" | The offset operators (+, -, +=, -=) cannot be used on iterators belonging to a JSON object, because JSON objects are unordered. -json.exception.[invalid_iterator](@ref invalid_iterator).210 | "iterators do not fit" | The iterator range passed to the insert function are not compatible, meaning they do not belong to the same container. Therefore, the range (@a first, @a last) is invalid. -json.exception.[invalid_iterator](@ref invalid_iterator).211 | "passed iterators may not belong to container" | The iterator range passed to the insert function must not be a subrange of the container to insert to. -json.exception.[invalid_iterator](@ref invalid_iterator).212 | "cannot compare iterators of different containers" | When two iterators are compared, they must belong to the same container. -json.exception.[invalid_iterator](@ref invalid_iterator).213 | "cannot compare order of object iterators" | The order of object iterators cannot be compated, because JSON objects are unordered. -json.exception.[invalid_iterator](@ref invalid_iterator).214 | "cannot get value" | Cannot get value for iterator: Either the iterator belongs to a null value or it is an iterator to a primitive type (number, boolean, or string), but the iterator is different to @ref begin(). +name / id | example massage | description +----------------------------------- | --------------- | ------------------------- +json.exception.invalid_iterator.201 | iterators are not compatible | The iterators passed to constructor @ref basic_json(InputIT first, InputIT last) are not compatible, meaning they do not belong to the same container. Therefore, the range (@a first, @a last) is invalid. +json.exception.invalid_iterator.202 | iterator does not fit current value | In an erase or insert function, the passed iterator @a pos does not belong to the JSON value for which the function was called. It hence does not define a valid position for the deletion/insertion. +json.exception.invalid_iterator.203 | iterators do not fit current value | Either iterator passed to function @ref erase(IteratorType first, IteratorType last) does not belong to the JSON value from which values shall be erased. It hence does not define a valid range to delete values from. +json.exception.invalid_iterator.204 | iterators out of range | When an iterator range for a primitive type (number, boolean, or string) is passed to a constructor or an erase function, this range has to be exactly (@ref begin(), @ref end()), because this is the only way the single stored value is expressed. All other ranges are invalid. +json.exception.invalid_iterator.205 | iterator out of range | When an iterator for a primitive type (number, boolean, or string) is passed to an erase function, the iterator has to be the @ref begin() iterator, because it is the only way to address the stored value. All other iterators are invalid. +json.exception.invalid_iterator.206 | cannot construct with iterators from null | The iterators passed to constructor @ref basic_json(InputIT first, InputIT last) belong to a JSON null value and hence to not define a valid range. +json.exception.invalid_iterator.207 | cannot use key() for non-object iterators | The key() member function can only be used on iterators belonging to a JSON object, because other types do not have a concept of a key. +json.exception.invalid_iterator.208 | cannot use operator[] for object iterators | The operator[] to specify a concrete offset cannot be used on iterators belonging to a JSON object, because JSON objects are unordered. +json.exception.invalid_iterator.209 | cannot use offsets with object iterators | The offset operators (+, -, +=, -=) cannot be used on iterators belonging to a JSON object, because JSON objects are unordered. +json.exception.invalid_iterator.210 | iterators do not fit | The iterator range passed to the insert function are not compatible, meaning they do not belong to the same container. Therefore, the range (@a first, @a last) is invalid. +json.exception.invalid_iterator.211 | passed iterators may not belong to container | The iterator range passed to the insert function must not be a subrange of the container to insert to. +json.exception.invalid_iterator.212 | cannot compare iterators of different containers | When two iterators are compared, they must belong to the same container. +json.exception.invalid_iterator.213 | cannot compare order of object iterators | The order of object iterators cannot be compated, because JSON objects are unordered. +json.exception.invalid_iterator.214 | cannot get value | Cannot get value for iterator: Either the iterator belongs to a null value or it is an iterator to a primitive type (number, boolean, or string), but the iterator is different to @ref begin(). @since version 3.0.0 */ @@ -244,22 +244,22 @@ class invalid_iterator : public exception Exceptions have ids 3xx. -name / id | example massage | description ------------------------------- | --------------- | ------------------------- -json.exception.[type_error](@ref type_error).301 | "cannot create object from initializer list" | To create an object from an initializer list, the initializer list must consist only of a list of pairs whose first element is a string. When this constraint is violated, an array is created instead. -json.exception.[type_error](@ref type_error).302 | "type must be object, but is array" | During implicit or explicit value conversion, the JSON type must be compatible to the target type. For instance, a JSON string can only be converted into string types, but not into numbers or boolean types. -json.exception.[type_error](@ref type_error).303 | "incompatible ReferenceType for get_ref, actual type is object" | To retrieve a reference to a value stored in a @ref basic_json object with @ref get_ref, the type of the reference must match the value type. For instance, for a JSON array, the @a ReferenceType must be @ref array_t&. -json.exception.[type_error](@ref type_error).304 | "cannot use at() with string" | The @ref at() member functions can only be executed for certain JSON types. -json.exception.[type_error](@ref type_error).305 | "cannot use operator[] with string" | The @ref operator[] member functions can only be executed for certain JSON types. -json.exception.[type_error](@ref type_error).306 | "cannot use value() with string" | The @ref value() member functions can only be executed for certain JSON types. -json.exception.[type_error](@ref type_error).307 | "cannot use erase() with string" | The @ref erase() member functions can only be executed for certain JSON types. -json.exception.[type_error](@ref type_error).308 | "cannot use push_back() with string" | The @ref push_back() and @ref operator+= member functions can only be executed for certain JSON types. -json.exception.[type_error](@ref type_error).309 | "cannot use insert() with" | The @ref insert() member functions can only be executed for certain JSON types. -json.exception.[type_error](@ref type_error).310 | "cannot use swap() with number" | The @ref swap() member functions can only be executed for certain JSON types. -json.exception.[type_error](@ref type_error).311 | "cannot use emplace_back() with string" | The @ref emplace_back() member function can only be executed for certain JSON types. -json.exception.[type_error](@ref type_error).313 | "invalid value to unflatten" | The @ref unflatten function converts an object whose keys are JSON Pointers back into an arbitrary nested JSON value. The JSON Pointers must not overlap, because then the resulting value would not be well defined. -json.exception.[type_error](@ref type_error).314 | "only objects can be unflattened" | The @ref unflatten function only works for an object whose keys are JSON Pointers. -json.exception.[type_error](@ref type_error).315 | "values in object must be primitive" | The @ref unflatten function only works for an object whose keys are JSON Pointers and whose values are primitive. +name / id | example massage | description +----------------------------- | --------------- | ------------------------- +json.exception.type_error.301 | cannot create object from initializer list | To create an object from an initializer list, the initializer list must consist only of a list of pairs whose first element is a string. When this constraint is violated, an array is created instead. +json.exception.type_error.302 | type must be object, but is array | During implicit or explicit value conversion, the JSON type must be compatible to the target type. For instance, a JSON string can only be converted into string types, but not into numbers or boolean types. +json.exception.type_error.303 | incompatible ReferenceType for get_ref, actual type is object | To retrieve a reference to a value stored in a @ref basic_json object with @ref get_ref, the type of the reference must match the value type. For instance, for a JSON array, the @a ReferenceType must be @ref array_t&. +json.exception.type_error.304 | cannot use at() with string | The @ref at() member functions can only be executed for certain JSON types. +json.exception.type_error.305 | cannot use operator[] with string | The @ref operator[] member functions can only be executed for certain JSON types. +json.exception.type_error.306 | cannot use value() with string | The @ref value() member functions can only be executed for certain JSON types. +json.exception.type_error.307 | cannot use erase() with string | The @ref erase() member functions can only be executed for certain JSON types. +json.exception.type_error.308 | cannot use push_back() with string | The @ref push_back() and @ref operator+= member functions can only be executed for certain JSON types. +json.exception.type_error.309 | cannot use insert() with | The @ref insert() member functions can only be executed for certain JSON types. +json.exception.type_error.310 | cannot use swap() with number | The @ref swap() member functions can only be executed for certain JSON types. +json.exception.type_error.311 | cannot use emplace_back() with string | The @ref emplace_back() member function can only be executed for certain JSON types. +json.exception.type_error.313 | invalid value to unflatten | The @ref unflatten function converts an object whose keys are JSON Pointers back into an arbitrary nested JSON value. The JSON Pointers must not overlap, because then the resulting value would not be well defined. +json.exception.type_error.314 | only objects can be unflattened | The @ref unflatten function only works for an object whose keys are JSON Pointers. +json.exception.type_error.315 | values in object must be primitive | The @ref unflatten function only works for an object whose keys are JSON Pointers and whose values are primitive. @since version 3.0.0 */ @@ -276,13 +276,13 @@ class type_error : public exception Exceptions have ids 4xx. -name / id | example massage | description ------------------------------- | --------------- | ------------------------- -json.exception.[out_of_range](@ref out_of_range).401 | "array index 3 is out of range" | The provided array index @a i is larger than @a size-1. -json.exception.[out_of_range](@ref out_of_range).402 | "array index '-' (3) is out of range" | The special array index `-` in a JSON Pointer never describes a valid element of the array, but the index past the end. -json.exception.[out_of_range](@ref out_of_range).403 | "key 'foo' not found" | The provided key was not found in the JSON object. -json.exception.[out_of_range](@ref out_of_range).404 | "unresolved reference token 'foo'" | A reference token in a JSON Pointer could not be resolved. -json.exception.[out_of_range](@ref out_of_range).405 | "JSON pointer has no parent" | The JSON Patch operations 'remove' and 'add' can not be applied to the root element of the JSON value. +name / id | example massage | description +------------------------------- | --------------- | ------------------------- +json.exception.out_of_range.401 | array index 3 is out of range | The provided array index @a i is larger than @a size-1. +json.exception.out_of_range.402 | array index '-' (3) is out of range | The special array index `-` in a JSON Pointer never describes a valid element of the array, but the index past the end. That is, it can only be used to add elements at this position, but not to read it. +json.exception.out_of_range.403 | key 'foo' not found | The provided key was not found in the JSON object. +json.exception.out_of_range.404 | unresolved reference token 'foo' | A reference token in a JSON Pointer could not be resolved. +json.exception.out_of_range.405 | JSON pointer has no parent | The JSON Patch operations 'remove' and 'add' can not be applied to the root element of the JSON value. @since version 3.0.0 */ @@ -301,8 +301,7 @@ Exceptions have ids 5xx. name / id | example massage | description ------------------------------ | --------------- | ------------------------- -json.exception.[other_error](@ref other_error).501 | "unsuccessful: {"op":"test","path":"/baz", - "value":"bar"}" | A JSON Patch operation 'test' failed. +json.exception.other_error.501 | unsuccessful: {"op":"test","path":"/baz", "value":"bar"} | A JSON Patch operation 'test' failed. The unsuccessful operation is also printed. @since version 3.0.0 */ @@ -2122,9 +2121,6 @@ class basic_json @complexity Constant. - @throw std::bad_alloc if allocation for object, array, or string value - fails - @liveexample{The following code shows the constructor for different @ref value_t values,basic_json__value_t} @@ -2281,8 +2277,10 @@ class basic_json @throw type_error.301 if @a type_deduction is `false`, @a manual_type is `value_t::object`, but @a init contains an element which is not a pair - whose first element is a string; example: `"cannot create object from - initializer list"` + whose first element is a string. In this case, the constructor could not + create an object. If @a type_deduction would have be `true`, an array + would have been created. See @ref object(std::initializer_list) + for an example. @complexity Linear in the size of the initializer list @a init. @@ -2396,16 +2394,17 @@ class basic_json related function @ref array(std::initializer_list), there are no cases which can only be expressed by this function. That is, any initializer list @a init can also be passed to the initializer list - constructor @ref basic_json(std::initializer_list, bool, - value_t). + constructor @ref basic_json(std::initializer_list, bool, value_t). @param[in] init initializer list to create an object from (optional) @return JSON object value - @throw type_error.301 if @a init is not a pair whose first elements are - strings; thrown by - @ref basic_json(std::initializer_list, bool, value_t) + @throw type_error.301 if @a init is not a list of pairs whose first + elements are strings. In this case, no object can be created. When such a + value is passed to @ref basic_json(std::initializer_list, bool, value_t), + an array would have been created from the passed initializer list @a init. + See example below. @complexity Linear in the size of @a init. @@ -2457,10 +2456,10 @@ class basic_json The semantics depends on the different types a JSON value can have: - In case of primitive types (number, boolean, or string), @a first must be `begin()` and @a last must be `end()`. In this case, the value is - copied. Otherwise, std::out_of_range is thrown. + copied. Otherwise, invalid_iterator.204 is thrown. - In case of structured types (array, object), the constructor behaves as similar versions for `std::vector`. - - In case of a null type, std::domain_error is thrown. + - In case of a null type, invalid_iterator.206 is thrown. @tparam InputIT an input iterator type (@ref iterator or @ref const_iterator) @@ -2471,15 +2470,19 @@ class basic_json @pre Iterators @a first and @a last must be initialized. **This precondition is enforced with an assertion.** - @throw invalid_iterator.201 if iterators are not compatible; that is, do - not belong to the same JSON value; example: `"iterators are not - compatible"` - @throw invalid_iterator.204 if iterators are for a primitive type (number, - boolean, or string) where an out of range error can be detected easily; - example: `"iterators out of range"` - @throw std::bad_alloc if allocation for object, array, or string fails - @throw invalid_iterator.206 if called with a null value; example: `"cannot - construct with iterators from null"` + @pre Range `[first, last)` is valid. Usually, this precondition cannot be + checked efficiently. Only certain edge cases are detected; see the + description of the exceptions below. + + @throw invalid_iterator.201 if iterators @a first and @a last are not + compatible (i.e., do not belong to the same JSON value). In this case, + the range `[first, last)` is undefined. + @throw invalid_iterator.204 if iterators @a first and @a last belong to a + primitive type (number, boolean, or string), but @a first does not point + to the first element any more. In this case, the range `[first, last)` is + undefined. See example code below. + @throw invalid_iterator.206 if iterators @a first and @a last belong to a + null value. In this case, the range `[first, last)` is undefined. @complexity Linear in distance between @a first and @a last. @@ -2603,8 +2606,6 @@ class basic_json - The complexity is linear. - As postcondition, it holds: `other == basic_json(other)`. - @throw std::bad_alloc if allocation for object, array, or string fails. - @liveexample{The following code shows an example for the copy constructor.,basic_json__basic_json} @@ -3607,10 +3608,10 @@ class basic_json @return reference to the internally stored JSON value if the requested reference type @a ReferenceType fits to the JSON value; throws - std::domain_error otherwise + type_error.303 otherwise @throw type_error.303 in case passed type @a ReferenceType is incompatible - with the stored JSON value + with the stored JSON value; see example below @complexity Constant. @@ -3654,7 +3655,8 @@ class basic_json @return copy of the JSON value, converted to type @a ValueType @throw type_error.302 in case passed type @a ValueType is incompatible - to JSON, thrown by @ref get() const + to the JSON value type (e.g., the JSON value is of type boolean, but a + string is requested); see example below @complexity Linear in the size of the JSON value. @@ -3701,10 +3703,10 @@ class basic_json @return reference to the element at index @a idx - @throw type_error.304 if the JSON value is not an array; example: `"cannot - use at() with string"` + @throw type_error.304 if the JSON value is not an array; in this case, + calling `at` with an index makes no sense. @throw out_of_range.401 if the index @a idx is out of range of the array; - that is, `idx >= size()`; example: `"array index 7 is out of range"` + that is, `idx >= size()`; see example below. @complexity Constant. @@ -3744,10 +3746,10 @@ class basic_json @return const reference to the element at index @a idx - @throw type_error.304 if the JSON value is not an array; example: `"cannot - use at() with string"` + @throw type_error.304 if the JSON value is not an array; in this case, + calling `at` with an index makes no sense. @throw out_of_range.401 if the index @a idx is out of range of the array; - that is, `idx >= size()`; example: `"array index 7 is out of range"` + that is, `idx >= size()`; see example below. @complexity Constant. @@ -3787,10 +3789,10 @@ class basic_json @return reference to the element at key @a key - @throw type_error.304 if the JSON value is not an object; example: - `"cannot use at() with boolean"` + @throw type_error.304 if the JSON value is not an object; in this case, + calling `at` with a key makes no sense. @throw out_of_range.403 if the key @a key is is not stored in the object; - that is, `find(key) == end()`; example: `"key "the fast" not found"` + that is, `find(key) == end()`; see example below. @complexity Logarithmic in the size of the container. @@ -3834,10 +3836,10 @@ class basic_json @return const reference to the element at key @a key - @throw type_error.304 if the JSON value is not an object; example: - `"cannot use at() with boolean"` + @throw type_error.304 if the JSON value is not an object; in this case, + calling `at` with a key makes no sense. @throw out_of_range.403 if the key @a key is is not stored in the object; - that is, `find(key) == end()`; example: `"key "the fast" not found"` + that is, `find(key) == end()`; see example below. @complexity Logarithmic in the size of the container. @@ -3884,8 +3886,8 @@ class basic_json @return reference to the element at index @a idx - @throw type_error.305 if JSON is not an array or null; example: `"cannot - use operator[] with string" + @throw type_error.305 if the JSON value is not an array or null; in that + cases, using the [] operator with an index makes no sense. @complexity Constant if @a idx is in the range of the array. Otherwise linear in `idx - size()`. @@ -3932,8 +3934,8 @@ class basic_json @return const reference to the element at index @a idx - @throw type_error.305 if JSON is not an array; example: `"cannot use - operator[] with null"` + @throw type_error.305 if the JSON value is not an array; in that cases, + using the [] operator with an index makes no sense. @complexity Constant. @@ -3966,8 +3968,8 @@ class basic_json @return reference to the element at key @a key - @throw type_error.305 if JSON is not an object or null; example: `"cannot - use operator[] with string"` + @throw type_error.305 if the JSON value is not an object or null; in that + cases, using the [] operator with a key makes no sense. @complexity Logarithmic in the size of the container. @@ -4015,8 +4017,8 @@ class basic_json @pre The element with key @a key must exist. **This precondition is enforced with an assertion.** - @throw type_error.305 if JSON is not an object; example: `"cannot use - operator[] with null"` + @throw type_error.305 if the JSON value is not an object; in that cases, + using the [] operator with a key makes no sense. @complexity Logarithmic in the size of the container. @@ -4054,8 +4056,8 @@ class basic_json @return reference to the element at key @a key - @throw type_error.305 if JSON is not an object or null; example: `"cannot - use operator[] with string"` + @throw type_error.305 if the JSON value is not an object or null; in that + cases, using the [] operator with a key makes no sense. @complexity Logarithmic in the size of the container. @@ -4089,8 +4091,8 @@ class basic_json @return const reference to the element at key @a key - @throw type_error.305 if JSON is not an object; example: `"cannot use - operator[] with null"` + @throw type_error.305 if the JSON value is not an object; in that cases, + using the [] operator with a key makes no sense. @complexity Logarithmic in the size of the container. @@ -4122,8 +4124,8 @@ class basic_json @return reference to the element at key @a key - @throw type_error.305 if JSON is not an object or null; example: `"cannot - use operator[] with string"` + @throw type_error.305 if the JSON value is not an object or null; in that + cases, using the [] operator with a key makes no sense. @complexity Logarithmic in the size of the container. @@ -4172,8 +4174,8 @@ class basic_json @pre The element with key @a key must exist. **This precondition is enforced with an assertion.** - @throw type_error.305 if JSON is not an object; example: `"cannot use - operator[] with null"` + @throw type_error.305 if the JSON value is not an object; in that cases, + using the [] operator with a key makes no sense. @complexity Logarithmic in the size of the container. @@ -4232,8 +4234,8 @@ class basic_json @return copy of the element at key @a key or @a default_value if @a key is not found - @throw type_error.306 if JSON is not an object; example: `"cannot use - value() with null"` + @throw type_error.306 if the JSON value is not an objec; in that cases, + using `value()` with a key makes no sense. @complexity Logarithmic in the size of the container. @@ -4307,8 +4309,8 @@ class basic_json @return copy of the element at key @a key or @a default_value if @a key is not found - @throw type_error.306 if JSON is not an object; example: `"cannot use - value() with null"` + @throw type_error.306 if the JSON value is not an objec; in that cases, + using `value()` with a key makes no sense. @complexity Logarithmic in the size of the container. diff --git a/src/json.hpp.re2c b/src/json.hpp.re2c index d2f6346f8..22e128412 100644 --- a/src/json.hpp.re2c +++ b/src/json.hpp.re2c @@ -162,18 +162,18 @@ Exceptions have ids 1xx. name / id | example massage | description ------------------------------ | --------------- | ------------------------- -json.exception.[parse_error](@ref parse_error).101 | "parse error at 2: unexpected end of input; expected string literal" | This error indicates a syntax error while deserializing a JSON text. The error message describes that an unexpected token (character) was encountered, and the member @ref parse_error::byte indicates the error position. -json.exception.[parse_error](@ref parse_error).102 | "parse error at 14: missing or wrong low surrogate" | JSON uses the `\uxxxx` format to describe Unicode characters. Code points above above 0xFFFF are split into two `\uxxxx` entries ("surrogate pairs"). This error indicates that the surrogate pair is incomplete or contains an invalid code point. -json.exception.[parse_error](@ref parse_error).103 | "parse error: code points above 0x10FFFF are invalid" | Unicode supports code points up to 0x10FFFF. Code points above 0x10FFFF are invalid. -json.exception.[parse_error](@ref parse_error).104 | "parse error: JSON patch must be an array of objects" | [RFC 6902](https://tools.ietf.org/html/rfc6902) requires a JSON Patch document to be a JSON document that represents an array of objects. -json.exception.[parse_error](@ref parse_error).105 | "parse error: operation must have string member 'op'" | An operation of a JSON Patch document must contain exactly one "op" member, whose value indicates the operation to perform. Its value must be one of "add", "remove", "replace", "move", "copy", or "test"; other values are errors. -json.exception.[parse_error](@ref parse_error).106 | "parse error: array index '01' must not begin with '0'" | An array index in a JSON Pointer ([RFC 6901](https://tools.ietf.org/html/rfc6901)) may be `0` or any number wihtout a leading `0`. -json.exception.[parse_error](@ref parse_error).107 | "parse error: JSON pointer must be empty or begin with '/' - was: 'foo'" | A JSON Pointer must be a Unicode string containing a sequence of zero or more reference tokens, each prefixed by a `/` character. -json.exception.[parse_error](@ref parse_error).108 | "parse error: escape character '~' must be followed with '0' or '1'" | In a JSON Pointer, only `~0` and `~1` are valid escape sequences. -json.exception.[parse_error](@ref parse_error).109 | "parse error: array index 'one' is not a number" | A JSON Pointer array index must be a number. -json.exception.[parse_error](@ref parse_error).110 | "parse error at 1: cannot read 2 bytes from vector" | When parsing CBOR or MessagePack, the byte vector ends before the complete value has been read. -json.exception.[parse_error](@ref parse_error).111 | "parse error: bad input stream" | Parsing CBOR or MessagePack from an input stream where the `badbit` or `failbit` is set. -json.exception.[parse_error](@ref parse_error).112 | "parse error at 1: error reading CBOR; last byte: 0xf8" | Not all types of CBOR or MessagePack are supported. This exception occurs if an unsupported byte was read. +json.exception.parse_error.101 | parse error at 2: unexpected end of input; expected string literal | This error indicates a syntax error while deserializing a JSON text. The error message describes that an unexpected token (character) was encountered, and the member @a byte indicates the error position. +json.exception.parse_error.102 | parse error at 14: missing or wrong low surrogate | JSON uses the `\uxxxx` format to describe Unicode characters. Code points above above 0xFFFF are split into two `\uxxxx` entries ("surrogate pairs"). This error indicates that the surrogate pair is incomplete or contains an invalid code point. +json.exception.parse_error.103 | parse error: code points above 0x10FFFF are invalid | Unicode supports code points up to 0x10FFFF. Code points above 0x10FFFF are invalid. +json.exception.parse_error.104 | parse error: JSON patch must be an array of objects | [RFC 6902](https://tools.ietf.org/html/rfc6902) requires a JSON Patch document to be a JSON document that represents an array of objects. +json.exception.parse_error.105 | parse error: operation must have string member 'op' | An operation of a JSON Patch document must contain exactly one "op" member, whose value indicates the operation to perform. Its value must be one of "add", "remove", "replace", "move", "copy", or "test"; other values are errors. +json.exception.parse_error.106 | parse error: array index '01' must not begin with '0' | An array index in a JSON Pointer ([RFC 6901](https://tools.ietf.org/html/rfc6901)) may be `0` or any number wihtout a leading `0`. +json.exception.parse_error.107 | parse error: JSON pointer must be empty or begin with '/' - was: 'foo' | A JSON Pointer must be a Unicode string containing a sequence of zero or more reference tokens, each prefixed by a `/` character. +json.exception.parse_error.108 | parse error: escape character '~' must be followed with '0' or '1' | In a JSON Pointer, only `~0` and `~1` are valid escape sequences. +json.exception.parse_error.109 | parse error: array index 'one' is not a number | A JSON Pointer array index must be a number. +json.exception.parse_error.110 | parse error at 1: cannot read 2 bytes from vector | When parsing CBOR or MessagePack, the byte vector ends before the complete value has been read. +json.exception.parse_error.111 | parse error: bad input stream | Parsing CBOR or MessagePack from an input stream where the [`badbit` or `failbit`](http://en.cppreference.com/w/cpp/io/ios_base/iostate) is set. +json.exception.parse_error.112 | parse error at 1: error reading CBOR; last byte: 0xf8 | Not all types of CBOR or MessagePack are supported. This exception occurs if an unsupported byte was read. @since version 3.0.0 */ @@ -212,22 +212,22 @@ class parse_error : public exception Exceptions have ids 2xx. -name / id | example massage | description ------------------------------- | --------------- | ------------------------- -json.exception.[invalid_iterator](@ref invalid_iterator).201 | "iterators are not compatible" | The iterators passed to constructor @ref basic_json(InputIT first, InputIT last) are not compatible, meaning they do not belong to the same container. Therefore, the range (@a first, @a last) is invalid. -json.exception.[invalid_iterator](@ref invalid_iterator).202 | "iterator does not fit current value" | In an erase or insert function, the passed iterator @a pos does not belong to the JSON value for which the function was called. It hence does not define a valid position for the deletion/insertion. -json.exception.[invalid_iterator](@ref invalid_iterator).203 | "iterators do not fit current value" | Either iterator passed to function @ref erase(IteratorType first, IteratorType last) does not belong to the JSON value from which values shall be erased. It hence does not define a valid range to delete values from. -json.exception.[invalid_iterator](@ref invalid_iterator).204 | "iterators out of range" | When an iterator range for a primitive type (number, boolean, or string) is passed to a constructor or an erase function, this range has to be exactly (@ref begin(), @ref end()), because this is the only way the single stored value is expressed. All other ranges are invalid. -json.exception.[invalid_iterator](@ref invalid_iterator).205 | "iterator out of range" | When an iterator for a primitive type (number, boolean, or string) is passed to an erase function, the iterator has to be the @ref begin() iterator, because it is the only way to address the stored value. All other iterators are invalid. -json.exception.[invalid_iterator](@ref invalid_iterator).206 | "cannot construct with iterators from null" | The iterators passed to constructor @ref basic_json(InputIT first, InputIT last) belong to a JSON null value and hence to not define a valid range. -json.exception.[invalid_iterator](@ref invalid_iterator).207 | "cannot use key() for non-object iterators" | The key() member function can only be used on iterators belonging to a JSON object, because other types do not have a concept of a key. -json.exception.[invalid_iterator](@ref invalid_iterator).208 | "cannot use operator[] for object iterators" | The operator[] to specify a concrete offset cannot be used on iterators belonging to a JSON object, because JSON objects are unordered. -json.exception.[invalid_iterator](@ref invalid_iterator).209 | "cannot use offsets with object iterators" | The offset operators (+, -, +=, -=) cannot be used on iterators belonging to a JSON object, because JSON objects are unordered. -json.exception.[invalid_iterator](@ref invalid_iterator).210 | "iterators do not fit" | The iterator range passed to the insert function are not compatible, meaning they do not belong to the same container. Therefore, the range (@a first, @a last) is invalid. -json.exception.[invalid_iterator](@ref invalid_iterator).211 | "passed iterators may not belong to container" | The iterator range passed to the insert function must not be a subrange of the container to insert to. -json.exception.[invalid_iterator](@ref invalid_iterator).212 | "cannot compare iterators of different containers" | When two iterators are compared, they must belong to the same container. -json.exception.[invalid_iterator](@ref invalid_iterator).213 | "cannot compare order of object iterators" | The order of object iterators cannot be compated, because JSON objects are unordered. -json.exception.[invalid_iterator](@ref invalid_iterator).214 | "cannot get value" | Cannot get value for iterator: Either the iterator belongs to a null value or it is an iterator to a primitive type (number, boolean, or string), but the iterator is different to @ref begin(). +name / id | example massage | description +----------------------------------- | --------------- | ------------------------- +json.exception.invalid_iterator.201 | iterators are not compatible | The iterators passed to constructor @ref basic_json(InputIT first, InputIT last) are not compatible, meaning they do not belong to the same container. Therefore, the range (@a first, @a last) is invalid. +json.exception.invalid_iterator.202 | iterator does not fit current value | In an erase or insert function, the passed iterator @a pos does not belong to the JSON value for which the function was called. It hence does not define a valid position for the deletion/insertion. +json.exception.invalid_iterator.203 | iterators do not fit current value | Either iterator passed to function @ref erase(IteratorType first, IteratorType last) does not belong to the JSON value from which values shall be erased. It hence does not define a valid range to delete values from. +json.exception.invalid_iterator.204 | iterators out of range | When an iterator range for a primitive type (number, boolean, or string) is passed to a constructor or an erase function, this range has to be exactly (@ref begin(), @ref end()), because this is the only way the single stored value is expressed. All other ranges are invalid. +json.exception.invalid_iterator.205 | iterator out of range | When an iterator for a primitive type (number, boolean, or string) is passed to an erase function, the iterator has to be the @ref begin() iterator, because it is the only way to address the stored value. All other iterators are invalid. +json.exception.invalid_iterator.206 | cannot construct with iterators from null | The iterators passed to constructor @ref basic_json(InputIT first, InputIT last) belong to a JSON null value and hence to not define a valid range. +json.exception.invalid_iterator.207 | cannot use key() for non-object iterators | The key() member function can only be used on iterators belonging to a JSON object, because other types do not have a concept of a key. +json.exception.invalid_iterator.208 | cannot use operator[] for object iterators | The operator[] to specify a concrete offset cannot be used on iterators belonging to a JSON object, because JSON objects are unordered. +json.exception.invalid_iterator.209 | cannot use offsets with object iterators | The offset operators (+, -, +=, -=) cannot be used on iterators belonging to a JSON object, because JSON objects are unordered. +json.exception.invalid_iterator.210 | iterators do not fit | The iterator range passed to the insert function are not compatible, meaning they do not belong to the same container. Therefore, the range (@a first, @a last) is invalid. +json.exception.invalid_iterator.211 | passed iterators may not belong to container | The iterator range passed to the insert function must not be a subrange of the container to insert to. +json.exception.invalid_iterator.212 | cannot compare iterators of different containers | When two iterators are compared, they must belong to the same container. +json.exception.invalid_iterator.213 | cannot compare order of object iterators | The order of object iterators cannot be compated, because JSON objects are unordered. +json.exception.invalid_iterator.214 | cannot get value | Cannot get value for iterator: Either the iterator belongs to a null value or it is an iterator to a primitive type (number, boolean, or string), but the iterator is different to @ref begin(). @since version 3.0.0 */ @@ -244,22 +244,22 @@ class invalid_iterator : public exception Exceptions have ids 3xx. -name / id | example massage | description ------------------------------- | --------------- | ------------------------- -json.exception.[type_error](@ref type_error).301 | "cannot create object from initializer list" | To create an object from an initializer list, the initializer list must consist only of a list of pairs whose first element is a string. When this constraint is violated, an array is created instead. -json.exception.[type_error](@ref type_error).302 | "type must be object, but is array" | During implicit or explicit value conversion, the JSON type must be compatible to the target type. For instance, a JSON string can only be converted into string types, but not into numbers or boolean types. -json.exception.[type_error](@ref type_error).303 | "incompatible ReferenceType for get_ref, actual type is object" | To retrieve a reference to a value stored in a @ref basic_json object with @ref get_ref, the type of the reference must match the value type. For instance, for a JSON array, the @a ReferenceType must be @ref array_t&. -json.exception.[type_error](@ref type_error).304 | "cannot use at() with string" | The @ref at() member functions can only be executed for certain JSON types. -json.exception.[type_error](@ref type_error).305 | "cannot use operator[] with string" | The @ref operator[] member functions can only be executed for certain JSON types. -json.exception.[type_error](@ref type_error).306 | "cannot use value() with string" | The @ref value() member functions can only be executed for certain JSON types. -json.exception.[type_error](@ref type_error).307 | "cannot use erase() with string" | The @ref erase() member functions can only be executed for certain JSON types. -json.exception.[type_error](@ref type_error).308 | "cannot use push_back() with string" | The @ref push_back() and @ref operator+= member functions can only be executed for certain JSON types. -json.exception.[type_error](@ref type_error).309 | "cannot use insert() with" | The @ref insert() member functions can only be executed for certain JSON types. -json.exception.[type_error](@ref type_error).310 | "cannot use swap() with number" | The @ref swap() member functions can only be executed for certain JSON types. -json.exception.[type_error](@ref type_error).311 | "cannot use emplace_back() with string" | The @ref emplace_back() member function can only be executed for certain JSON types. -json.exception.[type_error](@ref type_error).313 | "invalid value to unflatten" | The @ref unflatten function converts an object whose keys are JSON Pointers back into an arbitrary nested JSON value. The JSON Pointers must not overlap, because then the resulting value would not be well defined. -json.exception.[type_error](@ref type_error).314 | "only objects can be unflattened" | The @ref unflatten function only works for an object whose keys are JSON Pointers. -json.exception.[type_error](@ref type_error).315 | "values in object must be primitive" | The @ref unflatten function only works for an object whose keys are JSON Pointers and whose values are primitive. +name / id | example massage | description +----------------------------- | --------------- | ------------------------- +json.exception.type_error.301 | cannot create object from initializer list | To create an object from an initializer list, the initializer list must consist only of a list of pairs whose first element is a string. When this constraint is violated, an array is created instead. +json.exception.type_error.302 | type must be object, but is array | During implicit or explicit value conversion, the JSON type must be compatible to the target type. For instance, a JSON string can only be converted into string types, but not into numbers or boolean types. +json.exception.type_error.303 | incompatible ReferenceType for get_ref, actual type is object | To retrieve a reference to a value stored in a @ref basic_json object with @ref get_ref, the type of the reference must match the value type. For instance, for a JSON array, the @a ReferenceType must be @ref array_t&. +json.exception.type_error.304 | cannot use at() with string | The @ref at() member functions can only be executed for certain JSON types. +json.exception.type_error.305 | cannot use operator[] with string | The @ref operator[] member functions can only be executed for certain JSON types. +json.exception.type_error.306 | cannot use value() with string | The @ref value() member functions can only be executed for certain JSON types. +json.exception.type_error.307 | cannot use erase() with string | The @ref erase() member functions can only be executed for certain JSON types. +json.exception.type_error.308 | cannot use push_back() with string | The @ref push_back() and @ref operator+= member functions can only be executed for certain JSON types. +json.exception.type_error.309 | cannot use insert() with | The @ref insert() member functions can only be executed for certain JSON types. +json.exception.type_error.310 | cannot use swap() with number | The @ref swap() member functions can only be executed for certain JSON types. +json.exception.type_error.311 | cannot use emplace_back() with string | The @ref emplace_back() member function can only be executed for certain JSON types. +json.exception.type_error.313 | invalid value to unflatten | The @ref unflatten function converts an object whose keys are JSON Pointers back into an arbitrary nested JSON value. The JSON Pointers must not overlap, because then the resulting value would not be well defined. +json.exception.type_error.314 | only objects can be unflattened | The @ref unflatten function only works for an object whose keys are JSON Pointers. +json.exception.type_error.315 | values in object must be primitive | The @ref unflatten function only works for an object whose keys are JSON Pointers and whose values are primitive. @since version 3.0.0 */ @@ -276,13 +276,13 @@ class type_error : public exception Exceptions have ids 4xx. -name / id | example massage | description ------------------------------- | --------------- | ------------------------- -json.exception.[out_of_range](@ref out_of_range).401 | "array index 3 is out of range" | The provided array index @a i is larger than @a size-1. -json.exception.[out_of_range](@ref out_of_range).402 | "array index '-' (3) is out of range" | The special array index `-` in a JSON Pointer never describes a valid element of the array, but the index past the end. -json.exception.[out_of_range](@ref out_of_range).403 | "key 'foo' not found" | The provided key was not found in the JSON object. -json.exception.[out_of_range](@ref out_of_range).404 | "unresolved reference token 'foo'" | A reference token in a JSON Pointer could not be resolved. -json.exception.[out_of_range](@ref out_of_range).405 | "JSON pointer has no parent" | The JSON Patch operations 'remove' and 'add' can not be applied to the root element of the JSON value. +name / id | example massage | description +------------------------------- | --------------- | ------------------------- +json.exception.out_of_range.401 | array index 3 is out of range | The provided array index @a i is larger than @a size-1. +json.exception.out_of_range.402 | array index '-' (3) is out of range | The special array index `-` in a JSON Pointer never describes a valid element of the array, but the index past the end. That is, it can only be used to add elements at this position, but not to read it. +json.exception.out_of_range.403 | key 'foo' not found | The provided key was not found in the JSON object. +json.exception.out_of_range.404 | unresolved reference token 'foo' | A reference token in a JSON Pointer could not be resolved. +json.exception.out_of_range.405 | JSON pointer has no parent | The JSON Patch operations 'remove' and 'add' can not be applied to the root element of the JSON value. @since version 3.0.0 */ @@ -301,8 +301,7 @@ Exceptions have ids 5xx. name / id | example massage | description ------------------------------ | --------------- | ------------------------- -json.exception.[other_error](@ref other_error).501 | "unsuccessful: {"op":"test","path":"/baz", - "value":"bar"}" | A JSON Patch operation 'test' failed. +json.exception.other_error.501 | unsuccessful: {"op":"test","path":"/baz", "value":"bar"} | A JSON Patch operation 'test' failed. The unsuccessful operation is also printed. @since version 3.0.0 */ @@ -2122,9 +2121,6 @@ class basic_json @complexity Constant. - @throw std::bad_alloc if allocation for object, array, or string value - fails - @liveexample{The following code shows the constructor for different @ref value_t values,basic_json__value_t} @@ -2281,8 +2277,10 @@ class basic_json @throw type_error.301 if @a type_deduction is `false`, @a manual_type is `value_t::object`, but @a init contains an element which is not a pair - whose first element is a string; example: `"cannot create object from - initializer list"` + whose first element is a string. In this case, the constructor could not + create an object. If @a type_deduction would have be `true`, an array + would have been created. See @ref object(std::initializer_list) + for an example. @complexity Linear in the size of the initializer list @a init. @@ -2396,16 +2394,17 @@ class basic_json related function @ref array(std::initializer_list), there are no cases which can only be expressed by this function. That is, any initializer list @a init can also be passed to the initializer list - constructor @ref basic_json(std::initializer_list, bool, - value_t). + constructor @ref basic_json(std::initializer_list, bool, value_t). @param[in] init initializer list to create an object from (optional) @return JSON object value - @throw type_error.301 if @a init is not a pair whose first elements are - strings; thrown by - @ref basic_json(std::initializer_list, bool, value_t) + @throw type_error.301 if @a init is not a list of pairs whose first + elements are strings. In this case, no object can be created. When such a + value is passed to @ref basic_json(std::initializer_list, bool, value_t), + an array would have been created from the passed initializer list @a init. + See example below. @complexity Linear in the size of @a init. @@ -2457,10 +2456,10 @@ class basic_json The semantics depends on the different types a JSON value can have: - In case of primitive types (number, boolean, or string), @a first must be `begin()` and @a last must be `end()`. In this case, the value is - copied. Otherwise, std::out_of_range is thrown. + copied. Otherwise, invalid_iterator.204 is thrown. - In case of structured types (array, object), the constructor behaves as similar versions for `std::vector`. - - In case of a null type, std::domain_error is thrown. + - In case of a null type, invalid_iterator.206 is thrown. @tparam InputIT an input iterator type (@ref iterator or @ref const_iterator) @@ -2471,15 +2470,19 @@ class basic_json @pre Iterators @a first and @a last must be initialized. **This precondition is enforced with an assertion.** - @throw invalid_iterator.201 if iterators are not compatible; that is, do - not belong to the same JSON value; example: `"iterators are not - compatible"` - @throw invalid_iterator.204 if iterators are for a primitive type (number, - boolean, or string) where an out of range error can be detected easily; - example: `"iterators out of range"` - @throw std::bad_alloc if allocation for object, array, or string fails - @throw invalid_iterator.206 if called with a null value; example: `"cannot - construct with iterators from null"` + @pre Range `[first, last)` is valid. Usually, this precondition cannot be + checked efficiently. Only certain edge cases are detected; see the + description of the exceptions below. + + @throw invalid_iterator.201 if iterators @a first and @a last are not + compatible (i.e., do not belong to the same JSON value). In this case, + the range `[first, last)` is undefined. + @throw invalid_iterator.204 if iterators @a first and @a last belong to a + primitive type (number, boolean, or string), but @a first does not point + to the first element any more. In this case, the range `[first, last)` is + undefined. See example code below. + @throw invalid_iterator.206 if iterators @a first and @a last belong to a + null value. In this case, the range `[first, last)` is undefined. @complexity Linear in distance between @a first and @a last. @@ -2603,8 +2606,6 @@ class basic_json - The complexity is linear. - As postcondition, it holds: `other == basic_json(other)`. - @throw std::bad_alloc if allocation for object, array, or string fails. - @liveexample{The following code shows an example for the copy constructor.,basic_json__basic_json} @@ -3607,10 +3608,10 @@ class basic_json @return reference to the internally stored JSON value if the requested reference type @a ReferenceType fits to the JSON value; throws - std::domain_error otherwise + type_error.303 otherwise @throw type_error.303 in case passed type @a ReferenceType is incompatible - with the stored JSON value + with the stored JSON value; see example below @complexity Constant. @@ -3654,7 +3655,8 @@ class basic_json @return copy of the JSON value, converted to type @a ValueType @throw type_error.302 in case passed type @a ValueType is incompatible - to JSON, thrown by @ref get() const + to the JSON value type (e.g., the JSON value is of type boolean, but a + string is requested); see example below @complexity Linear in the size of the JSON value. @@ -3701,10 +3703,10 @@ class basic_json @return reference to the element at index @a idx - @throw type_error.304 if the JSON value is not an array; example: `"cannot - use at() with string"` + @throw type_error.304 if the JSON value is not an array; in this case, + calling `at` with an index makes no sense. @throw out_of_range.401 if the index @a idx is out of range of the array; - that is, `idx >= size()`; example: `"array index 7 is out of range"` + that is, `idx >= size()`; see example below. @complexity Constant. @@ -3744,10 +3746,10 @@ class basic_json @return const reference to the element at index @a idx - @throw type_error.304 if the JSON value is not an array; example: `"cannot - use at() with string"` + @throw type_error.304 if the JSON value is not an array; in this case, + calling `at` with an index makes no sense. @throw out_of_range.401 if the index @a idx is out of range of the array; - that is, `idx >= size()`; example: `"array index 7 is out of range"` + that is, `idx >= size()`; see example below. @complexity Constant. @@ -3787,10 +3789,10 @@ class basic_json @return reference to the element at key @a key - @throw type_error.304 if the JSON value is not an object; example: - `"cannot use at() with boolean"` + @throw type_error.304 if the JSON value is not an object; in this case, + calling `at` with a key makes no sense. @throw out_of_range.403 if the key @a key is is not stored in the object; - that is, `find(key) == end()`; example: `"key "the fast" not found"` + that is, `find(key) == end()`; see example below. @complexity Logarithmic in the size of the container. @@ -3834,10 +3836,10 @@ class basic_json @return const reference to the element at key @a key - @throw type_error.304 if the JSON value is not an object; example: - `"cannot use at() with boolean"` + @throw type_error.304 if the JSON value is not an object; in this case, + calling `at` with a key makes no sense. @throw out_of_range.403 if the key @a key is is not stored in the object; - that is, `find(key) == end()`; example: `"key "the fast" not found"` + that is, `find(key) == end()`; see example below. @complexity Logarithmic in the size of the container. @@ -3884,8 +3886,8 @@ class basic_json @return reference to the element at index @a idx - @throw type_error.305 if JSON is not an array or null; example: `"cannot - use operator[] with string" + @throw type_error.305 if the JSON value is not an array or null; in that + cases, using the [] operator with an index makes no sense. @complexity Constant if @a idx is in the range of the array. Otherwise linear in `idx - size()`. @@ -3932,8 +3934,8 @@ class basic_json @return const reference to the element at index @a idx - @throw type_error.305 if JSON is not an array; example: `"cannot use - operator[] with null"` + @throw type_error.305 if the JSON value is not an array; in that cases, + using the [] operator with an index makes no sense. @complexity Constant. @@ -3966,8 +3968,8 @@ class basic_json @return reference to the element at key @a key - @throw type_error.305 if JSON is not an object or null; example: `"cannot - use operator[] with string"` + @throw type_error.305 if the JSON value is not an object or null; in that + cases, using the [] operator with a key makes no sense. @complexity Logarithmic in the size of the container. @@ -4015,8 +4017,8 @@ class basic_json @pre The element with key @a key must exist. **This precondition is enforced with an assertion.** - @throw type_error.305 if JSON is not an object; example: `"cannot use - operator[] with null"` + @throw type_error.305 if the JSON value is not an object; in that cases, + using the [] operator with a key makes no sense. @complexity Logarithmic in the size of the container. @@ -4054,8 +4056,8 @@ class basic_json @return reference to the element at key @a key - @throw type_error.305 if JSON is not an object or null; example: `"cannot - use operator[] with string"` + @throw type_error.305 if the JSON value is not an object or null; in that + cases, using the [] operator with a key makes no sense. @complexity Logarithmic in the size of the container. @@ -4089,8 +4091,8 @@ class basic_json @return const reference to the element at key @a key - @throw type_error.305 if JSON is not an object; example: `"cannot use - operator[] with null"` + @throw type_error.305 if the JSON value is not an object; in that cases, + using the [] operator with a key makes no sense. @complexity Logarithmic in the size of the container. @@ -4122,8 +4124,8 @@ class basic_json @return reference to the element at key @a key - @throw type_error.305 if JSON is not an object or null; example: `"cannot - use operator[] with string"` + @throw type_error.305 if the JSON value is not an object or null; in that + cases, using the [] operator with a key makes no sense. @complexity Logarithmic in the size of the container. @@ -4172,8 +4174,8 @@ class basic_json @pre The element with key @a key must exist. **This precondition is enforced with an assertion.** - @throw type_error.305 if JSON is not an object; example: `"cannot use - operator[] with null"` + @throw type_error.305 if the JSON value is not an object; in that cases, + using the [] operator with a key makes no sense. @complexity Logarithmic in the size of the container. @@ -4232,8 +4234,8 @@ class basic_json @return copy of the element at key @a key or @a default_value if @a key is not found - @throw type_error.306 if JSON is not an object; example: `"cannot use - value() with null"` + @throw type_error.306 if the JSON value is not an objec; in that cases, + using `value()` with a key makes no sense. @complexity Logarithmic in the size of the container. @@ -4307,8 +4309,8 @@ class basic_json @return copy of the element at key @a key or @a default_value if @a key is not found - @throw type_error.306 if JSON is not an object; example: `"cannot use - value() with null"` + @throw type_error.306 if the JSON value is not an objec; in that cases, + using `value()` with a key makes no sense. @complexity Logarithmic in the size of the container. From 0f6b8aa7181aabb51ef71c80b64e12016e7667ae Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Wed, 8 Mar 2017 23:30:38 +0100 Subject: [PATCH 34/52] :memo: more documentation for the new exceptions --- doc/examples/at_json_pointer.cpp | 10 +++++++ doc/examples/at_json_pointer.link | 2 +- doc/examples/at_json_pointer.output | 1 + doc/examples/at_json_pointer_const.cpp | 10 +++++++ doc/examples/at_json_pointer_const.link | 2 +- doc/examples/at_json_pointer_const.output | 1 + doc/examples/back.cpp | 13 +++++++-- doc/examples/back.link | 2 +- doc/examples/back.output | 1 + src/json.hpp | 35 +++++++++++++++++------ src/json.hpp.re2c | 35 +++++++++++++++++------ 11 files changed, 89 insertions(+), 23 deletions(-) diff --git a/doc/examples/at_json_pointer.cpp b/doc/examples/at_json_pointer.cpp index 0665e608c..6d1617e65 100644 --- a/doc/examples/at_json_pointer.cpp +++ b/doc/examples/at_json_pointer.cpp @@ -32,4 +32,14 @@ int main() j.at("/array/1"_json_pointer) = 21; // output the changed array std::cout << j["array"] << '\n'; + + // try to use an invalid JSON pointer + try + { + auto ref = j.at("/number/foo"_json_pointer); + } + catch (json::out_of_range& e) + { + std::cout << e.what() << '\n'; + } } diff --git a/doc/examples/at_json_pointer.link b/doc/examples/at_json_pointer.link index 7a7efa268..454023032 100644 --- a/doc/examples/at_json_pointer.link +++ b/doc/examples/at_json_pointer.link @@ -1 +1 @@ -online \ No newline at end of file +online \ No newline at end of file diff --git a/doc/examples/at_json_pointer.output b/doc/examples/at_json_pointer.output index 11913c723..a45737ad2 100644 --- a/doc/examples/at_json_pointer.output +++ b/doc/examples/at_json_pointer.output @@ -4,3 +4,4 @@ 2 "bar" [1,21] +[json.exception.out_of_range.404] unresolved reference token 'foo' diff --git a/doc/examples/at_json_pointer_const.cpp b/doc/examples/at_json_pointer_const.cpp index e3cfc5154..dab1b39c4 100644 --- a/doc/examples/at_json_pointer_const.cpp +++ b/doc/examples/at_json_pointer_const.cpp @@ -20,4 +20,14 @@ int main() std::cout << j.at("/array"_json_pointer) << '\n'; // output element with JSON pointer "/array/1" std::cout << j.at("/array/1"_json_pointer) << '\n'; + + // try to use an invalid JSON pointer + try + { + auto ref = j.at("/number/foo"_json_pointer); + } + catch (json::out_of_range& e) + { + std::cout << e.what() << '\n'; + } } diff --git a/doc/examples/at_json_pointer_const.link b/doc/examples/at_json_pointer_const.link index 9057e0b27..70e7cf868 100644 --- a/doc/examples/at_json_pointer_const.link +++ b/doc/examples/at_json_pointer_const.link @@ -1 +1 @@ -online \ No newline at end of file +online \ No newline at end of file diff --git a/doc/examples/at_json_pointer_const.output b/doc/examples/at_json_pointer_const.output index 7b9306bbc..21712e867 100644 --- a/doc/examples/at_json_pointer_const.output +++ b/doc/examples/at_json_pointer_const.output @@ -2,3 +2,4 @@ "foo" [1,2] 2 +[json.exception.out_of_range.404] unresolved reference token 'foo' diff --git a/doc/examples/back.cpp b/doc/examples/back.cpp index 70516e588..45f9483c7 100644 --- a/doc/examples/back.cpp +++ b/doc/examples/back.cpp @@ -5,7 +5,6 @@ using json = nlohmann::json; int main() { // create JSON values - json j_null; json j_boolean = true; json j_number_integer = 17; json j_number_float = 23.42; @@ -16,7 +15,6 @@ int main() json j_string = "Hello, world"; // call back() - //std::cout << j_null.back() << '\n'; // would throw std::cout << j_boolean.back() << '\n'; std::cout << j_number_integer.back() << '\n'; std::cout << j_number_float.back() << '\n'; @@ -25,4 +23,15 @@ int main() std::cout << j_array.back() << '\n'; //std::cout << j_array_empty.back() << '\n'; // undefined behavior std::cout << j_string.back() << '\n'; + + // back() called on a null value + try + { + json j_null; + j_null.back(); + } + catch (json::invalid_iterator& e) + { + std::cout << e.what() << '\n'; + } } diff --git a/doc/examples/back.link b/doc/examples/back.link index 0b0097805..15b1102ba 100644 --- a/doc/examples/back.link +++ b/doc/examples/back.link @@ -1 +1 @@ -online \ No newline at end of file +online \ No newline at end of file diff --git a/doc/examples/back.output b/doc/examples/back.output index 159ba0fc5..2990dbf0e 100644 --- a/doc/examples/back.output +++ b/doc/examples/back.output @@ -4,3 +4,4 @@ true 2 16 "Hello, world" +[json.exception.invalid_iterator.214] cannot get value diff --git a/src/json.hpp b/src/json.hpp index 9fb7690f3..5a3e6c3a7 100644 --- a/src/json.hpp +++ b/src/json.hpp @@ -4411,7 +4411,8 @@ class basic_json assertions**). @post The JSON value remains unchanged. - @throw invalid_iterator.214 when called on `null` value. + @throw invalid_iterator.214 when called on a `null` value. See example + below. @liveexample{The following code shows an example for `back()`.,back} @@ -12769,10 +12770,18 @@ basic_json_parser_74: @complexity Constant. - @throw parse_error.106 if an array index begins with '0' - @throw parse_error.109 if an array index was not a number - @throw out_of_range.402 if the array index '-' is used - @throw out_of_range.404 if the JSON pointer can not be resolved + @throw parse_error.106 if an array index in the passed JSON pointer @a ptr + begins with '0' + + @throw parse_error.109 if an array index in the passed JSON pointer @a ptr + is not a number + + @throw out_of_range.402 if the array index `-` is used in the passed JSON + pointer @a ptr. As `at` provides checked access (and no elements are + implicitly inserted), the index `-` is always invalid. + + @throw out_of_range.404 if the JSON pointer @a ptr can not be resolved; + see example below. @liveexample{The behavior is shown in the example.,at_json_pointer} @@ -12795,10 +12804,18 @@ basic_json_parser_74: @complexity Constant. - @throw parse_error.106 if an array index begins with '0' - @throw parse_error.109 if an array index was not a number - @throw out_of_range.402 if the array index '-' is used - @throw out_of_range.404 if the JSON pointer can not be resolved + @throw parse_error.106 if an array index in the passed JSON pointer @a ptr + begins with '0' + + @throw parse_error.109 if an array index in the passed JSON pointer @a ptr + is not a number + + @throw out_of_range.402 if the array index `-` is used in the passed JSON + pointer @a ptr. As `at` provides checked access (and no elements are + implicitly inserted), the index `-` is always invalid. + + @throw out_of_range.404 if the JSON pointer @a ptr can not be resolved; + see example below. @liveexample{The behavior is shown in the example.,at_json_pointer_const} diff --git a/src/json.hpp.re2c b/src/json.hpp.re2c index 22e128412..289e3f10a 100644 --- a/src/json.hpp.re2c +++ b/src/json.hpp.re2c @@ -4411,7 +4411,8 @@ class basic_json assertions**). @post The JSON value remains unchanged. - @throw invalid_iterator.214 when called on `null` value. + @throw invalid_iterator.214 when called on a `null` value. See example + below. @liveexample{The following code shows an example for `back()`.,back} @@ -11802,10 +11803,18 @@ class basic_json @complexity Constant. - @throw parse_error.106 if an array index begins with '0' - @throw parse_error.109 if an array index was not a number - @throw out_of_range.402 if the array index '-' is used - @throw out_of_range.404 if the JSON pointer can not be resolved + @throw parse_error.106 if an array index in the passed JSON pointer @a ptr + begins with '0' + + @throw parse_error.109 if an array index in the passed JSON pointer @a ptr + is not a number + + @throw out_of_range.402 if the array index `-` is used in the passed JSON + pointer @a ptr. As `at` provides checked access (and no elements are + implicitly inserted), the index `-` is always invalid. + + @throw out_of_range.404 if the JSON pointer @a ptr can not be resolved; + see example below. @liveexample{The behavior is shown in the example.,at_json_pointer} @@ -11828,10 +11837,18 @@ class basic_json @complexity Constant. - @throw parse_error.106 if an array index begins with '0' - @throw parse_error.109 if an array index was not a number - @throw out_of_range.402 if the array index '-' is used - @throw out_of_range.404 if the JSON pointer can not be resolved + @throw parse_error.106 if an array index in the passed JSON pointer @a ptr + begins with '0' + + @throw parse_error.109 if an array index in the passed JSON pointer @a ptr + is not a number + + @throw out_of_range.402 if the array index `-` is used in the passed JSON + pointer @a ptr. As `at` provides checked access (and no elements are + implicitly inserted), the index `-` is always invalid. + + @throw out_of_range.404 if the JSON pointer @a ptr can not be resolved; + see example below. @liveexample{The behavior is shown in the example.,at_json_pointer_const} From f4126e4dd84dfb723acb34dd3dbfcd6364b11fb2 Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Sat, 11 Mar 2017 15:44:14 +0100 Subject: [PATCH 35/52] :sparkles: added overload for std::less #486 MSVC needs this overload to compile code containing a std::map that uses nlohmann::detail::operator as key. --- src/json.hpp | 16 ++++++++++++++++ src/json.hpp.re2c | 16 ++++++++++++++++ test/src/unit-regression.cpp | 7 +++++++ 3 files changed, 39 insertions(+) diff --git a/src/json.hpp b/src/json.hpp index ff0ce5add..6f52255bc 100644 --- a/src/json.hpp +++ b/src/json.hpp @@ -13025,6 +13025,22 @@ struct hash return h(j.dump()); } }; + +/// specialization for std::less +template <> +struct less<::nlohmann::detail::value_t> +{ + /*! + @brief compare two value_t enum values + @since version 3.0.0 + */ + bool operator()(nlohmann::detail::value_t lhs, + nlohmann::detail::value_t rhs) const noexcept + { + return nlohmann::detail::operator<(lhs, rhs); + } +}; + } // namespace std /*! diff --git a/src/json.hpp.re2c b/src/json.hpp.re2c index fc7cf9653..7c2c24bfb 100644 --- a/src/json.hpp.re2c +++ b/src/json.hpp.re2c @@ -12059,6 +12059,22 @@ struct hash return h(j.dump()); } }; + +/// specialization for std::less +template <> +struct less<::nlohmann::detail::value_t> +{ + /*! + @brief compare two value_t enum values + @since version 3.0.0 + */ + bool operator()(nlohmann::detail::value_t lhs, + nlohmann::detail::value_t rhs) const noexcept + { + return nlohmann::detail::operator<(lhs, rhs); + } +}; + } // namespace std /*! diff --git a/test/src/unit-regression.cpp b/test/src/unit-regression.cpp index 7980371bc..f7b560502 100644 --- a/test/src/unit-regression.cpp +++ b/test/src/unit-regression.cpp @@ -795,4 +795,11 @@ TEST_CASE("regression tests") std::string s2 = j2.dump(); CHECK(s1 == s2); } + + SECTION("issue #486 - json::value_t can't be a map's key type in VC++ 2015") + { + // the code below must compile with MSVC + std::map jsonTypes ; + jsonTypes[json::value_t::array] = "array"; + } } From 65dfc97d401e17befa4d9a2320660b381529304e Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Sat, 11 Mar 2017 17:44:54 +0100 Subject: [PATCH 36/52] :hammer: using __cpp_exceptions to detect exception support #498 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit I used __EXCEPTIONS to detect whether exceptions are supported. Apparently, this is a macro that is only used by libstdc++ (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=64276). It’s much cleaner to use __cpp_exceptions as it is in the standard since C++98. Note that compiling the unit-tests with “-fno-exceptions” still does not work, because Catch uses throw internally. However, the library’s exceptions can be switched off by defining JSON_NOEXCEPTION. --- src/json.hpp | 2 +- src/json.hpp.re2c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/json.hpp b/src/json.hpp index 33456a515..9fb5fefe5 100644 --- a/src/json.hpp +++ b/src/json.hpp @@ -82,7 +82,7 @@ SOFTWARE. #endif // allow to disable exceptions -#if not defined(JSON_NOEXCEPTION) || defined(__EXCEPTIONS) +#if __cpp_exceptions && not defined(JSON_NOEXCEPTION) #define JSON_THROW(exception) throw exception #define JSON_TRY try #define JSON_CATCH(exception) catch(exception) diff --git a/src/json.hpp.re2c b/src/json.hpp.re2c index 180f5d3b4..a837df065 100644 --- a/src/json.hpp.re2c +++ b/src/json.hpp.re2c @@ -82,7 +82,7 @@ SOFTWARE. #endif // allow to disable exceptions -#if not defined(JSON_NOEXCEPTION) || defined(__EXCEPTIONS) +#if __cpp_exceptions && not defined(JSON_NOEXCEPTION) #define JSON_THROW(exception) throw exception #define JSON_TRY try #define JSON_CATCH(exception) catch(exception) From e3e6cbecc7a150590636d13b17a0260b5c46d90e Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Sat, 11 Mar 2017 17:59:24 +0100 Subject: [PATCH 37/52] :checkered_flag: added check for _CPPUNWIND MSVC does not define __cpp_exceptions, but seems to use _CPPUNWIND when exception support is switched on, see https://msdn.microsoft.com/en-us/library/b0084kay.aspx. --- src/json.hpp | 2 +- src/json.hpp.re2c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/json.hpp b/src/json.hpp index 9fb5fefe5..f9a928202 100644 --- a/src/json.hpp +++ b/src/json.hpp @@ -82,7 +82,7 @@ SOFTWARE. #endif // allow to disable exceptions -#if __cpp_exceptions && not defined(JSON_NOEXCEPTION) +#if (__cpp_exceptions || defined(_CPPUNWIND)) && not defined(JSON_NOEXCEPTION) #define JSON_THROW(exception) throw exception #define JSON_TRY try #define JSON_CATCH(exception) catch(exception) diff --git a/src/json.hpp.re2c b/src/json.hpp.re2c index a837df065..2cad18aa4 100644 --- a/src/json.hpp.re2c +++ b/src/json.hpp.re2c @@ -82,7 +82,7 @@ SOFTWARE. #endif // allow to disable exceptions -#if __cpp_exceptions && not defined(JSON_NOEXCEPTION) +#if (__cpp_exceptions || defined(_CPPUNWIND)) && not defined(JSON_NOEXCEPTION) #define JSON_THROW(exception) throw exception #define JSON_TRY try #define JSON_CATCH(exception) catch(exception) From 122afbf1280413ade3719d6af2c37352215e30f0 Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Sat, 11 Mar 2017 18:43:21 +0100 Subject: [PATCH 38/52] :hammer: added defined() check --- src/json.hpp | 2 +- src/json.hpp.re2c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/json.hpp b/src/json.hpp index f9a928202..725310f6d 100644 --- a/src/json.hpp +++ b/src/json.hpp @@ -82,7 +82,7 @@ SOFTWARE. #endif // allow to disable exceptions -#if (__cpp_exceptions || defined(_CPPUNWIND)) && not defined(JSON_NOEXCEPTION) +#if (defined(__cpp_exceptions) || defined(_CPPUNWIND)) && not defined(JSON_NOEXCEPTION) #define JSON_THROW(exception) throw exception #define JSON_TRY try #define JSON_CATCH(exception) catch(exception) diff --git a/src/json.hpp.re2c b/src/json.hpp.re2c index 2cad18aa4..9172d2bfa 100644 --- a/src/json.hpp.re2c +++ b/src/json.hpp.re2c @@ -82,7 +82,7 @@ SOFTWARE. #endif // allow to disable exceptions -#if (__cpp_exceptions || defined(_CPPUNWIND)) && not defined(JSON_NOEXCEPTION) +#if (defined(__cpp_exceptions) || defined(_CPPUNWIND)) && not defined(JSON_NOEXCEPTION) #define JSON_THROW(exception) throw exception #define JSON_TRY try #define JSON_CATCH(exception) catch(exception) From 4b9c2f128740842abb8ba60956778bb59af15bd4 Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Sat, 11 Mar 2017 20:16:13 +0100 Subject: [PATCH 39/52] :hammer: added __EXCEPTIONS to the list --- src/json.hpp | 2 +- src/json.hpp.re2c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/json.hpp b/src/json.hpp index 725310f6d..c7b0154ae 100644 --- a/src/json.hpp +++ b/src/json.hpp @@ -82,7 +82,7 @@ SOFTWARE. #endif // allow to disable exceptions -#if (defined(__cpp_exceptions) || defined(_CPPUNWIND)) && not defined(JSON_NOEXCEPTION) +#if (defined(__cpp_exceptions) || defined(__EXCEPTIONS) || defined(_CPPUNWIND)) && not defined(JSON_NOEXCEPTION) #define JSON_THROW(exception) throw exception #define JSON_TRY try #define JSON_CATCH(exception) catch(exception) diff --git a/src/json.hpp.re2c b/src/json.hpp.re2c index 9172d2bfa..3ee67b1a1 100644 --- a/src/json.hpp.re2c +++ b/src/json.hpp.re2c @@ -82,7 +82,7 @@ SOFTWARE. #endif // allow to disable exceptions -#if (defined(__cpp_exceptions) || defined(_CPPUNWIND)) && not defined(JSON_NOEXCEPTION) +#if (defined(__cpp_exceptions) || defined(__EXCEPTIONS) || defined(_CPPUNWIND)) && not defined(JSON_NOEXCEPTION) #define JSON_THROW(exception) throw exception #define JSON_TRY try #define JSON_CATCH(exception) catch(exception) From 01470f388b496050be164b9fe6bcc613d1203109 Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Sun, 12 Mar 2017 11:04:26 +0100 Subject: [PATCH 40/52] :construction_worker: fixed no_exceptions test case This test case relied on logics that have been replaced by CMake with #461. This change enables compilation and execution of the test suite without exceptions by adding an after_success task. --- .travis.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index c3cba69e6..5060b728f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -78,13 +78,13 @@ matrix: env: - COMPILER=g++-4.9 - SPECIAL=no_exceptions - - TEST_PATTERN=-e \"*\" addons: apt: sources: ['ubuntu-toolchain-r-test'] packages: [g++-4.9, cppcheck] - before_script: - - CPPFLAGS="-DJSON_NOEXCEPTION" make + after_success: + - make clean + - CPPFLAGS="-DJSON_NOEXCEPTION" make check TEST_PATTERN=-e \"*\"" # Coveralls (http://gronlier.fr/blog/2015/01/adding-code-coverage-to-your-c-project/) From e3e941ef2b9a5405cff77c64e52b3c5f20567029 Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Sun, 12 Mar 2017 11:19:27 +0100 Subject: [PATCH 41/52] :construction_worker: fixed a syntax error --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 5060b728f..dcf7b6a29 100644 --- a/.travis.yml +++ b/.travis.yml @@ -84,7 +84,7 @@ matrix: packages: [g++-4.9, cppcheck] after_success: - make clean - - CPPFLAGS="-DJSON_NOEXCEPTION" make check TEST_PATTERN=-e \"*\"" + - CPPFLAGS="-DJSON_NOEXCEPTION" make check TEST_PATTERN="-e \"*\"" # Coveralls (http://gronlier.fr/blog/2015/01/adding-code-coverage-to-your-c-project/) From 28dbe4e6515f4160184bf9d19496fa5682d0b2fc Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Sun, 12 Mar 2017 13:49:39 +0100 Subject: [PATCH 42/52] :memo: overworked documentation for the at functions Added all possible exceptions to the examples of the at functions. --- doc/examples/at__object_t_key_type | Bin 130960 -> 0 bytes doc/examples/at__object_t_key_type.cpp | 16 ++- doc/examples/at__object_t_key_type.link | 2 +- doc/examples/at__object_t_key_type.output | 1 + doc/examples/at__object_t_key_type_const.cpp | 16 ++- doc/examples/at__object_t_key_type_const.link | 2 +- .../at__object_t_key_type_const.output | 1 + doc/examples/at__size_type.cpp | 16 ++- doc/examples/at__size_type.link | 2 +- doc/examples/at__size_type.output | 1 + doc/examples/at__size_type_const.cpp | 20 +++- doc/examples/at__size_type_const.link | 2 +- doc/examples/at__size_type_const.output | 1 + doc/examples/at_json_pointer.cpp | 50 ++++++++- doc/examples/at_json_pointer.link | 2 +- doc/examples/at_json_pointer.output | 4 + doc/examples/at_json_pointer_const.cpp | 40 ++++++- doc/examples/at_json_pointer_const.link | 2 +- doc/examples/at_json_pointer_const.output | 3 + src/json.hpp | 104 +++++++++++------- src/json.hpp.re2c | 104 +++++++++++------- 21 files changed, 296 insertions(+), 93 deletions(-) delete mode 100755 doc/examples/at__object_t_key_type diff --git a/doc/examples/at__object_t_key_type b/doc/examples/at__object_t_key_type deleted file mode 100755 index 03f48e68ca3efe94e36855f9d69bd72b6854b4ff..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 130960 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 JywMTA{}1@W;O+nb diff --git a/doc/examples/at__object_t_key_type.cpp b/doc/examples/at__object_t_key_type.cpp index a66bd9a3d..7797418f4 100644 --- a/doc/examples/at__object_t_key_type.cpp +++ b/doc/examples/at__object_t_key_type.cpp @@ -21,9 +21,23 @@ int main() // output changed array std::cout << object << '\n'; - // try to write at a nonexisting key + + // exception type_error.304 try { + // use at() on a non-object type + json str = "I am a string"; + str.at("the good") = "Another string"; + } + catch (json::type_error& e) + { + std::cout << e.what() << '\n'; + } + + // exception out_of_range.401 + try + { + // try to write at a nonexisting key object.at("the fast") = "il rapido"; } catch (json::out_of_range& e) diff --git a/doc/examples/at__object_t_key_type.link b/doc/examples/at__object_t_key_type.link index 1cb99d461..8874783bd 100644 --- a/doc/examples/at__object_t_key_type.link +++ b/doc/examples/at__object_t_key_type.link @@ -1 +1 @@ -online \ No newline at end of file +online \ No newline at end of file diff --git a/doc/examples/at__object_t_key_type.output b/doc/examples/at__object_t_key_type.output index 654b9eb63..b544b7299 100644 --- a/doc/examples/at__object_t_key_type.output +++ b/doc/examples/at__object_t_key_type.output @@ -1,3 +1,4 @@ "il brutto" {"the bad":"il cattivo","the good":"il buono","the ugly":"il brutto"} +[json.exception.type_error.304] cannot use at() with string [json.exception.out_of_range.403] key 'the fast' not found diff --git a/doc/examples/at__object_t_key_type_const.cpp b/doc/examples/at__object_t_key_type_const.cpp index 99eb6f013..f60424041 100644 --- a/doc/examples/at__object_t_key_type_const.cpp +++ b/doc/examples/at__object_t_key_type_const.cpp @@ -15,9 +15,23 @@ int main() // output element with key "the ugly" std::cout << object.at("the ugly") << '\n'; - // try to read from a nonexisting key + + // exception type_error.304 try { + // use at() on a non-object type + const json str = "I am a string"; + std::cout << str.at("the good") << '\n'; + } + catch (json::type_error& e) + { + std::cout << e.what() << '\n'; + } + + // exception out_of_range.401 + try + { + // try to read from a nonexisting key std::cout << object.at("the fast") << '\n'; } catch (json::out_of_range) diff --git a/doc/examples/at__object_t_key_type_const.link b/doc/examples/at__object_t_key_type_const.link index a07dbd594..cd8594e66 100644 --- a/doc/examples/at__object_t_key_type_const.link +++ b/doc/examples/at__object_t_key_type_const.link @@ -1 +1 @@ -online \ No newline at end of file +online \ No newline at end of file diff --git a/doc/examples/at__object_t_key_type_const.output b/doc/examples/at__object_t_key_type_const.output index b3dd11d35..40ca3f09f 100644 --- a/doc/examples/at__object_t_key_type_const.output +++ b/doc/examples/at__object_t_key_type_const.output @@ -1,2 +1,3 @@ "il brutto" +[json.exception.type_error.304] cannot use at() with string out of range diff --git a/doc/examples/at__size_type.cpp b/doc/examples/at__size_type.cpp index 07e363ab3..28def1dd2 100644 --- a/doc/examples/at__size_type.cpp +++ b/doc/examples/at__size_type.cpp @@ -16,9 +16,23 @@ int main() // output changed array std::cout << array << '\n'; - // try to write beyond the array limit + + // exception type_error.304 try { + // use at() on a non-array type + json str = "I am a string"; + str.at(0) = "Another string"; + } + catch (json::type_error& e) + { + std::cout << e.what() << '\n'; + } + + // exception out_of_range.401 + try + { + // try to write beyond the array limit array.at(5) = "sixth"; } catch (json::out_of_range& e) diff --git a/doc/examples/at__size_type.link b/doc/examples/at__size_type.link index 78ec0ca02..cba0fa00f 100644 --- a/doc/examples/at__size_type.link +++ b/doc/examples/at__size_type.link @@ -1 +1 @@ -online \ No newline at end of file +online \ No newline at end of file diff --git a/doc/examples/at__size_type.output b/doc/examples/at__size_type.output index 4f0c9e54f..54026436f 100644 --- a/doc/examples/at__size_type.output +++ b/doc/examples/at__size_type.output @@ -1,3 +1,4 @@ "third" ["first","second","third","fourth"] +[json.exception.type_error.304] cannot use at() with string [json.exception.out_of_range.401] array index 5 is out of range diff --git a/doc/examples/at__size_type_const.cpp b/doc/examples/at__size_type_const.cpp index 88d28be6f..213d22fd6 100644 --- a/doc/examples/at__size_type_const.cpp +++ b/doc/examples/at__size_type_const.cpp @@ -5,17 +5,31 @@ using json = nlohmann::json; int main() { // create JSON array - json array = {"first", "2nd", "third", "fourth"}; + const json array = {"first", "2nd", "third", "fourth"}; // output element at index 2 (third element) std::cout << array.at(2) << '\n'; - // try to read beyond the array limit + + // exception type_error.304 try { + // use at() on a non-array type + const json str = "I am a string"; + std::cout << str.at(0) << '\n'; + } + catch (json::type_error& e) + { + std::cout << e.what() << '\n'; + } + + // exception out_of_range.401 + try + { + // try to read beyond the array limit std::cout << array.at(5) << '\n'; } - catch (const json::out_of_range& e) + catch (json::out_of_range& e) { std::cout << e.what() << '\n'; } diff --git a/doc/examples/at__size_type_const.link b/doc/examples/at__size_type_const.link index c703c5d97..ce3647aca 100644 --- a/doc/examples/at__size_type_const.link +++ b/doc/examples/at__size_type_const.link @@ -1 +1 @@ -online \ No newline at end of file +online \ No newline at end of file diff --git a/doc/examples/at__size_type_const.output b/doc/examples/at__size_type_const.output index e52b6cc0b..8135a27a5 100644 --- a/doc/examples/at__size_type_const.output +++ b/doc/examples/at__size_type_const.output @@ -1,2 +1,3 @@ "third" +[json.exception.type_error.304] cannot use at() with string [json.exception.out_of_range.401] array index 5 is out of range diff --git a/doc/examples/at_json_pointer.cpp b/doc/examples/at_json_pointer.cpp index 6d1617e65..3ef91282a 100644 --- a/doc/examples/at_json_pointer.cpp +++ b/doc/examples/at_json_pointer.cpp @@ -33,10 +33,56 @@ int main() // output the changed array std::cout << j["array"] << '\n'; - // try to use an invalid JSON pointer + + // out_of_range.106 try { - auto ref = j.at("/number/foo"_json_pointer); + // try to use an array index with leading '0' + json::reference ref = j.at("/array/01"_json_pointer); + } + catch (json::parse_error& e) + { + std::cout << e.what() << '\n'; + } + + // out_of_range.109 + try + { + // try to use an array index that is not a number + json::reference ref = j.at("/array/one"_json_pointer); + } + catch (json::parse_error& e) + { + std::cout << e.what() << '\n'; + } + + // out_of_range.401 + try + { + // try to use a an invalid array index + json::reference ref = j.at("/array/4"_json_pointer); + } + catch (json::out_of_range& e) + { + std::cout << e.what() << '\n'; + } + + // out_of_range.402 + try + { + // try to use the array index '-' + json::reference ref = j.at("/array/-"_json_pointer); + } + catch (json::out_of_range& e) + { + std::cout << e.what() << '\n'; + } + + // out_of_range.404 + try + { + // try to use a JSON pointer that cannot be resolved + json::reference ref = j.at("/number/foo"_json_pointer); } catch (json::out_of_range& e) { diff --git a/doc/examples/at_json_pointer.link b/doc/examples/at_json_pointer.link index 454023032..c8563ec20 100644 --- a/doc/examples/at_json_pointer.link +++ b/doc/examples/at_json_pointer.link @@ -1 +1 @@ -online \ No newline at end of file +online \ No newline at end of file diff --git a/doc/examples/at_json_pointer.output b/doc/examples/at_json_pointer.output index a45737ad2..505792f2a 100644 --- a/doc/examples/at_json_pointer.output +++ b/doc/examples/at_json_pointer.output @@ -4,4 +4,8 @@ 2 "bar" [1,21] +[json.exception.parse_error.106] parse error: array index '01' must not begin with '0' +[json.exception.parse_error.109] parse error: array index 'one' is not a number +[json.exception.out_of_range.401] array index 4 is out of range +[json.exception.out_of_range.402] array index '-' (2) is out of range [json.exception.out_of_range.404] unresolved reference token 'foo' diff --git a/doc/examples/at_json_pointer_const.cpp b/doc/examples/at_json_pointer_const.cpp index dab1b39c4..a1d065f23 100644 --- a/doc/examples/at_json_pointer_const.cpp +++ b/doc/examples/at_json_pointer_const.cpp @@ -5,7 +5,7 @@ using json = nlohmann::json; int main() { // create a JSON value - json j = + const json j = { {"number", 1}, {"string", "foo"}, {"array", {1, 2}} }; @@ -21,10 +21,44 @@ int main() // output element with JSON pointer "/array/1" std::cout << j.at("/array/1"_json_pointer) << '\n'; - // try to use an invalid JSON pointer + // out_of_range.109 try { - auto ref = j.at("/number/foo"_json_pointer); + // try to use an array index that is not a number + json::const_reference ref = j.at("/array/one"_json_pointer); + } + catch (json::parse_error& e) + { + std::cout << e.what() << '\n'; + } + + // out_of_range.401 + try + { + // try to use a an invalid array index + json::const_reference ref = j.at("/array/4"_json_pointer); + } + catch (json::out_of_range& e) + { + std::cout << e.what() << '\n'; + } + + // out_of_range.402 + try + { + // try to use the array index '-' + json::const_reference ref = j.at("/array/-"_json_pointer); + } + catch (json::out_of_range& e) + { + std::cout << e.what() << '\n'; + } + + // out_of_range.404 + try + { + // try to use a JSON pointer that cannot be resolved + json::const_reference ref = j.at("/number/foo"_json_pointer); } catch (json::out_of_range& e) { diff --git a/doc/examples/at_json_pointer_const.link b/doc/examples/at_json_pointer_const.link index 70e7cf868..f421faf45 100644 --- a/doc/examples/at_json_pointer_const.link +++ b/doc/examples/at_json_pointer_const.link @@ -1 +1 @@ -online \ No newline at end of file +online \ No newline at end of file diff --git a/doc/examples/at_json_pointer_const.output b/doc/examples/at_json_pointer_const.output index 21712e867..b3361f04b 100644 --- a/doc/examples/at_json_pointer_const.output +++ b/doc/examples/at_json_pointer_const.output @@ -2,4 +2,7 @@ "foo" [1,2] 2 +[json.exception.parse_error.109] parse error: array index 'one' is not a number +[json.exception.out_of_range.401] array index 4 is out of range +[json.exception.out_of_range.402] array index '-' (2) is out of range [json.exception.out_of_range.404] unresolved reference token 'foo' diff --git a/src/json.hpp b/src/json.hpp index 605d6aa56..7f31377f0 100644 --- a/src/json.hpp +++ b/src/json.hpp @@ -3723,16 +3723,20 @@ class basic_json @return reference to the element at index @a idx @throw type_error.304 if the JSON value is not an array; in this case, - calling `at` with an index makes no sense. + calling `at` with an index makes no sense. See example below. @throw out_of_range.401 if the index @a idx is out of range of the array; - that is, `idx >= size()`; see example below. + that is, `idx >= size()`. See example below. + + @exceptionsafety Strong guarantee: if an exception is thrown, there are no + changes in the JSON value. @complexity Constant. - @liveexample{The example below shows how array elements can be read and - written using `at()`.,at__size_type} - @since version 1.0.0 + + @liveexample{The example below shows how array elements can be read and + written using `at()`. It also demonstrates the different exceptions that + can be thrown.,at__size_type} */ reference at(size_type idx) { @@ -3766,16 +3770,20 @@ class basic_json @return const reference to the element at index @a idx @throw type_error.304 if the JSON value is not an array; in this case, - calling `at` with an index makes no sense. + calling `at` with an index makes no sense. See example below. @throw out_of_range.401 if the index @a idx is out of range of the array; - that is, `idx >= size()`; see example below. + that is, `idx >= size()`. See example below. + + @exceptionsafety Strong guarantee: if an exception is thrown, there are no + changes in the JSON value. @complexity Constant. - @liveexample{The example below shows how array elements can be read using - `at()`.,at__size_type_const} - @since version 1.0.0 + + @liveexample{The example below shows how array elements can be read using + `at()`. It also demonstrates the different exceptions that can be thrown., + at__size_type_const} */ const_reference at(size_type idx) const { @@ -3809,20 +3817,24 @@ class basic_json @return reference to the element at key @a key @throw type_error.304 if the JSON value is not an object; in this case, - calling `at` with a key makes no sense. + calling `at` with a key makes no sense. See example below. @throw out_of_range.403 if the key @a key is is not stored in the object; - that is, `find(key) == end()`; see example below. + that is, `find(key) == end()`. See example below. + + @exceptionsafety Strong guarantee: if an exception is thrown, there are no + changes in the JSON value. @complexity Logarithmic in the size of the container. - @liveexample{The example below shows how object elements can be read and - written using `at()`.,at__object_t_key_type} - @sa @ref operator[](const typename object_t::key_type&) for unchecked access by reference @sa @ref value() for access by value with a default value @since version 1.0.0 + + @liveexample{The example below shows how object elements can be read and + written using `at()`. It also demonstrates the different exceptions that + can be thrown.,at__object_t_key_type} */ reference at(const typename object_t::key_type& key) { @@ -3856,20 +3868,24 @@ class basic_json @return const reference to the element at key @a key @throw type_error.304 if the JSON value is not an object; in this case, - calling `at` with a key makes no sense. + calling `at` with a key makes no sense. See example below. @throw out_of_range.403 if the key @a key is is not stored in the object; - that is, `find(key) == end()`; see example below. + that is, `find(key) == end()`. See example below. + + @exceptionsafety Strong guarantee: if an exception is thrown, there are no + changes in the JSON value. @complexity Logarithmic in the size of the container. - @liveexample{The example below shows how object elements can be read using - `at()`.,at__object_t_key_type_const} - @sa @ref operator[](const typename object_t::key_type&) for unchecked access by reference @sa @ref value() for access by value with a default value @since version 1.0.0 + + @liveexample{The example below shows how object elements can be read using + `at()`. It also demonstrates the different exceptions that can be thrown., + at__object_t_key_type_const} */ const_reference at(const typename object_t::key_type& key) const { @@ -12791,24 +12807,30 @@ basic_json_parser_74: @return reference to the element pointed to by @a ptr - @complexity Constant. - @throw parse_error.106 if an array index in the passed JSON pointer @a ptr - begins with '0' + begins with '0'. See example below. @throw parse_error.109 if an array index in the passed JSON pointer @a ptr - is not a number + is not a number. See example below. - @throw out_of_range.402 if the array index `-` is used in the passed JSON + @throw out_of_range.401 if an array index in the passed JSON pointer @a ptr + is out of range. See example below. + + @throw out_of_range.402 if the array index '-' is used in the passed JSON pointer @a ptr. As `at` provides checked access (and no elements are - implicitly inserted), the index `-` is always invalid. + implicitly inserted), the index '-' is always invalid. See example below. - @throw out_of_range.404 if the JSON pointer @a ptr can not be resolved; - see example below. + @throw out_of_range.404 if the JSON pointer @a ptr can not be resolved. + See example below. - @liveexample{The behavior is shown in the example.,at_json_pointer} + @exceptionsafety Strong guarantee: if an exception is thrown, there are no + changes in the JSON value. + + @complexity Constant. @since version 2.0.0 + + @liveexample{The behavior is shown in the example.,at_json_pointer} */ reference at(const json_pointer& ptr) { @@ -12825,24 +12847,30 @@ basic_json_parser_74: @return reference to the element pointed to by @a ptr - @complexity Constant. - @throw parse_error.106 if an array index in the passed JSON pointer @a ptr - begins with '0' + begins with '0'. See example below. @throw parse_error.109 if an array index in the passed JSON pointer @a ptr - is not a number + is not a number. See example below. - @throw out_of_range.402 if the array index `-` is used in the passed JSON + @throw out_of_range.401 if an array index in the passed JSON pointer @a ptr + is out of range. See example below. + + @throw out_of_range.402 if the array index '-' is used in the passed JSON pointer @a ptr. As `at` provides checked access (and no elements are - implicitly inserted), the index `-` is always invalid. + implicitly inserted), the index '-' is always invalid. See example below. - @throw out_of_range.404 if the JSON pointer @a ptr can not be resolved; - see example below. + @throw out_of_range.404 if the JSON pointer @a ptr can not be resolved. + See example below. - @liveexample{The behavior is shown in the example.,at_json_pointer_const} + @exceptionsafety Strong guarantee: if an exception is thrown, there are no + changes in the JSON value. + + @complexity Constant. @since version 2.0.0 + + @liveexample{The behavior is shown in the example.,at_json_pointer_const} */ const_reference at(const json_pointer& ptr) const { diff --git a/src/json.hpp.re2c b/src/json.hpp.re2c index 2bd2fd763..48111521e 100644 --- a/src/json.hpp.re2c +++ b/src/json.hpp.re2c @@ -3723,16 +3723,20 @@ class basic_json @return reference to the element at index @a idx @throw type_error.304 if the JSON value is not an array; in this case, - calling `at` with an index makes no sense. + calling `at` with an index makes no sense. See example below. @throw out_of_range.401 if the index @a idx is out of range of the array; - that is, `idx >= size()`; see example below. + that is, `idx >= size()`. See example below. + + @exceptionsafety Strong guarantee: if an exception is thrown, there are no + changes in the JSON value. @complexity Constant. - @liveexample{The example below shows how array elements can be read and - written using `at()`.,at__size_type} - @since version 1.0.0 + + @liveexample{The example below shows how array elements can be read and + written using `at()`. It also demonstrates the different exceptions that + can be thrown.,at__size_type} */ reference at(size_type idx) { @@ -3766,16 +3770,20 @@ class basic_json @return const reference to the element at index @a idx @throw type_error.304 if the JSON value is not an array; in this case, - calling `at` with an index makes no sense. + calling `at` with an index makes no sense. See example below. @throw out_of_range.401 if the index @a idx is out of range of the array; - that is, `idx >= size()`; see example below. + that is, `idx >= size()`. See example below. + + @exceptionsafety Strong guarantee: if an exception is thrown, there are no + changes in the JSON value. @complexity Constant. - @liveexample{The example below shows how array elements can be read using - `at()`.,at__size_type_const} - @since version 1.0.0 + + @liveexample{The example below shows how array elements can be read using + `at()`. It also demonstrates the different exceptions that can be thrown., + at__size_type_const} */ const_reference at(size_type idx) const { @@ -3809,20 +3817,24 @@ class basic_json @return reference to the element at key @a key @throw type_error.304 if the JSON value is not an object; in this case, - calling `at` with a key makes no sense. + calling `at` with a key makes no sense. See example below. @throw out_of_range.403 if the key @a key is is not stored in the object; - that is, `find(key) == end()`; see example below. + that is, `find(key) == end()`. See example below. + + @exceptionsafety Strong guarantee: if an exception is thrown, there are no + changes in the JSON value. @complexity Logarithmic in the size of the container. - @liveexample{The example below shows how object elements can be read and - written using `at()`.,at__object_t_key_type} - @sa @ref operator[](const typename object_t::key_type&) for unchecked access by reference @sa @ref value() for access by value with a default value @since version 1.0.0 + + @liveexample{The example below shows how object elements can be read and + written using `at()`. It also demonstrates the different exceptions that + can be thrown.,at__object_t_key_type} */ reference at(const typename object_t::key_type& key) { @@ -3856,20 +3868,24 @@ class basic_json @return const reference to the element at key @a key @throw type_error.304 if the JSON value is not an object; in this case, - calling `at` with a key makes no sense. + calling `at` with a key makes no sense. See example below. @throw out_of_range.403 if the key @a key is is not stored in the object; - that is, `find(key) == end()`; see example below. + that is, `find(key) == end()`. See example below. + + @exceptionsafety Strong guarantee: if an exception is thrown, there are no + changes in the JSON value. @complexity Logarithmic in the size of the container. - @liveexample{The example below shows how object elements can be read using - `at()`.,at__object_t_key_type_const} - @sa @ref operator[](const typename object_t::key_type&) for unchecked access by reference @sa @ref value() for access by value with a default value @since version 1.0.0 + + @liveexample{The example below shows how object elements can be read using + `at()`. It also demonstrates the different exceptions that can be thrown., + at__object_t_key_type_const} */ const_reference at(const typename object_t::key_type& key) const { @@ -11824,24 +11840,30 @@ class basic_json @return reference to the element pointed to by @a ptr - @complexity Constant. - @throw parse_error.106 if an array index in the passed JSON pointer @a ptr - begins with '0' + begins with '0'. See example below. @throw parse_error.109 if an array index in the passed JSON pointer @a ptr - is not a number + is not a number. See example below. - @throw out_of_range.402 if the array index `-` is used in the passed JSON + @throw out_of_range.401 if an array index in the passed JSON pointer @a ptr + is out of range. See example below. + + @throw out_of_range.402 if the array index '-' is used in the passed JSON pointer @a ptr. As `at` provides checked access (and no elements are - implicitly inserted), the index `-` is always invalid. + implicitly inserted), the index '-' is always invalid. See example below. - @throw out_of_range.404 if the JSON pointer @a ptr can not be resolved; - see example below. + @throw out_of_range.404 if the JSON pointer @a ptr can not be resolved. + See example below. - @liveexample{The behavior is shown in the example.,at_json_pointer} + @exceptionsafety Strong guarantee: if an exception is thrown, there are no + changes in the JSON value. + + @complexity Constant. @since version 2.0.0 + + @liveexample{The behavior is shown in the example.,at_json_pointer} */ reference at(const json_pointer& ptr) { @@ -11858,24 +11880,30 @@ class basic_json @return reference to the element pointed to by @a ptr - @complexity Constant. - @throw parse_error.106 if an array index in the passed JSON pointer @a ptr - begins with '0' + begins with '0'. See example below. @throw parse_error.109 if an array index in the passed JSON pointer @a ptr - is not a number + is not a number. See example below. - @throw out_of_range.402 if the array index `-` is used in the passed JSON + @throw out_of_range.401 if an array index in the passed JSON pointer @a ptr + is out of range. See example below. + + @throw out_of_range.402 if the array index '-' is used in the passed JSON pointer @a ptr. As `at` provides checked access (and no elements are - implicitly inserted), the index `-` is always invalid. + implicitly inserted), the index '-' is always invalid. See example below. - @throw out_of_range.404 if the JSON pointer @a ptr can not be resolved; - see example below. + @throw out_of_range.404 if the JSON pointer @a ptr can not be resolved. + See example below. - @liveexample{The behavior is shown in the example.,at_json_pointer_const} + @exceptionsafety Strong guarantee: if an exception is thrown, there are no + changes in the JSON value. + + @complexity Constant. @since version 2.0.0 + + @liveexample{The behavior is shown in the example.,at_json_pointer_const} */ const_reference at(const json_pointer& ptr) const { From 80dcf22fc33897ed027d7bd4e687c48bf9148280 Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Sun, 12 Mar 2017 14:39:20 +0100 Subject: [PATCH 43/52] :hammer: added a check function for MsgPack strings #497 To avoid the error described in #497, I added a function msgpack_expect_string that is executed every time a string is expected during the parsing of a map. In case the current byte does not belong to a MsgPack string, an exception is thrown. --- src/json.hpp | 32 ++++++++++++++++++++++++++++++++ src/json.hpp.re2c | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 64 insertions(+) diff --git a/src/json.hpp b/src/json.hpp index f7b832b52..5fdf48522 100644 --- a/src/json.hpp +++ b/src/json.hpp @@ -7748,6 +7748,35 @@ class basic_json } } + /*! + @brief check if the next byte belongs to a string + + While parsing a map, the keys must be strings. This function checks if the + current byte is one of the start bytes for a string in MessagePack: + + - 0xa0 - 0xbf: fixstr + - 0xd9: str 8 + - 0xda: str 16 + - 0xdb: str 32 + + @param[in] v MessagePack serialization + @param[in] idx byte index in @a v to check for a string + + @throw std::invalid_argument if `v[idx]` does not belong to a string + */ + static void msgpack_expect_string(const std::vector& v, size_t idx) + { + check_length(v.size(), 1, idx); + + const auto byte = v[idx]; + if ((byte >= 0xa0 and byte <= 0xbf) or (byte >= 0xd9 and byte <= 0xdb)) + { + return; + } + + JSON_THROW(std::invalid_argument("error parsing a msgpack string @ " + std::to_string(idx) + ": " + std::to_string(static_cast(v[idx])))); + } + /*! @brief create a JSON value from a given MessagePack vector @@ -7782,6 +7811,7 @@ class basic_json const size_t len = v[current_idx] & 0x0f; for (size_t i = 0; i < len; ++i) { + msgpack_expect_string(v, idx); std::string key = from_msgpack_internal(v, idx); result[key] = from_msgpack_internal(v, idx); } @@ -7959,6 +7989,7 @@ class basic_json idx += 2; // skip 2 size bytes for (size_t i = 0; i < len; ++i) { + msgpack_expect_string(v, idx); std::string key = from_msgpack_internal(v, idx); result[key] = from_msgpack_internal(v, idx); } @@ -7972,6 +8003,7 @@ class basic_json idx += 4; // skip 4 size bytes for (size_t i = 0; i < len; ++i) { + msgpack_expect_string(v, idx); std::string key = from_msgpack_internal(v, idx); result[key] = from_msgpack_internal(v, idx); } diff --git a/src/json.hpp.re2c b/src/json.hpp.re2c index 04de67cfa..b3a39d64d 100644 --- a/src/json.hpp.re2c +++ b/src/json.hpp.re2c @@ -7748,6 +7748,35 @@ class basic_json } } + /*! + @brief check if the next byte belongs to a string + + While parsing a map, the keys must be strings. This function checks if the + current byte is one of the start bytes for a string in MessagePack: + + - 0xa0 - 0xbf: fixstr + - 0xd9: str 8 + - 0xda: str 16 + - 0xdb: str 32 + + @param[in] v MessagePack serialization + @param[in] idx byte index in @a v to check for a string + + @throw std::invalid_argument if `v[idx]` does not belong to a string + */ + static void msgpack_expect_string(const std::vector& v, size_t idx) + { + check_length(v.size(), 1, idx); + + const auto byte = v[idx]; + if ((byte >= 0xa0 and byte <= 0xbf) or (byte >= 0xd9 and byte <= 0xdb)) + { + return; + } + + JSON_THROW(std::invalid_argument("error parsing a msgpack string @ " + std::to_string(idx) + ": " + std::to_string(static_cast(v[idx])))); + } + /*! @brief create a JSON value from a given MessagePack vector @@ -7782,6 +7811,7 @@ class basic_json const size_t len = v[current_idx] & 0x0f; for (size_t i = 0; i < len; ++i) { + msgpack_expect_string(v, idx); std::string key = from_msgpack_internal(v, idx); result[key] = from_msgpack_internal(v, idx); } @@ -7959,6 +7989,7 @@ class basic_json idx += 2; // skip 2 size bytes for (size_t i = 0; i < len; ++i) { + msgpack_expect_string(v, idx); std::string key = from_msgpack_internal(v, idx); result[key] = from_msgpack_internal(v, idx); } @@ -7972,6 +8003,7 @@ class basic_json idx += 4; // skip 4 size bytes for (size_t i = 0; i < len; ++i) { + msgpack_expect_string(v, idx); std::string key = from_msgpack_internal(v, idx); result[key] = from_msgpack_internal(v, idx); } From 87eafd8d6af591254646b53265c21f8d7b8d28e8 Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Sun, 12 Mar 2017 15:20:17 +0100 Subject: [PATCH 44/52] :white_check_mark: added regression tests for #473 These tests currently pass without any adjustments to the source code. --- test/src/unit-regression.cpp | 50 ++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/test/src/unit-regression.cpp b/test/src/unit-regression.cpp index 957d5a25a..7b4086b10 100644 --- a/test/src/unit-regression.cpp +++ b/test/src/unit-regression.cpp @@ -32,6 +32,7 @@ SOFTWARE. using nlohmann::json; #include +#include TEST_CASE("regression tests") { @@ -796,6 +797,55 @@ TEST_CASE("regression tests") CHECK(s1 == s2); } + SECTION("issue #473 - inconsistent behavior in conversion to array type") + { + json j_array = {1, 2, 3, 4}; + json j_number = 42; + json j_null = nullptr; + + SECTION("std::vector") + { + auto create = [](const json & j) + { + std::vector v = j; + }; + + CHECK_NOTHROW(create(j_array)); + CHECK_THROWS_AS(create(j_number), std::domain_error); + CHECK_THROWS_WITH(create(j_number), "type must be array, but is number"); + CHECK_THROWS_AS(create(j_null), std::domain_error); + CHECK_THROWS_WITH(create(j_null), "type must be array, but is null"); + } + + SECTION("std::list") + { + auto create = [](const json & j) + { + std::list v = j; + }; + + CHECK_NOTHROW(create(j_array)); + CHECK_THROWS_AS(create(j_number), std::domain_error); + CHECK_THROWS_WITH(create(j_number), "type must be array, but is number"); + CHECK_THROWS_AS(create(j_null), std::domain_error); + CHECK_THROWS_WITH(create(j_null), "type must be array, but is null"); + } + + SECTION("std::forward_list") + { + auto create = [](const json & j) + { + std::forward_list v = j; + }; + + CHECK_NOTHROW(create(j_array)); + CHECK_THROWS_AS(create(j_number), std::domain_error); + CHECK_THROWS_WITH(create(j_number), "type must be array, but is number"); + CHECK_THROWS_AS(create(j_null), std::domain_error); + CHECK_THROWS_WITH(create(j_null), "type must be array, but is null"); + } + } + SECTION("issue #486 - json::value_t can't be a map's key type in VC++ 2015") { // the code below must compile with MSVC From 9355f0588817683d918b35c6366a9193a3e9e331 Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Sun, 12 Mar 2017 17:05:02 +0100 Subject: [PATCH 45/52] :hammer: cleaned up array from_json methods #473 Removed some code that is not needed any more. Thus, streamlining the array from_json methods. --- src/json.hpp | 30 ++++++++---------------------- src/json.hpp.re2c | 30 ++++++++---------------------- 2 files changed, 16 insertions(+), 44 deletions(-) diff --git a/src/json.hpp b/src/json.hpp index 5fdf48522..ebca577f4 100644 --- a/src/json.hpp +++ b/src/json.hpp @@ -700,22 +700,15 @@ void from_json(const BasicJsonType& j, typename BasicJsonType::array_t& arr) } // forward_list doesn't have an insert method -template +template::value, int> = 0> void from_json(const BasicJsonType& j, std::forward_list& l) { - // do not perform the check when user wants to retrieve jsons - // (except when it's null.. ?) - if (j.is_null()) + if (not j.is_array()) { JSON_THROW(std::domain_error("type must be array, but is " + j.type_name())); } - if (not std::is_same::value) - { - if (not j.is_array()) - { - JSON_THROW(std::domain_error("type must be array, but is " + j.type_name())); - } - } + for (auto it = j.rbegin(), end = j.rend(); it != end; ++it) { l.push_front(it->template get()); @@ -747,8 +740,8 @@ auto from_json_array_impl(const BasicJsonType& j, CompatibleArrayType& arr, prio using std::end; arr.reserve(j.size()); - std::transform( - j.begin(), j.end(), std::inserter(arr, end(arr)), [](const BasicJsonType & i) + std::transform(j.begin(), j.end(), + std::inserter(arr, end(arr)), [](const BasicJsonType & i) { // get() returns *this, this won't call a from_json // method when value_type is BasicJsonType @@ -758,22 +751,15 @@ auto from_json_array_impl(const BasicJsonType& j, CompatibleArrayType& arr, prio template::value and + std::is_convertible::value and not std::is_same::value, int> = 0> void from_json(const BasicJsonType& j, CompatibleArrayType& arr) { - if (j.is_null()) + if (not j.is_array()) { JSON_THROW(std::domain_error("type must be array, but is " + j.type_name())); } - // when T == BasicJsonType, do not check if value_t is correct - if (not std::is_same::value) - { - if (not j.is_array()) - { - JSON_THROW(std::domain_error("type must be array, but is " + j.type_name())); - } - } from_json_array_impl(j, arr, priority_tag<1> {}); } diff --git a/src/json.hpp.re2c b/src/json.hpp.re2c index b3a39d64d..bdbd806db 100644 --- a/src/json.hpp.re2c +++ b/src/json.hpp.re2c @@ -700,22 +700,15 @@ void from_json(const BasicJsonType& j, typename BasicJsonType::array_t& arr) } // forward_list doesn't have an insert method -template +template::value, int> = 0> void from_json(const BasicJsonType& j, std::forward_list& l) { - // do not perform the check when user wants to retrieve jsons - // (except when it's null.. ?) - if (j.is_null()) + if (not j.is_array()) { JSON_THROW(std::domain_error("type must be array, but is " + j.type_name())); } - if (not std::is_same::value) - { - if (not j.is_array()) - { - JSON_THROW(std::domain_error("type must be array, but is " + j.type_name())); - } - } + for (auto it = j.rbegin(), end = j.rend(); it != end; ++it) { l.push_front(it->template get()); @@ -747,8 +740,8 @@ auto from_json_array_impl(const BasicJsonType& j, CompatibleArrayType& arr, prio using std::end; arr.reserve(j.size()); - std::transform( - j.begin(), j.end(), std::inserter(arr, end(arr)), [](const BasicJsonType & i) + std::transform(j.begin(), j.end(), + std::inserter(arr, end(arr)), [](const BasicJsonType & i) { // get() returns *this, this won't call a from_json // method when value_type is BasicJsonType @@ -758,22 +751,15 @@ auto from_json_array_impl(const BasicJsonType& j, CompatibleArrayType& arr, prio template::value and + std::is_convertible::value and not std::is_same::value, int> = 0> void from_json(const BasicJsonType& j, CompatibleArrayType& arr) { - if (j.is_null()) + if (not j.is_array()) { JSON_THROW(std::domain_error("type must be array, but is " + j.type_name())); } - // when T == BasicJsonType, do not check if value_t is correct - if (not std::is_same::value) - { - if (not j.is_array()) - { - JSON_THROW(std::domain_error("type must be array, but is " + j.type_name())); - } - } from_json_array_impl(j, arr, priority_tag<1> {}); } From 8feaf8dc94a88393510637af36a24163c95a1b45 Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Sun, 12 Mar 2017 18:38:05 +0100 Subject: [PATCH 46/52] :boom: implemented new handling of NaN and INF #70 #329 #388 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - If an overflow occurs during parsing a number from a JSON text, an exception (std::out_of_range for the moment, to be replaced by a user-defined exception #244) is thrown so that the overflow is detected early and roundtripping is guaranteed. - NaN and INF floating-point values can be stored in a JSON value and are not replaced by null. That is, the basic_json class behaves like double in this regard (no exception occurs). However, NaN and INF are serialized to “null”. - Adjusted test cases appropriately. --- src/json.hpp | 24 +++++++++++------------ src/json.hpp.re2c | 24 +++++++++++------------ test/src/unit-cbor.cpp | 15 ++++++++++----- test/src/unit-class_parser.cpp | 4 +++- test/src/unit-constructor1.cpp | 12 +++++++++--- test/src/unit-msgpack.cpp | 6 +++--- test/src/unit-regression.cpp | 35 ++++++++++++++++++++++++++++++++-- test/src/unit-testsuites.cpp | 26 +++++++++++++++++++------ 8 files changed, 100 insertions(+), 46 deletions(-) diff --git a/src/json.hpp b/src/json.hpp index ebca577f4..42a07f872 100644 --- a/src/json.hpp +++ b/src/json.hpp @@ -263,16 +263,8 @@ struct external_constructor template static void construct(BasicJsonType& j, typename BasicJsonType::number_float_t val) noexcept { - // replace infinity and NAN by null - if (not std::isfinite(val)) - { - j = BasicJsonType{}; - } - else - { - j.m_type = value_t::number_float; - j.m_value = val; - } + j.m_type = value_t::number_float; + j.m_value = val; j.assert_invariant(); } }; @@ -6653,6 +6645,13 @@ class basic_json */ void dump_float(number_float_t x) { + // NaN / inf + if (not std::isfinite(x) or std::isnan(x)) + { + o.write("null", 4); + return; + } + // special case for 0.0 and -0.0 if (x == 0) { @@ -11425,11 +11424,10 @@ basic_json_parser_74: result.m_type = value_t::number_float; result.m_value = val; - // replace infinity and NAN by null + // throw in case of infinity or NAN if (not std::isfinite(result.m_value.number_float)) { - result.m_type = value_t::null; - result.m_value = basic_json::json_value(); + JSON_THROW(std::out_of_range("number overflow: " + get_token_string())); } return true; diff --git a/src/json.hpp.re2c b/src/json.hpp.re2c index bdbd806db..042e3ab7d 100644 --- a/src/json.hpp.re2c +++ b/src/json.hpp.re2c @@ -263,16 +263,8 @@ struct external_constructor template static void construct(BasicJsonType& j, typename BasicJsonType::number_float_t val) noexcept { - // replace infinity and NAN by null - if (not std::isfinite(val)) - { - j = BasicJsonType{}; - } - else - { - j.m_type = value_t::number_float; - j.m_value = val; - } + j.m_type = value_t::number_float; + j.m_value = val; j.assert_invariant(); } }; @@ -6653,6 +6645,13 @@ class basic_json */ void dump_float(number_float_t x) { + // NaN / inf + if (not std::isfinite(x) or std::isnan(x)) + { + o.write("null", 4); + return; + } + // special case for 0.0 and -0.0 if (x == 0) { @@ -10459,11 +10458,10 @@ class basic_json result.m_type = value_t::number_float; result.m_value = val; - // replace infinity and NAN by null + // throw in case of infinity or NAN if (not std::isfinite(result.m_value.number_float)) { - result.m_type = value_t::null; - result.m_value = basic_json::json_value(); + JSON_THROW(std::out_of_range("number overflow: " + get_token_string())); } return true; diff --git a/test/src/unit-cbor.cpp b/test/src/unit-cbor.cpp index 84b280bc9..d313727d7 100644 --- a/test/src/unit-cbor.cpp +++ b/test/src/unit-cbor.cpp @@ -33,6 +33,7 @@ SOFTWARE. using nlohmann::json; #include +#include TEST_CASE("CBOR") { @@ -744,13 +745,17 @@ TEST_CASE("CBOR") SECTION("infinity") { json j = json::from_cbor(std::vector({0xf9, 0x7c, 0x00})); - CHECK(j == nullptr); + json::number_float_t d = j; + CHECK(not std::isfinite(d)); + CHECK(j.dump() == "null"); } SECTION("NaN") { json j = json::from_cbor(std::vector({0xf9, 0x7c, 0x01})); - CHECK(j == nullptr); + json::number_float_t d = j; + CHECK(std::isnan(d)); + CHECK(j.dump() == "null"); } } } @@ -1344,7 +1349,7 @@ TEST_CASE("CBOR roundtrips", "[hide]") "test/data/nst_json_testsuite/test_parsing/y_number_after_space.json", "test/data/nst_json_testsuite/test_parsing/y_number_double_close_to_zero.json", "test/data/nst_json_testsuite/test_parsing/y_number_double_huge_neg_exp.json", - "test/data/nst_json_testsuite/test_parsing/y_number_huge_exp.json", + //"test/data/nst_json_testsuite/test_parsing/y_number_huge_exp.json", "test/data/nst_json_testsuite/test_parsing/y_number_int_with_exp.json", "test/data/nst_json_testsuite/test_parsing/y_number_minus_zero.json", "test/data/nst_json_testsuite/test_parsing/y_number_negative_int.json", @@ -1356,9 +1361,9 @@ TEST_CASE("CBOR roundtrips", "[hide]") "test/data/nst_json_testsuite/test_parsing/y_number_real_exponent.json", "test/data/nst_json_testsuite/test_parsing/y_number_real_fraction_exponent.json", "test/data/nst_json_testsuite/test_parsing/y_number_real_neg_exp.json", - "test/data/nst_json_testsuite/test_parsing/y_number_real_neg_overflow.json", + //"test/data/nst_json_testsuite/test_parsing/y_number_real_neg_overflow.json", "test/data/nst_json_testsuite/test_parsing/y_number_real_pos_exponent.json", - "test/data/nst_json_testsuite/test_parsing/y_number_real_pos_overflow.json", + //"test/data/nst_json_testsuite/test_parsing/y_number_real_pos_overflow.json", "test/data/nst_json_testsuite/test_parsing/y_number_real_underflow.json", "test/data/nst_json_testsuite/test_parsing/y_number_simple_int.json", "test/data/nst_json_testsuite/test_parsing/y_number_simple_real.json", diff --git a/test/src/unit-class_parser.cpp b/test/src/unit-class_parser.cpp index e3ad3723a..35aafe059 100644 --- a/test/src/unit-class_parser.cpp +++ b/test/src/unit-class_parser.cpp @@ -272,7 +272,9 @@ TEST_CASE("parser class") SECTION("overflow") { - CHECK(json::parser("1.18973e+4932").parse() == json()); + // overflows during parsing yield an exception + CHECK_THROWS_AS(json::parser("1.18973e+4932").parse() == json(), std::out_of_range); + CHECK_THROWS_WITH(json::parser("1.18973e+4932").parse() == json(), "number overflow: 1.18973e+4932"); } SECTION("invalid numbers") diff --git a/test/src/unit-constructor1.cpp b/test/src/unit-constructor1.cpp index 9363f0ba2..3b23d78dc 100644 --- a/test/src/unit-constructor1.cpp +++ b/test/src/unit-constructor1.cpp @@ -702,11 +702,17 @@ TEST_CASE("constructors") SECTION("infinity") { - // infinity is stored as null - // should change in the future: https://github.com/nlohmann/json/issues/388 + // infinity is stored properly, but serialized to null json::number_float_t n(std::numeric_limits::infinity()); json j(n); - CHECK(j.type() == json::value_t::null); + CHECK(j.type() == json::value_t::number_float); + + // check round trip of infinity + json::number_float_t d = j; + CHECK(d == n); + + // check that inf is serialized to null + CHECK(j.dump() == "null"); } } diff --git a/test/src/unit-msgpack.cpp b/test/src/unit-msgpack.cpp index 3a2ae5b15..90b4eb2a7 100644 --- a/test/src/unit-msgpack.cpp +++ b/test/src/unit-msgpack.cpp @@ -1116,7 +1116,7 @@ TEST_CASE("MessagePack roundtrips", "[hide]") "test/data/nst_json_testsuite/test_parsing/y_number_after_space.json", "test/data/nst_json_testsuite/test_parsing/y_number_double_close_to_zero.json", "test/data/nst_json_testsuite/test_parsing/y_number_double_huge_neg_exp.json", - "test/data/nst_json_testsuite/test_parsing/y_number_huge_exp.json", + //"test/data/nst_json_testsuite/test_parsing/y_number_huge_exp.json", "test/data/nst_json_testsuite/test_parsing/y_number_int_with_exp.json", "test/data/nst_json_testsuite/test_parsing/y_number_minus_zero.json", "test/data/nst_json_testsuite/test_parsing/y_number_negative_int.json", @@ -1128,9 +1128,9 @@ TEST_CASE("MessagePack roundtrips", "[hide]") "test/data/nst_json_testsuite/test_parsing/y_number_real_exponent.json", "test/data/nst_json_testsuite/test_parsing/y_number_real_fraction_exponent.json", "test/data/nst_json_testsuite/test_parsing/y_number_real_neg_exp.json", - "test/data/nst_json_testsuite/test_parsing/y_number_real_neg_overflow.json", + //"test/data/nst_json_testsuite/test_parsing/y_number_real_neg_overflow.json", "test/data/nst_json_testsuite/test_parsing/y_number_real_pos_exponent.json", - "test/data/nst_json_testsuite/test_parsing/y_number_real_pos_overflow.json", + //"test/data/nst_json_testsuite/test_parsing/y_number_real_pos_overflow.json", "test/data/nst_json_testsuite/test_parsing/y_number_real_underflow.json", "test/data/nst_json_testsuite/test_parsing/y_number_simple_int.json", "test/data/nst_json_testsuite/test_parsing/y_number_simple_real.json", diff --git a/test/src/unit-regression.cpp b/test/src/unit-regression.cpp index 7b4086b10..b1c1f590a 100644 --- a/test/src/unit-regression.cpp +++ b/test/src/unit-regression.cpp @@ -49,6 +49,7 @@ TEST_CASE("regression tests") SECTION("issue #70 - Handle infinity and NaN cases") { + /* SECTION("NAN value") { CHECK(json(NAN) == json()); @@ -60,6 +61,36 @@ TEST_CASE("regression tests") CHECK(json(INFINITY) == json()); CHECK(json(json::number_float_t(INFINITY)) == json()); } + */ + + // With 3.0.0, the semantics of this changed: NAN and infinity are + // stored properly inside the JSON value (no exception or conversion + // to null), but are serialized as null. + SECTION("NAN value") + { + json j1 = NAN; + CHECK(j1.is_number_float()); + json::number_float_t f1 = j1; + CHECK(std::isnan(f1)); + + json j2 = json::number_float_t(NAN); + CHECK(j2.is_number_float()); + json::number_float_t f2 = j2; + CHECK(std::isnan(f2)); + } + + SECTION("infinity") + { + json j1 = INFINITY; + CHECK(j1.is_number_float()); + json::number_float_t f1 = j1; + CHECK(not std::isfinite(f1)); + + json j2 = json::number_float_t(INFINITY); + CHECK(j2.is_number_float()); + json::number_float_t f2 = j2; + CHECK(not std::isfinite(f2)); + } } SECTION("pull request #71 - handle enum type") @@ -559,8 +590,8 @@ TEST_CASE("regression tests") SECTION("issue #329 - serialized value not always can be parsed") { - json j = json::parse("22e2222"); - CHECK(j == json()); + CHECK_THROWS_AS(json::parse("22e2222"), std::out_of_range); + CHECK_THROWS_WITH(json::parse("22e2222"), "number overflow: 22e2222"); } SECTION("issue #366 - json::parse on failed stream gets stuck") diff --git a/test/src/unit-testsuites.cpp b/test/src/unit-testsuites.cpp index e83d5b740..8eb4d211f 100644 --- a/test/src/unit-testsuites.cpp +++ b/test/src/unit-testsuites.cpp @@ -460,7 +460,6 @@ TEST_CASE("nst's JSONTestSuite") "test/data/nst_json_testsuite/test_parsing/y_number_after_space.json", "test/data/nst_json_testsuite/test_parsing/y_number_double_close_to_zero.json", "test/data/nst_json_testsuite/test_parsing/y_number_double_huge_neg_exp.json", - "test/data/nst_json_testsuite/test_parsing/y_number_huge_exp.json", "test/data/nst_json_testsuite/test_parsing/y_number_int_with_exp.json", "test/data/nst_json_testsuite/test_parsing/y_number_minus_zero.json", "test/data/nst_json_testsuite/test_parsing/y_number_negative_int.json", @@ -472,9 +471,7 @@ TEST_CASE("nst's JSONTestSuite") "test/data/nst_json_testsuite/test_parsing/y_number_real_exponent.json", "test/data/nst_json_testsuite/test_parsing/y_number_real_fraction_exponent.json", "test/data/nst_json_testsuite/test_parsing/y_number_real_neg_exp.json", - "test/data/nst_json_testsuite/test_parsing/y_number_real_neg_overflow.json", "test/data/nst_json_testsuite/test_parsing/y_number_real_pos_exponent.json", - "test/data/nst_json_testsuite/test_parsing/y_number_real_pos_overflow.json", "test/data/nst_json_testsuite/test_parsing/y_number_real_underflow.json", "test/data/nst_json_testsuite/test_parsing/y_number_simple_int.json", "test/data/nst_json_testsuite/test_parsing/y_number_simple_real.json", @@ -765,9 +762,6 @@ TEST_CASE("nst's JSONTestSuite") { for (auto filename : { - // we currently do not limit exponents - "test/data/nst_json_testsuite/test_parsing/i_number_neg_int_huge_exp.json", - "test/data/nst_json_testsuite/test_parsing/i_number_pos_double_huge_exp.json", // we do not pose a limit on nesting "test/data/nst_json_testsuite/test_parsing/i_structure_500_nested_arrays.json", // we silently ignore BOMs @@ -787,6 +781,26 @@ TEST_CASE("nst's JSONTestSuite") } } + // numbers that overflow during parsing + SECTION("i/y -> n (out of range)") + { + for (auto filename : + { + "test/data/nst_json_testsuite/test_parsing/i_number_neg_int_huge_exp.json", + "test/data/nst_json_testsuite/test_parsing/i_number_pos_double_huge_exp.json", + "test/data/nst_json_testsuite/test_parsing/y_number_huge_exp.json", + "test/data/nst_json_testsuite/test_parsing/y_number_real_neg_overflow.json", + "test/data/nst_json_testsuite/test_parsing/y_number_real_pos_overflow.json" + } + ) + { + CAPTURE(filename); + std::ifstream f(filename); + json j; + CHECK_THROWS_AS(j << f, std::out_of_range); + } + } + SECTION("i -> n") { for (auto filename : From c5cf32e34d19573e2fefde373ca7a48bdae52be3 Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Sun, 12 Mar 2017 20:59:33 +0100 Subject: [PATCH 47/52] :hammer: added user-defined exception 406 --- src/json.hpp | 3 ++- src/json.hpp.re2c | 3 ++- test/src/unit-class_parser.cpp | 5 +++-- test/src/unit-regression.cpp | 5 +++-- test/src/unit-testsuites.cpp | 2 +- 5 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/json.hpp b/src/json.hpp index 41a85eaa8..5511dcd51 100644 --- a/src/json.hpp +++ b/src/json.hpp @@ -283,6 +283,7 @@ json.exception.out_of_range.402 | array index '-' (3) is out of range | The spec json.exception.out_of_range.403 | key 'foo' not found | The provided key was not found in the JSON object. json.exception.out_of_range.404 | unresolved reference token 'foo' | A reference token in a JSON Pointer could not be resolved. json.exception.out_of_range.405 | JSON pointer has no parent | The JSON Patch operations 'remove' and 'add' can not be applied to the root element of the JSON value. +json.exception.out_of_range.406 | number overflow parsing '10E1000' | A parsed number could not be stored as without changing it to NaN or INF. @since version 3.0.0 */ @@ -11717,7 +11718,7 @@ basic_json_parser_74: // throw in case of infinity or NAN if (not std::isfinite(result.m_value.number_float)) { - JSON_THROW(std::out_of_range("number overflow: " + get_token_string())); + JSON_THROW(out_of_range(406, "number overflow parsing '" + get_token_string() + "'")); } return true; diff --git a/src/json.hpp.re2c b/src/json.hpp.re2c index 711dd6889..f11736883 100644 --- a/src/json.hpp.re2c +++ b/src/json.hpp.re2c @@ -283,6 +283,7 @@ json.exception.out_of_range.402 | array index '-' (3) is out of range | The spec json.exception.out_of_range.403 | key 'foo' not found | The provided key was not found in the JSON object. json.exception.out_of_range.404 | unresolved reference token 'foo' | A reference token in a JSON Pointer could not be resolved. json.exception.out_of_range.405 | JSON pointer has no parent | The JSON Patch operations 'remove' and 'add' can not be applied to the root element of the JSON value. +json.exception.out_of_range.406 | number overflow parsing '10E1000' | A parsed number could not be stored as without changing it to NaN or INF. @since version 3.0.0 */ @@ -10750,7 +10751,7 @@ class basic_json // throw in case of infinity or NAN if (not std::isfinite(result.m_value.number_float)) { - JSON_THROW(std::out_of_range("number overflow: " + get_token_string())); + JSON_THROW(out_of_range(406, "number overflow parsing '" + get_token_string() + "'")); } return true; diff --git a/test/src/unit-class_parser.cpp b/test/src/unit-class_parser.cpp index c9240c9f4..61aa1c371 100644 --- a/test/src/unit-class_parser.cpp +++ b/test/src/unit-class_parser.cpp @@ -277,8 +277,9 @@ TEST_CASE("parser class") SECTION("overflow") { // overflows during parsing yield an exception - CHECK_THROWS_AS(json::parser("1.18973e+4932").parse() == json(), std::out_of_range); - CHECK_THROWS_WITH(json::parser("1.18973e+4932").parse() == json(), "number overflow: 1.18973e+4932"); + CHECK_THROWS_AS(json::parser("1.18973e+4932").parse() == json(), json::out_of_range); + CHECK_THROWS_WITH(json::parser("1.18973e+4932").parse() == json(), + "[json.exception.out_of_range.406] number overflow parsing '1.18973e+4932'"); } SECTION("invalid numbers") diff --git a/test/src/unit-regression.cpp b/test/src/unit-regression.cpp index a8287aeb3..33f7a9ef2 100644 --- a/test/src/unit-regression.cpp +++ b/test/src/unit-regression.cpp @@ -590,8 +590,9 @@ TEST_CASE("regression tests") SECTION("issue #329 - serialized value not always can be parsed") { - CHECK_THROWS_AS(json::parse("22e2222"), std::out_of_range); - CHECK_THROWS_WITH(json::parse("22e2222"), "number overflow: 22e2222"); + CHECK_THROWS_AS(json::parse("22e2222"), json::out_of_range); + CHECK_THROWS_WITH(json::parse("22e2222"), + "[json.exception.out_of_range.406] number overflow parsing '22e2222'"); } SECTION("issue #366 - json::parse on failed stream gets stuck") diff --git a/test/src/unit-testsuites.cpp b/test/src/unit-testsuites.cpp index 71b45b916..8d6a81622 100644 --- a/test/src/unit-testsuites.cpp +++ b/test/src/unit-testsuites.cpp @@ -797,7 +797,7 @@ TEST_CASE("nst's JSONTestSuite") CAPTURE(filename); std::ifstream f(filename); json j; - CHECK_THROWS_AS(j << f, std::out_of_range); + CHECK_THROWS_AS(j << f, json::out_of_range); } } From b8b4362ca49698c677d04a8c2088d30925657bf5 Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Mon, 13 Mar 2017 19:04:19 +0100 Subject: [PATCH 48/52] :fire: removed accidentally committed binaries --- doc/examples/get_ref | Bin 38132 -> 0 bytes doc/examples/json_pointer | Bin 47612 -> 0 bytes 2 files changed, 0 insertions(+), 0 deletions(-) delete mode 100755 doc/examples/get_ref delete mode 100755 doc/examples/json_pointer diff --git a/doc/examples/get_ref b/doc/examples/get_ref deleted file mode 100755 index d2dda9ba81796fd46a0b3d8cb861339285e07f15..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 38132 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 YQ}lEPF-EoUdQKrtW|j%#ZWEvX1IimE#Q*>R diff --git a/doc/examples/json_pointer b/doc/examples/json_pointer deleted file mode 100755 index 83f8491caf97ba3c05ab47ff0005c6be85579bdc..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 47612 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 T?I}{RMEETcDX$x0Bj(=$@v}rg From 84072fbd6d77619525f7ee4cdbc6cb7ca35db143 Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Tue, 14 Mar 2017 16:07:28 +0100 Subject: [PATCH 49/52] :lipstick: fixed indentation --- test/src/unit-class_parser.cpp | 2 +- test/src/unit-regression.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/test/src/unit-class_parser.cpp b/test/src/unit-class_parser.cpp index 61aa1c371..7f2c9a952 100644 --- a/test/src/unit-class_parser.cpp +++ b/test/src/unit-class_parser.cpp @@ -279,7 +279,7 @@ TEST_CASE("parser class") // overflows during parsing yield an exception CHECK_THROWS_AS(json::parser("1.18973e+4932").parse() == json(), json::out_of_range); CHECK_THROWS_WITH(json::parser("1.18973e+4932").parse() == json(), - "[json.exception.out_of_range.406] number overflow parsing '1.18973e+4932'"); + "[json.exception.out_of_range.406] number overflow parsing '1.18973e+4932'"); } SECTION("invalid numbers") diff --git a/test/src/unit-regression.cpp b/test/src/unit-regression.cpp index 33f7a9ef2..880f8325d 100644 --- a/test/src/unit-regression.cpp +++ b/test/src/unit-regression.cpp @@ -592,7 +592,7 @@ TEST_CASE("regression tests") { CHECK_THROWS_AS(json::parse("22e2222"), json::out_of_range); CHECK_THROWS_WITH(json::parse("22e2222"), - "[json.exception.out_of_range.406] number overflow parsing '22e2222'"); + "[json.exception.out_of_range.406] number overflow parsing '22e2222'"); } SECTION("issue #366 - json::parse on failed stream gets stuck") From bfe4788e323ef91792af9fdd181a2ddb29f67487 Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Tue, 14 Mar 2017 16:14:05 +0100 Subject: [PATCH 50/52] :ambulance: fix for #500 Removed a check that already failed in MSVC. --- test/src/unit-regression.cpp | 22 ---------------------- 1 file changed, 22 deletions(-) diff --git a/test/src/unit-regression.cpp b/test/src/unit-regression.cpp index 880f8325d..558a09558 100644 --- a/test/src/unit-regression.cpp +++ b/test/src/unit-regression.cpp @@ -460,16 +460,6 @@ TEST_CASE("regression tests") { setlocale(LC_NUMERIC, "de_DE.UTF-8"); - // Verify that snprintf uses special decimal and grouping characters. - // Disabled, because can't trigger locale-specific behavior in AppVeyor -#ifndef _MSC_VER - { - std::array buf; - std::snprintf(buf.data(), buf.size(), "%.2f", 12345.67); - CHECK(strcmp(buf.data(), "12345,67") == 0); - } -#endif - // verify that dumped correctly with '.' and no grouping const json j1 = 12345.67; CHECK(json(12345.67).dump() == "12345.67"); @@ -480,18 +470,6 @@ TEST_CASE("regression tests") { setlocale(LC_NUMERIC, "de_DE.UTF-8"); - // disabled, because locale-specific beharivor is not - // triggered in AppVeyor for some reason -#ifndef _MSC_VER - { - // verify that strtod now uses commas as decimal-separator - CHECK(std::strtod("3,14", nullptr) == 3.14); - - // verify that strtod does not understand dots as decimal separator - CHECK(std::strtod("3.14", nullptr) == 3); - } -#endif - // verify that parsed correctly despite using strtod internally CHECK(json::parse("3.14").get() == 3.14); From b026591e9e566b3ecd80a0161bd845756986c4b3 Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Tue, 14 Mar 2017 21:05:38 +0100 Subject: [PATCH 51/52] :ambulance: added special case to fuzzers to fix #504 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since #329, NaN and inf numbers do not yield an exception, but are stored internally and are dumped as “null”. This commit adjusts the fuzz testers to deal with this special case. --- src/json.hpp | 39 ++++++++++++++++++++++++++++++++-- src/json.hpp.re2c | 39 ++++++++++++++++++++++++++++++++-- test/src/fuzzer-parse_cbor.cpp | 4 ++-- test/src/unit-regression.cpp | 20 +++++++++++++++++ 4 files changed, 96 insertions(+), 6 deletions(-) diff --git a/src/json.hpp b/src/json.hpp index 5511dcd51..baa421fa7 100644 --- a/src/json.hpp +++ b/src/json.hpp @@ -174,6 +174,7 @@ json.exception.parse_error.109 | parse error: array index 'one' is not a number json.exception.parse_error.110 | parse error at 1: cannot read 2 bytes from vector | When parsing CBOR or MessagePack, the byte vector ends before the complete value has been read. json.exception.parse_error.111 | parse error: bad input stream | Parsing CBOR or MessagePack from an input stream where the [`badbit` or `failbit`](http://en.cppreference.com/w/cpp/io/ios_base/iostate) is set. json.exception.parse_error.112 | parse error at 1: error reading CBOR; last byte: 0xf8 | Not all types of CBOR or MessagePack are supported. This exception occurs if an unsupported byte was read. +json.exception.parse_error.113 | | While parsing a map key, a value that is not a string has been read. @since version 3.0.0 */ @@ -8020,7 +8021,7 @@ class basic_json @param[in] v MessagePack serialization @param[in] idx byte index in @a v to check for a string - @throw std::invalid_argument if `v[idx]` does not belong to a string + @throw parse_error.113 if `v[idx]` does not belong to a string */ static void msgpack_expect_string(const std::vector& v, size_t idx) { @@ -8032,7 +8033,39 @@ class basic_json return; } - JSON_THROW(std::invalid_argument("error parsing a msgpack string @ " + std::to_string(idx) + ": " + std::to_string(static_cast(v[idx])))); + std::stringstream ss; + ss << std::hex << static_cast(v[idx]); + JSON_THROW(parse_error(113, idx + 1, "expected a MessagePack string; last byte: 0x" + ss.str())); + } + + /*! + @brief check if the next byte belongs to a string + + While parsing a map, the keys must be strings. This function checks if the + current byte is one of the start bytes for a string in CBOR: + + - 0x60 - 0x77: fixed length + - 0x78 - 0x7b: variable length + - 0x7f: indefinity length + + @param[in] v CBOR serialization + @param[in] idx byte index in @a v to check for a string + + @throw parse_error.113 if `v[idx]` does not belong to a string + */ + static void cbor_expect_string(const std::vector& v, size_t idx) + { + check_length(v.size(), 1, idx); + + const auto byte = v[idx]; + if ((byte >= 0x60 and byte <= 0x7b) or byte == 0x7f) + { + return; + } + + std::stringstream ss; + ss << std::hex << static_cast(v[idx]); + JSON_THROW(parse_error(113, idx + 1, "expected a CBOR string; last byte: 0x" + ss.str())); } /*! @@ -8046,6 +8079,7 @@ class basic_json @throw parse_error.110 if the given vector ends prematurely @throw parse_error.112 if unsupported features from MessagePack were used in the given vector @a v or if the input is not valid MessagePack + @throw parse_error.113 if a string was expected as map key, but not found @sa https://github.com/msgpack/msgpack/blob/master/spec.md */ @@ -8291,6 +8325,7 @@ class basic_json @throw parse_error.110 if the given vector ends prematurely @throw parse_error.112 if unsupported features from CBOR were used in the given vector @a v or if the input is not valid CBOR + @throw parse_error.113 if a string was expected as map key, but not found @sa https://tools.ietf.org/html/rfc7049 */ diff --git a/src/json.hpp.re2c b/src/json.hpp.re2c index f11736883..c77770574 100644 --- a/src/json.hpp.re2c +++ b/src/json.hpp.re2c @@ -174,6 +174,7 @@ json.exception.parse_error.109 | parse error: array index 'one' is not a number json.exception.parse_error.110 | parse error at 1: cannot read 2 bytes from vector | When parsing CBOR or MessagePack, the byte vector ends before the complete value has been read. json.exception.parse_error.111 | parse error: bad input stream | Parsing CBOR or MessagePack from an input stream where the [`badbit` or `failbit`](http://en.cppreference.com/w/cpp/io/ios_base/iostate) is set. json.exception.parse_error.112 | parse error at 1: error reading CBOR; last byte: 0xf8 | Not all types of CBOR or MessagePack are supported. This exception occurs if an unsupported byte was read. +json.exception.parse_error.113 | | While parsing a map key, a value that is not a string has been read. @since version 3.0.0 */ @@ -8020,7 +8021,7 @@ class basic_json @param[in] v MessagePack serialization @param[in] idx byte index in @a v to check for a string - @throw std::invalid_argument if `v[idx]` does not belong to a string + @throw parse_error.113 if `v[idx]` does not belong to a string */ static void msgpack_expect_string(const std::vector& v, size_t idx) { @@ -8032,7 +8033,39 @@ class basic_json return; } - JSON_THROW(std::invalid_argument("error parsing a msgpack string @ " + std::to_string(idx) + ": " + std::to_string(static_cast(v[idx])))); + std::stringstream ss; + ss << std::hex << static_cast(v[idx]); + JSON_THROW(parse_error(113, idx + 1, "expected a MessagePack string; last byte: 0x" + ss.str())); + } + + /*! + @brief check if the next byte belongs to a string + + While parsing a map, the keys must be strings. This function checks if the + current byte is one of the start bytes for a string in CBOR: + + - 0x60 - 0x77: fixed length + - 0x78 - 0x7b: variable length + - 0x7f: indefinity length + + @param[in] v CBOR serialization + @param[in] idx byte index in @a v to check for a string + + @throw parse_error.113 if `v[idx]` does not belong to a string + */ + static void cbor_expect_string(const std::vector& v, size_t idx) + { + check_length(v.size(), 1, idx); + + const auto byte = v[idx]; + if ((byte >= 0x60 and byte <= 0x7b) or byte == 0x7f) + { + return; + } + + std::stringstream ss; + ss << std::hex << static_cast(v[idx]); + JSON_THROW(parse_error(113, idx + 1, "expected a CBOR string; last byte: 0x" + ss.str())); } /*! @@ -8046,6 +8079,7 @@ class basic_json @throw parse_error.110 if the given vector ends prematurely @throw parse_error.112 if unsupported features from MessagePack were used in the given vector @a v or if the input is not valid MessagePack + @throw parse_error.113 if a string was expected as map key, but not found @sa https://github.com/msgpack/msgpack/blob/master/spec.md */ @@ -8291,6 +8325,7 @@ class basic_json @throw parse_error.110 if the given vector ends prematurely @throw parse_error.112 if unsupported features from CBOR were used in the given vector @a v or if the input is not valid CBOR + @throw parse_error.113 if a string was expected as map key, but not found @sa https://tools.ietf.org/html/rfc7049 */ diff --git a/test/src/fuzzer-parse_cbor.cpp b/test/src/fuzzer-parse_cbor.cpp index 6e7ae6362..4bcfc7eff 100644 --- a/test/src/fuzzer-parse_cbor.cpp +++ b/test/src/fuzzer-parse_cbor.cpp @@ -41,8 +41,8 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) // parse serialization json j2 = json::from_cbor(vec2); - // deserializations must match - assert(j1 == j2); + // serializations must match + assert(json::to_cbor(j2) == vec2); } catch (const json::parse_error&) { diff --git a/test/src/unit-regression.cpp b/test/src/unit-regression.cpp index 558a09558..bc45cb653 100644 --- a/test/src/unit-regression.cpp +++ b/test/src/unit-regression.cpp @@ -909,4 +909,24 @@ TEST_CASE("regression tests") CHECK(j["bool_vector"].dump() == "[false,true,false,false]"); } + + SECTION("issue #504 - assertion error (OSS-Fuzz 856)") + { + std::vector vec1 = {0xf9, 0xff, 0xff, 0x4a, 0x3a, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01, 0x37, 0x02, 0x38}; + json j1 = json::from_cbor(vec1); + + // step 2: round trip + std::vector vec2 = json::to_cbor(j1); + + // parse serialization + json j2 = json::from_cbor(vec2); + + // NaN is dumped to "null" + CHECK(j2.is_number_float()); + CHECK(std::isnan(j2.get())); + CHECK(j2.dump() == "null"); + + // check if serializations match + CHECK(json::to_cbor(j2) == vec2); + } } From 95474e420de25ec7db4875e889201229820ef564 Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Tue, 14 Mar 2017 21:11:20 +0100 Subject: [PATCH 52/52] :checkered_flag: added parentheses around max/min calls #506 When is included with MSVC, a macro NOMINMAX is defined that yields compilation errors when max/min calls are encountered. This can be fixed by un-defining NOMINMAX, or by placing parentheses around all min/max calls. We chose the latter. --- src/json.hpp | 38 +++++++++++++++++++------------------- src/json.hpp.re2c | 38 +++++++++++++++++++------------------- 2 files changed, 38 insertions(+), 38 deletions(-) diff --git a/src/json.hpp b/src/json.hpp index baa421fa7..847aa3e22 100644 --- a/src/json.hpp +++ b/src/json.hpp @@ -7494,25 +7494,25 @@ class basic_json // positive fixnum add_to_vector(v, 1, j.m_value.number_unsigned); } - else if (j.m_value.number_unsigned <= std::numeric_limits::max()) + else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) { // uint 8 v.push_back(0xcc); add_to_vector(v, 1, j.m_value.number_unsigned); } - else if (j.m_value.number_unsigned <= std::numeric_limits::max()) + else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) { // uint 16 v.push_back(0xcd); add_to_vector(v, 2, j.m_value.number_unsigned); } - else if (j.m_value.number_unsigned <= std::numeric_limits::max()) + else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) { // uint 32 v.push_back(0xce); add_to_vector(v, 4, j.m_value.number_unsigned); } - else if (j.m_value.number_unsigned <= std::numeric_limits::max()) + else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) { // uint 64 v.push_back(0xcf); @@ -7526,25 +7526,25 @@ class basic_json // negative fixnum add_to_vector(v, 1, j.m_value.number_integer); } - else if (j.m_value.number_integer >= std::numeric_limits::min() and j.m_value.number_integer <= std::numeric_limits::max()) + else if (j.m_value.number_integer >= (std::numeric_limits::min)() and j.m_value.number_integer <= (std::numeric_limits::max)()) { // int 8 v.push_back(0xd0); add_to_vector(v, 1, j.m_value.number_integer); } - else if (j.m_value.number_integer >= std::numeric_limits::min() and j.m_value.number_integer <= std::numeric_limits::max()) + else if (j.m_value.number_integer >= (std::numeric_limits::min)() and j.m_value.number_integer <= (std::numeric_limits::max)()) { // int 16 v.push_back(0xd1); add_to_vector(v, 2, j.m_value.number_integer); } - else if (j.m_value.number_integer >= std::numeric_limits::min() and j.m_value.number_integer <= std::numeric_limits::max()) + else if (j.m_value.number_integer >= (std::numeric_limits::min)() and j.m_value.number_integer <= (std::numeric_limits::max)()) { // int 32 v.push_back(0xd2); add_to_vector(v, 4, j.m_value.number_integer); } - else if (j.m_value.number_integer >= std::numeric_limits::min() and j.m_value.number_integer <= std::numeric_limits::max()) + else if (j.m_value.number_integer >= (std::numeric_limits::min)() and j.m_value.number_integer <= (std::numeric_limits::max)()) { // int 64 v.push_back(0xd3); @@ -7561,25 +7561,25 @@ class basic_json // positive fixnum add_to_vector(v, 1, j.m_value.number_unsigned); } - else if (j.m_value.number_unsigned <= std::numeric_limits::max()) + else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) { // uint 8 v.push_back(0xcc); add_to_vector(v, 1, j.m_value.number_unsigned); } - else if (j.m_value.number_unsigned <= std::numeric_limits::max()) + else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) { // uint 16 v.push_back(0xcd); add_to_vector(v, 2, j.m_value.number_unsigned); } - else if (j.m_value.number_unsigned <= std::numeric_limits::max()) + else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) { // uint 32 v.push_back(0xce); add_to_vector(v, 4, j.m_value.number_unsigned); } - else if (j.m_value.number_unsigned <= std::numeric_limits::max()) + else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) { // uint 64 v.push_back(0xcf); @@ -7736,19 +7736,19 @@ class basic_json { add_to_vector(v, 1, j.m_value.number_integer); } - else if (j.m_value.number_integer <= std::numeric_limits::max()) + else if (j.m_value.number_integer <= (std::numeric_limits::max)()) { v.push_back(0x18); // one-byte uint8_t add_to_vector(v, 1, j.m_value.number_integer); } - else if (j.m_value.number_integer <= std::numeric_limits::max()) + else if (j.m_value.number_integer <= (std::numeric_limits::max)()) { v.push_back(0x19); // two-byte uint16_t add_to_vector(v, 2, j.m_value.number_integer); } - else if (j.m_value.number_integer <= std::numeric_limits::max()) + else if (j.m_value.number_integer <= (std::numeric_limits::max)()) { v.push_back(0x1a); // four-byte uint32_t @@ -7770,19 +7770,19 @@ class basic_json { v.push_back(static_cast(0x20 + positive_number)); } - else if (positive_number <= std::numeric_limits::max()) + else if (positive_number <= (std::numeric_limits::max)()) { // int 8 v.push_back(0x38); add_to_vector(v, 1, positive_number); } - else if (positive_number <= std::numeric_limits::max()) + else if (positive_number <= (std::numeric_limits::max)()) { // int 16 v.push_back(0x39); add_to_vector(v, 2, positive_number); } - else if (positive_number <= std::numeric_limits::max()) + else if (positive_number <= (std::numeric_limits::max)()) { // int 32 v.push_back(0x3a); @@ -7995,7 +7995,7 @@ class basic_json } // second case: adding offset would result in overflow - if ((size > (std::numeric_limits::max() - offset))) + if ((size > ((std::numeric_limits::max)() - offset))) { JSON_THROW(parse_error(110, offset + 1, "cannot read " + std::to_string(len) + " bytes from vector")); } diff --git a/src/json.hpp.re2c b/src/json.hpp.re2c index c77770574..e78df0804 100644 --- a/src/json.hpp.re2c +++ b/src/json.hpp.re2c @@ -7494,25 +7494,25 @@ class basic_json // positive fixnum add_to_vector(v, 1, j.m_value.number_unsigned); } - else if (j.m_value.number_unsigned <= std::numeric_limits::max()) + else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) { // uint 8 v.push_back(0xcc); add_to_vector(v, 1, j.m_value.number_unsigned); } - else if (j.m_value.number_unsigned <= std::numeric_limits::max()) + else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) { // uint 16 v.push_back(0xcd); add_to_vector(v, 2, j.m_value.number_unsigned); } - else if (j.m_value.number_unsigned <= std::numeric_limits::max()) + else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) { // uint 32 v.push_back(0xce); add_to_vector(v, 4, j.m_value.number_unsigned); } - else if (j.m_value.number_unsigned <= std::numeric_limits::max()) + else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) { // uint 64 v.push_back(0xcf); @@ -7526,25 +7526,25 @@ class basic_json // negative fixnum add_to_vector(v, 1, j.m_value.number_integer); } - else if (j.m_value.number_integer >= std::numeric_limits::min() and j.m_value.number_integer <= std::numeric_limits::max()) + else if (j.m_value.number_integer >= (std::numeric_limits::min)() and j.m_value.number_integer <= (std::numeric_limits::max)()) { // int 8 v.push_back(0xd0); add_to_vector(v, 1, j.m_value.number_integer); } - else if (j.m_value.number_integer >= std::numeric_limits::min() and j.m_value.number_integer <= std::numeric_limits::max()) + else if (j.m_value.number_integer >= (std::numeric_limits::min)() and j.m_value.number_integer <= (std::numeric_limits::max)()) { // int 16 v.push_back(0xd1); add_to_vector(v, 2, j.m_value.number_integer); } - else if (j.m_value.number_integer >= std::numeric_limits::min() and j.m_value.number_integer <= std::numeric_limits::max()) + else if (j.m_value.number_integer >= (std::numeric_limits::min)() and j.m_value.number_integer <= (std::numeric_limits::max)()) { // int 32 v.push_back(0xd2); add_to_vector(v, 4, j.m_value.number_integer); } - else if (j.m_value.number_integer >= std::numeric_limits::min() and j.m_value.number_integer <= std::numeric_limits::max()) + else if (j.m_value.number_integer >= (std::numeric_limits::min)() and j.m_value.number_integer <= (std::numeric_limits::max)()) { // int 64 v.push_back(0xd3); @@ -7561,25 +7561,25 @@ class basic_json // positive fixnum add_to_vector(v, 1, j.m_value.number_unsigned); } - else if (j.m_value.number_unsigned <= std::numeric_limits::max()) + else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) { // uint 8 v.push_back(0xcc); add_to_vector(v, 1, j.m_value.number_unsigned); } - else if (j.m_value.number_unsigned <= std::numeric_limits::max()) + else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) { // uint 16 v.push_back(0xcd); add_to_vector(v, 2, j.m_value.number_unsigned); } - else if (j.m_value.number_unsigned <= std::numeric_limits::max()) + else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) { // uint 32 v.push_back(0xce); add_to_vector(v, 4, j.m_value.number_unsigned); } - else if (j.m_value.number_unsigned <= std::numeric_limits::max()) + else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) { // uint 64 v.push_back(0xcf); @@ -7736,19 +7736,19 @@ class basic_json { add_to_vector(v, 1, j.m_value.number_integer); } - else if (j.m_value.number_integer <= std::numeric_limits::max()) + else if (j.m_value.number_integer <= (std::numeric_limits::max)()) { v.push_back(0x18); // one-byte uint8_t add_to_vector(v, 1, j.m_value.number_integer); } - else if (j.m_value.number_integer <= std::numeric_limits::max()) + else if (j.m_value.number_integer <= (std::numeric_limits::max)()) { v.push_back(0x19); // two-byte uint16_t add_to_vector(v, 2, j.m_value.number_integer); } - else if (j.m_value.number_integer <= std::numeric_limits::max()) + else if (j.m_value.number_integer <= (std::numeric_limits::max)()) { v.push_back(0x1a); // four-byte uint32_t @@ -7770,19 +7770,19 @@ class basic_json { v.push_back(static_cast(0x20 + positive_number)); } - else if (positive_number <= std::numeric_limits::max()) + else if (positive_number <= (std::numeric_limits::max)()) { // int 8 v.push_back(0x38); add_to_vector(v, 1, positive_number); } - else if (positive_number <= std::numeric_limits::max()) + else if (positive_number <= (std::numeric_limits::max)()) { // int 16 v.push_back(0x39); add_to_vector(v, 2, positive_number); } - else if (positive_number <= std::numeric_limits::max()) + else if (positive_number <= (std::numeric_limits::max)()) { // int 32 v.push_back(0x3a); @@ -7995,7 +7995,7 @@ class basic_json } // second case: adding offset would result in overflow - if ((size > (std::numeric_limits::max() - offset))) + if ((size > ((std::numeric_limits::max)() - offset))) { JSON_THROW(parse_error(110, offset + 1, "cannot read " + std::to_string(len) + " bytes from vector")); }