Merge 377a93d3d1 into 39f737443b
This commit is contained in:
commit
a2292058a7
@ -139,7 +139,7 @@ class YAML_CPP_API Node {
|
|||||||
|
|
||||||
YAML_CPP_API bool operator==(const Node& lhs, const Node& rhs);
|
YAML_CPP_API bool operator==(const Node& lhs, const Node& rhs);
|
||||||
|
|
||||||
YAML_CPP_API Node Clone(const Node& node);
|
YAML_CPP_API Node Clone(const Node& node, bool preserveMarks = false);
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
struct convert;
|
struct convert;
|
||||||
|
|||||||
@ -3,10 +3,10 @@
|
|||||||
#include "nodeevents.h"
|
#include "nodeevents.h"
|
||||||
|
|
||||||
namespace YAML {
|
namespace YAML {
|
||||||
Node Clone(const Node& node) {
|
Node Clone(const Node& node, bool preserveMarks) {
|
||||||
NodeEvents events(node);
|
NodeEvents events(node);
|
||||||
NodeBuilder builder;
|
NodeBuilder builder;
|
||||||
events.Emit(builder);
|
events.Emit(builder, preserveMarks);
|
||||||
return builder.Root();
|
return builder.Root();
|
||||||
}
|
}
|
||||||
} // namespace YAML
|
} // namespace YAML
|
||||||
|
|||||||
@ -42,17 +42,17 @@ void NodeEvents::Setup(const detail::node& node) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void NodeEvents::Emit(EventHandler& handler) {
|
void NodeEvents::Emit(EventHandler& handler, bool preserveMarks) {
|
||||||
AliasManager am;
|
AliasManager am;
|
||||||
|
|
||||||
handler.OnDocumentStart(Mark());
|
handler.OnDocumentStart(Mark());
|
||||||
if (m_root)
|
if (m_root)
|
||||||
Emit(*m_root, handler, am);
|
Emit(*m_root, handler, am, preserveMarks);
|
||||||
handler.OnDocumentEnd();
|
handler.OnDocumentEnd();
|
||||||
}
|
}
|
||||||
|
|
||||||
void NodeEvents::Emit(const detail::node& node, EventHandler& handler,
|
void NodeEvents::Emit(const detail::node& node, EventHandler& handler,
|
||||||
AliasManager& am) const {
|
AliasManager& am, bool preserveMarks) const {
|
||||||
anchor_t anchor = NullAnchor;
|
anchor_t anchor = NullAnchor;
|
||||||
if (IsAliased(node)) {
|
if (IsAliased(node)) {
|
||||||
anchor = am.LookupAnchor(node);
|
anchor = am.LookupAnchor(node);
|
||||||
@ -65,26 +65,30 @@ void NodeEvents::Emit(const detail::node& node, EventHandler& handler,
|
|||||||
anchor = am.LookupAnchor(node);
|
anchor = am.LookupAnchor(node);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto getMark = [preserveMarks, &node]() {
|
||||||
|
return preserveMarks ? node.mark() : Mark();
|
||||||
|
};
|
||||||
|
|
||||||
switch (node.type()) {
|
switch (node.type()) {
|
||||||
case NodeType::Undefined:
|
case NodeType::Undefined:
|
||||||
break;
|
break;
|
||||||
case NodeType::Null:
|
case NodeType::Null:
|
||||||
handler.OnNull(Mark(), anchor);
|
handler.OnNull(getMark(), anchor);
|
||||||
break;
|
break;
|
||||||
case NodeType::Scalar:
|
case NodeType::Scalar:
|
||||||
handler.OnScalar(Mark(), node.tag(), anchor, node.scalar());
|
handler.OnScalar(getMark(), node.tag(), anchor, node.scalar());
|
||||||
break;
|
break;
|
||||||
case NodeType::Sequence:
|
case NodeType::Sequence:
|
||||||
handler.OnSequenceStart(Mark(), node.tag(), anchor, node.style());
|
handler.OnSequenceStart(getMark(), node.tag(), anchor, node.style());
|
||||||
for (auto element : node)
|
for (auto element : node)
|
||||||
Emit(*element, handler, am);
|
Emit(*element, handler, am, preserveMarks);
|
||||||
handler.OnSequenceEnd();
|
handler.OnSequenceEnd();
|
||||||
break;
|
break;
|
||||||
case NodeType::Map:
|
case NodeType::Map:
|
||||||
handler.OnMapStart(Mark(), node.tag(), anchor, node.style());
|
handler.OnMapStart(getMark(), node.tag(), anchor, node.style());
|
||||||
for (auto element : node) {
|
for (auto element : node) {
|
||||||
Emit(*element.first, handler, am);
|
Emit(*element.first, handler, am, preserveMarks);
|
||||||
Emit(*element.second, handler, am);
|
Emit(*element.second, handler, am, preserveMarks);
|
||||||
}
|
}
|
||||||
handler.OnMapEnd();
|
handler.OnMapEnd();
|
||||||
break;
|
break;
|
||||||
|
|||||||
@ -31,7 +31,7 @@ class NodeEvents {
|
|||||||
NodeEvents& operator=(const NodeEvents&) = delete;
|
NodeEvents& operator=(const NodeEvents&) = delete;
|
||||||
NodeEvents& operator=(NodeEvents&&) = delete;
|
NodeEvents& operator=(NodeEvents&&) = delete;
|
||||||
|
|
||||||
void Emit(EventHandler& handler);
|
void Emit(EventHandler& handler, bool preserveMarks = false);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
class AliasManager {
|
class AliasManager {
|
||||||
@ -52,8 +52,8 @@ class NodeEvents {
|
|||||||
};
|
};
|
||||||
|
|
||||||
void Setup(const detail::node& node);
|
void Setup(const detail::node& node);
|
||||||
void Emit(const detail::node& node, EventHandler& handler,
|
void Emit(const detail::node& node, EventHandler& handler, AliasManager& am,
|
||||||
AliasManager& am) const;
|
bool preserveMarks) const;
|
||||||
bool IsAliased(const detail::node& node) const;
|
bool IsAliased(const detail::node& node) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|||||||
84
test/integration/clone_node_test.cpp
Normal file
84
test/integration/clone_node_test.cpp
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
#include "gmock/gmock.h"
|
||||||
|
#include "gtest/gtest.h"
|
||||||
|
#include <yaml-cpp/yaml.h>
|
||||||
|
|
||||||
|
struct ComparableMark {
|
||||||
|
int pos;
|
||||||
|
int line, column;
|
||||||
|
|
||||||
|
ComparableMark(int pos, int line, int column)
|
||||||
|
: pos(pos), line(line), column(column) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
bool operator==(const YAML::Mark& a, const ComparableMark& b) {
|
||||||
|
return a.pos == b.pos && a.line == b.line && a.column == b.column;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Mark>
|
||||||
|
void PrintMark(const Mark& mark, std::ostream* os) {
|
||||||
|
*os << mark.line << ':' << mark.column << " (pos " << mark.pos << ')';
|
||||||
|
}
|
||||||
|
|
||||||
|
void PrintTo(const ComparableMark& mark, std::ostream* os) {
|
||||||
|
PrintMark(mark, os);
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace YAML {
|
||||||
|
void PrintTo(const Mark& mark, std::ostream* os) { PrintMark(mark, os); }
|
||||||
|
} // namespace YAML
|
||||||
|
|
||||||
|
TEST(CloneNodeTest, PreserveMark) {
|
||||||
|
std::string yaml_str = R"(
|
||||||
|
scalar: value
|
||||||
|
sequence: [1, 2, 3]
|
||||||
|
"null": null
|
||||||
|
[1, 2, 3]: value # check non-scalar keys
|
||||||
|
)";
|
||||||
|
|
||||||
|
auto checkMarks = [](const YAML::Node& root_node) {
|
||||||
|
EXPECT_EQ(root_node.Mark(), ComparableMark(1, 1, 0));
|
||||||
|
|
||||||
|
const YAML::Node& scalar = root_node["scalar"];
|
||||||
|
EXPECT_EQ(scalar.Mark(), ComparableMark(9, 1, 8));
|
||||||
|
|
||||||
|
const YAML::Node& sequence = root_node["sequence"];
|
||||||
|
EXPECT_EQ(sequence.Mark(), ComparableMark(25, 2, 10));
|
||||||
|
EXPECT_EQ(sequence[0].Mark(), ComparableMark(26, 2, 11));
|
||||||
|
EXPECT_EQ(sequence[1].Mark(), ComparableMark(29, 2, 14));
|
||||||
|
EXPECT_EQ(sequence[2].Mark(), ComparableMark(32, 2, 17));
|
||||||
|
|
||||||
|
const YAML::Node& null = root_node["null"];
|
||||||
|
EXPECT_EQ(null.Mark(), ComparableMark(43, 3, 8));
|
||||||
|
|
||||||
|
YAML::Node sequence_key;
|
||||||
|
std::vector<YAML::Mark> key_marks;
|
||||||
|
for (auto it = root_node.begin(); it != root_node.end(); ++it) {
|
||||||
|
// Not assuming any key order
|
||||||
|
key_marks.emplace_back(it->first.Mark());
|
||||||
|
if (it->first.IsSequence()) {
|
||||||
|
sequence_key.reset(it->first);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
EXPECT_THAT(key_marks,
|
||||||
|
testing::UnorderedElementsAre(
|
||||||
|
ComparableMark(1, 1, 0), ComparableMark(15, 2, 0),
|
||||||
|
ComparableMark(35, 3, 0), ComparableMark(48, 4, 0)));
|
||||||
|
|
||||||
|
ASSERT_TRUE(sequence_key);
|
||||||
|
EXPECT_EQ(sequence_key[0].Mark(), ComparableMark(49, 4, 1));
|
||||||
|
EXPECT_EQ(sequence_key[1].Mark(), ComparableMark(52, 4, 4));
|
||||||
|
EXPECT_EQ(sequence_key[2].Mark(), ComparableMark(55, 4, 7));
|
||||||
|
};
|
||||||
|
|
||||||
|
YAML::Node root_node = YAML::Load(yaml_str);
|
||||||
|
{
|
||||||
|
SCOPED_TRACE("original node");
|
||||||
|
checkMarks(root_node);
|
||||||
|
}
|
||||||
|
YAML::Node cloned_node = YAML::Clone(root_node, true);
|
||||||
|
{
|
||||||
|
SCOPED_TRACE("cloned node");
|
||||||
|
checkMarks(cloned_node);
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user