1 // Copyright 2015 The Weave Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "src/notification/xml_node.h"
6 
7 #include <memory>
8 
9 #include <gtest/gtest.h>
10 
11 #include "src/notification/xmpp_stream_parser.h"
12 
13 namespace weave {
14 namespace {
15 
16 class XmlParser : public XmppStreamParser::Delegate {
17  public:
Parse(const std::string & xml)18   std::unique_ptr<XmlNode> Parse(const std::string& xml) {
19     parser_.ParseData(xml);
20     return std::move(node_);
21   }
22 
23  private:
24   // Overrides from XmppStreamParser::Delegate.
OnStreamStart(const std::string & node_name,std::map<std::string,std::string> attributes)25   void OnStreamStart(const std::string& node_name,
26                      std::map<std::string, std::string> attributes) override {
27     node_.reset(new XmlNode{node_name, std::move(attributes)});
28   }
29 
OnStreamEnd(const std::string & node_name)30   void OnStreamEnd(const std::string& node_name) override {}
31 
OnStanza(std::unique_ptr<XmlNode> stanza)32   void OnStanza(std::unique_ptr<XmlNode> stanza) override {
33     node_->AddChild(std::move(stanza));
34   }
35 
36   std::unique_ptr<XmlNode> node_;
37   XmppStreamParser parser_{this};
38 };
39 
40 }  // anonymous namespace
41 
42 class XmlNodeTest : public testing::Test {
43  public:
SetUp()44   void SetUp() override {
45     node_.reset(
46         new XmlNode{"test_node", {{"attr1", "val1"}, {"attr2", "val2"}}});
47   }
48 
49   // Accessor helpers for private members of XmlNode.
GetParent(const XmlNode & node)50   static const XmlNode* GetParent(const XmlNode& node) { return node.parent_; }
51 
SetText(XmlNode * node,const std::string & text)52   static void SetText(XmlNode* node, const std::string& text) {
53     node->SetText(text);
54   }
55 
AppendText(XmlNode * node,const std::string & text)56   static void AppendText(XmlNode* node, const std::string& text) {
57     node->AppendText(text);
58   }
59 
CreateNodeTree()60   void CreateNodeTree() {
61     node_ = XmlParser{}.Parse(R"(
62         <top>
63           <node1 id="1"><node2 id="2"><node3 id="3"/></node2></node1>
64           <node2 id="4"><node3 id="5"/></node2>
65           <node3 id="6"/>
66           <node2 id="7"><node4 id="8"><node3 id="9"/></node4></node2>
67         </top>
68         )");
69   }
70 
71   std::unique_ptr<XmlNode> node_;
72 };
73 
TEST_F(XmlNodeTest,DefaultConstruction)74 TEST_F(XmlNodeTest, DefaultConstruction) {
75   EXPECT_EQ("test_node", node_->name());
76   EXPECT_TRUE(node_->children().empty());
77   EXPECT_TRUE(node_->text().empty());
78 }
79 
TEST_F(XmlNodeTest,SetText)80 TEST_F(XmlNodeTest, SetText) {
81   SetText(node_.get(), "foobar");
82   EXPECT_EQ("foobar", node_->text());
83 }
84 
TEST_F(XmlNodeTest,AppendText)85 TEST_F(XmlNodeTest, AppendText) {
86   SetText(node_.get(), "foobar");
87   AppendText(node_.get(), "-baz");
88   EXPECT_EQ("foobar-baz", node_->text());
89 }
90 
TEST_F(XmlNodeTest,AddChild)91 TEST_F(XmlNodeTest, AddChild) {
92   std::unique_ptr<XmlNode> child{new XmlNode{"child", {}}};
93   node_->AddChild(std::move(child));
94   EXPECT_EQ(1u, node_->children().size());
95   EXPECT_EQ("child", node_->children().front()->name());
96   EXPECT_EQ(node_.get(), GetParent(*node_->children().front().get()));
97 }
98 
TEST_F(XmlNodeTest,Attributes)99 TEST_F(XmlNodeTest, Attributes) {
100   const std::map<std::string, std::string> expected_attrs{{"attr1", "val1"},
101                                                           {"attr2", "val2"}};
102   EXPECT_EQ(expected_attrs, node_->attributes());
103   std::string attr = "bar";
104   EXPECT_FALSE(node_->GetAttribute("foo", &attr));
105   EXPECT_EQ("bar", attr);  // Shouldn't be changed by failed GetAttribute().
106   EXPECT_TRUE(node_->GetAttribute("attr1", &attr));
107   EXPECT_EQ("val1", attr);
108   EXPECT_TRUE(node_->GetAttribute("attr2", &attr));
109   EXPECT_EQ("val2", attr);
110 
111   XmlNode new_node{"node", {}};
112   EXPECT_FALSE(new_node.GetAttribute("attr1", &attr));
113 }
114 
TEST_F(XmlNodeTest,FindFirstChild_SingleNode)115 TEST_F(XmlNodeTest, FindFirstChild_SingleNode) {
116   CreateNodeTree();
117   const XmlNode* node = node_->FindFirstChild("node3", false);
118   ASSERT_NE(nullptr, node);
119   EXPECT_EQ("node3", node->name());
120   EXPECT_EQ("6", node->GetAttributeOrEmpty("id"));
121 
122   node = node_->FindFirstChild("node3", true);
123   ASSERT_NE(nullptr, node);
124   EXPECT_EQ("node3", node->name());
125   EXPECT_EQ("3", node->GetAttributeOrEmpty("id"));
126 
127   node = node_->FindFirstChild("foo", true);
128   ASSERT_EQ(nullptr, node);
129 }
130 
TEST_F(XmlNodeTest,FindFirstChild_Path)131 TEST_F(XmlNodeTest, FindFirstChild_Path) {
132   CreateNodeTree();
133   const XmlNode* node = node_->FindFirstChild("node2/node3", false);
134   ASSERT_NE(nullptr, node);
135   EXPECT_EQ("node3", node->name());
136   EXPECT_EQ("5", node->GetAttributeOrEmpty("id"));
137 
138   node = node_->FindFirstChild("node2/node3", true);
139   ASSERT_NE(nullptr, node);
140   EXPECT_EQ("node3", node->name());
141   EXPECT_EQ("3", node->GetAttributeOrEmpty("id"));
142 
143   node = node_->FindFirstChild("node1/node2/node3", false);
144   ASSERT_NE(nullptr, node);
145   EXPECT_EQ("node3", node->name());
146   EXPECT_EQ("3", node->GetAttributeOrEmpty("id"));
147 
148   node = node_->FindFirstChild("node1/node2/node3", true);
149   ASSERT_NE(nullptr, node);
150   EXPECT_EQ("node3", node->name());
151   EXPECT_EQ("3", node->GetAttributeOrEmpty("id"));
152 
153   node = node_->FindFirstChild("foo/node3", true);
154   ASSERT_EQ(nullptr, node);
155 }
156 
TEST_F(XmlNodeTest,FindChildren_SingleNode)157 TEST_F(XmlNodeTest, FindChildren_SingleNode) {
158   CreateNodeTree();
159   auto children = node_->FindChildren("node3", false);
160   ASSERT_EQ(1u, children.size());
161   EXPECT_EQ("node3", children[0]->name());
162   EXPECT_EQ("6", children[0]->GetAttributeOrEmpty("id"));
163 
164   children = node_->FindChildren("node3", true);
165   ASSERT_EQ(4u, children.size());
166   EXPECT_EQ("node3", children[0]->name());
167   EXPECT_EQ("3", children[0]->GetAttributeOrEmpty("id"));
168   EXPECT_EQ("node3", children[1]->name());
169   EXPECT_EQ("5", children[1]->GetAttributeOrEmpty("id"));
170   EXPECT_EQ("node3", children[2]->name());
171   EXPECT_EQ("6", children[2]->GetAttributeOrEmpty("id"));
172   EXPECT_EQ("node3", children[3]->name());
173   EXPECT_EQ("9", children[3]->GetAttributeOrEmpty("id"));
174 }
175 
TEST_F(XmlNodeTest,FindChildren_Path)176 TEST_F(XmlNodeTest, FindChildren_Path) {
177   CreateNodeTree();
178   auto children = node_->FindChildren("node2/node3", false);
179   ASSERT_EQ(1u, children.size());
180   EXPECT_EQ("node3", children[0]->name());
181   EXPECT_EQ("5", children[0]->GetAttributeOrEmpty("id"));
182 
183   children = node_->FindChildren("node2/node3", true);
184   ASSERT_EQ(2u, children.size());
185   EXPECT_EQ("node3", children[0]->name());
186   EXPECT_EQ("3", children[0]->GetAttributeOrEmpty("id"));
187   EXPECT_EQ("node3", children[1]->name());
188   EXPECT_EQ("5", children[1]->GetAttributeOrEmpty("id"));
189 
190   children = node_->FindChildren("node1/node2/node3", false);
191   ASSERT_EQ(1u, children.size());
192   EXPECT_EQ("node3", children[0]->name());
193   EXPECT_EQ("3", children[0]->GetAttributeOrEmpty("id"));
194 
195   children = node_->FindChildren("node1/node2/node3", true);
196   ASSERT_EQ(1u, children.size());
197   EXPECT_EQ("node3", children[0]->name());
198   EXPECT_EQ("3", children[0]->GetAttributeOrEmpty("id"));
199 
200   children = node_->FindChildren("foo/bar", false);
201   ASSERT_EQ(0u, children.size());
202 
203   children = node_->FindChildren("node2/baz", false);
204   ASSERT_EQ(0u, children.size());
205 }
206 
207 }  // namespace weave
208