diff options
Diffstat (limited to 'tests')
-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 |
8 files changed, 278 insertions, 13 deletions
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 |