aboutsummaryrefslogtreecommitdiffstats
path: root/library/cpp/xml/document/xml-document_ut.cpp
diff options
context:
space:
mode:
authorDevtools Arcadia <arcadia-devtools@yandex-team.ru>2022-02-07 18:08:42 +0300
committerDevtools Arcadia <arcadia-devtools@mous.vla.yp-c.yandex.net>2022-02-07 18:08:42 +0300
commit1110808a9d39d4b808aef724c861a2e1a38d2a69 (patch)
treee26c9fed0de5d9873cce7e00bc214573dc2195b7 /library/cpp/xml/document/xml-document_ut.cpp
downloadydb-1110808a9d39d4b808aef724c861a2e1a38d2a69.tar.gz
intermediate changes
ref:cde9a383711a11544ce7e107a78147fb96cc4029
Diffstat (limited to 'library/cpp/xml/document/xml-document_ut.cpp')
-rw-r--r--library/cpp/xml/document/xml-document_ut.cpp319
1 files changed, 319 insertions, 0 deletions
diff --git a/library/cpp/xml/document/xml-document_ut.cpp b/library/cpp/xml/document/xml-document_ut.cpp
new file mode 100644
index 0000000000..9f537b75c4
--- /dev/null
+++ b/library/cpp/xml/document/xml-document_ut.cpp
@@ -0,0 +1,319 @@
+#include <library/cpp/testing/unittest/registar.h>
+#include <util/generic/map.h>
+
+#include "xml-document.h"
+
+Y_UNIT_TEST_SUITE(TestXmlDocument) {
+ Y_UNIT_TEST(Iteration) {
+ NXml::TDocument xml(
+ "<?xml version=\"1.0\"?>\n"
+ "<root>qq<a><b></b></a>ww<c></c></root>",
+ 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(
+ "<?xml version=\"1.0\"?>\n"
+ "<root>\n"
+ "<a><b len=\"15\" correct=\"1\">hello world</b></a>\n"
+ "<text>Некоторый текст</text>\n"
+ "</root>",
+ NXml::TDocument::String);
+
+ NXml::TConstNode root = xml.Root();
+ NXml::TConstNode b = root.Node("a/b");
+ UNIT_ASSERT_EQUAL(b.Attr<int>("len"), 15);
+ UNIT_ASSERT_EQUAL(b.Attr<bool>("correct"), true);
+
+ NXml::TConstNode text = root.Node("text");
+ UNIT_ASSERT_EQUAL(text.Value<TString>(), "Некоторый текст");
+ }
+ 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, "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
+ "<frob xyzzy=\"Frobozz\" kulness=\"0.3\" timelimit=\"3\">\n"
+ " <authors>\n"
+ " <graham name=\"Nelson\"/>\n"
+ " <zarf>Andrew Plotkin</zarf>\n"
+ " <emshort>Emily Short</emshort>\n"
+ " </authors>\n"
+ "</frob>\n");
+ // check default utf8 output with ru
+ {
+ NXml::TDocument xml2("frob", NXml::TDocument::RootName);
+ xml2.Root().SetAttr("xyzzy", "привет =)");
+ UNIT_ASSERT_VALUES_EQUAL(xml2.ToString(), "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
+ "<frob xyzzy=\"привет =)\"/>\n");
+ }
+ }
+ Y_UNIT_TEST(XPathNs) {
+ using namespace NXml;
+ TDocument xml(
+ "<?xml version=\"1.0\"?>\n"
+ "<root xmlns='http://hello.com/hello'>\n"
+ "<a><b len=\"15\" correct=\"1\">hello world</b></a>\n"
+ "<text>Некоторый текст</text>\n"
+ "</root>",
+ 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<int>("len"), 15);
+ UNIT_ASSERT_EQUAL(b.Attr<bool>("correct"), true);
+
+ TConstNode text = root.Node("h:text", false, nss);
+ UNIT_ASSERT_EQUAL(text.Value<TString>(), "Некоторый текст");
+
+ // 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<TString>(), "Некоторый текст");
+ }
+ Y_UNIT_TEST(XmlNodes) {
+ using namespace NXml;
+ TDocument xml("<?xml version=\"1.0\"?>\n"
+ "<root>qq<a><b>asdfg</b></a>ww<c></c></root>",
+ NXml::TDocument::String);
+ TNode root = xml.Root();
+ UNIT_ASSERT_EQUAL(root.Value<TString>(), "qqasdfgww");
+ TConstNode node = root.FirstChild();
+ UNIT_ASSERT_EQUAL(node.IsText(), true);
+ UNIT_ASSERT_EQUAL(node.Value<TString>(), "qq");
+ node = node.NextSibling();
+ UNIT_ASSERT_EQUAL(node.IsText(), false);
+ UNIT_ASSERT_EQUAL(node.Name(), "a");
+ UNIT_ASSERT_EQUAL(node.Value<TString>(), "asdfg");
+ node = node.NextSibling();
+ UNIT_ASSERT_EQUAL(node.IsText(), true);
+ UNIT_ASSERT_EQUAL(node.Value<TString>(), "ww");
+ node = node.NextSibling();
+ UNIT_ASSERT_EQUAL(node.IsText(), false);
+ UNIT_ASSERT_EQUAL(node.Name(), "c");
+ UNIT_ASSERT_EQUAL(node.Value<TString>(), "");
+ 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<TString>(), yexception);
+ UNIT_ASSERT_EXCEPTION(node.IsText(), yexception);
+ }
+ Y_UNIT_TEST(DefVal) {
+ using namespace NXml;
+ TDocument xml("<?xml version=\"1.0\"?>\n"
+ "<root><a></a></root>",
+ NXml::TDocument::String);
+ UNIT_ASSERT_EQUAL(xml.Root().Node("a", true).Node("b", true).Value<int>(3), 3);
+ }
+ Y_UNIT_TEST(NodesVsXPath) {
+ using namespace NXml;
+ TDocument xml("<?xml version=\"1.0\"?>\n"
+ "<root><a x=\"y\"></a></root>",
+ 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("<?xml version=\"1.0\"?>\n"
+ "<root><a x=\"y\">first</a>"
+ "<a>second</a></root>",
+ NXml::TDocument::String);
+ UNIT_ASSERT_EXCEPTION(xml.Root().Node("/root/a/@x"), yexception);
+ UNIT_ASSERT_STRINGS_EQUAL(xml.Root().Node("/root/a").Value<TString>(), "first");
+ }
+ Y_UNIT_TEST(CopyNode) {
+ using namespace NXml;
+ // default-construct empty node
+ TNode empty;
+ // put to container
+ TMap<int, TNode> nmap;
+ nmap[2];
+
+ // do copy
+ TDocument xml("<?xml version=\"1.0\"?>\n"
+ "<root><a></a></root>",
+ TDocument::String);
+
+ TDocument xml2("<?xml version=\"1.0\"?>\n"
+ "<root><node><b>bold</b><i>ita</i></node></root>",
+ 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(),
+ "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
+ "<root><a><node><b>bold</b><i>ita</i></node></a></root>\n");
+ }
+
+ Y_UNIT_TEST(RenderNode) {
+ using namespace NXml;
+ {
+ // no namespaces
+ TDocument xml(
+ "<?xml version=\"1.0\"?>\n"
+ "<root>\n"
+ "<a><b len=\"15\" correct=\"1\">hello world</b></a>\n"
+ "<text>Некоторый текст</text>\n"
+ "</root>",
+ TDocument::String);
+ TNode n = xml.Root().Node("//a");
+ UNIT_ASSERT_VALUES_EQUAL(n.ToString(), "<a><b len=\"15\" correct=\"1\">hello world</b></a>");
+ }
+ {
+ // namespaces
+ TDocument xml(
+ "<?xml version=\"1.0\"?>\n"
+ "<root xmlns='http://hello.com/hello'>\n"
+ "<a><b len=\"15\" correct=\"1\">hello world</b></a>\n"
+ "<text>Некоторый текст</text>\n"
+ "</root>",
+ 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(), "<a><b len=\"15\" correct=\"1\">hello world</b></a>");
+ }
+ }
+
+ Y_UNIT_TEST(ReuseXPathContext) {
+ using namespace NXml;
+
+ TDocument xml(
+ "<?xml version=\"1.0\"?>\n"
+ "<root>\n"
+ "<a><b><c>Hello, world!</c></b></a>\n"
+ "<text x=\"10\">First</text>\n"
+ "<text y=\"20\">Second</text>\n"
+ "</root>",
+ 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<TString>(), "Hello, world!");
+
+ TXPathContextPtr bCtxt = b.CreateXPathContext();
+ TConstNode c2 = b.Node("c", false, *bCtxt);
+ UNIT_ASSERT_EQUAL(c2.Value<TString>(), "Hello, world!");
+
+ // Mixing contexts from different documents is forbidden
+ TDocument otherXml("<root></root>", 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<int>(), 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(), "<video controls></video>");
+ }
+
+ Y_UNIT_TEST(Move) {
+ using namespace NXml;
+
+ TDocument xml1("foo", TDocument::RootName);
+ xml1.Root().AddChild("bar");
+
+ UNIT_ASSERT_VALUES_EQUAL(xml1.Root().ToString(), "<foo><bar/></foo>");
+
+ TDocument xml2 = std::move(xml1);
+ UNIT_ASSERT_EXCEPTION(xml1.Root(), yexception);
+ UNIT_ASSERT_VALUES_EQUAL(xml2.Root().ToString(), "<foo><bar/></foo>");
+ }
+
+ 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);
+ }
+}