summaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
authorArseny Kapoulkine <arseny.kapoulkine@gmail.com>2017-02-05 21:34:54 -0800
committerGitHub <noreply@github.com>2017-02-05 21:34:54 -0800
commita9fe2bb62e0976ab74fdb5266cc3725250eca075 (patch)
tree85c96e92afb2e3437b0eb20c805227b91e5e69f2 /tests
parentd3b9e4e1e85d0aca562d0e6b62533e68e5a4a749 (diff)
parent10676b6b8548ddbf9458993062e6a27c2c233d48 (diff)
Merge pull request #131 from zeux/xpath-noeh
XPath: Remove exceptional control flow
Diffstat (limited to 'tests')
-rw-r--r--tests/test_compact.cpp114
-rw-r--r--tests/test_document.cpp9
-rw-r--r--tests/test_dom_modify.cpp28
-rw-r--r--tests/test_dom_traverse.cpp21
-rw-r--r--tests/test_parse.cpp149
-rw-r--r--tests/test_write.cpp6
-rw-r--r--tests/test_xpath.cpp120
-rw-r--r--tests/test_xpath_api.cpp15
-rw-r--r--tests/test_xpath_functions.cpp14
-rw-r--r--tests/test_xpath_operators.cpp10
-rw-r--r--tests/test_xpath_parse.cpp76
-rw-r--r--tests/test_xpath_paths.cpp7
12 files changed, 556 insertions, 13 deletions
diff --git a/tests/test_compact.cpp b/tests/test_compact.cpp
new file mode 100644
index 0000000..f9560c9
--- /dev/null
+++ b/tests/test_compact.cpp
@@ -0,0 +1,114 @@
+#ifdef PUGIXML_COMPACT
+#include "common.hpp"
+
+static void overflow_hash_table(xml_document& doc)
+{
+ xml_node n = doc.child(STR("n"));
+
+ // compact encoding assumes next_sibling is a forward-only pointer so we can allocate hash entries by reordering nodes
+ // we allocate enough hash entries to be exactly on the edge of rehash threshold
+ for (int i = 0; i < 8; ++i)
+ CHECK(n.prepend_child(node_element));
+}
+
+TEST_XML_FLAGS(compact_out_of_memory_string, "<n a='v'/><?n v?>", parse_pi)
+{
+ test_runner::_memory_fail_threshold = 1;
+
+ overflow_hash_table(doc);
+
+ xml_attribute a = doc.child(STR("n")).attribute(STR("a"));
+ xml_node pi = doc.last_child();
+
+ CHECK_ALLOC_FAIL(CHECK(!pi.set_name(STR("name"))));
+ CHECK_ALLOC_FAIL(CHECK(!pi.set_value(STR("value"))));
+ CHECK_ALLOC_FAIL(CHECK(!a.set_name(STR("name"))));
+ CHECK_ALLOC_FAIL(CHECK(!a.set_value(STR("value"))));
+}
+
+TEST_XML(compact_out_of_memory_attribute, "<n a='v'/>")
+{
+ test_runner::_memory_fail_threshold = 1;
+
+ overflow_hash_table(doc);
+
+ xml_node n = doc.child(STR("n"));
+ xml_attribute a = n.attribute(STR("a"));
+
+ CHECK_ALLOC_FAIL(CHECK(!n.append_attribute(STR(""))));
+ CHECK_ALLOC_FAIL(CHECK(!n.prepend_attribute(STR(""))));
+ CHECK_ALLOC_FAIL(CHECK(!n.insert_attribute_after(STR(""), a)));
+ CHECK_ALLOC_FAIL(CHECK(!n.insert_attribute_before(STR(""), a)));
+}
+
+TEST_XML(compact_out_of_memory_attribute_copy, "<n a='v'/>")
+{
+ test_runner::_memory_fail_threshold = 1;
+
+ overflow_hash_table(doc);
+
+ xml_node n = doc.child(STR("n"));
+ xml_attribute a = n.attribute(STR("a"));
+
+ CHECK_ALLOC_FAIL(CHECK(!n.append_copy(a)));
+ CHECK_ALLOC_FAIL(CHECK(!n.prepend_copy(a)));
+ CHECK_ALLOC_FAIL(CHECK(!n.insert_copy_after(a, a)));
+ CHECK_ALLOC_FAIL(CHECK(!n.insert_copy_before(a, a)));
+}
+
+TEST_XML(compact_out_of_memory_node, "<n/>")
+{
+ test_runner::_memory_fail_threshold = 1;
+
+ overflow_hash_table(doc);
+
+ xml_node n = doc.child(STR("n"));
+
+ CHECK_ALLOC_FAIL(CHECK(!doc.append_child(node_element)));
+ CHECK_ALLOC_FAIL(CHECK(!doc.prepend_child(node_element)));
+ CHECK_ALLOC_FAIL(CHECK(!doc.insert_child_after(node_element, n)));
+ CHECK_ALLOC_FAIL(CHECK(!doc.insert_child_before(node_element, n)));
+}
+
+TEST_XML(compact_out_of_memory_node_copy, "<n/>")
+{
+ test_runner::_memory_fail_threshold = 1;
+
+ overflow_hash_table(doc);
+
+ xml_node n = doc.child(STR("n"));
+
+ CHECK_ALLOC_FAIL(CHECK(!doc.append_copy(n)));
+ CHECK_ALLOC_FAIL(CHECK(!doc.prepend_copy(n)));
+ CHECK_ALLOC_FAIL(CHECK(!doc.insert_copy_after(n, n)));
+ CHECK_ALLOC_FAIL(CHECK(!doc.insert_copy_before(n, n)));
+}
+
+TEST_XML(compact_out_of_memory_node_move, "<n/><ne/>")
+{
+ test_runner::_memory_fail_threshold = 1;
+
+ overflow_hash_table(doc);
+
+ xml_node n = doc.child(STR("n"));
+ xml_node ne = doc.child(STR("ne"));
+
+ CHECK_ALLOC_FAIL(CHECK(!doc.append_move(n)));
+ CHECK_ALLOC_FAIL(CHECK(!doc.prepend_move(n)));
+ CHECK_ALLOC_FAIL(CHECK(!doc.insert_move_after(n, ne)));
+ CHECK_ALLOC_FAIL(CHECK(!doc.insert_move_before(n, ne)));
+}
+
+TEST_XML(compact_out_of_memory_remove, "<n a='v'/>")
+{
+ test_runner::_memory_fail_threshold = 1;
+
+ overflow_hash_table(doc);
+
+ xml_node n = doc.child(STR("n"));
+ xml_attribute a = n.attribute(STR("a"));
+
+ CHECK_ALLOC_FAIL(CHECK(!n.remove_attribute(a)));
+ CHECK_ALLOC_FAIL(CHECK(!doc.remove_child(n)));
+}
+#endif
diff --git a/tests/test_document.cpp b/tests/test_document.cpp
index c7219e1..95bd873 100644
--- a/tests/test_document.cpp
+++ b/tests/test_document.cpp
@@ -496,6 +496,15 @@ TEST_XML(document_save_declaration_latin1, "<node/>")
CHECK(writer.as_narrow() == "<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>\n<node />\n");
}
+TEST_XML(document_save_declaration_raw, "<node/>")
+{
+ xml_writer_string writer;
+
+ doc.save(writer, STR(""), pugi::format_raw, get_native_encoding());
+
+ CHECK(writer.as_string() == STR("<?xml version=\"1.0\"?><node/>"));
+}
+
struct temp_file
{
char path[512];
diff --git a/tests/test_dom_modify.cpp b/tests/test_dom_modify.cpp
index f2d7ea8..7b26c5f 100644
--- a/tests/test_dom_modify.cpp
+++ b/tests/test_dom_modify.cpp
@@ -389,7 +389,7 @@ TEST_XML(dom_node_append_copy_attribute, "<node a1='v1'><child a2='v2'/><child/>
CHECK_NODE(doc, STR("<node a1=\"v1\" a3=\"v3\" a4=\"v4\"><child a2=\"v2\"/><child a5=\"v5\"/></node>"));
}
-TEST_XML(dom_node_insert_copy_after_attribute, "<node a1='v1'><child a2='v2'/></node>")
+TEST_XML(dom_node_insert_copy_after_attribute, "<node a1='v1'><child a2='v2'/>text</node>")
{
CHECK(xml_node().insert_copy_after(xml_attribute(), xml_attribute()) == xml_attribute());
@@ -402,6 +402,7 @@ TEST_XML(dom_node_insert_copy_after_attribute, "<node a1='v1'><child a2='v2'/></
CHECK(node.insert_copy_after(a1, xml_attribute()) == xml_attribute());
CHECK(node.insert_copy_after(xml_attribute(), a1) == xml_attribute());
CHECK(node.insert_copy_after(a2, a2) == xml_attribute());
+ CHECK(node.last_child().insert_copy_after(a2, a2) == xml_attribute());
xml_attribute a3 = node.insert_copy_after(a1, a1);
CHECK(a3 && a3 != a2 && a3 != a1);
@@ -414,7 +415,7 @@ TEST_XML(dom_node_insert_copy_after_attribute, "<node a1='v1'><child a2='v2'/></
CHECK(child.insert_copy_after(a4, a4) == xml_attribute());
- CHECK_NODE(doc, STR("<node a1=\"v1\" a2=\"v2\" a2=\"v2\" a1=\"v1\"><child a2=\"v2\"/></node>"));
+ CHECK_NODE(doc, STR("<node a1=\"v1\" a2=\"v2\" a2=\"v2\" a1=\"v1\"><child a2=\"v2\"/>text</node>"));
a3.set_name(STR("a3"));
a3 = STR("v3");
@@ -425,10 +426,10 @@ TEST_XML(dom_node_insert_copy_after_attribute, "<node a1='v1'><child a2='v2'/></
a5.set_name(STR("a5"));
a5 = STR("v5");
- CHECK_NODE(doc, STR("<node a1=\"v1\" a5=\"v5\" a4=\"v4\" a3=\"v3\"><child a2=\"v2\"/></node>"));
+ CHECK_NODE(doc, STR("<node a1=\"v1\" a5=\"v5\" a4=\"v4\" a3=\"v3\"><child a2=\"v2\"/>text</node>"));
}
-TEST_XML(dom_node_insert_copy_before_attribute, "<node a1='v1'><child a2='v2'/></node>")
+TEST_XML(dom_node_insert_copy_before_attribute, "<node a1='v1'><child a2='v2'/>text</node>")
{
CHECK(xml_node().insert_copy_before(xml_attribute(), xml_attribute()) == xml_attribute());
@@ -441,6 +442,7 @@ TEST_XML(dom_node_insert_copy_before_attribute, "<node a1='v1'><child a2='v2'/><
CHECK(node.insert_copy_before(a1, xml_attribute()) == xml_attribute());
CHECK(node.insert_copy_before(xml_attribute(), a1) == xml_attribute());
CHECK(node.insert_copy_before(a2, a2) == xml_attribute());
+ CHECK(node.last_child().insert_copy_before(a2, a2) == xml_attribute());
xml_attribute a3 = node.insert_copy_before(a1, a1);
CHECK(a3 && a3 != a2 && a3 != a1);
@@ -453,7 +455,7 @@ TEST_XML(dom_node_insert_copy_before_attribute, "<node a1='v1'><child a2='v2'/><
CHECK(child.insert_copy_before(a4, a4) == xml_attribute());
- CHECK_NODE(doc, STR("<node a1=\"v1\" a2=\"v2\" a2=\"v2\" a1=\"v1\"><child a2=\"v2\"/></node>"));
+ CHECK_NODE(doc, STR("<node a1=\"v1\" a2=\"v2\" a2=\"v2\" a1=\"v1\"><child a2=\"v2\"/>text</node>"));
a3.set_name(STR("a3"));
a3 = STR("v3");
@@ -464,7 +466,7 @@ TEST_XML(dom_node_insert_copy_before_attribute, "<node a1='v1'><child a2='v2'/><
a5.set_name(STR("a5"));
a5 = STR("v5");
- CHECK_NODE(doc, STR("<node a3=\"v3\" a4=\"v4\" a5=\"v5\" a1=\"v1\"><child a2=\"v2\"/></node>"));
+ CHECK_NODE(doc, STR("<node a3=\"v3\" a4=\"v4\" a5=\"v5\" a1=\"v1\"><child a2=\"v2\"/>text</node>"));
}
TEST_XML(dom_node_remove_attribute, "<node a1='v1' a2='v2' a3='v3'><child a4='v4'/></node>")
@@ -550,6 +552,7 @@ TEST_XML(dom_node_insert_child_after, "<node>foo<child/></node>")
xml_node node = doc.child(STR("node"));
xml_node child = node.child(STR("child"));
+ CHECK(node.insert_child_after(node_element, xml_node()) == xml_node());
CHECK(node.insert_child_after(node_element, node) == xml_node());
CHECK(child.insert_child_after(node_element, node) == xml_node());
@@ -584,6 +587,7 @@ TEST_XML(dom_node_insert_child_before, "<node>foo<child/></node>")
xml_node node = doc.child(STR("node"));
xml_node child = node.child(STR("child"));
+ CHECK(node.insert_child_before(node_element, xml_node()) == xml_node());
CHECK(node.insert_child_before(node_element, node) == xml_node());
CHECK(child.insert_child_before(node_element, node) == xml_node());
@@ -770,13 +774,16 @@ TEST_XML(dom_node_append_copy, "<node>foo<child/></node>")
TEST_XML(dom_node_insert_copy_after, "<node>foo<child/></node>")
{
+ xml_node child = doc.child(STR("node")).child(STR("child"));
+
CHECK(xml_node().insert_copy_after(xml_node(), xml_node()) == xml_node());
CHECK(doc.child(STR("node")).first_child().insert_copy_after(doc.child(STR("node")), doc.child(STR("node"))) == xml_node());
CHECK(doc.insert_copy_after(doc, doc) == xml_node());
CHECK(doc.insert_copy_after(xml_node(), doc.child(STR("node"))) == xml_node());
CHECK(doc.insert_copy_after(doc.child(STR("node")), xml_node()) == xml_node());
+ CHECK(doc.insert_copy_after(doc.child(STR("node")), child) == xml_node());
- xml_node n1 = doc.child(STR("node")).insert_copy_after(doc.child(STR("node")).child(STR("child")), doc.child(STR("node")).first_child());
+ xml_node n1 = doc.child(STR("node")).insert_copy_after(child, doc.child(STR("node")).first_child());
CHECK(n1);
CHECK_STRING(n1.name(), STR("child"));
CHECK_NODE(doc, STR("<node>foo<child/><child/></node>"));
@@ -794,13 +801,16 @@ TEST_XML(dom_node_insert_copy_after, "<node>foo<child/></node>")
TEST_XML(dom_node_insert_copy_before, "<node>foo<child/></node>")
{
+ xml_node child = doc.child(STR("node")).child(STR("child"));
+
CHECK(xml_node().insert_copy_before(xml_node(), xml_node()) == xml_node());
CHECK(doc.child(STR("node")).first_child().insert_copy_before(doc.child(STR("node")), doc.child(STR("node"))) == xml_node());
CHECK(doc.insert_copy_before(doc, doc) == xml_node());
CHECK(doc.insert_copy_before(xml_node(), doc.child(STR("node"))) == xml_node());
CHECK(doc.insert_copy_before(doc.child(STR("node")), xml_node()) == xml_node());
+ CHECK(doc.insert_copy_before(doc.child(STR("node")), child) == xml_node());
- xml_node n1 = doc.child(STR("node")).insert_copy_before(doc.child(STR("node")).child(STR("child")), doc.child(STR("node")).first_child());
+ xml_node n1 = doc.child(STR("node")).insert_copy_before(child, doc.child(STR("node")).first_child());
CHECK(n1);
CHECK_STRING(n1.name(), STR("child"));
CHECK_NODE(doc, STR("<node><child/>foo<child/></node>"));
@@ -1314,6 +1324,7 @@ TEST_XML(dom_node_insert_move_after, "<node>foo<child>bar</child></node>")
CHECK(doc.insert_move_after(doc, doc) == xml_node());
CHECK(doc.insert_move_after(xml_node(), doc.child(STR("node"))) == xml_node());
CHECK(doc.insert_move_after(doc.child(STR("node")), xml_node()) == xml_node());
+ CHECK(doc.insert_move_after(doc.child(STR("node")), child) == xml_node());
xml_node n1 = doc.child(STR("node")).insert_move_after(child, doc.child(STR("node")).first_child());
CHECK(n1 && n1 == child);
@@ -1340,6 +1351,7 @@ TEST_XML(dom_node_insert_move_before, "<node>foo<child>bar</child></node>")
CHECK(doc.insert_move_before(doc, doc) == xml_node());
CHECK(doc.insert_move_before(xml_node(), doc.child(STR("node"))) == xml_node());
CHECK(doc.insert_move_before(doc.child(STR("node")), xml_node()) == xml_node());
+ CHECK(doc.insert_move_before(doc.child(STR("node")), child) == xml_node());
xml_node n1 = doc.child(STR("node")).insert_move_before(child, doc.child(STR("node")).first_child());
CHECK(n1 && n1 == child);
diff --git a/tests/test_dom_traverse.cpp b/tests/test_dom_traverse.cpp
index f977e15..3d30a82 100644
--- a/tests/test_dom_traverse.cpp
+++ b/tests/test_dom_traverse.cpp
@@ -137,6 +137,10 @@ TEST_XML(dom_attr_as_integer_space, "<node attr1=' \t1234' attr2='\t 0x123' attr
CHECK(node.attribute(STR("attr2")).as_int() == 291);
CHECK(node.attribute(STR("attr3")).as_int() == 0);
CHECK(node.attribute(STR("attr4")).as_int() == 0);
+
+#ifdef PUGIXML_HAS_LONG_LONG
+ CHECK(node.attribute(STR("attr1")).as_llong() == 1234);
+#endif
}
TEST_XML(dom_attr_as_float, "<node attr1='0' attr2='1' attr3='0.12' attr4='-5.1' attr5='3e-4' attr6='3.14159265358979323846'/>")
@@ -736,6 +740,9 @@ TEST_XML(dom_node_path, "<node><child1>text<child2/></child1></node>")
CHECK(doc.child(STR("node")).child(STR("child1")).first_child().path() == STR("/node/child1/"));
CHECK(doc.child(STR("node")).child(STR("child1")).path('\\') == STR("\\node\\child1"));
+
+ doc.append_child(node_element);
+ CHECK(doc.last_child().path() == STR("/"));
}
#endif
@@ -1274,3 +1281,17 @@ TEST_XML(dom_as_int_plus, "<node attr1='+1' attr2='+0xa' />")
CHECK(node.attribute(STR("attr2")).as_ullong() == 10);
#endif
}
+
+TEST(dom_node_anonymous)
+{
+ xml_document doc;
+ doc.append_child(node_element);
+ doc.append_child(node_element);
+ doc.append_child(node_pcdata);
+
+ CHECK(doc.child(STR("node")) == xml_node());
+ CHECK(doc.first_child().next_sibling(STR("node")) == xml_node());
+ CHECK(doc.last_child().previous_sibling(STR("node")) == xml_node());
+ CHECK_STRING(doc.child_value(), STR(""));
+ CHECK_STRING(doc.last_child().child_value(), STR(""));
+}
diff --git a/tests/test_parse.cpp b/tests/test_parse.cpp
index ba45a45..013bca9 100644
--- a/tests/test_parse.cpp
+++ b/tests/test_parse.cpp
@@ -88,6 +88,16 @@ TEST(parse_pi_error)
CHECK(doc.load_string(STR("<?name& x?>"), parse_fragment | parse_pi).status == status_bad_pi);
}
+TEST(parse_pi_error_buffer_boundary)
+{
+ char buf1[] = "<?name?>";
+ char buf2[] = "<?name?x";
+
+ xml_document doc;
+ CHECK(doc.load_buffer_inplace(buf1, 8, parse_fragment | parse_pi));
+ CHECK(doc.load_buffer_inplace(buf2, 8, parse_fragment | parse_pi).status == status_bad_pi);
+}
+
TEST(parse_comments_skip)
{
xml_document doc;
@@ -746,6 +756,36 @@ TEST(parse_attribute_quot_inside)
}
}
+TEST(parse_attribute_wnorm_coverage)
+{
+ xml_document doc;
+ CHECK(doc.load_string(STR("<n a1='v' a2=' ' a3='x y' a4='x y' a5='x y' />"), parse_wnorm_attribute));
+ CHECK_NODE(doc, STR("<n a1=\"v\" a2=\"\" a3=\"x y\" a4=\"x y\" a5=\"x y\"/>"));
+
+ CHECK(doc.load_string(STR("<n a1='v' a2=' ' a3='x y' a4='x y' a5='x y' />"), parse_wnorm_attribute | parse_escapes));
+ CHECK_NODE(doc, STR("<n a1=\"v\" a2=\"\" a3=\"x y\" a4=\"x y\" a5=\"x y\"/>"));
+}
+
+TEST(parse_attribute_wconv_coverage)
+{
+ xml_document doc;
+ CHECK(doc.load_string(STR("<n a1='v' a2='\r' a3='\r\n\n' a4='\n' />"), parse_wconv_attribute));
+ CHECK_NODE(doc, STR("<n a1=\"v\" a2=\" \" a3=\" \" a4=\" \"/>"));
+
+ CHECK(doc.load_string(STR("<n a1='v' a2='\r' a3='\r\n\n' a4='\n' />"), parse_wconv_attribute | parse_escapes));
+ CHECK_NODE(doc, STR("<n a1=\"v\" a2=\" \" a3=\" \" a4=\" \"/>"));
+}
+
+TEST(parse_attribute_eol_coverage)
+{
+ xml_document doc;
+ CHECK(doc.load_string(STR("<n a1='v' a2='\r' a3='\r\n\n' a4='\n' />"), parse_eol));
+ CHECK_NODE(doc, STR("<n a1=\"v\" a2=\"&#10;\" a3=\"&#10;&#10;\" a4=\"&#10;\"/>"));
+
+ CHECK(doc.load_string(STR("<n a1='v' a2='\r' a3='\r\n\n' a4='\n' />"), parse_eol | parse_escapes));
+ CHECK_NODE(doc, STR("<n a1=\"v\" a2=\"&#10;\" a3=\"&#10;&#10;\" a4=\"&#10;\"/>"));
+}
+
TEST(parse_tag_single)
{
xml_document doc;
@@ -928,7 +968,7 @@ TEST(parse_out_of_memory_halfway_attr)
TEST(parse_out_of_memory_conversion)
{
- test_runner::_memory_fail_threshold = 256;
+ test_runner::_memory_fail_threshold = 1;
xml_document doc;
CHECK_ALLOC_FAIL(CHECK(doc.load_buffer("<foo\x90/>", 7, parse_default, encoding_latin1).status == status_out_of_memory));
@@ -1183,6 +1223,33 @@ TEST(parse_embed_pcdata)
}
}
+TEST_XML_FLAGS(parse_embed_pcdata_fragment, "text", parse_fragment | parse_embed_pcdata)
+{
+ CHECK_NODE(doc, STR("text"));
+ CHECK(doc.first_child().type() == node_pcdata);
+ CHECK_STRING(doc.first_child().value(), STR("text"));
+}
+
+TEST_XML_FLAGS(parse_embed_pcdata_child, "<n><child/>text</n>", parse_embed_pcdata)
+{
+ xml_node n = doc.child(STR("n"));
+
+ CHECK_NODE(doc, STR("<n><child/>text</n>"));
+ CHECK(n.last_child().type() == node_pcdata);
+ CHECK_STRING(n.last_child().value(), STR("text"));
+}
+
+TEST_XML_FLAGS(parse_embed_pcdata_comment, "<n>text1<!---->text2</n>", parse_embed_pcdata)
+{
+ xml_node n = doc.child(STR("n"));
+
+ CHECK_NODE(doc, STR("<n>text1text2</n>"));
+ CHECK_STRING(n.value(), STR("text1"));
+ CHECK(n.first_child() == n.last_child());
+ CHECK(n.last_child().type() == node_pcdata);
+ CHECK_STRING(n.last_child().value(), STR("text2"));
+}
+
TEST(parse_encoding_detect)
{
char test[] = "<?xml version='1.0' encoding='utf-8'?><n/>";
@@ -1206,3 +1273,83 @@ TEST(parse_encoding_detect_latin1)
CHECK(doc.load_buffer(test3, sizeof(test3)).encoding == encoding_latin1);
CHECK(doc.load_buffer(test4, sizeof(test4)).encoding == encoding_latin1);
}
+
+TEST(parse_encoding_detect_auto)
+{
+ struct data_t
+ {
+ const char* contents;
+ size_t size;
+ xml_encoding encoding;
+ };
+
+ const data_t data[] =
+ {
+ // BOM
+ { "\x00\x00\xfe\xff", 4, encoding_utf32_be },
+ { "\xff\xfe\x00\x00", 4, encoding_utf32_le },
+ { "\xfe\xff ", 4, encoding_utf16_be },
+ { "\xff\xfe ", 4, encoding_utf16_le },
+ { "\xef\xbb\xbf ", 4, encoding_utf8 },
+ // automatic tag detection for < or <?
+ { "\x00\x00\x00<\x00\x00\x00n\x00\x00\x00/\x00\x00\x00>", 16, encoding_utf32_be },
+ { "<\x00\x00\x00n\x00\x00\x00/\x00\x00\x00>\x00\x00\x00", 16, encoding_utf32_le },
+ { "\x00<\x00?\x00n\x00?\x00>", 10, encoding_utf16_be },
+ { "<\x00?\x00n\x00?\x00>\x00", 10, encoding_utf16_le },
+ { "\x00<\x00n\x00/\x00>", 8, encoding_utf16_be },
+ { "<\x00n\x00/\x00>\x00", 8, encoding_utf16_le },
+ // <?xml encoding
+ { "<?xml encoding='latin1'?>", 25, encoding_latin1 },
+ };
+
+ for (size_t i = 0; i < sizeof(data) / sizeof(data[0]); ++i)
+ {
+ xml_document doc;
+ xml_parse_result result = doc.load_buffer(data[i].contents, data[i].size, parse_fragment);
+
+ CHECK(result);
+ CHECK(result.encoding == data[i].encoding);
+ }
+}
+
+TEST(parse_encoding_detect_auto_incomplete)
+{
+ struct data_t
+ {
+ const char* contents;
+ size_t size;
+ xml_encoding encoding;
+ };
+
+ const data_t data[] =
+ {
+ // BOM
+ { "\x00\x00\xfe ", 4, encoding_utf8 },
+ { "\x00\x00 ", 4, encoding_utf8 },
+ { "\xff\xfe\x00 ", 4, encoding_utf16_le },
+ { "\xfe ", 4, encoding_utf8 },
+ { "\xff ", 4, encoding_utf8 },
+ { "\xef\xbb ", 4, encoding_utf8 },
+ { "\xef ", 4, encoding_utf8 },
+ // automatic tag detection for < or <?
+ { "\x00\x00\x00 ", 4, encoding_utf8 },
+ { "<\x00\x00n/\x00>\x00", 8, encoding_utf16_le },
+ { "\x00<n\x00\x00/\x00>", 8, encoding_utf16_be },
+ { "<\x00?n/\x00>\x00", 8, encoding_utf16_le },
+ { "\x00 ", 8, encoding_utf8 },
+ // <?xml encoding
+ { "<?xmC encoding='latin1'?>", 25, encoding_utf8 },
+ { "<?xBC encoding='latin1'?>", 25, encoding_utf8 },
+ { "<?ABC encoding='latin1'?>", 25, encoding_utf8 },
+ { "<_ABC encoding='latin1'/>", 25, encoding_utf8 },
+ };
+
+ for (size_t i = 0; i < sizeof(data) / sizeof(data[0]); ++i)
+ {
+ xml_document doc;
+ xml_parse_result result = doc.load_buffer(data[i].contents, data[i].size, parse_fragment);
+
+ CHECK(result);
+ CHECK(result.encoding == data[i].encoding);
+ }
+}
diff --git a/tests/test_write.cpp b/tests/test_write.cpp
index d5f3dad..5cd92a5 100644
--- a/tests/test_write.cpp
+++ b/tests/test_write.cpp
@@ -69,6 +69,12 @@ TEST_XML_FLAGS(write_cdata_escape, "<![CDATA[value]]>", parse_cdata | parse_frag
doc.first_child().set_value(STR("1]]>2]]>3"));
CHECK_NODE(doc, STR("<![CDATA[1]]]]><![CDATA[>2]]]]><![CDATA[>3]]>"));
+
+ doc.first_child().set_value(STR("1]"));
+ CHECK_NODE(doc, STR("<![CDATA[1]]]>"));
+
+ doc.first_child().set_value(STR("1]]"));
+ CHECK_NODE(doc, STR("<![CDATA[1]]]]>"));
}
TEST_XML(write_cdata_inner, "<node><![CDATA[value]]></node>")
diff --git a/tests/test_xpath.cpp b/tests/test_xpath.cpp
index 33c1696..6cae607 100644
--- a/tests/test_xpath.cpp
+++ b/tests/test_xpath.cpp
@@ -367,6 +367,32 @@ TEST(xpath_large_node_set)
CHECK(ns.size() == 10001);
}
+TEST(xpath_out_of_memory_query)
+{
+ test_runner::_memory_fail_threshold = 1;
+
+ CHECK_ALLOC_FAIL(xpath_query q(STR("node")));
+}
+
+TEST_XML(xpath_out_of_memory_evaluate, "<n/>")
+{
+ test_runner::_memory_fail_threshold = 4196 * sizeof(char_t) + 4096 * 2 + 32768;
+
+ std::basic_string<char_t> query = STR("*[concat(\"a\", \"");
+
+ query.resize(4196, 'a');
+ query += STR("\")]");
+
+ pugi::xpath_query q(query.c_str());
+
+ CHECK_ALLOC_FAIL(CHECK(q.evaluate_boolean(doc) == false));
+ CHECK_ALLOC_FAIL(CHECK_DOUBLE_NAN(q.evaluate_number(doc)));
+ CHECK_ALLOC_FAIL(CHECK(q.evaluate_string(doc).empty()));
+ CHECK_ALLOC_FAIL(CHECK(q.evaluate_string(0, 0, doc) == 1));
+ CHECK_ALLOC_FAIL(CHECK(q.evaluate_node(doc) == xpath_node()));
+ CHECK_ALLOC_FAIL(CHECK(q.evaluate_node_set(doc).empty()));
+}
+
TEST(xpath_out_of_memory_evaluate_concat)
{
test_runner::_memory_fail_threshold = 4196 * sizeof(char_t) + 4096 * 2;
@@ -404,15 +430,83 @@ TEST_XML(xpath_out_of_memory_evaluate_union, "<node><a/><a/><a/><a/><a/><a/><a/>
CHECK_ALLOC_FAIL(CHECK(q.evaluate_node_set(doc.child(STR("node"))).empty()));
}
-TEST_XML(xpath_out_of_memory_evaluate_predicate, "<node><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/></node>")
+TEST_XML(xpath_out_of_memory_evaluate_predicate, "<node><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/></node>")
{
test_runner::_memory_fail_threshold = 32768 + 4096 * 2;
- pugi::xpath_query q(STR("//a[//a[//a[//a[//a[//a[//a[//a[//a[//a[//a[//a[//a[//a[true()]]]]]]]]]]]]]]"));
+ pugi::xpath_query q(STR("//a[//a[//a[//a[true()]]]]"));
CHECK_ALLOC_FAIL(CHECK(q.evaluate_node_set(doc).empty()));
}
+TEST_XML(xpath_out_of_memory_evaluate_normalize_space_0, "<node> a b c d e f g h i j k l m n o p q r s t u v w x y z a b c d e f g h i j k l m n o p q r s t u v w x y z a b c d e f g h i j k l m n o p q r s t u v w x y z a b c d e f g h i j k l m n o p q r s t u v w x y z a b c d e f g h i j k l m n o p q r s t u v w x y z a b c d e f g h i j k l m n o p q r s t u v w x y z a b c d e f g h i j k l m n o p q r s t u v w x y z a b c d e f g h i j k l m n o p q r s t u v w x y z a b c d e f g h i j k l m n o p q r s t u v w x y z a b c d e f g h i j k l m n o p q r s t u v w x y z </node>")
+{
+ test_runner::_memory_fail_threshold = 32768 + 4096 * 2;
+
+ pugi::xpath_query q(STR("concat(normalize-space(), normalize-space(), normalize-space(), normalize-space(), normalize-space(), normalize-space(), normalize-space(), normalize-space())"));
+
+ CHECK_ALLOC_FAIL(CHECK(q.evaluate_string(doc.first_child()).empty()));
+}
+
+TEST_XML(xpath_out_of_memory_evaluate_normalize_space_1, "<node> a b c d e f g h i j k l m n o p q r s t u v w x y z a b c d e f g h i j k l m n o p q r s t u v w x y z a b c d e f g h i j k l m n o p q r s t u v w x y z a b c d e f g h i j k l m n o p q r s t u v w x y z a b c d e f g h i j k l m n o p q r s t u v w x y z a b c d e f g h i j k l m n o p q r s t u v w x y z a b c d e f g h i j k l m n o p q r s t u v w x y z a b c d e f g h i j k l m n o p q r s t u v w x y z a b c d e f g h i j k l m n o p q r s t u v w x y z a b c d e f g h i j k l m n o p q r s t u v w x y z </node>")
+{
+ test_runner::_memory_fail_threshold = 32768 + 4096 * 2;
+
+ pugi::xpath_query q(STR("concat(normalize-space(node), normalize-space(node), normalize-space(node), normalize-space(node), normalize-space(node), normalize-space(node), normalize-space(node), normalize-space(node))"));
+
+ CHECK_ALLOC_FAIL(CHECK(q.evaluate_string(doc).empty()));
+}
+
+TEST_XML(xpath_out_of_memory_evaluate_translate, "<node> a b c d e f g h i j k l m n o p q r s t u v w x y z a b c d e f g h i j k l m n o p q r s t u v w x y z a b c d e f g h i j k l m n o p q r s t u v w x y z a b c d e f g h i j k l m n o p q r s t u v w x y z a b c d e f g h i j k l m n o p q r s t u v w x y z a b c d e f g h i j k l m n o p q r s t u v w x y z a b c d e f g h i j k l m n o p q r s t u v w x y z a b c d e f g h i j k l m n o p q r s t u v w x y z a b c d e f g h i j k l m n o p q r s t u v w x y z a b c d e f g h i j k l m n o p q r s t u v w x y z </node>")
+{
+ test_runner::_memory_fail_threshold = 32768 + 4096 * 2;
+
+ pugi::xpath_query q(STR("concat(translate(node, 'a', '\xe9'), translate(node, 'a', '\xe9'), translate(node, 'a', '\xe9'), translate(node, 'a', '\xe9'), translate(node, 'a', '\xe9'), translate(node, 'a', '\xe9'), translate(node, 'a', '\xe9'), translate(node, 'a', '\xe9'))"));
+
+ CHECK_ALLOC_FAIL(CHECK(q.evaluate_string(doc).empty()));
+}
+
+TEST_XML(xpath_out_of_memory_evaluate_translate_table, "<node> a b c d e f g h i j k l m n o p q r s t u v w x y z a b c d e f g h i j k l m n o p q r s t u v w x y z a b c d e f g h i j k l m n o p q r s t u v w x y z a b c d e f g h i j k l m n o p q r s t u v w x y z a b c d e f g h i j k l m n o p q r s t u v w x y z a b c d e f g h i j k l m n o p q r s t u v w x y z a b c d e f g h i j k l m n o p q r s t u v w x y z a b c d e f g h i j k l m n o p q r s t u v w x y z a b c d e f g h i j k l m n o p q r s t u v w x y z a b c d e f g h i j k l m n o p q r s t u v w x y z </node>")
+{
+ test_runner::_memory_fail_threshold = 32768 + 4096 * 2;
+
+ pugi::xpath_query q(STR("concat(translate(node, 'a', 'A'), translate(node, 'a', 'A'), translate(node, 'a', 'A'), translate(node, 'a', 'A'), translate(node, 'a', 'A'), translate(node, 'a', 'A'), translate(node, 'a', 'A'), translate(node, 'a', 'A'))"));
+
+ CHECK_ALLOC_FAIL(CHECK(q.evaluate_string(doc).empty()));
+}
+
+TEST(xpath_out_of_memory_evaluate_string_append)
+{
+ test_runner::_memory_fail_threshold = 32768 + 4096 * 2;
+
+ std::basic_string<char_t> literal(5000, 'a');
+
+ std::basic_string<char_t> buf;
+ buf += STR("<n><c>text</c><c>");
+ buf += literal;
+ buf += STR("</c></n>");
+
+ xml_document doc;
+ CHECK(doc.load_buffer_inplace(&buf[0], buf.size() * sizeof(char_t)));
+
+ pugi::xpath_query q(STR("string(n)"));
+ CHECK(q);
+
+ CHECK_ALLOC_FAIL(CHECK(q.evaluate_string(doc).empty()));
+}
+
+TEST(xpath_out_of_memory_evaluate_number_to_string)
+{
+ test_runner::_memory_fail_threshold = 4096 + 128;
+
+ xpath_variable_set vars;
+ vars.set(STR("x"), 1e+308);
+
+ xpath_query q(STR("concat($x, $x, $x, $x, $x, $x, $x, $x, $x, $x, $x, $x, $x, $x, $x, $x, $x)"), &vars);
+
+ CHECK_ALLOC_FAIL(CHECK(q.evaluate_string(xml_node()).empty()));
+}
+
TEST(xpath_memory_concat_massive)
{
pugi::xml_document doc;
@@ -578,6 +672,17 @@ TEST(xpath_sort_crossdoc_different_depth)
CHECK((ns[0] == ns1[0] && ns[1] == ns2[0]) || (ns[0] == ns2[0] && ns[1] == ns1[0]));
}
+TEST_XML(xpath_sort_empty_node, "<node><child1/><child2/></node>")
+{
+ xml_node n = doc.child(STR("node"));
+ xpath_node nodes[] = { n.child(STR("child2")), xml_node(), n.child(STR("child1")), xml_node() };
+ xpath_node_set ns(nodes, nodes + sizeof(nodes) / sizeof(nodes[0]));
+
+ ns.sort();
+
+ CHECK(!ns[0] && !ns[1] && ns[2] == nodes[2] && ns[3] == nodes[0]);
+}
+
TEST(xpath_allocate_string_out_of_memory)
{
std::basic_string<char_t> query;
@@ -612,4 +717,15 @@ TEST(xpath_remove_duplicates)
tester % (2 + i);
}
}
+
+TEST(xpath_anonymous_nodes)
+{
+ xml_document doc;
+ doc.append_child(node_element);
+ doc.append_child(node_pi);
+
+ CHECK_XPATH_NODESET(doc, STR("/name"));
+ CHECK_XPATH_NODESET(doc, STR("/processing-instruction('a')"));
+ CHECK_XPATH_NODESET(doc, STR("/ns:*"));
+}
#endif
diff --git a/tests/test_xpath_api.cpp b/tests/test_xpath_api.cpp
index c1a4968..3f05e13 100644
--- a/tests/test_xpath_api.cpp
+++ b/tests/test_xpath_api.cpp
@@ -107,6 +107,7 @@ TEST_XML(xpath_api_nodeset_accessors, "<node><foo/><foo/></node>")
TEST_XML(xpath_api_nodeset_copy, "<node><foo/><foo/></node>")
{
+ xpath_node_set empty;
xpath_node_set set = doc.select_nodes(STR("node/foo"));
xpath_node_set copy1 = set;
@@ -132,7 +133,7 @@ TEST_XML(xpath_api_nodeset_copy, "<node><foo/><foo/></node>")
xpath_node_set copy5;
copy5 = set;
- copy5 = xpath_node_set();
+ copy5 = empty;
CHECK(copy5.size() == 0);
}
@@ -572,6 +573,18 @@ TEST(xpath_api_nodeset_move_assign_empty)
CHECK(move.type() == xpath_node_set::type_sorted);
}
+TEST_XML(xpath_api_nodeset_move_assign_self, "<node><foo/><foo/><bar/></node>")
+{
+ xpath_node_set set = doc.select_nodes(STR("node/bar"));
+
+ CHECK(set.size() == 1);
+ CHECK(set.type() == xpath_node_set::type_sorted);
+
+ test_runner::_memory_fail_threshold = 1;
+
+ set = std::move(*&set);
+}
+
TEST(xpath_api_query_move)
{
xml_node c;
diff --git a/tests/test_xpath_functions.cpp b/tests/test_xpath_functions.cpp
index 211dbfb..480eb97 100644
--- a/tests/test_xpath_functions.cpp
+++ b/tests/test_xpath_functions.cpp
@@ -566,6 +566,7 @@ TEST(xpath_string_translate_table)
CHECK_XPATH_STRING(c, STR("translate('abcd\xe9 ', 'abc', 'ABC')"), STR("ABCd\xe9 "));
CHECK_XPATH_STRING(c, STR("translate('abcd\xe9 ', 'abc\xe9', 'ABC!')"), STR("ABCd! "));
+ CHECK_XPATH_STRING(c, STR("translate('abcd! ', 'abc!', 'ABC\xe9')"), STR("ABCd\xe9 "));
CHECK_XPATH_STRING(c, STR("translate('abcde', concat('abc', 'd'), 'ABCD')"), STR("ABCDe"));
CHECK_XPATH_STRING(c, STR("translate('abcde', 'abcd', concat('ABC', 'D'))"), STR("ABCDe"));
}
@@ -799,4 +800,17 @@ TEST_XML(xpath_string_concat_translate, "<node>foobar</node>")
CHECK_XPATH_STRING(doc, STR("concat('a', 'b', 'c', translate(node, 'o', 'a'), 'd')"), STR("abcfaabard"));
}
+TEST(xpath_unknown_functions)
+{
+ char_t query[] = STR("a()");
+
+ for (char ch = 'a'; ch <= 'z'; ++ch)
+ {
+ query[0] = ch;
+ CHECK_XPATH_FAIL(query);
+
+ query[0] = ch - 32;
+ CHECK_XPATH_FAIL(query);
+ }
+}
#endif
diff --git a/tests/test_xpath_operators.cpp b/tests/test_xpath_operators.cpp
index 1a97c7d..c2281e6 100644
--- a/tests/test_xpath_operators.cpp
+++ b/tests/test_xpath_operators.cpp
@@ -332,11 +332,21 @@ TEST_XML(xpath_operators_inequality_node_set_node_set, "<node><c1><v>1</v><v>-1<
CHECK_XPATH_BOOLEAN(n, STR("c1/v < c3/v"), true);
CHECK_XPATH_BOOLEAN(n, STR("c1/v <= c3/v"), true);
+ CHECK_XPATH_BOOLEAN(n, STR("c1/v[1] > c1/v[1]"), false);
+ CHECK_XPATH_BOOLEAN(n, STR("c1/v[1] < c1/v[1]"), false);
+ CHECK_XPATH_BOOLEAN(n, STR("c1/v[1] >= c1/v[1]"), true);
+ CHECK_XPATH_BOOLEAN(n, STR("c1/v[1] <= c1/v[1]"), true);
+
#ifndef MSVC6_NAN_BUG
CHECK_XPATH_BOOLEAN(n, STR("c1/v > c2/v"), false);
CHECK_XPATH_BOOLEAN(n, STR("c1/v >= c2/v"), true);
CHECK_XPATH_BOOLEAN(n, STR("c1/v < c2/v"), true);
CHECK_XPATH_BOOLEAN(n, STR("c1/v <= c2/v"), true);
+
+ CHECK_XPATH_BOOLEAN(n, STR("c2/v[2] < c2/v[2]"), false);
+ CHECK_XPATH_BOOLEAN(n, STR("c2/v[2] > c2/v[2]"), false);
+ CHECK_XPATH_BOOLEAN(n, STR("c2/v[2] <= c2/v[2]"), false);
+ CHECK_XPATH_BOOLEAN(n, STR("c2/v[2] >= c2/v[2]"), false);
#endif
}
diff --git a/tests/test_xpath_parse.cpp b/tests/test_xpath_parse.cpp
index b6de42e..8819a5d 100644
--- a/tests/test_xpath_parse.cpp
+++ b/tests/test_xpath_parse.cpp
@@ -274,7 +274,7 @@ TEST_XML(xpath_parse_absolute, "<div><s/></div>")
TEST(xpath_parse_out_of_memory_first_page)
{
- test_runner::_memory_fail_threshold = 1;
+ test_runner::_memory_fail_threshold = 128;
CHECK_ALLOC_FAIL(CHECK_XPATH_FAIL(STR("1")));
}
@@ -293,6 +293,27 @@ TEST(xpath_parse_out_of_memory_string_to_number)
CHECK_ALLOC_FAIL(CHECK_XPATH_FAIL(STR("0.11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111")));
}
+TEST(xpath_parse_out_of_memory_quoted_string)
+{
+ test_runner::_memory_fail_threshold = 4096 + 128;
+
+ std::basic_string<char_t> literal(5000, 'a');
+ std::basic_string<char_t> query = STR("'") + literal + STR("'");
+
+ CHECK_ALLOC_FAIL(CHECK_XPATH_FAIL(query.c_str()));
+}
+
+TEST(xpath_parse_out_of_memory_variable)
+{
+ test_runner::_memory_fail_threshold = 4096 + 128;
+
+ std::basic_string<char_t> literal(5000, 'a');
+ std::basic_string<char_t> query = STR("$") + literal;
+
+ xpath_variable_set vars;
+ CHECK_ALLOC_FAIL(CHECK_XPATH_FAIL_VAR(query.c_str(), &vars));
+}
+
TEST(xpath_parse_qname_error)
{
CHECK_XPATH_FAIL(STR("foo: bar"));
@@ -313,4 +334,57 @@ TEST(xpath_parse_result_default)
CHECK(result.offset == 0);
}
+TEST(xpath_parse_error_propagation)
+{
+ char_t query[] = STR("(//foo[count(. | @*)] | ((a)//b)[1] | /foo | /foo/bar//more/ancestor-or-self::foobar | /text() | a[1 + 2 * 3 div (1+0) mod 2]//b[1]/c | a[$x])[true()]");
+
+ xpath_variable_set vars;
+ vars.set(STR("x"), 1.0);
+
+ xpath_query q(query, &vars);
+ CHECK(q);
+
+ for (size_t i = 0; i + 1 < sizeof(query) / sizeof(query[0]); ++i)
+ {
+ char_t ch = query[i];
+
+ query[i] = '%';
+
+ CHECK_XPATH_FAIL(query);
+
+ query[i] = ch;
+ }
+}
+
+TEST(xpath_parse_oom_propagation)
+{
+ const char_t* query_base = STR("(//foo[count(. | @*)] | ((a)//b)[1] | /foo | /foo/bar//more/ancestor-or-self::foobar | /text() | a[1 + 2 * 3 div (1+0) mod 2]//b[1]/c | a[$x])[true()]");
+
+ xpath_variable_set vars;
+ vars.set(STR("x"), 1.0);
+
+ test_runner::_memory_fail_threshold = 4096 + 128;
+
+ {
+ xpath_query q(query_base, &vars);
+ CHECK(q);
+ }
+
+ for (size_t i = 3200; i < 4200; ++i)
+ {
+ std::basic_string<char_t> literal(i, 'a');
+ std::basic_string<char_t> query = STR("processing-instruction('") + literal + STR("') | ") + query_base;
+
+ CHECK_ALLOC_FAIL(CHECK_XPATH_FAIL(query.c_str()));
+ }
+}
+
+TEST_XML(xpath_parse_location_path, "<node><child/></node>")
+{
+ CHECK_XPATH_NODESET(doc, STR("/node")) % 2;
+ CHECK_XPATH_NODESET(doc, STR("/@*"));
+ CHECK_XPATH_NODESET(doc, STR("/.")) % 1;
+ CHECK_XPATH_NODESET(doc, STR("/.."));
+ CHECK_XPATH_NODESET(doc, STR("/*")) % 2;
+}
#endif
diff --git a/tests/test_xpath_paths.cpp b/tests/test_xpath_paths.cpp
index 69215d8..7915df1 100644
--- a/tests/test_xpath_paths.cpp
+++ b/tests/test_xpath_paths.cpp
@@ -358,6 +358,13 @@ TEST_XML_FLAGS(xpath_paths_nodetest_principal, "<node attr='value'>pcdata<child/
CHECK_XPATH_NODESET(doc, STR("child::abra:*/attribute::abra:*/descendant-or-self::abra:*")); // attribute is not of element type
}
+TEST_XML(xpath_paths_nodetest_attribute_namespace, "<node a1='v1' xmlns:x='?' />")
+{
+ CHECK_XPATH_NODESET(doc, STR("node/attribute::node()")) % 3;
+ CHECK_XPATH_NODESET(doc, STR("node/attribute::xmlns:x"));
+ CHECK_XPATH_NODESET(doc, STR("node/attribute::xmlns:*"));
+}
+
TEST_XML(xpath_paths_absolute, "<node attr='value'><foo><foo/><foo/></foo></node>")
{
xml_node c;