Unverified Commit 43b82852 by Niels Lohmann

🔀 merge branch 'feature/exceptions_3.0.0' into develop

parents 8feaf8dc 855cdcf0
......@@ -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"
......
......@@ -58,6 +58,9 @@ 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
$(SED) -i 's@&lt; ObjectType, ArrayType, StringType, BooleanType, NumberIntegerType, NumberUnsignedType, NumberFloatType, AllocatorType, JSONSerializer &gt;@@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
upload: clean doxygen check_output
cd html ; ../scripts/git-update-ghpages nlohmann/json
......
......@@ -21,13 +21,27 @@ 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 (std::out_of_range& e)
catch (json::out_of_range& e)
{
std::cout << "out of range: " << e.what() << '\n';
std::cout << e.what() << '\n';
}
}
<a target="_blank" href="http://melpon.org/wandbox/permlink/tb5CaFfsMWpAvi7m"><b>online</b></a>
\ No newline at end of file
<a target="_blank" href="http://melpon.org/wandbox/permlink/8ldtT0NOhidn0fOA"><b>online</b></a>
\ No newline at end of file
"il brutto"
{"the bad":"il cattivo","the good":"il buono","the ugly":"il brutto"}
out of range: key 'the fast' not found
[json.exception.type_error.304] cannot use at() with string
[json.exception.out_of_range.403] key 'the fast' not found
"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
......@@ -15,12 +15,26 @@ 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 (std::out_of_range)
catch (json::out_of_range)
{
std::cout << "out of range" << '\n';
}
......
<a target="_blank" href="http://melpon.org/wandbox/permlink/NFG86H5khRUePc1s"><b>online</b></a>
\ No newline at end of file
<a target="_blank" href="http://melpon.org/wandbox/permlink/nfmFWMaJJHFJ7eVK"><b>online</b></a>
\ No newline at end of file
"il brutto"
[json.exception.type_error.304] cannot use at() with string
out of range
......@@ -16,13 +16,27 @@ 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 (std::out_of_range& e)
catch (json::out_of_range& e)
{
std::cout << "out of range: " << e.what() << '\n';
std::cout << e.what() << '\n';
}
}
<a target="_blank" href="http://melpon.org/wandbox/permlink/R7z2SB2rMdFQ9XtR"><b>online</b></a>
\ No newline at end of file
<a target="_blank" href="http://melpon.org/wandbox/permlink/8UnQY256zGX2Lx6d"><b>online</b></a>
\ No newline at end of file
"third"
["first","second","third","fourth"]
out of range: array index 5 is out of range
[json.exception.type_error.304] cannot use at() with string
[json.exception.out_of_range.401] array index 5 is out of range
......@@ -5,18 +5,32 @@ 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 (std::out_of_range)
catch (json::out_of_range& e)
{
std::cout << "out of range" << '\n';
std::cout << e.what() << '\n';
}
}
<a target="_blank" href="http://melpon.org/wandbox/permlink/L1bMeiN6nYm7JrvA"><b>online</b></a>
\ No newline at end of file
<a target="_blank" href="http://melpon.org/wandbox/permlink/U1fv6LY7xZOAuSBs"><b>online</b></a>
\ No newline at end of file
"third"
out of range
[json.exception.type_error.304] cannot use at() with string
[json.exception.out_of_range.401] array index 5 is out of range
......@@ -32,4 +32,60 @@ int main()
j.at("/array/1"_json_pointer) = 21;
// output the changed array
std::cout << j["array"] << '\n';
// out_of_range.106
try
{
// 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)
{
std::cout << e.what() << '\n';
}
}
<a target="_blank" href="http://melpon.org/wandbox/permlink/NDSjglHZIjIZ0Uxg"><b>online</b></a>
\ No newline at end of file
<a target="_blank" href="http://melpon.org/wandbox/permlink/Fy2xBfZMols2DUQC"><b>online</b></a>
\ No newline at end of file
......@@ -4,3 +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'
......@@ -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}}
};
......@@ -20,4 +20,48 @@ 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';
// out_of_range.109
try
{
// 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)
{
std::cout << e.what() << '\n';
}
}
<a target="_blank" href="http://melpon.org/wandbox/permlink/OuLYiMJ3pgyOHupb"><b>online</b></a>
\ No newline at end of file
<a target="_blank" href="http://melpon.org/wandbox/permlink/WxhV3mL9YX8FJonk"><b>online</b></a>
\ No newline at end of file
......@@ -2,3 +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'
......@@ -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';
}
}
<a target="_blank" href="http://melpon.org/wandbox/permlink/nPVnBcHf8nrNpGOJ"><b>online</b></a>
\ No newline at end of file
<a target="_blank" href="http://melpon.org/wandbox/permlink/CAv4NNr4D1FJhhUv"><b>online</b></a>
\ No newline at end of file
......@@ -4,3 +4,4 @@ true
2
16
"Hello, world"
[json.exception.invalid_iterator.214] cannot get value
......@@ -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';
}
}
<a target="_blank" href="http://melpon.org/wandbox/permlink/nKF1QcieoCHm6Lez"><b>online</b></a>
\ No newline at end of file
<a target="_blank" href="http://melpon.org/wandbox/permlink/oUU2X0pbZq7gawRB"><b>online</b></a>
\ No newline at end of file
["bravo","charly"]
42
{"one":"eins"}
[json.exception.invalid_iterator.204] iterators out of range
......@@ -19,7 +19,7 @@ int main()
{
auto r3 = value.get_ref<json::number_float_t&>();
}
catch (std::domain_error& ex)
catch (json::type_error& ex)
{
std::cout << ex.what() << '\n';
}
......
<a target="_blank" href="http://melpon.org/wandbox/permlink/WiO1oBWDvIs82OX1"><b>online</b></a>
\ No newline at end of file
<a target="_blank" href="http://melpon.org/wandbox/permlink/lsl8Ex3d3SOYnKHu"><b>online</b></a>
\ No newline at end of file
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
17 17
[json.exception.type_error.303] incompatible ReferenceType for get_ref, actual type is number
......@@ -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';
}
}
<a target="_blank" href="http://melpon.org/wandbox/permlink/WM2WWKnXdmdw17Wu"><b>online</b></a>
\ No newline at end of file
<a target="_blank" href="http://melpon.org/wandbox/permlink/Wlvqfd3JpEXTv2iH"><b>online</b></a>
\ No newline at end of file
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'
[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'
......@@ -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';
}
}
<a target="_blank" href="http://melpon.org/wandbox/permlink/hhxRaUctq3FA54SW"><b>online</b></a>
\ No newline at end of file
<a target="_blank" href="http://melpon.org/wandbox/permlink/Ub9U5AMbng3oZiao"><b>online</b></a>
\ No newline at end of file
{}
{}
{"one":1,"two":2}
[json.exception.type_error.301] cannot create object from initializer list
......@@ -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';
}
}
<a target="_blank" href="http://melpon.org/wandbox/permlink/rUGX6AaVuZfwiiYI"><b>online</b></a>
\ No newline at end of file
<a target="_blank" href="http://melpon.org/wandbox/permlink/drFSKFXJd8IMzMK3"><b>online</b></a>
\ No newline at end of file
......@@ -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
This source diff could not be displayed because it is too large. You can view the blob instead.
......@@ -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
......
......@@ -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
}
......
......@@ -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
......
......@@ -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");
}
}
......
......@@ -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")
......
......@@ -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")
......
......@@ -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");
}
}
......@@ -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);
}
}
}
......
......@@ -1016,6 +1016,90 @@ TEST_CASE("MessagePack")
json j = json::from_msgpack(given);
CHECK(j.get<double>() == Approx(25.0000019073486));
}
SECTION("errors")
{
SECTION("too short byte vector")
{
CHECK_THROWS_AS(json::from_msgpack(std::vector<uint8_t>({0xcc})), json::parse_error);
CHECK_THROWS_AS(json::from_msgpack(std::vector<uint8_t>({0xcd})), json::parse_error);
CHECK_THROWS_AS(json::from_msgpack(std::vector<uint8_t>({0xcd, 0x00})), json::parse_error);
CHECK_THROWS_AS(json::from_msgpack(std::vector<uint8_t>({0xce})), json::parse_error);
CHECK_THROWS_AS(json::from_msgpack(std::vector<uint8_t>({0xce, 0x00})), json::parse_error);
CHECK_THROWS_AS(json::from_msgpack(std::vector<uint8_t>({0xce, 0x00, 0x00})), json::parse_error);
CHECK_THROWS_AS(json::from_msgpack(std::vector<uint8_t>({0xce, 0x00, 0x00, 0x00})), json::parse_error);
CHECK_THROWS_AS(json::from_msgpack(std::vector<uint8_t>({0xcf})), json::parse_error);
CHECK_THROWS_AS(json::from_msgpack(std::vector<uint8_t>({0xcf, 0x00})), json::parse_error);
CHECK_THROWS_AS(json::from_msgpack(std::vector<uint8_t>({0xcf, 0x00, 0x00})), json::parse_error);
CHECK_THROWS_AS(json::from_msgpack(std::vector<uint8_t>({0xcf, 0x00, 0x00, 0x00})), json::parse_error);
CHECK_THROWS_AS(json::from_msgpack(std::vector<uint8_t>({0xcf, 0x00, 0x00, 0x00, 0x00})), json::parse_error);
CHECK_THROWS_AS(json::from_msgpack(std::vector<uint8_t>({0xcf, 0x00, 0x00, 0x00, 0x00, 0x00})), json::parse_error);
CHECK_THROWS_AS(json::from_msgpack(std::vector<uint8_t>({0xcf, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00})), json::parse_error);
CHECK_THROWS_AS(json::from_msgpack(std::vector<uint8_t>({0xcf, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00})), json::parse_error);
CHECK_THROWS_WITH(json::from_msgpack(std::vector<uint8_t>({0xcc})),
"[json.exception.parse_error.110] parse error at 2: cannot read 1 bytes from vector");
CHECK_THROWS_WITH(json::from_msgpack(std::vector<uint8_t>({0xcd})),
"[json.exception.parse_error.110] parse error at 2: cannot read 2 bytes from vector");
CHECK_THROWS_WITH(json::from_msgpack(std::vector<uint8_t>({0xcd, 0x00})),
"[json.exception.parse_error.110] parse error at 2: cannot read 2 bytes from vector");
CHECK_THROWS_WITH(json::from_msgpack(std::vector<uint8_t>({0xce})),
"[json.exception.parse_error.110] parse error at 2: cannot read 4 bytes from vector");
CHECK_THROWS_WITH(json::from_msgpack(std::vector<uint8_t>({0xce, 0x00})),
"[json.exception.parse_error.110] parse error at 2: cannot read 4 bytes from vector");
CHECK_THROWS_WITH(json::from_msgpack(std::vector<uint8_t>({0xce, 0x00, 0x00})),
"[json.exception.parse_error.110] parse error at 2: cannot read 4 bytes from vector");
CHECK_THROWS_WITH(json::from_msgpack(std::vector<uint8_t>({0xce, 0x00, 0x00, 0x00})),
"[json.exception.parse_error.110] parse error at 2: cannot read 4 bytes from vector");
CHECK_THROWS_WITH(json::from_msgpack(std::vector<uint8_t>({0xcf})),
"[json.exception.parse_error.110] parse error at 2: cannot read 8 bytes from vector");
CHECK_THROWS_WITH(json::from_msgpack(std::vector<uint8_t>({0xcf, 0x00})),
"[json.exception.parse_error.110] parse error at 2: cannot read 8 bytes from vector");
CHECK_THROWS_WITH(json::from_msgpack(std::vector<uint8_t>({0xcf, 0x00, 0x00})),
"[json.exception.parse_error.110] parse error at 2: cannot read 8 bytes from vector");
CHECK_THROWS_WITH(json::from_msgpack(std::vector<uint8_t>({0xcf, 0x00, 0x00, 0x00})),
"[json.exception.parse_error.110] parse error at 2: cannot read 8 bytes from vector");
CHECK_THROWS_WITH(json::from_msgpack(std::vector<uint8_t>({0xcf, 0x00, 0x00, 0x00, 0x00})),
"[json.exception.parse_error.110] parse error at 2: cannot read 8 bytes from vector");
CHECK_THROWS_WITH(json::from_msgpack(std::vector<uint8_t>({0xcf, 0x00, 0x00, 0x00, 0x00, 0x00})),
"[json.exception.parse_error.110] parse error at 2: cannot read 8 bytes from vector");
CHECK_THROWS_WITH(json::from_msgpack(std::vector<uint8_t>({0xcf, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00})),
"[json.exception.parse_error.110] parse error at 2: cannot read 8 bytes from vector");
CHECK_THROWS_WITH(json::from_msgpack(std::vector<uint8_t>({0xcf, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00})),
"[json.exception.parse_error.110] parse error at 2: cannot read 8 bytes from vector");
}
SECTION("unsupported bytes")
{
SECTION("concrete examples")
{
CHECK_THROWS_AS(json::from_msgpack(std::vector<uint8_t>({0xc1})), json::parse_error);
CHECK_THROWS_WITH(json::from_msgpack(std::vector<uint8_t>({0xc1})),
"[json.exception.parse_error.112] parse error at 1: error reading MessagePack; last byte: 0xc1");
CHECK_THROWS_AS(json::from_msgpack(std::vector<uint8_t>({0xc6})), json::parse_error);
CHECK_THROWS_WITH(json::from_msgpack(std::vector<uint8_t>({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<uint8_t>({static_cast<uint8_t>(byte)})), json::parse_error);
}
}
}
}
}
......
......@@ -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);
}
}
......@@ -754,7 +754,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);
}
}
......@@ -824,7 +824,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);
}
}
}
......
......@@ -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);
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment