accept functions to check if input is valid JSON #458

This commit is contained in:
Niels Lohmann 2017-06-16 19:23:55 +02:00
parent d415293d41
commit b27d2adcbe
No known key found for this signature in database
GPG key ID: 7F3CEA63AE251B69
2 changed files with 87 additions and 4 deletions

View file

@ -7421,6 +7421,13 @@ class basic_json
return parse(std::begin(array), std::end(array), cb); return parse(std::begin(array), std::end(array), cb);
} }
template<class T, std::size_t N>
static bool accept(T (&array)[N])
{
// delegate the call to the iterator-range accept overload
return accept(std::begin(array), std::end(array));
}
/*! /*!
@brief deserialize from string literal @brief deserialize from string literal
@ -7462,6 +7469,15 @@ class basic_json
return parser(input_adapter::create(s), cb).parse(true); return parser(input_adapter::create(s), cb).parse(true);
} }
template<typename CharT, typename std::enable_if<
std::is_pointer<CharT>::value and
std::is_integral<typename std::remove_pointer<CharT>::type>::value and
sizeof(typename std::remove_pointer<CharT>::type) == 1, int>::type = 0>
static bool accept(const CharT s)
{
return parser(input_adapter::create(s)).accept(true);
}
/*! /*!
@brief deserialize from stream @brief deserialize from stream
@ -7497,6 +7513,11 @@ class basic_json
return parser(input_adapter::create(i), cb).parse(true); return parser(input_adapter::create(i), cb).parse(true);
} }
static bool accept(std::istream& i)
{
return parser(input_adapter::create(i)).accept(true);
}
/*! /*!
@copydoc parse(std::istream&, const parser_callback_t) @copydoc parse(std::istream&, const parser_callback_t)
*/ */
@ -7506,6 +7527,11 @@ class basic_json
return parser(input_adapter::create(i), cb).parse(true); return parser(input_adapter::create(i), cb).parse(true);
} }
static bool accept(std::istream&& i)
{
return parser(input_adapter::create(i)).accept(true);
}
/*! /*!
@brief deserialize from an iterator range with contiguous storage @brief deserialize from an iterator range with contiguous storage
@ -7561,6 +7587,15 @@ class basic_json
return parser(input_adapter::create(first, last), cb).parse(true); return parser(input_adapter::create(first, last), cb).parse(true);
} }
template<class IteratorType, typename std::enable_if<
std::is_base_of<
std::random_access_iterator_tag,
typename std::iterator_traits<IteratorType>::iterator_category>::value, int>::type = 0>
static bool accept(IteratorType first, IteratorType last)
{
return parser(input_adapter::create(first, last)).accept(true);
}
/*! /*!
@brief deserialize from a container with contiguous storage @brief deserialize from a container with contiguous storage
@ -7618,6 +7653,18 @@ class basic_json
return parse(std::begin(c), std::end(c), cb); return parse(std::begin(c), std::end(c), cb);
} }
template<class ContiguousContainer, typename std::enable_if<
not std::is_pointer<ContiguousContainer>::value and
std::is_base_of<
std::random_access_iterator_tag,
typename std::iterator_traits<decltype(std::begin(std::declval<ContiguousContainer const>()))>::iterator_category>::value
, int>::type = 0>
static bool accept(const ContiguousContainer& c)
{
// delegate the call to the iterator-range accept overload
return accept(std::begin(c), std::end(c));
}
/*! /*!
@brief deserialize from stream @brief deserialize from stream
@deprecated This stream operator is deprecated and will be removed in a @deprecated This stream operator is deprecated and will be removed in a

View file

@ -39,9 +39,11 @@ TEST_CASE("deserialization")
{ {
SECTION("stream") SECTION("stream")
{ {
std::stringstream ss; std::stringstream ss1, ss2;
ss << "[\"foo\",1,2,3,false,{\"one\":1}]"; ss1 << "[\"foo\",1,2,3,false,{\"one\":1}]";
json j = json::parse(ss); ss2 << "[\"foo\",1,2,3,false,{\"one\":1}]";
json j = json::parse(ss1);
CHECK(json::accept(ss2));
CHECK(j == json({"foo", 1, 2, 3, false, {{"one", 1}}})); CHECK(j == json({"foo", 1, 2, 3, false, {{"one", 1}}}));
} }
@ -49,6 +51,7 @@ TEST_CASE("deserialization")
{ {
auto s = "[\"foo\",1,2,3,false,{\"one\":1}]"; auto s = "[\"foo\",1,2,3,false,{\"one\":1}]";
json j = json::parse(s); json j = json::parse(s);
CHECK(json::accept(s));
CHECK(j == json({"foo", 1, 2, 3, false, {{"one", 1}}})); CHECK(j == json({"foo", 1, 2, 3, false, {{"one", 1}}}));
} }
@ -56,6 +59,7 @@ TEST_CASE("deserialization")
{ {
json::string_t s = "[\"foo\",1,2,3,false,{\"one\":1}]"; json::string_t s = "[\"foo\",1,2,3,false,{\"one\":1}]";
json j = json::parse(s); json j = json::parse(s);
CHECK(json::accept(s));
CHECK(j == json({"foo", 1, 2, 3, false, {{"one", 1}}})); CHECK(j == json({"foo", 1, 2, 3, false, {{"one", 1}}}));
} }
@ -87,12 +91,14 @@ TEST_CASE("deserialization")
{ {
SECTION("stream") SECTION("stream")
{ {
std::stringstream ss1, ss2; std::stringstream ss1, ss2, ss3;
ss1 << "[\"foo\",1,2,3,false,{\"one\":1}"; ss1 << "[\"foo\",1,2,3,false,{\"one\":1}";
ss2 << "[\"foo\",1,2,3,false,{\"one\":1}"; ss2 << "[\"foo\",1,2,3,false,{\"one\":1}";
ss3 << "[\"foo\",1,2,3,false,{\"one\":1}";
CHECK_THROWS_AS(json::parse(ss1), json::parse_error); CHECK_THROWS_AS(json::parse(ss1), json::parse_error);
CHECK_THROWS_WITH(json::parse(ss2), CHECK_THROWS_WITH(json::parse(ss2),
"[json.exception.parse_error.101] parse error at 29: syntax error - unexpected end of input; expected ']'"); "[json.exception.parse_error.101] parse error at 29: syntax error - unexpected end of input; expected ']'");
CHECK(not json::accept(ss3));
} }
SECTION("string") SECTION("string")
@ -101,6 +107,7 @@ TEST_CASE("deserialization")
CHECK_THROWS_AS(json::parse(s), json::parse_error); CHECK_THROWS_AS(json::parse(s), json::parse_error);
CHECK_THROWS_WITH(json::parse(s), CHECK_THROWS_WITH(json::parse(s),
"[json.exception.parse_error.101] parse error at 29: syntax error - unexpected end of input; expected ']'"); "[json.exception.parse_error.101] parse error at 29: syntax error - unexpected end of input; expected ']'");
CHECK(not json::accept(s));
} }
SECTION("operator<<") SECTION("operator<<")
@ -141,18 +148,21 @@ TEST_CASE("deserialization")
{ {
std::vector<uint8_t> v = {'t', 'r', 'u', 'e'}; std::vector<uint8_t> v = {'t', 'r', 'u', 'e'};
CHECK(json::parse(v) == json(true)); CHECK(json::parse(v) == json(true));
CHECK(json::accept(v));
} }
SECTION("from std::array") SECTION("from std::array")
{ {
std::array<uint8_t, 5> v { {'t', 'r', 'u', 'e'} }; std::array<uint8_t, 5> v { {'t', 'r', 'u', 'e'} };
CHECK(json::parse(v) == json(true)); CHECK(json::parse(v) == json(true));
CHECK(json::accept(v));
} }
SECTION("from array") SECTION("from array")
{ {
uint8_t v[] = {'t', 'r', 'u', 'e'}; uint8_t v[] = {'t', 'r', 'u', 'e'};
CHECK(json::parse(v) == json(true)); CHECK(json::parse(v) == json(true));
CHECK(json::accept(v));
} }
SECTION("from chars") SECTION("from chars")
@ -164,6 +174,7 @@ TEST_CASE("deserialization")
v[3] = 'e'; v[3] = 'e';
v[4] = '\0'; v[4] = '\0';
CHECK(json::parse(v) == json(true)); CHECK(json::parse(v) == json(true));
CHECK(json::accept(v));
delete[] v; delete[] v;
} }
@ -171,18 +182,21 @@ TEST_CASE("deserialization")
{ {
std::string v = {'t', 'r', 'u', 'e'}; std::string v = {'t', 'r', 'u', 'e'};
CHECK(json::parse(v) == json(true)); CHECK(json::parse(v) == json(true));
CHECK(json::accept(v));
} }
SECTION("from std::initializer_list") SECTION("from std::initializer_list")
{ {
std::initializer_list<uint8_t> v = {'t', 'r', 'u', 'e'}; std::initializer_list<uint8_t> v = {'t', 'r', 'u', 'e'};
CHECK(json::parse(v) == json(true)); CHECK(json::parse(v) == json(true));
CHECK(json::accept(v));
} }
SECTION("empty container") SECTION("empty container")
{ {
std::vector<uint8_t> v; std::vector<uint8_t> v;
CHECK_THROWS_AS(json::parse(v), json::parse_error); CHECK_THROWS_AS(json::parse(v), json::parse_error);
CHECK(not json::accept(v));
} }
} }
@ -192,42 +206,49 @@ TEST_CASE("deserialization")
{ {
std::vector<uint8_t> v = {'t', 'r', 'u', 'e'}; std::vector<uint8_t> v = {'t', 'r', 'u', 'e'};
CHECK(json::parse(std::begin(v), std::end(v)) == json(true)); CHECK(json::parse(std::begin(v), std::end(v)) == json(true));
CHECK(json::accept(std::begin(v), std::end(v)));
} }
SECTION("from std::array") SECTION("from std::array")
{ {
std::array<uint8_t, 5> v { {'t', 'r', 'u', 'e'} }; std::array<uint8_t, 5> v { {'t', 'r', 'u', 'e'} };
CHECK(json::parse(std::begin(v), std::end(v)) == json(true)); CHECK(json::parse(std::begin(v), std::end(v)) == json(true));
CHECK(json::accept(std::begin(v), std::end(v)));
} }
SECTION("from array") SECTION("from array")
{ {
uint8_t v[] = {'t', 'r', 'u', 'e'}; uint8_t v[] = {'t', 'r', 'u', 'e'};
CHECK(json::parse(std::begin(v), std::end(v)) == json(true)); CHECK(json::parse(std::begin(v), std::end(v)) == json(true));
CHECK(json::accept(std::begin(v), std::end(v)));
} }
SECTION("from std::string") SECTION("from std::string")
{ {
std::string v = {'t', 'r', 'u', 'e'}; std::string v = {'t', 'r', 'u', 'e'};
CHECK(json::parse(std::begin(v), std::end(v)) == json(true)); CHECK(json::parse(std::begin(v), std::end(v)) == json(true));
CHECK(json::accept(std::begin(v), std::end(v)));
} }
SECTION("from std::initializer_list") SECTION("from std::initializer_list")
{ {
std::initializer_list<uint8_t> v = {'t', 'r', 'u', 'e'}; std::initializer_list<uint8_t> v = {'t', 'r', 'u', 'e'};
CHECK(json::parse(std::begin(v), std::end(v)) == json(true)); CHECK(json::parse(std::begin(v), std::end(v)) == json(true));
CHECK(json::accept(std::begin(v), std::end(v)));
} }
SECTION("from std::valarray") SECTION("from std::valarray")
{ {
std::valarray<uint8_t> v = {'t', 'r', 'u', 'e'}; std::valarray<uint8_t> v = {'t', 'r', 'u', 'e'};
CHECK(json::parse(std::begin(v), std::end(v)) == json(true)); CHECK(json::parse(std::begin(v), std::end(v)) == json(true));
CHECK(json::accept(std::begin(v), std::end(v)));
} }
SECTION("with empty range") SECTION("with empty range")
{ {
std::vector<uint8_t> v; std::vector<uint8_t> v;
CHECK_THROWS_AS(json::parse(std::begin(v), std::end(v)), json::parse_error); CHECK_THROWS_AS(json::parse(std::begin(v), std::end(v)), json::parse_error);
CHECK(not json::accept(std::begin(v), std::end(v)));
} }
} }
@ -238,90 +259,105 @@ TEST_CASE("deserialization")
{ {
uint8_t v[] = {'\"', 'a', 'a', 'a', 'a', 'a', 'a', '\\', 'u'}; uint8_t v[] = {'\"', 'a', 'a', 'a', 'a', 'a', 'a', '\\', 'u'};
CHECK_THROWS_AS(json::parse(std::begin(v), std::end(v)), json::parse_error); CHECK_THROWS_AS(json::parse(std::begin(v), std::end(v)), json::parse_error);
CHECK(not json::accept(std::begin(v), std::end(v)));
} }
SECTION("case 2") SECTION("case 2")
{ {
uint8_t v[] = {'\"', 'a', 'a', 'a', 'a', 'a', 'a', '\\', 'u', '1'}; uint8_t v[] = {'\"', 'a', 'a', 'a', 'a', 'a', 'a', '\\', 'u', '1'};
CHECK_THROWS_AS(json::parse(std::begin(v), std::end(v)), json::parse_error); CHECK_THROWS_AS(json::parse(std::begin(v), std::end(v)), json::parse_error);
CHECK(not json::accept(std::begin(v), std::end(v)));
} }
SECTION("case 3") SECTION("case 3")
{ {
uint8_t v[] = {'\"', 'a', 'a', 'a', 'a', 'a', 'a', '\\', 'u', '1', '1', '1', '1', '1', '1', '1', '1'}; 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)), json::parse_error); CHECK_THROWS_AS(json::parse(std::begin(v), std::end(v)), json::parse_error);
CHECK(not json::accept(std::begin(v), std::end(v)));
} }
SECTION("case 4") SECTION("case 4")
{ {
uint8_t v[] = {'\"', 'a', 'a', 'a', 'a', 'a', 'a', 'u', '1', '1', '1', '1', '1', '1', '1', '1', '\\'}; 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)), json::parse_error); CHECK_THROWS_AS(json::parse(std::begin(v), std::end(v)), json::parse_error);
CHECK(not json::accept(std::begin(v), std::end(v)));
} }
SECTION("case 5") SECTION("case 5")
{ {
uint8_t v[] = {'\"', 0x7F, 0xC1}; uint8_t v[] = {'\"', 0x7F, 0xC1};
CHECK_THROWS_AS(json::parse(std::begin(v), std::end(v)), json::parse_error); CHECK_THROWS_AS(json::parse(std::begin(v), std::end(v)), json::parse_error);
CHECK(not json::accept(std::begin(v), std::end(v)));
} }
SECTION("case 6") SECTION("case 6")
{ {
uint8_t v[] = {'\"', 0x7F, 0xDF, 0x7F}; uint8_t v[] = {'\"', 0x7F, 0xDF, 0x7F};
CHECK_THROWS_AS(json::parse(std::begin(v), std::end(v)), json::parse_error); CHECK_THROWS_AS(json::parse(std::begin(v), std::end(v)), json::parse_error);
CHECK(not json::accept(std::begin(v), std::end(v)));
} }
SECTION("case 7") SECTION("case 7")
{ {
uint8_t v[] = {'\"', 0x7F, 0xDF, 0xC0}; uint8_t v[] = {'\"', 0x7F, 0xDF, 0xC0};
CHECK_THROWS_AS(json::parse(std::begin(v), std::end(v)), json::parse_error); CHECK_THROWS_AS(json::parse(std::begin(v), std::end(v)), json::parse_error);
CHECK(not json::accept(std::begin(v), std::end(v)));
} }
SECTION("case 8") SECTION("case 8")
{ {
uint8_t v[] = {'\"', 0x7F, 0xE0, 0x9F}; uint8_t v[] = {'\"', 0x7F, 0xE0, 0x9F};
CHECK_THROWS_AS(json::parse(std::begin(v), std::end(v)), json::parse_error); CHECK_THROWS_AS(json::parse(std::begin(v), std::end(v)), json::parse_error);
CHECK(not json::accept(std::begin(v), std::end(v)));
} }
SECTION("case 9") SECTION("case 9")
{ {
uint8_t v[] = {'\"', 0x7F, 0xEF, 0xC0}; uint8_t v[] = {'\"', 0x7F, 0xEF, 0xC0};
CHECK_THROWS_AS(json::parse(std::begin(v), std::end(v)), json::parse_error); CHECK_THROWS_AS(json::parse(std::begin(v), std::end(v)), json::parse_error);
CHECK(not json::accept(std::begin(v), std::end(v)));
} }
SECTION("case 10") SECTION("case 10")
{ {
uint8_t v[] = {'\"', 0x7F, 0xED, 0x7F}; uint8_t v[] = {'\"', 0x7F, 0xED, 0x7F};
CHECK_THROWS_AS(json::parse(std::begin(v), std::end(v)), json::parse_error); CHECK_THROWS_AS(json::parse(std::begin(v), std::end(v)), json::parse_error);
CHECK(not json::accept(std::begin(v), std::end(v)));
} }
SECTION("case 11") SECTION("case 11")
{ {
uint8_t v[] = {'\"', 0x7F, 0xF0, 0x8F}; uint8_t v[] = {'\"', 0x7F, 0xF0, 0x8F};
CHECK_THROWS_AS(json::parse(std::begin(v), std::end(v)), json::parse_error); CHECK_THROWS_AS(json::parse(std::begin(v), std::end(v)), json::parse_error);
CHECK(not json::accept(std::begin(v), std::end(v)));
} }
SECTION("case 12") SECTION("case 12")
{ {
uint8_t v[] = {'\"', 0x7F, 0xF0, 0xC0}; uint8_t v[] = {'\"', 0x7F, 0xF0, 0xC0};
CHECK_THROWS_AS(json::parse(std::begin(v), std::end(v)), json::parse_error); CHECK_THROWS_AS(json::parse(std::begin(v), std::end(v)), json::parse_error);
CHECK(not json::accept(std::begin(v), std::end(v)));
} }
SECTION("case 13") SECTION("case 13")
{ {
uint8_t v[] = {'\"', 0x7F, 0xF3, 0x7F}; uint8_t v[] = {'\"', 0x7F, 0xF3, 0x7F};
CHECK_THROWS_AS(json::parse(std::begin(v), std::end(v)), json::parse_error); CHECK_THROWS_AS(json::parse(std::begin(v), std::end(v)), json::parse_error);
CHECK(not json::accept(std::begin(v), std::end(v)));
} }
SECTION("case 14") SECTION("case 14")
{ {
uint8_t v[] = {'\"', 0x7F, 0xF3, 0xC0}; uint8_t v[] = {'\"', 0x7F, 0xF3, 0xC0};
CHECK_THROWS_AS(json::parse(std::begin(v), std::end(v)), json::parse_error); CHECK_THROWS_AS(json::parse(std::begin(v), std::end(v)), json::parse_error);
CHECK(not json::accept(std::begin(v), std::end(v)));
} }
SECTION("case 15") SECTION("case 15")
{ {
uint8_t v[] = {'\"', 0x7F, 0xF4, 0x7F}; uint8_t v[] = {'\"', 0x7F, 0xF4, 0x7F};
CHECK_THROWS_AS(json::parse(std::begin(v), std::end(v)), json::parse_error); CHECK_THROWS_AS(json::parse(std::begin(v), std::end(v)), json::parse_error);
CHECK(not json::accept(std::begin(v), std::end(v)));
} }
} }
} }