|  | // Copyright 2015 The Weave Authors. All rights reserved. | 
|  | // Use of this source code is governed by a BSD-style license that can be | 
|  | // found in the LICENSE file. | 
|  |  | 
|  | #include "src/notification/xml_node.h" | 
|  |  | 
|  | #include <memory> | 
|  |  | 
|  | #include <gtest/gtest.h> | 
|  |  | 
|  | #include "src/notification/xmpp_stream_parser.h" | 
|  |  | 
|  | namespace weave { | 
|  | namespace { | 
|  |  | 
|  | class XmlParser : public XmppStreamParser::Delegate { | 
|  | public: | 
|  | std::unique_ptr<XmlNode> Parse(const std::string& xml) { | 
|  | parser_.ParseData(xml); | 
|  | return std::move(node_); | 
|  | } | 
|  |  | 
|  | private: | 
|  | // Overrides from XmppStreamParser::Delegate. | 
|  | void OnStreamStart(const std::string& node_name, | 
|  | std::map<std::string, std::string> attributes) override { | 
|  | node_.reset(new XmlNode{node_name, std::move(attributes)}); | 
|  | } | 
|  |  | 
|  | void OnStreamEnd(const std::string& node_name) override {} | 
|  |  | 
|  | void OnStanza(std::unique_ptr<XmlNode> stanza) override { | 
|  | node_->AddChild(std::move(stanza)); | 
|  | } | 
|  |  | 
|  | std::unique_ptr<XmlNode> node_; | 
|  | XmppStreamParser parser_{this}; | 
|  | }; | 
|  |  | 
|  | }  // anonymous namespace | 
|  |  | 
|  | class XmlNodeTest : public testing::Test { | 
|  | public: | 
|  | void SetUp() override { | 
|  | node_.reset( | 
|  | new XmlNode{"test_node", {{"attr1", "val1"}, {"attr2", "val2"}}}); | 
|  | } | 
|  |  | 
|  | // Accessor helpers for private members of XmlNode. | 
|  | static const XmlNode* GetParent(const XmlNode& node) { return node.parent_; } | 
|  |  | 
|  | static void SetText(XmlNode* node, const std::string& text) { | 
|  | node->SetText(text); | 
|  | } | 
|  |  | 
|  | static void AppendText(XmlNode* node, const std::string& text) { | 
|  | node->AppendText(text); | 
|  | } | 
|  |  | 
|  | void CreateNodeTree() { | 
|  | node_ = XmlParser{}.Parse(R"( | 
|  | <top> | 
|  | <node1 id="1"><node2 id="2"><node3 id="3"/></node2></node1> | 
|  | <node2 id="4"><node3 id="5"/></node2> | 
|  | <node3 id="6"/> | 
|  | <node2 id="7"><node4 id="8"><node3 id="9"/></node4></node2> | 
|  | </top> | 
|  | )"); | 
|  | } | 
|  |  | 
|  | std::unique_ptr<XmlNode> node_; | 
|  | }; | 
|  |  | 
|  | TEST_F(XmlNodeTest, DefaultConstruction) { | 
|  | EXPECT_EQ("test_node", node_->name()); | 
|  | EXPECT_TRUE(node_->children().empty()); | 
|  | EXPECT_TRUE(node_->text().empty()); | 
|  | } | 
|  |  | 
|  | TEST_F(XmlNodeTest, SetText) { | 
|  | SetText(node_.get(), "foobar"); | 
|  | EXPECT_EQ("foobar", node_->text()); | 
|  | } | 
|  |  | 
|  | TEST_F(XmlNodeTest, AppendText) { | 
|  | SetText(node_.get(), "foobar"); | 
|  | AppendText(node_.get(), "-baz"); | 
|  | EXPECT_EQ("foobar-baz", node_->text()); | 
|  | } | 
|  |  | 
|  | TEST_F(XmlNodeTest, AddChild) { | 
|  | std::unique_ptr<XmlNode> child{new XmlNode{"child", {}}}; | 
|  | node_->AddChild(std::move(child)); | 
|  | EXPECT_EQ(1u, node_->children().size()); | 
|  | EXPECT_EQ("child", node_->children().front()->name()); | 
|  | EXPECT_EQ(node_.get(), GetParent(*node_->children().front().get())); | 
|  | } | 
|  |  | 
|  | TEST_F(XmlNodeTest, Attributes) { | 
|  | const std::map<std::string, std::string> expected_attrs{{"attr1", "val1"}, | 
|  | {"attr2", "val2"}}; | 
|  | EXPECT_EQ(expected_attrs, node_->attributes()); | 
|  | std::string attr = "bar"; | 
|  | EXPECT_FALSE(node_->GetAttribute("foo", &attr)); | 
|  | EXPECT_EQ("bar", attr);  // Shouldn't be changed by failed GetAttribute(). | 
|  | EXPECT_TRUE(node_->GetAttribute("attr1", &attr)); | 
|  | EXPECT_EQ("val1", attr); | 
|  | EXPECT_TRUE(node_->GetAttribute("attr2", &attr)); | 
|  | EXPECT_EQ("val2", attr); | 
|  |  | 
|  | XmlNode new_node{"node", {}}; | 
|  | EXPECT_FALSE(new_node.GetAttribute("attr1", &attr)); | 
|  | } | 
|  |  | 
|  | TEST_F(XmlNodeTest, FindFirstChild_SingleNode) { | 
|  | CreateNodeTree(); | 
|  | const XmlNode* node = node_->FindFirstChild("node3", false); | 
|  | ASSERT_NE(nullptr, node); | 
|  | EXPECT_EQ("node3", node->name()); | 
|  | EXPECT_EQ("6", node->GetAttributeOrEmpty("id")); | 
|  |  | 
|  | node = node_->FindFirstChild("node3", true); | 
|  | ASSERT_NE(nullptr, node); | 
|  | EXPECT_EQ("node3", node->name()); | 
|  | EXPECT_EQ("3", node->GetAttributeOrEmpty("id")); | 
|  |  | 
|  | node = node_->FindFirstChild("foo", true); | 
|  | ASSERT_EQ(nullptr, node); | 
|  | } | 
|  |  | 
|  | TEST_F(XmlNodeTest, FindFirstChild_Path) { | 
|  | CreateNodeTree(); | 
|  | const XmlNode* node = node_->FindFirstChild("node2/node3", false); | 
|  | ASSERT_NE(nullptr, node); | 
|  | EXPECT_EQ("node3", node->name()); | 
|  | EXPECT_EQ("5", node->GetAttributeOrEmpty("id")); | 
|  |  | 
|  | node = node_->FindFirstChild("node2/node3", true); | 
|  | ASSERT_NE(nullptr, node); | 
|  | EXPECT_EQ("node3", node->name()); | 
|  | EXPECT_EQ("3", node->GetAttributeOrEmpty("id")); | 
|  |  | 
|  | node = node_->FindFirstChild("node1/node2/node3", false); | 
|  | ASSERT_NE(nullptr, node); | 
|  | EXPECT_EQ("node3", node->name()); | 
|  | EXPECT_EQ("3", node->GetAttributeOrEmpty("id")); | 
|  |  | 
|  | node = node_->FindFirstChild("node1/node2/node3", true); | 
|  | ASSERT_NE(nullptr, node); | 
|  | EXPECT_EQ("node3", node->name()); | 
|  | EXPECT_EQ("3", node->GetAttributeOrEmpty("id")); | 
|  |  | 
|  | node = node_->FindFirstChild("foo/node3", true); | 
|  | ASSERT_EQ(nullptr, node); | 
|  | } | 
|  |  | 
|  | TEST_F(XmlNodeTest, FindChildren_SingleNode) { | 
|  | CreateNodeTree(); | 
|  | auto children = node_->FindChildren("node3", false); | 
|  | ASSERT_EQ(1u, children.size()); | 
|  | EXPECT_EQ("node3", children[0]->name()); | 
|  | EXPECT_EQ("6", children[0]->GetAttributeOrEmpty("id")); | 
|  |  | 
|  | children = node_->FindChildren("node3", true); | 
|  | ASSERT_EQ(4u, children.size()); | 
|  | EXPECT_EQ("node3", children[0]->name()); | 
|  | EXPECT_EQ("3", children[0]->GetAttributeOrEmpty("id")); | 
|  | EXPECT_EQ("node3", children[1]->name()); | 
|  | EXPECT_EQ("5", children[1]->GetAttributeOrEmpty("id")); | 
|  | EXPECT_EQ("node3", children[2]->name()); | 
|  | EXPECT_EQ("6", children[2]->GetAttributeOrEmpty("id")); | 
|  | EXPECT_EQ("node3", children[3]->name()); | 
|  | EXPECT_EQ("9", children[3]->GetAttributeOrEmpty("id")); | 
|  | } | 
|  |  | 
|  | TEST_F(XmlNodeTest, FindChildren_Path) { | 
|  | CreateNodeTree(); | 
|  | auto children = node_->FindChildren("node2/node3", false); | 
|  | ASSERT_EQ(1u, children.size()); | 
|  | EXPECT_EQ("node3", children[0]->name()); | 
|  | EXPECT_EQ("5", children[0]->GetAttributeOrEmpty("id")); | 
|  |  | 
|  | children = node_->FindChildren("node2/node3", true); | 
|  | ASSERT_EQ(2u, children.size()); | 
|  | EXPECT_EQ("node3", children[0]->name()); | 
|  | EXPECT_EQ("3", children[0]->GetAttributeOrEmpty("id")); | 
|  | EXPECT_EQ("node3", children[1]->name()); | 
|  | EXPECT_EQ("5", children[1]->GetAttributeOrEmpty("id")); | 
|  |  | 
|  | children = node_->FindChildren("node1/node2/node3", false); | 
|  | ASSERT_EQ(1u, children.size()); | 
|  | EXPECT_EQ("node3", children[0]->name()); | 
|  | EXPECT_EQ("3", children[0]->GetAttributeOrEmpty("id")); | 
|  |  | 
|  | children = node_->FindChildren("node1/node2/node3", true); | 
|  | ASSERT_EQ(1u, children.size()); | 
|  | EXPECT_EQ("node3", children[0]->name()); | 
|  | EXPECT_EQ("3", children[0]->GetAttributeOrEmpty("id")); | 
|  |  | 
|  | children = node_->FindChildren("foo/bar", false); | 
|  | ASSERT_EQ(0u, children.size()); | 
|  |  | 
|  | children = node_->FindChildren("node2/baz", false); | 
|  | ASSERT_EQ(0u, children.size()); | 
|  | } | 
|  |  | 
|  | }  // namespace weave |