🔨 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).
pull/508/head
Niels Lohmann 2017-03-01 21:28:44 +01:00
parent 7b8fd864e2
commit c085e3bac2
No known key found for this signature in database
GPG Key ID: 7F3CEA63AE251B69
9 changed files with 650 additions and 252 deletions

View File

@ -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@&lt;&#160;ObjectType,&#160;ArrayType,&#160;StringType,&#160;BooleanType,&#160;NumberIntegerType,&#160;NumberUnsignedType,&#160;NumberFloatType,&#160;AllocatorType&#160;JSONSerializer&#160;&gt;@@g' html/*.html
$(SED) -i 's@template&lt;template&lt; typename U, typename V, typename... Args &gt; class ObjectType = std::map, template&lt; typename U, typename... Args &gt; 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&lt; typename U &gt; class AllocatorType = std::allocator, template&lt; typename T, typename SFINAE=void &gt; class JSONSerializer = adl_serializer&gt;@@g' html/*.html
upload: clean doxygen check_output
cd html ; ../scripts/git-update-ghpages nlohmann/json

View File

@ -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 <http://en.wikipedia.org/wiki/UTF-8#Sample_code>
*/
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<size_t>((m_cursor - m_start));
continue;
}
basic_json_parser_9:
@ -10889,6 +11065,7 @@ basic_json_parser_74:
}
position += static_cast<size_t>((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));
}
}

View File

@ -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 <http://en.wikipedia.org/wiki/UTF-8#Sample_code>
*/
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<size_t>((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<size_t>((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));
}
}

View File

@ -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<const json::lexer::lexer_char_t*>(""), 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");
}
}

View File

@ -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
{

View File

@ -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<uint8_t> 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<uint8_t> 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);
}
}
}

View File

@ -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<uint8_t> 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")

View File

@ -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);
}
}
}

View File

@ -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<const json::lexer::lexer_char_t*>(""), 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);
}
}