This commit is contained in:
Arseny Kapoulkine 2018-10-17 20:52:43 -07:00
parent 7d6901bff2
commit e61dbc5e88
38 changed files with 14694 additions and 13719 deletions

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,144 +1,146 @@
#include "allocator.hpp"
#include <string.h>
#include <assert.h>
#include <stdlib.h>
#include <string.h>
// Address sanitizer
#if defined(__has_feature)
# define ADDRESS_SANITIZER __has_feature(address_sanitizer)
#define ADDRESS_SANITIZER __has_feature(address_sanitizer)
#else
# if defined(__SANITIZE_ADDRESS__)
# define ADDRESS_SANITIZER 1
# else
# define ADDRESS_SANITIZER 0
# endif
#if defined(__SANITIZE_ADDRESS__)
#define ADDRESS_SANITIZER 1
#else
#define ADDRESS_SANITIZER 0
#endif
#endif
// Low-level allocation functions
#if defined(_WIN32) || defined(_WIN64)
# ifdef __MWERKS__
# pragma ANSI_strict off // disable ANSI strictness to include windows.h
# pragma cpp_extensions on // enable some extensions to include windows.h
# endif
#ifdef __MWERKS__
#pragma ANSI_strict off // disable ANSI strictness to include windows.h
#pragma cpp_extensions on // enable some extensions to include windows.h
#endif
# if defined(_MSC_VER)
# pragma warning(disable: 4201) // nonstandard extension used: nameless struct/union
# endif
#if defined(_MSC_VER)
#pragma warning(disable : 4201) // nonstandard extension used: nameless struct/union
#endif
# ifdef _XBOX_VER
# define NOD3D
# include <xtl.h>
# else
# include <windows.h>
# endif
#ifdef _XBOX_VER
#define NOD3D
#include <xtl.h>
#else
#include <windows.h>
#endif
namespace
{
const size_t page_size = 4096;
const size_t page_size = 4096;
size_t align_to_page(size_t value)
{
return (value + page_size - 1) & ~(page_size - 1);
}
void* allocate_page_aligned(size_t size)
{
// We can't use VirtualAlloc because it has 64Kb granularity so we run out of address space quickly
// We can't use malloc because of occasional problems with CW on CRT termination
static HANDLE heap = HeapCreate(0, 0, 0);
void* result = HeapAlloc(heap, 0, size + page_size);
return reinterpret_cast<void*>(align_to_page(reinterpret_cast<size_t>(result)));
}
void* allocate(size_t size)
{
size_t aligned_size = align_to_page(size);
void* ptr = allocate_page_aligned(aligned_size + page_size);
if (!ptr) return 0;
char* end = static_cast<char*>(ptr) + aligned_size;
DWORD old_flags;
VirtualProtect(end, page_size, PAGE_NOACCESS, &old_flags);
return end - size;
}
void deallocate(void* ptr, size_t size)
{
size_t aligned_size = align_to_page(size);
void* rptr = static_cast<char*>(ptr) + size - aligned_size;
DWORD old_flags;
VirtualProtect(rptr, aligned_size + page_size, PAGE_NOACCESS, &old_flags);
}
size_t align_to_page(size_t value)
{
return (value + page_size - 1) & ~(page_size - 1);
}
void* allocate_page_aligned(size_t size)
{
// We can't use VirtualAlloc because it has 64Kb granularity so we run out of address space quickly
// We can't use malloc because of occasional problems with CW on CRT termination
static HANDLE heap = HeapCreate(0, 0, 0);
void* result = HeapAlloc(heap, 0, size + page_size);
return reinterpret_cast<void*>(align_to_page(reinterpret_cast<size_t>(result)));
}
void* allocate(size_t size)
{
size_t aligned_size = align_to_page(size);
void* ptr = allocate_page_aligned(aligned_size + page_size);
if (!ptr)
return 0;
char* end = static_cast<char*>(ptr) + aligned_size;
DWORD old_flags;
VirtualProtect(end, page_size, PAGE_NOACCESS, &old_flags);
return end - size;
}
void deallocate(void* ptr, size_t size)
{
size_t aligned_size = align_to_page(size);
void* rptr = static_cast<char*>(ptr) + size - aligned_size;
DWORD old_flags;
VirtualProtect(rptr, aligned_size + page_size, PAGE_NOACCESS, &old_flags);
}
} // namespace
#elif (defined(__APPLE__) || defined(__linux__)) && (defined(__i386) || defined(__x86_64)) && !ADDRESS_SANITIZER
# include <sys/mman.h>
#include <sys/mman.h>
namespace
{
const size_t page_size = 4096;
const size_t page_size = 4096;
size_t align_to_page(size_t value)
{
return (value + page_size - 1) & ~(page_size - 1);
}
void* allocate_page_aligned(size_t size)
{
void* result = malloc(size + page_size);
return reinterpret_cast<void*>(align_to_page(reinterpret_cast<size_t>(result)));
}
void* allocate(size_t size)
{
size_t aligned_size = align_to_page(size);
void* ptr = allocate_page_aligned(aligned_size + page_size);
if (!ptr) return 0;
char* end = static_cast<char*>(ptr) + aligned_size;
int res = mprotect(end, page_size, PROT_NONE);
assert(res == 0);
(void)!res;
return end - size;
}
void deallocate(void* ptr, size_t size)
{
size_t aligned_size = align_to_page(size);
void* rptr = static_cast<char*>(ptr) + size - aligned_size;
int res = mprotect(rptr, aligned_size + page_size, PROT_NONE);
assert(res == 0);
(void)!res;
}
size_t align_to_page(size_t value)
{
return (value + page_size - 1) & ~(page_size - 1);
}
void* allocate_page_aligned(size_t size)
{
void* result = malloc(size + page_size);
return reinterpret_cast<void*>(align_to_page(reinterpret_cast<size_t>(result)));
}
void* allocate(size_t size)
{
size_t aligned_size = align_to_page(size);
void* ptr = allocate_page_aligned(aligned_size + page_size);
if (!ptr)
return 0;
char* end = static_cast<char*>(ptr) + aligned_size;
int res = mprotect(end, page_size, PROT_NONE);
assert(res == 0);
(void)!res;
return end - size;
}
void deallocate(void* ptr, size_t size)
{
size_t aligned_size = align_to_page(size);
void* rptr = static_cast<char*>(ptr) + size - aligned_size;
int res = mprotect(rptr, aligned_size + page_size, PROT_NONE);
assert(res == 0);
(void)!res;
}
} // namespace
#else
namespace
{
void* allocate(size_t size)
{
return malloc(size);
}
void deallocate(void* ptr, size_t size)
{
(void)size;
free(ptr);
}
void* allocate(size_t size)
{
return malloc(size);
}
void deallocate(void* ptr, size_t size)
{
(void)size;
free(ptr);
}
} // namespace
#endif
// High-level allocation functions
@ -147,7 +149,8 @@ const size_t memory_alignment = sizeof(double) > sizeof(void*) ? sizeof(double)
void* memory_allocate(size_t size)
{
void* result = allocate(size + memory_alignment);
if (!result) return 0;
if (!result)
return 0;
memcpy(result, &size, sizeof(size_t));
@ -166,10 +169,10 @@ size_t memory_size(void* ptr)
void memory_deallocate(void* ptr)
{
if (!ptr) return;
if (!ptr)
return;
size_t size = memory_size(ptr);
deallocate(static_cast<char*>(ptr) - memory_alignment, size + memory_alignment);
}

View File

@ -2,9 +2,9 @@
#include <stdint.h>
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size)
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* Data, size_t Size)
{
pugi::xml_document doc;
pugi::xml_document doc;
doc.load_buffer(Data, Size);
doc.load_buffer(Data, Size, pugi::parse_minimal);

View File

@ -3,7 +3,7 @@
#include <stdint.h>
#include <string.h>
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size)
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* Data, size_t Size)
{
char* text = new char[Size + 1];
memcpy(text, Data, Size);

View File

@ -5,7 +5,8 @@
#include <utility>
template <typename T> static void generic_bool_ops_test(const T& obj)
template <typename T>
static void generic_bool_ops_test(const T& obj)
{
T null;
@ -14,14 +15,14 @@ template <typename T> static void generic_bool_ops_test(const T& obj)
CHECK(!!obj);
#ifdef _MSC_VER
# pragma warning(push)
# pragma warning(disable: 4800) // forcing value to bool 'true' or 'false' (performance warning) - we really want to just cast to bool instead of !!
#pragma warning(push)
#pragma warning(disable : 4800) // forcing value to bool 'true' or 'false' (performance warning) - we really want to just cast to bool instead of !!
#endif
bool b1 = null, b2 = obj;
#ifdef _MSC_VER
# pragma warning(pop)
#pragma warning(pop)
#endif
CHECK(!b1);
@ -33,7 +34,8 @@ template <typename T> static void generic_bool_ops_test(const T& obj)
CHECK(obj || obj);
}
template <typename T> static void generic_eq_ops_test(const T& obj1, const T& obj2)
template <typename T>
static void generic_eq_ops_test(const T& obj1, const T& obj2)
{
T null = T();
@ -54,7 +56,8 @@ template <typename T> static void generic_eq_ops_test(const T& obj1, const T& ob
CHECK(!(T(obj1) != obj1));
}
template <typename T> static void generic_rel_ops_test(T obj1, T obj2)
template <typename T>
static void generic_rel_ops_test(T obj1, T obj2)
{
T null = T();
@ -103,7 +106,8 @@ template <typename T> static void generic_rel_ops_test(T obj1, T obj2)
CHECK(!(obj1 >= obj2));
}
template <typename T> static void generic_empty_test(const T& obj)
template <typename T>
static void generic_empty_test(const T& obj)
{
T null;

View File

@ -1,21 +1,21 @@
#include "test.hpp"
#include "allocator.hpp"
#include "test.hpp"
#include <assert.h>
#include <float.h>
#include <stdio.h>
#include <stdlib.h>
#include <float.h>
#include <assert.h>
#include <string>
#ifndef PUGIXML_NO_EXCEPTIONS
# include <exception>
#include <exception>
#endif
#ifdef _WIN32_WCE
# undef DebugBreak
# pragma warning(disable: 4201) // nonstandard extension used: nameless struct/union
# include <windows.h>
#undef DebugBreak
#pragma warning(disable : 4201) // nonstandard extension used: nameless struct/union
#include <windows.h>
#endif
test_runner* test_runner::_tests = 0;
@ -41,7 +41,8 @@ static void* custom_allocate(size_t size)
else
{
void* ptr = memory_allocate(size);
if (!ptr) return 0;
if (!ptr)
return 0;
g_memory_total_size += memory_size(ptr);
g_memory_total_count++;
@ -89,9 +90,9 @@ static void replace_memory_management()
namespace std
{
_CRTIMP2 _Prhand _Raise_handler;
_CRTIMP2 void __cdecl _Throw(const exception&) {}
}
_CRTIMP2 _Prhand _Raise_handler;
_CRTIMP2 void __cdecl _Throw(const exception&) {}
} // namespace std
#endif
static bool run_test(test_runner* test, const char* test_name, pugi::allocation_function allocate)
@ -109,15 +110,15 @@ static bool run_test(test_runner* test, const char* test_name, pugi::allocation_
pugi::set_memory_management_functions(allocate, custom_deallocate);
#ifdef _MSC_VER
# pragma warning(push)
# pragma warning(disable: 4611) // interaction between _setjmp and C++ object destruction is non-portable
# pragma warning(disable: 4793) // function compiled as native: presence of '_setjmp' makes a function unmanaged
#pragma warning(push)
#pragma warning(disable : 4611) // interaction between _setjmp and C++ object destruction is non-portable
#pragma warning(disable : 4793) // function compiled as native: presence of '_setjmp' makes a function unmanaged
#endif
volatile int result = setjmp(test_runner::_failure_buffer);
#ifdef _MSC_VER
# pragma warning(pop)
#pragma warning(pop)
#endif
if (result)
@ -193,10 +194,10 @@ int main(int, char** argv)
if (g_memory_fail_triggered)
{
// run tests that trigger memory failures twice - with an allocator that returns NULL and with an allocator that throws
#ifndef PUGIXML_NO_EXCEPTIONS
#ifndef PUGIXML_NO_EXCEPTIONS
total++;
passed += run_test(test, (test->_name + std::string(" (throw)")).c_str(), custom_allocate_throw);
#endif
#endif
}
}

View File

@ -5,8 +5,8 @@
#include "writer_string.hpp"
#include <math.h>
#include <float.h>
#include <math.h>
#include <string.h>
#include <wchar.h>
@ -33,10 +33,12 @@ static void build_document_order(std::vector<pugi::xpath_node>& result, pugi::xm
cur = cur.next_sibling();
else
{
while (cur && !cur.next_sibling()) cur = cur.parent();
while (cur && !cur.next_sibling())
cur = cur.parent();
cur = cur.next_sibling();
if (!cur) break;
if (!cur)
break;
}
}
}
@ -45,11 +47,11 @@ static void build_document_order(std::vector<pugi::xpath_node>& result, pugi::xm
bool test_string_equal(const pugi::char_t* lhs, const pugi::char_t* rhs)
{
return (!lhs || !rhs) ? lhs == rhs :
#ifdef PUGIXML_WCHAR_MODE
wcscmp(lhs, rhs) == 0;
#else
strcmp(lhs, rhs) == 0;
#endif
#ifdef PUGIXML_WCHAR_MODE
wcscmp(lhs, rhs) == 0;
#else
strcmp(lhs, rhs) == 0;
#endif
}
bool test_node(const pugi::xml_node& node, const pugi::char_t* contents, const pugi::char_t* indent, unsigned int flags)
@ -83,7 +85,8 @@ static size_t strlength(const pugi::char_t* s)
bool test_xpath_string(const pugi::xpath_node& node, const pugi::char_t* query, pugi::xpath_variable_set* variables, const pugi::char_t* expected)
{
pugi::xpath_query q(query, variables);
if (!q) return false;
if (!q)
return false;
const size_t capacity = 64;
pugi::char_t result[capacity];
@ -104,7 +107,8 @@ bool test_xpath_string(const pugi::xpath_node& node, const pugi::char_t* query,
bool test_xpath_boolean(const pugi::xpath_node& node, const pugi::char_t* query, pugi::xpath_variable_set* variables, bool expected)
{
pugi::xpath_query q(query, variables);
if (!q) return false;
if (!q)
return false;
return q.evaluate_boolean(node) == expected;
}
@ -112,7 +116,8 @@ bool test_xpath_boolean(const pugi::xpath_node& node, const pugi::char_t* query,
bool test_xpath_number(const pugi::xpath_node& node, const pugi::char_t* query, pugi::xpath_variable_set* variables, double expected)
{
pugi::xpath_query q(query, variables);
if (!q) return false;
if (!q)
return false;
double value = q.evaluate_number(node);
double absolute_error = fabs(value - expected);
@ -124,7 +129,8 @@ bool test_xpath_number(const pugi::xpath_node& node, const pugi::char_t* query,
bool test_xpath_number_nan(const pugi::xpath_node& node, const pugi::char_t* query, pugi::xpath_variable_set* variables)
{
pugi::xpath_query q(query, variables);
if (!q) return false;
if (!q)
return false;
return test_double_nan(q.evaluate_number(node));
}
@ -155,12 +161,15 @@ void xpath_node_set_tester::check(bool condition)
}
}
xpath_node_set_tester::xpath_node_set_tester(const pugi::xpath_node_set& set, const char* message_): last(0), message(message_)
xpath_node_set_tester::xpath_node_set_tester(const pugi::xpath_node_set& set, const char* message_)
: last(0)
, message(message_)
{
result = set;
// only sort unsorted sets so that we're able to verify reverse order for some axes
if (result.type() == pugi::xpath_node_set::type_unsorted) result.sort();
if (result.type() == pugi::xpath_node_set::type_unsorted)
result.sort();
if (result.empty())
{

View File

@ -36,7 +36,8 @@ struct test_runner
bool test_string_equal(const pugi::char_t* lhs, const pugi::char_t* rhs);
template <typename Node> inline bool test_node_name_value(const Node& node, const pugi::char_t* name, const pugi::char_t* value)
template <typename Node>
inline bool test_node_name_value(const Node& node, const pugi::char_t* name, const pugi::char_t* value)
{
return test_string_equal(node.name(), name) && test_string_equal(node.value(), value);
}
@ -71,17 +72,22 @@ struct xpath_node_set_tester
#endif
struct dummy_fixture {};
struct dummy_fixture
{
};
#define TEST_FIXTURE(name, fixture) \
struct test_runner_helper_##name: fixture \
struct test_runner_helper_##name : fixture \
{ \
void run(); \
}; \
static struct test_runner_##name: test_runner \
static struct test_runner_##name : test_runner \
{ \
test_runner_##name(): test_runner(#name) {} \
\
test_runner_##name() \
: test_runner(#name) \
{ \
} \
\
virtual void run() PUGIXML_OVERRIDE \
{ \
test_runner_helper_##name helper; \
@ -96,30 +102,34 @@ struct dummy_fixture {};
struct test_fixture_##name \
{ \
pugi::xml_document doc; \
\
\
test_fixture_##name() \
{ \
CHECK(doc.load_string(PUGIXML_TEXT(xml), flags)); \
} \
\
private: \
\
private: \
test_fixture_##name(const test_fixture_##name&); \
test_fixture_##name& operator=(const test_fixture_##name&); \
}; \
\
\
TEST_FIXTURE(name, test_fixture_##name)
#define TEST_XML(name, xml) TEST_XML_FLAGS(name, xml, pugi::parse_default)
#define CHECK_JOIN(text, file, line) text " at " file ":" #line
#define CHECK_JOIN2(text, file, line) CHECK_JOIN(text, file, line)
#define CHECK_TEXT(condition, text) if (condition) ; else test_runner::_failure_message = CHECK_JOIN2(text, __FILE__, __LINE__), longjmp(test_runner::_failure_buffer, 1)
#define CHECK_TEXT(condition, text) \
if (condition) \
; \
else \
test_runner::_failure_message = CHECK_JOIN2(text, __FILE__, __LINE__), longjmp(test_runner::_failure_buffer, 1)
#define CHECK_FORCE_FAIL(text) test_runner::_failure_message = CHECK_JOIN2(text, __FILE__, __LINE__), longjmp(test_runner::_failure_buffer, 1)
#if (defined(_MSC_VER) && _MSC_VER == 1200) || defined(__MWERKS__) || (defined(__BORLANDC__) && __BORLANDC__ <= 0x540)
# define STRINGIZE(value) "??" // Some compilers have issues with stringizing expressions that contain strings w/escaping inside
#define STRINGIZE(value) "??" // Some compilers have issues with stringizing expressions that contain strings w/escaping inside
#else
# define STRINGIZE(value) #value
#define STRINGIZE(value) #value
#endif
#define CHECK(condition) CHECK_TEXT(condition, STRINGIZE(condition) " is false")
@ -147,9 +157,29 @@ struct dummy_fixture {};
#endif
#ifdef PUGIXML_NO_EXCEPTIONS
#define CHECK_ALLOC_FAIL(code) do { CHECK(!test_runner::_memory_fail_triggered); code; CHECK(test_runner::_memory_fail_triggered); test_runner::_memory_fail_triggered = false; } while (test_runner::_memory_fail_triggered)
#define CHECK_ALLOC_FAIL(code) \
do \
{ \
CHECK(!test_runner::_memory_fail_triggered); \
code; \
CHECK(test_runner::_memory_fail_triggered); \
test_runner::_memory_fail_triggered = false; \
} while (test_runner::_memory_fail_triggered)
#else
#define CHECK_ALLOC_FAIL(code) do { CHECK(!test_runner::_memory_fail_triggered); try { code; } catch (std::bad_alloc&) {} CHECK(test_runner::_memory_fail_triggered); test_runner::_memory_fail_triggered = false; } while (test_runner::_memory_fail_triggered)
#define CHECK_ALLOC_FAIL(code) \
do \
{ \
CHECK(!test_runner::_memory_fail_triggered); \
try \
{ \
code; \
} \
catch (std::bad_alloc&) \
{ \
} \
CHECK(test_runner::_memory_fail_triggered); \
test_runner::_memory_fail_triggered = false; \
} while (test_runner::_memory_fail_triggered)
#endif
#define STR(text) PUGIXML_TEXT(text)
@ -161,7 +191,7 @@ struct dummy_fixture {};
#if (defined(_MSC_VER) && _MSC_VER == 1200) || (defined(__INTEL_COMPILER) && __INTEL_COMPILER == 800) || defined(__BORLANDC__)
// NaN comparison on MSVC6 is incorrect, see http://www.nabble.com/assertDoubleEquals,-NaN---Microsoft-Visual-Studio-6-td9137859.html
// IC8 and BCC are also affected by the same bug
# define MSVC6_NAN_BUG
#define MSVC6_NAN_BUG
#endif
inline wchar_t wchar_cast(unsigned int value)

View File

@ -15,19 +15,19 @@
#include <fstream>
#include <sstream>
#include <string>
#include <algorithm>
#include <string>
#ifndef PUGIXML_NO_EXCEPTIONS
# include <stdexcept>
#include <stdexcept>
#endif
#ifdef __MINGW32__
# include <io.h> // for unlink in C++0x mode
#include <io.h> // for unlink in C++0x mode
#endif
#if defined(__CELLOS_LV2__) || defined(ANDROID) || defined(_GLIBCXX_HAVE_UNISTD_H) || defined(__APPLE__)
# include <unistd.h> // for unlink
#include <unistd.h> // for unlink
#endif
using namespace pugi;
@ -35,7 +35,8 @@ using namespace pugi;
static bool load_file_in_memory(const char* path, char*& data, size_t& size)
{
FILE* file = fopen(path, "rb");
if (!file) return false;
if (!file)
return false;
fseek(file, 0, SEEK_END);
long length = ftell(file);
@ -53,15 +54,16 @@ static bool load_file_in_memory(const char* path, char*& data, size_t& size)
static bool test_file_contents(const char* path, const char* data, size_t size)
{
char* fdata;
size_t fsize;
if (!load_file_in_memory(path, fdata, fsize)) return false;
char* fdata;
size_t fsize;
if (!load_file_in_memory(path, fdata, fsize))
return false;
bool result = (size == fsize && memcmp(data, fdata, size) == 0);
bool result = (size == fsize && memcmp(data, fdata, size) == 0);
delete[] fdata;
delete[] fdata;
return result;
return result;
}
TEST(document_create_empty)
@ -199,114 +201,120 @@ TEST(document_load_stream_wide_error_previous)
CHECK(!doc.first_child());
}
template <typename T> class char_array_buffer: public std::basic_streambuf<T>
template <typename T>
class char_array_buffer : public std::basic_streambuf<T>
{
public:
char_array_buffer(T* begin, T* end)
{
this->setg(begin, begin, end);
}
public:
char_array_buffer(T* begin, T* end)
{
this->setg(begin, begin, end);
}
};
TEST(document_load_stream_nonseekable)
{
char contents[] = "<node />";
char_array_buffer<char> buffer(contents, contents + sizeof(contents) / sizeof(contents[0]));
std::istream in(&buffer);
char contents[] = "<node />";
char_array_buffer<char> buffer(contents, contents + sizeof(contents) / sizeof(contents[0]));
std::istream in(&buffer);
xml_document doc;
CHECK(doc.load(in));
CHECK_NODE(doc, STR("<node/>"));
xml_document doc;
CHECK(doc.load(in));
CHECK_NODE(doc, STR("<node/>"));
}
TEST(document_load_stream_wide_nonseekable)
{
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);
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);
xml_document doc;
CHECK(doc.load(in));
CHECK_NODE(doc, STR("<node/>"));
xml_document doc;
CHECK(doc.load(in));
CHECK_NODE(doc, STR("<node/>"));
}
TEST(document_load_stream_nonseekable_large)
{
std::basic_string<char_t> str;
str += STR("<node>");
for (int i = 0; i < 10000; ++i) str += STR("<node/>");
for (int i = 0; i < 10000; ++i)
str += STR("<node/>");
str += STR("</node>");
char_array_buffer<char_t> buffer(&str[0], &str[0] + str.length());
std::basic_istream<char_t> in(&buffer);
char_array_buffer<char_t> buffer(&str[0], &str[0] + str.length());
std::basic_istream<char_t> in(&buffer);
xml_document doc;
CHECK(doc.load(in));
CHECK_NODE(doc, str.c_str());
xml_document doc;
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);
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;
test_runner::_memory_fail_threshold = 1;
xml_document doc;
CHECK_ALLOC_FAIL(CHECK(doc.load(in).status == status_out_of_memory));
xml_document doc;
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);
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;
test_runner::_memory_fail_threshold = 1;
xml_document doc;
CHECK_ALLOC_FAIL(CHECK(doc.load(in).status == status_out_of_memory));
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<char> str;
str += "<node>";
for (int i = 0; i < 10000; ++i) str += "<node />";
for (int i = 0; i < 10000; ++i)
str += "<node />";
str += "</node>";
char_array_buffer<char> buffer(&str[0], &str[0] + str.length());
std::basic_istream<char> in(&buffer);
char_array_buffer<char> buffer(&str[0], &str[0] + str.length());
std::basic_istream<char> in(&buffer);
test_runner::_memory_fail_threshold = 32768 * 3 + 4096;
test_runner::_memory_fail_threshold = 32768 * 3 + 4096;
xml_document doc;
CHECK_ALLOC_FAIL(CHECK(doc.load(in).status == status_out_of_memory));
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 />";
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);
char_array_buffer<wchar_t> buffer(&str[0], &str[0] + str.length());
std::basic_istream<wchar_t> in(&buffer);
test_runner::_memory_fail_threshold = 32768 * 3 * sizeof(wchar_t) + 4096;
test_runner::_memory_fail_threshold = 32768 * 3 * sizeof(wchar_t) + 4096;
xml_document doc;
CHECK_ALLOC_FAIL(CHECK(doc.load(in).status == status_out_of_memory));
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>
template <typename T>
class seek_fail_buffer : public std::basic_streambuf<T>
{
public:
public:
int seeks;
seek_fail_buffer(): seeks(0)
seek_fail_buffer()
: seeks(0)
{
}
@ -321,28 +329,30 @@ public:
TEST(document_load_stream_seekable_fail_seek)
{
seek_fail_buffer<char> buffer;
std::basic_istream<char> in(&buffer);
seek_fail_buffer<char> buffer;
std::basic_istream<char> in(&buffer);
xml_document doc;
CHECK(doc.load(in).status == status_io_error);
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);
seek_fail_buffer<wchar_t> buffer;
std::basic_istream<wchar_t> in(&buffer);
xml_document doc;
CHECK(doc.load(in).status == status_io_error);
xml_document doc;
CHECK(doc.load(in).status == status_io_error);
}
template <typename T> class tell_fail_buffer: public std::basic_streambuf<T>
template <typename T>
class tell_fail_buffer : public std::basic_streambuf<T>
{
public:
public:
int seeks;
tell_fail_buffer(): seeks(0)
tell_fail_buffer()
: seeks(0)
{
}
@ -361,80 +371,89 @@ public:
TEST(document_load_stream_seekable_fail_tell)
{
tell_fail_buffer<char> buffer;
std::basic_istream<char> in(&buffer);
tell_fail_buffer<char> buffer;
std::basic_istream<char> in(&buffer);
xml_document doc;
CHECK(doc.load(in).status == status_io_error);
xml_document doc;
CHECK(doc.load(in).status == status_io_error);
}
TEST(document_load_stream_wide_seekable_fail_tell)
{
tell_fail_buffer<wchar_t> buffer;
std::basic_istream<wchar_t> in(&buffer);
tell_fail_buffer<wchar_t> buffer;
std::basic_istream<wchar_t> in(&buffer);
xml_document doc;
CHECK(doc.load(in).status == status_io_error);
xml_document doc;
CHECK(doc.load(in).status == status_io_error);
}
#ifndef PUGIXML_NO_EXCEPTIONS
template <typename T> class read_fail_buffer: public std::basic_streambuf<T>
template <typename T>
class read_fail_buffer : public std::basic_streambuf<T>
{
public:
typename std::basic_streambuf<T>::int_type underflow() PUGIXML_OVERRIDE
public:
typename std::basic_streambuf<T>::int_type underflow() PUGIXML_OVERRIDE
{
throw std::runtime_error("underflow failed");
#ifdef __DMC__
#ifdef __DMC__
return 0;
#endif
#endif
}
};
TEST(document_load_stream_nonseekable_fail_read)
{
read_fail_buffer<char> buffer;
std::basic_istream<char> in(&buffer);
read_fail_buffer<char> buffer;
std::basic_istream<char> in(&buffer);
xml_document doc;
CHECK(doc.load(in).status == status_io_error);
xml_document doc;
CHECK(doc.load(in).status == status_io_error);
}
TEST(document_load_stream_wide_nonseekable_fail_read)
{
read_fail_buffer<wchar_t> buffer;
std::basic_istream<wchar_t> in(&buffer);
read_fail_buffer<wchar_t> buffer;
std::basic_istream<wchar_t> in(&buffer);
xml_document doc;
CHECK(doc.load(in).status == status_io_error);
xml_document doc;
CHECK(doc.load(in).status == status_io_error);
}
template <typename T> class read_fail_seekable_buffer: public std::basic_streambuf<T>
template <typename T>
class read_fail_seekable_buffer : public std::basic_streambuf<T>
{
public:
public:
typename std::basic_streambuf<T>::pos_type offset;
read_fail_seekable_buffer(): offset(0)
{
}
read_fail_seekable_buffer()
: offset(0)
{
}
typename std::basic_streambuf<T>::int_type underflow() PUGIXML_OVERRIDE
typename std::basic_streambuf<T>::int_type underflow() PUGIXML_OVERRIDE
{
throw std::runtime_error("underflow failed");
#ifdef __DMC__
#ifdef __DMC__
return 0;
#endif
#endif
}
typename std::basic_streambuf<T>::pos_type seekoff(typename std::basic_streambuf<T>::off_type off, std::ios_base::seekdir dir, std::ios_base::openmode) PUGIXML_OVERRIDE
{
switch (dir)
{
case std::ios_base::beg: offset = off; break;
case std::ios_base::cur: offset += off; break;
case std::ios_base::end: offset = 16 + off; break;
default: ;
case std::ios_base::beg:
offset = off;
break;
case std::ios_base::cur:
offset += off;
break;
case std::ios_base::end:
offset = 16 + off;
break;
default:;
}
return offset;
}
@ -448,20 +467,20 @@ public:
TEST(document_load_stream_seekable_fail_read)
{
read_fail_seekable_buffer<char> buffer;
std::basic_istream<char> in(&buffer);
read_fail_seekable_buffer<char> buffer;
std::basic_istream<char> in(&buffer);
xml_document doc;
CHECK(doc.load(in).status == status_io_error);
xml_document doc;
CHECK(doc.load(in).status == status_io_error);
}
TEST(document_load_stream_wide_seekable_fail_read)
{
read_fail_seekable_buffer<wchar_t> buffer;
std::basic_istream<wchar_t> in(&buffer);
read_fail_seekable_buffer<wchar_t> buffer;
std::basic_istream<wchar_t> in(&buffer);
xml_document doc;
CHECK(doc.load(in).status == status_io_error);
xml_document doc;
CHECK(doc.load(in).status == status_io_error);
}
#endif
#endif
@ -498,7 +517,8 @@ TEST(document_load_file_large)
std::basic_string<char_t> str;
str += STR("<node>");
for (int i = 0; i < 10000; ++i) str += STR("<node/>");
for (int i = 0; i < 10000; ++i)
str += STR("<node/>");
str += STR("</node>");
CHECK_NODE(doc, str.c_str());
@ -744,9 +764,9 @@ struct temp_file
~temp_file()
{
#ifndef _WIN32_WCE
#ifndef _WIN32_WCE
CHECK(unlink(path) == 0);
#endif
#endif
}
};
@ -784,10 +804,10 @@ TEST_XML(document_save_file_text, "<node/>")
temp_file f;
CHECK(doc.save_file(f.path, STR(""), format_no_declaration | format_save_file_text));
CHECK(test_file_contents(f.path, "<node />\n", 9) || test_file_contents(f.path, "<node />\r\n", 10));
CHECK(test_file_contents(f.path, "<node />\n", 9) || test_file_contents(f.path, "<node />\r\n", 10));
CHECK(doc.save_file(f.path, STR(""), format_no_declaration));
CHECK(test_file_contents(f.path, "<node />\n", 9));
CHECK(test_file_contents(f.path, "<node />\n", 9));
}
TEST_XML(document_save_file_wide_text, "<node/>")
@ -799,10 +819,10 @@ TEST_XML(document_save_file_wide_text, "<node/>")
std::copy(f.path, f.path + strlen(f.path) + 1, wpath + 0);
CHECK(doc.save_file(wpath, STR(""), format_no_declaration | format_save_file_text));
CHECK(test_file_contents(f.path, "<node />\n", 9) || test_file_contents(f.path, "<node />\r\n", 10));
CHECK(test_file_contents(f.path, "<node />\n", 9) || test_file_contents(f.path, "<node />\r\n", 10));
CHECK(doc.save_file(wpath, STR(""), format_no_declaration));
CHECK(test_file_contents(f.path, "<node />\n", 9));
CHECK(test_file_contents(f.path, "<node />\n", 9));
}
TEST_XML(document_save_file_leak, "<node/>")
@ -926,32 +946,30 @@ inline void check_utftest_document(const xml_document& doc)
TEST(document_load_file_convert_auto)
{
const char* files[] =
{
"tests/data/utftest_utf16_be.xml",
"tests/data/utftest_utf16_be_bom.xml",
"tests/data/utftest_utf16_be_nodecl.xml",
"tests/data/utftest_utf16_le.xml",
"tests/data/utftest_utf16_le_bom.xml",
"tests/data/utftest_utf16_le_nodecl.xml",
"tests/data/utftest_utf32_be.xml",
"tests/data/utftest_utf32_be_bom.xml",
"tests/data/utftest_utf32_be_nodecl.xml",
"tests/data/utftest_utf32_le.xml",
"tests/data/utftest_utf32_le_bom.xml",
"tests/data/utftest_utf32_le_nodecl.xml",
"tests/data/utftest_utf8.xml",
"tests/data/utftest_utf8_bom.xml",
"tests/data/utftest_utf8_nodecl.xml"
};
{
"tests/data/utftest_utf16_be.xml",
"tests/data/utftest_utf16_be_bom.xml",
"tests/data/utftest_utf16_be_nodecl.xml",
"tests/data/utftest_utf16_le.xml",
"tests/data/utftest_utf16_le_bom.xml",
"tests/data/utftest_utf16_le_nodecl.xml",
"tests/data/utftest_utf32_be.xml",
"tests/data/utftest_utf32_be_bom.xml",
"tests/data/utftest_utf32_be_nodecl.xml",
"tests/data/utftest_utf32_le.xml",
"tests/data/utftest_utf32_le_bom.xml",
"tests/data/utftest_utf32_le_nodecl.xml",
"tests/data/utftest_utf8.xml",
"tests/data/utftest_utf8_bom.xml",
"tests/data/utftest_utf8_nodecl.xml"};
xml_encoding encodings[] =
{
encoding_utf16_be, encoding_utf16_be, encoding_utf16_be,
encoding_utf16_le, encoding_utf16_le, encoding_utf16_le,
encoding_utf32_be, encoding_utf32_be, encoding_utf32_be,
encoding_utf32_le, encoding_utf32_le, encoding_utf32_le,
encoding_utf8, encoding_utf8, encoding_utf8
};
{
encoding_utf16_be, encoding_utf16_be, encoding_utf16_be,
encoding_utf16_le, encoding_utf16_le, encoding_utf16_le,
encoding_utf32_be, encoding_utf32_be, encoding_utf32_be,
encoding_utf32_le, encoding_utf32_le, encoding_utf32_le,
encoding_utf8, encoding_utf8, encoding_utf8};
for (unsigned int i = 0; i < sizeof(files) / sizeof(files[0]); ++i)
{
@ -967,32 +985,30 @@ TEST(document_load_file_convert_auto)
TEST(document_load_file_convert_specific)
{
const char* files[] =
{
"tests/data/utftest_utf16_be.xml",
"tests/data/utftest_utf16_be_bom.xml",
"tests/data/utftest_utf16_be_nodecl.xml",
"tests/data/utftest_utf16_le.xml",
"tests/data/utftest_utf16_le_bom.xml",
"tests/data/utftest_utf16_le_nodecl.xml",
"tests/data/utftest_utf32_be.xml",
"tests/data/utftest_utf32_be_bom.xml",
"tests/data/utftest_utf32_be_nodecl.xml",
"tests/data/utftest_utf32_le.xml",
"tests/data/utftest_utf32_le_bom.xml",
"tests/data/utftest_utf32_le_nodecl.xml",
"tests/data/utftest_utf8.xml",
"tests/data/utftest_utf8_bom.xml",
"tests/data/utftest_utf8_nodecl.xml"
};
{
"tests/data/utftest_utf16_be.xml",
"tests/data/utftest_utf16_be_bom.xml",
"tests/data/utftest_utf16_be_nodecl.xml",
"tests/data/utftest_utf16_le.xml",
"tests/data/utftest_utf16_le_bom.xml",
"tests/data/utftest_utf16_le_nodecl.xml",
"tests/data/utftest_utf32_be.xml",
"tests/data/utftest_utf32_be_bom.xml",
"tests/data/utftest_utf32_be_nodecl.xml",
"tests/data/utftest_utf32_le.xml",
"tests/data/utftest_utf32_le_bom.xml",
"tests/data/utftest_utf32_le_nodecl.xml",
"tests/data/utftest_utf8.xml",
"tests/data/utftest_utf8_bom.xml",
"tests/data/utftest_utf8_nodecl.xml"};
xml_encoding encodings[] =
{
encoding_utf16_be, encoding_utf16_be, encoding_utf16_be,
encoding_utf16_le, encoding_utf16_le, encoding_utf16_le,
encoding_utf32_be, encoding_utf32_be, encoding_utf32_be,
encoding_utf32_le, encoding_utf32_le, encoding_utf32_le,
encoding_utf8, encoding_utf8, encoding_utf8
};
{
encoding_utf16_be, encoding_utf16_be, encoding_utf16_be,
encoding_utf16_le, encoding_utf16_le, encoding_utf16_le,
encoding_utf32_be, encoding_utf32_be, encoding_utf32_be,
encoding_utf32_le, encoding_utf32_le, encoding_utf32_le,
encoding_utf8, encoding_utf8, encoding_utf8};
for (unsigned int i = 0; i < sizeof(files) / sizeof(files[0]); ++i)
{
@ -1021,30 +1037,28 @@ TEST(document_load_file_convert_specific)
TEST(document_load_file_convert_native_endianness)
{
const char* files[2][6] =
{
{
"tests/data/utftest_utf16_be.xml",
"tests/data/utftest_utf16_be_bom.xml",
"tests/data/utftest_utf16_be_nodecl.xml",
"tests/data/utftest_utf32_be.xml",
"tests/data/utftest_utf32_be_bom.xml",
"tests/data/utftest_utf32_be_nodecl.xml",
},
{
"tests/data/utftest_utf16_le.xml",
"tests/data/utftest_utf16_le_bom.xml",
"tests/data/utftest_utf16_le_nodecl.xml",
"tests/data/utftest_utf32_le.xml",
"tests/data/utftest_utf32_le_bom.xml",
"tests/data/utftest_utf32_le_nodecl.xml",
}
};
{
{
"tests/data/utftest_utf16_be.xml",
"tests/data/utftest_utf16_be_bom.xml",
"tests/data/utftest_utf16_be_nodecl.xml",
"tests/data/utftest_utf32_be.xml",
"tests/data/utftest_utf32_be_bom.xml",
"tests/data/utftest_utf32_be_nodecl.xml",
},
{
"tests/data/utftest_utf16_le.xml",
"tests/data/utftest_utf16_le_bom.xml",
"tests/data/utftest_utf16_le_nodecl.xml",
"tests/data/utftest_utf32_le.xml",
"tests/data/utftest_utf32_le_bom.xml",
"tests/data/utftest_utf32_le_nodecl.xml",
}};
xml_encoding encodings[] =
{
encoding_utf16, encoding_utf16, encoding_utf16,
encoding_utf32, encoding_utf32, encoding_utf32
};
{
encoding_utf16, encoding_utf16, encoding_utf16,
encoding_utf32, encoding_utf32, encoding_utf32};
for (unsigned int i = 0; i < sizeof(files[0]) / sizeof(files[0][0]); ++i)
{
@ -1084,24 +1098,22 @@ TEST(document_load_file_convert_native_endianness)
struct file_data_t
{
const char* path;
xml_encoding encoding;
const char* path;
xml_encoding encoding;
char* data;
size_t size;
char* data;
size_t size;
};
TEST(document_contents_preserve)
{
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/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}};
// load files in memory
for (unsigned int i = 0; i < sizeof(files) / sizeof(files[0]); ++i)
@ -1133,10 +1145,9 @@ TEST(document_contents_preserve)
TEST(document_contents_preserve_latin1)
{
file_data_t files[] =
{
{"tests/data/latintest_utf8.xml", encoding_utf8, 0, 0},
{"tests/data/latintest_latin1.xml", encoding_latin1, 0, 0}
};
{
{"tests/data/latintest_utf8.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)
@ -1216,18 +1227,17 @@ TEST(document_convert_invalid_utf16)
TEST(document_load_buffer_empty)
{
xml_encoding encodings[] =
{
encoding_auto,
encoding_utf8,
encoding_utf16_le,
encoding_utf16_be,
encoding_utf16,
encoding_utf32_le,
encoding_utf32_be,
encoding_utf32,
encoding_wchar,
encoding_latin1
};
{
encoding_auto,
encoding_utf8,
encoding_utf16_le,
encoding_utf16_be,
encoding_utf16,
encoding_utf32_le,
encoding_utf32_be,
encoding_utf32,
encoding_wchar,
encoding_latin1};
char buffer[1];
@ -1252,18 +1262,17 @@ TEST(document_load_buffer_empty)
TEST(document_load_buffer_empty_fragment)
{
xml_encoding encodings[] =
{
encoding_auto,
encoding_utf8,
encoding_utf16_le,
encoding_utf16_be,
encoding_utf16,
encoding_utf32_le,
encoding_utf32_be,
encoding_utf32,
encoding_wchar,
encoding_latin1
};
{
encoding_auto,
encoding_utf8,
encoding_utf16_le,
encoding_utf16_be,
encoding_utf16,
encoding_utf32_le,
encoding_utf32_be,
encoding_utf32,
encoding_wchar,
encoding_latin1};
char buffer[1];
@ -1390,91 +1399,92 @@ TEST(document_load_buffer_inplace_short)
#ifndef PUGIXML_NO_EXCEPTIONS
TEST(document_load_exceptions)
{
bool thrown = false;
bool thrown = false;
try
{
xml_document doc;
if (!doc.load_string(STR("<node attribute='value"))) throw std::bad_alloc();
try
{
xml_document doc;
if (!doc.load_string(STR("<node attribute='value")))
throw std::bad_alloc();
CHECK_FORCE_FAIL("Expected parsing failure");
}
catch (const std::bad_alloc&)
{
thrown = true;
}
CHECK_FORCE_FAIL("Expected parsing failure");
}
catch (const std::bad_alloc&)
{
thrown = true;
}
CHECK(thrown);
CHECK(thrown);
}
#endif
TEST_XML_FLAGS(document_element, "<?xml version='1.0'?><node><child/></node><!---->", parse_default | parse_declaration | parse_comments)
{
CHECK(doc.document_element() == doc.child(STR("node")));
CHECK(doc.document_element() == doc.child(STR("node")));
}
TEST_XML_FLAGS(document_element_absent, "<!---->", parse_comments | parse_fragment)
{
CHECK(doc.document_element() == xml_node());
CHECK(doc.document_element() == xml_node());
}
TEST_XML(document_reset, "<node><child/></node>")
{
CHECK(doc.first_child());
CHECK(doc.first_child());
doc.reset();
CHECK(!doc.first_child());
CHECK_NODE(doc, STR(""));
doc.reset();
CHECK(!doc.first_child());
CHECK_NODE(doc, STR(""));
doc.reset();
CHECK(!doc.first_child());
CHECK_NODE(doc, STR(""));
doc.reset();
CHECK(!doc.first_child());
CHECK_NODE(doc, STR(""));
CHECK(doc.load_string(STR("<node/>")));
CHECK(doc.first_child());
CHECK_NODE(doc, STR("<node/>"));
CHECK(doc.load_string(STR("<node/>")));
CHECK(doc.first_child());
CHECK_NODE(doc, STR("<node/>"));
doc.reset();
CHECK(!doc.first_child());
CHECK_NODE(doc, STR(""));
doc.reset();
CHECK(!doc.first_child());
CHECK_NODE(doc, STR(""));
}
TEST(document_reset_empty)
{
xml_document doc;
xml_document doc;
doc.reset();
CHECK(!doc.first_child());
CHECK_NODE(doc, STR(""));
doc.reset();
CHECK(!doc.first_child());
CHECK_NODE(doc, STR(""));
}
TEST_XML(document_reset_copy, "<node><child/></node>")
{
xml_document doc2;
xml_document doc2;
CHECK_NODE(doc2, STR(""));
CHECK_NODE(doc2, STR(""));
doc2.reset(doc);
doc2.reset(doc);
CHECK_NODE(doc2, STR("<node><child/></node>"));
CHECK(doc.first_child() != doc2.first_child());
CHECK_NODE(doc2, STR("<node><child/></node>"));
CHECK(doc.first_child() != doc2.first_child());
doc.reset(doc2);
doc.reset(doc2);
CHECK_NODE(doc, STR("<node><child/></node>"));
CHECK(doc.first_child() != doc2.first_child());
CHECK_NODE(doc, STR("<node><child/></node>"));
CHECK(doc.first_child() != doc2.first_child());
CHECK(doc.first_child().offset_debug() == -1);
CHECK(doc.first_child().offset_debug() == -1);
}
TEST_XML(document_reset_copy_self, "<node><child/></node>")
{
CHECK_NODE(doc, STR("<node><child/></node>"));
CHECK_NODE(doc, STR("<node><child/></node>"));
doc.reset(doc);
doc.reset(doc);
CHECK(!doc.first_child());
CHECK_NODE(doc, STR(""));
CHECK(!doc.first_child());
CHECK_NODE(doc, STR(""));
}
TEST(document_load_buffer_utf_truncated)
@ -1487,20 +1497,20 @@ TEST(document_load_buffer_utf_truncated)
struct document_data_t
{
xml_encoding encoding;
xml_encoding encoding;
const unsigned char* data;
size_t size;
const unsigned char* data;
size_t size;
};
const document_data_t data[] =
{
{ encoding_utf8, utf8, sizeof(utf8) },
{ encoding_utf16_be, utf16_be, sizeof(utf16_be) },
{ encoding_utf16_le, utf16_le, sizeof(utf16_le) },
{ encoding_utf32_be, utf32_be, sizeof(utf32_be) },
{ encoding_utf32_le, utf32_le, sizeof(utf32_le) },
};
{
{encoding_utf8, utf8, sizeof(utf8)},
{encoding_utf16_be, utf16_be, sizeof(utf16_be)},
{encoding_utf16_le, utf16_le, sizeof(utf16_le)},
{encoding_utf32_be, utf32_be, sizeof(utf32_be)},
{encoding_utf32_le, utf32_le, sizeof(utf32_le)},
};
for (size_t i = 0; i < sizeof(data) / sizeof(data[0]); ++i)
{
@ -1520,11 +1530,11 @@ TEST(document_load_buffer_utf_truncated)
const char_t* name = doc.first_child().name();
#ifdef PUGIXML_WCHAR_MODE
#ifdef PUGIXML_WCHAR_MODE
CHECK(name[0] == 0x20ac && name[1] == 0);
#else
#else
CHECK_STRING(name, "\xe2\x82\xac");
#endif
#endif
}
else
{
@ -1565,11 +1575,11 @@ TEST(document_load_stream_truncated)
{
const char_t* name = doc.first_child().name();
#ifdef PUGIXML_WCHAR_MODE
#ifdef PUGIXML_WCHAR_MODE
CHECK(name[0] == 0x20ac && name[1] == 0);
#else
#else
CHECK_STRING(name, "\xe2\x82\xac");
#endif
#endif
}
}
}
@ -1594,14 +1604,13 @@ TEST(document_alignment)
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}
};
{
{"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)
@ -1761,7 +1770,7 @@ TEST(document_move_empty_zero_alloc)
test_runner::_memory_fail_threshold = 1;
for (int i = 1; i < 32; ++i)
docs[i] = std::move(docs[i-1]);
docs[i] = std::move(docs[i - 1]);
delete[] docs;
}
@ -1776,7 +1785,7 @@ TEST(document_move_repeated_zero_alloc)
test_runner::_memory_fail_threshold = 1;
for (int i = 1; i < 32; ++i)
docs[i] = std::move(docs[i-1]);
docs[i] = std::move(docs[i - 1]);
for (int i = 0; i < 31; ++i)
CHECK(!docs[i].first_child());
@ -1797,15 +1806,15 @@ TEST(document_move_compact_fail)
int safe_count = 21;
for (int i = 1; i <= safe_count; ++i)
docs[i] = std::move(docs[i-1]);
docs[i] = std::move(docs[i - 1]);
CHECK_ALLOC_FAIL(docs[safe_count+1] = std::move(docs[safe_count]));
CHECK_ALLOC_FAIL(docs[safe_count + 1] = std::move(docs[safe_count]));
for (int i = 0; i < safe_count; ++i)
CHECK(!docs[i].first_child());
CHECK_NODE(docs[safe_count], STR("<node><child/></node>"));
CHECK(!docs[safe_count+1].first_child());
CHECK(!docs[safe_count + 1].first_child());
}
#endif
#endif

View File

@ -3,9 +3,9 @@
#include <limits>
#include <string>
#include <limits.h>
#include <math.h>
#include <string.h>
#include <limits.h>
using namespace pugi;
@ -174,7 +174,7 @@ TEST_XML(dom_attr_assign_large_number_float, "<node attr='' />")
node.attribute(STR("attr")) = std::numeric_limits<float>::max();
CHECK(test_node(node, STR("<node attr=\"3.40282347e+038\"/>"), STR(""), format_raw) ||
test_node(node, STR("<node attr=\"3.40282347e+38\"/>"), STR(""), format_raw));
test_node(node, STR("<node attr=\"3.40282347e+38\"/>"), STR(""), format_raw));
}
TEST_XML(dom_attr_assign_large_number_double, "<node attr='' />")
@ -880,12 +880,12 @@ TEST(dom_node_declaration_name)
TEST(dom_node_declaration_attributes)
{
xml_document doc;
xml_node node = doc.append_child(node_declaration);
node.append_attribute(STR("version")) = STR("1.0");
node.append_attribute(STR("encoding")) = STR("utf-8");
xml_document doc;
xml_node node = doc.append_child(node_declaration);
node.append_attribute(STR("version")) = STR("1.0");
node.append_attribute(STR("encoding")) = STR("utf-8");
CHECK_NODE(doc, STR("<?xml version=\"1.0\" encoding=\"utf-8\"?>"));
CHECK_NODE(doc, STR("<?xml version=\"1.0\" encoding=\"utf-8\"?>"));
}
TEST(dom_node_declaration_top_level)
@ -926,7 +926,8 @@ TEST(dom_string_out_of_memory)
const unsigned int length = 65536;
static char_t string[length + 1];
for (unsigned int i = 0; i < length; ++i) string[i] = 'a';
for (unsigned int i = 0; i < length; ++i)
string[i] = 'a';
string[length] = 0;
xml_document doc;
@ -976,8 +977,8 @@ TEST(dom_node_out_of_memory)
xml_attribute a = n.append_attribute(STR("a"));
CHECK(a);
CHECK_ALLOC_FAIL(while (n.append_child(node_comment)) { /* nop */ });
CHECK_ALLOC_FAIL(while (n.append_attribute(STR("b"))) { /* nop */ });
CHECK_ALLOC_FAIL(while (n.append_child(node_comment)){/* nop */});
CHECK_ALLOC_FAIL(while (n.append_attribute(STR("b"))){/* nop */});
// verify all node modification operations
CHECK_ALLOC_FAIL(CHECK(!n.append_child()));
@ -1005,7 +1006,8 @@ TEST(dom_node_memory_limit)
const unsigned int length = 65536;
static char_t string[length + 1];
for (unsigned int i = 0; i < length; ++i) string[i] = 'a';
for (unsigned int i = 0; i < length; ++i)
string[i] = 'a';
string[length] = 0;
test_runner::_memory_fail_threshold = 32768 * 2 + sizeof(string);
@ -1024,7 +1026,8 @@ TEST(dom_node_memory_limit_pi)
const unsigned int length = 65536;
static char_t string[length + 1];
for (unsigned int i = 0; i < length; ++i) string[i] = 'a';
for (unsigned int i = 0; i < length; ++i)
string[i] = 'a';
string[length] = 0;
test_runner::_memory_fail_threshold = 32768 * 2 + sizeof(string);
@ -1073,15 +1076,15 @@ TEST(dom_node_doctype_copy)
TEST(dom_node_doctype_value)
{
xml_document doc;
xml_node node = doc.append_child(node_doctype);
xml_document doc;
xml_node node = doc.append_child(node_doctype);
CHECK(node.type() == node_doctype);
CHECK_STRING(node.value(), STR(""));
CHECK_NODE(node, STR("<!DOCTYPE>"));
CHECK(node.type() == node_doctype);
CHECK_STRING(node.value(), STR(""));
CHECK_NODE(node, STR("<!DOCTYPE>"));
CHECK(node.set_value(STR("id [ foo ]")));
CHECK_NODE(node, STR("<!DOCTYPE id [ foo ]>"));
CHECK(node.set_value(STR("id [ foo ]")));
CHECK_NODE(node, STR("<!DOCTYPE id [ foo ]>"));
}
TEST_XML(dom_node_append_buffer_native, "<node>test</node>")
@ -1112,7 +1115,6 @@ TEST_XML(dom_node_append_buffer_convert, "<node>test</node>")
CHECK_NODE(doc, STR("<node>test<n/><n/></node>"));
}
TEST_XML(dom_node_append_buffer_remove, "<node>test</node>")
{
xml_node node = doc.child(STR("node"));
@ -1127,15 +1129,21 @@ TEST_XML(dom_node_append_buffer_remove, "<node>test</node>")
CHECK_NODE(doc, STR("<node>test<child1 id=\"1\"/><child2>text</child2><child3/><child1 id=\"1\"/><child2>text</child2><child3/></node>"));
while (node.remove_child(STR("child2"))) {}
while (node.remove_child(STR("child2")))
{
}
CHECK_NODE(doc, STR("<node>test<child1 id=\"1\"/><child3/><child1 id=\"1\"/><child3/></node>"));
while (node.remove_child(STR("child1"))) {}
while (node.remove_child(STR("child1")))
{
}
CHECK_NODE(doc, STR("<node>test<child3/><child3/></node>"));
while (node.remove_child(STR("child3"))) {}
while (node.remove_child(STR("child3")))
{
}
CHECK_NODE(doc, STR("<node>test</node>"));
@ -1665,7 +1673,8 @@ TEST(dom_node_copy_declaration_empty_name)
CHECK_STRING(decl2.name(), STR(""));
}
template <typename T> bool fp_equal(T lhs, T rhs)
template <typename T>
bool fp_equal(T lhs, T rhs)
{
// Several compilers compare float/double values on x87 stack without proper rounding
// This causes roundtrip tests to fail, although they correctly preserve the data.
@ -1703,13 +1712,13 @@ TEST(dom_fp_roundtrip_min_max_double)
}
const double fp_roundtrip_base[] =
{
0.31830988618379067154,
0.43429448190325182765,
0.57721566490153286061,
0.69314718055994530942,
0.70710678118654752440,
0.78539816339744830962,
{
0.31830988618379067154,
0.43429448190325182765,
0.57721566490153286061,
0.69314718055994530942,
0.70710678118654752440,
0.78539816339744830962,
};
TEST(dom_fp_roundtrip_float)
@ -1738,17 +1747,17 @@ TEST(dom_fp_roundtrip_double)
{
for (size_t i = 0; i < sizeof(fp_roundtrip_base) / sizeof(fp_roundtrip_base[0]); ++i)
{
#if (defined(_MSC_VER) && _MSC_VER < 1400) || defined(__MWERKS__)
#if (defined(_MSC_VER) && _MSC_VER < 1400) || defined(__MWERKS__)
// Not all runtime libraries guarantee roundtripping for denormals
if (e == -1021 && fp_roundtrip_base[i] < 0.5)
continue;
#endif
#endif
#ifdef __DMC__
#ifdef __DMC__
// Digital Mars C does not roundtrip on exactly one combination
if (e == -12 && i == 1)
continue;
#endif
#endif
double value = ldexp(fp_roundtrip_base[i], e);

View File

@ -8,57 +8,57 @@ using namespace pugi;
TEST_XML_FLAGS(dom_text_empty, "<node><a>foo</a><b><![CDATA[bar]]></b><c><?pi value?></c><d/></node>", parse_default | parse_pi)
{
xml_node node = doc.child(STR("node"));
xml_node node = doc.child(STR("node"));
CHECK(node.child(STR("a")).text());
CHECK(node.child(STR("b")).text());
CHECK(!node.child(STR("c")).text());
CHECK(!node.child(STR("d")).text());
CHECK(!xml_node().text());
CHECK(!xml_text());
CHECK(node.child(STR("a")).text());
CHECK(node.child(STR("b")).text());
CHECK(!node.child(STR("c")).text());
CHECK(!node.child(STR("d")).text());
CHECK(!xml_node().text());
CHECK(!xml_text());
generic_empty_test(node.child(STR("a")).text());
generic_empty_test(node.child(STR("a")).text());
}
TEST_XML(dom_text_bool_ops, "<node>foo</node>")
{
generic_bool_ops_test(doc.child(STR("node")).text());
generic_bool_ops_test(doc.child(STR("node")).text());
}
TEST_XML_FLAGS(dom_text_get, "<node><a>foo</a><b><node/><![CDATA[bar]]></b><c><?pi value?></c><d/></node>", parse_default | parse_pi)
{
xml_node node = doc.child(STR("node"));
xml_node node = doc.child(STR("node"));
CHECK_STRING(node.child(STR("a")).text().get(), STR("foo"));
CHECK_STRING(node.child(STR("a")).first_child().text().get(), STR("foo"));
CHECK_STRING(node.child(STR("a")).text().get(), STR("foo"));
CHECK_STRING(node.child(STR("a")).first_child().text().get(), STR("foo"));
CHECK_STRING(node.child(STR("b")).text().get(), STR("bar"));
CHECK_STRING(node.child(STR("b")).last_child().text().get(), STR("bar"));
CHECK_STRING(node.child(STR("b")).text().get(), STR("bar"));
CHECK_STRING(node.child(STR("b")).last_child().text().get(), STR("bar"));
CHECK_STRING(node.child(STR("c")).text().get(), STR(""));
CHECK_STRING(node.child(STR("c")).first_child().text().get(), STR(""));
CHECK_STRING(node.child(STR("c")).text().get(), STR(""));
CHECK_STRING(node.child(STR("c")).first_child().text().get(), STR(""));
CHECK_STRING(node.child(STR("d")).text().get(), STR(""));
CHECK_STRING(node.child(STR("d")).text().get(), STR(""));
CHECK_STRING(xml_node().text().get(), STR(""));
CHECK_STRING(xml_node().text().get(), STR(""));
}
TEST_XML_FLAGS(dom_text_as_string, "<node><a>foo</a><b><node/><![CDATA[bar]]></b><c><?pi value?></c><d/></node>", parse_default | parse_pi)
{
xml_node node = doc.child(STR("node"));
xml_node node = doc.child(STR("node"));
CHECK_STRING(node.child(STR("a")).text().as_string(), STR("foo"));
CHECK_STRING(node.child(STR("a")).first_child().text().as_string(), STR("foo"));
CHECK_STRING(node.child(STR("a")).text().as_string(), STR("foo"));
CHECK_STRING(node.child(STR("a")).first_child().text().as_string(), STR("foo"));
CHECK_STRING(node.child(STR("b")).text().as_string(), STR("bar"));
CHECK_STRING(node.child(STR("b")).last_child().text().as_string(), STR("bar"));
CHECK_STRING(node.child(STR("b")).text().as_string(), STR("bar"));
CHECK_STRING(node.child(STR("b")).last_child().text().as_string(), STR("bar"));
CHECK_STRING(node.child(STR("c")).text().as_string(), STR(""));
CHECK_STRING(node.child(STR("c")).first_child().text().as_string(), STR(""));
CHECK_STRING(node.child(STR("c")).text().as_string(), STR(""));
CHECK_STRING(node.child(STR("c")).first_child().text().as_string(), STR(""));
CHECK_STRING(node.child(STR("d")).text().as_string(), STR(""));
CHECK_STRING(node.child(STR("d")).text().as_string(), STR(""));
CHECK_STRING(xml_node().text().as_string(), STR(""));
CHECK_STRING(xml_node().text().as_string(), STR(""));
}
TEST_XML(dom_text_as_int, "<node><text1>1</text1><text2>-1</text2><text3>-2147483648</text3><text4>2147483647</text4><text5>0</text5></node>")
@ -70,19 +70,19 @@ TEST_XML(dom_text_as_int, "<node><text1>1</text1><text2>-1</text2><text3>-214748
CHECK(node.child(STR("text2")).text().as_int() == -1);
CHECK(node.child(STR("text3")).text().as_int() == -2147483647 - 1);
CHECK(node.child(STR("text4")).text().as_int() == 2147483647);
CHECK(node.child(STR("text5")).text().as_int() == 0);
CHECK(node.child(STR("text5")).text().as_int() == 0);
}
TEST_XML(dom_text_as_int_hex, "<node><text1>0777</text1><text2>0x5ab</text2><text3>0XFf</text3><text4>-0x20</text4><text5>-0x80000000</text5><text6>0x</text6></node>")
{
xml_node node = doc.child(STR("node"));
xml_node node = doc.child(STR("node"));
CHECK(node.child(STR("text1")).text().as_int() == 777); // no octal support! intentional
CHECK(node.child(STR("text2")).text().as_int() == 1451);
CHECK(node.child(STR("text3")).text().as_int() == 255);
CHECK(node.child(STR("text4")).text().as_int() == -32);
CHECK(node.child(STR("text5")).text().as_int() == -2147483647 - 1);
CHECK(node.child(STR("text6")).text().as_int() == 0);
CHECK(node.child(STR("text1")).text().as_int() == 777); // no octal support! intentional
CHECK(node.child(STR("text2")).text().as_int() == 1451);
CHECK(node.child(STR("text3")).text().as_int() == 255);
CHECK(node.child(STR("text4")).text().as_int() == -32);
CHECK(node.child(STR("text5")).text().as_int() == -2147483647 - 1);
CHECK(node.child(STR("text6")).text().as_int() == 0);
}
TEST_XML(dom_text_as_uint, "<node><text1>0</text1><text2>1</text2><text3>2147483647</text3><text4>4294967295</text4><text5>0</text5></node>")
@ -94,29 +94,29 @@ TEST_XML(dom_text_as_uint, "<node><text1>0</text1><text2>1</text2><text3>2147483
CHECK(node.child(STR("text2")).text().as_uint() == 1);
CHECK(node.child(STR("text3")).text().as_uint() == 2147483647);
CHECK(node.child(STR("text4")).text().as_uint() == 4294967295u);
CHECK(node.child(STR("text5")).text().as_uint() == 0);
CHECK(node.child(STR("text5")).text().as_uint() == 0);
}
TEST_XML(dom_text_as_uint_hex, "<node><text1>0777</text1><text2>0x5ab</text2><text3>0XFf</text3><text4>0x20</text4><text5>0xFFFFFFFF</text5><text6>0x</text6></node>")
{
xml_node node = doc.child(STR("node"));
xml_node node = doc.child(STR("node"));
CHECK(node.child(STR("text1")).text().as_uint() == 777); // no octal support! intentional
CHECK(node.child(STR("text2")).text().as_uint() == 1451);
CHECK(node.child(STR("text3")).text().as_uint() == 255);
CHECK(node.child(STR("text4")).text().as_uint() == 32);
CHECK(node.child(STR("text5")).text().as_uint() == 4294967295u);
CHECK(node.child(STR("text6")).text().as_uint() == 0);
CHECK(node.child(STR("text1")).text().as_uint() == 777); // no octal support! intentional
CHECK(node.child(STR("text2")).text().as_uint() == 1451);
CHECK(node.child(STR("text3")).text().as_uint() == 255);
CHECK(node.child(STR("text4")).text().as_uint() == 32);
CHECK(node.child(STR("text5")).text().as_uint() == 4294967295u);
CHECK(node.child(STR("text6")).text().as_uint() == 0);
}
TEST_XML(dom_text_as_integer_space, "<node><text1> \t\n1234</text1><text2>\n\t 0x123</text2><text3>- 16</text3><text4>- 0x10</text4></node>")
{
xml_node node = doc.child(STR("node"));
xml_node node = doc.child(STR("node"));
CHECK(node.child(STR("text1")).text().as_int() == 1234);
CHECK(node.child(STR("text2")).text().as_int() == 291);
CHECK(node.child(STR("text3")).text().as_int() == 0);
CHECK(node.child(STR("text4")).text().as_int() == 0);
CHECK(node.child(STR("text1")).text().as_int() == 1234);
CHECK(node.child(STR("text2")).text().as_int() == 291);
CHECK(node.child(STR("text3")).text().as_int() == 0);
CHECK(node.child(STR("text4")).text().as_int() == 0);
}
TEST_XML(dom_text_as_float, "<node><text1>0</text1><text2>1</text2><text3>0.12</text3><text4>-5.1</text4><text5>3e-4</text5><text6>3.14159265358979323846</text6></node>")
@ -211,42 +211,42 @@ TEST_XML(dom_text_as_ullong_hex, "<node><text1>0777</text1><text2>0x5ab</text2><
TEST_XML(dom_text_get_no_state, "<node/>")
{
xml_node node = doc.child(STR("node"));
xml_text t = node.text();
xml_node node = doc.child(STR("node"));
xml_text t = node.text();
CHECK(!t);
CHECK(t.get() && *t.get() == 0);
CHECK(!node.first_child());
CHECK(!t);
CHECK(t.get() && *t.get() == 0);
CHECK(!node.first_child());
node.append_child(node_pcdata);
node.append_child(node_pcdata);
CHECK(t);
CHECK_STRING(t.get(), STR(""));
CHECK(t);
CHECK_STRING(t.get(), STR(""));
node.first_child().set_value(STR("test"));
node.first_child().set_value(STR("test"));
CHECK(t);
CHECK_STRING(t.get(), STR("test"));
CHECK(t);
CHECK_STRING(t.get(), STR("test"));
}
TEST_XML(dom_text_set, "<node/>")
{
xml_node node = doc.child(STR("node"));
xml_text t = node.text();
xml_node node = doc.child(STR("node"));
xml_text t = node.text();
t.set(STR(""));
CHECK(node.first_child().type() == node_pcdata);
CHECK_NODE(node, STR("<node></node>"));
t.set(STR(""));
CHECK(node.first_child().type() == node_pcdata);
CHECK_NODE(node, STR("<node></node>"));
t.set(STR("boo"));
CHECK(node.first_child().type() == node_pcdata);
CHECK(node.first_child() == node.last_child());
CHECK_NODE(node, STR("<node>boo</node>"));
t.set(STR("boo"));
CHECK(node.first_child().type() == node_pcdata);
CHECK(node.first_child() == node.last_child());
CHECK_NODE(node, STR("<node>boo</node>"));
t.set(STR("foobarfoobar"));
CHECK(node.first_child().type() == node_pcdata);
CHECK(node.first_child() == node.last_child());
CHECK_NODE(node, STR("<node>foobarfoobar</node>"));
t.set(STR("foobarfoobar"));
CHECK(node.first_child().type() == node_pcdata);
CHECK(node.first_child() == node.last_child());
CHECK_NODE(node, STR("<node>foobarfoobar</node>"));
}
TEST_XML(dom_text_assign, "<node/>")
@ -399,49 +399,49 @@ TEST_XML(dom_text_set_value_llong, "<node/>")
TEST_XML(dom_text_middle, "<node><c1>notthisone</c1>text<c2/></node>")
{
xml_node node = doc.child(STR("node"));
xml_text t = node.text();
xml_node node = doc.child(STR("node"));
xml_text t = node.text();
CHECK_STRING(t.get(), STR("text"));
t.set(STR("notext"));
CHECK_STRING(t.get(), STR("text"));
t.set(STR("notext"));
CHECK_NODE(node, STR("<node><c1>notthisone</c1>notext<c2/></node>"));
CHECK(node.remove_child(t.data()));
CHECK_NODE(node, STR("<node><c1>notthisone</c1>notext<c2/></node>"));
CHECK(node.remove_child(t.data()));
CHECK(!t);
CHECK_NODE(node, STR("<node><c1>notthisone</c1><c2/></node>"));
CHECK(!t);
CHECK_NODE(node, STR("<node><c1>notthisone</c1><c2/></node>"));
t.set(STR("yestext"));
t.set(STR("yestext"));
CHECK(t);
CHECK_NODE(node, STR("<node><c1>notthisone</c1><c2/>yestext</node>"));
CHECK(t.data() == node.last_child());
CHECK(t);
CHECK_NODE(node, STR("<node><c1>notthisone</c1><c2/>yestext</node>"));
CHECK(t.data() == node.last_child());
}
TEST_XML_FLAGS(dom_text_data, "<node><a>foo</a><b><![CDATA[bar]]></b><c><?pi value?></c><d/></node>", parse_default | parse_pi)
{
xml_node node = doc.child(STR("node"));
xml_node node = doc.child(STR("node"));
CHECK(node.child(STR("a")).text().data() == node.child(STR("a")).first_child());
CHECK(node.child(STR("b")).text().data() == node.child(STR("b")).first_child());
CHECK(!node.child(STR("c")).text().data());
CHECK(!node.child(STR("d")).text().data());
CHECK(!xml_text().data());
CHECK(node.child(STR("a")).text().data() == node.child(STR("a")).first_child());
CHECK(node.child(STR("b")).text().data() == node.child(STR("b")).first_child());
CHECK(!node.child(STR("c")).text().data());
CHECK(!node.child(STR("d")).text().data());
CHECK(!xml_text().data());
}
TEST(dom_text_defaults)
{
xml_text text;
xml_text text;
CHECK_STRING(text.as_string(STR("foo")), STR("foo"));
CHECK(text.as_int(42) == 42);
CHECK(text.as_uint(42) == 42);
CHECK(text.as_double(42) == 42);
CHECK(text.as_float(42) == 42);
CHECK(text.as_bool(true) == true);
CHECK_STRING(text.as_string(STR("foo")), STR("foo"));
CHECK(text.as_int(42) == 42);
CHECK(text.as_uint(42) == 42);
CHECK(text.as_double(42) == 42);
CHECK(text.as_float(42) == 42);
CHECK(text.as_bool(true) == true);
#ifdef PUGIXML_HAS_LONG_LONG
CHECK(text.as_llong(42) == 42);
CHECK(text.as_ullong(42) == 42);
CHECK(text.as_llong(42) == 42);
CHECK(text.as_ullong(42) == 42);
#endif
}

View File

@ -4,28 +4,34 @@
#include "test.hpp"
#include <string.h>
#include <stdio.h>
#include <string.h>
#include <wchar.h>
#include <utility>
#include <vector>
#include <iterator>
#include <string>
#include <utility>
#include <vector>
#include "helpers.hpp"
using namespace pugi;
#ifdef PUGIXML_NO_STL
template <typename I> static I move_iter(I base, int n)
template <typename I>
static I move_iter(I base, int n)
{
if (n > 0) while (n--) ++base;
else while (n++) --base;
if (n > 0)
while (n--)
++base;
else
while (n++)
--base;
return base;
}
#else
template <typename I> static I move_iter(I base, int n)
template <typename I>
static I move_iter(I base, int n)
{
std::advance(base, n);
return base;
@ -237,18 +243,18 @@ TEST_XML(dom_attr_as_ullong_hex, "<node attr1='0777' attr2='0x5ab' attr3='0XFf'
TEST(dom_attr_defaults)
{
xml_attribute attr;
xml_attribute attr;
CHECK_STRING(attr.as_string(STR("foo")), STR("foo"));
CHECK(attr.as_int(42) == 42);
CHECK(attr.as_uint(42) == 42);
CHECK(attr.as_double(42) == 42);
CHECK(attr.as_float(42) == 42);
CHECK(attr.as_bool(true) == true);
CHECK_STRING(attr.as_string(STR("foo")), STR("foo"));
CHECK(attr.as_int(42) == 42);
CHECK(attr.as_uint(42) == 42);
CHECK(attr.as_double(42) == 42);
CHECK(attr.as_float(42) == 42);
CHECK(attr.as_bool(true) == true);
#ifdef PUGIXML_HAS_LONG_LONG
CHECK(attr.as_llong(42) == 42);
CHECK(attr.as_ullong(42) == 42);
CHECK(attr.as_llong(42) == 42);
CHECK(attr.as_ullong(42) == 42);
#endif
}
@ -339,18 +345,18 @@ TEST_XML(dom_attr_iterator_invalidate, "<node><node1 attr1='0'/><node2 attr1='0'
TEST_XML(dom_attr_iterator_const, "<node attr1='0' attr2='1'/>")
{
xml_node node = doc.child(STR("node"));
xml_node node = doc.child(STR("node"));
const xml_attribute_iterator i1 = node.attributes_begin();
const xml_attribute_iterator i2 = ++xml_attribute_iterator(i1);
const xml_attribute_iterator i3 = ++xml_attribute_iterator(i2);
const xml_attribute_iterator i1 = node.attributes_begin();
const xml_attribute_iterator i2 = ++xml_attribute_iterator(i1);
const xml_attribute_iterator i3 = ++xml_attribute_iterator(i2);
CHECK(*i1 == node.attribute(STR("attr1")));
CHECK(*i2 == node.attribute(STR("attr2")));
CHECK(i3 == node.attributes_end());
CHECK(*i1 == node.attribute(STR("attr1")));
CHECK(*i2 == node.attribute(STR("attr2")));
CHECK(i3 == node.attributes_end());
CHECK_STRING(i1->name(), STR("attr1"));
CHECK_STRING(i2->name(), STR("attr2"));
CHECK_STRING(i1->name(), STR("attr1"));
CHECK_STRING(i2->name(), STR("attr2"));
}
TEST_XML(dom_node_bool_ops, "<node/>")
@ -461,18 +467,18 @@ TEST_XML(dom_node_iterator_invalidate, "<node><node1><child1/></node1><node2><ch
TEST_XML(dom_node_iterator_const, "<node><child1/><child2/></node>")
{
xml_node node = doc.child(STR("node"));
xml_node node = doc.child(STR("node"));
const xml_node_iterator i1 = node.begin();
const xml_node_iterator i2 = ++xml_node_iterator(i1);
const xml_node_iterator i3 = ++xml_node_iterator(i2);
const xml_node_iterator i1 = node.begin();
const xml_node_iterator i2 = ++xml_node_iterator(i1);
const xml_node_iterator i3 = ++xml_node_iterator(i2);
CHECK(*i1 == node.child(STR("child1")));
CHECK(*i2 == node.child(STR("child2")));
CHECK(i3 == node.end());
CHECK(*i1 == node.child(STR("child1")));
CHECK(*i2 == node.child(STR("child2")));
CHECK(i3 == node.end());
CHECK_STRING(i1->name(), STR("child1"));
CHECK_STRING(i2->name(), STR("child2"));
CHECK_STRING(i1->name(), STR("child1"));
CHECK_STRING(i2->name(), STR("child2"));
}
TEST_XML(dom_node_parent, "<node><child/></node>")
@ -659,11 +665,13 @@ struct find_predicate_const
{
bool result;
find_predicate_const(bool result_): result(result_)
find_predicate_const(bool result_)
: result(result_)
{
}
template <typename T> bool operator()(const T&) const
template <typename T>
bool operator()(const T&) const
{
return result;
}
@ -673,18 +681,20 @@ struct find_predicate_prefix
{
const char_t* prefix;
find_predicate_prefix(const char_t* prefix_): prefix(prefix_)
find_predicate_prefix(const char_t* prefix_)
: prefix(prefix_)
{
}
template <typename T> bool operator()(const T& obj) const
template <typename T>
bool operator()(const T& obj) const
{
#ifdef PUGIXML_WCHAR_MODE
#ifdef PUGIXML_WCHAR_MODE
// can't use wcsncmp here because of a bug in DMC
return std::basic_string<char_t>(obj.name()).compare(0, wcslen(prefix), prefix) == 0;
#else
#else
return strncmp(obj.name(), prefix, strlen(prefix)) == 0;
#endif
#endif
}
};
@ -782,13 +792,15 @@ TEST_XML(dom_node_first_element_by_path, "<node><child1>text<child2/></child1></
CHECK(doc.first_element_by_path(STR("//node")) == doc.child(STR("node")));
}
struct test_walker: xml_tree_walker
struct test_walker : xml_tree_walker
{
std::basic_string<char_t> log;
unsigned int call_count;
unsigned int stop_count;
test_walker(unsigned int stop_count_ = 0): call_count(0), stop_count(stop_count_)
test_walker(unsigned int stop_count_ = 0)
: call_count(0)
, stop_count(stop_count_)
{
}
@ -797,14 +809,14 @@ struct test_walker: xml_tree_walker
char buf[32];
sprintf(buf, "%d", depth());
#ifdef PUGIXML_WCHAR_MODE
#ifdef PUGIXML_WCHAR_MODE
wchar_t wbuf[32];
std::copy(buf, buf + strlen(buf) + 1, &wbuf[0]);
return std::basic_string<char_t>(wbuf);
#else
#else
return std::basic_string<char_t>(buf);
#endif
#endif
}
virtual bool begin(xml_node& node) PUGIXML_OVERRIDE
@ -935,7 +947,7 @@ TEST_XML_FLAGS(dom_offset_debug, "<?xml?><!DOCTYPE><?pi?><!--comment--><node>pcd
TEST(dom_offset_debug_encoding)
{
char buf[] = { 0, '<', 0, 'n', 0, '/', 0, '>' };
char buf[] = {0, '<', 0, 'n', 0, '/', 0, '>'};
xml_document doc;
CHECK(doc.load_buffer(buf, sizeof(buf)));
@ -979,17 +991,17 @@ TEST_XML(dom_internal_object, "<node attr='value'>value</node>")
CHECK(xml_node().internal_object() == 0);
CHECK(xml_attribute().internal_object() == 0);
CHECK(node.internal_object() != 0);
CHECK(value.internal_object() != 0);
CHECK(node.internal_object() != value.internal_object());
CHECK(node.internal_object() != 0);
CHECK(value.internal_object() != 0);
CHECK(node.internal_object() != value.internal_object());
CHECK(attr.internal_object() != 0);
CHECK(attr.internal_object() != 0);
xml_node node_copy = node;
CHECK(node_copy.internal_object() == node.internal_object());
xml_node node_copy = node;
CHECK(node_copy.internal_object() == node.internal_object());
xml_attribute attr_copy = attr;
CHECK(attr_copy.internal_object() == attr.internal_object());
xml_attribute attr_copy = attr;
CHECK(attr_copy.internal_object() == attr.internal_object());
}
TEST_XML(dom_hash_value, "<node attr='value'>value</node>")
@ -1001,17 +1013,17 @@ TEST_XML(dom_hash_value, "<node attr='value'>value</node>")
CHECK(xml_node().hash_value() == 0);
CHECK(xml_attribute().hash_value() == 0);
CHECK(node.hash_value() != 0);
CHECK(value.hash_value() != 0);
CHECK(node.hash_value() != value.hash_value());
CHECK(node.hash_value() != 0);
CHECK(value.hash_value() != 0);
CHECK(node.hash_value() != value.hash_value());
CHECK(attr.hash_value() != 0);
CHECK(attr.hash_value() != 0);
xml_node node_copy = node;
CHECK(node_copy.hash_value() == node.hash_value());
xml_node node_copy = node;
CHECK(node_copy.hash_value() == node.hash_value());
xml_attribute attr_copy = attr;
CHECK(attr_copy.hash_value() == attr.hash_value());
xml_attribute attr_copy = attr;
CHECK(attr_copy.hash_value() == attr.hash_value());
}
TEST_XML(dom_node_named_iterator, "<node><node1><child/></node1><node2><child/><child/></node2><node3/><node4><child/><x/></node4></node>")
@ -1121,15 +1133,15 @@ TEST_XML(dom_ranged_for, "<node attr1='1' attr2='2'><test>3</test><fake>5</fake>
{
int index = 1;
for (xml_node n: doc.children())
for (xml_node n : doc.children())
{
for (xml_attribute a: n.attributes())
for (xml_attribute a : n.attributes())
{
CHECK(a.as_int() == index);
index++;
}
for (xml_node c: n.children(STR("test")))
for (xml_node c : n.children(STR("test")))
{
CHECK(c.text().as_int() == index);
index++;

View File

@ -1,3 +1,2 @@
// Tests header guards
#include "../src/pugixml.hpp"
#include "../src/pugixml.hpp"

View File

@ -1,3 +1,3 @@
// Tests compatibility with iosfwd
#include <iosfwd>
#include "../src/pugixml.hpp"
#include <iosfwd>

View File

@ -1,3 +1,3 @@
// Tests compatibility with iostream
#include <iostream>
#include "../src/pugixml.hpp"
#include <iostream>

View File

@ -5,7 +5,6 @@
// Check header guards
#include "../src/pugixml.hpp"
#include "../src/pugixml.hpp"
using namespace pugi;

View File

@ -5,7 +5,6 @@
// Check header guards
#include "../src/pugixml.hpp"
#include "../src/pugixml.hpp"
using namespace pugi;

View File

@ -1,3 +1,3 @@
// Tests compatibility with string
#include <string>
#include "../src/pugixml.hpp"
#include <string>

View File

@ -1,5 +1,5 @@
// Tests compatibility with string/iostream
#include <string>
#include "../src/pugixml.hpp"
#include <istream>
#include <ostream>
#include <string>

View File

@ -1,7 +1,7 @@
#include "test.hpp"
#include "writer_string.hpp"
#include "allocator.hpp"
#include "writer_string.hpp"
#include <string>
#include <vector>
@ -10,28 +10,28 @@ using namespace pugi;
namespace
{
int page_allocs = 0;
int page_deallocs = 0;
int page_allocs = 0;
int page_deallocs = 0;
bool is_page(size_t size)
{
return size >= 16384;
}
void* allocate(size_t size)
{
void* ptr = memory_allocate(size);
page_allocs += is_page(memory_size(ptr));
return ptr;
}
void deallocate(void* ptr)
{
page_deallocs += is_page(memory_size(ptr));
memory_deallocate(ptr);
}
bool is_page(size_t size)
{
return size >= 16384;
}
void* allocate(size_t size)
{
void* ptr = memory_allocate(size);
page_allocs += is_page(memory_size(ptr));
return ptr;
}
void deallocate(void* ptr)
{
page_deallocs += is_page(memory_size(ptr));
memory_deallocate(ptr);
}
} // namespace
TEST(memory_custom_memory_management)
{
page_allocs = page_deallocs = 0;
@ -116,7 +116,7 @@ TEST(memory_large_allocations)
}
// prune
for (node = doc.first_child(); node; )
for (node = doc.first_child(); node;)
{
xml_node next = node.next_sibling().next_sibling();
@ -229,7 +229,8 @@ TEST(memory_string_allocate_decreasing)
std::basic_string<char_t> s = STR("ab");
for (int i = 0; i < 17; ++i) s += s;
for (int i = 0; i < 17; ++i)
s += s;
for (int j = 0; j < 17; ++j)
{
@ -286,7 +287,8 @@ TEST(memory_string_allocate_decreasing_inplace)
std::basic_string<char_t> s = STR("ab");
for (int i = 0; i < 17; ++i) s += s;
for (int i = 0; i < 17; ++i)
s += s;
for (int j = 0; j < 17; ++j)
{

View File

@ -279,132 +279,132 @@ TEST(parse_ws_pcdata_parse)
static int get_tree_node_count(xml_node n)
{
int result = 1;
int result = 1;
for (xml_node c = n.first_child(); c; c = c.next_sibling())
result += get_tree_node_count(c);
for (xml_node c = n.first_child(); c; c = c.next_sibling())
result += get_tree_node_count(c);
return result;
return result;
}
TEST(parse_ws_pcdata_permutations)
{
struct test_data_t
{
unsigned int mask; // 1 = default flags, 2 = parse_ws_pcdata, 4 = parse_ws_pcdata_single
const char_t* source;
const char_t* result;
int nodes; // negative if parsing should fail
};
struct test_data_t
{
unsigned int mask; // 1 = default flags, 2 = parse_ws_pcdata, 4 = parse_ws_pcdata_single
const char_t* source;
const char_t* result;
int nodes; // negative if parsing should fail
};
test_data_t test_data[] =
{
// external pcdata should be discarded (whitespace or not)
{7, STR("ext1<node/>"), STR("<node/>"), 2},
{7, STR("ext1<node/>ext2"), STR("<node/>"), 2},
{7, STR(" <node/>"), STR("<node/>"), 2},
{7, STR("<node/> "), STR("<node/>"), 2},
{7, STR(" <node/> "), STR("<node/>"), 2},
// inner pcdata should be preserved
{7, STR("<node>inner</node>"), STR("<node>inner</node>"), 3},
{7, STR("<node>inner1<child/>inner2</node>"), STR("<node>inner1<child/>inner2</node>"), 5},
{7, STR("<node>inner1<child>deep</child>inner2</node>"), STR("<node>inner1<child>deep</child>inner2</node>"), 6},
// empty pcdata nodes should never be created
{7, STR("<node>inner1<child></child>inner2</node>"), STR("<node>inner1<child/>inner2</node>"), 5},
{7, STR("<node><child></child>inner2</node>"), STR("<node><child/>inner2</node>"), 4},
{7, STR("<node>inner1<child></child></node>"), STR("<node>inner1<child/></node>"), 4},
{7, STR("<node><child></child></node>"), STR("<node><child/></node>"), 3},
// comments, pi or other nodes should not cause pcdata creation either
{7, STR("<node><!----><child><?pi?></child><![CDATA[x]]></node>"), STR("<node><child/><![CDATA[x]]></node>"), 4},
// leading/trailing pcdata whitespace should be preserved (note: this will change if parse_ws_pcdata_trim is introduced)
{7, STR("<node>\t \tinner1<child> deep </child>\t\ninner2\n\t</node>"), STR("<node>\t \tinner1<child> deep </child>\t\ninner2\n\t</node>"), 6},
// whitespace-only pcdata preservation depends on the parsing mode
{1, STR("<node>\n\t<child> </child>\n\t<child> <deep> </deep> </child>\n\t<!---->\n\t</node>"), STR("<node><child/><child><deep/></child></node>"), 5},
{2, STR("<node>\n\t<child> </child>\n\t<child> <deep> </deep> </child>\n\t<!---->\n\t</node>"), STR("<node>\n\t<child> </child>\n\t<child> <deep> </deep> </child>\n\t\n\t</node>"), 13},
{4, STR("<node>\n\t<child> </child>\n\t<child> <deep> </deep> </child>\n\t<!---->\n\t</node>"), STR("<node><child> </child><child><deep> </deep></child></node>"), 7},
// current implementation of parse_ws_pcdata_single has an unfortunate bug; reproduce it here
{4, STR("<node>\t\t<!---->\n\n</node>"), STR("<node>\n\n</node>"), 3},
// error case: terminate PCDATA in the middle
{7, STR("<node>abcdef"), STR("<node>abcdef</node>"), -3},
{5, STR("<node> "), STR("<node/>"), -2},
{2, STR("<node> "), STR("<node> </node>"), -3},
// error case: terminate PCDATA as early as possible
{7, STR("<node>"), STR("<node/>"), -2},
{7, STR("<node>a"), STR("<node>a</node>"), -3},
{5, STR("<node> "), STR("<node/>"), -2},
{2, STR("<node> "), STR("<node> </node>"), -3},
};
test_data_t test_data[] =
{
// external pcdata should be discarded (whitespace or not)
{7, STR("ext1<node/>"), STR("<node/>"), 2},
{7, STR("ext1<node/>ext2"), STR("<node/>"), 2},
{7, STR(" <node/>"), STR("<node/>"), 2},
{7, STR("<node/> "), STR("<node/>"), 2},
{7, STR(" <node/> "), STR("<node/>"), 2},
// inner pcdata should be preserved
{7, STR("<node>inner</node>"), STR("<node>inner</node>"), 3},
{7, STR("<node>inner1<child/>inner2</node>"), STR("<node>inner1<child/>inner2</node>"), 5},
{7, STR("<node>inner1<child>deep</child>inner2</node>"), STR("<node>inner1<child>deep</child>inner2</node>"), 6},
// empty pcdata nodes should never be created
{7, STR("<node>inner1<child></child>inner2</node>"), STR("<node>inner1<child/>inner2</node>"), 5},
{7, STR("<node><child></child>inner2</node>"), STR("<node><child/>inner2</node>"), 4},
{7, STR("<node>inner1<child></child></node>"), STR("<node>inner1<child/></node>"), 4},
{7, STR("<node><child></child></node>"), STR("<node><child/></node>"), 3},
// comments, pi or other nodes should not cause pcdata creation either
{7, STR("<node><!----><child><?pi?></child><![CDATA[x]]></node>"), STR("<node><child/><![CDATA[x]]></node>"), 4},
// leading/trailing pcdata whitespace should be preserved (note: this will change if parse_ws_pcdata_trim is introduced)
{7, STR("<node>\t \tinner1<child> deep </child>\t\ninner2\n\t</node>"), STR("<node>\t \tinner1<child> deep </child>\t\ninner2\n\t</node>"), 6},
// whitespace-only pcdata preservation depends on the parsing mode
{1, STR("<node>\n\t<child> </child>\n\t<child> <deep> </deep> </child>\n\t<!---->\n\t</node>"), STR("<node><child/><child><deep/></child></node>"), 5},
{2, STR("<node>\n\t<child> </child>\n\t<child> <deep> </deep> </child>\n\t<!---->\n\t</node>"), STR("<node>\n\t<child> </child>\n\t<child> <deep> </deep> </child>\n\t\n\t</node>"), 13},
{4, STR("<node>\n\t<child> </child>\n\t<child> <deep> </deep> </child>\n\t<!---->\n\t</node>"), STR("<node><child> </child><child><deep> </deep></child></node>"), 7},
// current implementation of parse_ws_pcdata_single has an unfortunate bug; reproduce it here
{4, STR("<node>\t\t<!---->\n\n</node>"), STR("<node>\n\n</node>"), 3},
// error case: terminate PCDATA in the middle
{7, STR("<node>abcdef"), STR("<node>abcdef</node>"), -3},
{5, STR("<node> "), STR("<node/>"), -2},
{2, STR("<node> "), STR("<node> </node>"), -3},
// error case: terminate PCDATA as early as possible
{7, STR("<node>"), STR("<node/>"), -2},
{7, STR("<node>a"), STR("<node>a</node>"), -3},
{5, STR("<node> "), STR("<node/>"), -2},
{2, STR("<node> "), STR("<node> </node>"), -3},
};
for (size_t i = 0; i < sizeof(test_data) / sizeof(test_data[0]); ++i)
{
const test_data_t& td = test_data[i];
for (size_t i = 0; i < sizeof(test_data) / sizeof(test_data[0]); ++i)
{
const test_data_t& td = test_data[i];
for (int flag = 0; flag < 3; ++flag)
{
if (td.mask & (1 << flag))
{
unsigned int flags[] = {parse_default, parse_default | parse_ws_pcdata, parse_default | parse_ws_pcdata_single};
for (int flag = 0; flag < 3; ++flag)
{
if (td.mask & (1 << flag))
{
unsigned int flags[] = {parse_default, parse_default | parse_ws_pcdata, parse_default | parse_ws_pcdata_single};
xml_document doc;
CHECK((td.nodes > 0) == doc.load_string(td.source, flags[flag]));
CHECK_NODE(doc, td.result);
xml_document doc;
CHECK((td.nodes > 0) == doc.load_string(td.source, flags[flag]));
CHECK_NODE(doc, td.result);
int nodes = get_tree_node_count(doc);
CHECK((td.nodes < 0 ? -td.nodes : td.nodes) == nodes);
}
}
}
int nodes = get_tree_node_count(doc);
CHECK((td.nodes < 0 ? -td.nodes : td.nodes) == nodes);
}
}
}
}
TEST(parse_ws_pcdata_fragment_permutations)
{
struct test_data_t
{
unsigned int mask; // 1 = default flags, 2 = parse_ws_pcdata, 4 = parse_ws_pcdata_single
const char_t* source;
const char_t* result;
int nodes; // negative if parsing should fail
};
struct test_data_t
{
unsigned int mask; // 1 = default flags, 2 = parse_ws_pcdata, 4 = parse_ws_pcdata_single
const char_t* source;
const char_t* result;
int nodes; // negative if parsing should fail
};
test_data_t test_data[] =
{
// external pcdata should be preserved
{7, STR("ext1"), STR("ext1"), 2},
{5, STR(" "), STR(""), 1},
{2, STR(" "), STR(" "), 2},
{7, STR("ext1<node/>"), STR("ext1<node/>"), 3},
{7, STR("<node/>ext2"), STR("<node/>ext2"), 3},
{7, STR("ext1<node/>ext2"), STR("ext1<node/>ext2"), 4},
{7, STR("ext1<node1/>ext2<node2/>ext3"), STR("ext1<node1/>ext2<node2/>ext3"), 6},
{5, STR(" <node/>"), STR("<node/>"), 2},
{2, STR(" <node/>"), STR(" <node/>"), 3},
{5, STR("<node/> "), STR("<node/>"), 2},
{2, STR("<node/> "), STR("<node/> "), 3},
{5, STR(" <node/> "), STR("<node/>"), 2},
{2, STR(" <node/> "), STR(" <node/> "), 4},
{5, STR(" <node1/> <node2/> "), STR("<node1/><node2/>"), 3},
{2, STR(" <node1/> <node2/> "), STR(" <node1/> <node2/> "), 6},
};
test_data_t test_data[] =
{
// external pcdata should be preserved
{7, STR("ext1"), STR("ext1"), 2},
{5, STR(" "), STR(""), 1},
{2, STR(" "), STR(" "), 2},
{7, STR("ext1<node/>"), STR("ext1<node/>"), 3},
{7, STR("<node/>ext2"), STR("<node/>ext2"), 3},
{7, STR("ext1<node/>ext2"), STR("ext1<node/>ext2"), 4},
{7, STR("ext1<node1/>ext2<node2/>ext3"), STR("ext1<node1/>ext2<node2/>ext3"), 6},
{5, STR(" <node/>"), STR("<node/>"), 2},
{2, STR(" <node/>"), STR(" <node/>"), 3},
{5, STR("<node/> "), STR("<node/>"), 2},
{2, STR("<node/> "), STR("<node/> "), 3},
{5, STR(" <node/> "), STR("<node/>"), 2},
{2, STR(" <node/> "), STR(" <node/> "), 4},
{5, STR(" <node1/> <node2/> "), STR("<node1/><node2/>"), 3},
{2, STR(" <node1/> <node2/> "), STR(" <node1/> <node2/> "), 6},
};
for (size_t i = 0; i < sizeof(test_data) / sizeof(test_data[0]); ++i)
{
const test_data_t& td = test_data[i];
for (size_t i = 0; i < sizeof(test_data) / sizeof(test_data[0]); ++i)
{
const test_data_t& td = test_data[i];
for (int flag = 0; flag < 3; ++flag)
{
if (td.mask & (1 << flag))
{
unsigned int flags[] = {parse_default, parse_default | parse_ws_pcdata, parse_default | parse_ws_pcdata_single};
for (int flag = 0; flag < 3; ++flag)
{
if (td.mask & (1 << flag))
{
unsigned int flags[] = {parse_default, parse_default | parse_ws_pcdata, parse_default | parse_ws_pcdata_single};
xml_document doc;
CHECK((td.nodes > 0) == doc.load_string(td.source, flags[flag] | parse_fragment));
CHECK_NODE(doc, td.result);
xml_document doc;
CHECK((td.nodes > 0) == doc.load_string(td.source, flags[flag] | parse_fragment));
CHECK_NODE(doc, td.result);
int nodes = get_tree_node_count(doc);
CHECK((td.nodes < 0 ? -td.nodes : td.nodes) == nodes);
}
}
}
int nodes = get_tree_node_count(doc);
CHECK((td.nodes < 0 ? -td.nodes : td.nodes) == nodes);
}
}
}
}
TEST(parse_pcdata_no_eol)
@ -439,49 +439,48 @@ TEST(parse_pcdata_error)
TEST(parse_pcdata_trim)
{
struct test_data_t
{
const char_t* source;
const char_t* result;
unsigned int flags;
};
struct test_data_t
{
const char_t* source;
const char_t* result;
unsigned int flags;
};
test_data_t test_data[] =
{
{ STR("<node> text</node>"), STR("text"), 0 },
{ STR("<node>\t\n text</node>"), STR("text"), 0 },
{ STR("<node>text </node>"), STR("text"), 0 },
{ STR("<node>text \t\n</node>"), STR("text"), 0 },
{ STR("<node>\r\n\t text \t\n\r</node>"), STR("text"), 0 },
{ STR(" text"), STR("text"), parse_fragment },
{ STR("\t\n text"), STR("text"), parse_fragment },
{ STR("text "), STR("text"), parse_fragment },
{ STR("text \t\n"), STR("text"), parse_fragment },
{ STR("\r\n\t text \t\n\r"), STR("text"), parse_fragment },
{ STR("<node>\r\n\t text \t\n\r more \r\n\t</node>"), STR("text \t\n\r more"), 0 },
{ STR("<node>\r\n\t text \t\n\r more \r\n\t</node>"), STR("text \t\n\n more"), parse_eol },
{ STR("<node>\r\n\t text \r\n\r\n\r\n\r\n\r\n\r\n\r\n more \r\n\t</node>"), STR("text \n\n\n\n\n\n\n more"), parse_eol },
{ STR("<node> test&amp;&amp;&amp;&amp;&amp;&amp;&amp; </node>"), STR("test&amp;&amp;&amp;&amp;&amp;&amp;&amp;"), 0 },
{ STR("<node> test&amp;&amp;&amp;&amp;&amp;&amp;&amp; </node>"), STR("test&&&&&&&"), parse_escapes },
{ STR(" test&amp;&amp;&amp;&amp;&amp;&amp;&amp; "), STR("test&&&&&&&"), parse_fragment | parse_escapes },
{ STR("<node>\r\n\t text \t\n\r m&amp;&amp;e \r\n\t</node>"), STR("text \t\n\n m&&e"), parse_eol | parse_escapes }
};
test_data_t test_data[] =
{
{STR("<node> text</node>"), STR("text"), 0},
{STR("<node>\t\n text</node>"), STR("text"), 0},
{STR("<node>text </node>"), STR("text"), 0},
{STR("<node>text \t\n</node>"), STR("text"), 0},
{STR("<node>\r\n\t text \t\n\r</node>"), STR("text"), 0},
{STR(" text"), STR("text"), parse_fragment},
{STR("\t\n text"), STR("text"), parse_fragment},
{STR("text "), STR("text"), parse_fragment},
{STR("text \t\n"), STR("text"), parse_fragment},
{STR("\r\n\t text \t\n\r"), STR("text"), parse_fragment},
{STR("<node>\r\n\t text \t\n\r more \r\n\t</node>"), STR("text \t\n\r more"), 0},
{STR("<node>\r\n\t text \t\n\r more \r\n\t</node>"), STR("text \t\n\n more"), parse_eol},
{STR("<node>\r\n\t text \r\n\r\n\r\n\r\n\r\n\r\n\r\n more \r\n\t</node>"), STR("text \n\n\n\n\n\n\n more"), parse_eol},
{STR("<node> test&amp;&amp;&amp;&amp;&amp;&amp;&amp; </node>"), STR("test&amp;&amp;&amp;&amp;&amp;&amp;&amp;"), 0},
{STR("<node> test&amp;&amp;&amp;&amp;&amp;&amp;&amp; </node>"), STR("test&&&&&&&"), parse_escapes},
{STR(" test&amp;&amp;&amp;&amp;&amp;&amp;&amp; "), STR("test&&&&&&&"), parse_fragment | parse_escapes},
{STR("<node>\r\n\t text \t\n\r m&amp;&amp;e \r\n\t</node>"), STR("text \t\n\n m&&e"), parse_eol | parse_escapes}};
for (size_t i = 0; i < sizeof(test_data) / sizeof(test_data[0]); ++i)
{
const test_data_t& td = test_data[i];
for (size_t i = 0; i < sizeof(test_data) / sizeof(test_data[0]); ++i)
{
const test_data_t& td = test_data[i];
xml_document doc;
CHECK(doc.load_string(td.source, td.flags | parse_trim_pcdata));
xml_document doc;
CHECK(doc.load_string(td.source, td.flags | parse_trim_pcdata));
const char_t* value = doc.child(STR("node")) ? doc.child_value(STR("node")) : doc.text().get();
CHECK_STRING(value, td.result);
}
const char_t* value = doc.child(STR("node")) ? doc.child_value(STR("node")) : doc.text().get();
CHECK_STRING(value, td.result);
}
}
TEST(parse_pcdata_trim_empty)
{
unsigned int flags[] = { 0, parse_ws_pcdata, parse_ws_pcdata_single, parse_ws_pcdata | parse_ws_pcdata_single };
unsigned int flags[] = {0, parse_ws_pcdata, parse_ws_pcdata_single, parse_ws_pcdata | parse_ws_pcdata_single};
for (size_t i = 0; i < sizeof(flags) / sizeof(flags[0]); ++i)
{
@ -696,7 +695,6 @@ TEST(parse_attribute_variations)
}
}
TEST(parse_attribute_error)
{
xml_document doc;
@ -926,10 +924,10 @@ TEST(parse_out_of_memory_halfway_node)
for (unsigned int i = 0; i < count; ++i)
{
text[4*i + 0] = '<';
text[4*i + 1] = 'n';
text[4*i + 2] = '/';
text[4*i + 3] = '>';
text[4 * i + 0] = '<';
text[4 * i + 1] = 'n';
text[4 * i + 2] = '/';
text[4 * i + 3] = '>';
}
test_runner::_memory_fail_threshold = 65536;
@ -949,11 +947,11 @@ TEST(parse_out_of_memory_halfway_attr)
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 * i + 2] = ' ';
text[5 * i + 3] = 'a';
text[5 * i + 4] = '=';
text[5 * i + 5] = '"';
text[5 * i + 6] = '"';
}
text[5 * count + 2] = '/';
@ -984,10 +982,10 @@ TEST(parse_out_of_memory_allocator_state_sync)
for (unsigned int i = 0; i < count; ++i)
{
text[4*i + 0] = '<';
text[4*i + 1] = 'n';
text[4*i + 2] = '/';
text[4*i + 3] = '>';
text[4 * i + 0] = '<';
text[4 * i + 1] = 'n';
text[4 * i + 2] = '/';
text[4 * i + 3] = '>';
}
test_runner::_memory_fail_threshold = 65536;
@ -1072,18 +1070,18 @@ TEST(parse_bom_fragment)
};
const test_data_t data[] =
{
{ encoding_utf8, "\xef\xbb\xbf", 3, STR("") },
{ encoding_utf8, "\xef\xbb\xbftest", 7, STR("test") },
{ encoding_utf16_be, "\xfe\xff", 2, STR("") },
{ encoding_utf16_be, "\xfe\xff\x00t\x00o\x00s\x00t", 10, STR("tost") },
{ encoding_utf16_le, "\xff\xfe", 2, STR("") },
{ encoding_utf16_le, "\xff\xfet\x00o\x00s\x00t\x00", 10, STR("tost") },
{ encoding_utf32_be, "\x00\x00\xfe\xff", 4, STR("") },
{ encoding_utf32_be, "\x00\x00\xfe\xff\x00\x00\x00t\x00\x00\x00o\x00\x00\x00s\x00\x00\x00t", 20, STR("tost") },
{ encoding_utf32_le, "\xff\xfe\x00\x00", 4, STR("") },
{ encoding_utf32_le, "\xff\xfe\x00\x00t\x00\x00\x00o\x00\x00\x00s\x00\x00\x00t\x00\x00\x00", 20, STR("tost") },
};
{
{encoding_utf8, "\xef\xbb\xbf", 3, STR("")},
{encoding_utf8, "\xef\xbb\xbftest", 7, STR("test")},
{encoding_utf16_be, "\xfe\xff", 2, STR("")},
{encoding_utf16_be, "\xfe\xff\x00t\x00o\x00s\x00t", 10, STR("tost")},
{encoding_utf16_le, "\xff\xfe", 2, STR("")},
{encoding_utf16_le, "\xff\xfet\x00o\x00s\x00t\x00", 10, STR("tost")},
{encoding_utf32_be, "\x00\x00\xfe\xff", 4, STR("")},
{encoding_utf32_be, "\x00\x00\xfe\xff\x00\x00\x00t\x00\x00\x00o\x00\x00\x00s\x00\x00\x00t", 20, STR("tost")},
{encoding_utf32_le, "\xff\xfe\x00\x00", 4, STR("")},
{encoding_utf32_le, "\xff\xfe\x00\x00t\x00\x00\x00o\x00\x00\x00s\x00\x00\x00t\x00\x00\x00", 20, STR("tost")},
};
for (size_t i = 0; i < sizeof(data) / sizeof(data[0]); ++i)
{
@ -1171,12 +1169,11 @@ TEST(parse_close_tag_eof)
TEST(parse_fuzz_doctype)
{
unsigned char data[] =
{
0x3b, 0x3c, 0x21, 0x44, 0x4f, 0x43, 0x54, 0x59, 0x50, 0x45, 0xef, 0xbb, 0xbf, 0x3c, 0x3f, 0x78,
0x6d, 0x6c, 0x20, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x3d, 0x22, 0x31, 0x2e, 0x30, 0x22,
0x3f, 0x3e, 0x3c, 0x21, 0x2d, 0x2d, 0x20, 0xe9, 0x80, 0xb1, 0xe5, 0xa0, 0xb1, 0xe3, 0x82, 0xb4,
0xe3, 0x83, 0xb3, 0x20, 0xef, 0x83, 0x97, 0xe3, 0xa9, 0x2a, 0x20, 0x2d, 0x2d, 0x3e
};
{
0x3b, 0x3c, 0x21, 0x44, 0x4f, 0x43, 0x54, 0x59, 0x50, 0x45, 0xef, 0xbb, 0xbf, 0x3c, 0x3f, 0x78,
0x6d, 0x6c, 0x20, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x3d, 0x22, 0x31, 0x2e, 0x30, 0x22,
0x3f, 0x3e, 0x3c, 0x21, 0x2d, 0x2d, 0x20, 0xe9, 0x80, 0xb1, 0xe5, 0xa0, 0xb1, 0xe3, 0x82, 0xb4,
0xe3, 0x83, 0xb3, 0x20, 0xef, 0x83, 0x97, 0xe3, 0xa9, 0x2a, 0x20, 0x2d, 0x2d, 0x3e};
xml_document doc;
CHECK(doc.load_buffer(data, sizeof(data)).status == status_bad_doctype);
@ -1215,9 +1212,9 @@ TEST(parse_embed_pcdata)
CHECK_STRING(child.child_value(), STR("outer"));
CHECK_STRING(child.child_value(STR("inner2")), STR("value2"));
#ifndef PUGIXML_NO_XPATH
#ifndef PUGIXML_NO_XPATH
CHECK_XPATH_NUMBER(doc, STR("count(node/child/*[starts-with(., 'value')])"), 2);
#endif
#endif
CHECK_NODE(doc, STR("<node><key>value</key><child><inner1>value1</inner1><inner2>value2</inner2>outer</child><two>text<data/></two></node>"));
CHECK_NODE_EX(doc, STR("<node>\n<key>value</key>\n<child>\n<inner1>value1</inner1>\n<inner2>value2</inner2>outer</child>\n<two>text<data />\n</two>\n</node>\n"), STR("\t"), 0);
@ -1286,23 +1283,23 @@ TEST(parse_encoding_detect_auto)
};
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 },
};
{
// 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)
{
@ -1324,27 +1321,27 @@ TEST(parse_encoding_detect_auto_incomplete)
};
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 ", 2, 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 },
};
{
// 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 ", 2, 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)
{

View File

@ -3,8 +3,8 @@
#include "test.hpp"
#include <string.h>
#include <wchar.h>
#include <string>
#include <wchar.h>
using namespace pugi;
@ -30,21 +30,28 @@ static bool test_doctype_wf(const char_t* decl)
xml_document doc;
// standalone
if (!load_concat(doc, decl) || !doc.first_child().empty()) return false;
if (!load_concat(doc, decl) || !doc.first_child().empty())
return false;
// pcdata pre/postfix
if (!load_concat(doc, STR("a"), decl) || !test_node(doc, STR("a"), STR(""), format_raw)) return false;
if (!load_concat(doc, decl, STR("b")) || !test_node(doc, STR("b"), STR(""), format_raw)) return false;
if (!load_concat(doc, STR("a"), decl, STR("b")) || !test_node(doc, STR("ab"), STR(""), format_raw)) return false;
if (!load_concat(doc, STR("a"), decl) || !test_node(doc, STR("a"), STR(""), format_raw))
return false;
if (!load_concat(doc, decl, STR("b")) || !test_node(doc, STR("b"), STR(""), format_raw))
return false;
if (!load_concat(doc, STR("a"), decl, STR("b")) || !test_node(doc, STR("ab"), STR(""), format_raw))
return false;
// node pre/postfix
if (!load_concat(doc, STR("<nodea/>"), decl) || !test_node(doc, STR("<nodea/>"), STR(""), format_raw)) return false;
if (!load_concat(doc, decl, STR("<nodeb/>")) || !test_node(doc, STR("<nodeb/>"), STR(""), format_raw)) return false;
if (!load_concat(doc, STR("<nodea/>"), decl, STR("<nodeb/>")) || !test_node(doc, STR("<nodea/><nodeb/>"), STR(""), format_raw)) return false;
if (!load_concat(doc, STR("<nodea/>"), decl) || !test_node(doc, STR("<nodea/>"), STR(""), format_raw))
return false;
if (!load_concat(doc, decl, STR("<nodeb/>")) || !test_node(doc, STR("<nodeb/>"), STR(""), format_raw))
return false;
if (!load_concat(doc, STR("<nodea/>"), decl, STR("<nodeb/>")) || !test_node(doc, STR("<nodea/><nodeb/>"), STR(""), format_raw))
return false;
// check load-store contents preservation
CHECK(doc.load_string(decl, parse_doctype | parse_fragment));
CHECK_NODE(doc, decl);
// check load-store contents preservation
CHECK(doc.load_string(decl, parse_doctype | parse_fragment));
CHECK_NODE(doc, decl);
return true;
}
@ -54,13 +61,16 @@ static bool test_doctype_nwf(const char_t* decl)
xml_document doc;
// standalone
if (load_concat(doc, decl).status != status_bad_doctype) return false;
if (load_concat(doc, decl).status != status_bad_doctype)
return false;
// pcdata postfix
if (load_concat(doc, decl, STR("b")).status != status_bad_doctype) return false;
if (load_concat(doc, decl, STR("b")).status != status_bad_doctype)
return false;
// node postfix
if (load_concat(doc, decl, STR("<nodeb/>")).status != status_bad_doctype) return false;
if (load_concat(doc, decl, STR("<nodeb/>")).status != status_bad_doctype)
return false;
return true;
}
@ -281,9 +291,9 @@ TEST(parse_doctype_xmlconf_oasis_1)
TEST_DOCTYPE_WF("<!DOCTYPE doc [ <!ELEMENT doc EMPTY> <!NOTATION not1 PUBLIC \"a b cdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ\"> <!NOTATION not2 PUBLIC '0123456789-()+,./:=?;!*#@$_%'> <!NOTATION not3 PUBLIC \"0123456789-()+,.'/:=?;!*#@$_%\"> ]>");
TEST_DOCTYPE_WF("<!DOCTYPE doc SYSTEM \"p31pass1.dtd\" [<!ELEMENT doc EMPTY>]>");
// not actually a doctype :)
xml_document doc;
CHECK(doc.load_string(STR("<!--a <!DOCTYPE <?- ]]>-<[ CDATA [ \"- -'- -<doc>--> <!---->"), parse_full | parse_fragment) && doc.first_child().type() == node_comment && doc.last_child().type() == node_comment && doc.first_child().next_sibling() == doc.last_child());
// not actually a doctype :)
xml_document doc;
CHECK(doc.load_string(STR("<!--a <!DOCTYPE <?- ]]>-<[ CDATA [ \"- -'- -<doc>--> <!---->"), parse_full | parse_fragment) && doc.first_child().type() == node_comment && doc.last_child().type() == node_comment && doc.first_child().next_sibling() == doc.last_child());
CHECK(doc.load_string(STR("<?xmla <!DOCTYPE <[ CDATA [</doc> &a%b&#c?>"), parse_full | parse_fragment) && doc.first_child().type() == node_pi && doc.first_child() == doc.last_child());
}
@ -303,22 +313,22 @@ TEST(parse_doctype_xmlconf_xmltest_1)
TEST_XML_FLAGS(parse_doctype_value, "<!DOCTYPE doc [ <!ELEMENT doc (#PCDATA)> <!ENTITY e \"<![CDATA[Tim & Michael]]>\"> ]>", parse_fragment | parse_doctype)
{
xml_node n = doc.first_child();
xml_node n = doc.first_child();
CHECK(n.type() == node_doctype);
CHECK_STRING(n.value(), STR("doc [ <!ELEMENT doc (#PCDATA)> <!ENTITY e \"<![CDATA[Tim & Michael]]>\"> ]"));
CHECK(n.type() == node_doctype);
CHECK_STRING(n.value(), STR("doc [ <!ELEMENT doc (#PCDATA)> <!ENTITY e \"<![CDATA[Tim & Michael]]>\"> ]"));
}
TEST(parse_doctype_error_toplevel)
{
xml_document doc;
CHECK(doc.load_string(STR("<node><!DOCTYPE></node>")).status == status_bad_doctype);
CHECK(doc.load_string(STR("<node><!DOCTYPE></node>"), parse_doctype).status == status_bad_doctype);
xml_document doc;
CHECK(doc.load_string(STR("<node><!DOCTYPE></node>")).status == status_bad_doctype);
CHECK(doc.load_string(STR("<node><!DOCTYPE></node>"), parse_doctype).status == status_bad_doctype);
}
TEST(parse_doctype_error_ignore)
{
xml_document doc;
xml_document doc;
CHECK(doc.load_string(STR("<!DOCTYPE root [ <![IGNORE[ ")).status == status_bad_doctype);
CHECK(doc.load_string(STR("<!DOCTYPE root [ <![IGNORE[ "), parse_doctype).status == status_bad_doctype);
CHECK(doc.load_string(STR("<!DOCTYPE root [ <![IGNORE[ <![INCLUDE[")).status == status_bad_doctype);

View File

@ -73,9 +73,9 @@ TEST(as_wide_invalid)
TEST(as_wide_string)
{
std::string s = "abcd";
std::string s = "abcd";
CHECK(as_wide(s) == L"abcd");
CHECK(as_wide(s) == L"abcd");
}
TEST(as_utf8_empty)
@ -110,11 +110,11 @@ TEST(as_utf8_valid_astral)
}
else
{
#ifdef U_LITERALS
#ifdef U_LITERALS
CHECK(as_utf8(L"\uda1d\ude24 \udbc0\udfff") == "\xf2\x97\x98\xa4 \xf4\x80\x8f\xbf");
#else
#else
CHECK(as_utf8(L"\xda1d\xde24 \xdbc0\xdfff") == "\xf2\x97\x98\xa4 \xf4\x80\x8f\xbf");
#endif
#endif
}
}
@ -125,29 +125,29 @@ TEST(as_utf8_invalid)
if (wcharsize == 2)
{
// check non-terminated degenerate handling
#ifdef U_LITERALS
#ifdef U_LITERALS
CHECK(as_utf8(L"a\uda1d") == "a");
CHECK(as_utf8(L"a\uda1d_") == "a_");
#else
#else
CHECK(as_utf8(L"a\xda1d") == "a");
CHECK(as_utf8(L"a\xda1d_") == "a_");
#endif
#endif
// check incorrect leading code
#ifdef U_LITERALS
#ifdef U_LITERALS
CHECK(as_utf8(L"a\ude24") == "a");
CHECK(as_utf8(L"a\ude24_") == "a_");
#else
#else
CHECK(as_utf8(L"a\xde24") == "a");
CHECK(as_utf8(L"a\xde24_") == "a_");
#endif
#endif
}
}
TEST(as_utf8_string)
{
std::basic_string<wchar_t> s = L"abcd";
std::basic_string<wchar_t> s = L"abcd";
CHECK(as_utf8(s) == "abcd");
CHECK(as_utf8(s) == "abcd");
}
#endif

View File

@ -2,9 +2,9 @@
#include "writer_string.hpp"
#include <string>
#include <sstream>
#include <stdexcept>
#include <string>
using namespace pugi;
@ -199,11 +199,11 @@ TEST_XML(write_escape, "<node attr=''>text</node>")
TEST_XML(write_escape_unicode, "<node attr='&#x3c00;'/>")
{
#ifdef PUGIXML_WCHAR_MODE
#ifdef U_LITERALS
CHECK_NODE(doc, STR("<node attr=\"\u3c00\"/>"));
#else
CHECK_NODE(doc, STR("<node attr=\"\x3c00\"/>"));
#endif
#ifdef U_LITERALS
CHECK_NODE(doc, STR("<node attr=\"\u3c00\"/>"));
#else
CHECK_NODE(doc, STR("<node attr=\"\x3c00\"/>"));
#endif
#else
CHECK_NODE(doc, STR("<node attr=\"\xe3\xb0\x80\"/>"));
#endif
@ -217,7 +217,7 @@ TEST_XML(write_no_escapes, "<node attr=''>text</node>")
CHECK_NODE_EX(doc, STR("<node attr=\"<>'\"&\x04\r\n\t\"><>'\"&\x04\r\n\t</node>"), STR(""), format_raw | format_no_escapes);
}
struct test_writer: xml_writer
struct test_writer : xml_writer
{
std::basic_string<char_t> contents;
@ -302,7 +302,7 @@ TEST(write_encodings)
CHECK(v.size() == 10 && v[0] == '<' && v[1] == 0x54 && v[2] == 0xA2 && v[3] == 0x20AC && v[4] == wchar_cast(0xd852) && v[5] == wchar_cast(0xdf62) && v[6] == ' ' && v[7] == '/' && v[8] == '>' && v[9] == '\n');
}
CHECK(test_write_narrow(doc, format_default, encoding_latin1, "<\x54\xA2?? />\n", 9));
CHECK(test_write_narrow(doc, format_default, encoding_latin1, "<\x54\xA2?? />\n", 9));
}
#ifdef PUGIXML_WCHAR_MODE
@ -313,7 +313,8 @@ TEST(write_encoding_huge)
// make a large utf16 name consisting of 6-byte char pairs (6 does not divide internal buffer size, so will need split correction)
std::string s_utf16 = std::string("\x00<", 2);
for (unsigned int i = 0; i < N; ++i) s_utf16 += "\x20\xAC\xd8\x52\xdf\x62";
for (unsigned int i = 0; i < N; ++i)
s_utf16 += "\x20\xAC\xd8\x52\xdf\x62";
s_utf16 += std::string("\x00/\x00>", 4);
@ -322,7 +323,8 @@ TEST(write_encoding_huge)
std::string s_utf8 = "<";
for (unsigned int j = 0; j < N; ++j) s_utf8 += "\xE2\x82\xAC\xF0\xA4\xAD\xA2";
for (unsigned int j = 0; j < N; ++j)
s_utf8 += "\xE2\x82\xAC\xF0\xA4\xAD\xA2";
s_utf8 += " />\n";
@ -340,7 +342,8 @@ TEST(write_encoding_huge_invalid)
// make a large utf16 name consisting of leading surrogate chars
std::basic_string<wchar_t> s_utf16;
for (unsigned int i = 0; i < N; ++i) s_utf16 += static_cast<wchar_t>(0xd852);
for (unsigned int i = 0; i < N; ++i)
s_utf16 += static_cast<wchar_t>(0xd852);
xml_document doc;
doc.append_child().set_name(s_utf16.c_str());
@ -356,7 +359,8 @@ TEST(write_encoding_huge)
// make a large utf8 name consisting of 3-byte chars (3 does not divide internal buffer size, so will need split correction)
std::string s_utf8 = "<";
for (unsigned int i = 0; i < N; ++i) s_utf8 += "\xE2\x82\xAC";
for (unsigned int i = 0; i < N; ++i)
s_utf8 += "\xE2\x82\xAC";
s_utf8 += "/>";
@ -365,7 +369,8 @@ TEST(write_encoding_huge)
std::string s_utf16 = std::string("\x00<", 2);
for (unsigned int j = 0; j < N; ++j) s_utf16 += "\x20\xAC";
for (unsigned int j = 0; j < N; ++j)
s_utf16 += "\x20\xAC";
s_utf16 += std::string("\x00 \x00/\x00>\x00\n", 8);
@ -379,7 +384,8 @@ TEST(write_encoding_huge_invalid)
// make a large utf8 name consisting of non-leading chars
std::string s_utf8;
for (unsigned int i = 0; i < N; ++i) s_utf8 += "\x82";
for (unsigned int i = 0; i < N; ++i)
s_utf8 += "\x82";
xml_document doc;
doc.append_child().set_name(s_utf8.c_str());
@ -416,22 +422,22 @@ TEST(write_unicode_invalid_utf16)
if (wcharsize == 2)
{
// check non-terminated degenerate handling
#ifdef U_LITERALS
#ifdef U_LITERALS
CHECK(test_write_unicode_invalid(L"a\uda1d", "a"));
CHECK(test_write_unicode_invalid(L"a\uda1d_", "a_"));
#else
#else
CHECK(test_write_unicode_invalid(L"a\xda1d", "a"));
CHECK(test_write_unicode_invalid(L"a\xda1d_", "a_"));
#endif
#endif
// check incorrect leading code
#ifdef U_LITERALS
#ifdef U_LITERALS
CHECK(test_write_unicode_invalid(L"a\ude24", "a"));
CHECK(test_write_unicode_invalid(L"a\ude24_", "a_"));
#else
#else
CHECK(test_write_unicode_invalid(L"a\xde24", "a"));
CHECK(test_write_unicode_invalid(L"a\xde24_", "a_"));
#endif
#endif
}
}
#else
@ -569,19 +575,17 @@ TEST(write_pcdata_whitespace_fixedpoint)
const char_t* data = STR("<node> test <child>\n <sub/>\n </child>\n</node>");
static const unsigned int flags_parse[] =
{
0,
parse_ws_pcdata,
parse_ws_pcdata_single,
parse_trim_pcdata
};
{
0,
parse_ws_pcdata,
parse_ws_pcdata_single,
parse_trim_pcdata};
static const unsigned int flags_format[] =
{
0,
format_raw,
format_indent
};
{
0,
format_raw,
format_indent};
for (unsigned int i = 0; i < sizeof(flags_parse) / sizeof(flags_parse[0]); ++i)
{
@ -618,7 +622,7 @@ TEST_XML(write_no_empty_element_tags, "<node><child1/><child2>text</child2><chil
TEST_XML_FLAGS(write_roundtrip, "<node><child1 attr1='value1' attr2='value2'/><child2 attr='value'>pre<![CDATA[data]]>mid&lt;text&amp;escape<!--comment--><test/>post<?pi value?>fin</child2><child3/></node>", parse_full)
{
const unsigned int flagset[] = { format_indent, format_raw, format_no_declaration, format_indent_attributes, format_no_empty_element_tags };
const unsigned int flagset[] = {format_indent, format_raw, format_no_declaration, format_indent_attributes, format_no_empty_element_tags};
size_t flagcount = sizeof(flagset) / sizeof(flagset[0]);
for (size_t i = 0; i < (size_t(1) << flagcount); ++i)
@ -669,7 +673,7 @@ TEST(write_flush_coverage)
}
#ifndef PUGIXML_NO_EXCEPTIONS
struct throwing_writer: xml_writer
struct throwing_writer : xml_writer
{
virtual void write(const void*, size_t) PUGIXML_OVERRIDE
{

View File

@ -5,10 +5,10 @@
#include <string.h>
#include <wchar.h>
#include <string>
#include <vector>
#include <algorithm>
#include <limits>
#include <string>
#include <vector>
using namespace pugi;
@ -24,7 +24,8 @@ TEST(xpath_allocator_many_pages)
{
std::basic_string<char_t> query = STR("0");
for (int i = 0; i < 128; ++i) query += STR("+string-length('abcdefgh')");
for (int i = 0; i < 128; ++i)
query += STR("+string-length('abcdefgh')");
CHECK_XPATH_NUMBER(xml_node(), query.c_str(), 1024);
}
@ -33,7 +34,8 @@ TEST(xpath_allocator_large_page)
{
std::basic_string<char_t> query;
for (int i = 0; i < 1024; ++i) query += STR("abcdefgh");
for (int i = 0; i < 1024; ++i)
query += STR("abcdefgh");
CHECK_XPATH_NUMBER(xml_node(), (STR("string-length('") + query + STR("')")).c_str(), 8192);
}
@ -147,10 +149,10 @@ TEST(xpath_sort_random_medium)
{
xml_document doc;
load_document_copy(doc, STR("<node>")
STR("<child1 attr1='value1' attr2='value2'/><child2 attr1='value1'>test</child2><child1 attr1='value1' attr2='value2'/><child2 attr1='value1'>test</child2>")
STR("<child1 attr1='value1' attr2='value2'/><child2 attr1='value1'>test</child2><child1 attr1='value1' attr2='value2'/><child2 attr1='value1'>test</child2>")
STR("<child1 attr1='value1' attr2='value2'/><child2 attr1='value1'>test</child2><child1 attr1='value1' attr2='value2'/><child2 attr1='value1'>test</child2>")
STR("</node>"));
STR("<child1 attr1='value1' attr2='value2'/><child2 attr1='value1'>test</child2><child1 attr1='value1' attr2='value2'/><child2 attr1='value1'>test</child2>")
STR("<child1 attr1='value1' attr2='value2'/><child2 attr1='value1'>test</child2><child1 attr1='value1' attr2='value2'/><child2 attr1='value1'>test</child2>")
STR("<child1 attr1='value1' attr2='value2'/><child2 attr1='value1'>test</child2><child1 attr1='value1' attr2='value2'/><child2 attr1='value1'>test</child2>")
STR("</node>"));
xpath_node_set ns = doc.select_nodes(STR("//node() | //@*"));
@ -162,24 +164,25 @@ TEST(xpath_sort_random_medium)
xpath_node_set_tester tester(copy, "sorted order failed");
for (unsigned int i = 2; i < 39; ++i) tester % i;
for (unsigned int i = 2; i < 39; ++i)
tester % i;
}
TEST(xpath_sort_random_large)
{
xml_document doc;
load_document_copy(doc, STR("<node>")
STR("<child1 attr1='value1' attr2='value2'/><child2 attr1='value1'>test</child2><child1 attr1='value1' attr2='value2'/><child2 attr1='value1'>test</child2>")
STR("<child1 attr1='value1' attr2='value2'/><child2 attr1='value1'>test</child2><child1 attr1='value1' attr2='value2'/><child2 attr1='value1'>test</child2>")
STR("<child1 attr1='value1' attr2='value2'/><child2 attr1='value1'>test</child2><child1 attr1='value1' attr2='value2'/><child2 attr1='value1'>test</child2>")
STR("<child1 attr1='value1' attr2='value2'/><child2 attr1='value1'>test</child2><child1 attr1='value1' attr2='value2'/><child2 attr1='value1'>test</child2>")
STR("<child1 attr1='value1' attr2='value2'/><child2 attr1='value1'>test</child2><child1 attr1='value1' attr2='value2'/><child2 attr1='value1'>test</child2>")
STR("<child1 attr1='value1' attr2='value2'/><child2 attr1='value1'>test</child2><child1 attr1='value1' attr2='value2'/><child2 attr1='value1'>test</child2>")
STR("<child1 attr1='value1' attr2='value2'/><child2 attr1='value1'>test</child2><child1 attr1='value1' attr2='value2'/><child2 attr1='value1'>test</child2>")
STR("<child1 attr1='value1' attr2='value2'/><child2 attr1='value1'>test</child2><child1 attr1='value1' attr2='value2'/><child2 attr1='value1'>test</child2>")
STR("<child1 attr1='value1' attr2='value2'/><child2 attr1='value1'>test</child2><child1 attr1='value1' attr2='value2'/><child2 attr1='value1'>test</child2>")
STR("<child1 attr1='value1' attr2='value2'/><child2 attr1='value1'>test</child2><child1 attr1='value1' attr2='value2'/><child2 attr1='value1'>test</child2>")
STR("<child1 attr1='value1' attr2='value2'/><child2 attr1='value1'>test</child2></node>"));
STR("<child1 attr1='value1' attr2='value2'/><child2 attr1='value1'>test</child2><child1 attr1='value1' attr2='value2'/><child2 attr1='value1'>test</child2>")
STR("<child1 attr1='value1' attr2='value2'/><child2 attr1='value1'>test</child2><child1 attr1='value1' attr2='value2'/><child2 attr1='value1'>test</child2>")
STR("<child1 attr1='value1' attr2='value2'/><child2 attr1='value1'>test</child2><child1 attr1='value1' attr2='value2'/><child2 attr1='value1'>test</child2>")
STR("<child1 attr1='value1' attr2='value2'/><child2 attr1='value1'>test</child2><child1 attr1='value1' attr2='value2'/><child2 attr1='value1'>test</child2>")
STR("<child1 attr1='value1' attr2='value2'/><child2 attr1='value1'>test</child2><child1 attr1='value1' attr2='value2'/><child2 attr1='value1'>test</child2>")
STR("<child1 attr1='value1' attr2='value2'/><child2 attr1='value1'>test</child2><child1 attr1='value1' attr2='value2'/><child2 attr1='value1'>test</child2>")
STR("<child1 attr1='value1' attr2='value2'/><child2 attr1='value1'>test</child2><child1 attr1='value1' attr2='value2'/><child2 attr1='value1'>test</child2>")
STR("<child1 attr1='value1' attr2='value2'/><child2 attr1='value1'>test</child2><child1 attr1='value1' attr2='value2'/><child2 attr1='value1'>test</child2>")
STR("<child1 attr1='value1' attr2='value2'/><child2 attr1='value1'>test</child2><child1 attr1='value1' attr2='value2'/><child2 attr1='value1'>test</child2>")
STR("<child1 attr1='value1' attr2='value2'/><child2 attr1='value1'>test</child2><child1 attr1='value1' attr2='value2'/><child2 attr1='value1'>test</child2>")
STR("<child1 attr1='value1' attr2='value2'/><child2 attr1='value1'>test</child2></node>"));
xpath_node_set ns = doc.select_nodes(STR("//node() | //@*"));
@ -191,7 +194,8 @@ TEST(xpath_sort_random_large)
xpath_node_set_tester tester(copy, "sorted order failed");
for (unsigned int i = 2; i < 129; ++i) tester % i;
for (unsigned int i = 2; i < 129; ++i)
tester % i;
}
TEST(xpath_long_numbers_parse)
@ -247,7 +251,8 @@ TEST(xpath_denorm_numbers)
// 10^-318 - double denormal
for (int i = 0; i < 106; ++i)
{
if (i != 0) query += STR(" * ");
if (i != 0)
query += STR(" * ");
query += STR("0.001");
}
@ -282,7 +287,7 @@ TEST_XML(xpath_rexml_2, "<a:x xmlns:a='1'><a:y p='p' q='q'><a:z>zzz</a:z></a:y><
TEST_XML(xpath_rexml_3, "<article><section role='subdivision' id='1'><para>free flowing text.</para></section><section role='division'><section role='subdivision' id='2'><para>free flowing text.</para></section><section role='division'><para>free flowing text.</para></section></section></article>")
{
CHECK_XPATH_NODESET(doc, STR("//section[../self::section[@role=\"division\"]]")) % 10 % 15;
CHECK_XPATH_NODESET(doc, STR("//section[@role=\"subdivision\" and not(../self::section[@role=\"division\"])]")) % 3;
CHECK_XPATH_NODESET(doc, STR("//section[@role=\"subdivision\" and not(../self::section[@role=\"division\"])]")) % 3;
CHECK_XPATH_NODESET(doc, STR("//section[@role=\"subdivision\"][not(../self::section[@role=\"division\"])]")) % 3;
}
@ -716,7 +721,7 @@ TEST(xpath_sort_crossdoc_different_depth)
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 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();
@ -728,9 +733,10 @@ TEST(xpath_allocate_string_out_of_memory)
{
std::basic_string<char_t> query;
for (int i = 0; i < 1024; ++i) query += STR("abcdefgh");
for (int i = 0; i < 1024; ++i)
query += STR("abcdefgh");
test_runner::_memory_fail_threshold = 8*1024;
test_runner::_memory_fail_threshold = 8 * 1024;
#ifndef __DMC__ // DigitalMars exception handling crashes instead of catching the exception...
CHECK_ALLOC_FAIL(CHECK(!xpath_query(query.c_str())));

View File

@ -141,10 +141,10 @@ TEST_XML(xpath_api_nodeset_copy, "<node><foo/><foo/></node>")
TEST(xpath_api_nodeset_copy_empty)
{
xpath_node_set set;
xpath_node_set set2 = set;
xpath_node_set set3;
set3 = set;
xpath_node_set set;
xpath_node_set set2 = set;
xpath_node_set set3;
set3 = set;
}
TEST_XML(xpath_api_evaluate, "<node attr='3'/>")
@ -430,7 +430,6 @@ TEST_XML(xpath_api_nodeset_move_ctor, "<node><foo/><foo/><bar/></node>")
CHECK(move[1] == doc.first_child().first_child());
}
TEST_XML(xpath_api_nodeset_move_ctor_single, "<node><foo/><foo/><bar/></node>")
{
xpath_node_set set = doc.select_nodes(STR("node/bar"));

View File

@ -57,7 +57,7 @@ TEST_XML(xpath_number_sum, "<node>123<child>789</child></node><node/>")
CHECK_XPATH_NUMBER(n, STR("sum(.)"), 123789); // 123 .. 789
CHECK_XPATH_NUMBER(n, STR("sum(./descendant-or-self::node())"), 125490); // node + 123 + child + 789 = 123789 + 123 + 789 + 789 = 125490
CHECK_XPATH_NUMBER(n, STR("sum(.//node())"), 1701); // 123 + child + 789 = 123 + 789 + 789
CHECK_XPATH_NUMBER(n, STR("sum(.//node())"), 1701); // 123 + child + 789 = 123 + 789 + 789
CHECK_XPATH_NUMBER_NAN(doc.last_child(), STR("sum(.)"));
// sum with 2 arguments
@ -423,9 +423,9 @@ TEST(xpath_string_substring_after)
TEST_XML(xpath_string_substring_after_heap, "<node>foo<child/>bar</node>")
{
CHECK_XPATH_STRING(doc, STR("substring-after(node, 'fo')"), STR("obar"));
CHECK_XPATH_STRING(doc, STR("substring-after(node, 'fooba')"), STR("r"));
CHECK_XPATH_STRING(doc, STR("substring-after(node, 'foobar')"), STR(""));
CHECK_XPATH_STRING(doc, STR("substring-after(node, 'fo')"), STR("obar"));
CHECK_XPATH_STRING(doc, STR("substring-after(node, 'fooba')"), STR("r"));
CHECK_XPATH_STRING(doc, STR("substring-after(node, 'foobar')"), STR(""));
}
TEST(xpath_string_substring)
@ -452,7 +452,7 @@ TEST(xpath_string_substring)
CHECK_XPATH_STRING(c, STR("substring('abcd', 0 div 0)"), STR(""));
CHECK_XPATH_STRING(c, STR("substring('', 1)"), STR(""));
CHECK_XPATH_STRING(c, STR("substring('', 0)"), STR(""));
CHECK_XPATH_STRING(c, STR("substring(substring('internalexternalcorrect substring',9),9)"), STR("correct substring"));
CHECK_XPATH_STRING(c, STR("substring(substring('internalexternalcorrect substring',9),9)"), STR("correct substring"));
// substring with 3 arguments
CHECK_XPATH_STRING(c, STR("substring('abcd', 2, 1)"), STR("b"));
@ -490,9 +490,9 @@ TEST(xpath_string_substring)
TEST_XML(xpath_string_substring_heap, "<node>foo<child/>bar</node>")
{
CHECK_XPATH_STRING(doc, STR("substring(node, 3)"), STR("obar"));
CHECK_XPATH_STRING(doc, STR("substring(node, 6)"), STR("r"));
CHECK_XPATH_STRING(doc, STR("substring(node, 7)"), STR(""));
CHECK_XPATH_STRING(doc, STR("substring(node, 3)"), STR("obar"));
CHECK_XPATH_STRING(doc, STR("substring(node, 6)"), STR("r"));
CHECK_XPATH_STRING(doc, STR("substring(node, 7)"), STR(""));
}
TEST_XML(xpath_string_string_length, "<node>123</node>")
@ -590,7 +590,7 @@ TEST_XML(xpath_nodeset_last, "<node><c1/><c1/><c2/><c3/><c3/><c3/><c3/></node>")
// last with 0 arguments
CHECK_XPATH_NUMBER(n, STR("last()"), 1);
CHECK_XPATH_NODESET(n, STR("c1[last() = 1]"));
CHECK_XPATH_NODESET(n, STR("c1[last() = 2]")) % 3 % 4; // c1, c1
CHECK_XPATH_NODESET(n, STR("c1[last() = 2]")) % 3 % 4; // c1, c1
CHECK_XPATH_NODESET(n, STR("c2/preceding-sibling::node()[last() = 2]")) % 4 % 3; // c1, c1
// last with 1 argument
@ -829,7 +829,8 @@ TEST(xpath_string_translate_table_out_of_memory)
for (size_t i = 0; i < count; ++i)
{
if (i != 0) query += STR(",");
if (i != 0)
query += STR(",");
query += STR("translate('a','a','A')");
}

View File

@ -99,82 +99,80 @@ TEST(xpath_semantics_posinv) // coverage for contains()
TEST(xpath_parse_paths_valid)
{
const char_t* paths[] =
{
// From Jaxen tests
STR("foo[.='bar']"), STR("foo[.!='bar']"), STR("/"), STR("*"), STR("//foo"), STR("/*"), STR("/."), STR("/foo[/bar[/baz]]"),
STR("/foo/bar/baz[(1 or 2) + 3 * 4 + 8 and 9]"), STR("/foo/bar/baz"), STR("(.)[1]"), STR("self::node()"), STR("."), STR("count(/)"),
STR("foo[1]"), STR("/baz[(1 or 2) + 3 * 4 + 8 and 9]"), STR("foo/bar[/baz[(1 or 2) - 3 mod 4 + 8 and 9 div 8]]"),
STR("foo/bar/yeah:baz[a/b/c and toast]"), STR("/foo/bar[../x='123']"), STR("/foo[@bar='1234']"), STR("foo|bar"),
STR("/foo|/bar[@id='1234']"), STR("count(//author/attribute::*)"), STR("/child::node()/child::node()[@id='_13563275']"),
STR("10 + (count(descendant::author) * 5)"), STR("10 + count(descendant::author) * 5"), STR("2 + (2 * 5)"), STR("//foo:bar"),
STR("count(//author)+5"), STR("count(//author)+count(//author/attribute::*)"), STR("/foo/bar[@a='1' and @c!='2']"),
STR("12 + (count(//author)+count(//author/attribute::*)) div 2"), STR("text()[.='foo']"), STR("/*/*[@id='123']")
STR("/foo/bar[@a='1' and @b='2']"), STR("/foo/bar[@a='1' and @b!='2']"), STR("//attribute::*[.!='crunchy']"),
STR("'//*[contains(string(text()),\"yada yada\")]'"),
const char_t* paths[] =
{
// From Jaxen tests
STR("foo[.='bar']"), STR("foo[.!='bar']"), STR("/"), STR("*"), STR("//foo"), STR("/*"), STR("/."), STR("/foo[/bar[/baz]]"),
STR("/foo/bar/baz[(1 or 2) + 3 * 4 + 8 and 9]"), STR("/foo/bar/baz"), STR("(.)[1]"), STR("self::node()"), STR("."), STR("count(/)"),
STR("foo[1]"), STR("/baz[(1 or 2) + 3 * 4 + 8 and 9]"), STR("foo/bar[/baz[(1 or 2) - 3 mod 4 + 8 and 9 div 8]]"),
STR("foo/bar/yeah:baz[a/b/c and toast]"), STR("/foo/bar[../x='123']"), STR("/foo[@bar='1234']"), STR("foo|bar"),
STR("/foo|/bar[@id='1234']"), STR("count(//author/attribute::*)"), STR("/child::node()/child::node()[@id='_13563275']"),
STR("10 + (count(descendant::author) * 5)"), STR("10 + count(descendant::author) * 5"), STR("2 + (2 * 5)"), STR("//foo:bar"),
STR("count(//author)+5"), STR("count(//author)+count(//author/attribute::*)"), STR("/foo/bar[@a='1' and @c!='2']"),
STR("12 + (count(//author)+count(//author/attribute::*)) div 2"), STR("text()[.='foo']"), STR("/*/*[@id='123']") STR("/foo/bar[@a='1' and @b='2']"), STR("/foo/bar[@a='1' and @b!='2']"), STR("//attribute::*[.!='crunchy']"),
STR("'//*[contains(string(text()),\"yada yada\")]'"),
// From ajaxslt tests
STR("@*"), STR("@*|node()"), STR("/descendant-or-self::div"), STR("/div"), STR("//div"), STR("/descendant-or-self::node()/child::para"),
STR("substring('12345', 0, 3)"), STR("//title | //link"), STR("x//title"), STR("x/title"), STR("id('a')//title"), STR("//*[@about]"),
STR("count(descendant::*)"), STR("count(descendant::*) + count(ancestor::*)"), STR("@*|text()"), STR("*|/"), STR("source|destination"),
STR("page != 'to' and page != 'from'"), STR("substring-after(icon/@image, '/mapfiles/marker')"), STR("substring-before(str, c)"), STR("page = 'from'"),
STR("segments/@time"), STR("child::para"), STR("child::*"), STR("child::text()"), STR("child::node()"), STR("attribute::name"), STR("attribute::*"),
STR("descendant::para"), STR("ancestor::div"), STR("ancestor-or-self::div"), STR("descendant-or-self::para"), STR("self::para"), STR("child::*/child::para"),
STR("concat(substring-before(@image,'marker'),'icon',substring-after(@image,'marker'))"), STR("/"), STR("/descendant::para"), STR("/descendant::olist/child::item"),
STR("child::para[position()=1]"), STR("child::para[position()=last()]"), STR("child::para[position()=last()-1]"), STR("child::para[position()>1]"),
STR("following-sibling::chapter[position()=1]"), STR("preceding-sibling::chapter[position()=1]"), STR("/descendant::figure[position()=42]"),
STR("/child::doc/child::chapter[position()=5]/child::section[position()=2]"), STR("child::chapter/descendant::para"), STR("child::para[attribute::type='warning']"),
STR("child::para[attribute::type='warning'][position()=5]"), STR("child::para[position()=5][attribute::type='warning']"), STR("child::chapter[child::title='Introduction']"),
STR("child::chapter[child::title]"), STR("child::*[self::chapter or self::appendix]"), STR("child::*[self::chapter or self::appendix][position()=last()]"),
STR("count(//*[id='u1']|//*[id='u2'])"), STR("count(//*[id='u1']|//*[class='u'])"), STR("count(//*[class='u']|//*[class='u'])"), STR("count(//*[class='u']|//*[id='u1'])"),
STR("count(//*[@id='self']/ancestor-or-self::*)"), STR("count(//*[@id='self']/ancestor::*)"), STR("count(//*[@id='self']/attribute::*)"), STR("count(//*[@id='self']/child::*)"),
STR("count(//*[@id='self']/descendant-or-self::*)"), STR("count(//*[@id='self']/descendant::*)"), STR("count(//*[@id='self']/following-sibling::*)"),
STR("count(//*[@id='self']/following::*)"), STR("//*[@id='self']/parent::*/@id"), STR("count(//*[@id='self']/preceding-sibling::*)"),
STR("count(//*[@id='self']/preceding::*)"), STR("//*[@id='self']/self::*/@id"), STR("id('nested1')/div[1]//input[2]"), STR("id('foo')//div[contains(@id, 'useful')]//input"),
STR("(//table[@class='stylee'])//th[text()='theHeaderText']/../td"), STR("address"), STR("address=string(/page/user/defaultlocation)"), STR("count-of-snippet-of-url = 0"),
STR("daddr"), STR("form"), STR("form = 'from'"), STR("form = 'to'"), STR("form='near'"), STR("home"), STR("i"), STR("i > page and i < page + range"),
STR("i < page and i >= page - range"), STR("i < @max"), STR("i <= page"), STR("i + 1"), STR("i = page"), STR("i = 1"), STR("info = position() or (not(info) and position() = 1)"),
STR("is-first-order"), STR("is-first-order and snippets-exist"), STR("more"), STR("more > 0"), STR("near-point"), STR("page"), STR("page != 'from'"), STR("page != 'to'"),
STR("page != 'to' and page != 'from'"), STR("page > 1"), STR("page = 'basics'"), STR("page = 'details'"), STR("page = 'from'"), STR("page = 'to'"), STR("page='from'"),
STR("page='to'"), STR("r >= 0.5"), STR("r >= 1"), STR("r - 0"), STR("r - 1"), STR("r - 2"), STR("r - 3"), STR("r - 4"), STR("saddr"), STR("sources"), STR("sources[position() < details]"),
STR("src"), STR("str"), STR("\"'\""), STR("(//location[string(info/references/reference[1]/url)=string(current-url)]/info/references/reference[1])[1]"),
STR("(not(count-of-snippet-of-url = 0) and (position() = 1) or not(current-url = //locations/location[position() = last-pos]//reference[1]/url))"),
STR("(not(info) and position() = 1) or info = position()"), STR("."), STR("../@arg0"), STR("../@filterpng"), STR("/page/@filterpng"), STR("4"), STR("@attribution"),
STR("@id"), STR("@max > @num"), STR("@meters > 16093"), STR("@name"), STR("@start div @num + 1"), STR("@url"), STR("ad"), STR("address/line"), STR("adsmessage"),
STR("attr"), STR("boolean(location[@id='near'][icon/@image])"), STR("bubble/node()"), STR("calltoaction/node()"), STR("category"), STR("contains(str, c)"),
STR("count(//location[string(info/references/reference[1]/url)=string(current-url)]//snippet)"), STR("count(//snippet)"), STR("count(attr)"), STR("count(location)"),
STR("count(structured/source) > 1"), STR("description/node()"), STR("destination"), STR("destinationAddress"), STR("domain"), STR("false()"), STR("icon/@class != 'noicon'"),
STR("icon/@image"), STR("info"), STR("info/address/line"), STR("info/distance"), STR("info/distance and near-point"), STR("info/distance and info/phone and near-point"),
STR("info/distance or info/phone"), STR("info/panel/node()"), STR("info/phone"), STR("info/references/reference[1]"), STR("info/references/reference[1]/snippet"),
STR("info/references/reference[1]/url"), STR("info/title"), STR("info/title/node()"), STR("line"), STR("location"), STR("location[@id!='near']"), STR("location[@id='near'][icon/@image]"),
STR("location[position() > umlocations div 2]"), STR("location[position() <= numlocations div 2]"), STR("locations"), STR("locations/location"), STR("near"), STR("node()"),
STR("not(count-of-snippets = 0)"), STR("not(form = 'from')"), STR("not(form = 'near')"), STR("not(form = 'to')"), STR("not(../@page)"), STR("not(structured/source)"), STR("notice"),
STR("number(../@info)"), STR("number(../@items)"), STR("number(/page/@linewidth)"), STR("page/ads"), STR("page/directions"), STR("page/error"), STR("page/overlay"),
STR("page/overlay/locations/location"), STR("page/refinements"), STR("page/request/canonicalnear"), STR("page/request/near"), STR("page/request/query"), STR("page/spelling/suggestion"),
STR("page/user/defaultlocation"), STR("phone"), STR("position()"), STR("position() != 1"), STR("position() != last()"), STR("position() > 1"), STR("position() < details"),
STR("position()-1"), STR("query"), STR("references/@total"), STR("references/reference"), STR("references/reference/domain"), STR("references/reference/url"),
STR("reviews/@positive div (reviews/@positive + reviews/@negative) * 5"), STR("reviews/@positive div (reviews/@positive + reviews/@negative) * (5)"), STR("reviews/@total"),
STR("reviews/@total > 1"), STR("reviews/@total > 5"), STR("reviews/@total = 1"), STR("segments/@distance"), STR("segments/@time"), STR("segments/segment"), STR("shorttitle/node()"),
STR("snippet"), STR("snippet/node()"), STR("source"), STR("sourceAddress"), STR("sourceAddress and destinationAddress"), STR("string(../@daddr)"), STR("string(../@form)"),
STR("string(../@page)"), STR("string(../@saddr)"), STR("string(info/title)"), STR("string(page/request/canonicalnear) != ''"), STR("string(page/request/near) != ''"),
STR("string-length(address) > linewidth"), STR("structured/@total - details"), STR("structured/source"), STR("structured/source[@name]"), STR("substring(address, 1, linewidth - 3)"),
STR("substring-after(str, c)"), STR("substring-after(icon/@image, '/mapfiles/marker')"), STR("substring-before(str, c)"), STR("tagline/node()"), STR("targetedlocation"),
STR("title"), STR("title/node()"), STR("true()"), STR("url"), STR("visibleurl"), STR("id(\"level10\")/ancestor::SPAN"), STR("id(\"level10\")/ancestor-or-self::SPAN"), STR("//attribute::*"),
STR("child::HTML/child::BODY/child::H1"), STR("descendant::node()"), STR("descendant-or-self::SPAN"), STR("id(\"first\")/following::text()"), STR("id(\"first\")/following-sibling::node()"),
STR("id(\"level10\")/parent::node()"), STR("id(\"last\")/preceding::text()"), STR("id(\"last\")/preceding-sibling::node()"), STR("/HTML/BODY/H1/self::node()"), STR("//*[@name]"),
STR("id(\"pet\")/SELECT[@name=\"species\"]/OPTION[@selected]/@value"), STR("descendant::INPUT[@name=\"name\"]/@value"), STR("id(\"pet\")/INPUT[@name=\"gender\" and @checked]/@value"),
STR("//TEXTAREA[@name=\"description\"]/text()"), STR("id(\"div1\")|id(\"div2\")|id(\"div3 div4 div5\")"), STR("//LI[1]"), STR("//LI[last()]/text()"), STR("//LI[position() mod 2]/@class"),
STR("//text()[.=\"foo\"]"), STR("descendant-or-self::SPAN[position() > 2]"), STR("descendant::*[contains(@class,\" fruit \")]"),
// From ajaxslt tests
STR("@*"), STR("@*|node()"), STR("/descendant-or-self::div"), STR("/div"), STR("//div"), STR("/descendant-or-self::node()/child::para"),
STR("substring('12345', 0, 3)"), STR("//title | //link"), STR("x//title"), STR("x/title"), STR("id('a')//title"), STR("//*[@about]"),
STR("count(descendant::*)"), STR("count(descendant::*) + count(ancestor::*)"), STR("@*|text()"), STR("*|/"), STR("source|destination"),
STR("page != 'to' and page != 'from'"), STR("substring-after(icon/@image, '/mapfiles/marker')"), STR("substring-before(str, c)"), STR("page = 'from'"),
STR("segments/@time"), STR("child::para"), STR("child::*"), STR("child::text()"), STR("child::node()"), STR("attribute::name"), STR("attribute::*"),
STR("descendant::para"), STR("ancestor::div"), STR("ancestor-or-self::div"), STR("descendant-or-self::para"), STR("self::para"), STR("child::*/child::para"),
STR("concat(substring-before(@image,'marker'),'icon',substring-after(@image,'marker'))"), STR("/"), STR("/descendant::para"), STR("/descendant::olist/child::item"),
STR("child::para[position()=1]"), STR("child::para[position()=last()]"), STR("child::para[position()=last()-1]"), STR("child::para[position()>1]"),
STR("following-sibling::chapter[position()=1]"), STR("preceding-sibling::chapter[position()=1]"), STR("/descendant::figure[position()=42]"),
STR("/child::doc/child::chapter[position()=5]/child::section[position()=2]"), STR("child::chapter/descendant::para"), STR("child::para[attribute::type='warning']"),
STR("child::para[attribute::type='warning'][position()=5]"), STR("child::para[position()=5][attribute::type='warning']"), STR("child::chapter[child::title='Introduction']"),
STR("child::chapter[child::title]"), STR("child::*[self::chapter or self::appendix]"), STR("child::*[self::chapter or self::appendix][position()=last()]"),
STR("count(//*[id='u1']|//*[id='u2'])"), STR("count(//*[id='u1']|//*[class='u'])"), STR("count(//*[class='u']|//*[class='u'])"), STR("count(//*[class='u']|//*[id='u1'])"),
STR("count(//*[@id='self']/ancestor-or-self::*)"), STR("count(//*[@id='self']/ancestor::*)"), STR("count(//*[@id='self']/attribute::*)"), STR("count(//*[@id='self']/child::*)"),
STR("count(//*[@id='self']/descendant-or-self::*)"), STR("count(//*[@id='self']/descendant::*)"), STR("count(//*[@id='self']/following-sibling::*)"),
STR("count(//*[@id='self']/following::*)"), STR("//*[@id='self']/parent::*/@id"), STR("count(//*[@id='self']/preceding-sibling::*)"),
STR("count(//*[@id='self']/preceding::*)"), STR("//*[@id='self']/self::*/@id"), STR("id('nested1')/div[1]//input[2]"), STR("id('foo')//div[contains(@id, 'useful')]//input"),
STR("(//table[@class='stylee'])//th[text()='theHeaderText']/../td"), STR("address"), STR("address=string(/page/user/defaultlocation)"), STR("count-of-snippet-of-url = 0"),
STR("daddr"), STR("form"), STR("form = 'from'"), STR("form = 'to'"), STR("form='near'"), STR("home"), STR("i"), STR("i > page and i < page + range"),
STR("i < page and i >= page - range"), STR("i < @max"), STR("i <= page"), STR("i + 1"), STR("i = page"), STR("i = 1"), STR("info = position() or (not(info) and position() = 1)"),
STR("is-first-order"), STR("is-first-order and snippets-exist"), STR("more"), STR("more > 0"), STR("near-point"), STR("page"), STR("page != 'from'"), STR("page != 'to'"),
STR("page != 'to' and page != 'from'"), STR("page > 1"), STR("page = 'basics'"), STR("page = 'details'"), STR("page = 'from'"), STR("page = 'to'"), STR("page='from'"),
STR("page='to'"), STR("r >= 0.5"), STR("r >= 1"), STR("r - 0"), STR("r - 1"), STR("r - 2"), STR("r - 3"), STR("r - 4"), STR("saddr"), STR("sources"), STR("sources[position() < details]"),
STR("src"), STR("str"), STR("\"'\""), STR("(//location[string(info/references/reference[1]/url)=string(current-url)]/info/references/reference[1])[1]"),
STR("(not(count-of-snippet-of-url = 0) and (position() = 1) or not(current-url = //locations/location[position() = last-pos]//reference[1]/url))"),
STR("(not(info) and position() = 1) or info = position()"), STR("."), STR("../@arg0"), STR("../@filterpng"), STR("/page/@filterpng"), STR("4"), STR("@attribution"),
STR("@id"), STR("@max > @num"), STR("@meters > 16093"), STR("@name"), STR("@start div @num + 1"), STR("@url"), STR("ad"), STR("address/line"), STR("adsmessage"),
STR("attr"), STR("boolean(location[@id='near'][icon/@image])"), STR("bubble/node()"), STR("calltoaction/node()"), STR("category"), STR("contains(str, c)"),
STR("count(//location[string(info/references/reference[1]/url)=string(current-url)]//snippet)"), STR("count(//snippet)"), STR("count(attr)"), STR("count(location)"),
STR("count(structured/source) > 1"), STR("description/node()"), STR("destination"), STR("destinationAddress"), STR("domain"), STR("false()"), STR("icon/@class != 'noicon'"),
STR("icon/@image"), STR("info"), STR("info/address/line"), STR("info/distance"), STR("info/distance and near-point"), STR("info/distance and info/phone and near-point"),
STR("info/distance or info/phone"), STR("info/panel/node()"), STR("info/phone"), STR("info/references/reference[1]"), STR("info/references/reference[1]/snippet"),
STR("info/references/reference[1]/url"), STR("info/title"), STR("info/title/node()"), STR("line"), STR("location"), STR("location[@id!='near']"), STR("location[@id='near'][icon/@image]"),
STR("location[position() > umlocations div 2]"), STR("location[position() <= numlocations div 2]"), STR("locations"), STR("locations/location"), STR("near"), STR("node()"),
STR("not(count-of-snippets = 0)"), STR("not(form = 'from')"), STR("not(form = 'near')"), STR("not(form = 'to')"), STR("not(../@page)"), STR("not(structured/source)"), STR("notice"),
STR("number(../@info)"), STR("number(../@items)"), STR("number(/page/@linewidth)"), STR("page/ads"), STR("page/directions"), STR("page/error"), STR("page/overlay"),
STR("page/overlay/locations/location"), STR("page/refinements"), STR("page/request/canonicalnear"), STR("page/request/near"), STR("page/request/query"), STR("page/spelling/suggestion"),
STR("page/user/defaultlocation"), STR("phone"), STR("position()"), STR("position() != 1"), STR("position() != last()"), STR("position() > 1"), STR("position() < details"),
STR("position()-1"), STR("query"), STR("references/@total"), STR("references/reference"), STR("references/reference/domain"), STR("references/reference/url"),
STR("reviews/@positive div (reviews/@positive + reviews/@negative) * 5"), STR("reviews/@positive div (reviews/@positive + reviews/@negative) * (5)"), STR("reviews/@total"),
STR("reviews/@total > 1"), STR("reviews/@total > 5"), STR("reviews/@total = 1"), STR("segments/@distance"), STR("segments/@time"), STR("segments/segment"), STR("shorttitle/node()"),
STR("snippet"), STR("snippet/node()"), STR("source"), STR("sourceAddress"), STR("sourceAddress and destinationAddress"), STR("string(../@daddr)"), STR("string(../@form)"),
STR("string(../@page)"), STR("string(../@saddr)"), STR("string(info/title)"), STR("string(page/request/canonicalnear) != ''"), STR("string(page/request/near) != ''"),
STR("string-length(address) > linewidth"), STR("structured/@total - details"), STR("structured/source"), STR("structured/source[@name]"), STR("substring(address, 1, linewidth - 3)"),
STR("substring-after(str, c)"), STR("substring-after(icon/@image, '/mapfiles/marker')"), STR("substring-before(str, c)"), STR("tagline/node()"), STR("targetedlocation"),
STR("title"), STR("title/node()"), STR("true()"), STR("url"), STR("visibleurl"), STR("id(\"level10\")/ancestor::SPAN"), STR("id(\"level10\")/ancestor-or-self::SPAN"), STR("//attribute::*"),
STR("child::HTML/child::BODY/child::H1"), STR("descendant::node()"), STR("descendant-or-self::SPAN"), STR("id(\"first\")/following::text()"), STR("id(\"first\")/following-sibling::node()"),
STR("id(\"level10\")/parent::node()"), STR("id(\"last\")/preceding::text()"), STR("id(\"last\")/preceding-sibling::node()"), STR("/HTML/BODY/H1/self::node()"), STR("//*[@name]"),
STR("id(\"pet\")/SELECT[@name=\"species\"]/OPTION[@selected]/@value"), STR("descendant::INPUT[@name=\"name\"]/@value"), STR("id(\"pet\")/INPUT[@name=\"gender\" and @checked]/@value"),
STR("//TEXTAREA[@name=\"description\"]/text()"), STR("id(\"div1\")|id(\"div2\")|id(\"div3 div4 div5\")"), STR("//LI[1]"), STR("//LI[last()]/text()"), STR("//LI[position() mod 2]/@class"),
STR("//text()[.=\"foo\"]"), STR("descendant-or-self::SPAN[position() > 2]"), STR("descendant::*[contains(@class,\" fruit \")]"),
// ajaxslt considers this path invalid, however I believe it's valid as per spec
STR("***"),
// ajaxslt considers this path invalid, however I believe it's valid as per spec
STR("***"),
// Oasis MSFT considers this path invalid, however I believe it's valid as per spec
STR("**..**"),
// Oasis MSFT considers this path invalid, however I believe it's valid as per spec
STR("**..**"),
// Miscellaneous
STR("..***..***.***.***..***..***..")
};
// Miscellaneous
STR("..***..***.***.***..***..***..")};
for (size_t i = 0; i < sizeof(paths) / sizeof(paths[0]); ++i)
{
@ -185,73 +183,125 @@ TEST(xpath_parse_paths_valid)
#if defined(PUGIXML_WCHAR_MODE) || !defined(PUGIXML_NO_STL)
TEST(xpath_parse_paths_valid_unicode)
{
// From ajaxslt
// From ajaxslt
const wchar_t* paths[] =
{
#ifdef U_LITERALS
L"/descendant-or-self::\u90e8\u5206", L"//\u90e8\u5206", L"substring('\uff11\uff12\uff13\uff14\uff15', 0, 3)", L"//\u30bf\u30a4\u30c8\u30eb | //\u30ea\u30f3\u30af",
L"\u8b0e//\u30bf\u30a4\u30c8\u30eb", L"//*[@\u30c7\u30b9\u30c6\u30a3\u30cd\u30a4\u30b7\u30e7\u30f3]", L"\u30da\u30fc\u30b8 = '\u304b\u3089'",
L"concat(substring-before(@\u30a4\u30e1\u30fc\u30b8,'\u76ee\u5370'),'\u30a2\u30a4\u30b3\u30f3',substring-after(@\u30a4\u30e1\u30fc\u30b8,'\u76ee\u5370'))",
L"\u30bd\u30fc\u30b9|\u30c7\u30b9\u30c6\u30a3\u30cd\u30a4\u30b7\u30e7\u30f3", L"\u30da\u30fc\u30b8 != '\u307e\u3067' and \u30da\u30fc\u30b8 != '\u304b\u3089'",
L"substring-after(\u30a2\u30a4\u30b3\u30f3/@\u30a4\u30e1\u30fc\u30b8, '/\u5730\u56f3\u30d5\u30a1\u30a4\u30eb/\u76ee\u5370')", L"child::\u6bb5\u843d",
L"substring-before(\u6587\u5b57\u5217, \u6587\u5b57)", L"\u30bb\u30b0\u30e1\u30f3\u30c8/@\u6642\u523b", L"attribute::\u540d\u524d", L"descendant::\u6bb5\u843d",
L"ancestor::\u90e8\u5206", L"ancestor-or-self::\u90e8\u5206", L"descendant-or-self::\u6bb5\u843d", L"self::\u6bb5\u843d", L"child::\u7ae0/descendant::\u6bb5\u843d",
L"child::*/child::\u6bb5\u843d", L"/descendant::\u6bb5\u843d", L"/descendant::\u9806\u5e8f\u30ea\u30b9\u30c8/child::\u9805\u76ee", L"child::\u6bb5\u843d[position()=1]",
L"child::\u6bb5\u843d[position()=last()]", L"child::\u6bb5\u843d[position()=last()-1]", L"child::\u6bb5\u843d[position()>1]", L"following-sibling::\u7ae0[position()=1]",
L"preceding-sibling::\u7ae0[position()=1]", L"/descendant::\u56f3\u8868[position()=42]", L"/child::\u6587\u66f8/child::\u7ae0[position()=5]/child::\u7bc0[position()=2]",
L"child::\u6bb5\u843d[attribute::\u30bf\u30a4\u30d7='\u8b66\u544a']", L"child::\u6bb5\u843d[attribute::\u30bf\u30a4\u30d7='\u8b66\u544a'][position()=5]",
L"child::\u6bb5\u843d[position()=5][attribute::\u30bf\u30a4\u30d7='\u8b66\u544a']", L"child::\u7ae0[child::\u30bf\u30a4\u30c8\u30eb='\u306f\u3058\u3081\u306b']",
L"child::\u7ae0[child::\u30bf\u30a4\u30c8\u30eb]", L"child::*[self::\u7ae0 or self::\u4ed8\u9332]", L"child::*[self::\u7ae0 or self::\u4ed8\u9332][position()=last()]",
#else
L"/descendant-or-self::\x90e8\x5206", L"//\x90e8\x5206", L"substring('\xff11\xff12\xff13\xff14\xff15', 0, 3)", L"//\x30bf\x30a4\x30c8\x30eb | //\x30ea\x30f3\x30af",
L"\x8b0e//\x30bf\x30a4\x30c8\x30eb", L"//*[@\x30c7\x30b9\x30c6\x30a3\x30cd\x30a4\x30b7\x30e7\x30f3]", L"\x30da\x30fc\x30b8 = '\x304b\x3089'",
L"concat(substring-before(@\x30a4\x30e1\x30fc\x30b8,'\x76ee\x5370'),'\x30a2\x30a4\x30b3\x30f3',substring-after(@\x30a4\x30e1\x30fc\x30b8,'\x76ee\x5370'))",
L"\x30bd\x30fc\x30b9|\x30c7\x30b9\x30c6\x30a3\x30cd\x30a4\x30b7\x30e7\x30f3", L"\x30da\x30fc\x30b8 != '\x307e\x3067' and \x30da\x30fc\x30b8 != '\x304b\x3089'",
L"substring-after(\x30a2\x30a4\x30b3\x30f3/@\x30a4\x30e1\x30fc\x30b8, '/\x5730\x56f3\x30d5\x30a1\x30a4\x30eb/\x76ee\x5370')", L"child::\x6bb5\x843d",
L"substring-before(\x6587\x5b57\x5217, \x6587\x5b57)", L"\x30bb\x30b0\x30e1\x30f3\x30c8/@\x6642\x523b", L"attribute::\x540d\x524d", L"descendant::\x6bb5\x843d",
L"ancestor::\x90e8\x5206", L"ancestor-or-self::\x90e8\x5206", L"descendant-or-self::\x6bb5\x843d", L"self::\x6bb5\x843d", L"child::\x7ae0/descendant::\x6bb5\x843d",
L"child::*/child::\x6bb5\x843d", L"/descendant::\x6bb5\x843d", L"/descendant::\x9806\x5e8f\x30ea\x30b9\x30c8/child::\x9805\x76ee", L"child::\x6bb5\x843d[position()=1]",
L"child::\x6bb5\x843d[position()=last()]", L"child::\x6bb5\x843d[position()=last()-1]", L"child::\x6bb5\x843d[position()>1]", L"following-sibling::\x7ae0[position()=1]",
L"preceding-sibling::\x7ae0[position()=1]", L"/descendant::\x56f3\x8868[position()=42]", L"/child::\x6587\x66f8/child::\x7ae0[position()=5]/child::\x7bc0[position()=2]",
L"child::\x6bb5\x843d[attribute::\x30bf\x30a4\x30d7='\x8b66\x544a']", L"child::\x6bb5\x843d[attribute::\x30bf\x30a4\x30d7='\x8b66\x544a'][position()=5]",
L"child::\x6bb5\x843d[position()=5][attribute::\x30bf\x30a4\x30d7='\x8b66\x544a']", L"child::\x7ae0[child::\x30bf\x30a4\x30c8\x30eb='\x306f\x3058\x3081\x306b']",
L"child::\x7ae0[child::\x30bf\x30a4\x30c8\x30eb]", L"child::*[self::\x7ae0 or self::\x4ed8\x9332]", L"child::*[self::\x7ae0 or self::\x4ed8\x9332][position()=last()]",
#endif
};
{
#ifdef U_LITERALS
L"/descendant-or-self::\u90e8\u5206",
L"//\u90e8\u5206",
L"substring('\uff11\uff12\uff13\uff14\uff15', 0, 3)",
L"//\u30bf\u30a4\u30c8\u30eb | //\u30ea\u30f3\u30af",
L"\u8b0e//\u30bf\u30a4\u30c8\u30eb",
L"//*[@\u30c7\u30b9\u30c6\u30a3\u30cd\u30a4\u30b7\u30e7\u30f3]",
L"\u30da\u30fc\u30b8 = '\u304b\u3089'",
L"concat(substring-before(@\u30a4\u30e1\u30fc\u30b8,'\u76ee\u5370'),'\u30a2\u30a4\u30b3\u30f3',substring-after(@\u30a4\u30e1\u30fc\u30b8,'\u76ee\u5370'))",
L"\u30bd\u30fc\u30b9|\u30c7\u30b9\u30c6\u30a3\u30cd\u30a4\u30b7\u30e7\u30f3",
L"\u30da\u30fc\u30b8 != '\u307e\u3067' and \u30da\u30fc\u30b8 != '\u304b\u3089'",
L"substring-after(\u30a2\u30a4\u30b3\u30f3/@\u30a4\u30e1\u30fc\u30b8, '/\u5730\u56f3\u30d5\u30a1\u30a4\u30eb/\u76ee\u5370')",
L"child::\u6bb5\u843d",
L"substring-before(\u6587\u5b57\u5217, \u6587\u5b57)",
L"\u30bb\u30b0\u30e1\u30f3\u30c8/@\u6642\u523b",
L"attribute::\u540d\u524d",
L"descendant::\u6bb5\u843d",
L"ancestor::\u90e8\u5206",
L"ancestor-or-self::\u90e8\u5206",
L"descendant-or-self::\u6bb5\u843d",
L"self::\u6bb5\u843d",
L"child::\u7ae0/descendant::\u6bb5\u843d",
L"child::*/child::\u6bb5\u843d",
L"/descendant::\u6bb5\u843d",
L"/descendant::\u9806\u5e8f\u30ea\u30b9\u30c8/child::\u9805\u76ee",
L"child::\u6bb5\u843d[position()=1]",
L"child::\u6bb5\u843d[position()=last()]",
L"child::\u6bb5\u843d[position()=last()-1]",
L"child::\u6bb5\u843d[position()>1]",
L"following-sibling::\u7ae0[position()=1]",
L"preceding-sibling::\u7ae0[position()=1]",
L"/descendant::\u56f3\u8868[position()=42]",
L"/child::\u6587\u66f8/child::\u7ae0[position()=5]/child::\u7bc0[position()=2]",
L"child::\u6bb5\u843d[attribute::\u30bf\u30a4\u30d7='\u8b66\u544a']",
L"child::\u6bb5\u843d[attribute::\u30bf\u30a4\u30d7='\u8b66\u544a'][position()=5]",
L"child::\u6bb5\u843d[position()=5][attribute::\u30bf\u30a4\u30d7='\u8b66\u544a']",
L"child::\u7ae0[child::\u30bf\u30a4\u30c8\u30eb='\u306f\u3058\u3081\u306b']",
L"child::\u7ae0[child::\u30bf\u30a4\u30c8\u30eb]",
L"child::*[self::\u7ae0 or self::\u4ed8\u9332]",
L"child::*[self::\u7ae0 or self::\u4ed8\u9332][position()=last()]",
#else
L"/descendant-or-self::\x90e8\x5206",
L"//\x90e8\x5206",
L"substring('\xff11\xff12\xff13\xff14\xff15', 0, 3)",
L"//\x30bf\x30a4\x30c8\x30eb | //\x30ea\x30f3\x30af",
L"\x8b0e//\x30bf\x30a4\x30c8\x30eb",
L"//*[@\x30c7\x30b9\x30c6\x30a3\x30cd\x30a4\x30b7\x30e7\x30f3]",
L"\x30da\x30fc\x30b8 = '\x304b\x3089'",
L"concat(substring-before(@\x30a4\x30e1\x30fc\x30b8,'\x76ee\x5370'),'\x30a2\x30a4\x30b3\x30f3',substring-after(@\x30a4\x30e1\x30fc\x30b8,'\x76ee\x5370'))",
L"\x30bd\x30fc\x30b9|\x30c7\x30b9\x30c6\x30a3\x30cd\x30a4\x30b7\x30e7\x30f3",
L"\x30da\x30fc\x30b8 != '\x307e\x3067' and \x30da\x30fc\x30b8 != '\x304b\x3089'",
L"substring-after(\x30a2\x30a4\x30b3\x30f3/@\x30a4\x30e1\x30fc\x30b8, '/\x5730\x56f3\x30d5\x30a1\x30a4\x30eb/\x76ee\x5370')",
L"child::\x6bb5\x843d",
L"substring-before(\x6587\x5b57\x5217, \x6587\x5b57)",
L"\x30bb\x30b0\x30e1\x30f3\x30c8/@\x6642\x523b",
L"attribute::\x540d\x524d",
L"descendant::\x6bb5\x843d",
L"ancestor::\x90e8\x5206",
L"ancestor-or-self::\x90e8\x5206",
L"descendant-or-self::\x6bb5\x843d",
L"self::\x6bb5\x843d",
L"child::\x7ae0/descendant::\x6bb5\x843d",
L"child::*/child::\x6bb5\x843d",
L"/descendant::\x6bb5\x843d",
L"/descendant::\x9806\x5e8f\x30ea\x30b9\x30c8/child::\x9805\x76ee",
L"child::\x6bb5\x843d[position()=1]",
L"child::\x6bb5\x843d[position()=last()]",
L"child::\x6bb5\x843d[position()=last()-1]",
L"child::\x6bb5\x843d[position()>1]",
L"following-sibling::\x7ae0[position()=1]",
L"preceding-sibling::\x7ae0[position()=1]",
L"/descendant::\x56f3\x8868[position()=42]",
L"/child::\x6587\x66f8/child::\x7ae0[position()=5]/child::\x7bc0[position()=2]",
L"child::\x6bb5\x843d[attribute::\x30bf\x30a4\x30d7='\x8b66\x544a']",
L"child::\x6bb5\x843d[attribute::\x30bf\x30a4\x30d7='\x8b66\x544a'][position()=5]",
L"child::\x6bb5\x843d[position()=5][attribute::\x30bf\x30a4\x30d7='\x8b66\x544a']",
L"child::\x7ae0[child::\x30bf\x30a4\x30c8\x30eb='\x306f\x3058\x3081\x306b']",
L"child::\x7ae0[child::\x30bf\x30a4\x30c8\x30eb]",
L"child::*[self::\x7ae0 or self::\x4ed8\x9332]",
L"child::*[self::\x7ae0 or self::\x4ed8\x9332][position()=last()]",
#endif
};
for (size_t i = 0; i < sizeof(paths) / sizeof(paths[0]); ++i)
{
#if defined(PUGIXML_WCHAR_MODE)
#if defined(PUGIXML_WCHAR_MODE)
xpath_query q(paths[i]);
#elif !defined(PUGIXML_NO_STL)
#elif !defined(PUGIXML_NO_STL)
std::basic_string<char> path_utf8 = as_utf8(paths[i]);
xpath_query q(path_utf8.c_str());
#endif
#endif
}
}
#endif
TEST(xpath_parse_invalid)
{
const char_t* paths[] =
{
// From Jaxen tests
STR("//:p"), STR("/foo/bar/"), STR("12 + (count(//author)+count(//author/attribute::*)) / 2"), STR("id()/2"), STR("+"),
STR("///triple slash"), STR("/numbers numbers"), STR("/a/b[c > d]efg"), STR("/inv/child::"), STR("/invoice/@test[abcd"),
STR("/invoice/@test[abcd > x"), STR("string-length('a"), STR("/descendant::()"), STR("(1 + 1"), STR("!false()"),
STR("$author"), STR("10 + $foo"), STR("$foo:bar"), STR("$varname[@a='1']"), STR("foo/$variable/foo"),
STR(".[1]"), STR("chyld::foo"), STR("foo/tacos()"), STR("foo/tacos()"), STR("/foo/bar[baz"), STR("//"), STR("*:foo"),
STR("/cracker/cheese[(mold > 1) and (sense/taste"),
const char_t* paths[] =
{
// From Jaxen tests
STR("//:p"), STR("/foo/bar/"), STR("12 + (count(//author)+count(//author/attribute::*)) / 2"), STR("id()/2"), STR("+"),
STR("///triple slash"), STR("/numbers numbers"), STR("/a/b[c > d]efg"), STR("/inv/child::"), STR("/invoice/@test[abcd"),
STR("/invoice/@test[abcd > x"), STR("string-length('a"), STR("/descendant::()"), STR("(1 + 1"), STR("!false()"),
STR("$author"), STR("10 + $foo"), STR("$foo:bar"), STR("$varname[@a='1']"), STR("foo/$variable/foo"),
STR(".[1]"), STR("chyld::foo"), STR("foo/tacos()"), STR("foo/tacos()"), STR("/foo/bar[baz"), STR("//"), STR("*:foo"),
STR("/cracker/cheese[(mold > 1) and (sense/taste"),
// From xpath-as3 tests
STR("a b"), STR("//self::node())"), STR("/x/y[contains(self::node())"), STR("/x/y[contains(self::node()]"), STR("///"), STR("text::a"),
// From xpath-as3 tests
STR("a b"), STR("//self::node())"), STR("/x/y[contains(self::node())"), STR("/x/y[contains(self::node()]"), STR("///"), STR("text::a"),
// From haXe-xpath tests
STR("|/gjs"), STR("+3"), STR("/html/body/p != ---'div'/a"), STR(""), STR("@"), STR("#akf"), STR(",")
// From haXe-xpath tests
STR("|/gjs"), STR("+3"), STR("/html/body/p != ---'div'/a"), STR(""), STR("@"), STR("#akf"), STR(",")
// Miscellaneous
STR("..."), STR("...."), STR("**"), STR("****"), STR("******"), STR("..***..***.***.***..***..***..*"), STR("/[1]")
};
// Miscellaneous
STR("..."),
STR("...."), STR("**"), STR("****"), STR("******"), STR("..***..***.***.***..***..***..*"), STR("/[1]")};
for (size_t i = 0; i < sizeof(paths) / sizeof(paths[0]); ++i)
{

View File

@ -27,9 +27,9 @@ TEST_XML(xpath_paths_axes_descendant, "<node attr='value'><child attr='value'><s
CHECK_XPATH_NODESET(c, STR("descendant:: node()"));
CHECK_XPATH_NODESET(n, STR("descendant:: node()")) % 4 % 6 % 7 % 8 % 9; // child, subchild, another, subchild, last
CHECK_XPATH_NODESET(n, STR("descendant:: node()")) % 4 % 6 % 7 % 8 % 9; // child, subchild, another, subchild, last
CHECK_XPATH_NODESET(doc, STR("descendant:: node()")) % 2 % 4 % 6 % 7 % 8 % 9; // node, child, subchild, another, subchild, last
CHECK_XPATH_NODESET(n, STR("another/descendant:: node()")) % 8; // subchild
CHECK_XPATH_NODESET(n, STR("another/descendant:: node()")) % 8; // subchild
CHECK_XPATH_NODESET(n, STR("last/descendant:: node()"));
CHECK_XPATH_NODESET(n, STR("@attr/descendant::node()"));
@ -45,9 +45,9 @@ TEST_XML(xpath_paths_axes_parent, "<node attr='value'><child attr='value'><subch
CHECK_XPATH_NODESET(c, STR("parent:: node()"));
CHECK_XPATH_NODESET(n.child(STR("child")), STR("parent:: node()")) % 2; // node
CHECK_XPATH_NODESET(n, STR("child/subchild/parent:: node()")) % 4; // child
CHECK_XPATH_NODESET(n, STR("@attr/parent:: node()")) % 2; // node
CHECK_XPATH_NODESET(n, STR("parent:: node()")) % 1; // root
CHECK_XPATH_NODESET(n, STR("child/subchild/parent:: node()")) % 4; // child
CHECK_XPATH_NODESET(n, STR("@attr/parent:: node()")) % 2; // node
CHECK_XPATH_NODESET(n, STR("parent:: node()")) % 1; // root
CHECK_XPATH_NODESET(doc, STR("parent:: node()"));
CHECK_XPATH_NODESET(na, STR("parent:: node()")) % 2; // node
@ -62,9 +62,9 @@ TEST_XML(xpath_paths_axes_ancestor, "<node attr='value'><child attr='value'><sub
CHECK_XPATH_NODESET(c, STR("ancestor:: node()"));
CHECK_XPATH_NODESET(n.child(STR("child")), STR("ancestor:: node()")) % 2 % 1; // node, root
CHECK_XPATH_NODESET(n, STR("child/subchild/ancestor:: node()")) % 4 % 2 % 1; // child, node, root
CHECK_XPATH_NODESET(n, STR("child/@attr/ancestor:: node()")) % 4 % 2 % 1; // child, node, root
CHECK_XPATH_NODESET(n, STR("ancestor:: node()")) % 1; // root
CHECK_XPATH_NODESET(n, STR("child/subchild/ancestor:: node()")) % 4 % 2 % 1; // child, node, root
CHECK_XPATH_NODESET(n, STR("child/@attr/ancestor:: node()")) % 4 % 2 % 1; // child, node, root
CHECK_XPATH_NODESET(n, STR("ancestor:: node()")) % 1; // root
CHECK_XPATH_NODESET(doc, STR("ancestor:: node()"));
CHECK_XPATH_NODESET(na, STR("ancestor:: node()")) % 4 % 2 % 1; // child, node, root
@ -82,7 +82,7 @@ TEST_XML(xpath_paths_axes_following_sibling, "<node attr1='value' attr2='value'>
CHECK_XPATH_NODESET(n.child(STR("last")), STR("following-sibling:: node()"));
CHECK_XPATH_NODESET(n, STR("@attr1/following-sibling:: node()")); // attributes are not siblings
CHECK_XPATH_NODESET(na, STR("following-sibling:: node()")); // attributes are not siblings
CHECK_XPATH_NODESET(na, STR("following-sibling:: node()")); // attributes are not siblings
}
TEST_XML(xpath_paths_axes_preceding_sibling, "<node attr1='value' attr2='value'><child attr='value'><subchild/></child><another><subchild/></another><last/></node>")
@ -97,7 +97,7 @@ TEST_XML(xpath_paths_axes_preceding_sibling, "<node attr1='value' attr2='value'>
CHECK_XPATH_NODESET(n.child(STR("last")), STR("preceding-sibling:: node()")) % 8 % 5; // another, child
CHECK_XPATH_NODESET(n, STR("@attr2/following-sibling:: node()")); // attributes are not siblings
CHECK_XPATH_NODESET(na, STR("following-sibling:: node()")); // attributes are not siblings
CHECK_XPATH_NODESET(na, STR("following-sibling:: node()")); // attributes are not siblings
}
TEST_XML(xpath_paths_axes_following, "<node attr1='value' attr2='value'><child attr='value'><subchild/></child><another><subchild/></another><almost/><last/></node>")
@ -108,14 +108,14 @@ TEST_XML(xpath_paths_axes_following, "<node attr1='value' attr2='value'><child a
CHECK_XPATH_NODESET(c, STR("following:: node()"));
CHECK_XPATH_NODESET(n, STR("following:: node()")); // no descendants
CHECK_XPATH_NODESET(n.child(STR("child")), STR("following:: node()")) % 8 % 9 % 10 % 11; // another, subchild, almost, last
CHECK_XPATH_NODESET(n, STR("following:: node()")); // no descendants
CHECK_XPATH_NODESET(n.child(STR("child")), STR("following:: node()")) % 8 % 9 % 10 % 11; // another, subchild, almost, last
CHECK_XPATH_NODESET(n.child(STR("child")).child(STR("subchild")), STR("following:: node()")) % 8 % 9 % 10 % 11; // another, subchild, almost, last
CHECK_XPATH_NODESET(n.child(STR("last")), STR("following:: node()"));
CHECK_XPATH_NODESET(n, STR("@attr1/following::node()")) % 5 % 7 % 8 % 9 % 10 % 11; // child, subchild, another, subchild, almost, last - because @/following
CHECK_XPATH_NODESET(n, STR("@attr1/following::node()")) % 5 % 7 % 8 % 9 % 10 % 11; // child, subchild, another, subchild, almost, last - because @/following
CHECK_XPATH_NODESET(n, STR("child/@attr/following::node()")) % 7 % 8 % 9 % 10 % 11; // subchild, another, subchild, almost, last
CHECK_XPATH_NODESET(na, STR("following::node()")) % 5 % 7 % 8 % 9 % 10 % 11; // child, subchild, another, subchild, almost, last - because @/following
CHECK_XPATH_NODESET(na, STR("following::node()")) % 5 % 7 % 8 % 9 % 10 % 11; // child, subchild, another, subchild, almost, last - because @/following
}
TEST_XML(xpath_paths_axes_preceding, "<node attr1='value' attr2='value'><child attr='value'><subchild/></child><another><subchild id='1'/></another><almost/><last/></node>")
@ -126,14 +126,14 @@ TEST_XML(xpath_paths_axes_preceding, "<node attr1='value' attr2='value'><child a
CHECK_XPATH_NODESET(c, STR("preceding:: node()"));
CHECK_XPATH_NODESET(n.child(STR("child")), STR("preceding:: node()")); // no ancestors
CHECK_XPATH_NODESET(n.child(STR("last")), STR("preceding:: node()")) % 11 % 9 % 8 % 7 % 5; // almost, subchild, another, subchild, child
CHECK_XPATH_NODESET(n.child(STR("child")), STR("preceding:: node()")); // no ancestors
CHECK_XPATH_NODESET(n.child(STR("last")), STR("preceding:: node()")) % 11 % 9 % 8 % 7 % 5; // almost, subchild, another, subchild, child
CHECK_XPATH_NODESET(n.child(STR("another")).child(STR("subchild")), STR("preceding:: node()")) % 7 % 5; // subchild, child
CHECK_XPATH_NODESET(n, STR("preceding:: node()"));
CHECK_XPATH_NODESET(n, STR("child/@attr/preceding::node()")); // no ancestors
CHECK_XPATH_NODESET(n, STR("child/@attr/preceding::node()")); // no ancestors
CHECK_XPATH_NODESET(n, STR("//subchild[@id]/@id/preceding::node()")) % 7 % 5; // subchild, child
CHECK_XPATH_NODESET(na, STR("preceding::node()")); // no ancestors
CHECK_XPATH_NODESET(na, STR("preceding::node()")); // no ancestors
}
TEST_XML(xpath_paths_axes_attribute, "<node attr1='value' attr2='value'><child attr='value'><subchild/></child><another xmlns:foo='bar'><subchild/></another><last/></node>")
@ -146,9 +146,9 @@ TEST_XML(xpath_paths_axes_attribute, "<node attr1='value' attr2='value'><child a
CHECK_XPATH_NODESET(n.child(STR("child")), STR("attribute:: node()")) % 6; // child/@attr
CHECK_XPATH_NODESET(n.child(STR("last")), STR("attribute:: node()"));
CHECK_XPATH_NODESET(n, STR("attribute:: node()")) % 3 % 4; // node/@attr1 node/@attr2
CHECK_XPATH_NODESET(n, STR("attribute:: node()")) % 3 % 4; // node/@attr1 node/@attr2
CHECK_XPATH_NODESET(doc, STR("descendant-or-self:: node()/attribute:: node()")) % 3 % 4 % 6; // all attributes
CHECK_XPATH_NODESET(n.child(STR("another")), STR("attribute:: node()")); // namespace nodes are not attributes
CHECK_XPATH_NODESET(n.child(STR("another")), STR("attribute:: node()")); // namespace nodes are not attributes
CHECK_XPATH_NODESET(n, STR("@attr1/attribute::node()"));
CHECK_XPATH_NODESET(na, STR("attribute::node()"));
@ -174,11 +174,11 @@ TEST_XML(xpath_paths_axes_self, "<node attr='value'><child attr='value'><subchil
CHECK_XPATH_NODESET(c, STR("self:: node()"));
CHECK_XPATH_NODESET(n.child(STR("child")), STR("self:: node()")) % 4; // child
CHECK_XPATH_NODESET(n, STR("self:: node()")) % 2; // node
CHECK_XPATH_NODESET(n, STR("child/self:: node()")) % 4; // child
CHECK_XPATH_NODESET(n, STR("child/@attr/self:: node()")) % 5; // @attr
CHECK_XPATH_NODESET(doc, STR("self:: node()")) % 1; // root
CHECK_XPATH_NODESET(na, STR("self:: node()")) % 3; // @attr
CHECK_XPATH_NODESET(n, STR("self:: node()")) % 2; // node
CHECK_XPATH_NODESET(n, STR("child/self:: node()")) % 4; // child
CHECK_XPATH_NODESET(n, STR("child/@attr/self:: node()")) % 5; // @attr
CHECK_XPATH_NODESET(doc, STR("self:: node()")) % 1; // root
CHECK_XPATH_NODESET(na, STR("self:: node()")) % 3; // @attr
}
TEST_XML(xpath_paths_axes_descendant_or_self, "<node attr='value'><child attr='value'><subchild/></child><another><subchild/></another><last/></node>")
@ -189,13 +189,13 @@ TEST_XML(xpath_paths_axes_descendant_or_self, "<node attr='value'><child attr='v
CHECK_XPATH_NODESET(c, STR("descendant-or-self:: node()"));
CHECK_XPATH_NODESET(n, STR("descendant-or-self:: node()")) % 2 % 4 % 6 % 7 % 8 % 9; // node, child, subchild, another, subchild, last
CHECK_XPATH_NODESET(n, STR("descendant-or-self:: node()")) % 2 % 4 % 6 % 7 % 8 % 9; // node, child, subchild, another, subchild, last
CHECK_XPATH_NODESET(doc, STR("descendant-or-self:: node()")) % 1 % 2 % 4 % 6 % 7 % 8 % 9; // root, node, child, subchild, another, subchild, last
CHECK_XPATH_NODESET(n, STR("another/descendant-or-self:: node()")) % 7 % 8; // another, subchild
CHECK_XPATH_NODESET(n, STR("last/descendant-or-self:: node()")) % 9; // last
CHECK_XPATH_NODESET(n, STR("another/descendant-or-self:: node()")) % 7 % 8; // another, subchild
CHECK_XPATH_NODESET(n, STR("last/descendant-or-self:: node()")) % 9; // last
CHECK_XPATH_NODESET(n, STR("child/@attr/descendant-or-self::node()")) % 5; // @attr
CHECK_XPATH_NODESET(na, STR("descendant-or-self::node()")) % 5; // @attr
CHECK_XPATH_NODESET(na, STR("descendant-or-self::node()")) % 5; // @attr
}
TEST_XML(xpath_paths_axes_ancestor_or_self, "<node attr='value'><child attr='value'><subchild/></child><another><subchild/></another><last/></node>")
@ -207,13 +207,13 @@ TEST_XML(xpath_paths_axes_ancestor_or_self, "<node attr='value'><child attr='val
CHECK_XPATH_NODESET(c, STR("ancestor-or-self:: node()"));
CHECK_XPATH_NODESET(n.child(STR("child")), STR("ancestor-or-self:: node()")) % 4 % 2 % 1; // child, node, root
CHECK_XPATH_NODESET(n, STR("child/subchild/ancestor-or-self:: node()")) % 6 % 4 % 2 % 1; // subchild, child, node, root
CHECK_XPATH_NODESET(n, STR("child/@attr/ancestor-or-self:: node()")) % 5 % 4 % 2 % 1; // @attr, child, node, root
CHECK_XPATH_NODESET(n, STR("ancestor-or-self:: node()")) % 2 % 1; // root, node
CHECK_XPATH_NODESET(doc, STR("ancestor-or-self:: node()")) % 1; // root
CHECK_XPATH_NODESET(n, STR("ancestor-or-self:: node()")) % 2 % 1; // root, node
CHECK_XPATH_NODESET(n, STR("last/ancestor-or-self::node()")) % 9 % 2 % 1; // root, node, last
CHECK_XPATH_NODESET(na, STR("ancestor-or-self:: node()")) % 5 % 4 % 2 % 1; // @attr, child, node, root
CHECK_XPATH_NODESET(n, STR("child/subchild/ancestor-or-self:: node()")) % 6 % 4 % 2 % 1; // subchild, child, node, root
CHECK_XPATH_NODESET(n, STR("child/@attr/ancestor-or-self:: node()")) % 5 % 4 % 2 % 1; // @attr, child, node, root
CHECK_XPATH_NODESET(n, STR("ancestor-or-self:: node()")) % 2 % 1; // root, node
CHECK_XPATH_NODESET(doc, STR("ancestor-or-self:: node()")) % 1; // root
CHECK_XPATH_NODESET(n, STR("ancestor-or-self:: node()")) % 2 % 1; // root, node
CHECK_XPATH_NODESET(n, STR("last/ancestor-or-self::node()")) % 9 % 2 % 1; // root, node, last
CHECK_XPATH_NODESET(na, STR("ancestor-or-self:: node()")) % 5 % 4 % 2 % 1; // @attr, child, node, root
}
TEST_XML(xpath_paths_axes_abbrev, "<node attr='value'><foo/></node>")
@ -561,7 +561,7 @@ TEST_XML(xpath_paths_descendant_double_slash_w3c, "<node><para><para/><para/><pa
TEST_XML(xpath_paths_needs_sorting, "<node><child/><child/><child><subchild/><subchild/></child></node>")
{
CHECK_XPATH_NODESET(doc, STR("(node/child/subchild)[2]")) % 7;
CHECK_XPATH_NODESET(doc, STR("(node/child/subchild)[2]")) % 7;
}
TEST_XML(xpath_paths_descendant_filters, "<node><para><para/><para/><para><para/></para></para><para/></node>")
@ -657,53 +657,53 @@ TEST_XML(xpath_paths_optimize_compare_attribute, "<node id='1' /><node id='2' />
TEST_XML(xpath_paths_optimize_step_once, "<node><para1><para2/><para3/><para4><para5 attr5=''/></para4></para1><para6/></node>")
{
CHECK_XPATH_BOOLEAN(doc, STR("node//para2/following::*"), true);
CHECK_XPATH_BOOLEAN(doc, STR("node//para6/following::*"), false);
CHECK_XPATH_BOOLEAN(doc, STR("node//para2/following::*"), true);
CHECK_XPATH_BOOLEAN(doc, STR("node//para6/following::*"), false);
CHECK_XPATH_STRING(doc, STR("name(node//para2/following::*)"), STR("para3"));
CHECK_XPATH_STRING(doc, STR("name(node//para6/following::*)"), STR(""));
CHECK_XPATH_STRING(doc, STR("name(node//para2/following::*)"), STR("para3"));
CHECK_XPATH_STRING(doc, STR("name(node//para6/following::*)"), STR(""));
CHECK_XPATH_BOOLEAN(doc, STR("node//para1/preceding::*"), false);
CHECK_XPATH_BOOLEAN(doc, STR("node//para6/preceding::*"), true);
CHECK_XPATH_BOOLEAN(doc, STR("node//para1/preceding::*"), false);
CHECK_XPATH_BOOLEAN(doc, STR("node//para6/preceding::*"), true);
CHECK_XPATH_STRING(doc, STR("name(node//para1/preceding::*)"), STR(""));
CHECK_XPATH_STRING(doc, STR("name(node//para6/preceding::*)"), STR("para1"));
CHECK_XPATH_STRING(doc, STR("name(node//para1/preceding::*)"), STR(""));
CHECK_XPATH_STRING(doc, STR("name(node//para6/preceding::*)"), STR("para1"));
CHECK_XPATH_BOOLEAN(doc, STR("node//para6/preceding::para4"), true);
CHECK_XPATH_BOOLEAN(doc, STR("node//para6/preceding::para4"), true);
CHECK_XPATH_BOOLEAN(doc, STR("//@attr5/ancestor-or-self::*"), true);
CHECK_XPATH_BOOLEAN(doc, STR("//@attr5/ancestor::*"), true);
CHECK_XPATH_BOOLEAN(doc, STR("//@attr5/ancestor-or-self::*"), true);
CHECK_XPATH_BOOLEAN(doc, STR("//@attr5/ancestor::*"), true);
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("//@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);
CHECK_XPATH_BOOLEAN(doc, STR("//para5/ancestor-or-self::*"), true);
CHECK_XPATH_BOOLEAN(doc, STR("//para5/ancestor::*"), true);
CHECK_XPATH_BOOLEAN(doc, STR("//@attr5/ancestor-or-self::node()"), true);
CHECK_XPATH_BOOLEAN(doc, STR("//@attr5/ancestor-or-self::node()"), true);
}
TEST_XML(xpath_paths_null_nodeset_entries, "<node attr='value'/>")
{
xpath_node nodes[] =
{
xpath_node(doc.first_child()),
xpath_node(xml_node()),
xpath_node(doc.first_child().first_attribute(), doc.first_child()),
xpath_node(xml_attribute(), doc.first_child()),
xpath_node(xml_attribute(), xml_node()),
};
xpath_node nodes[] =
{
xpath_node(doc.first_child()),
xpath_node(xml_node()),
xpath_node(doc.first_child().first_attribute(), doc.first_child()),
xpath_node(xml_attribute(), doc.first_child()),
xpath_node(xml_attribute(), xml_node()),
};
xpath_node_set ns(nodes, nodes + sizeof(nodes) / sizeof(nodes[0]));
xpath_node_set ns(nodes, nodes + sizeof(nodes) / sizeof(nodes[0]));
xpath_variable_set vars;
vars.set(STR("x"), ns);
xpath_variable_set vars;
vars.set(STR("x"), ns);
xpath_node_set rs = xpath_query(STR("$x/."), &vars).evaluate_node_set(xml_node());
xpath_node_set rs = xpath_query(STR("$x/."), &vars).evaluate_node_set(xml_node());
CHECK(rs.size() == 2);
CHECK(rs[0] == nodes[0]);
CHECK(rs[1] == nodes[2]);
CHECK(rs.size() == 2);
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>")

View File

@ -404,11 +404,11 @@ TEST(xpath_variables_name_case)
TEST(xpath_variables_name_unicode)
{
#ifdef PUGIXML_WCHAR_MODE
#ifdef U_LITERALS
const char_t* name = L"\u0400\u203D";
#else
const char_t* name = L"\x0400\x203D";
#endif
#ifdef U_LITERALS
const char_t* name = L"\u0400\u203D";
#else
const char_t* name = L"\x0400\x203D";
#endif
#else
const char_t* name = "\xd0\x80\xe2\x80\xbd";
#endif

View File

@ -322,16 +322,16 @@ TEST(xpath_xalan_math_5)
CHECK_XPATH_NUMBER(c, STR("10+5+25+20+15+50+35+40"), 200);
CHECK_XPATH_NUMBER(c, STR("100-9-7-4-17-18-5"), 40);
CHECK_XPATH_NUMBER(c, STR("3*2+5*4-4*2-1"), 17);
CHECK_XPATH_NUMBER(c, STR("6*5-8*2+5*2"), 24);
CHECK_XPATH_NUMBER(c, STR("10*5-4*2+6*1 -3*3"), 39);
CHECK_XPATH_NUMBER(c, STR("6*5-8*2+5*2"), 24);
CHECK_XPATH_NUMBER(c, STR("10*5-4*2+6*1 -3*3"), 39);
CHECK_XPATH_NUMBER(c, STR("(24 div 3 +2) div (40 div 8 -3)"), 5);
CHECK_XPATH_NUMBER(c, STR("80 div 2 + 12 div 2 - 4 div 2"), 44);
CHECK_XPATH_NUMBER(c, STR("70 div 10 - 18 div 6 + 10 div 2"), 9);
CHECK_XPATH_NUMBER(c, STR("(24 div 3 +2) div (40 div 8 -3)"), 5);
CHECK_XPATH_NUMBER(c, STR("80 div 2 + 12 div 2 - 4 div 2"), 44);
CHECK_XPATH_NUMBER(c, STR("70 div 10 - 18 div 6 + 10 div 2"), 9);
CHECK_XPATH_NUMBER(c, STR("48 mod 17 - 2 mod 9 + 13 mod 5"), 15);
CHECK_XPATH_NUMBER(c, STR("56 mod round(5*2+1.444) - 6 mod 4 + 7 mod 4"), 2);
CHECK_XPATH_NUMBER(c, STR("(77 mod 10 + 5 mod 8) mod 10"), 2);
CHECK_XPATH_NUMBER(c, STR("48 mod 17 - 2 mod 9 + 13 mod 5"), 15);
CHECK_XPATH_NUMBER(c, STR("56 mod round(5*2+1.444) - 6 mod 4 + 7 mod 4"), 2);
CHECK_XPATH_NUMBER(c, STR("(77 mod 10 + 5 mod 8) mod 10"), 2);
}
TEST_XML(xpath_xalan_math_6, "<doc><n1>3</n1><n2>7</n2><n3>x</n3></doc>")

View File

@ -4,8 +4,8 @@
#include "test.hpp"
#include <string>
#include <algorithm>
#include <string>
using namespace pugi;

View File

@ -193,7 +193,7 @@ TEST_XML(xpath_xalan_axes_9, "<doc><foo att1='c'><foo att1='b'><foo att1='a'><ba
xml_node baz = doc.select_node(STR("//baz")).node();
CHECK_XPATH_NODESET(baz, STR("ancestor-or-self::*[@att1][1]/@att1")) % 8;
CHECK_XPATH_NODESET(baz, STR("(ancestor-or-self::*)[@att1][1]/@att1")) % 4;
CHECK_XPATH_NODESET(baz, STR("(ancestor-or-self::*)[@att1][1]/@att1")) % 4;
CHECK_XPATH_NODESET(baz, STR("ancestor::foo[1]/@att1")) % 8;
CHECK_XPATH_NODESET(baz, STR("(ancestor::foo[1])/@att1")) % 8;
@ -203,7 +203,7 @@ TEST_XML(xpath_xalan_axes_9, "<doc><foo att1='c'><foo att1='b'><foo att1='a'><ba
xml_node bar = doc.child(STR("doc")).child(STR("bar"));
CHECK_XPATH_NODESET(bar, STR("preceding::foo[1]/@att1")) % 8;
CHECK_XPATH_NODESET(bar, STR("preceding::foo[1]/@att1")) % 8;
CHECK_XPATH_NODESET(bar, STR("(preceding::foo)[1]/@att1")) % 4;
}
@ -211,7 +211,7 @@ TEST_XML(xpath_xalan_axes_10, "<doc><foo att1='c'/><foo att1='b'/><foo att1='a'/
{
xml_node baz = doc.child(STR("doc")).child(STR("baz"));
CHECK_XPATH_NODESET(baz, STR("preceding-sibling::foo[1]/@att1")) % 8;
CHECK_XPATH_NODESET(baz, STR("preceding-sibling::foo[1]/@att1")) % 8;
CHECK_XPATH_NODESET(baz, STR("(preceding-sibling::foo)[1]/@att1")) % 4;
}
@ -219,10 +219,10 @@ TEST_XML(xpath_xalan_axes_11, "<chapter title='A' x='0'><section title='A1' x='1
{
xml_node chapter = doc.child(STR("chapter"));
CHECK_XPATH_NUMBER(doc, STR("count(//@*)"), 16);
CHECK_XPATH_NUMBER(doc, STR("count(//@title)"), 12);
CHECK_XPATH_NUMBER(doc, STR("count(//section//@*)"), 14);
CHECK_XPATH_NUMBER(doc, STR("count(//section//@title)"), 11);
CHECK_XPATH_NUMBER(doc, STR("count(//@*)"), 16);
CHECK_XPATH_NUMBER(doc, STR("count(//@title)"), 12);
CHECK_XPATH_NUMBER(doc, STR("count(//section//@*)"), 14);
CHECK_XPATH_NUMBER(doc, STR("count(//section//@title)"), 11);
CHECK_XPATH_NUMBER(chapter, STR("count(.//@*)"), 16);
CHECK_XPATH_NUMBER(chapter, STR("count(.//@title)"), 12);
@ -254,13 +254,13 @@ TEST_XML(xpath_xalan_axes_13, "<doc att1='e'><foo att1='d'><foo att1='c'><foo at
CHECK_XPATH_NODESET(d, STR("(descendant-or-self::*/@att1)[last()]")) % 11;
CHECK_XPATH_NUMBER(baz, STR("count(ancestor-or-self::*/@att1)"), 5);
CHECK_XPATH_NODESET(baz, STR("ancestor-or-self::*/@att1[last()]")) % 3 % 5 % 7 % 9 % 11;
CHECK_XPATH_STRING(baz, STR("string(ancestor-or-self::*/@att1[last()])"), STR("e"));
CHECK_XPATH_NODESET(baz, STR("(ancestor-or-self::*)/@att1[last()]")) % 3 % 5 % 7 % 9 % 11;
CHECK_XPATH_STRING(baz, STR("string((ancestor-or-self::*)/@att1[last()])"), STR("e"));
CHECK_XPATH_NODESET(baz, STR("(ancestor-or-self::*/@att1)[last()]")) % 11;
CHECK_XPATH_NODESET(baz, STR("(ancestor::*|self::*)/@att1[last()]")) % 3 % 5 % 7 % 9 % 11;
CHECK_XPATH_STRING(baz, STR("string((ancestor::*|self::*)/@att1[last()])"), STR("e"));
CHECK_XPATH_NODESET(baz, STR("ancestor-or-self::*/@att1[last()]")) % 3 % 5 % 7 % 9 % 11;
CHECK_XPATH_STRING(baz, STR("string(ancestor-or-self::*/@att1[last()])"), STR("e"));
CHECK_XPATH_NODESET(baz, STR("(ancestor-or-self::*)/@att1[last()]")) % 3 % 5 % 7 % 9 % 11;
CHECK_XPATH_STRING(baz, STR("string((ancestor-or-self::*)/@att1[last()])"), STR("e"));
CHECK_XPATH_NODESET(baz, STR("(ancestor-or-self::*/@att1)[last()]")) % 11;
CHECK_XPATH_NODESET(baz, STR("(ancestor::*|self::*)/@att1[last()]")) % 3 % 5 % 7 % 9 % 11;
CHECK_XPATH_STRING(baz, STR("string((ancestor::*|self::*)/@att1[last()])"), STR("e"));
CHECK_XPATH_NODESET(baz, STR("((ancestor::*|self::*)/@att1)[last()]")) % 11;
}

View File

@ -52,12 +52,12 @@ TEST_XML_FLAGS(xpath_xalan_position_2, "<doc><a test='true'><num>1</num></a><a><
CHECK_XPATH_NODESET(c, STR("processing-instruction()[2]")) % 34;
CHECK_XPATH_NODESET(c, STR("processing-instruction('pi')[2]")) % 34;
CHECK_XPATH_NODESET(c, STR("comment()[2]")) % 36;
CHECK_XPATH_NODESET(c, STR("a/*[last()]")) % 5 % 8 % 11 % 15 % 18 % 21 % 25 % 29;
CHECK_XPATH_NODESET(c, STR("a/child::*[last()]")) % 5 % 8 % 11 % 15 % 18 % 21 % 25 % 29;
CHECK_XPATH_NODESET(c, STR("a/descendant::*[last()]")) % 5 % 8 % 11 % 15 % 18 % 21 % 25 % 31;
CHECK_XPATH_NODESET(c, STR("a/child::node()[last()]")) % 5 % 8 % 11 % 15 % 18 % 21 % 25 % 29;
CHECK_XPATH_NODESET(c, STR("a/descendant::text()[last()]")) % 6 % 9 % 12 % 16 % 19 % 22 % 26 % 32;
CHECK_XPATH_NODESET(c, STR("child::comment()[last()]")) % 36;
CHECK_XPATH_NODESET(c, STR("a/*[last()]")) % 5 % 8 % 11 % 15 % 18 % 21 % 25 % 29;
CHECK_XPATH_NODESET(c, STR("a/child::*[last()]")) % 5 % 8 % 11 % 15 % 18 % 21 % 25 % 29;
CHECK_XPATH_NODESET(c, STR("a/descendant::*[last()]")) % 5 % 8 % 11 % 15 % 18 % 21 % 25 % 31;
CHECK_XPATH_NODESET(c, STR("a/child::node()[last()]")) % 5 % 8 % 11 % 15 % 18 % 21 % 25 % 29;
CHECK_XPATH_NODESET(c, STR("a/descendant::text()[last()]")) % 6 % 9 % 12 % 16 % 19 % 22 % 26 % 32;
CHECK_XPATH_NODESET(c, STR("child::comment()[last()]")) % 36;
}
TEST_XML(xpath_xalan_position_3, "<article class='whitepaper' status='Note'><articleinfo><title>AAA</title><section id='info'><title>BBB</title><para>About this article</para><section revisionflag='added'><title>CCC</title><para>This is the section titled 'ZZZ'.</para><ednote who='KKK'><title>DDD</title><para>Don't worry.</para><section revisionflag='added'><title>EEE</title><para>This is the deep subsection.</para></section></ednote></section></section></articleinfo></article>")
@ -111,7 +111,6 @@ TEST_XML(xpath_xalan_match_1, "<root><x spot='a' num='1'/><x spot='b' num='2'/><
CHECK_XPATH_NODESET(c, STR("x[(((((2*10)-4)+9) div 5) mod 3)]")) % 6;
}
TEST_XML(xpath_xalan_match_2, "<doc><l1><v2>doc-l1-v2</v2><x2>doc-l1-x2</x2><l2><v3>doc-l1-l2-v3</v3><w3>doc-l1-l2-w3</w3><x3>doc-l1-l2-x3</x3><y3>doc-l1-l2-y3</y3><l3><v4>doc-l1-l2-l3-v4</v4><x4>doc-l1-l2-l3-x4</x4></l3></l2></l1></doc>")
{
CHECK_XPATH_STRING(doc, STR("doc/l1/v2"), STR("doc-l1-v2"));

View File

@ -111,7 +111,7 @@ TEST_XML(xpath_xalan_select_11, "<doc><sub1 pos='1'><child1>descendant number 1<
TEST_XML(xpath_xalan_select_12, "<doc><sub pos='1'><child>child number 1</child><sub-sub pos='1sub'><child>grandchild number 1</child></sub-sub></sub><sub0 pos='2-no'><child>child number 2</child><sub pos='2.5'><child>grandchild number 2</child></sub></sub0><sub pos='3'><child>child number 3</child><subno pos='3.5-no'><child>grandchild number 3</child></subno></sub><sub0 pos='4-no'><child>child number 4</child><sub-sub pos='4sub'><child>grandchild number 4</child></sub-sub></sub0></doc>")
{
CHECK_XPATH_NODESET(doc, STR("//child/ancestor-or-self::sub | //child/ancestor-or-self::sub-sub")) % 3 % 7 % 15 % 19 % 31;
CHECK_XPATH_NODESET(doc, STR("//child/ancestor-or-self::sub | //child/ancestor-or-self::sub-sub")) % 3 % 7 % 15 % 19 % 31;
}
TEST_XML(xpath_xalan_select_13, "<doc><book><author><name real='no'>Carmelo Montanez</name><chapters>Nine</chapters><bibliography></bibliography></author></book><book><author><name real='na'>David Marston</name><chapters>Seven</chapters><bibliography></bibliography></author></book><book><author><name real='yes'>Mary Brady</name><chapters>Ten</chapters><bibliography><author><name>Lynne Rosenthal</name><chapters>Five</chapters></author></bibliography></author></book></doc>")
@ -154,17 +154,17 @@ TEST_XML(xpath_xalan_select_17, "<directions><north><dup1/><dup2/><south/><east/
{
xml_node c = doc.child(STR("directions"));
CHECK_XPATH_NODESET(c, STR("north/* | north/dup1 | north/dup2")) % 4 % 5 % 6 % 7 % 8;
CHECK_XPATH_NODESET(c, STR("north/dup2 | north/dup1 | north/*")) % 4 % 5 % 6 % 7 % 8;
CHECK_XPATH_NODESET(c, STR("//north/dup2 | south/preceding-sibling::*[4]/* | north/dup1 | north/*")) % 4 % 5 % 6 % 7 % 8;
CHECK_XPATH_NODESET(c, STR("north/dup2 | south/preceding-sibling::*[4]/* | north/*")) % 4 % 5 % 6 % 7 % 8;
CHECK_XPATH_NODESET(c, STR("north/* | north/dup1 | north/dup2")) % 4 % 5 % 6 % 7 % 8;
CHECK_XPATH_NODESET(c, STR("north/dup2 | north/dup1 | north/*")) % 4 % 5 % 6 % 7 % 8;
CHECK_XPATH_NODESET(c, STR("//north/dup2 | south/preceding-sibling::*[4]/* | north/dup1 | north/*")) % 4 % 5 % 6 % 7 % 8;
CHECK_XPATH_NODESET(c, STR("north/dup2 | south/preceding-sibling::*[4]/* | north/*")) % 4 % 5 % 6 % 7 % 8;
}
TEST_XML(xpath_xalan_select_18, "<para><font color='red'>Hello</font><font color='green'>There</font><font color='blue'>World</font></para>")
{
CHECK_XPATH_NODESET(doc, STR("/para/font[@color='green']")) % 6;
CHECK_XPATH_NODESET(doc.child(STR("para")), STR("/para/font[@color='green']")) % 6;
CHECK_XPATH_NODESET(doc.child(STR("para")).last_child(), STR("/para/font[@color='green']")) % 6;
CHECK_XPATH_NODESET(doc, STR("/para/font[@color='green']")) % 6;
CHECK_XPATH_NODESET(doc.child(STR("para")), STR("/para/font[@color='green']")) % 6;
CHECK_XPATH_NODESET(doc.child(STR("para")).last_child(), STR("/para/font[@color='green']")) % 6;
}
TEST_XML_FLAGS(xpath_xalan_select_19, "<doc>1<a>in-a</a>2<!-- upper comment --><b>3<bb>4<bbb>5</bbb>6</bb>7</b><!-- lower comment -->8<c>in-c</c>9<?pi?></doc>", parse_default | parse_comments | parse_pi)

View File

@ -5,10 +5,12 @@
static bool test_narrow(const std::string& result, const char* expected, size_t length)
{
// check result
if (result != std::string(expected, expected + length)) return false;
if (result != std::string(expected, expected + length))
return false;
// check comparison operator (incorrect implementation can theoretically early-out on zero terminators...)
if (length > 0 && result == std::string(expected, expected + length - 1) + "?") return false;
if (length > 0 && result == std::string(expected, expected + length - 1) + "?")
return false;
return true;
}
@ -27,7 +29,7 @@ std::basic_string<wchar_t> xml_writer_string::as_wide() const
{
CHECK(contents.size() % sizeof(wchar_t) == 0);
// round-trip pointer through void* to avoid pointer alignment warnings; contents data should be heap allocated => safe to cast
// round-trip pointer through void* to avoid pointer alignment warnings; contents data should be heap allocated => safe to cast
return std::basic_string<wchar_t>(static_cast<const wchar_t*>(static_cast<const void*>(contents.data())), contents.size() / sizeof(wchar_t));
}
@ -37,7 +39,7 @@ std::basic_string<pugi::char_t> xml_writer_string::as_string() const
CHECK(contents.size() % sizeof(pugi::char_t) == 0);
#endif
// round-trip pointer through void* to avoid pointer alignment warnings; contents data should be heap allocated => safe to cast
// round-trip pointer through void* to avoid pointer alignment warnings; contents data should be heap allocated => safe to cast
return std::basic_string<pugi::char_t>(static_cast<const pugi::char_t*>(static_cast<const void*>(contents.data())), contents.size() / sizeof(pugi::char_t));
}

View File

@ -5,7 +5,7 @@
#include <string>
struct xml_writer_string: public pugi::xml_writer
struct xml_writer_string : public pugi::xml_writer
{
std::string contents;