#include #include #include "xml-document.h" Y_UNIT_TEST_SUITE(TestXmlDocument) { Y_UNIT_TEST(Iteration) { NXml::TDocument xml( "\n" "qqww", NXml::TDocument::String); NXml::TConstNode root = xml.Root(); UNIT_ASSERT_EQUAL(root.Name(), "root"); NXml::TConstNode n = root.FirstChild().NextSibling(); UNIT_ASSERT_EQUAL(n.Name(), "a"); n = n.NextSibling().NextSibling(); UNIT_ASSERT_EQUAL(n.Name(), "c"); } Y_UNIT_TEST(ParseString) { NXml::TDocument xml( "\n" "\n" "hello world\n" "Некоторый текст\n" "", NXml::TDocument::String); NXml::TConstNode root = xml.Root(); NXml::TConstNode b = root.Node("a/b"); UNIT_ASSERT_EQUAL(b.Attr("len"), 15); UNIT_ASSERT_EQUAL(b.Attr("correct"), true); NXml::TConstNode text = root.Node("text"); UNIT_ASSERT_EQUAL(text.Value(), "Некоторый текст"); } Y_UNIT_TEST(SerializeString) { NXml::TDocument xml("frob", NXml::TDocument::RootName); xml.Root().SetAttr("xyzzy", "Frobozz"); xml.Root().SetAttr("kulness", 0.3); xml.Root().SetAttr("timelimit", 3); NXml::TNode authors = xml.Root().AddChild("authors"); authors.AddChild("graham").SetAttr("name", "Nelson"); authors.AddChild("zarf").SetValue("Andrew Plotkin"); authors.AddChild("emshort", "Emily Short"); TString data = xml.ToString("utf-8"); UNIT_ASSERT_EQUAL(data, "\n" "\n" " \n" " \n" " Andrew Plotkin\n" " Emily Short\n" " \n" "\n"); // check default utf8 output with ru { NXml::TDocument xml2("frob", NXml::TDocument::RootName); xml2.Root().SetAttr("xyzzy", "привет =)"); UNIT_ASSERT_VALUES_EQUAL(xml2.ToString(), "\n" "\n"); } } Y_UNIT_TEST(XPathNs) { using namespace NXml; TDocument xml( "\n" "\n" "hello world\n" "Некоторый текст\n" "", TDocument::String); TNamespacesForXPath nss; TNamespaceForXPath ns = {"h", "http://hello.com/hello"}; nss.push_back(ns); TConstNode root = xml.Root(); TConstNode b = root.Node("h:a/h:b", false, nss); UNIT_ASSERT_EQUAL(b.Attr("len"), 15); UNIT_ASSERT_EQUAL(b.Attr("correct"), true); TConstNode text = root.Node("h:text", false, nss); UNIT_ASSERT_EQUAL(text.Value(), "Некоторый текст"); // For performance you can create xpath context once using nss and pass it. TXPathContextPtr ctxt = root.CreateXPathContext(nss); UNIT_ASSERT(root.Node("text", true, *ctxt).IsNull()); UNIT_ASSERT_EXCEPTION(root.Node("text", false, *ctxt), yexception); UNIT_ASSERT_EQUAL(root.Node("h:text", false, *ctxt).Value(), "Некоторый текст"); } Y_UNIT_TEST(XmlNodes) { using namespace NXml; TDocument xml("\n" "qqasdfgww", NXml::TDocument::String); TNode root = xml.Root(); UNIT_ASSERT_EQUAL(root.Value(), "qqasdfgww"); TConstNode node = root.FirstChild(); UNIT_ASSERT_EQUAL(node.IsText(), true); UNIT_ASSERT_EQUAL(node.Value(), "qq"); node = node.NextSibling(); UNIT_ASSERT_EQUAL(node.IsText(), false); UNIT_ASSERT_EQUAL(node.Name(), "a"); UNIT_ASSERT_EQUAL(node.Value(), "asdfg"); node = node.NextSibling(); UNIT_ASSERT_EQUAL(node.IsText(), true); UNIT_ASSERT_EQUAL(node.Value(), "ww"); node = node.NextSibling(); UNIT_ASSERT_EQUAL(node.IsText(), false); UNIT_ASSERT_EQUAL(node.Name(), "c"); UNIT_ASSERT_EQUAL(node.Value(), ""); node = node.NextSibling(); UNIT_ASSERT_EQUAL(node.IsNull(), true); TStringStream iterLog; for (const auto& node2 : root.Nodes("/root/*")) { iterLog << node2.Name() << ';'; } UNIT_ASSERT_STRINGS_EQUAL(iterLog.Str(), "a;c;"); // get only element nodes, ignore text nodes with empty "name" param node = root.FirstChild(TString()); UNIT_ASSERT_EQUAL(node.IsText(), false); UNIT_ASSERT_EQUAL(node.Name(), "a"); node = node.NextSibling(TString()); UNIT_ASSERT_EQUAL(node.IsText(), false); UNIT_ASSERT_EQUAL(node.Name(), "c"); // use exact "name" to retrieve children and siblings node = root.FirstChild("a"); UNIT_ASSERT_EQUAL(node.IsNull(), false); UNIT_ASSERT_EQUAL(node.Name(), "a"); node = node.NextSibling("c"); UNIT_ASSERT_EQUAL(node.IsNull(), false); UNIT_ASSERT_EQUAL(node.Name(), "c"); node = root.FirstChild("c"); // skip "a" UNIT_ASSERT_EQUAL(node.IsNull(), false); UNIT_ASSERT_EQUAL(node.Name(), "c"); // node not found: no exceptions, null nodes are returned node = root.FirstChild("b"); // b is not direct child of root UNIT_ASSERT_EQUAL(node.IsNull(), true); node = root.FirstChild("nosuchnode"); UNIT_ASSERT_EQUAL(node.IsNull(), true); node = root.FirstChild(); node = root.NextSibling("unknownnode"); UNIT_ASSERT_EQUAL(node.IsNull(), true); UNIT_ASSERT_EXCEPTION(node.Name(), yexception); UNIT_ASSERT_EXCEPTION(node.Value(), yexception); UNIT_ASSERT_EXCEPTION(node.IsText(), yexception); } Y_UNIT_TEST(DefVal) { using namespace NXml; TDocument xml("\n" "", NXml::TDocument::String); UNIT_ASSERT_EQUAL(xml.Root().Node("a", true).Node("b", true).Value(3), 3); } Y_UNIT_TEST(NodesVsXPath) { using namespace NXml; TDocument xml("\n" "", NXml::TDocument::String); UNIT_ASSERT_EXCEPTION(xml.Root().Nodes("/root/a/@x"), yexception); UNIT_ASSERT_VALUES_EQUAL(xml.Root().XPath("/root/a/@x").Size(), 1); } Y_UNIT_TEST(NodeIsFirst) { using namespace NXml; TDocument xml("\n" "first" "second", NXml::TDocument::String); UNIT_ASSERT_EXCEPTION(xml.Root().Node("/root/a/@x"), yexception); UNIT_ASSERT_STRINGS_EQUAL(xml.Root().Node("/root/a").Value(), "first"); } Y_UNIT_TEST(CopyNode) { using namespace NXml; // default-construct empty node TNode empty; // put to container TMap nmap; nmap[2]; // do copy TDocument xml("\n" "", TDocument::String); TDocument xml2("\n" "boldita", TDocument::String); TNode node = xml2.Root().Node("//node"); TNode place = xml.Root().Node("//a"); place.AddChild(node); TStringStream s; xml.Save(s, "", false); UNIT_ASSERT_VALUES_EQUAL(s.Str(), "\n" "boldita\n"); } Y_UNIT_TEST(RenderNode) { using namespace NXml; { // no namespaces TDocument xml( "\n" "\n" "hello world\n" "Некоторый текст\n" "", TDocument::String); TNode n = xml.Root().Node("//a"); UNIT_ASSERT_VALUES_EQUAL(n.ToString(), "hello world"); } { // namespaces TDocument xml( "\n" "\n" "hello world\n" "Некоторый текст\n" "", TDocument::String); TNamespacesForXPath nss; TNamespaceForXPath ns = {"h", "http://hello.com/hello"}; nss.push_back(ns); TNode n = xml.Root().Node("//h:a", false, nss); UNIT_ASSERT_VALUES_EQUAL(n.ToString(), "hello world"); } } Y_UNIT_TEST(ReuseXPathContext) { using namespace NXml; TDocument xml( "\n" "\n" "Hello, world!\n" "First\n" "Second\n" "", TDocument::String); TXPathContextPtr rootCtxt = xml.Root().CreateXPathContext(); // Check Node() TConstNode b = xml.Root().Node("a/b", false, *rootCtxt); // We can use root node context for xpath evaluation in any node TConstNode c1 = b.Node("c", false, *rootCtxt); UNIT_ASSERT_EQUAL(c1.Value(), "Hello, world!"); TXPathContextPtr bCtxt = b.CreateXPathContext(); TConstNode c2 = b.Node("c", false, *bCtxt); UNIT_ASSERT_EQUAL(c2.Value(), "Hello, world!"); // Mixing contexts from different documents is forbidden TDocument otherXml("", TDocument::String); TXPathContextPtr otherCtxt = otherXml.Root().CreateXPathContext(); UNIT_ASSERT_EXCEPTION(b.Node("c", false, *otherCtxt), yexception); // Check Nodes() TConstNodes texts = xml.Root().Nodes("text", true, *rootCtxt); UNIT_ASSERT_EQUAL(texts.Size(), 2); // Nodes() does't work for non-element nodes UNIT_ASSERT_EXCEPTION(xml.Root().Nodes("text/@x", true, *rootCtxt), yexception); // Check XPath() TConstNodes ys = xml.Root().XPath("text/@y", true, *rootCtxt); UNIT_ASSERT_EQUAL(ys.Size(), 1); UNIT_ASSERT_EQUAL(ys[0].Value(), 20); } Y_UNIT_TEST(Html) { using namespace NXml; TDocument htmlChunk("video", TDocument::RootName); TNode videoNode = htmlChunk.Root(); videoNode.SetAttr("controls"); TStringStream ss; videoNode.SaveAsHtml(ss); UNIT_ASSERT_EQUAL(ss.Str(), ""); } Y_UNIT_TEST(Move) { using namespace NXml; TDocument xml1("foo", TDocument::RootName); xml1.Root().AddChild("bar"); UNIT_ASSERT_VALUES_EQUAL(xml1.Root().ToString(), ""); TDocument xml2 = std::move(xml1); UNIT_ASSERT_EXCEPTION(xml1.Root(), yexception); UNIT_ASSERT_VALUES_EQUAL(xml2.Root().ToString(), ""); } Y_UNIT_TEST(StringConversion) { using namespace NXml; TDocument xml("foo", TDocument::RootName); auto root = xml.Root(); const TStringBuf stringBuf = "bar"; root.SetAttr("bar", stringBuf); const TString tString = "baz"; root.SetAttr("baz", tString); root.SetAttr("quux", "literal"); root.SetAttr("frob", 500); } }