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: case 1:
JSON_THROW(*reinterpret_cast<const detail::parse_error*>(&ex)); JSON_THROW(*reinterpret_cast<const detail::parse_error*>(&ex));
case 2: 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: 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: case 4:
JSON_THROW(*reinterpret_cast<const detail::out_of_range*>(&ex)); JSON_THROW(*reinterpret_cast<const detail::out_of_range*>(&ex));
case 5: case 5:
JSON_THROW(*reinterpret_cast<const detail::other_error*>(&ex)); JSON_THROW(*reinterpret_cast<const detail::other_error*>(&ex)); // LCOV_EXCL_LINE
default: default:
assert(false); // LCOV_EXCL_LINE assert(false); // LCOV_EXCL_LINE
} }

View file

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

View file

@ -134,6 +134,81 @@ class SaxEventLogger : public nlohmann::json::json_sax_t
bool errored = false; 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); json parser_helper(const std::string& s);
bool accept_helper(const std::string& s); bool accept_helper(const std::string& s);
@ -1595,4 +1670,100 @@ TEST_CASE("parser class")
CHECK(j == json(true)); 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);
}
}
}
} }