diff options
| -rw-r--r-- | .travis.yml | 4 | ||||
| -rw-r--r-- | CMakeLists.txt | 4 | ||||
| -rw-r--r-- | src/pugixml.cpp | 77 | ||||
| -rw-r--r-- | tests/main.cpp | 2 | ||||
| -rw-r--r-- | tests/test_compact.cpp | 34 | ||||
| -rw-r--r-- | tests/test_document.cpp | 104 | ||||
| -rw-r--r-- | tests/test_write.cpp | 27 | ||||
| -rw-r--r-- | tests/test_xpath.cpp | 16 | ||||
| -rw-r--r-- | tests/test_xpath_functions.cpp | 2 | ||||
| -rw-r--r-- | tests/test_xpath_paths.cpp | 75 | ||||
| -rw-r--r-- | tests/test_xpath_variables.cpp | 31 | 
11 files changed, 326 insertions, 50 deletions
| diff --git a/.travis.yml b/.travis.yml index df5569c..f35124d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -14,4 +14,6 @@ script:    - make test cxxstd=c++11 defines=$DEFINES config=release -j2    - make test cxxstd=c++98 defines=$DEFINES config=debug -j2 -after_success: bash <(curl -s https://codecov.io/bash) -f pugixml.cpp.gcov +after_success: +  - sed -e "s/#####\(.*\)\(\/\/ unreachable.*\)/    1\1\2/" -i pugixml.cpp.gcov +  - bash <(curl -s https://codecov.io/bash) -f pugixml.cpp.gcov diff --git a/CMakeLists.txt b/CMakeLists.txt index 8a1169b..855045c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,6 +1,6 @@  project(pugixml) -cmake_minimum_required(VERSION 2.6) +cmake_minimum_required(VERSION 2.8.12)  option(BUILD_SHARED_LIBS "Build shared instead of static library" OFF)  option(BUILD_TESTS "Build tests" OFF) @@ -79,4 +79,4 @@ if(BUILD_TESTS)  	add_executable(check ${TEST_SOURCES})  	target_link_libraries(check pugixml)  	add_custom_command(TARGET check POST_BUILD COMMAND check WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}) -endif()
\ No newline at end of file +endif() diff --git a/src/pugixml.cpp b/src/pugixml.cpp index 56d7c75..4bc971b 100644 --- a/src/pugixml.cpp +++ b/src/pugixml.cpp @@ -127,6 +127,16 @@ using std::memset;  #	define PUGI__MSVC_CRT_VERSION _MSC_VER  #endif +// Not all platforms have snprintf; we define a wrapper that uses snprintf if possible. This only works with buffers with a known size. +#if __cplusplus >= 201103 +#	define PUGI__SNPRINTF(buf, ...) snprintf(buf, sizeof(buf), __VA_ARGS__) +#elif defined(_MSC_VER) && _MSC_VER >= 1400 +#	define PUGI__SNPRINTF(buf, ...) _snprintf_s(buf, sizeof(buf), _TRUNCATE, __VA_ARGS__) +#else +#	define PUGI__SNPRINTF sprintf +#endif + +// We put implementation details into an anonymous namespace in source mode, but have to keep it in non-anonymous namespace in header-only mode to prevent binary bloat.  #ifdef PUGIXML_HEADER_ONLY  #	define PUGI__NS_BEGIN namespace pugi { namespace impl {  #	define PUGI__NS_END } } @@ -353,7 +363,7 @@ PUGI__NS_BEGIN  				bucket = (bucket + probe + 1) & hashmod;  			} -			assert(false && "Hash table is full"); +			assert(false && "Hash table is full"); // unreachable  			return 0;  		} @@ -2144,7 +2154,7 @@ PUGI__NS_BEGIN  		if (encoding == encoding_latin1)  			return convert_buffer_generic(out_buffer, out_length, contents, size, latin1_decoder()); -		assert(false && "Invalid encoding"); +		assert(false && "Invalid encoding"); // unreachable  		return false;  	}  #else @@ -2249,7 +2259,7 @@ PUGI__NS_BEGIN  		if (encoding == encoding_latin1)  			return convert_buffer_latin1(out_buffer, out_length, contents, size, is_mutable); -		assert(false && "Invalid encoding"); +		assert(false && "Invalid encoding"); // unreachable  		return false;  	}  #endif @@ -2696,7 +2706,7 @@ PUGI__NS_BEGIN  		case 5: return strconv_pcdata_impl<opt_true, opt_false, opt_true>::parse;  		case 6: return strconv_pcdata_impl<opt_true, opt_true, opt_false>::parse;  		case 7: return strconv_pcdata_impl<opt_true, opt_true, opt_true>::parse; -		default: assert(false); return 0; // should not get here +		default: assert(false); return 0; // unreachable  		}  	} @@ -2873,7 +2883,7 @@ PUGI__NS_BEGIN  		case 13: return strconv_attribute_impl<opt_true>::parse_wnorm;  		case 14: return strconv_attribute_impl<opt_false>::parse_wnorm;  		case 15: return strconv_attribute_impl<opt_true>::parse_wnorm; -		default: assert(false); return 0; // should not get here +		default: assert(false); return 0; // unreachable  		}  	} @@ -3622,7 +3632,7 @@ PUGI__NS_BEGIN  		if (encoding == encoding_latin1)  			return convert_buffer_output_generic(r_u8, data, length, wchar_decoder(), latin1_writer()); -		assert(false && "Invalid encoding"); +		assert(false && "Invalid encoding"); // unreachable  		return 0;  	}  #else @@ -3661,7 +3671,7 @@ PUGI__NS_BEGIN  		if (encoding == encoding_latin1)  			return convert_buffer_output_generic(r_u8, data, length, utf8_decoder(), latin1_writer()); -		assert(false && "Invalid encoding"); +		assert(false && "Invalid encoding"); // unreachable  		return 0;  	}  #endif @@ -4188,7 +4198,7 @@ PUGI__NS_BEGIN  				break;  			default: -				assert(false && "Invalid node type"); +				assert(false && "Invalid node type"); // unreachable  		}  	} @@ -4632,7 +4642,7 @@ PUGI__NS_BEGIN  	PUGI__FN bool set_value_convert(String& dest, Header& header, uintptr_t header_mask, float value)  	{  		char buf[128]; -		sprintf(buf, "%.9g", value); +		PUGI__SNPRINTF(buf, "%.9g", value);  		return set_value_ascii(dest, header, header_mask, buf);  	} @@ -4641,7 +4651,7 @@ PUGI__NS_BEGIN  	PUGI__FN bool set_value_convert(String& dest, Header& header, uintptr_t header_mask, double value)  	{  		char buf[128]; -		sprintf(buf, "%.17g", value); +		PUGI__SNPRINTF(buf, "%.17g", value);  		return set_value_ascii(dest, header, header_mask, buf);  	} @@ -6290,7 +6300,7 @@ namespace pugi  			return _root->value && (_root->header & impl::xml_memory_page_value_allocated_or_shared_mask) == 0 ? _root->value - doc.buffer : -1;  		default: -			assert(false && "Invalid node type"); +			assert(false && "Invalid node type"); // unreachable  			return -1;  		}  	} @@ -7252,7 +7262,7 @@ PUGI__NS_BEGIN  		return middle;  	} -	template <typename T, typename Pred> void partition(T* begin, T* end, T pivot, const Pred& pred, T** out_eqbeg, T** out_eqend) +	template <typename T, typename Pred> void partition3(T* begin, T* end, T pivot, const Pred& pred, T** out_eqbeg, T** out_eqend)  	{  		// invariant: array is split into 4 groups: = < ? > (each variable denotes the boundary between the groups)  		T* eq = begin; @@ -7290,7 +7300,7 @@ PUGI__NS_BEGIN  			// partition in three chunks (< = >)  			I eqbeg, eqend; -			partition(begin, end, *median, pred, &eqbeg, &eqend); +			partition3(begin, end, *median, pred, &eqbeg, &eqend);  			// loop on larger half  			if (eqbeg - begin > end - eqend) @@ -7980,11 +7990,11 @@ PUGI__NS_BEGIN  	// gets mantissa digits in the form of 0.xxxxx with 0. implied and the exponent  #if defined(PUGI__MSVC_CRT_VERSION) && PUGI__MSVC_CRT_VERSION >= 1400 && !defined(_WIN32_WCE) -	PUGI__FN void convert_number_to_mantissa_exponent(double value, char* buffer, size_t buffer_size, char** out_mantissa, int* out_exponent) +	PUGI__FN void convert_number_to_mantissa_exponent(double value, char (&buffer)[32], char** out_mantissa, int* out_exponent)  	{  		// get base values  		int sign, exponent; -		_ecvt_s(buffer, buffer_size, value, DBL_DIG + 1, &exponent, &sign); +		_ecvt_s(buffer, sizeof(buffer), value, DBL_DIG + 1, &exponent, &sign);  		// truncate redundant zeros  		truncate_zeros(buffer, buffer + strlen(buffer)); @@ -7994,12 +8004,10 @@ PUGI__NS_BEGIN  		*out_exponent = exponent;  	}  #else -	PUGI__FN void convert_number_to_mantissa_exponent(double value, char* buffer, size_t buffer_size, char** out_mantissa, int* out_exponent) +	PUGI__FN void convert_number_to_mantissa_exponent(double value, char (&buffer)[32], char** out_mantissa, int* out_exponent)  	{  		// get a scientific notation value with IEEE DBL_DIG decimals -		sprintf(buffer, "%.*e", DBL_DIG, value); -		assert(strlen(buffer) < buffer_size); -		(void)!buffer_size; +		PUGI__SNPRINTF(buffer, "%.*e", DBL_DIG, value);  		// get the exponent (possibly negative)  		char* exponent_string = strchr(buffer, 'e'); @@ -8036,7 +8044,7 @@ PUGI__NS_BEGIN  		char* mantissa;  		int exponent; -		convert_number_to_mantissa_exponent(value, mantissa_buffer, sizeof(mantissa_buffer), &mantissa, &exponent); +		convert_number_to_mantissa_exponent(value, mantissa_buffer, &mantissa, &exponent);  		// allocate a buffer of suitable length for the number  		size_t result_size = strlen(mantissa_buffer) + (exponent > 0 ? exponent : -exponent) + 4; @@ -8498,7 +8506,7 @@ PUGI__NS_BEGIN  			break;  		default: -			assert(false && "Invalid variable type"); +			assert(false && "Invalid variable type"); // unreachable  		}  	} @@ -8519,7 +8527,7 @@ PUGI__NS_BEGIN  			return lhs->set(static_cast<const xpath_variable_boolean*>(rhs)->value);  		default: -			assert(false && "Invalid variable type"); +			assert(false && "Invalid variable type"); // unreachable  			return false;  		}  	} @@ -8606,7 +8614,7 @@ PUGI__NS_BEGIN  			return *min_element(begin, end, document_order_comparator());  		default: -			assert(false && "Invalid node set type"); +			assert(false && "Invalid node set type"); // unreachable  			return xpath_node();  		}  	} @@ -9336,7 +9344,7 @@ PUGI__NS_BEGIN  				}  			} -			assert(false && "Wrong types"); +			assert(false && "Wrong types"); // unreachable  			return false;  		} @@ -9411,7 +9419,7 @@ PUGI__NS_BEGIN  			}  			else  			{ -				assert(false && "Wrong types"); +				assert(false && "Wrong types"); // unreachable  				return false;  			}  		} @@ -9629,7 +9637,7 @@ PUGI__NS_BEGIN  				break;  			default: -				assert(false && "Unknown axis"); +				assert(false && "Unknown axis"); // unreachable  			}  			return false; @@ -9824,7 +9832,7 @@ PUGI__NS_BEGIN  			}  			default: -				assert(false && "Unimplemented axis"); +				assert(false && "Unimplemented axis"); // unreachable  			}  		} @@ -9905,7 +9913,7 @@ PUGI__NS_BEGIN  			}  			default: -				assert(false && "Unimplemented axis"); +				assert(false && "Unimplemented axis"); // unreachable  			}  		} @@ -10146,7 +10154,7 @@ PUGI__NS_BEGIN  				}  				default: -					assert(false && "Wrong expression for return type boolean"); +					assert(false && "Wrong expression for return type boolean"); // unreachable  					return false;  				}  			} @@ -10281,7 +10289,7 @@ PUGI__NS_BEGIN  				}  				default: -					assert(false && "Wrong expression for return type number"); +					assert(false && "Wrong expression for return type number"); // unreachable  					return 0;  				} @@ -10571,7 +10579,7 @@ PUGI__NS_BEGIN  				}  				default: -					assert(false && "Wrong expression for return type string"); +					assert(false && "Wrong expression for return type string"); // unreachable  					return xpath_string();  				}  			} @@ -10662,7 +10670,7 @@ PUGI__NS_BEGIN  					return step_do(c, stack, eval, axis_to_type<axis_self>());  				default: -					assert(false && "Unknown axis"); +					assert(false && "Unknown axis"); // unreachable  					return xpath_node_set_raw();  				}  			} @@ -10700,7 +10708,7 @@ PUGI__NS_BEGIN  			// fallthrough  			default: -				assert(false && "Wrong expression for return type node set"); +				assert(false && "Wrong expression for return type node set"); // unreachable  				return xpath_node_set_raw();  			}  		} @@ -12042,7 +12050,7 @@ namespace pugi  			return static_cast<const impl::xpath_variable_boolean*>(this)->name;  		default: -			assert(false && "Invalid variable type"); +			assert(false && "Invalid variable type"); // unreachable  			return 0;  		}  	} @@ -12593,6 +12601,7 @@ namespace pugi  #undef PUGI__DMC_VOLATILE  #undef PUGI__UNSIGNED_OVERFLOW  #undef PUGI__MSVC_CRT_VERSION +#undef PUGI__SNPRINTF  #undef PUGI__NS_BEGIN  #undef PUGI__NS_END  #undef PUGI__FN diff --git a/tests/main.cpp b/tests/main.cpp index 712edda..352b58b 100644 --- a/tests/main.cpp +++ b/tests/main.cpp @@ -41,7 +41,7 @@ static void* custom_allocate(size_t size)  	else  	{  		void* ptr = memory_allocate(size); -		assert(ptr); +		if (!ptr) return 0;  		g_memory_total_size += memory_size(ptr);  		g_memory_total_count++; diff --git a/tests/test_compact.cpp b/tests/test_compact.cpp index f9560c9..f5dc4ee 100644 --- a/tests/test_compact.cpp +++ b/tests/test_compact.cpp @@ -111,4 +111,38 @@ TEST_XML(compact_out_of_memory_remove, "<n a='v'/>")  	CHECK_ALLOC_FAIL(CHECK(!n.remove_attribute(a)));  	CHECK_ALLOC_FAIL(CHECK(!doc.remove_child(n)));  } + +TEST_XML(compact_pointer_attribute_list, "<n a='v'/>") +{ +	xml_node n = doc.child(STR("n")); +	xml_attribute a = n.attribute(STR("a")); + +	// make sure we fill the page with node x +	for (int i = 0; i < 1000; ++i) +		doc.append_child(STR("x")); + +	// this requires extended encoding for prev_attribute_c/next_attribute +	n.append_attribute(STR("b")); + +	// this requires extended encoding for first_attribute +	n.remove_attribute(a); + +	CHECK(!n.attribute(STR("a"))); +	CHECK(n.attribute(STR("b"))); +} + +TEST_XML(compact_pointer_node_list, "<n/>") +{ +	xml_node n = doc.child(STR("n")); + +	// make sure we fill the page with node x +	// this requires extended encoding for prev_sibling_c/next_sibling +	for (int i = 0; i < 1000; ++i) +		doc.append_child(STR("x")); + +	// this requires extended encoding for first_child +	n.append_child(STR("child")); + +	CHECK(n.child(STR("child"))); +}  #endif diff --git a/tests/test_document.cpp b/tests/test_document.cpp index 9860737..b702a07 100644 --- a/tests/test_document.cpp +++ b/tests/test_document.cpp @@ -109,12 +109,26 @@ TEST(document_load_stream_error)  	std::ifstream fs("filedoesnotexist");  	CHECK(doc.load(fs).status == status_io_error); +} + +TEST(document_load_stream_out_of_memory) +{ +	pugi::xml_document doc;  	std::istringstream iss("<node/>");  	test_runner::_memory_fail_threshold = 1;  	CHECK_ALLOC_FAIL(CHECK(doc.load(iss).status == status_out_of_memory));  } +TEST(document_load_stream_wide_out_of_memory) +{ +	pugi::xml_document doc; + +	std::basic_istringstream<wchar_t> iss(L"<node/>"); +	test_runner::_memory_fail_threshold = 1; +	CHECK_ALLOC_FAIL(CHECK(doc.load(iss).status == status_out_of_memory)); +} +  TEST(document_load_stream_empty)  {  	std::istringstream iss; @@ -186,11 +200,6 @@ public:      {          this->setg(begin, begin, end);      } - -    typename std::basic_streambuf<T>::int_type underflow() PUGIXML_OVERRIDE -    { -        return this->gptr() == this->egptr() ? std::basic_streambuf<T>::traits_type::eof() : std::basic_streambuf<T>::traits_type::to_int_type(*this->gptr()); -    }  };  TEST(document_load_stream_nonseekable) @@ -242,21 +251,77 @@ TEST(document_load_stream_nonseekable_out_of_memory)      CHECK_ALLOC_FAIL(CHECK(doc.load(in).status == status_out_of_memory));  } +TEST(document_load_stream_wide_nonseekable_out_of_memory) +{ +    wchar_t contents[] = L"<node />"; +    char_array_buffer<wchar_t> buffer(contents, contents + sizeof(contents) / sizeof(contents[0])); +    std::basic_istream<wchar_t> in(&buffer); + +    test_runner::_memory_fail_threshold = 1; + +    pugi::xml_document doc; +    CHECK_ALLOC_FAIL(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>"); +	std::basic_string<char> str; +	str += "<node>"; +	for (int i = 0; i < 10000; ++i) str += "<node />"; +	str += "</node>"; -    char_array_buffer<pugi::char_t> buffer(&str[0], &str[0] + str.length()); -    std::basic_istream<pugi::char_t> in(&buffer); +    char_array_buffer<char> buffer(&str[0], &str[0] + str.length()); +    std::basic_istream<char> in(&buffer);      test_runner::_memory_fail_threshold = 10000 * 8 * 3 / 2;      pugi::xml_document doc;      CHECK_ALLOC_FAIL(CHECK(doc.load(in).status == status_out_of_memory));  } + +TEST(document_load_stream_wide_nonseekable_out_of_memory_large) +{ +	std::basic_string<wchar_t> str; +	str += L"<node>"; +	for (int i = 0; i < 10000; ++i) str += L"<node />"; +	str += L"</node>"; + +    char_array_buffer<wchar_t> buffer(&str[0], &str[0] + str.length()); +    std::basic_istream<wchar_t> in(&buffer); + +    test_runner::_memory_fail_threshold = 10000 * 8 * 3 / 2; + +    pugi::xml_document doc; +    CHECK_ALLOC_FAIL(CHECK(doc.load(in).status == status_out_of_memory)); +} + +template <typename T> class seek_fail_buffer: public std::basic_streambuf<T> +{ +public: +	typename std::basic_streambuf<T>::pos_type seekoff(typename std::basic_streambuf<T>::off_type, std::ios_base::seekdir, std::ios_base::openmode) PUGIXML_OVERRIDE +	{ +		// pretend that our buffer is seekable (this is called by tellg); actual seeks will fail +		return 0; +	} +}; + +TEST(document_load_stream_seekable_fail_seek) +{ +    seek_fail_buffer<char> buffer; +    std::basic_istream<char> in(&buffer); + +    pugi::xml_document doc; +    CHECK(doc.load(in).status == status_io_error); +} + +TEST(document_load_stream_wide_seekable_fail_seek) +{ +    seek_fail_buffer<wchar_t> buffer; +    std::basic_istream<wchar_t> in(&buffer); + +    pugi::xml_document doc; +    CHECK(doc.load(in).status == status_io_error); +}  #endif  TEST(document_load_string) @@ -383,6 +448,23 @@ TEST(document_load_file_wide_out_of_memory)  	CHECK(result.status == status_out_of_memory || result.status == status_file_not_found);  } +#if defined(__linux__) || defined(__APPLE__) +TEST(document_load_file_special_folder) +{ +	xml_document doc; +	xml_parse_result result = doc.load_file("."); +	// status_out_of_memory is somewhat counter-intuitive but on Linux ftell returns LONG_MAX for directories +	CHECK(result.status == status_file_not_found || result.status == status_io_error || result.status == status_out_of_memory); +} + +TEST(document_load_file_special_device) +{ +	xml_document doc; +	xml_parse_result result = doc.load_file("/dev/tty"); +	CHECK(result.status == status_file_not_found || result.status == status_io_error); +} +#endif +  TEST_XML(document_save, "<node/>")  {  	xml_writer_string writer; diff --git a/tests/test_write.cpp b/tests/test_write.cpp index 5cd92a5..be77aa8 100644 --- a/tests/test_write.cpp +++ b/tests/test_write.cpp @@ -639,6 +639,33 @@ TEST_XML_FLAGS(write_roundtrip, "<node><child1 attr1='value1' attr2='value2'/><c  	}  } +TEST(write_flush_coverage) +{ +	xml_document doc; + +	// this creates a node that uses short sequences of lengths 1-6 for output +	xml_node n = doc.append_child(STR("n")); + +	xml_attribute a = n.append_attribute(STR("a")); + +	xml_attribute b = n.append_attribute(STR("b")); +	b.set_value(STR("<&\"")); + +	n.append_child(node_comment); + +	size_t basel = save_narrow(doc, format_raw, encoding_auto).size(); +	size_t bufl = 2048; + +	for (size_t l = 0; l <= basel; ++l) +	{ +		std::basic_string<pugi::char_t> pad(bufl - l, STR('v')); +		a.set_value(pad.c_str()); + +		std::string s = save_narrow(doc, format_raw, encoding_auto); +		CHECK(s.size() == basel + bufl - l); +	} +} +  #ifndef PUGIXML_NO_EXCEPTIONS  struct throwing_writer: pugi::xml_writer  { diff --git a/tests/test_xpath.cpp b/tests/test_xpath.cpp index 69513fc..3f5d084 100644 --- a/tests/test_xpath.cpp +++ b/tests/test_xpath.cpp @@ -407,6 +407,22 @@ TEST(xpath_out_of_memory_evaluate_concat)  	CHECK_ALLOC_FAIL(CHECK(q.evaluate_string(0, 0, xml_node()) == 1));  } +TEST(xpath_out_of_memory_evaluate_concat_list) +{ +	std::basic_string<char_t> query = STR("concat("); + +	for (size_t i = 0; i < 500; ++i) +		query += STR("\"\","); + +	query += STR("\"\")"); + +	pugi::xpath_query q(query.c_str()); + +	test_runner::_memory_fail_threshold = 1; + +	CHECK_ALLOC_FAIL(CHECK(q.evaluate_string(0, 0, xml_node()) == 1)); +} +  TEST(xpath_out_of_memory_evaluate_substring)  {  	test_runner::_memory_fail_threshold = 4196 * sizeof(char_t) + 4096 * 2; diff --git a/tests/test_xpath_functions.cpp b/tests/test_xpath_functions.cpp index 480eb97..604da78 100644 --- a/tests/test_xpath_functions.cpp +++ b/tests/test_xpath_functions.cpp @@ -809,7 +809,7 @@ TEST(xpath_unknown_functions)  		query[0] = ch;  		CHECK_XPATH_FAIL(query); -		query[0] = ch - 32; +		query[0] = char_t(ch - 32);  		CHECK_XPATH_FAIL(query);  	}  } diff --git a/tests/test_xpath_paths.cpp b/tests/test_xpath_paths.cpp index 7915df1..dd97019 100644 --- a/tests/test_xpath_paths.cpp +++ b/tests/test_xpath_paths.cpp @@ -703,4 +703,79 @@ TEST_XML(xpath_paths_null_nodeset_entries, "<node attr='value'/>")      CHECK(rs[0] == nodes[0]);      CHECK(rs[1] == nodes[2]);  } + +TEST_XML(xpath_paths_step_leaf_coverage, "<n><n1/><n2 a='v'><child/></n2><n3/></n>") +{ +	xml_node n = doc.child(STR("n")).child(STR("n2")); + +	CHECK_XPATH_NODESET(n, STR("ancestor::node()")) % 2 % 1; +	CHECK_XPATH_NODESET(n, STR("ancestor-or-self::node()")) % 4 % 2 % 1; +	CHECK_XPATH_NODESET(n, STR("attribute::node()")) % 5; +	CHECK_XPATH_NODESET(n, STR("child::node()")) % 6; +	CHECK_XPATH_NODESET(n, STR("descendant::node()")) % 6; +	CHECK_XPATH_NODESET(n, STR("descendant-or-self::node()")) % 4 % 6; +	CHECK_XPATH_NODESET(n, STR("following::node()")) % 7; +	CHECK_XPATH_NODESET(n, STR("following-sibling::node()")) % 7; +	CHECK_XPATH_NODESET(n, STR("namespace::node()")); +	CHECK_XPATH_NODESET(n, STR("parent::node()")) % 2; +	CHECK_XPATH_NODESET(n, STR("preceding::node()")) % 3; +	CHECK_XPATH_NODESET(n, STR("preceding-sibling::node()")) % 3; +	CHECK_XPATH_NODESET(n, STR("self::node()")) % 4; +} +TEST_XML(xpath_paths_step_leaf_predicate_coverage, "<n><n1/><n2 a='v'><child/></n2><n3/></n>") +{ +	xml_node n = doc.child(STR("n")).child(STR("n2")); + +	CHECK_XPATH_NODESET(n, STR("ancestor::node()[1]")) % 2; +	CHECK_XPATH_NODESET(n, STR("ancestor-or-self::node()[1]")) % 4; +	CHECK_XPATH_NODESET(n, STR("attribute::node()[1]")) % 5; +	CHECK_XPATH_NODESET(n, STR("child::node()[1]")) % 6; +	CHECK_XPATH_NODESET(n, STR("descendant::node()[1]")) % 6; +	CHECK_XPATH_NODESET(n, STR("descendant-or-self::node()[1]")) % 4; +	CHECK_XPATH_NODESET(n, STR("following::node()[1]")) % 7; +	CHECK_XPATH_NODESET(n, STR("following-sibling::node()[1]")) % 7; +	CHECK_XPATH_NODESET(n, STR("namespace::node()[1]")); +	CHECK_XPATH_NODESET(n, STR("parent::node()[1]")) % 2; +	CHECK_XPATH_NODESET(n, STR("preceding::node()[1]")) % 3; +	CHECK_XPATH_NODESET(n, STR("preceding-sibling::node()[1]")) % 3; +	CHECK_XPATH_NODESET(n, STR("self::node()[1]")) % 4; +} + +TEST_XML(xpath_paths_step_step_coverage, "<n><n1/><n2 a='v'><child/></n2><n3/></n>") +{ +	xml_node n = doc.child(STR("n")).child(STR("n2")); + +	CHECK_XPATH_NODESET(n, STR("./ancestor::node()")) % 2 % 1; +	CHECK_XPATH_NODESET(n, STR("./ancestor-or-self::node()")) % 4 % 2 % 1; +	CHECK_XPATH_NODESET(n, STR("./attribute::node()")) % 5; +	CHECK_XPATH_NODESET(n, STR("./child::node()")) % 6; +	CHECK_XPATH_NODESET(n, STR("./descendant::node()")) % 6; +	CHECK_XPATH_NODESET(n, STR("./descendant-or-self::node()")) % 4 % 6; +	CHECK_XPATH_NODESET(n, STR("./following::node()")) % 7; +	CHECK_XPATH_NODESET(n, STR("./following-sibling::node()")) % 7; +	CHECK_XPATH_NODESET(n, STR("./namespace::node()")); +	CHECK_XPATH_NODESET(n, STR("./parent::node()")) % 2; +	CHECK_XPATH_NODESET(n, STR("./preceding::node()")) % 3; +	CHECK_XPATH_NODESET(n, STR("./preceding-sibling::node()")) % 3; +	CHECK_XPATH_NODESET(n, STR("./self::node()")) % 4; +} + +TEST_XML(xpath_paths_step_step_predicate_coverage, "<n><n1/><n2 a='v'><child/></n2><n3/></n>") +{ +	xml_node n = doc.child(STR("n")).child(STR("n2")); + +	CHECK_XPATH_NODESET(n, STR("./ancestor::node()[1]")) % 2; +	CHECK_XPATH_NODESET(n, STR("./ancestor-or-self::node()[1]")) % 4; +	CHECK_XPATH_NODESET(n, STR("./attribute::node()[1]")) % 5; +	CHECK_XPATH_NODESET(n, STR("./child::node()[1]")) % 6; +	CHECK_XPATH_NODESET(n, STR("./descendant::node()[1]")) % 6; +	CHECK_XPATH_NODESET(n, STR("./descendant-or-self::node()[1]")) % 4; +	CHECK_XPATH_NODESET(n, STR("./following::node()[1]")) % 7; +	CHECK_XPATH_NODESET(n, STR("./following-sibling::node()[1]")) % 7; +	CHECK_XPATH_NODESET(n, STR("./namespace::node()[1]")); +	CHECK_XPATH_NODESET(n, STR("./parent::node()[1]")) % 2; +	CHECK_XPATH_NODESET(n, STR("./preceding::node()[1]")) % 3; +	CHECK_XPATH_NODESET(n, STR("./preceding-sibling::node()[1]")) % 3; +	CHECK_XPATH_NODESET(n, STR("./self::node()[1]")) % 4; +}  #endif diff --git a/tests/test_xpath_variables.cpp b/tests/test_xpath_variables.cpp index c64e0e6..9349004 100644 --- a/tests/test_xpath_variables.cpp +++ b/tests/test_xpath_variables.cpp @@ -302,7 +302,23 @@ TEST_XML(xpath_variables_select, "<node attr='1'/><node attr='2'/>")  TEST(xpath_variables_empty_name)  {  	xpath_variable_set set; +	CHECK(!set.add(STR(""), xpath_type_node_set));  	CHECK(!set.add(STR(""), xpath_type_number)); +	CHECK(!set.add(STR(""), xpath_type_string)); +	CHECK(!set.add(STR(""), xpath_type_boolean)); +} + +TEST(xpath_variables_long_name_out_of_memory_add) +{ +	std::basic_string<char_t> name(1000, 'a'); + +	test_runner::_memory_fail_threshold = 1000; + +	xpath_variable_set set; +	CHECK_ALLOC_FAIL(CHECK(!set.add(name.c_str(), xpath_type_node_set))); +	CHECK_ALLOC_FAIL(CHECK(!set.add(name.c_str(), xpath_type_number))); +	CHECK_ALLOC_FAIL(CHECK(!set.add(name.c_str(), xpath_type_string))); +	CHECK_ALLOC_FAIL(CHECK(!set.add(name.c_str(), xpath_type_boolean)));  }  TEST_XML(xpath_variables_inside_filter, "<node key='1' value='2'/><node key='2' value='1'/><node key='1' value='1'/>") @@ -591,4 +607,19 @@ TEST(xpath_variables_copy_big_out_of_memory)  		CHECK(!copy.get(name));  	}  } + +TEST(xpath_variables_copy_big_value_out_of_memory) +{ +	xpath_variable_set set; + +	std::basic_string<char_t> var(10000, 'a'); +	set.set(STR("x"), var.c_str()); + +	test_runner::_memory_fail_threshold = 15000; + +	xpath_variable_set copy; +	CHECK_ALLOC_FAIL(copy = set); + +	CHECK(!copy.get(STR("x"))); +}  #endif | 
