Merge pull request #547 from biojppm/fix/firstdocseq

fix Tree::set_root_as_stream() when the original root is an empty seq
This commit is contained in:
jpmag
2025-10-02 22:25:20 +01:00
committed by GitHub
5 changed files with 216 additions and 15 deletions

View File

@@ -0,0 +1,8 @@
### Changes
- [PR#547](https://github.com/biojppm/rapidyaml/pull/547) - Fix parsing of implicit first documents with empty sequences, caused by a problem in `Tree::set_root_as_stream()`:
```yaml
[] # this container was lost during parsing
---
more data here
```

View File

@@ -190,7 +190,7 @@ public:
id_type first = m_tree->first_child(m_tree->root_id());
_RYML_CB_ASSERT(m_stack.m_callbacks, m_tree->is_stream(m_tree->root_id()));
_RYML_CB_ASSERT(m_stack.m_callbacks, m_tree->num_children(m_tree->root_id()) == 1u);
if(m_tree->has_children(first) || m_tree->is_val(first))
if(m_tree->is_container(first) || m_tree->is_val(first))
{
_c4dbgp("push!");
_push();
@@ -693,15 +693,10 @@ public:
_c4dbgp("set root as stream");
_RYML_CB_ASSERT(m_tree->callbacks(), m_tree->root_id() == 0u);
_RYML_CB_ASSERT(m_tree->callbacks(), m_curr->node_id == 0u);
const bool hack = !m_tree->has_children(m_curr->node_id) && !m_tree->is_val(m_curr->node_id);
if(hack)
m_tree->_p(m_tree->root_id())->m_type.add(VAL);
m_tree->set_root_as_stream();
_RYML_CB_ASSERT(m_tree->callbacks(), m_tree->is_stream(m_tree->root_id()));
_RYML_CB_ASSERT(m_tree->callbacks(), m_tree->has_children(m_tree->root_id()));
_RYML_CB_ASSERT(m_tree->callbacks(), m_tree->is_doc(m_tree->first_child(m_tree->root_id())));
if(hack)
m_tree->_p(m_tree->first_child(m_tree->root_id()))->m_type.rem(VAL);
_set_state_(m_curr, m_tree->root_id());
}

View File

@@ -825,7 +825,13 @@ void Tree::set_root_as_stream()
// don't use _add_flags() because it's checked and will fail
if(!has_children(root))
{
if(is_val(root))
if(is_container(root))
{
id_type next_doc = append_child(root);
_copy_props_wo_key(next_doc, root);
_p(next_doc)->m_type.add(DOC);
}
else
{
_p(root)->m_type.add(SEQ);
id_type next_doc = append_child(root);

View File

@@ -909,10 +909,10 @@ ENGINE_TEST(DocStream,
//-----------------------------------------------------------------------------
ENGINE_TEST(DocStreamImplicitDocFirst,
"doc0\n--- doc1\n--- doc2\n"
ENGINE_TEST(DocStreamImplicitDocFirstVal,
"doc0\n--- doc1\n"
,
"--- doc0\n--- doc1\n--- doc2\n"
"--- doc0\n--- doc1\n"
,
"+STR\n"
"+DOC\n"
@@ -921,9 +921,6 @@ ENGINE_TEST(DocStreamImplicitDocFirst,
"+DOC ---\n"
"=VAL :doc1\n"
"-DOC\n"
"+DOC ---\n"
"=VAL :doc2\n"
"-DOC\n"
"-STR\n")
{
___(ps.begin_stream());
@@ -933,8 +930,201 @@ ENGINE_TEST(DocStreamImplicitDocFirst,
___(ps.begin_doc_expl());
___(ps.set_val_scalar_plain("doc1"));
___(ps.end_doc());
___(ps.end_stream());
}
ENGINE_TEST(DocStreamImplicitDocFirstAnchor,
"&anch1\n"
"--- &anch2\n"
,
"--- &anch1 \n"
"--- &anch2 \n"
,
"+STR\n"
"+DOC\n"
"=VAL &anch1 :\n"
"-DOC\n"
"+DOC ---\n"
"=VAL &anch2 :\n"
"-DOC\n"
"-STR\n")
{
___(ps.begin_stream());
___(ps.begin_doc());
___(ps.set_val_anchor("anch1"));
___(ps.set_val_scalar_plain_empty());
___(ps.end_doc());
___(ps.begin_doc_expl());
___(ps.set_val_scalar_plain("doc2"));
___(ps.set_val_anchor("anch2"));
___(ps.set_val_scalar_plain_empty());
___(ps.end_doc());
___(ps.end_stream());
}
ENGINE_TEST(DocStreamImplicitDocFirstTag,
"!!str\n"
"--- !!str\n"
,
"--- !!str \n"
"--- !!str \n"
,
"+STR\n"
"+DOC\n"
"=VAL <tag:yaml.org,2002:str> :\n"
"-DOC\n"
"+DOC ---\n"
"=VAL <tag:yaml.org,2002:str> :\n"
"-DOC\n"
"-STR\n")
{
___(ps.begin_stream());
___(ps.begin_doc());
___(ps.set_val_tag("!!str"));
___(ps.set_val_scalar_plain_empty());
___(ps.end_doc());
___(ps.begin_doc_expl());
___(ps.set_val_tag("!!str"));
___(ps.set_val_scalar_plain_empty());
___(ps.end_doc());
___(ps.end_stream());
}
ENGINE_TEST(DocStreamImplicitDocFirstSeqFlowEmpty,
"[]\n"
"--- []\n"
,
"---\n"
"[]\n"
"---\n"
"[]\n"
,
"+STR\n"
"+DOC\n"
"+SEQ []\n"
"-SEQ\n"
"-DOC\n"
"+DOC ---\n"
"+SEQ []\n"
"-SEQ\n"
"-DOC\n"
"-STR\n")
{
___(ps.begin_stream());
___(ps.begin_doc());
___(ps.begin_seq_val_flow());
___(ps.end_seq());
___(ps.end_doc());
___(ps.begin_doc_expl());
___(ps.begin_seq_val_flow());
___(ps.end_seq());
___(ps.end_doc());
___(ps.end_stream());
}
ENGINE_TEST(DocStreamImplicitDocFirstSeqFlow,
"[a]\n"
"--- [b]\n"
,
"---\n"
"[a]\n"
"---\n"
"[b]\n"
,
"+STR\n"
"+DOC\n"
"+SEQ []\n"
"=VAL :a\n"
"-SEQ\n"
"-DOC\n"
"+DOC ---\n"
"+SEQ []\n"
"=VAL :b\n"
"-SEQ\n"
"-DOC\n"
"-STR\n")
{
___(ps.begin_stream());
___(ps.begin_doc());
___(ps.begin_seq_val_flow());
___(ps.set_val_scalar_plain("a"));
___(ps.end_seq());
___(ps.end_doc());
___(ps.begin_doc_expl());
___(ps.begin_seq_val_flow());
___(ps.set_val_scalar_plain("b"));
___(ps.end_seq());
___(ps.end_doc());
___(ps.end_stream());
}
ENGINE_TEST(DocStreamImplicitDocFirstMapEmpty,
"{}\n"
"--- {}\n"
,
"---\n"
"{}\n"
"---\n"
"{}\n"
,
"+STR\n"
"+DOC\n"
"+MAP {}\n"
"-MAP\n"
"-DOC\n"
"+DOC ---\n"
"+MAP {}\n"
"-MAP\n"
"-DOC\n"
"-STR\n")
{
___(ps.begin_stream());
___(ps.begin_doc());
___(ps.begin_map_val_flow());
___(ps.end_map());
___(ps.end_doc());
___(ps.begin_doc_expl());
___(ps.begin_map_val_flow());
___(ps.end_map());
___(ps.end_doc());
___(ps.end_stream());
}
ENGINE_TEST(DocStreamImplicitDocFirstMap,
"{a: b}\n"
"--- {c: d}\n"
,
"---\n"
"{a: b}\n"
"---\n"
"{c: d}\n"
,
"+STR\n"
"+DOC\n"
"+MAP {}\n"
"=VAL :a\n"
"=VAL :b\n"
"-MAP\n"
"-DOC\n"
"+DOC ---\n"
"+MAP {}\n"
"=VAL :c\n"
"=VAL :d\n"
"-MAP\n"
"-DOC\n"
"-STR\n")
{
___(ps.begin_stream());
___(ps.begin_doc());
___(ps.begin_map_val_flow());
___(ps.set_key_scalar_plain("a"));
___(ps.set_val_scalar_plain("b"));
___(ps.end_map());
___(ps.end_doc());
___(ps.begin_doc_expl());
___(ps.begin_map_val_flow());
___(ps.set_key_scalar_plain("c"));
___(ps.set_val_scalar_plain("d"));
___(ps.end_map());
___(ps.end_doc());
___(ps.end_stream());
}

View File

@@ -4132,8 +4132,10 @@ TEST(set_root_as_stream, empty_tree)
EXPECT_EQ(r.is_stream(), false);
EXPECT_EQ(r.num_children(), 0u);
t.set_root_as_stream();
r = t.rootref();
EXPECT_EQ(r.is_stream(), true);
EXPECT_EQ(r.num_children(), 0u);
ASSERT_EQ(r.num_children(), 1u);
EXPECT_EQ(r[0].is_doc(), 1u);
}
TEST(set_root_as_stream, already_with_stream)