From a1bc15c8d525ff2cac165cc0e5d08b272d79fc33 Mon Sep 17 00:00:00 2001
From: Arseny Kapoulkine <arseny.kapoulkine@gmail.com>
Date: Mon, 30 Jan 2017 23:24:20 -0800
Subject: [PATCH] tests: Add more coverage tests

Expand out of memory coverage during XPath parsing and evaluation and
add some other small tests.
---
 tests/test_xpath.cpp       | 36 ++++++++++++++++++++++++++++++++++++
 tests/test_xpath_api.cpp   | 12 ++++++++++++
 tests/test_xpath_parse.cpp | 25 ++++++++++++++++++++++++-
 tests/test_xpath_paths.cpp |  7 +++++++
 4 files changed, 79 insertions(+), 1 deletion(-)

diff --git a/tests/test_xpath.cpp b/tests/test_xpath.cpp
index 8359f4f3..f8a4b154 100644
--- a/tests/test_xpath.cpp
+++ b/tests/test_xpath.cpp
@@ -439,6 +439,42 @@ TEST_XML(xpath_out_of_memory_evaluate_predicate, "<node><a/><a/><a/><a/><a/><a/>
 	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_memory_concat_massive)
 {
 	pugi::xml_document doc;
diff --git a/tests/test_xpath_api.cpp b/tests/test_xpath_api.cpp
index 1e7f924c..3f05e13a 100644
--- a/tests/test_xpath_api.cpp
+++ b/tests/test_xpath_api.cpp
@@ -573,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_parse.cpp b/tests/test_xpath_parse.cpp
index c39481b1..9b28478a 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")));
 }
@@ -335,6 +335,29 @@ TEST(xpath_parse_error_propagation)
 	}
 }
 
+TEST(xpath_parse_oom_propagation)
+{
+	const char_t* query_base = STR("(//foo[count(. | @*)] | /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;
diff --git a/tests/test_xpath_paths.cpp b/tests/test_xpath_paths.cpp
index 69215d82..7915df19 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;
-- 
GitLab