improved test coverage

This commit is contained in:
Niels Lohmann 2018-03-17 19:15:59 +01:00
parent c87ffad45c
commit 606a25195f
No known key found for this signature in database
GPG Key ID: 7F3CEA63AE251B69
3 changed files with 194 additions and 19 deletions

View File

@ -241,13 +241,13 @@ class json_sax_dom_parser : public json_sax<BasicJsonType>
case 1:
JSON_THROW(*reinterpret_cast<const detail::parse_error*>(&ex));
case 2:
JSON_THROW(*reinterpret_cast<const detail::invalid_iterator*>(&ex));
JSON_THROW(*reinterpret_cast<const detail::invalid_iterator*>(&ex)); // LCOV_EXCL_LINE
case 3:
JSON_THROW(*reinterpret_cast<const detail::type_error*>(&ex));
JSON_THROW(*reinterpret_cast<const detail::type_error*>(&ex)); // LCOV_EXCL_LINE
case 4:
JSON_THROW(*reinterpret_cast<const detail::out_of_range*>(&ex));
case 5:
JSON_THROW(*reinterpret_cast<const detail::other_error*>(&ex));
JSON_THROW(*reinterpret_cast<const detail::other_error*>(&ex)); // LCOV_EXCL_LINE
default:
assert(false); // LCOV_EXCL_LINE
}

View File

@ -3377,13 +3377,13 @@ class json_sax_dom_parser : public json_sax<BasicJsonType>
case 1:
JSON_THROW(*reinterpret_cast<const detail::parse_error*>(&ex));
case 2:
JSON_THROW(*reinterpret_cast<const detail::invalid_iterator*>(&ex));
JSON_THROW(*reinterpret_cast<const detail::invalid_iterator*>(&ex)); // LCOV_EXCL_LINE
case 3:
JSON_THROW(*reinterpret_cast<const detail::type_error*>(&ex));
JSON_THROW(*reinterpret_cast<const detail::type_error*>(&ex)); // LCOV_EXCL_LINE
case 4:
JSON_THROW(*reinterpret_cast<const detail::out_of_range*>(&ex));
case 5:
JSON_THROW(*reinterpret_cast<const detail::other_error*>(&ex));
JSON_THROW(*reinterpret_cast<const detail::other_error*>(&ex)); // LCOV_EXCL_LINE
default:
assert(false); // LCOV_EXCL_LINE
}
@ -3946,11 +3946,11 @@ class parser
// stack to remember the hieararchy of structured values we are parsing
std::vector<parse_state_t> states;
// value to avoid a goto (see comment where set to true)
bool skip_to_tail = false;
bool skip_to_state_evaluation = false;
while (true)
{
if (not skip_to_tail)
if (not skip_to_state_evaluation)
{
// invariant: get_token() was called before each iteration
switch (last_token)
@ -3999,9 +3999,11 @@ class parser
parse_error::create(101, m_lexer.get_position(), exception_message(token_type::name_separator)));
}
// remember we are now inside an object
states.push_back(parse_state_t::object_value);
// parse values
get_token();
states.push_back(parse_state_t::object_value);
continue;
}
@ -4025,8 +4027,10 @@ class parser
break;
}
// parse values (no need to call get_token)
// remember we are now inside an array
states.push_back(parse_state_t::array_value);
// parse values (no need to call get_token)
continue;
}
@ -4122,7 +4126,7 @@ class parser
}
else
{
skip_to_tail = false;
skip_to_state_evaluation = false;
}
// we reached this line after we successfully parsed a value
@ -4156,12 +4160,12 @@ class parser
// We are done with this array. Before we can parse
// a new value, we need to evaluate the new state
// first. By setting skip_to_tail to false, we are
// effectively jumping to the beginning of this
// switch.
// first. By setting skip_to_state_evaluation to
// false, we are effectively jumping to the
// beginning of this switch.
assert(not states.empty());
states.pop_back();
skip_to_tail = true;
skip_to_state_evaluation = true;
continue;
}
else
@ -4218,12 +4222,12 @@ class parser
// We are done with this object. Before we can
// parse a new value, we need to evaluate the new
// state first. By setting skip_to_tail to false,
// we are effectively jumping to the beginning of
// this switch.
// state first. By setting skip_to_state_evaluation
// to false, we are effectively jumping to the
// beginning of this switch.
assert(not states.empty());
states.pop_back();
skip_to_tail = true;
skip_to_state_evaluation = true;
continue;
}
else

