From 98d58d0b4dbb5575cada7694f5ef60cc247befd0 Mon Sep 17 00:00:00 2001 From: Robert Haschke Date: Sun, 11 Mar 2018 10:47:56 +0100 Subject: [PATCH 1/4] failing unittest The failure is related to the assignment to the very same Node "value". If different Nodes are used each time, it works. If no alias is involved, it works as well. --- test/integration/load_node_test.cpp | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/test/integration/load_node_test.cpp b/test/integration/load_node_test.cpp index 02bb8fe58..4a782963b 100644 --- a/test/integration/load_node_test.cpp +++ b/test/integration/load_node_test.cpp @@ -78,6 +78,22 @@ TEST(LoadNodeTest, IterateMap) { EXPECT_EQ(3, i); } +TEST(LoadNodeTest, AliasMultipleAssign) { + Node doc = Load("{A: &DEFAULT {str: string, int: 42, float: 3.1415}, B: *DEFAULT}"); + + for (YAML::const_iterator it = doc.begin(); it != doc.end(); ++it) { + SCOPED_TRACE("group " + it->first.as()); + Node value; + + value = it->second["str"]; + EXPECT_STREQ(value.as().c_str(), "string"); + value = it->second["float"]; + EXPECT_EQ(value.as(), 3.1415f); + value = it->second["int"]; + EXPECT_EQ(value.as(), 42); + } +} + #ifdef BOOST_FOREACH TEST(LoadNodeTest, ForEach) { Node node = Load("[1, 3, 5, 7]"); From 1b38ced1750ad4e831c57ee8632666668a471176 Mon Sep 17 00:00:00 2001 From: Robert Haschke Date: Sat, 17 Mar 2018 17:30:39 +0100 Subject: [PATCH 2/4] remove include to avoid warnings about unused variables --- test/integration/handler_test.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/test/integration/handler_test.cpp b/test/integration/handler_test.cpp index 601146071..da9a10c1a 100644 --- a/test/integration/handler_test.cpp +++ b/test/integration/handler_test.cpp @@ -1,5 +1,4 @@ #include "handler_test.h" -#include "specexamples.h" // IWYU pragma: keep #include "yaml-cpp/yaml.h" // IWYU pragma: keep #include "gmock/gmock.h" From 7542e041518f5ed973b5276ab4d05c8e25da11b1 Mon Sep 17 00:00:00 2001 From: Robert Haschke Date: Sat, 17 Mar 2018 17:58:55 +0100 Subject: [PATCH 3/4] make alias assignment explicit --- include/yaml-cpp/node/impl.h | 11 ++++++----- include/yaml-cpp/node/node.h | 10 ++++++++++ 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/include/yaml-cpp/node/impl.h b/include/yaml-cpp/node/impl.h index 20c487a68..fdca08422 100644 --- a/include/yaml-cpp/node/impl.h +++ b/include/yaml-cpp/node/impl.h @@ -239,11 +239,12 @@ inline void Node::Assign(char* rhs) { } inline Node& Node::operator=(const Node& rhs) { - if (!m_isValid || !rhs.m_isValid) - throw InvalidNode(); - if (is(rhs)) - return *this; - AssignNode(rhs); + AssignData(rhs); + return *this; +} + +inline Node& Node::operator=(const NodeAlias& rhs) { + AssignNode(rhs.m_node); return *this; } diff --git a/include/yaml-cpp/node/node.h b/include/yaml-cpp/node/node.h index 1ded7d27b..5d82368fc 100644 --- a/include/yaml-cpp/node/node.h +++ b/include/yaml-cpp/node/node.h @@ -26,6 +26,7 @@ struct iterator_value; } // namespace YAML namespace YAML { +class YAML_CPP_API NodeAlias; class YAML_CPP_API Node { public: friend class NodeBuilder; @@ -81,6 +82,7 @@ class YAML_CPP_API Node { template Node& operator=(const T& rhs); Node& operator=(const Node& rhs); + Node& operator=(const NodeAlias& rhs); void reset(const Node& rhs = Node()); // size/iterator @@ -134,6 +136,14 @@ class YAML_CPP_API Node { mutable detail::node* m_pNode; }; +class NodeAlias { + friend class Node; +public: + NodeAlias(const Node& node) : m_node(node) {} +private: + const Node& m_node; +}; + YAML_CPP_API bool operator==(const Node& lhs, const Node& rhs); YAML_CPP_API Node Clone(const Node& node); From 61e237d892b52d865be1cd2df77058b55be6aecb Mon Sep 17 00:00:00 2001 From: Robert Haschke Date: Sat, 17 Mar 2018 17:59:32 +0100 Subject: [PATCH 4/4] adapt unittests, to use explicit alias assignment where intended --- test/node/node_test.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/test/node/node_test.cpp b/test/node/node_test.cpp index 485ad09e1..e6f105446 100644 --- a/test/node/node_test.cpp +++ b/test/node/node_test.cpp @@ -254,7 +254,7 @@ TEST(NodeTest, StdPair) { TEST(NodeTest, SimpleAlias) { Node node; node["foo"] = "value"; - node["bar"] = node["foo"]; + node["bar"] = NodeAlias(node["foo"]); EXPECT_EQ("value", node["foo"].as()); EXPECT_EQ("value", node["bar"].as()); EXPECT_EQ(node["bar"], node["foo"]); @@ -274,7 +274,7 @@ TEST(NodeTest, AliasAsKey) { TEST(NodeTest, SelfReferenceSequence) { Node node; - node[0] = node; + node[0] = NodeAlias(node); EXPECT_TRUE(node.IsSequence()); EXPECT_EQ(1, node.size()); EXPECT_EQ(node, node[0]); @@ -284,7 +284,7 @@ TEST(NodeTest, SelfReferenceSequence) { TEST(NodeTest, ValueSelfReferenceMap) { Node node; - node["key"] = node; + node["key"] = NodeAlias(node); EXPECT_TRUE(node.IsMap()); EXPECT_EQ(1, node.size()); EXPECT_EQ(node, node["key"]); @@ -302,7 +302,7 @@ TEST(NodeTest, KeySelfReferenceMap) { TEST(NodeTest, SelfReferenceMap) { Node node; - node[node] = node; + node[node] = NodeAlias(node); EXPECT_TRUE(node.IsMap()); EXPECT_EQ(1, node.size()); EXPECT_EQ(node, node[node]); @@ -322,7 +322,7 @@ TEST(NodeTest, TempMapVariable) { TEST(NodeTest, TempMapVariableAlias) { Node node; Node tmp = node["key"]; - tmp = node["other"]; + tmp = NodeAlias(node["other"]); node["other"] = "value"; EXPECT_TRUE(node.IsMap()); EXPECT_EQ(2, node.size());