Skip to content

Commit

Permalink
added test cases & addressed coverage loss
Browse files Browse the repository at this point in the history
  • Loading branch information
fktn-k committed Dec 22, 2024
1 parent f898296 commit 8136f3f
Show file tree
Hide file tree
Showing 3 changed files with 68 additions and 80 deletions.
65 changes: 29 additions & 36 deletions include/fkYAML/detail/input/deserializer.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -444,6 +444,10 @@ class basic_deserializer {
throw parse_error("sequence key should not be empty.", line, indent);
}

if (m_flow_context_depth > 0) {
break;
}

// hold the line count of the key separator for later use.
const uint32_t old_indent = indent;
const uint32_t old_line = line;
Expand All @@ -461,10 +465,6 @@ class basic_deserializer {
line = lexer.get_lines_processed();
indent = lexer.get_last_token_begin_pos();

if (m_flow_context_depth > 0) {
continue;
}

const bool is_implicit_same_line =
(line == old_line) && (m_context_stack.empty() || old_indent > m_context_stack.back().indent);
if (is_implicit_same_line) {
Expand Down Expand Up @@ -538,8 +538,9 @@ class basic_deserializer {
continue;
}

if (m_flow_context_depth == 0 && m_context_stack.back().state == context_state_t::MAPPING_VALUE &&
indent <= m_context_stack.back().indent) {
if (indent <= m_context_stack.back().indent) {
FK_YAML_ASSERT(m_context_stack.back().state == context_state_t::MAPPING_VALUE);

// Mapping values can be omitted and are considered to be null.
// ```yaml
// foo:
Expand All @@ -549,7 +550,7 @@ class basic_deserializer {
// # -> {foo: null, bar: {baz: null}, qux: null}
// ```
pop_to_parent_node(line, indent, [indent](const parse_context& c) {
return (indent == c.indent) && (c.state == context_state_t::BLOCK_MAPPING);
return (c.state == context_state_t::BLOCK_MAPPING) && (indent == c.indent);
});
}

Expand Down Expand Up @@ -620,14 +621,10 @@ class basic_deserializer {

if (indent <= m_context_stack.back().indent) {
pop_to_parent_node(line, indent, [indent](const parse_context& c) {
if (indent != c.indent) {
return false;
}

switch (c.state) {
case context_state_t::BLOCK_MAPPING:
case context_state_t::MAPPING_VALUE:
return true;
return indent == c.indent;
default:
return false;
}
Expand Down Expand Up @@ -747,14 +744,10 @@ class basic_deserializer {

if (indent <= m_context_stack.back().indent) {
pop_to_parent_node(line, indent, [indent](const parse_context& c) {
if (indent != c.indent) {
return false;
}

switch (c.state) {
case context_state_t::BLOCK_MAPPING:
case context_state_t::MAPPING_VALUE:
return true;
return indent == c.indent;
default:
return false;
}
Expand Down Expand Up @@ -903,11 +896,8 @@ class basic_deserializer {
apply_directive_set(node);
apply_node_properties(node);

const bool should_continue = deserialize_scalar(lexer, std::move(node), indent, line, token);
if (should_continue) {
continue;
}
break;
deserialize_scalar(lexer, std::move(node), indent, line, token);
continue;
}
case lexical_token_t::PLAIN_SCALAR:
case lexical_token_t::SINGLE_QUOTED_SCALAR:
Expand All @@ -921,11 +911,8 @@ class basic_deserializer {
apply_directive_set(node);
apply_node_properties(node);

const bool do_continue = deserialize_scalar(lexer, std::move(node), indent, line, token);
if (do_continue) {
continue;
}
break;
deserialize_scalar(lexer, std::move(node), indent, line, token);
continue;
}
case lexical_token_t::BLOCK_LITERAL_SCALAR:
case lexical_token_t::BLOCK_FOLDED_SCALAR: {
Expand Down Expand Up @@ -1039,10 +1026,12 @@ class basic_deserializer {
/// @param line The line where the key is found.
/// @param indent The indentation width in the current line where the key is found.
void add_new_key(basic_node_type&& key, const uint32_t line, const uint32_t indent) {
if (m_flow_context_depth == 0 && indent <= m_context_stack.back().indent) {
pop_to_parent_node(line, indent, [indent](const parse_context& c) {
return (indent == c.indent) && (c.state == context_state_t::BLOCK_MAPPING);
});
if (m_flow_context_depth == 0) {
if (indent <= m_context_stack.back().indent) {
pop_to_parent_node(line, indent, [indent](const parse_context& c) {
return (c.state == context_state_t::BLOCK_MAPPING) && (indent == c.indent);
});
}
}
else if FK_YAML_UNLIKELY (m_flow_token_state != flow_token_state_t::NEEDS_VALUE_OR_SUFFIX) {
throw parse_error("Flow mapping entry is found without separated with a comma.", line, indent);
Expand Down Expand Up @@ -1106,11 +1095,13 @@ class basic_deserializer {
/// @param line The number of processed lines. Can be updated in this function.
/// @param token The storage for last lexical token.
/// @return true if next token has already been got, false otherwise.
bool deserialize_scalar(
void deserialize_scalar(
lexer_type& lexer, basic_node_type&& node, uint32_t& indent, uint32_t& line, lexical_token& token) {
token = lexer.get_next_token();
if (mp_current_node->is_mapping()) {
if (token.type != lexical_token_t::KEY_SEPARATOR || line != lexer.get_lines_processed()) {
const bool is_key_sep_followed =
(token.type == lexical_token_t::KEY_SEPARATOR) && (line == lexer.get_lines_processed());
if FK_YAML_UNLIKELY (!is_key_sep_followed) {
throw parse_error(
"The \":\" mapping value indicator must be followed after a mapping key.",
lexer.get_lines_processed(),
Expand All @@ -1119,7 +1110,7 @@ class basic_deserializer {
add_new_key(std::move(node), line, indent);
}
else if (token.type == lexical_token_t::KEY_SEPARATOR) {
if (line != lexer.get_lines_processed()) {
if FK_YAML_UNLIKELY (line != lexer.get_lines_processed()) {
// This path is for explicit mapping key separator like:
//
// ```yaml
Expand All @@ -1134,7 +1125,7 @@ class basic_deserializer {
}
indent = lexer.get_last_token_begin_pos();
line = lexer.get_lines_processed();
return true;
return;
}

if (mp_current_node->is_scalar()) {
Expand Down Expand Up @@ -1181,9 +1172,9 @@ class basic_deserializer {
else {
assign_node_value(std::move(node), line, indent);
}

indent = lexer.get_last_token_begin_pos();
line = lexer.get_lines_processed();
return true;
}

/// @brief Pops parent contexts to a block mapping with the given indentation.
Expand All @@ -1199,7 +1190,9 @@ class basic_deserializer {
pop_num = static_cast<uint32_t>(m_context_stack.size() - 1);
}
else {
// LCOV_EXCL_START
auto itr = std::find_if(m_context_stack.rbegin(), m_context_stack.rend(), std::forward<Pred>(pred));
// LCOV_EXCL_STOP
const bool is_indent_valid = (itr != m_context_stack.rend());
if FK_YAML_UNLIKELY (!is_indent_valid) {
throw parse_error("Detected invalid indentation.", line, indent);
Expand Down
65 changes: 29 additions & 36 deletions single_include/fkYAML/node.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -7451,6 +7451,10 @@ class basic_deserializer {
throw parse_error("sequence key should not be empty.", line, indent);
}

if (m_flow_context_depth > 0) {
break;
}

// hold the line count of the key separator for later use.
const uint32_t old_indent = indent;
const uint32_t old_line = line;
Expand All @@ -7468,10 +7472,6 @@ class basic_deserializer {
line = lexer.get_lines_processed();
indent = lexer.get_last_token_begin_pos();

if (m_flow_context_depth > 0) {
continue;
}

const bool is_implicit_same_line =
(line == old_line) && (m_context_stack.empty() || old_indent > m_context_stack.back().indent);
if (is_implicit_same_line) {
Expand Down Expand Up @@ -7545,8 +7545,9 @@ class basic_deserializer {
continue;
}

if (m_flow_context_depth == 0 && m_context_stack.back().state == context_state_t::MAPPING_VALUE &&
indent <= m_context_stack.back().indent) {
if (indent <= m_context_stack.back().indent) {
FK_YAML_ASSERT(m_context_stack.back().state == context_state_t::MAPPING_VALUE);

// Mapping values can be omitted and are considered to be null.
// ```yaml
// foo:
Expand All @@ -7556,7 +7557,7 @@ class basic_deserializer {
// # -> {foo: null, bar: {baz: null}, qux: null}
// ```
pop_to_parent_node(line, indent, [indent](const parse_context& c) {
return (indent == c.indent) && (c.state == context_state_t::BLOCK_MAPPING);
return (c.state == context_state_t::BLOCK_MAPPING) && (indent == c.indent);
});
}

Expand Down Expand Up @@ -7627,14 +7628,10 @@ class basic_deserializer {

if (indent <= m_context_stack.back().indent) {
pop_to_parent_node(line, indent, [indent](const parse_context& c) {
if (indent != c.indent) {
return false;
}

switch (c.state) {
case context_state_t::BLOCK_MAPPING:
case context_state_t::MAPPING_VALUE:
return true;
return indent == c.indent;
default:
return false;
}
Expand Down Expand Up @@ -7754,14 +7751,10 @@ class basic_deserializer {

if (indent <= m_context_stack.back().indent) {
pop_to_parent_node(line, indent, [indent](const parse_context& c) {
if (indent != c.indent) {
return false;
}

switch (c.state) {
case context_state_t::BLOCK_MAPPING:
case context_state_t::MAPPING_VALUE:
return true;
return indent == c.indent;
default:
return false;
}
Expand Down Expand Up @@ -7910,11 +7903,8 @@ class basic_deserializer {
apply_directive_set(node);
apply_node_properties(node);

const bool should_continue = deserialize_scalar(lexer, std::move(node), indent, line, token);
if (should_continue) {
continue;
}
break;
deserialize_scalar(lexer, std::move(node), indent, line, token);
continue;
}
case lexical_token_t::PLAIN_SCALAR:
case lexical_token_t::SINGLE_QUOTED_SCALAR:
Expand All @@ -7928,11 +7918,8 @@ class basic_deserializer {
apply_directive_set(node);
apply_node_properties(node);

const bool do_continue = deserialize_scalar(lexer, std::move(node), indent, line, token);
if (do_continue) {
continue;
}
break;
deserialize_scalar(lexer, std::move(node), indent, line, token);
continue;
}
case lexical_token_t::BLOCK_LITERAL_SCALAR:
case lexical_token_t::BLOCK_FOLDED_SCALAR: {
Expand Down Expand Up @@ -8046,10 +8033,12 @@ class basic_deserializer {
/// @param line The line where the key is found.
/// @param indent The indentation width in the current line where the key is found.
void add_new_key(basic_node_type&& key, const uint32_t line, const uint32_t indent) {
if (m_flow_context_depth == 0 && indent <= m_context_stack.back().indent) {
pop_to_parent_node(line, indent, [indent](const parse_context& c) {
return (indent == c.indent) && (c.state == context_state_t::BLOCK_MAPPING);
});
if (m_flow_context_depth == 0) {
if (indent <= m_context_stack.back().indent) {
pop_to_parent_node(line, indent, [indent](const parse_context& c) {
return (c.state == context_state_t::BLOCK_MAPPING) && (indent == c.indent);
});
}
}
else if FK_YAML_UNLIKELY (m_flow_token_state != flow_token_state_t::NEEDS_VALUE_OR_SUFFIX) {
throw parse_error("Flow mapping entry is found without separated with a comma.", line, indent);
Expand Down Expand Up @@ -8113,11 +8102,13 @@ class basic_deserializer {
/// @param line The number of processed lines. Can be updated in this function.
/// @param token The storage for last lexical token.
/// @return true if next token has already been got, false otherwise.
bool deserialize_scalar(
void deserialize_scalar(
lexer_type& lexer, basic_node_type&& node, uint32_t& indent, uint32_t& line, lexical_token& token) {
token = lexer.get_next_token();
if (mp_current_node->is_mapping()) {
if (token.type != lexical_token_t::KEY_SEPARATOR || line != lexer.get_lines_processed()) {
const bool is_key_sep_followed =
(token.type == lexical_token_t::KEY_SEPARATOR) && (line == lexer.get_lines_processed());
if FK_YAML_UNLIKELY (!is_key_sep_followed) {
throw parse_error(
"The \":\" mapping value indicator must be followed after a mapping key.",
lexer.get_lines_processed(),
Expand All @@ -8126,7 +8117,7 @@ class basic_deserializer {
add_new_key(std::move(node), line, indent);
}
else if (token.type == lexical_token_t::KEY_SEPARATOR) {
if (line != lexer.get_lines_processed()) {
if FK_YAML_UNLIKELY (line != lexer.get_lines_processed()) {
// This path is for explicit mapping key separator like:
//
// ```yaml
Expand All @@ -8141,7 +8132,7 @@ class basic_deserializer {
}
indent = lexer.get_last_token_begin_pos();
line = lexer.get_lines_processed();
return true;
return;
}

if (mp_current_node->is_scalar()) {
Expand Down Expand Up @@ -8188,9 +8179,9 @@ class basic_deserializer {
else {
assign_node_value(std::move(node), line, indent);
}

indent = lexer.get_last_token_begin_pos();
line = lexer.get_lines_processed();
return true;
}

/// @brief Pops parent contexts to a block mapping with the given indentation.
Expand All @@ -8206,7 +8197,9 @@ class basic_deserializer {
pop_num = static_cast<uint32_t>(m_context_stack.size() - 1);
}
else {
// LCOV_EXCL_START
auto itr = std::find_if(m_context_stack.rbegin(), m_context_stack.rend(), std::forward<Pred>(pred));
// LCOV_EXCL_STOP
const bool is_indent_valid = (itr != m_context_stack.rend());
if FK_YAML_UNLIKELY (!is_indent_valid) {
throw parse_error("Detected invalid indentation.", line, indent);
Expand Down
18 changes: 10 additions & 8 deletions test/unit_test/test_deserializer_class.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1063,7 +1063,6 @@ TEST_CASE("Deserializer_BlockMapping") {
}

// // regression test for https://github.com/fktn-k/fkYAML/issues/449
// FIXME: not passing
SECTION("missing the \":\" mapping value indicator after key (root)") {
std::string input = "1:\n"
"1";
Expand All @@ -1083,23 +1082,26 @@ TEST_CASE("Deserializer_BlockMapping") {
SECTION("block mapping which contains empty mapping values") {
std::string input = "foo:\n"
"bar:\n"
" baz:\n"
"qux:\n";
" foo:\n"
" bar:\n"
"baz:\n";

REQUIRE_NOTHROW(root = deserializer.deserialize(fkyaml::detail::input_adapter(input)));

REQUIRE(root.is_mapping());
REQUIRE(root.size() == 3);
REQUIRE(root.contains("foo"));
REQUIRE(root.contains("bar"));
REQUIRE(root.contains("qux"));
REQUIRE(root.contains("baz"));

REQUIRE(root["foo"].is_null());
REQUIRE(root["bar"].is_mapping());
REQUIRE(root["bar"].size() == 1);
REQUIRE(root["bar"].contains("baz"));
REQUIRE(root["bar"]["baz"].is_null());
REQUIRE(root["qux"].is_null());
REQUIRE(root["bar"].size() == 2);
REQUIRE(root["bar"].contains("foo"));
REQUIRE(root["bar"].contains("bar"));
REQUIRE(root["bar"]["foo"].is_null());
REQUIRE(root["bar"]["bar"].is_null());
REQUIRE(root["baz"].is_null());
}
}

Expand Down

0 comments on commit 8136f3f

Please sign in to comment.