Skip to content

Commit

Permalink
Merge pull request #492 from biojppm/fix/emit_empty_key
Browse files Browse the repository at this point in the history
Fix emit of explicit keys
  • Loading branch information
biojppm authored Jan 20, 2025
2 parents d4457b9 + 6291900 commit c7b792d
Show file tree
Hide file tree
Showing 10 changed files with 1,098 additions and 686 deletions.
6 changes: 0 additions & 6 deletions .github/workflows/infra.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,6 @@ env:
CMAKE_FLAGS: -DRYML_TEST_SUITE=ON
NUM_JOBS_BUILD: null
jobs:
log-github-event:
name: log github event
runs-on: ubuntu-24.04
steps:
- name: log github event
run: echo "${{toJSON(github.event)}}" || echo >/dev/null
check_workflows:
if: always()
continue-on-error: false
Expand Down
10 changes: 10 additions & 0 deletions changelog/current.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,16 @@
- add workarounds for problems with codegen of gcc 11,12,13.
- improve CI coverage of gcc and clang optimization levels.
- [BREAKING] Fix [#477](https://github.com/biojppm/rapidyaml/issues/477) ([PR#479](https://github.com/biojppm/rapidyaml/pull/479)): changed `read<std::map>()` to overwrite existing entries. The provided implementations had an inconsistency between `std::map` (which wasn't overwriting) and `std::vector` (which *was* overwriting).
- [PR#492](https://github.com/biojppm/rapidyaml/pull/492): fix emit of explicit keys when indented:
```yaml
fixed:
? explicit key
: value
previously:
? explicit key
: value # this was not indented
```
- [PR#492](https://github.com/biojppm/rapidyaml/pull/492): fix parser reset for full reuse (`m_doc_empty` was not resetted), which would cause problems under specific scenarios in subsequent reuse.


## Thanks
Expand Down
2 changes: 1 addition & 1 deletion ext/c4core
6 changes: 6 additions & 0 deletions src/c4/yml/emit.def.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -778,7 +778,10 @@ void Emitter<Writer>::_write_scalar_literal(csubstr s, id_type ilevel, bool expl
for(size_t i = !is_newline_only; i < numnewlines_at_end; ++i)
this->Writer::_do_write('\n');
if(explicit_key)
{
this->Writer::_do_write('\n');
this->_indent(ilevel);
}
}

template<class Writer>
Expand Down Expand Up @@ -856,7 +859,10 @@ void Emitter<Writer>::_write_scalar_folded(csubstr s, id_type ilevel, bool expli
for(size_t i = !is_newline_only; i < numnewlines_at_end; ++i)
this->Writer::_do_write('\n');
if(explicit_key)
{
this->Writer::_do_write('\n');
this->_indent(ilevel);
}
}

template<class Writer>
Expand Down
1 change: 1 addition & 0 deletions src/c4/yml/parse_engine.def.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -384,6 +384,7 @@ void ParseEngine<EventHandler>::_reset()
{
m_pending_anchors = {};
m_pending_tags = {};
m_doc_empty = true;
if(m_options.locations())
{
_prepare_locations();
Expand Down
1 change: 0 additions & 1 deletion test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,6 @@ ryml_add_test_case_group(map_generic)
ryml_add_test_case_group(map_set)
ryml_add_test_case_group(seq_of_map)
ryml_add_test_case_group(map_of_seq)
ryml_add_test_case_group(scalar_empty)
ryml_add_test_case_group(scalar_null)
ryml_add_test_case_group(scalar_squoted)
ryml_add_test_case_group(scalar_dquoted)
Expand Down
310 changes: 310 additions & 0 deletions test/test_emit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -359,6 +359,316 @@ TEST(emit, no_node)
test_emits(t, NONE, expected, expected_json);
}

TEST(emit, empty_key_squo)
{
{
SCOPED_TRACE("one only");
const Tree t = parse_in_arena(R"(
? ''
: literal
)");
std::string expected = "'': literal\n";
std::string expected_json = R"({"": "literal"})";
test_emits(t, t.root_id(), expected, expected_json);
}
{
SCOPED_TRACE("nested");
const Tree t = parse_in_arena(R"(
level1:
? ''
: literal
)");
std::string expected = "level1:\n '': literal\n";
std::string expected_json = R"({"level1": {"": "literal"}})";
test_emits(t, t.root_id(), expected, expected_json);
}
const Tree t = parse_in_arena(R"(
? ''
: literal
level1:
? ''
: literal
level2:
? ''
: literal
level3:
? ''
: literal
)");
{
SCOPED_TRACE("level3");
std::string expected = "level3:\n '': literal\n";
std::string expected_json = R"("level3": {"": "literal"})";
test_emits(t, t["level1"]["level2"]["level3"].id(), expected, expected_json);
}
{
SCOPED_TRACE("level2");
std::string expected = "level2:\n '': literal\n level3:\n '': literal\n";
std::string expected_json = "\"level2\": {\"\": \"literal\",\"level3\": {\"\": \"literal\"}}";
test_emits(t, t["level1"]["level2"].id(), expected, expected_json);
}
{
SCOPED_TRACE("level1");
std::string expected = "level1:\n '': literal\n level2:\n '': literal\n level3:\n '': literal\n";
std::string expected_json = "\"level1\": {\"\": \"literal\",\"level2\": {\"\": \"literal\",\"level3\": {\"\": \"literal\"}}}";
test_emits(t, t["level1"].id(), expected, expected_json);
}
{
SCOPED_TRACE("level0");
std::string expected = "'': literal\nlevel1:\n '': literal\n level2:\n '': literal\n level3:\n '': literal\n";
std::string expected_json = "{\"\": \"literal\",\"level1\": {\"\": \"literal\",\"level2\": {\"\": \"literal\",\"level3\": {\"\": \"literal\"}}}}";
test_emits(t, NONE, expected, expected_json);
}
}

TEST(emit, empty_key_dquo)
{
{
SCOPED_TRACE("one only");
const Tree t = parse_in_arena(R"(
? ""
: literal
)");
std::string expected = "\"\": literal\n";
std::string expected_json = R"({"": "literal"})";
test_emits(t, t.root_id(), expected, expected_json);
}
{
SCOPED_TRACE("nested");
const Tree t = parse_in_arena(R"(
level1:
? ""
: literal
)");
std::string expected = "level1:\n \"\": literal\n";
std::string expected_json = R"({"level1": {"": "literal"}})";
test_emits(t, t.root_id(), expected, expected_json);
}
const Tree t = parse_in_arena(R"(
? ""
: literal
level1:
? ""
: literal
level2:
? ""
: literal
level3:
? ""
: literal
)");
{
SCOPED_TRACE("level3");
std::string expected = "level3:\n \"\": literal\n";
std::string expected_json = R"("level3": {"": "literal"})";
test_emits(t, t["level1"]["level2"]["level3"].id(), expected, expected_json);
}
{
SCOPED_TRACE("level2");
std::string expected = "level2:\n \"\": literal\n level3:\n \"\": literal\n";
std::string expected_json = "\"level2\": {\"\": \"literal\",\"level3\": {\"\": \"literal\"}}";
test_emits(t, t["level1"]["level2"].id(), expected, expected_json);
}
{
SCOPED_TRACE("level1");
std::string expected = "level1:\n \"\": literal\n level2:\n \"\": literal\n level3:\n \"\": literal\n";
std::string expected_json = "\"level1\": {\"\": \"literal\",\"level2\": {\"\": \"literal\",\"level3\": {\"\": \"literal\"}}}";
test_emits(t, t["level1"].id(), expected, expected_json);
}
{
SCOPED_TRACE("level0");
std::string expected = "\"\": literal\nlevel1:\n \"\": literal\n level2:\n \"\": literal\n level3:\n \"\": literal\n";
std::string expected_json = "{\"\": \"literal\",\"level1\": {\"\": \"literal\",\"level2\": {\"\": \"literal\",\"level3\": {\"\": \"literal\"}}}}";
test_emits(t, NONE, expected, expected_json);
}
}

TEST(emit, empty_key_plain)
{
{
SCOPED_TRACE("one only");
const Tree t = parse_in_arena(R"(
?
: literal
)");
std::string expected = ": literal\n";
std::string expected_json = R"({"": "literal"})";
test_emits(t, t.root_id(), expected, expected_json);
}
{
SCOPED_TRACE("nested");
const Tree t = parse_in_arena(R"(
level1:
?
: literal
)");
std::string expected = "level1:\n : literal\n";
std::string expected_json = R"({"level1": {"": "literal"}})";
test_emits(t, t.root_id(), expected, expected_json);
}
const Tree t = parse_in_arena(R"(
?
: literal
level1:
?
: literal
level2:
?
: literal
level3:
?
: literal
)");
{
SCOPED_TRACE("level3");
std::string expected = "level3:\n : literal\n";
std::string expected_json = R"("level3": {"": "literal"})";
test_emits(t, t["level1"]["level2"]["level3"].id(), expected, expected_json);
}
{
SCOPED_TRACE("level2");
std::string expected = "level2:\n : literal\n level3:\n : literal\n";
std::string expected_json = "\"level2\": {\"\": \"literal\",\"level3\": {\"\": \"literal\"}}";
test_emits(t, t["level1"]["level2"].id(), expected, expected_json);
}
{
SCOPED_TRACE("level1");
std::string expected = "level1:\n : literal\n level2:\n : literal\n level3:\n : literal\n";
std::string expected_json = "\"level1\": {\"\": \"literal\",\"level2\": {\"\": \"literal\",\"level3\": {\"\": \"literal\"}}}";
test_emits(t, t["level1"].id(), expected, expected_json);
}
{
SCOPED_TRACE("level0");
std::string expected = ": literal\nlevel1:\n : literal\n level2:\n : literal\n level3:\n : literal\n";
std::string expected_json = "{\"\": \"literal\",\"level1\": {\"\": \"literal\",\"level2\": {\"\": \"literal\",\"level3\": {\"\": \"literal\"}}}}";
test_emits(t, NONE, expected, expected_json);
}
}

TEST(emit, empty_key_literal)
{
{
SCOPED_TRACE("one only");
const Tree t = parse_in_arena(R"(
? |-
: literal
)");
std::string expected = "? |-\n: literal\n";
std::string expected_json = R"({"": "literal"})";
test_emits(t, t.root_id(), expected, expected_json);
}
{
SCOPED_TRACE("nested");
const Tree t = parse_in_arena(R"(
level1:
? |-
: literal
)");
std::string expected = "level1:\n ? |-\n : literal\n";
std::string expected_json = R"({"level1": {"": "literal"}})";
test_emits(t, t.root_id(), expected, expected_json);
}
const Tree t = parse_in_arena(R"(
? |-
: literal
level1:
? |-
: literal
level2:
? |-
: literal
level3:
? |-
: literal
)");
{
SCOPED_TRACE("level3");
std::string expected = "level3:\n ? |-\n : literal\n";
std::string expected_json = R"("level3": {"": "literal"})";
test_emits(t, t["level1"]["level2"]["level3"].id(), expected, expected_json);
}
{
SCOPED_TRACE("level2");
std::string expected = "level2:\n ? |-\n : literal\n level3:\n ? |-\n : literal\n";
std::string expected_json = "\"level2\": {\"\": \"literal\",\"level3\": {\"\": \"literal\"}}";
test_emits(t, t["level1"]["level2"].id(), expected, expected_json);
}
{
SCOPED_TRACE("level1");
std::string expected = "level1:\n ? |-\n : literal\n level2:\n ? |-\n : literal\n level3:\n ? |-\n : literal\n";
std::string expected_json = "\"level1\": {\"\": \"literal\",\"level2\": {\"\": \"literal\",\"level3\": {\"\": \"literal\"}}}";
test_emits(t, t["level1"].id(), expected, expected_json);
}
{
SCOPED_TRACE("level0");
std::string expected = "? |-\n: literal\nlevel1:\n ? |-\n : literal\n level2:\n ? |-\n : literal\n level3:\n ? |-\n : literal\n";
std::string expected_json = "{\"\": \"literal\",\"level1\": {\"\": \"literal\",\"level2\": {\"\": \"literal\",\"level3\": {\"\": \"literal\"}}}}";
test_emits(t, NONE, expected, expected_json);
}
}

TEST(emit, empty_key_folded)
{
{
SCOPED_TRACE("one only");
const Tree t = parse_in_arena(R"(
? >-
: folded
)");
std::string expected = "? >-\n: folded\n";
std::string expected_json = R"({"": "folded"})";
test_emits(t, t.root_id(), expected, expected_json);
}
{
SCOPED_TRACE("nested");
const Tree t = parse_in_arena(R"(
level1:
? >-
: folded
)");
std::string expected = "level1:\n ? >-\n : folded\n";
std::string expected_json = R"({"level1": {"": "folded"}})";
test_emits(t, t.root_id(), expected, expected_json);
}
const Tree t = parse_in_arena(R"(
? >-
: folded
level1:
? >-
: folded
level2:
? >-
: folded
level3:
? >-
: folded
)");
{
SCOPED_TRACE("level3");
std::string expected = "level3:\n ? >-\n : folded\n";
std::string expected_json = R"("level3": {"": "folded"})";
test_emits(t, t["level1"]["level2"]["level3"].id(), expected, expected_json);
}
{
SCOPED_TRACE("level2");
std::string expected = "level2:\n ? >-\n : folded\n level3:\n ? >-\n : folded\n";
std::string expected_json = "\"level2\": {\"\": \"folded\",\"level3\": {\"\": \"folded\"}}";
test_emits(t, t["level1"]["level2"].id(), expected, expected_json);
}
{
SCOPED_TRACE("level1");
std::string expected = "level1:\n ? >-\n : folded\n level2:\n ? >-\n : folded\n level3:\n ? >-\n : folded\n";
std::string expected_json = "\"level1\": {\"\": \"folded\",\"level2\": {\"\": \"folded\",\"level3\": {\"\": \"folded\"}}}";
test_emits(t, t["level1"].id(), expected, expected_json);
}
{
SCOPED_TRACE("level0");
std::string expected = "? >-\n: folded\nlevel1:\n ? >-\n : folded\n level2:\n ? >-\n : folded\n level3:\n ? >-\n : folded\n";
std::string expected_json = "{\"\": \"folded\",\"level1\": {\"\": \"folded\",\"level2\": {\"\": \"folded\",\"level3\": {\"\": \"folded\"}}}}";
test_emits(t, NONE, expected, expected_json);
}
}

TEST(emit, existing_seq_node_flow)
{
Tree nct = parse_in_arena("[foo, bar, [nested, seq], {nested: map}]");
Expand Down
Loading

0 comments on commit c7b792d

Please sign in to comment.