View File

@ -134,6 +134,81 @@ class SaxEventLogger : public nlohmann::json::json_sax_t
bool errored = false;
};
class SaxCountdown : public nlohmann::json::json_sax_t
{
public:
explicit SaxCountdown(const int count) : events_left(count)
{}
bool null() override
{
return events_left-- > 0;
}
bool boolean(bool) override
{
return events_left-- > 0;
}
bool number_integer(json::number_integer_t) override
{
return events_left-- > 0;
}
bool number_unsigned(json::number_unsigned_t) override
{
return events_left-- > 0;
}
bool number_float(json::number_float_t, const std::string&) override
{
return events_left-- > 0;
}
bool string(std::string&&) override
{
return events_left-- > 0;
}
bool start_object(std::size_t) override
{
return events_left-- > 0;
}
bool key(std::string&&) override
{
return events_left-- > 0;
}
bool end_object() override
{
return events_left-- > 0;
}
bool start_array(std::size_t) override
{
return events_left-- > 0;
}
bool end_array() override
{
return events_left-- > 0;
}
bool binary(const std::vector<uint8_t>&) override
{
return events_left-- > 0;
}
bool parse_error(std::size_t, const std::string&, const json::exception&) override
{
return false;
}
private:
int events_left = 0;
};
json parser_helper(const std::string& s);
bool accept_helper(const std::string& s);
@ -1595,4 +1670,100 @@ TEST_CASE("parser class")
CHECK(j == json(true));
}
}
SECTION("improve test coverage")
{
SECTION("parser with callback")
{
json::parser_callback_t cb = [](int, json::parse_event_t, json&)
{
return true;
};
CHECK(json::parse("{\"foo\": true:", cb, false).is_discarded());
CHECK_THROWS_AS(json::parse("{\"foo\": true:", cb), json::parse_error&);
CHECK_THROWS_WITH(json::parse("{\"foo\": true:", cb),
"[json.exception.parse_error.101] parse error at 13: syntax error - unexpected ':'; expected '}'");
CHECK_THROWS_AS(json::parse("1.18973e+4932", cb), json::out_of_range&);
CHECK_THROWS_WITH(json::parse("1.18973e+4932", cb),
"[json.exception.out_of_range.406] number overflow parsing '1.18973e+4932'");
}
SECTION("SAX parser")
{
SECTION("} without value")
{
SaxCountdown s(1);
CHECK(json::sax_parse("{}", &s) == false);
}
SECTION("} with value")
{
SaxCountdown s(3);
CHECK(json::sax_parse("{\"k1\": true}", &s) == false);
}
SECTION("second key")
{
SaxCountdown s(3);
CHECK(json::sax_parse("{\"k1\": true, \"k2\": false}", &s) == false);
}
SECTION("] without value")
{
SaxCountdown s(1);
CHECK(json::sax_parse("[]", &s) == false);
}
SECTION("] with value")
{
SaxCountdown s(2);
CHECK(json::sax_parse("[1]", &s) == false);
}
SECTION("float")
{
SaxCountdown s(0);
CHECK(json::sax_parse("3.14", &s) == false);
}
SECTION("false")
{
SaxCountdown s(0);
CHECK(json::sax_parse("false", &s) == false);
}
SECTION("null")
{
SaxCountdown s(0);
CHECK(json::sax_parse("null", &s) == false);
}
SECTION("true")
{
SaxCountdown s(0);
CHECK(json::sax_parse("true", &s) == false);
}
SECTION("unsigned")
{
SaxCountdown s(0);
CHECK(json::sax_parse("12", &s) == false);
}
SECTION("integer")
{
SaxCountdown s(0);
CHECK(json::sax_parse("-12", &s) == false);
}
SECTION("string")
{
SaxCountdown s(0);
CHECK(json::sax_parse("\"foo\"", &s) == false);
}
}
}
}