🔨 removed a logic error and improved coverage
This commit is contained in:
parent
922f7a3d0e
commit
8c7f46f7d0
4 changed files with 156 additions and 53 deletions
|
@ -594,7 +594,7 @@ class parser
|
||||||
get_token();
|
get_token();
|
||||||
|
|
||||||
// closing } -> we are done
|
// closing } -> we are done
|
||||||
if (last_token == token_type::end_object)
|
if (JSON_UNLIKELY(last_token == token_type::end_object))
|
||||||
{
|
{
|
||||||
return sax->end_object();
|
return sax->end_object();
|
||||||
}
|
}
|
||||||
|
@ -603,7 +603,12 @@ class parser
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
// parse key
|
// parse key
|
||||||
if (last_token != token_type::value_string)
|
if (JSON_UNLIKELY(last_token != token_type::value_string))
|
||||||
|
{
|
||||||
|
return sax->parse_error(m_lexer.get_position(),
|
||||||
|
m_lexer.get_token_string());
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
if (not sax->key(m_lexer.move_string()))
|
if (not sax->key(m_lexer.move_string()))
|
||||||
{
|
{
|
||||||
|
@ -613,9 +618,10 @@ class parser
|
||||||
|
|
||||||
// parse separator (:)
|
// parse separator (:)
|
||||||
get_token();
|
get_token();
|
||||||
if (last_token != token_type::name_separator)
|
if (JSON_UNLIKELY(last_token != token_type::name_separator))
|
||||||
{
|
{
|
||||||
return sax->parse_error(m_lexer.get_position(), m_lexer.get_token_string());
|
return sax->parse_error(m_lexer.get_position(),
|
||||||
|
m_lexer.get_token_string());
|
||||||
}
|
}
|
||||||
|
|
||||||
// parse value
|
// parse value
|
||||||
|
@ -634,13 +640,14 @@ class parser
|
||||||
}
|
}
|
||||||
|
|
||||||
// closing }
|
// closing }
|
||||||
if (last_token == token_type::end_object)
|
if (JSON_LIKELY(last_token == token_type::end_object))
|
||||||
{
|
{
|
||||||
return sax->end_object();
|
return sax->end_object();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return sax->parse_error(m_lexer.get_position(), m_lexer.get_token_string());
|
return sax->parse_error(m_lexer.get_position(),
|
||||||
|
m_lexer.get_token_string());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -679,13 +686,14 @@ class parser
|
||||||
}
|
}
|
||||||
|
|
||||||
// closing ]
|
// closing ]
|
||||||
if (last_token == token_type::end_array)
|
if (JSON_LIKELY(last_token == token_type::end_array))
|
||||||
{
|
{
|
||||||
return sax->end_array();
|
return sax->end_array();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return sax->parse_error(m_lexer.get_position(), m_lexer.get_token_string());
|
return sax->parse_error(m_lexer.get_position(),
|
||||||
|
m_lexer.get_token_string());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -696,7 +704,8 @@ class parser
|
||||||
|
|
||||||
if (JSON_UNLIKELY(not std::isfinite(res)))
|
if (JSON_UNLIKELY(not std::isfinite(res)))
|
||||||
{
|
{
|
||||||
return sax->parse_error(m_lexer.get_position(), m_lexer.get_token_string());
|
return sax->parse_error(m_lexer.get_position(),
|
||||||
|
m_lexer.get_token_string());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -736,7 +745,8 @@ class parser
|
||||||
|
|
||||||
default: // the last token was unexpected
|
default: // the last token was unexpected
|
||||||
{
|
{
|
||||||
return sax->parse_error(m_lexer.get_position(), m_lexer.get_token_string());
|
return sax->parse_error(m_lexer.get_position(),
|
||||||
|
m_lexer.get_token_string());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1054,8 +1054,6 @@ class basic_json
|
||||||
*/
|
*/
|
||||||
using parse_event_t = typename parser::parse_event_t;
|
using parse_event_t = typename parser::parse_event_t;
|
||||||
|
|
||||||
using SAX = typename parser::SAX;
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@brief per-element parser callback type
|
@brief per-element parser callback type
|
||||||
|
|
||||||
|
@ -1107,6 +1105,7 @@ class basic_json
|
||||||
*/
|
*/
|
||||||
using parser_callback_t = typename parser::parser_callback_t;
|
using parser_callback_t = typename parser::parser_callback_t;
|
||||||
|
|
||||||
|
using SAX = typename parser::SAX;
|
||||||
|
|
||||||
//////////////////
|
//////////////////
|
||||||
// constructors //
|
// constructors //
|
||||||
|
|
|
@ -3717,7 +3717,7 @@ class parser
|
||||||
get_token();
|
get_token();
|
||||||
|
|
||||||
// closing } -> we are done
|
// closing } -> we are done
|
||||||
if (last_token == token_type::end_object)
|
if (JSON_UNLIKELY(last_token == token_type::end_object))
|
||||||
{
|
{
|
||||||
return sax->end_object();
|
return sax->end_object();
|
||||||
}
|
}
|
||||||
|
@ -3726,7 +3726,12 @@ class parser
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
// parse key
|
// parse key
|
||||||
if (last_token != token_type::value_string)
|
if (JSON_UNLIKELY(last_token != token_type::value_string))
|
||||||
|
{
|
||||||
|
return sax->parse_error(m_lexer.get_position(),
|
||||||
|
m_lexer.get_token_string());
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
if (not sax->key(m_lexer.move_string()))
|
if (not sax->key(m_lexer.move_string()))
|
||||||
{
|
{
|
||||||
|
@ -3736,9 +3741,10 @@ class parser
|
||||||
|
|
||||||
// parse separator (:)
|
// parse separator (:)
|
||||||
get_token();
|
get_token();
|
||||||
if (last_token != token_type::name_separator)
|
if (JSON_UNLIKELY(last_token != token_type::name_separator))
|
||||||
{
|
{
|
||||||
return sax->parse_error(m_lexer.get_position(), m_lexer.get_token_string());
|
return sax->parse_error(m_lexer.get_position(),
|
||||||
|
m_lexer.get_token_string());
|
||||||
}
|
}
|
||||||
|
|
||||||
// parse value
|
// parse value
|
||||||
|
@ -3757,13 +3763,14 @@ class parser
|
||||||
}
|
}
|
||||||
|
|
||||||
// closing }
|
// closing }
|
||||||
if (last_token == token_type::end_object)
|
if (JSON_LIKELY(last_token == token_type::end_object))
|
||||||
{
|
{
|
||||||
return sax->end_object();
|
return sax->end_object();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return sax->parse_error(m_lexer.get_position(), m_lexer.get_token_string());
|
return sax->parse_error(m_lexer.get_position(),
|
||||||
|
m_lexer.get_token_string());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3802,13 +3809,14 @@ class parser
|
||||||
}
|
}
|
||||||
|
|
||||||
// closing ]
|
// closing ]
|
||||||
if (last_token == token_type::end_array)
|
if (JSON_LIKELY(last_token == token_type::end_array))
|
||||||
{
|
{
|
||||||
return sax->end_array();
|
return sax->end_array();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return sax->parse_error(m_lexer.get_position(), m_lexer.get_token_string());
|
return sax->parse_error(m_lexer.get_position(),
|
||||||
|
m_lexer.get_token_string());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3819,7 +3827,8 @@ class parser
|
||||||
|
|
||||||
if (JSON_UNLIKELY(not std::isfinite(res)))
|
if (JSON_UNLIKELY(not std::isfinite(res)))
|
||||||
{
|
{
|
||||||
return sax->parse_error(m_lexer.get_position(), m_lexer.get_token_string());
|
return sax->parse_error(m_lexer.get_position(),
|
||||||
|
m_lexer.get_token_string());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -3859,7 +3868,8 @@ class parser
|
||||||
|
|
||||||
default: // the last token was unexpected
|
default: // the last token was unexpected
|
||||||
{
|
{
|
||||||
return sax->parse_error(m_lexer.get_position(), m_lexer.get_token_string());
|
return sax->parse_error(m_lexer.get_position(),
|
||||||
|
m_lexer.get_token_string());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10875,8 +10885,6 @@ class basic_json
|
||||||
*/
|
*/
|
||||||
using parse_event_t = typename parser::parse_event_t;
|
using parse_event_t = typename parser::parse_event_t;
|
||||||
|
|
||||||
using SAX = typename parser::SAX;
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@brief per-element parser callback type
|
@brief per-element parser callback type
|
||||||
|
|
||||||
|
@ -10928,6 +10936,7 @@ class basic_json
|
||||||
*/
|
*/
|
||||||
using parser_callback_t = typename parser::parser_callback_t;
|
using parser_callback_t = typename parser::parser_callback_t;
|
||||||
|
|
||||||
|
using SAX = typename parser::SAX;
|
||||||
|
|
||||||
//////////////////
|
//////////////////
|
||||||
// constructors //
|
// constructors //
|
||||||
|
|
|
@ -34,9 +34,8 @@ using nlohmann::json;
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <valarray>
|
#include <valarray>
|
||||||
|
|
||||||
class SaxEventLogger : public nlohmann::json::SAX
|
struct SaxEventLogger : public nlohmann::json::SAX
|
||||||
{
|
{
|
||||||
public:
|
|
||||||
bool null() override
|
bool null() override
|
||||||
{
|
{
|
||||||
events.push_back("null()");
|
events.push_back("null()");
|
||||||
|
@ -132,6 +131,47 @@ class SaxEventLogger : public nlohmann::json::SAX
|
||||||
std::vector<std::string> events;
|
std::vector<std::string> events;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct SaxEventLoggerExitAfterStartObject : public SaxEventLogger
|
||||||
|
{
|
||||||
|
bool start_object(std::size_t elements) override
|
||||||
|
{
|
||||||
|
if (elements == -1)
|
||||||
|
{
|
||||||
|
events.push_back("start_object()");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
events.push_back("start_object(" + std::to_string(elements) + ")");
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SaxEventLoggerExitAfterKey : public SaxEventLogger
|
||||||
|
{
|
||||||
|
bool key(const std::string& val) override
|
||||||
|
{
|
||||||
|
events.push_back("key(" + val + ")");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SaxEventLoggerExitAfterStartArray : public SaxEventLogger
|
||||||
|
{
|
||||||
|
bool start_array(std::size_t elements) override
|
||||||
|
{
|
||||||
|
if (elements == -1)
|
||||||
|
{
|
||||||
|
events.push_back("start_array()");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
events.push_back("start_array(" + std::to_string(elements) + ")");
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
TEST_CASE("deserialization")
|
TEST_CASE("deserialization")
|
||||||
{
|
{
|
||||||
SECTION("successful deserialization")
|
SECTION("successful deserialization")
|
||||||
|
@ -148,13 +188,13 @@ TEST_CASE("deserialization")
|
||||||
|
|
||||||
SaxEventLogger l;
|
SaxEventLogger l;
|
||||||
CHECK(json::sax_parse(ss3, &l));
|
CHECK(json::sax_parse(ss3, &l));
|
||||||
CHECK(l.events.size() == 10);
|
CHECK(l.events.size() == 11);
|
||||||
CHECK(l.events == std::vector<std::string>(
|
CHECK(l.events == std::vector<std::string>(
|
||||||
{
|
{
|
||||||
"start_array()", "string(foo)",
|
"start_array()", "string(foo)", "number_unsigned(1)",
|
||||||
"number_unsigned(1)", "number_unsigned(2)", "number_unsigned(3)",
|
"number_unsigned(2)", "number_unsigned(3)", "boolean(false)",
|
||||||
"boolean(false)", "start_object()",
|
"start_object()", "key(one)", "number_unsigned(1)",
|
||||||
"number_unsigned(1)", "end_object()", "end_array()"
|
"end_object()", "end_array()"
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -167,13 +207,13 @@ TEST_CASE("deserialization")
|
||||||
|
|
||||||
SaxEventLogger l;
|
SaxEventLogger l;
|
||||||
CHECK(json::sax_parse(s, &l));
|
CHECK(json::sax_parse(s, &l));
|
||||||
CHECK(l.events.size() == 10);
|
CHECK(l.events.size() == 11);
|
||||||
CHECK(l.events == std::vector<std::string>(
|
CHECK(l.events == std::vector<std::string>(
|
||||||
{
|
{
|
||||||
"start_array()", "string(foo)",
|
"start_array()", "string(foo)", "number_unsigned(1)",
|
||||||
"number_unsigned(1)", "number_unsigned(2)", "number_unsigned(3)",
|
"number_unsigned(2)", "number_unsigned(3)", "boolean(false)",
|
||||||
"boolean(false)", "start_object()",
|
"start_object()", "key(one)", "number_unsigned(1)",
|
||||||
"number_unsigned(1)", "end_object()", "end_array()"
|
"end_object()", "end_array()"
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -186,13 +226,13 @@ TEST_CASE("deserialization")
|
||||||
|
|
||||||
SaxEventLogger l;
|
SaxEventLogger l;
|
||||||
CHECK(json::sax_parse(s, &l));
|
CHECK(json::sax_parse(s, &l));
|
||||||
CHECK(l.events.size() == 10);
|
CHECK(l.events.size() == 11);
|
||||||
CHECK(l.events == std::vector<std::string>(
|
CHECK(l.events == std::vector<std::string>(
|
||||||
{
|
{
|
||||||
"start_array()", "string(foo)",
|
"start_array()", "string(foo)", "number_unsigned(1)",
|
||||||
"number_unsigned(1)", "number_unsigned(2)", "number_unsigned(3)",
|
"number_unsigned(2)", "number_unsigned(3)", "boolean(false)",
|
||||||
"boolean(false)", "start_object()",
|
"start_object()", "key(one)", "number_unsigned(1)",
|
||||||
"number_unsigned(1)", "end_object()", "end_array()"
|
"end_object()", "end_array()"
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -241,13 +281,13 @@ TEST_CASE("deserialization")
|
||||||
|
|
||||||
SaxEventLogger l;
|
SaxEventLogger l;
|
||||||
CHECK(not json::sax_parse(ss5, &l));
|
CHECK(not json::sax_parse(ss5, &l));
|
||||||
CHECK(l.events.size() == 10);
|
CHECK(l.events.size() == 11);
|
||||||
CHECK(l.events == std::vector<std::string>(
|
CHECK(l.events == std::vector<std::string>(
|
||||||
{
|
{
|
||||||
"start_array()", "string(foo)",
|
"start_array()", "string(foo)", "number_unsigned(1)",
|
||||||
"number_unsigned(1)", "number_unsigned(2)", "number_unsigned(3)",
|
"number_unsigned(2)", "number_unsigned(3)", "boolean(false)",
|
||||||
"boolean(false)", "start_object()",
|
"start_object()", "key(one)", "number_unsigned(1)",
|
||||||
"number_unsigned(1)", "end_object()", "parse_error(29)"
|
"end_object()", "parse_error(29)"
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -265,13 +305,13 @@ TEST_CASE("deserialization")
|
||||||
|
|
||||||
SaxEventLogger l;
|
SaxEventLogger l;
|
||||||
CHECK(not json::sax_parse(s, &l));
|
CHECK(not json::sax_parse(s, &l));
|
||||||
CHECK(l.events.size() == 10);
|
CHECK(l.events.size() == 11);
|
||||||
CHECK(l.events == std::vector<std::string>(
|
CHECK(l.events == std::vector<std::string>(
|
||||||
{
|
{
|
||||||
"start_array()", "string(foo)",
|
"start_array()", "string(foo)", "number_unsigned(1)",
|
||||||
"number_unsigned(1)", "number_unsigned(2)", "number_unsigned(3)",
|
"number_unsigned(2)", "number_unsigned(3)", "boolean(false)",
|
||||||
"boolean(false)", "start_object()",
|
"start_object()", "key(one)", "number_unsigned(1)",
|
||||||
"number_unsigned(1)", "end_object()", "parse_error(29)"
|
"end_object()", "parse_error(29)"
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -746,10 +786,10 @@ TEST_CASE("deserialization")
|
||||||
|
|
||||||
SaxEventLogger l;
|
SaxEventLogger l;
|
||||||
CHECK(not json::sax_parse(std::begin(v), std::end(v), &l));
|
CHECK(not json::sax_parse(std::begin(v), std::end(v), &l));
|
||||||
CHECK(l.events.size() == 3);
|
CHECK(l.events.size() == 4);
|
||||||
CHECK(l.events == std::vector<std::string>(
|
CHECK(l.events == std::vector<std::string>(
|
||||||
{
|
{
|
||||||
"start_object()", "number_unsigned(11)",
|
"start_object()", "key()", "number_unsigned(11)",
|
||||||
"parse_error(7)"
|
"parse_error(7)"
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
@ -912,4 +952,49 @@ TEST_CASE("deserialization")
|
||||||
CHECK(j == 456);
|
CHECK(j == 456);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SECTION("SAX and early abort")
|
||||||
|
{
|
||||||
|
std::string s = "[1, [\"string\", 43.12], null, {\"key1\": true, \"key2\": false}]";
|
||||||
|
|
||||||
|
SaxEventLogger default_logger;
|
||||||
|
SaxEventLoggerExitAfterStartObject exit_after_start_object;
|
||||||
|
SaxEventLoggerExitAfterKey exit_after_key;
|
||||||
|
SaxEventLoggerExitAfterStartArray exit_after_start_array;
|
||||||
|
|
||||||
|
json::sax_parse(s, &default_logger);
|
||||||
|
CHECK(default_logger.events.size() == 14);
|
||||||
|
CHECK(default_logger.events == std::vector<std::string>(
|
||||||
|
{
|
||||||
|
"start_array()", "number_unsigned(1)", "start_array()",
|
||||||
|
"string(string)", "number_float(43.12)", "end_array()", "null()",
|
||||||
|
"start_object()", "key(key1)", "boolean(true)", "key(key2)",
|
||||||
|
"boolean(false)", "end_object()", "end_array()"
|
||||||
|
}));
|
||||||
|
|
||||||
|
json::sax_parse(s, &exit_after_start_object);
|
||||||
|
CHECK(exit_after_start_object.events.size() == 8);
|
||||||
|
CHECK(exit_after_start_object.events == std::vector<std::string>(
|
||||||
|
{
|
||||||
|
"start_array()", "number_unsigned(1)", "start_array()",
|
||||||
|
"string(string)", "number_float(43.12)", "end_array()", "null()",
|
||||||
|
"start_object()"
|
||||||
|
}));
|
||||||
|
|
||||||
|
json::sax_parse(s, &exit_after_key);
|
||||||
|
CHECK(exit_after_key.events.size() == 9);
|
||||||
|
CHECK(exit_after_key.events == std::vector<std::string>(
|
||||||
|
{
|
||||||
|
"start_array()", "number_unsigned(1)", "start_array()",
|
||||||
|
"string(string)", "number_float(43.12)", "end_array()", "null()",
|
||||||
|
"start_object()", "key(key1)"
|
||||||
|
}));
|
||||||
|
|
||||||
|
json::sax_parse(s, &exit_after_start_array);
|
||||||
|
CHECK(exit_after_start_array.events.size() == 1);
|
||||||
|
CHECK(exit_after_start_array.events == std::vector<std::string>(
|
||||||
|
{
|
||||||
|
"start_array()"
|
||||||
|
}));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue