diff options
Diffstat (limited to 'tests')
| -rwxr-xr-x | tests/gitsvn.sh | 5 | ||||
| -rw-r--r-- | tests/main.cpp | 6 | ||||
| -rw-r--r-- | tests/test.hpp | 1 | ||||
| -rw-r--r-- | tests/test_document.cpp | 73 | ||||
| -rw-r--r-- | tests/test_dom_modify.cpp | 69 | ||||
| -rw-r--r-- | tests/test_dom_traverse.cpp | 10 | ||||
| -rw-r--r-- | tests/test_parse.cpp | 53 | ||||
| -rw-r--r-- | tests/test_parse_doctype.cpp | 9 | ||||
| -rw-r--r-- | tests/test_write.cpp | 50 | ||||
| -rw-r--r-- | tests/test_xpath.cpp | 66 | ||||
| -rw-r--r-- | tests/test_xpath_api.cpp | 5 | ||||
| -rw-r--r-- | tests/test_xpath_functions.cpp | 15 | ||||
| -rw-r--r-- | tests/test_xpath_paths.cpp | 49 | ||||
| -rw-r--r-- | tests/test_xpath_variables.cpp | 26 | 
14 files changed, 419 insertions, 18 deletions
diff --git a/tests/gitsvn.sh b/tests/gitsvn.sh deleted file mode 100755 index 222a09f..0000000 --- a/tests/gitsvn.sh +++ /dev/null @@ -1,5 +0,0 @@ -#!/bin/sh - -git svn init https://pugixml.googlecode.com/svn/trunk -git update-ref refs/remotes/git-svn refs/remotes/origin/master -git svn rebase diff --git a/tests/main.cpp b/tests/main.cpp index 75b0108..c4c9341 100644 --- a/tests/main.cpp +++ b/tests/main.cpp @@ -20,6 +20,7 @@  test_runner* test_runner::_tests = 0;  size_t test_runner::_memory_fail_threshold = 0; +bool test_runner::_memory_fail_triggered = false;  jmp_buf test_runner::_failure_buffer;  const char* test_runner::_failure_message;  const char* test_runner::_temp_path; @@ -30,7 +31,11 @@ static size_t g_memory_total_count = 0;  static void* custom_allocate(size_t size)  {  	if (test_runner::_memory_fail_threshold > 0 && test_runner::_memory_fail_threshold < g_memory_total_size + size) +	{ +		test_runner::_memory_fail_triggered = true; +  		return 0; +	}  	else  	{  		void* ptr = memory_allocate(size); @@ -84,6 +89,7 @@ static bool run_test(test_runner* test)  		g_memory_total_size = 0;  		g_memory_total_count = 0;  		test_runner::_memory_fail_threshold = 0; +		test_runner::_memory_fail_triggered = false;  		pugi::set_memory_management_functions(custom_allocate, custom_deallocate); diff --git a/tests/test.hpp b/tests/test.hpp index 26260ad..509b0cd 100644 --- a/tests/test.hpp +++ b/tests/test.hpp @@ -23,6 +23,7 @@ struct test_runner  	static test_runner* _tests;  	static size_t _memory_fail_threshold; +	static bool _memory_fail_triggered;  	static jmp_buf _failure_buffer;  	static const char* _failure_message; diff --git a/tests/test_document.cpp b/tests/test_document.cpp index c75ed8f..2cc39a6 100644 --- a/tests/test_document.cpp +++ b/tests/test_document.cpp @@ -227,6 +227,34 @@ TEST(document_load_stream_nonseekable_large)      CHECK(doc.load(in));      CHECK_NODE(doc, str.c_str());  } + +TEST(document_load_stream_nonseekable_out_of_memory) +{ +    char contents[] = "<node />"; +    char_array_buffer<char> buffer(contents, contents + sizeof(contents) / sizeof(contents[0])); +    std::istream in(&buffer); + +    test_runner::_memory_fail_threshold = 1; + +    pugi::xml_document doc; +    CHECK(doc.load(in).status == status_out_of_memory); +} + +TEST(document_load_stream_nonseekable_out_of_memory_large) +{ +	std::basic_string<pugi::char_t> str; +	str += STR("<node>"); +	for (int i = 0; i < 10000; ++i) str += STR("<node />"); +	str += STR("</node>"); + +    char_array_buffer<pugi::char_t> buffer(&str[0], &str[0] + str.length()); +    std::basic_istream<pugi::char_t> in(&buffer); + +    test_runner::_memory_fail_threshold = 10000 * 8 * 3 / 2; + +    pugi::xml_document doc; +    CHECK(doc.load(in).status == status_out_of_memory); +}  #endif  TEST(document_load_string) @@ -295,6 +323,17 @@ TEST(document_load_file_wide_ascii)  	CHECK_NODE(doc, STR("<node />"));  } +TEST(document_load_file_wide_out_of_memory) +{ +	test_runner::_memory_fail_threshold = 1; + +	pugi::xml_document doc; + +	pugi::xml_parse_result result = doc.load_file(L"tests/data/small.xml"); + +	CHECK(result.status == status_out_of_memory || result.status == status_file_not_found); +} +  TEST_XML(document_save, "<node/>")  {  	xml_writer_string writer; @@ -1235,3 +1274,37 @@ TEST(document_alignment)  		doc->~xml_document();  	}  } + +TEST(document_convert_out_of_memory) +{ +	file_data_t files[] = +	{ +		{"tests/data/utftest_utf16_be_clean.xml", encoding_utf16_be, 0, 0}, +		{"tests/data/utftest_utf16_le_clean.xml", encoding_utf16_le, 0, 0}, +		{"tests/data/utftest_utf32_be_clean.xml", encoding_utf32_be, 0, 0}, +		{"tests/data/utftest_utf32_le_clean.xml", encoding_utf32_le, 0, 0}, +		{"tests/data/utftest_utf8_clean.xml", encoding_utf8, 0, 0}, +		{"tests/data/latintest_latin1.xml", encoding_latin1, 0, 0} +	}; + +	// load files in memory +	for (unsigned int i = 0; i < sizeof(files) / sizeof(files[0]); ++i) +	{ +		CHECK(load_file_in_memory(files[i].path, files[i].data, files[i].size)); +	} + +	// disallow allocations +	test_runner::_memory_fail_threshold = 1; + +	for (unsigned int src = 0; src < sizeof(files) / sizeof(files[0]); ++src) +	{ +		xml_document doc; +		CHECK(doc.load_buffer(files[src].data, files[src].size, parse_default, files[src].encoding).status == status_out_of_memory); +	} + +	// cleanup +	for (unsigned int j = 0; j < sizeof(files) / sizeof(files[0]); ++j) +	{ +		delete[] files[j].data; +	} +} diff --git a/tests/test_dom_modify.cpp b/tests/test_dom_modify.cpp index 612b017..07fe6dc 100644 --- a/tests/test_dom_modify.cpp +++ b/tests/test_dom_modify.cpp @@ -27,6 +27,16 @@ TEST_XML(dom_attr_assign, "<node/>")  	CHECK_NODE(node, STR("<node attr1=\"v1\" attr2=\"-2147483647\" attr3=\"-2147483648\" attr4=\"4294967295\" attr5=\"4294967294\" attr6=\"0.5\" attr7=\"true\" />"));  } +TEST_XML(dom_attr_set_name, "<node attr='value' />") +{ +	xml_attribute attr = doc.child(STR("node")).attribute(STR("attr")); + +	CHECK(attr.set_name(STR("n"))); +	CHECK(!xml_attribute().set_name(STR("n"))); + +	CHECK_NODE(doc, STR("<node n=\"value\" />")); +} +  TEST_XML(dom_attr_set_value, "<node/>")  {  	xml_node node = doc.child(STR("node")); @@ -758,8 +768,9 @@ TEST(dom_node_declaration_name)  	doc.insert_child_after(node_declaration, doc.first_child());  	doc.insert_child_before(node_declaration, doc.first_child()); +	doc.prepend_child(node_declaration); -	CHECK_NODE(doc, STR("<?xml?><?xml?><?xml?>")); +	CHECK_NODE(doc, STR("<?xml?><?xml?><?xml?><?xml?>"));  }  TEST(dom_node_declaration_attributes) @@ -867,17 +878,21 @@ TEST(dom_node_out_of_memory)  	// verify all node modification operations  	CHECK(!n.append_child()); +	CHECK(!n.prepend_child());  	CHECK(!n.insert_child_after(node_element, n.first_child()));  	CHECK(!n.insert_child_before(node_element, n.first_child()));  	CHECK(!n.append_attribute(STR(""))); +	CHECK(!n.prepend_attribute(STR("")));  	CHECK(!n.insert_attribute_after(STR(""), a));  	CHECK(!n.insert_attribute_before(STR(""), a));  	// verify node copy operations  	CHECK(!n.append_copy(n.first_child())); +	CHECK(!n.prepend_copy(n.first_child()));  	CHECK(!n.insert_copy_after(n.first_child(), n.first_child()));  	CHECK(!n.insert_copy_before(n.first_child(), n.first_child()));  	CHECK(!n.append_copy(a)); +	CHECK(!n.prepend_copy(a));  	CHECK(!n.insert_copy_after(a, a));  	CHECK(!n.insert_copy_before(a, a));  } @@ -1346,11 +1361,55 @@ TEST_XML(dom_node_copyless_taint, "<node attr=\"value\" />")  	CHECK_NODE(doc, STR("<nod1 attr=\"value\" /><node attr=\"valu2\" /><node att3=\"value\" />"));  } -TEST_XML(dom_node_copy_out_of_memory, "<node><child1 attr1='value1' attr2='value2' /><child2 /><child3>text1<child4 />text2</child3></node>") +TEST_XML(dom_node_copy_out_of_memory_node, "<node><child1 /><child2 /><child3>text1<child4 />text2</child3></node>")  {  	test_runner::_memory_fail_threshold = 32768 * 2 + 4096; -    xml_document copy; -    for (int i = 0; i < 100; ++i) -        copy.append_copy(doc.first_child()); +	xml_document copy; +	for (int i = 0; i < 1000; ++i) +		copy.append_copy(doc.first_child()); +} + +TEST_XML(dom_node_copy_out_of_memory_attr, "<node attr1='' attr2='' attr3='' attr4='' attr5='' attr6='' attr7='' attr8='' attr9='' attr10='' attr11='' attr12='' attr13='' attr14='' attr15='' />") +{ +	test_runner::_memory_fail_threshold = 32768 * 2 + 4096; + +	xml_document copy; +	for (int i = 0; i < 1000; ++i) +		copy.append_copy(doc.first_child()); +} + +TEST_XML(dom_node_remove_deallocate, "<node attr='value'>text</node>") +{ +	xml_node node = doc.child(STR("node")); + +	xml_attribute attr = node.attribute(STR("attr")); +	attr.set_name(STR("longattr")); +	attr.set_value(STR("longvalue")); + +	node.set_name(STR("longnode")); +	node.text().set(STR("longtext")); + +	node.remove_attribute(attr); +	doc.remove_child(node); + +	CHECK_NODE(doc, STR("")); +} + +TEST_XML(dom_node_set_deallocate, "<node attr='value'>text</node>") +{ +	xml_node node = doc.child(STR("node")); + +	xml_attribute attr = node.attribute(STR("attr")); + +	attr.set_name(STR("longattr")); +	attr.set_value(STR("longvalue")); +	node.set_name(STR("longnode")); + +	attr.set_name(STR("")); +	attr.set_value(STR("")); +	node.set_name(STR("")); +	node.text().set(STR("")); + +	CHECK_NODE(doc, STR("<:anonymous :anonymous=\"\"></:anonymous>"));  } diff --git a/tests/test_dom_traverse.cpp b/tests/test_dom_traverse.cpp index e42846f..83afec8 100644 --- a/tests/test_dom_traverse.cpp +++ b/tests/test_dom_traverse.cpp @@ -1048,14 +1048,14 @@ TEST_XML(dom_unspecified_bool_coverage, "<node attr='value'>text</node>")  {  	xml_node node = doc.first_child(); -	node(0); -	node.first_attribute()(0); -	node.text()(0); +	static_cast<void (*)(xml_node***)>(node)(0); +	static_cast<void (*)(xml_attribute***)>(node.first_attribute())(0); +	static_cast<void (*)(xml_text***)>(node.text())(0);  #ifndef PUGIXML_NO_XPATH  	xpath_query q(STR("/node")); -	q(0); -	q.evaluate_node(doc)(0); +	static_cast<void (*)(xpath_query***)>(q)(0); +	static_cast<void (*)(xpath_node***)>(q.evaluate_node(doc))(0);  #endif  } diff --git a/tests/test_parse.cpp b/tests/test_parse.cpp index 2094ef9..c45b783 100644 --- a/tests/test_parse.cpp +++ b/tests/test_parse.cpp @@ -876,7 +876,7 @@ TEST(parse_out_of_memory)  	CHECK(!doc.first_child());  } -TEST(parse_out_of_memory_halfway) +TEST(parse_out_of_memory_halfway_node)  {  	const unsigned int count = 10000;  	static char_t text[count * 4]; @@ -896,6 +896,35 @@ TEST(parse_out_of_memory_halfway)  	CHECK_NODE(doc.first_child(), STR("<n />"));  } +TEST(parse_out_of_memory_halfway_attr) +{ +	const unsigned int count = 10000; +	static char_t text[count * 5 + 4]; + +	text[0] = '<'; +	text[1] = 'n'; + +	for (unsigned int i = 0; i < count; ++i) +	{ +		text[5*i + 2] = ' '; +		text[5*i + 3] = 'a'; +		text[5*i + 4] = '='; +		text[5*i + 5] = '"'; +		text[5*i + 6] = '"'; +	} + +	text[5 * count + 2] = '/'; +	text[5 * count + 3] = '>'; + +	test_runner::_memory_fail_threshold = 65536; + +	xml_document doc; +	CHECK(doc.load_buffer_inplace(text, count * 5 + 4).status == status_out_of_memory); +	CHECK_STRING(doc.first_child().name(), STR("n")); +	CHECK_STRING(doc.first_child().first_attribute().name(), STR("a")); +	CHECK_STRING(doc.first_child().last_attribute().name(), STR("a")); +} +  static bool test_offset(const char_t* contents, unsigned int options, pugi::xml_parse_status status, ptrdiff_t offset)  {  	xml_document doc; @@ -1039,3 +1068,25 @@ TEST(parse_pcdata_gap_fragment)  	CHECK(doc.load(STR("a&b"), parse_fragment | parse_escapes));  	CHECK_STRING(doc.text().get(), STR("a&b"));  } + +TEST(parse_name_end_eof) +{ +	char_t test[] = STR("<node>"); + +	xml_document doc; +	CHECK(doc.load_buffer_inplace(test, 6 * sizeof(char_t)).status == status_end_element_mismatch); +	CHECK_STRING(doc.first_child().name(), STR("node")); +} + +TEST(parse_close_tag_eof) +{ +	char_t test1[] = STR("<node></node"); +	char_t test2[] = STR("<node></nodx"); + +	xml_document doc; +	CHECK(doc.load_buffer_inplace(test1, 12 * sizeof(char_t)).status == status_bad_end_element); +	CHECK_STRING(doc.first_child().name(), STR("node")); + +	CHECK(doc.load_buffer_inplace(test2, 12 * sizeof(char_t)).status == status_end_element_mismatch); +	CHECK_STRING(doc.first_child().name(), STR("node")); +} diff --git a/tests/test_parse_doctype.cpp b/tests/test_parse_doctype.cpp index 8976890..f8619fd 100644 --- a/tests/test_parse_doctype.cpp +++ b/tests/test_parse_doctype.cpp @@ -313,3 +313,12 @@ TEST(parse_doctype_error_toplevel)      CHECK(doc.load(STR("<node><!DOCTYPE></node>")).status == status_bad_doctype);      CHECK(doc.load(STR("<node><!DOCTYPE></node>"), parse_doctype).status == status_bad_doctype);  } + +TEST(parse_doctype_error_ignore) +{ +    xml_document doc; +	CHECK(doc.load(STR("<!DOCTYPE root [ <![IGNORE[ ")).status == status_bad_doctype); +	CHECK(doc.load(STR("<!DOCTYPE root [ <![IGNORE[ "), parse_doctype).status == status_bad_doctype); +	CHECK(doc.load(STR("<!DOCTYPE root [ <![IGNORE[ <![INCLUDE[")).status == status_bad_doctype); +	CHECK(doc.load(STR("<!DOCTYPE root [ <![IGNORE[ <![INCLUDE["), parse_doctype).status == status_bad_doctype); +} diff --git a/tests/test_write.cpp b/tests/test_write.cpp index 98650ac..8fc88e1 100644 --- a/tests/test_write.cpp +++ b/tests/test_write.cpp @@ -51,6 +51,15 @@ TEST_XML(write_cdata_inner, "<node><![CDATA[value]]></node>")  	CHECK_NODE_EX(doc, STR("<node><![CDATA[value]]></node>\n"), STR(""), 0);  } +TEST(write_cdata_null) +{ +	xml_document doc; +	doc.append_child(node_cdata); +	doc.append_child(STR("node")).append_child(node_cdata); + +	CHECK_NODE(doc, STR("<![CDATA[]]><node><![CDATA[]]></node>")); +} +  TEST_XML_FLAGS(write_comment, "<!--text-->", parse_comments | parse_fragment)  {  	CHECK_NODE(doc, STR("<!--text-->")); @@ -80,12 +89,32 @@ TEST(write_comment_invalid)  	CHECK_NODE(doc, STR("<!--- ->- -->"));  } +TEST(write_comment_null) +{ +	xml_document doc; +	doc.append_child(node_comment); + +	CHECK_NODE(doc, STR("<!---->")); +} +  TEST_XML_FLAGS(write_pi, "<?name value?>", parse_pi | parse_fragment)  {  	CHECK_NODE(doc, STR("<?name value?>"));  	CHECK_NODE_EX(doc, STR("<?name value?>\n"), STR(""), 0);  } +TEST(write_pi_null) +{ +	xml_document doc; +	xml_node node = doc.append_child(node_pi); + +	CHECK_NODE(doc, STR("<?:anonymous?>")); + +	node.set_value(STR("value")); + +	CHECK_NODE(doc, STR("<?:anonymous value?>")); +} +  TEST_XML_FLAGS(write_declaration, "<?xml version='2.0'?>", parse_declaration | parse_fragment)  {  	CHECK_NODE(doc, STR("<?xml version=\"2.0\"?>")); @@ -98,6 +127,14 @@ TEST_XML_FLAGS(write_doctype, "<!DOCTYPE id [ foo ]>", parse_doctype | parse_fra  	CHECK_NODE_EX(doc, STR("<!DOCTYPE id [ foo ]>\n"), STR(""), 0);  } +TEST(write_doctype_null) +{ +	xml_document doc; +	doc.append_child(node_doctype); + +	CHECK_NODE(doc, STR("<!DOCTYPE>")); +} +  TEST_XML(write_escape, "<node attr=''>text</node>")  {  	doc.child(STR("node")).attribute(STR("attr")) = STR("<>'\"&\x04\r\n\t"); @@ -460,3 +497,16 @@ TEST_XML(write_indent_custom, "<node attr='1'><child><sub>text</sub></child></no  	CHECK_NODE_EX(doc, STR("<node attr=\"1\">\nABCD<child>\nABCDABCD<sub>text</sub>\nABCD</child>\n</node>\n"), STR("ABCD"), format_indent);  	CHECK_NODE_EX(doc, STR("<node attr=\"1\">\nABCDE<child>\nABCDEABCDE<sub>text</sub>\nABCDE</child>\n</node>\n"), STR("ABCDE"), format_indent);  } + +TEST(write_pcdata_null) +{ +	xml_document doc; +	doc.append_child(STR("node")).append_child(node_pcdata); + +	CHECK_NODE(doc, STR("<node></node>")); +	CHECK_NODE_EX(doc, STR("<node></node>\n"), STR("\t"), format_indent); + +	doc.first_child().append_child(node_pcdata); + +	CHECK_NODE_EX(doc, STR("<node>\n\t\n\t\n</node>\n"), STR("\t"), format_indent); +} diff --git a/tests/test_xpath.cpp b/tests/test_xpath.cpp index 2143376..a65ee37 100644 --- a/tests/test_xpath.cpp +++ b/tests/test_xpath.cpp @@ -110,7 +110,7 @@ TEST_XML(xpath_sort_attributes, "<node/>")  	n.append_attribute(STR("attr3"));  	n.insert_attribute_before(STR("attr1"), n.attribute(STR("attr2"))); -	xpath_node_set ns = n.select_nodes(STR("@*")); +	xpath_node_set ns = n.select_nodes(STR("@* | @*"));  	ns.sort(true);  	xpath_node_set reverse_sorted = ns; @@ -122,6 +122,25 @@ TEST_XML(xpath_sort_attributes, "<node/>")  	xpath_node_set_tester(reverse_sorted, "reverse sorted order failed") % 5 % 4 % 3;  } +TEST_XML(xpath_sort_attributes_docorder, "<node attr1='' attr2='value' attr4='value' />") +{ +	xml_node n = doc.child(STR("node")); + +	n.first_attribute().set_name(STR("attribute1")); +	n.insert_attribute_after(STR("attr3"), n.attribute(STR("attr2"))); + +	xpath_node_set ns = n.select_nodes(STR("@* | @*")); + +	ns.sort(true); +	xpath_node_set reverse_sorted = ns; + +	ns.sort(false); +	xpath_node_set sorted = ns; + +	xpath_node_set_tester(sorted, "sorted order failed") % 3 % 4 % 5 % 6; +	xpath_node_set_tester(reverse_sorted, "reverse sorted order failed") % 6 % 5 % 4 % 3; +} +  TEST(xpath_sort_random_medium)  {  	xml_document doc; @@ -606,4 +625,49 @@ TEST(xpath_sort_crossdoc_different_depth)  	CHECK(ns.size() == 2);  	CHECK((ns[0] == ns1[0] && ns[1] == ns2[0]) || (ns[0] == ns2[0] && ns[1] == ns1[0]));  } + +TEST(xpath_allocate_string_out_of_memory) +{ +	std::basic_string<char_t> query; + +	for (int i = 0; i < 1024; ++i) query += STR("abcdefgh"); + +	test_runner::_memory_fail_threshold = 8*1024; + +#ifdef PUGIXML_NO_EXCEPTIONS +	CHECK(!xpath_query(query.c_str())); +#else +	try +	{ +		xpath_query q(query.c_str()); + +		CHECK_FORCE_FAIL("Expected out of memory exception"); +	} +	catch (const std::bad_alloc&) +	{ +	} +#endif +} + +TEST(xpath_remove_duplicates) +{ +	xml_document doc; + +	for (int i = 0; i < 20; ++i) +	{ +		doc.append_child(STR("node2")); +		doc.prepend_child(STR("node1")); +	} + +	xpath_node_set ns = doc.select_nodes(STR("/node2/preceding::* | //node1 | /node() | /* | /node1/following-sibling::*")); + +	ns.sort(); + +	{ +		xpath_node_set_tester tester(ns, "sorted order failed"); + +		for (int i = 0; i < 40; ++i) +			tester % (2 + i); +	} +}  #endif diff --git a/tests/test_xpath_api.cpp b/tests/test_xpath_api.cpp index 270f6aa..deb3beb 100644 --- a/tests/test_xpath_api.cpp +++ b/tests/test_xpath_api.cpp @@ -128,6 +128,11 @@ TEST_XML(xpath_api_nodeset_copy, "<node><foo/><foo/></node>")  	copy4 = copy1;  	CHECK(copy4.size() == 2);  	CHECK_STRING(copy4[0].node().name(), STR("foo")); + +	xpath_node_set copy5; +	copy5 = set; +	copy5 = xpath_node_set(); +	CHECK(copy5.size() == 0);  }  TEST(xpath_api_nodeset_copy_empty) diff --git a/tests/test_xpath_functions.cpp b/tests/test_xpath_functions.cpp index da820ef..678bc2e 100644 --- a/tests/test_xpath_functions.cpp +++ b/tests/test_xpath_functions.cpp @@ -216,7 +216,7 @@ TEST(xpath_boolean_false)  	CHECK_XPATH_FAIL(STR("false(1)"));  } -TEST_XML(xpath_boolean_lang, "<node xml:lang='en'><child xml:lang='zh-UK'><subchild/></child></node><foo><bar/></foo>") +TEST_XML(xpath_boolean_lang, "<node xml:lang='en'><child xml:lang='zh-UK'><subchild attr=''/></child></node><foo><bar/></foo>")  {  	xml_node c; @@ -244,6 +244,9 @@ TEST_XML(xpath_boolean_lang, "<node xml:lang='en'><child xml:lang='zh-UK'><subch  	CHECK_XPATH_BOOLEAN(doc.child(STR("node")).child(STR("child")), STR("lang('r')"), false);  	CHECK_XPATH_BOOLEAN(doc.child(STR("node")).child(STR("child")).child(STR("subchild")), STR("lang('en')"), false); +	// lang with 1 attribute argument +	CHECK_XPATH_NODESET(doc, STR("//@*[lang('en')]")); +  	// lang with 2 arguments  	CHECK_XPATH_FAIL(STR("lang(1, 2)"));  } @@ -773,6 +776,16 @@ TEST_XML_FLAGS(xpath_string_value, "<node><c1>pcdata</c1><c2><child/></c2><c3 at  	CHECK_XPATH_STRING(n, STR("string(c6/node())"), STR("cdata"));  } +TEST(xpath_string_value_empty) +{ +	xml_document doc; +	doc.append_child(node_pcdata).set_value(STR("head")); +	doc.append_child(node_pcdata); +	doc.append_child(node_pcdata).set_value(STR("tail")); + +	CHECK_XPATH_STRING(doc, STR("string()"), STR("headtail")); +} +  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")); diff --git a/tests/test_xpath_paths.cpp b/tests/test_xpath_paths.cpp index da8811d..df0dfa4 100644 --- a/tests/test_xpath_paths.cpp +++ b/tests/test_xpath_paths.cpp @@ -437,6 +437,52 @@ TEST_XML(xpath_paths_predicate_number, "<node><chapter/><chapter/><chapter/><cha  	CHECK_XPATH_NODESET(n, STR("preceding-sibling::chapter[2]")) % 3;  } +TEST_XML(xpath_paths_predicate_number_boundary, "<node><chapter/><chapter/><chapter/><chapter/><chapter/></node>") +{ +	CHECK_XPATH_NODESET(doc, STR("node/chapter[0.999999999999999]")); +	CHECK_XPATH_NODESET(doc, STR("node/chapter[1]")) % 3; +	CHECK_XPATH_NODESET(doc, STR("node/chapter[1.000000000000001]")); +	CHECK_XPATH_NODESET(doc, STR("node/chapter[1.999999999999999]")); +	CHECK_XPATH_NODESET(doc, STR("node/chapter[2]")) % 4; +	CHECK_XPATH_NODESET(doc, STR("node/chapter[2.000000000000001]")); +	CHECK_XPATH_NODESET(doc, STR("node/chapter[4.999999999999999]")); +	CHECK_XPATH_NODESET(doc, STR("node/chapter[5]")) % 7; +	CHECK_XPATH_NODESET(doc, STR("node/chapter[5.000000000000001]")); +} + +TEST_XML(xpath_paths_predicate_number_out_of_range, "<node><chapter/><chapter/><chapter/><chapter/><chapter/></node>") +{ +	xml_node n = doc.child(STR("node")).child(STR("chapter")).next_sibling().next_sibling(); + +	CHECK_XPATH_NODESET(n, STR("following-sibling::chapter[0]")); +	CHECK_XPATH_NODESET(n, STR("following-sibling::chapter[-1]")); +	CHECK_XPATH_NODESET(n, STR("following-sibling::chapter[-1000000000000]")); +	CHECK_XPATH_NODESET(n, STR("following-sibling::chapter[-1 div 0]")); +	CHECK_XPATH_NODESET(n, STR("following-sibling::chapter[1000000000000]")); +	CHECK_XPATH_NODESET(n, STR("following-sibling::chapter[1 div 0]")); +	CHECK_XPATH_NODESET(n, STR("following-sibling::chapter[0 div 0]")); +} + +TEST_XML(xpath_paths_predicate_constant_boolean, "<node><chapter/><chapter/><chapter/><chapter/><chapter/></node>") +{ +	xml_node n = doc.child(STR("node")).child(STR("chapter")).next_sibling().next_sibling(); + +	xpath_variable_set set; +	set.set(STR("true"), true); +	set.set(STR("false"), false); + +	CHECK_XPATH_NODESET_VAR(n, STR("following-sibling::chapter[$false]"), &set); +	CHECK_XPATH_NODESET_VAR(n, STR("following-sibling::chapter[$true]"), &set) % 6 % 7; +} + +TEST_XML(xpath_paths_predicate_position_eq, "<node><chapter/><chapter/><chapter>3</chapter><chapter/><chapter/></node>") +{ +	CHECK_XPATH_NODESET(doc, STR("node/chapter[position()=1]")) % 3; +	CHECK_XPATH_NODESET(doc, STR("node/chapter[position()=2+2]")) % 7; +	CHECK_XPATH_NODESET(doc, STR("node/chapter[position()=last()]")) % 8; +	CHECK_XPATH_NODESET(doc, STR("node/chapter[position()=string()]")) % 5; +} +  TEST_XML(xpath_paths_predicate_several, "<node><employee/><employee secretary=''/><employee assistant=''/><employee secretary='' assistant=''/><employee assistant='' secretary=''/></node>")  {  	xml_node n = doc.child(STR("node")); @@ -615,6 +661,9 @@ TEST_XML(xpath_paths_optimize_step_once, "<node><para1><para2/><para3/><para4><p      CHECK_XPATH_BOOLEAN(doc, STR("//@attr5/following::para6"), true);      CHECK_XPATH_STRING(doc, STR("name(//@attr5/following::para6)"), STR("para6")); + +    CHECK_XPATH_BOOLEAN(doc, STR("//para5/ancestor-or-self::*"), true); +    CHECK_XPATH_BOOLEAN(doc, STR("//para5/ancestor::*"), true);  }  TEST_XML(xpath_paths_null_nodeset_entries, "<node attr='value'/>") diff --git a/tests/test_xpath_variables.cpp b/tests/test_xpath_variables.cpp index 70bb4ea..53b40cf 100644 --- a/tests/test_xpath_variables.cpp +++ b/tests/test_xpath_variables.cpp @@ -88,6 +88,9 @@ TEST(xpath_variables_type_string)  	CHECK_DOUBLE_NAN(var->get_number());
  	CHECK_STRING(var->get_string(), STR("abc"));
  	CHECK(var->get_node_set().empty());
 +
 +	CHECK(var->set(STR("abcdef")));
 +	CHECK_STRING(var->get_string(), STR("abcdef"));
  }
  TEST_XML(xpath_variables_type_node_set, "<node/>")
 @@ -273,6 +276,29 @@ TEST(xpath_variables_long_name)  	CHECK_XPATH_BOOLEAN_VAR(xml_node(), STR("$abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"), &set, true);
  }
 +TEST(xpath_variables_long_name_out_of_memory)
 +{
 +	xpath_variable_set set;
 +	set.set(STR("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"), true);
 +
 +	test_runner::_memory_fail_threshold = 4096 + 64 + 52 * sizeof(char_t);
 +
 +#ifdef PUGIXML_NO_EXCEPTIONS
 +	xpath_query q(STR("$abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"), &set);
 +	CHECK(!q);
 +#else
 +	try
 +	{
 +		xpath_query q(STR("$abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"), &set);
 +
 +		CHECK_FORCE_FAIL("Expected exception");
 +	}
 +	catch (const xpath_exception&)
 +	{
 +	}
 +#endif
 +}
 +
  TEST_XML(xpath_variables_select, "<node attr='1'/><node attr='2'/>")
  {
  	xpath_variable_set set;
  | 
