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 "allocator.hpp"
#include <string.h>
#include <assert.h> #include <assert.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h>
// Address sanitizer // Address sanitizer
#if defined(__has_feature) #if defined(__has_feature)
# define ADDRESS_SANITIZER __has_feature(address_sanitizer) #define ADDRESS_SANITIZER __has_feature(address_sanitizer)
#else #else
# if defined(__SANITIZE_ADDRESS__) #if defined(__SANITIZE_ADDRESS__)
# define ADDRESS_SANITIZER 1 #define ADDRESS_SANITIZER 1
# else #else
# define ADDRESS_SANITIZER 0 #define ADDRESS_SANITIZER 0
# endif #endif
#endif #endif
// Low-level allocation functions // Low-level allocation functions
#if defined(_WIN32) || defined(_WIN64) #if defined(_WIN32) || defined(_WIN64)
# ifdef __MWERKS__ #ifdef __MWERKS__
# pragma ANSI_strict off // disable ANSI strictness to include windows.h #pragma ANSI_strict off // disable ANSI strictness to include windows.h
# pragma cpp_extensions on // enable some extensions to include windows.h #pragma cpp_extensions on // enable some extensions to include windows.h
# endif #endif
# if defined(_MSC_VER) #if defined(_MSC_VER)
# pragma warning(disable: 4201) // nonstandard extension used: nameless struct/union #pragma warning(disable : 4201) // nonstandard extension used: nameless struct/union
# endif #endif
# ifdef _XBOX_VER #ifdef _XBOX_VER
# define NOD3D #define NOD3D
# include <xtl.h> #include <xtl.h>
# else #else
# include <windows.h> #include <windows.h>
# endif #endif
namespace namespace
{ {
const size_t page_size = 4096; const size_t page_size = 4096;
size_t align_to_page(size_t value) size_t align_to_page(size_t value)
{ {
return (value + page_size - 1) & ~(page_size - 1); 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);
}
} }
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 #elif (defined(__APPLE__) || defined(__linux__)) && (defined(__i386) || defined(__x86_64)) && !ADDRESS_SANITIZER
# include <sys/mman.h> #include <sys/mman.h>
namespace namespace
{ {
const size_t page_size = 4096; const size_t page_size = 4096;
size_t align_to_page(size_t value) size_t align_to_page(size_t value)
{ {
return (value + page_size - 1) & ~(page_size - 1); 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;
}
} }
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 #else
namespace namespace
{ {
void* allocate(size_t size) void* allocate(size_t size)
{ {
return malloc(size); return malloc(size);
}
void deallocate(void* ptr, size_t size)
{
(void)size;
free(ptr);
}
} }
void deallocate(void* ptr, size_t size)
{
(void)size;
free(ptr);
}
} // namespace
#endif #endif
// High-level allocation functions // 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* memory_allocate(size_t size)
{ {
void* result = allocate(size + memory_alignment); void* result = allocate(size + memory_alignment);
if (!result) return 0; if (!result)
return 0;
memcpy(result, &size, sizeof(size_t)); memcpy(result, &size, sizeof(size_t));
@ -166,10 +169,10 @@ size_t memory_size(void* ptr)
void memory_deallocate(void* ptr) void memory_deallocate(void* ptr)
{ {
if (!ptr) return; if (!ptr)
return;
size_t size = memory_size(ptr); size_t size = memory_size(ptr);
deallocate(static_cast<char*>(ptr) - memory_alignment, size + memory_alignment); deallocate(static_cast<char*>(ptr) - memory_alignment, size + memory_alignment);
} }

View File

@ -2,9 +2,9 @@
#include <stdint.h> #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);
doc.load_buffer(Data, Size, pugi::parse_minimal); doc.load_buffer(Data, Size, pugi::parse_minimal);

View File

@ -3,7 +3,7 @@
#include <stdint.h> #include <stdint.h>
#include <string.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]; char* text = new char[Size + 1];
memcpy(text, Data, Size); memcpy(text, Data, Size);

View File

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

View File

@ -1,21 +1,21 @@
#include "test.hpp"
#include "allocator.hpp" #include "allocator.hpp"
#include "test.hpp"
#include <assert.h>
#include <float.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <float.h>
#include <assert.h>
#include <string> #include <string>
#ifndef PUGIXML_NO_EXCEPTIONS #ifndef PUGIXML_NO_EXCEPTIONS
# include <exception> #include <exception>
#endif #endif
#ifdef _WIN32_WCE #ifdef _WIN32_WCE
# undef DebugBreak #undef DebugBreak
# pragma warning(disable: 4201) // nonstandard extension used: nameless struct/union #pragma warning(disable : 4201) // nonstandard extension used: nameless struct/union
# include <windows.h> #include <windows.h>
#endif #endif
test_runner* test_runner::_tests = 0; test_runner* test_runner::_tests = 0;
@ -41,7 +41,8 @@ static void* custom_allocate(size_t size)
else else
{ {
void* ptr = memory_allocate(size); void* ptr = memory_allocate(size);
if (!ptr) return 0; if (!ptr)
return 0;
g_memory_total_size += memory_size(ptr); g_memory_total_size += memory_size(ptr);
g_memory_total_count++; g_memory_total_count++;
@ -89,9 +90,9 @@ static void replace_memory_management()
namespace std namespace std
{ {
_CRTIMP2 _Prhand _Raise_handler; _CRTIMP2 _Prhand _Raise_handler;
_CRTIMP2 void __cdecl _Throw(const exception&) {} _CRTIMP2 void __cdecl _Throw(const exception&) {}
} } // namespace std
#endif #endif
static bool run_test(test_runner* test, const char* test_name, pugi::allocation_function allocate) 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); pugi::set_memory_management_functions(allocate, custom_deallocate);
#ifdef _MSC_VER #ifdef _MSC_VER
# pragma warning(push) #pragma warning(push)
# pragma warning(disable: 4611) // interaction between _setjmp and C++ object destruction is non-portable #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(disable : 4793) // function compiled as native: presence of '_setjmp' makes a function unmanaged
#endif #endif
volatile int result = setjmp(test_runner::_failure_buffer); volatile int result = setjmp(test_runner::_failure_buffer);
#ifdef _MSC_VER #ifdef _MSC_VER
# pragma warning(pop) #pragma warning(pop)
#endif #endif
if (result) if (result)
@ -193,10 +194,10 @@ int main(int, char** argv)
if (g_memory_fail_triggered) if (g_memory_fail_triggered)
{ {
// run tests that trigger memory failures twice - with an allocator that returns NULL and with an allocator that throws // 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++; total++;
passed += run_test(test, (test->_name + std::string(" (throw)")).c_str(), custom_allocate_throw); 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 "writer_string.hpp"
#include <math.h>
#include <float.h> #include <float.h>
#include <math.h>
#include <string.h> #include <string.h>
#include <wchar.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(); cur = cur.next_sibling();
else else
{ {
while (cur && !cur.next_sibling()) cur = cur.parent(); while (cur && !cur.next_sibling())
cur = cur.parent();
cur = cur.next_sibling(); 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) bool test_string_equal(const pugi::char_t* lhs, const pugi::char_t* rhs)
{ {
return (!lhs || !rhs) ? lhs == rhs : return (!lhs || !rhs) ? lhs == rhs :
#ifdef PUGIXML_WCHAR_MODE #ifdef PUGIXML_WCHAR_MODE
wcscmp(lhs, rhs) == 0; wcscmp(lhs, rhs) == 0;
#else #else
strcmp(lhs, rhs) == 0; strcmp(lhs, rhs) == 0;
#endif #endif
} }
bool test_node(const pugi::xml_node& node, const pugi::char_t* contents, const pugi::char_t* indent, unsigned int flags) 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) 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); pugi::xpath_query q(query, variables);
if (!q) return false; if (!q)
return false;
const size_t capacity = 64; const size_t capacity = 64;
pugi::char_t result[capacity]; 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) 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); pugi::xpath_query q(query, variables);
if (!q) return false; if (!q)
return false;
return q.evaluate_boolean(node) == expected; 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) 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); pugi::xpath_query q(query, variables);
if (!q) return false; if (!q)
return false;
double value = q.evaluate_number(node); double value = q.evaluate_number(node);
double absolute_error = fabs(value - expected); 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) 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); pugi::xpath_query q(query, variables);
if (!q) return false; if (!q)
return false;
return test_double_nan(q.evaluate_number(node)); 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; result = set;
// only sort unsorted sets so that we're able to verify reverse order for some axes // 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()) 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); 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); return test_string_equal(node.name(), name) && test_string_equal(node.value(), value);
} }
@ -71,17 +72,22 @@ struct xpath_node_set_tester
#endif #endif
struct dummy_fixture {}; struct dummy_fixture
{
};
#define TEST_FIXTURE(name, fixture) \ #define TEST_FIXTURE(name, fixture) \
struct test_runner_helper_##name: fixture \ struct test_runner_helper_##name : fixture \
{ \ { \
void run(); \ 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 \ virtual void run() PUGIXML_OVERRIDE \
{ \ { \
test_runner_helper_##name helper; \ test_runner_helper_##name helper; \
@ -96,30 +102,34 @@ struct dummy_fixture {};
struct test_fixture_##name \ struct test_fixture_##name \
{ \ { \
pugi::xml_document doc; \ pugi::xml_document doc; \
\ \
test_fixture_##name() \ test_fixture_##name() \
{ \ { \
CHECK(doc.load_string(PUGIXML_TEXT(xml), flags)); \ CHECK(doc.load_string(PUGIXML_TEXT(xml), flags)); \
} \ } \
\ \
private: \ private: \
test_fixture_##name(const test_fixture_##name&); \ test_fixture_##name(const test_fixture_##name&); \
test_fixture_##name& operator=(const test_fixture_##name&); \ test_fixture_##name& operator=(const test_fixture_##name&); \
}; \ }; \
\ \
TEST_FIXTURE(name, test_fixture_##name) TEST_FIXTURE(name, test_fixture_##name)
#define TEST_XML(name, xml) TEST_XML_FLAGS(name, xml, pugi::parse_default) #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_JOIN(text, file, line) text " at " file ":" #line
#define CHECK_JOIN2(text, file, line) CHECK_JOIN(text, 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) #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) #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 #else
# define STRINGIZE(value) #value #define STRINGIZE(value) #value
#endif #endif
#define CHECK(condition) CHECK_TEXT(condition, STRINGIZE(condition) " is false") #define CHECK(condition) CHECK_TEXT(condition, STRINGIZE(condition) " is false")
@ -147,9 +157,29 @@ struct dummy_fixture {};
#endif #endif
#ifdef PUGIXML_NO_EXCEPTIONS #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 #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 #endif
#define STR(text) PUGIXML_TEXT(text) #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__) #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 // 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 // IC8 and BCC are also affected by the same bug
# define MSVC6_NAN_BUG #define MSVC6_NAN_BUG
#endif #endif
inline wchar_t wchar_cast(unsigned int value) inline wchar_t wchar_cast(unsigned int value)

View File

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

View File

@ -3,9 +3,9 @@
#include <limits> #include <limits>
#include <string> #include <string>
#include <limits.h>
#include <math.h> #include <math.h>
#include <string.h> #include <string.h>
#include <limits.h>
using namespace pugi; 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(); node.attribute(STR("attr")) = std::numeric_limits<float>::max();
CHECK(test_node(node, STR("<node attr=\"3.40282347e+038\"/>"), STR(""), format_raw) || 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='' />") TEST_XML(dom_attr_assign_large_number_double, "<node attr='' />")
@ -880,12 +880,12 @@ TEST(dom_node_declaration_name)
TEST(dom_node_declaration_attributes) TEST(dom_node_declaration_attributes)
{ {
xml_document doc; xml_document doc;
xml_node node = doc.append_child(node_declaration); xml_node node = doc.append_child(node_declaration);
node.append_attribute(STR("version")) = STR("1.0"); node.append_attribute(STR("version")) = STR("1.0");
node.append_attribute(STR("encoding")) = STR("utf-8"); 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) TEST(dom_node_declaration_top_level)
@ -926,7 +926,8 @@ TEST(dom_string_out_of_memory)
const unsigned int length = 65536; const unsigned int length = 65536;
static char_t string[length + 1]; 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; string[length] = 0;
xml_document doc; xml_document doc;
@ -976,8 +977,8 @@ TEST(dom_node_out_of_memory)
xml_attribute a = n.append_attribute(STR("a")); xml_attribute a = n.append_attribute(STR("a"));
CHECK(a); CHECK(a);
CHECK_ALLOC_FAIL(while (n.append_child(node_comment)) { /* nop */ }); 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_attribute(STR("b"))){/* nop */});
// verify all node modification operations // verify all node modification operations
CHECK_ALLOC_FAIL(CHECK(!n.append_child())); CHECK_ALLOC_FAIL(CHECK(!n.append_child()));
@ -1005,7 +1006,8 @@ TEST(dom_node_memory_limit)
const unsigned int length = 65536; const unsigned int length = 65536;
static char_t string[length + 1]; 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; string[length] = 0;
test_runner::_memory_fail_threshold = 32768 * 2 + sizeof(string); test_runner::_memory_fail_threshold = 32768 * 2 + sizeof(string);
@ -1024,7 +1026,8 @@ TEST(dom_node_memory_limit_pi)
const unsigned int length = 65536; const unsigned int length = 65536;
static char_t string[length + 1]; 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; string[length] = 0;
test_runner::_memory_fail_threshold = 32768 * 2 + sizeof(string); test_runner::_memory_fail_threshold = 32768 * 2 + sizeof(string);
@ -1073,15 +1076,15 @@ TEST(dom_node_doctype_copy)
TEST(dom_node_doctype_value) TEST(dom_node_doctype_value)
{ {
xml_document doc; xml_document doc;
xml_node node = doc.append_child(node_doctype); xml_node node = doc.append_child(node_doctype);
CHECK(node.type() == node_doctype); CHECK(node.type() == node_doctype);
CHECK_STRING(node.value(), STR("")); CHECK_STRING(node.value(), STR(""));
CHECK_NODE(node, STR("<!DOCTYPE>")); CHECK_NODE(node, STR("<!DOCTYPE>"));
CHECK(node.set_value(STR("id [ foo ]"))); CHECK(node.set_value(STR("id [ foo ]")));
CHECK_NODE(node, STR("<!DOCTYPE id [ foo ]>")); CHECK_NODE(node, STR("<!DOCTYPE id [ foo ]>"));
} }
TEST_XML(dom_node_append_buffer_native, "<node>test</node>") 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>")); CHECK_NODE(doc, STR("<node>test<n/><n/></node>"));
} }
TEST_XML(dom_node_append_buffer_remove, "<node>test</node>") TEST_XML(dom_node_append_buffer_remove, "<node>test</node>")
{ {
xml_node node = doc.child(STR("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>")); 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>")); 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>")); 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>")); CHECK_NODE(doc, STR("<node>test</node>"));
@ -1665,7 +1673,8 @@ TEST(dom_node_copy_declaration_empty_name)
CHECK_STRING(decl2.name(), STR("")); 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 // Several compilers compare float/double values on x87 stack without proper rounding
// This causes roundtrip tests to fail, although they correctly preserve the data. // 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[] = const double fp_roundtrip_base[] =
{ {
0.31830988618379067154, 0.31830988618379067154,
0.43429448190325182765, 0.43429448190325182765,
0.57721566490153286061, 0.57721566490153286061,
0.69314718055994530942, 0.69314718055994530942,
0.70710678118654752440, 0.70710678118654752440,
0.78539816339744830962, 0.78539816339744830962,
}; };
TEST(dom_fp_roundtrip_float) 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) 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 // Not all runtime libraries guarantee roundtripping for denormals
if (e == -1021 && fp_roundtrip_base[i] < 0.5) if (e == -1021 && fp_roundtrip_base[i] < 0.5)
continue; continue;
#endif #endif
#ifdef __DMC__ #ifdef __DMC__
// Digital Mars C does not roundtrip on exactly one combination // Digital Mars C does not roundtrip on exactly one combination
if (e == -12 && i == 1) if (e == -12 && i == 1)
continue; continue;
#endif #endif
double value = ldexp(fp_roundtrip_base[i], e); 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) 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("a")).text());
CHECK(node.child(STR("b")).text()); CHECK(node.child(STR("b")).text());
CHECK(!node.child(STR("c")).text()); CHECK(!node.child(STR("c")).text());
CHECK(!node.child(STR("d")).text()); CHECK(!node.child(STR("d")).text());
CHECK(!xml_node().text()); CHECK(!xml_node().text());
CHECK(!xml_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>") 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) 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")).text().get(), STR("foo"));
CHECK_STRING(node.child(STR("a")).first_child().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")).text().get(), STR("bar"));
CHECK_STRING(node.child(STR("b")).last_child().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")).text().get(), STR(""));
CHECK_STRING(node.child(STR("c")).first_child().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) 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")).text().as_string(), STR("foo"));
CHECK_STRING(node.child(STR("a")).first_child().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")).text().as_string(), STR("bar"));
CHECK_STRING(node.child(STR("b")).last_child().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")).text().as_string(), STR(""));
CHECK_STRING(node.child(STR("c")).first_child().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>") 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("text2")).text().as_int() == -1);
CHECK(node.child(STR("text3")).text().as_int() == -2147483647 - 1); CHECK(node.child(STR("text3")).text().as_int() == -2147483647 - 1);
CHECK(node.child(STR("text4")).text().as_int() == 2147483647); 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>") 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("text1")).text().as_int() == 777); // no octal support! intentional
CHECK(node.child(STR("text2")).text().as_int() == 1451); CHECK(node.child(STR("text2")).text().as_int() == 1451);
CHECK(node.child(STR("text3")).text().as_int() == 255); CHECK(node.child(STR("text3")).text().as_int() == 255);
CHECK(node.child(STR("text4")).text().as_int() == -32); CHECK(node.child(STR("text4")).text().as_int() == -32);
CHECK(node.child(STR("text5")).text().as_int() == -2147483647 - 1); CHECK(node.child(STR("text5")).text().as_int() == -2147483647 - 1);
CHECK(node.child(STR("text6")).text().as_int() == 0); 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>") 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("text2")).text().as_uint() == 1);
CHECK(node.child(STR("text3")).text().as_uint() == 2147483647); CHECK(node.child(STR("text3")).text().as_uint() == 2147483647);
CHECK(node.child(STR("text4")).text().as_uint() == 4294967295u); 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>") 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("text1")).text().as_uint() == 777); // no octal support! intentional
CHECK(node.child(STR("text2")).text().as_uint() == 1451); CHECK(node.child(STR("text2")).text().as_uint() == 1451);
CHECK(node.child(STR("text3")).text().as_uint() == 255); CHECK(node.child(STR("text3")).text().as_uint() == 255);
CHECK(node.child(STR("text4")).text().as_uint() == 32); CHECK(node.child(STR("text4")).text().as_uint() == 32);
CHECK(node.child(STR("text5")).text().as_uint() == 4294967295u); CHECK(node.child(STR("text5")).text().as_uint() == 4294967295u);
CHECK(node.child(STR("text6")).text().as_uint() == 0); 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>") 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("text1")).text().as_int() == 1234);
CHECK(node.child(STR("text2")).text().as_int() == 291); CHECK(node.child(STR("text2")).text().as_int() == 291);
CHECK(node.child(STR("text3")).text().as_int() == 0); CHECK(node.child(STR("text3")).text().as_int() == 0);
CHECK(node.child(STR("text4")).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>") 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/>") TEST_XML(dom_text_get_no_state, "<node/>")
{ {
xml_node node = doc.child(STR("node")); xml_node node = doc.child(STR("node"));
xml_text t = node.text(); xml_text t = node.text();
CHECK(!t); CHECK(!t);
CHECK(t.get() && *t.get() == 0); CHECK(t.get() && *t.get() == 0);
CHECK(!node.first_child()); CHECK(!node.first_child());
node.append_child(node_pcdata); node.append_child(node_pcdata);
CHECK(t); CHECK(t);
CHECK_STRING(t.get(), STR("")); CHECK_STRING(t.get(), STR(""));
node.first_child().set_value(STR("test")); node.first_child().set_value(STR("test"));
CHECK(t); CHECK(t);
CHECK_STRING(t.get(), STR("test")); CHECK_STRING(t.get(), STR("test"));
} }
TEST_XML(dom_text_set, "<node/>") TEST_XML(dom_text_set, "<node/>")
{ {
xml_node node = doc.child(STR("node")); xml_node node = doc.child(STR("node"));
xml_text t = node.text(); xml_text t = node.text();
t.set(STR("")); t.set(STR(""));
CHECK(node.first_child().type() == node_pcdata); CHECK(node.first_child().type() == node_pcdata);
CHECK_NODE(node, STR("<node></node>")); CHECK_NODE(node, STR("<node></node>"));
t.set(STR("boo")); t.set(STR("boo"));
CHECK(node.first_child().type() == node_pcdata); CHECK(node.first_child().type() == node_pcdata);
CHECK(node.first_child() == node.last_child()); CHECK(node.first_child() == node.last_child());
CHECK_NODE(node, STR("<node>boo</node>")); CHECK_NODE(node, STR("<node>boo</node>"));
t.set(STR("foobarfoobar")); t.set(STR("foobarfoobar"));
CHECK(node.first_child().type() == node_pcdata); CHECK(node.first_child().type() == node_pcdata);
CHECK(node.first_child() == node.last_child()); CHECK(node.first_child() == node.last_child());
CHECK_NODE(node, STR("<node>foobarfoobar</node>")); CHECK_NODE(node, STR("<node>foobarfoobar</node>"));
} }
TEST_XML(dom_text_assign, "<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>") TEST_XML(dom_text_middle, "<node><c1>notthisone</c1>text<c2/></node>")
{ {
xml_node node = doc.child(STR("node")); xml_node node = doc.child(STR("node"));
xml_text t = node.text(); xml_text t = node.text();
CHECK_STRING(t.get(), STR("text")); CHECK_STRING(t.get(), STR("text"));
t.set(STR("notext")); t.set(STR("notext"));
CHECK_NODE(node, STR("<node><c1>notthisone</c1>notext<c2/></node>")); CHECK_NODE(node, STR("<node><c1>notthisone</c1>notext<c2/></node>"));
CHECK(node.remove_child(t.data())); CHECK(node.remove_child(t.data()));
CHECK(!t); CHECK(!t);
CHECK_NODE(node, STR("<node><c1>notthisone</c1><c2/></node>")); CHECK_NODE(node, STR("<node><c1>notthisone</c1><c2/></node>"));
t.set(STR("yestext")); t.set(STR("yestext"));
CHECK(t); CHECK(t);
CHECK_NODE(node, STR("<node><c1>notthisone</c1><c2/>yestext</node>")); CHECK_NODE(node, STR("<node><c1>notthisone</c1><c2/>yestext</node>"));
CHECK(t.data() == node.last_child()); 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) 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("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("b")).text().data() == node.child(STR("b")).first_child());
CHECK(!node.child(STR("c")).text().data()); CHECK(!node.child(STR("c")).text().data());
CHECK(!node.child(STR("d")).text().data()); CHECK(!node.child(STR("d")).text().data());
CHECK(!xml_text().data()); CHECK(!xml_text().data());
} }
TEST(dom_text_defaults) TEST(dom_text_defaults)
{ {
xml_text text; xml_text text;
CHECK_STRING(text.as_string(STR("foo")), STR("foo")); CHECK_STRING(text.as_string(STR("foo")), STR("foo"));
CHECK(text.as_int(42) == 42); CHECK(text.as_int(42) == 42);
CHECK(text.as_uint(42) == 42); CHECK(text.as_uint(42) == 42);
CHECK(text.as_double(42) == 42); CHECK(text.as_double(42) == 42);
CHECK(text.as_float(42) == 42); CHECK(text.as_float(42) == 42);
CHECK(text.as_bool(true) == true); CHECK(text.as_bool(true) == true);
#ifdef PUGIXML_HAS_LONG_LONG #ifdef PUGIXML_HAS_LONG_LONG
CHECK(text.as_llong(42) == 42); CHECK(text.as_llong(42) == 42);
CHECK(text.as_ullong(42) == 42); CHECK(text.as_ullong(42) == 42);
#endif #endif
} }

View File

@ -4,28 +4,34 @@
#include "test.hpp" #include "test.hpp"
#include <string.h>
#include <stdio.h> #include <stdio.h>
#include <string.h>
#include <wchar.h> #include <wchar.h>
#include <utility>
#include <vector>
#include <iterator> #include <iterator>
#include <string> #include <string>
#include <utility>
#include <vector>
#include "helpers.hpp" #include "helpers.hpp"
using namespace pugi; using namespace pugi;
#ifdef PUGIXML_NO_STL #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; if (n > 0)
else while (n++) --base; while (n--)
++base;
else
while (n++)
--base;
return base; return base;
} }
#else #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); std::advance(base, n);
return base; return base;
@ -237,18 +243,18 @@ TEST_XML(dom_attr_as_ullong_hex, "<node attr1='0777' attr2='0x5ab' attr3='0XFf'
TEST(dom_attr_defaults) TEST(dom_attr_defaults)
{ {
xml_attribute attr; xml_attribute attr;
CHECK_STRING(attr.as_string(STR("foo")), STR("foo")); CHECK_STRING(attr.as_string(STR("foo")), STR("foo"));
CHECK(attr.as_int(42) == 42); CHECK(attr.as_int(42) == 42);
CHECK(attr.as_uint(42) == 42); CHECK(attr.as_uint(42) == 42);
CHECK(attr.as_double(42) == 42); CHECK(attr.as_double(42) == 42);
CHECK(attr.as_float(42) == 42); CHECK(attr.as_float(42) == 42);
CHECK(attr.as_bool(true) == true); CHECK(attr.as_bool(true) == true);
#ifdef PUGIXML_HAS_LONG_LONG #ifdef PUGIXML_HAS_LONG_LONG
CHECK(attr.as_llong(42) == 42); CHECK(attr.as_llong(42) == 42);
CHECK(attr.as_ullong(42) == 42); CHECK(attr.as_ullong(42) == 42);
#endif #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'/>") 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 i1 = node.attributes_begin();
const xml_attribute_iterator i2 = ++xml_attribute_iterator(i1); const xml_attribute_iterator i2 = ++xml_attribute_iterator(i1);
const xml_attribute_iterator i3 = ++xml_attribute_iterator(i2); const xml_attribute_iterator i3 = ++xml_attribute_iterator(i2);
CHECK(*i1 == node.attribute(STR("attr1"))); CHECK(*i1 == node.attribute(STR("attr1")));
CHECK(*i2 == node.attribute(STR("attr2"))); CHECK(*i2 == node.attribute(STR("attr2")));
CHECK(i3 == node.attributes_end()); CHECK(i3 == node.attributes_end());
CHECK_STRING(i1->name(), STR("attr1")); CHECK_STRING(i1->name(), STR("attr1"));
CHECK_STRING(i2->name(), STR("attr2")); CHECK_STRING(i2->name(), STR("attr2"));
} }
TEST_XML(dom_node_bool_ops, "<node/>") 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>") 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 i1 = node.begin();
const xml_node_iterator i2 = ++xml_node_iterator(i1); const xml_node_iterator i2 = ++xml_node_iterator(i1);
const xml_node_iterator i3 = ++xml_node_iterator(i2); const xml_node_iterator i3 = ++xml_node_iterator(i2);
CHECK(*i1 == node.child(STR("child1"))); CHECK(*i1 == node.child(STR("child1")));
CHECK(*i2 == node.child(STR("child2"))); CHECK(*i2 == node.child(STR("child2")));
CHECK(i3 == node.end()); CHECK(i3 == node.end());
CHECK_STRING(i1->name(), STR("child1")); CHECK_STRING(i1->name(), STR("child1"));
CHECK_STRING(i2->name(), STR("child2")); CHECK_STRING(i2->name(), STR("child2"));
} }
TEST_XML(dom_node_parent, "<node><child/></node>") TEST_XML(dom_node_parent, "<node><child/></node>")
@ -659,11 +665,13 @@ struct find_predicate_const
{ {
bool result; 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; return result;
} }
@ -673,18 +681,20 @@ struct find_predicate_prefix
{ {
const char_t* 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 // 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; return std::basic_string<char_t>(obj.name()).compare(0, wcslen(prefix), prefix) == 0;
#else #else
return strncmp(obj.name(), prefix, strlen(prefix)) == 0; 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"))); 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; std::basic_string<char_t> log;
unsigned int call_count; unsigned int call_count;
unsigned int stop_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]; char buf[32];
sprintf(buf, "%d", depth()); sprintf(buf, "%d", depth());
#ifdef PUGIXML_WCHAR_MODE #ifdef PUGIXML_WCHAR_MODE
wchar_t wbuf[32]; wchar_t wbuf[32];
std::copy(buf, buf + strlen(buf) + 1, &wbuf[0]); std::copy(buf, buf + strlen(buf) + 1, &wbuf[0]);
return std::basic_string<char_t>(wbuf); return std::basic_string<char_t>(wbuf);
#else #else
return std::basic_string<char_t>(buf); return std::basic_string<char_t>(buf);
#endif #endif
} }
virtual bool begin(xml_node& node) PUGIXML_OVERRIDE 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) TEST(dom_offset_debug_encoding)
{ {
char buf[] = { 0, '<', 0, 'n', 0, '/', 0, '>' }; char buf[] = {0, '<', 0, 'n', 0, '/', 0, '>'};
xml_document doc; xml_document doc;
CHECK(doc.load_buffer(buf, sizeof(buf))); 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_node().internal_object() == 0);
CHECK(xml_attribute().internal_object() == 0); CHECK(xml_attribute().internal_object() == 0);
CHECK(node.internal_object() != 0); CHECK(node.internal_object() != 0);
CHECK(value.internal_object() != 0); CHECK(value.internal_object() != 0);
CHECK(node.internal_object() != value.internal_object()); CHECK(node.internal_object() != value.internal_object());
CHECK(attr.internal_object() != 0); CHECK(attr.internal_object() != 0);
xml_node node_copy = node; xml_node node_copy = node;
CHECK(node_copy.internal_object() == node.internal_object()); CHECK(node_copy.internal_object() == node.internal_object());
xml_attribute attr_copy = attr; xml_attribute attr_copy = attr;
CHECK(attr_copy.internal_object() == attr.internal_object()); CHECK(attr_copy.internal_object() == attr.internal_object());
} }
TEST_XML(dom_hash_value, "<node attr='value'>value</node>") 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_node().hash_value() == 0);
CHECK(xml_attribute().hash_value() == 0); CHECK(xml_attribute().hash_value() == 0);
CHECK(node.hash_value() != 0); CHECK(node.hash_value() != 0);
CHECK(value.hash_value() != 0); CHECK(value.hash_value() != 0);
CHECK(node.hash_value() != value.hash_value()); CHECK(node.hash_value() != value.hash_value());
CHECK(attr.hash_value() != 0); CHECK(attr.hash_value() != 0);
xml_node node_copy = node; xml_node node_copy = node;
CHECK(node_copy.hash_value() == node.hash_value()); CHECK(node_copy.hash_value() == node.hash_value());
xml_attribute attr_copy = attr; xml_attribute attr_copy = attr;
CHECK(attr_copy.hash_value() == attr.hash_value()); 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>") 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; 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); CHECK(a.as_int() == index);
index++; index++;
} }
for (xml_node c: n.children(STR("test"))) for (xml_node c : n.children(STR("test")))
{ {
CHECK(c.text().as_int() == index); CHECK(c.text().as_int() == index);
index++; index++;

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,7 +1,7 @@
#include "test.hpp" #include "test.hpp"
#include "writer_string.hpp"
#include "allocator.hpp" #include "allocator.hpp"
#include "writer_string.hpp"
#include <string> #include <string>
#include <vector> #include <vector>
@ -10,28 +10,28 @@ using namespace pugi;
namespace namespace
{ {
int page_allocs = 0; int page_allocs = 0;
int page_deallocs = 0; int page_deallocs = 0;
bool is_page(size_t size) bool is_page(size_t size)
{ {
return size >= 16384; 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);
}
} }
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) TEST(memory_custom_memory_management)
{ {
page_allocs = page_deallocs = 0; page_allocs = page_deallocs = 0;
@ -116,7 +116,7 @@ TEST(memory_large_allocations)
} }
// prune // prune
for (node = doc.first_child(); node; ) for (node = doc.first_child(); node;)
{ {
xml_node next = node.next_sibling().next_sibling(); 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"); 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) 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"); 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) 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) 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()) for (xml_node c = n.first_child(); c; c = c.next_sibling())
result += get_tree_node_count(c); result += get_tree_node_count(c);
return result; return result;
} }
TEST(parse_ws_pcdata_permutations) TEST(parse_ws_pcdata_permutations)
{ {
struct test_data_t struct test_data_t
{ {
unsigned int mask; // 1 = default flags, 2 = parse_ws_pcdata, 4 = parse_ws_pcdata_single unsigned int mask; // 1 = default flags, 2 = parse_ws_pcdata, 4 = parse_ws_pcdata_single
const char_t* source; const char_t* source;
const char_t* result; const char_t* result;
int nodes; // negative if parsing should fail int nodes; // negative if parsing should fail
}; };
test_data_t test_data[] = test_data_t test_data[] =
{ {
// external pcdata should be discarded (whitespace or not) // external pcdata should be discarded (whitespace or not)
{7, STR("ext1<node/>"), STR("<node/>"), 2}, {7, STR("ext1<node/>"), STR("<node/>"), 2},
{7, STR("ext1<node/>ext2"), 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}, {7, STR("<node/> "), STR("<node/>"), 2},
{7, STR(" <node/> "), STR("<node/>"), 2}, {7, STR(" <node/> "), STR("<node/>"), 2},
// inner pcdata should be preserved // inner pcdata should be preserved
{7, STR("<node>inner</node>"), STR("<node>inner</node>"), 3}, {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/>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}, {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 // 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>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><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>inner1<child></child></node>"), STR("<node>inner1<child/></node>"), 4},
{7, STR("<node><child></child></node>"), STR("<node><child/></node>"), 3}, {7, STR("<node><child></child></node>"), STR("<node><child/></node>"), 3},
// comments, pi or other nodes should not cause pcdata creation either // 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}, {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) // 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}, {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 // 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}, {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}, {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}, {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 // 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}, {4, STR("<node>\t\t<!---->\n\n</node>"), STR("<node>\n\n</node>"), 3},
// error case: terminate PCDATA in the middle // error case: terminate PCDATA in the middle
{7, STR("<node>abcdef"), STR("<node>abcdef</node>"), -3}, {7, STR("<node>abcdef"), STR("<node>abcdef</node>"), -3},
{5, STR("<node> "), STR("<node/>"), -2}, {5, STR("<node> "), STR("<node/>"), -2},
{2, STR("<node> "), STR("<node> </node>"), -3}, {2, STR("<node> "), STR("<node> </node>"), -3},
// error case: terminate PCDATA as early as possible // error case: terminate PCDATA as early as possible
{7, STR("<node>"), STR("<node/>"), -2}, {7, STR("<node>"), STR("<node/>"), -2},
{7, STR("<node>a"), STR("<node>a</node>"), -3}, {7, STR("<node>a"), STR("<node>a</node>"), -3},
{5, STR("<node> "), STR("<node/>"), -2}, {5, STR("<node> "), STR("<node/>"), -2},
{2, STR("<node> "), STR("<node> </node>"), -3}, {2, STR("<node> "), STR("<node> </node>"), -3},
}; };
for (size_t i = 0; i < sizeof(test_data) / sizeof(test_data[0]); ++i) for (size_t i = 0; i < sizeof(test_data) / sizeof(test_data[0]); ++i)
{ {
const test_data_t& td = test_data[i]; const test_data_t& td = test_data[i];
for (int flag = 0; flag < 3; ++flag) for (int flag = 0; flag < 3; ++flag)
{ {
if (td.mask & (1 << flag)) if (td.mask & (1 << flag))
{ {
unsigned int flags[] = {parse_default, parse_default | parse_ws_pcdata, parse_default | parse_ws_pcdata_single}; unsigned int flags[] = {parse_default, parse_default | parse_ws_pcdata, parse_default | parse_ws_pcdata_single};
xml_document doc; xml_document doc;
CHECK((td.nodes > 0) == doc.load_string(td.source, flags[flag])); CHECK((td.nodes > 0) == doc.load_string(td.source, flags[flag]));
CHECK_NODE(doc, td.result); CHECK_NODE(doc, td.result);
int nodes = get_tree_node_count(doc); int nodes = get_tree_node_count(doc);
CHECK((td.nodes < 0 ? -td.nodes : td.nodes) == nodes); CHECK((td.nodes < 0 ? -td.nodes : td.nodes) == nodes);
} }
} }
} }
} }
TEST(parse_ws_pcdata_fragment_permutations) TEST(parse_ws_pcdata_fragment_permutations)
{ {
struct test_data_t struct test_data_t
{ {
unsigned int mask; // 1 = default flags, 2 = parse_ws_pcdata, 4 = parse_ws_pcdata_single unsigned int mask; // 1 = default flags, 2 = parse_ws_pcdata, 4 = parse_ws_pcdata_single
const char_t* source; const char_t* source;
const char_t* result; const char_t* result;
int nodes; // negative if parsing should fail int nodes; // negative if parsing should fail
}; };
test_data_t test_data[] = test_data_t test_data[] =
{ {
// external pcdata should be preserved // external pcdata should be preserved
{7, STR("ext1"), STR("ext1"), 2}, {7, STR("ext1"), STR("ext1"), 2},
{5, STR(" "), STR(""), 1}, {5, STR(" "), STR(""), 1},
{2, STR(" "), STR(" "), 2}, {2, STR(" "), STR(" "), 2},
{7, STR("ext1<node/>"), STR("ext1<node/>"), 3}, {7, STR("ext1<node/>"), STR("ext1<node/>"), 3},
{7, STR("<node/>ext2"), STR("<node/>ext2"), 3}, {7, STR("<node/>ext2"), STR("<node/>ext2"), 3},
{7, STR("ext1<node/>ext2"), STR("ext1<node/>ext2"), 4}, {7, STR("ext1<node/>ext2"), STR("ext1<node/>ext2"), 4},
{7, STR("ext1<node1/>ext2<node2/>ext3"), STR("ext1<node1/>ext2<node2/>ext3"), 6}, {7, STR("ext1<node1/>ext2<node2/>ext3"), STR("ext1<node1/>ext2<node2/>ext3"), 6},
{5, STR(" <node/>"), STR("<node/>"), 2}, {5, STR(" <node/>"), STR("<node/>"), 2},
{2, STR(" <node/>"), STR(" <node/>"), 3}, {2, STR(" <node/>"), STR(" <node/>"), 3},
{5, STR("<node/> "), STR("<node/>"), 2}, {5, STR("<node/> "), STR("<node/>"), 2},
{2, STR("<node/> "), STR("<node/> "), 3}, {2, STR("<node/> "), STR("<node/> "), 3},
{5, STR(" <node/> "), STR("<node/>"), 2}, {5, STR(" <node/> "), STR("<node/>"), 2},
{2, STR(" <node/> "), STR(" <node/> "), 4}, {2, STR(" <node/> "), STR(" <node/> "), 4},
{5, STR(" <node1/> <node2/> "), STR("<node1/><node2/>"), 3}, {5, STR(" <node1/> <node2/> "), STR("<node1/><node2/>"), 3},
{2, STR(" <node1/> <node2/> "), STR(" <node1/> <node2/> "), 6}, {2, STR(" <node1/> <node2/> "), STR(" <node1/> <node2/> "), 6},
}; };
for (size_t i = 0; i < sizeof(test_data) / sizeof(test_data[0]); ++i) for (size_t i = 0; i < sizeof(test_data) / sizeof(test_data[0]); ++i)
{ {
const test_data_t& td = test_data[i]; const test_data_t& td = test_data[i];
for (int flag = 0; flag < 3; ++flag) for (int flag = 0; flag < 3; ++flag)
{ {
if (td.mask & (1 << flag)) if (td.mask & (1 << flag))
{ {
unsigned int flags[] = {parse_default, parse_default | parse_ws_pcdata, parse_default | parse_ws_pcdata_single}; unsigned int flags[] = {parse_default, parse_default | parse_ws_pcdata, parse_default | parse_ws_pcdata_single};
xml_document doc; xml_document doc;
CHECK((td.nodes > 0) == doc.load_string(td.source, flags[flag] | parse_fragment)); CHECK((td.nodes > 0) == doc.load_string(td.source, flags[flag] | parse_fragment));
CHECK_NODE(doc, td.result); CHECK_NODE(doc, td.result);
int nodes = get_tree_node_count(doc); int nodes = get_tree_node_count(doc);
CHECK((td.nodes < 0 ? -td.nodes : td.nodes) == nodes); CHECK((td.nodes < 0 ? -td.nodes : td.nodes) == nodes);
} }
} }
} }
} }
TEST(parse_pcdata_no_eol) TEST(parse_pcdata_no_eol)
@ -439,49 +439,48 @@ TEST(parse_pcdata_error)
TEST(parse_pcdata_trim) TEST(parse_pcdata_trim)
{ {
struct test_data_t struct test_data_t
{ {
const char_t* source; const char_t* source;
const char_t* result; const char_t* result;
unsigned int flags; unsigned int flags;
}; };
test_data_t test_data[] = test_data_t test_data[] =
{ {
{ STR("<node> text</node>"), STR("text"), 0 }, {STR("<node> text</node>"), STR("text"), 0},
{ STR("<node>\t\n text</node>"), STR("text"), 0 }, {STR("<node>\t\n text</node>"), STR("text"), 0},
{ STR("<node>text </node>"), STR("text"), 0 }, {STR("<node>text </node>"), STR("text"), 0},
{ STR("<node>text \t\n</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("<node>\r\n\t text \t\n\r</node>"), STR("text"), 0},
{ STR(" text"), STR("text"), parse_fragment }, {STR(" text"), STR("text"), parse_fragment},
{ STR("\t\n text"), STR("text"), parse_fragment }, {STR("\t\n text"), STR("text"), parse_fragment},
{ STR("text "), STR("text"), parse_fragment }, {STR("text "), STR("text"), parse_fragment},
{ STR("text \t\n"), 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("\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\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 \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>\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&amp;&amp;&amp;&amp;&amp;&amp;&amp;"), 0},
{ STR("<node> test&amp;&amp;&amp;&amp;&amp;&amp;&amp; </node>"), STR("test&&&&&&&"), parse_escapes }, {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(" 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 } {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) for (size_t i = 0; i < sizeof(test_data) / sizeof(test_data[0]); ++i)
{ {
const test_data_t& td = test_data[i]; const test_data_t& td = test_data[i];
xml_document doc; xml_document doc;
CHECK(doc.load_string(td.source, td.flags | parse_trim_pcdata)); 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(); const char_t* value = doc.child(STR("node")) ? doc.child_value(STR("node")) : doc.text().get();
CHECK_STRING(value, td.result); CHECK_STRING(value, td.result);
} }
} }
TEST(parse_pcdata_trim_empty) 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) for (size_t i = 0; i < sizeof(flags) / sizeof(flags[0]); ++i)
{ {
@ -696,7 +695,6 @@ TEST(parse_attribute_variations)
} }
} }
TEST(parse_attribute_error) TEST(parse_attribute_error)
{ {
xml_document doc; xml_document doc;
@ -926,10 +924,10 @@ TEST(parse_out_of_memory_halfway_node)
for (unsigned int i = 0; i < count; ++i) for (unsigned int i = 0; i < count; ++i)
{ {
text[4*i + 0] = '<'; text[4 * i + 0] = '<';
text[4*i + 1] = 'n'; text[4 * i + 1] = 'n';
text[4*i + 2] = '/'; text[4 * i + 2] = '/';
text[4*i + 3] = '>'; text[4 * i + 3] = '>';
} }
test_runner::_memory_fail_threshold = 65536; 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) for (unsigned int i = 0; i < count; ++i)
{ {
text[5*i + 2] = ' '; text[5 * i + 2] = ' ';
text[5*i + 3] = 'a'; text[5 * i + 3] = 'a';
text[5*i + 4] = '='; text[5 * i + 4] = '=';
text[5*i + 5] = '"'; text[5 * i + 5] = '"';
text[5*i + 6] = '"'; text[5 * i + 6] = '"';
} }
text[5 * count + 2] = '/'; text[5 * count + 2] = '/';
@ -984,10 +982,10 @@ TEST(parse_out_of_memory_allocator_state_sync)
for (unsigned int i = 0; i < count; ++i) for (unsigned int i = 0; i < count; ++i)
{ {
text[4*i + 0] = '<'; text[4 * i + 0] = '<';
text[4*i + 1] = 'n'; text[4 * i + 1] = 'n';
text[4*i + 2] = '/'; text[4 * i + 2] = '/';
text[4*i + 3] = '>'; text[4 * i + 3] = '>';
} }
test_runner::_memory_fail_threshold = 65536; test_runner::_memory_fail_threshold = 65536;
@ -1072,18 +1070,18 @@ TEST(parse_bom_fragment)
}; };
const test_data_t data[] = const test_data_t data[] =
{ {
{ encoding_utf8, "\xef\xbb\xbf", 3, STR("") }, {encoding_utf8, "\xef\xbb\xbf", 3, STR("")},
{ encoding_utf8, "\xef\xbb\xbftest", 7, STR("test") }, {encoding_utf8, "\xef\xbb\xbftest", 7, STR("test")},
{ encoding_utf16_be, "\xfe\xff", 2, STR("") }, {encoding_utf16_be, "\xfe\xff", 2, STR("")},
{ encoding_utf16_be, "\xfe\xff\x00t\x00o\x00s\x00t", 10, STR("tost") }, {encoding_utf16_be, "\xfe\xff\x00t\x00o\x00s\x00t", 10, STR("tost")},
{ encoding_utf16_le, "\xff\xfe", 2, STR("") }, {encoding_utf16_le, "\xff\xfe", 2, STR("")},
{ encoding_utf16_le, "\xff\xfet\x00o\x00s\x00t\x00", 10, STR("tost") }, {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", 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_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\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_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) 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) TEST(parse_fuzz_doctype)
{ {
unsigned char data[] = unsigned char data[] =
{ {
0x3b, 0x3c, 0x21, 0x44, 0x4f, 0x43, 0x54, 0x59, 0x50, 0x45, 0xef, 0xbb, 0xbf, 0x3c, 0x3f, 0x78, 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, 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, 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 0xe3, 0x83, 0xb3, 0x20, 0xef, 0x83, 0x97, 0xe3, 0xa9, 0x2a, 0x20, 0x2d, 0x2d, 0x3e};
};
xml_document doc; xml_document doc;
CHECK(doc.load_buffer(data, sizeof(data)).status == status_bad_doctype); 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("outer"));
CHECK_STRING(child.child_value(STR("inner2")), STR("value2")); 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); 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(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); 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[] = const data_t data[] =
{ {
// BOM // BOM
{ "\x00\x00\xfe\xff", 4, encoding_utf32_be }, {"\x00\x00\xfe\xff", 4, encoding_utf32_be},
{ "\xff\xfe\x00\x00", 4, encoding_utf32_le }, {"\xff\xfe\x00\x00", 4, encoding_utf32_le},
{ "\xfe\xff ", 4, encoding_utf16_be }, {"\xfe\xff ", 4, encoding_utf16_be},
{ "\xff\xfe ", 4, encoding_utf16_le }, {"\xff\xfe ", 4, encoding_utf16_le},
{ "\xef\xbb\xbf ", 4, encoding_utf8 }, {"\xef\xbb\xbf ", 4, encoding_utf8},
// automatic tag detection for < or <? // automatic tag detection for < or <?
{ "\x00\x00\x00<\x00\x00\x00n\x00\x00\x00/\x00\x00\x00>", 16, encoding_utf32_be }, {"\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\x00/\x00\x00\x00>\x00\x00\x00", 16, encoding_utf32_le},
{ "\x00<\x00?\x00n\x00?\x00>", 10, encoding_utf16_be }, {"\x00<\x00?\x00n\x00?\x00>", 10, encoding_utf16_be},
{ "<\x00?\x00n\x00?\x00>\x00", 10, encoding_utf16_le }, {"<\x00?\x00n\x00?\x00>\x00", 10, encoding_utf16_le},
{ "\x00<\x00n\x00/\x00>", 8, encoding_utf16_be }, {"\x00<\x00n\x00/\x00>", 8, encoding_utf16_be},
{ "<\x00n\x00/\x00>\x00", 8, encoding_utf16_le }, {"<\x00n\x00/\x00>\x00", 8, encoding_utf16_le},
// <?xml encoding // <?xml encoding
{ "<?xml encoding='latin1'?>", 25, encoding_latin1 }, {"<?xml encoding='latin1'?>", 25, encoding_latin1},
}; };
for (size_t i = 0; i < sizeof(data) / sizeof(data[0]); ++i) 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[] = const data_t data[] =
{ {
// BOM // BOM
{ "\x00\x00\xfe ", 4, encoding_utf8 }, {"\x00\x00\xfe ", 4, encoding_utf8},
{ "\x00\x00 ", 4, encoding_utf8 }, {"\x00\x00 ", 4, encoding_utf8},
{ "\xff\xfe\x00 ", 4, encoding_utf16_le }, {"\xff\xfe\x00 ", 4, encoding_utf16_le},
{ "\xfe ", 4, encoding_utf8 }, {"\xfe ", 4, encoding_utf8},
{ "\xff ", 4, encoding_utf8 }, {"\xff ", 4, encoding_utf8},
{ "\xef\xbb ", 4, encoding_utf8 }, {"\xef\xbb ", 4, encoding_utf8},
{ "\xef ", 4, encoding_utf8 }, {"\xef ", 4, encoding_utf8},
// automatic tag detection for < or <? // automatic tag detection for < or <?
{ "\x00\x00\x00 ", 4, encoding_utf8 }, {"\x00\x00\x00 ", 4, encoding_utf8},
{ "<\x00\x00n/\x00>\x00", 8, encoding_utf16_le }, {"<\x00\x00n/\x00>\x00", 8, encoding_utf16_le},
{ "\x00<n\x00\x00/\x00>", 8, encoding_utf16_be }, {"\x00<n\x00\x00/\x00>", 8, encoding_utf16_be},
{ "<\x00?n/\x00>\x00", 8, encoding_utf16_le }, {"<\x00?n/\x00>\x00", 8, encoding_utf16_le},
{ "\x00 ", 2, encoding_utf8 }, {"\x00 ", 2, encoding_utf8},
// <?xml encoding // <?xml encoding
{ "<?xmC encoding='latin1'?>", 25, encoding_utf8 }, {"<?xmC encoding='latin1'?>", 25, encoding_utf8},
{ "<?xBC encoding='latin1'?>", 25, encoding_utf8 }, {"<?xBC encoding='latin1'?>", 25, encoding_utf8},
{ "<?ABC encoding='latin1'?>", 25, encoding_utf8 }, {"<?ABC 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) for (size_t i = 0; i < sizeof(data) / sizeof(data[0]); ++i)
{ {

View File

@ -3,8 +3,8 @@
#include "test.hpp" #include "test.hpp"
#include <string.h> #include <string.h>
#include <wchar.h>
#include <string> #include <string>
#include <wchar.h>
using namespace pugi; using namespace pugi;
@ -30,21 +30,28 @@ static bool test_doctype_wf(const char_t* decl)
xml_document doc; xml_document doc;
// standalone // 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 // pcdata pre/postfix
if (!load_concat(doc, STR("a"), decl) || !test_node(doc, STR("a"), STR(""), format_raw)) return false; if (!load_concat(doc, STR("a"), decl) || !test_node(doc, STR("a"), STR(""), format_raw))
if (!load_concat(doc, decl, STR("b")) || !test_node(doc, STR("b"), STR(""), format_raw)) return false; 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, 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 // node pre/postfix
if (!load_concat(doc, STR("<nodea/>"), decl) || !test_node(doc, STR("<nodea/>"), STR(""), format_raw)) return false; if (!load_concat(doc, STR("<nodea/>"), decl) || !test_node(doc, STR("<nodea/>"), STR(""), format_raw))
if (!load_concat(doc, decl, STR("<nodeb/>")) || !test_node(doc, STR("<nodeb/>"), STR(""), format_raw)) return false; 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, 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 load-store contents preservation
CHECK(doc.load_string(decl, parse_doctype | parse_fragment)); CHECK(doc.load_string(decl, parse_doctype | parse_fragment));
CHECK_NODE(doc, decl); CHECK_NODE(doc, decl);
return true; return true;
} }
@ -54,13 +61,16 @@ static bool test_doctype_nwf(const char_t* decl)
xml_document doc; xml_document doc;
// standalone // 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 // 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 // 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; 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 [ <!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>]>"); TEST_DOCTYPE_WF("<!DOCTYPE doc SYSTEM \"p31pass1.dtd\" [<!ELEMENT doc EMPTY>]>");
// not actually a doctype :) // not actually a doctype :)
xml_document doc; 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("<!--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()); 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) 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(n.type() == node_doctype);
CHECK_STRING(n.value(), STR("doc [ <!ELEMENT doc (#PCDATA)> <!ENTITY e \"<![CDATA[Tim & Michael]]>\"> ]")); CHECK_STRING(n.value(), STR("doc [ <!ELEMENT doc (#PCDATA)> <!ENTITY e \"<![CDATA[Tim & Michael]]>\"> ]"));
} }
TEST(parse_doctype_error_toplevel) TEST(parse_doctype_error_toplevel)
{ {
xml_document doc; xml_document doc;
CHECK(doc.load_string(STR("<node><!DOCTYPE></node>")).status == status_bad_doctype); 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); CHECK(doc.load_string(STR("<node><!DOCTYPE></node>"), parse_doctype).status == status_bad_doctype);
} }
TEST(parse_doctype_error_ignore) 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[ ")).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[ "), parse_doctype).status == status_bad_doctype);
CHECK(doc.load_string(STR("<!DOCTYPE root [ <![IGNORE[ <![INCLUDE[")).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) 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) TEST(as_utf8_empty)
@ -110,11 +110,11 @@ TEST(as_utf8_valid_astral)
} }
else else
{ {
#ifdef U_LITERALS #ifdef U_LITERALS
CHECK(as_utf8(L"\uda1d\ude24 \udbc0\udfff") == "\xf2\x97\x98\xa4 \xf4\x80\x8f\xbf"); 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"); 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) if (wcharsize == 2)
{ {
// check non-terminated degenerate handling // 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");
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");
CHECK(as_utf8(L"a\xda1d_") == "a_"); CHECK(as_utf8(L"a\xda1d_") == "a_");
#endif #endif
// check incorrect leading code // check incorrect leading code
#ifdef U_LITERALS #ifdef U_LITERALS
CHECK(as_utf8(L"a\ude24") == "a"); CHECK(as_utf8(L"a\ude24") == "a");
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");
CHECK(as_utf8(L"a\xde24_") == "a_"); CHECK(as_utf8(L"a\xde24_") == "a_");
#endif #endif
} }
} }
TEST(as_utf8_string) 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 #endif

View File

@ -2,9 +2,9 @@
#include "writer_string.hpp" #include "writer_string.hpp"
#include <string>
#include <sstream> #include <sstream>
#include <stdexcept> #include <stdexcept>
#include <string>
using namespace pugi; using namespace pugi;
@ -199,11 +199,11 @@ TEST_XML(write_escape, "<node attr=''>text</node>")
TEST_XML(write_escape_unicode, "<node attr='&#x3c00;'/>") TEST_XML(write_escape_unicode, "<node attr='&#x3c00;'/>")
{ {
#ifdef PUGIXML_WCHAR_MODE #ifdef PUGIXML_WCHAR_MODE
#ifdef U_LITERALS #ifdef U_LITERALS
CHECK_NODE(doc, STR("<node attr=\"\u3c00\"/>")); CHECK_NODE(doc, STR("<node attr=\"\u3c00\"/>"));
#else #else
CHECK_NODE(doc, STR("<node attr=\"\x3c00\"/>")); CHECK_NODE(doc, STR("<node attr=\"\x3c00\"/>"));
#endif #endif
#else #else
CHECK_NODE(doc, STR("<node attr=\"\xe3\xb0\x80\"/>")); CHECK_NODE(doc, STR("<node attr=\"\xe3\xb0\x80\"/>"));
#endif #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); 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; 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(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 #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) // 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); 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); s_utf16 += std::string("\x00/\x00>", 4);
@ -322,7 +323,8 @@ TEST(write_encoding_huge)
std::string s_utf8 = "<"; 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"; s_utf8 += " />\n";
@ -340,7 +342,8 @@ TEST(write_encoding_huge_invalid)
// make a large utf16 name consisting of leading surrogate chars // make a large utf16 name consisting of leading surrogate chars
std::basic_string<wchar_t> s_utf16; 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; xml_document doc;
doc.append_child().set_name(s_utf16.c_str()); 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) // 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 = "<"; 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 += "/>"; s_utf8 += "/>";
@ -365,7 +369,8 @@ TEST(write_encoding_huge)
std::string s_utf16 = std::string("\x00<", 2); 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); 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 // make a large utf8 name consisting of non-leading chars
std::string s_utf8; 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; xml_document doc;
doc.append_child().set_name(s_utf8.c_str()); doc.append_child().set_name(s_utf8.c_str());
@ -416,22 +422,22 @@ TEST(write_unicode_invalid_utf16)
if (wcharsize == 2) if (wcharsize == 2)
{ {
// check non-terminated degenerate handling // 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"));
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"));
CHECK(test_write_unicode_invalid(L"a\xda1d_", "a_")); CHECK(test_write_unicode_invalid(L"a\xda1d_", "a_"));
#endif #endif
// check incorrect leading code // 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"));
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"));
CHECK(test_write_unicode_invalid(L"a\xde24_", "a_")); CHECK(test_write_unicode_invalid(L"a\xde24_", "a_"));
#endif #endif
} }
} }
#else #else
@ -569,19 +575,17 @@ TEST(write_pcdata_whitespace_fixedpoint)
const char_t* data = STR("<node> test <child>\n <sub/>\n </child>\n</node>"); const char_t* data = STR("<node> test <child>\n <sub/>\n </child>\n</node>");
static const unsigned int flags_parse[] = static const unsigned int flags_parse[] =
{ {
0, 0,
parse_ws_pcdata, parse_ws_pcdata,
parse_ws_pcdata_single, parse_ws_pcdata_single,
parse_trim_pcdata parse_trim_pcdata};
};
static const unsigned int flags_format[] = static const unsigned int flags_format[] =
{ {
0, 0,
format_raw, format_raw,
format_indent format_indent};
};
for (unsigned int i = 0; i < sizeof(flags_parse) / sizeof(flags_parse[0]); ++i) 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) 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]); size_t flagcount = sizeof(flagset) / sizeof(flagset[0]);
for (size_t i = 0; i < (size_t(1) << flagcount); ++i) for (size_t i = 0; i < (size_t(1) << flagcount); ++i)
@ -669,7 +673,7 @@ TEST(write_flush_coverage)
} }
#ifndef PUGIXML_NO_EXCEPTIONS #ifndef PUGIXML_NO_EXCEPTIONS
struct throwing_writer: xml_writer struct throwing_writer : xml_writer
{ {
virtual void write(const void*, size_t) PUGIXML_OVERRIDE virtual void write(const void*, size_t) PUGIXML_OVERRIDE
{ {

View File

@ -5,10 +5,10 @@
#include <string.h> #include <string.h>
#include <wchar.h> #include <wchar.h>
#include <string>
#include <vector>
#include <algorithm> #include <algorithm>
#include <limits> #include <limits>
#include <string>
#include <vector>
using namespace pugi; using namespace pugi;
@ -24,7 +24,8 @@ TEST(xpath_allocator_many_pages)
{ {
std::basic_string<char_t> query = STR("0"); 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); CHECK_XPATH_NUMBER(xml_node(), query.c_str(), 1024);
} }
@ -33,7 +34,8 @@ TEST(xpath_allocator_large_page)
{ {
std::basic_string<char_t> query; 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); 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; xml_document doc;
load_document_copy(doc, STR("<node>") 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("</node>")); STR("</node>"));
xpath_node_set ns = doc.select_nodes(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"); 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) TEST(xpath_sort_random_large)
{ {
xml_document doc; xml_document doc;
load_document_copy(doc, STR("<node>") 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><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></node>"));
xpath_node_set ns = doc.select_nodes(STR("//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"); 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) TEST(xpath_long_numbers_parse)
@ -247,7 +251,8 @@ TEST(xpath_denorm_numbers)
// 10^-318 - double denormal // 10^-318 - double denormal
for (int i = 0; i < 106; ++i) for (int i = 0; i < 106; ++i)
{ {
if (i != 0) query += STR(" * "); if (i != 0)
query += STR(" * ");
query += STR("0.001"); 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>") 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[../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; 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>") TEST_XML(xpath_sort_empty_node, "<node><child1/><child2/></node>")
{ {
xml_node n = doc.child(STR("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])); xpath_node_set ns(nodes, nodes + sizeof(nodes) / sizeof(nodes[0]));
ns.sort(); ns.sort();
@ -728,9 +733,10 @@ TEST(xpath_allocate_string_out_of_memory)
{ {
std::basic_string<char_t> query; 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... #ifndef __DMC__ // DigitalMars exception handling crashes instead of catching the exception...
CHECK_ALLOC_FAIL(CHECK(!xpath_query(query.c_str()))); 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) TEST(xpath_api_nodeset_copy_empty)
{ {
xpath_node_set set; xpath_node_set set;
xpath_node_set set2 = set; xpath_node_set set2 = set;
xpath_node_set set3; xpath_node_set set3;
set3 = set; set3 = set;
} }
TEST_XML(xpath_api_evaluate, "<node attr='3'/>") 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()); CHECK(move[1] == doc.first_child().first_child());
} }
TEST_XML(xpath_api_nodeset_move_ctor_single, "<node><foo/><foo/><bar/></node>") TEST_XML(xpath_api_nodeset_move_ctor_single, "<node><foo/><foo/><bar/></node>")
{ {
xpath_node_set set = doc.select_nodes(STR("node/bar")); 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(.)"), 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(./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(.)")); CHECK_XPATH_NUMBER_NAN(doc.last_child(), STR("sum(.)"));
// sum with 2 arguments // 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>") 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, 'fo')"), STR("obar"));
CHECK_XPATH_STRING(doc, STR("substring-after(node, 'fooba')"), STR("r")); 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, 'foobar')"), STR(""));
} }
TEST(xpath_string_substring) 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('abcd', 0 div 0)"), STR(""));
CHECK_XPATH_STRING(c, STR("substring('', 1)"), STR("")); CHECK_XPATH_STRING(c, STR("substring('', 1)"), STR(""));
CHECK_XPATH_STRING(c, STR("substring('', 0)"), 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 // substring with 3 arguments
CHECK_XPATH_STRING(c, STR("substring('abcd', 2, 1)"), STR("b")); 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>") 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, 3)"), STR("obar"));
CHECK_XPATH_STRING(doc, STR("substring(node, 6)"), STR("r")); 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, 7)"), STR(""));
} }
TEST_XML(xpath_string_string_length, "<node>123</node>") 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 // last with 0 arguments
CHECK_XPATH_NUMBER(n, STR("last()"), 1); CHECK_XPATH_NUMBER(n, STR("last()"), 1);
CHECK_XPATH_NODESET(n, STR("c1[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 CHECK_XPATH_NODESET(n, STR("c2/preceding-sibling::node()[last() = 2]")) % 4 % 3; // c1, c1
// last with 1 argument // last with 1 argument
@ -829,7 +829,8 @@ TEST(xpath_string_translate_table_out_of_memory)
for (size_t i = 0; i < count; ++i) for (size_t i = 0; i < count; ++i)
{ {
if (i != 0) query += STR(","); if (i != 0)
query += STR(",");
query += STR("translate('a','a','A')"); query += STR("translate('a','a','A')");
} }

View File

@ -99,82 +99,80 @@ TEST(xpath_semantics_posinv) // coverage for contains()
TEST(xpath_parse_paths_valid) TEST(xpath_parse_paths_valid)
{ {
const char_t* paths[] = const char_t* paths[] =
{ {
// From Jaxen tests // From Jaxen tests
STR("foo[.='bar']"), STR("foo[.!='bar']"), STR("/"), STR("*"), STR("//foo"), STR("/*"), STR("/."), STR("/foo[/bar[/baz]]"), 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/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[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/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("/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("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("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("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("/foo/bar[@a='1' and @b='2']"), STR("/foo/bar[@a='1' and @b!='2']"), STR("//attribute::*[.!='crunchy']"), STR("'//*[contains(string(text()),\"yada yada\")]'"),
STR("'//*[contains(string(text()),\"yada yada\")]'"),
// From ajaxslt tests // From ajaxslt tests
STR("@*"), STR("@*|node()"), STR("/descendant-or-self::div"), STR("/div"), STR("//div"), STR("/descendant-or-self::node()/child::para"), 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("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("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("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("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("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("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("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("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::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::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("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='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']/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']/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']/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("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("(//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("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("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("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' 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("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("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(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("(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("@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("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(//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("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("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/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("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("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("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("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/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("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("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/@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("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("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(../@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("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("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("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("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(\"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("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("//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 \")]"), 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 // ajaxslt considers this path invalid, however I believe it's valid as per spec
STR("***"), STR("***"),
// Oasis MSFT considers this path invalid, however I believe it's valid as per spec // Oasis MSFT considers this path invalid, however I believe it's valid as per spec
STR("**..**"), STR("**..**"),
// Miscellaneous // Miscellaneous
STR("..***..***.***.***..***..***..") STR("..***..***.***.***..***..***..")};
};
for (size_t i = 0; i < sizeof(paths) / sizeof(paths[0]); ++i) 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) #if defined(PUGIXML_WCHAR_MODE) || !defined(PUGIXML_NO_STL)
TEST(xpath_parse_paths_valid_unicode) TEST(xpath_parse_paths_valid_unicode)
{ {
// From ajaxslt // From ajaxslt
const wchar_t* paths[] = const wchar_t* paths[] =
{ {
#ifdef U_LITERALS #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"/descendant-or-self::\u90e8\u5206",
L"\u8b0e//\u30bf\u30a4\u30c8\u30eb", L"//*[@\u30c7\u30b9\u30c6\u30a3\u30cd\u30a4\u30b7\u30e7\u30f3]", L"\u30da\u30fc\u30b8 = '\u304b\u3089'", L"//\u90e8\u5206",
L"concat(substring-before(@\u30a4\u30e1\u30fc\u30b8,'\u76ee\u5370'),'\u30a2\u30a4\u30b3\u30f3',substring-after(@\u30a4\u30e1\u30fc\u30b8,'\u76ee\u5370'))", L"substring('\uff11\uff12\uff13\uff14\uff15', 0, 3)",
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"//\u30bf\u30a4\u30c8\u30eb | //\u30ea\u30f3\u30af",
L"substring-after(\u30a2\u30a4\u30b3\u30f3/@\u30a4\u30e1\u30fc\u30b8, '/\u5730\u56f3\u30d5\u30a1\u30a4\u30eb/\u76ee\u5370')", L"child::\u6bb5\u843d", L"\u8b0e//\u30bf\u30a4\u30c8\u30eb",
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"//*[@\u30c7\u30b9\u30c6\u30a3\u30cd\u30a4\u30b7\u30e7\u30f3]",
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"\u30da\u30fc\u30b8 = '\u304b\u3089'",
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"concat(substring-before(@\u30a4\u30e1\u30fc\u30b8,'\u76ee\u5370'),'\u30a2\u30a4\u30b3\u30f3',substring-after(@\u30a4\u30e1\u30fc\u30b8,'\u76ee\u5370'))",
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"\u30bd\u30fc\u30b9|\u30c7\u30b9\u30c6\u30a3\u30cd\u30a4\u30b7\u30e7\u30f3",
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"\u30da\u30fc\u30b8 != '\u307e\u3067' and \u30da\u30fc\u30b8 != '\u304b\u3089'",
L"child::\u6bb5\u843d[attribute::\u30bf\u30a4\u30d7='\u8b66\u544a']", L"child::\u6bb5\u843d[attribute::\u30bf\u30a4\u30d7='\u8b66\u544a'][position()=5]", L"substring-after(\u30a2\u30a4\u30b3\u30f3/@\u30a4\u30e1\u30fc\u30b8, '/\u5730\u56f3\u30d5\u30a1\u30a4\u30eb/\u76ee\u5370')",
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::\u6bb5\u843d",
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()]", L"substring-before(\u6587\u5b57\u5217, \u6587\u5b57)",
#else L"\u30bb\u30b0\u30e1\u30f3\u30c8/@\u6642\u523b",
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"attribute::\u540d\u524d",
L"\x8b0e//\x30bf\x30a4\x30c8\x30eb", L"//*[@\x30c7\x30b9\x30c6\x30a3\x30cd\x30a4\x30b7\x30e7\x30f3]", L"\x30da\x30fc\x30b8 = '\x304b\x3089'", L"descendant::\u6bb5\u843d",
L"concat(substring-before(@\x30a4\x30e1\x30fc\x30b8,'\x76ee\x5370'),'\x30a2\x30a4\x30b3\x30f3',substring-after(@\x30a4\x30e1\x30fc\x30b8,'\x76ee\x5370'))", L"ancestor::\u90e8\u5206",
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"ancestor-or-self::\u90e8\u5206",
L"substring-after(\x30a2\x30a4\x30b3\x30f3/@\x30a4\x30e1\x30fc\x30b8, '/\x5730\x56f3\x30d5\x30a1\x30a4\x30eb/\x76ee\x5370')", L"child::\x6bb5\x843d", L"descendant-or-self::\u6bb5\u843d",
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"self::\u6bb5\u843d",
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::\u7ae0/descendant::\u6bb5\u843d",
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::*/child::\u6bb5\u843d",
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"/descendant::\u6bb5\u843d",
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"/descendant::\u9806\u5e8f\u30ea\u30b9\u30c8/child::\u9805\u76ee",
L"child::\x6bb5\x843d[attribute::\x30bf\x30a4\x30d7='\x8b66\x544a']", L"child::\x6bb5\x843d[attribute::\x30bf\x30a4\x30d7='\x8b66\x544a'][position()=5]", L"child::\u6bb5\u843d[position()=1]",
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::\u6bb5\u843d[position()=last()]",
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()]", L"child::\u6bb5\u843d[position()=last()-1]",
#endif 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) 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]); 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]); std::basic_string<char> path_utf8 = as_utf8(paths[i]);
xpath_query q(path_utf8.c_str()); xpath_query q(path_utf8.c_str());
#endif #endif
} }
} }
#endif #endif
TEST(xpath_parse_invalid) TEST(xpath_parse_invalid)
{ {
const char_t* paths[] = const char_t* paths[] =
{ {
// From Jaxen tests // From Jaxen tests
STR("//:p"), STR("/foo/bar/"), STR("12 + (count(//author)+count(//author/attribute::*)) / 2"), STR("id()/2"), STR("+"), 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("///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("/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("$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(".[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"), STR("/cracker/cheese[(mold > 1) and (sense/taste"),
// From xpath-as3 tests // 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"), 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 // From haXe-xpath tests
STR("|/gjs"), STR("+3"), STR("/html/body/p != ---'div'/a"), STR(""), STR("@"), STR("#akf"), STR(",") STR("|/gjs"), STR("+3"), STR("/html/body/p != ---'div'/a"), STR(""), STR("@"), STR("#akf"), STR(",")
// Miscellaneous // Miscellaneous
STR("..."), STR("...."), STR("**"), STR("****"), STR("******"), STR("..***..***.***.***..***..***..*"), STR("/[1]") STR("..."),
}; STR("...."), STR("**"), STR("****"), STR("******"), STR("..***..***.***.***..***..***..*"), STR("/[1]")};
for (size_t i = 0; i < sizeof(paths) / sizeof(paths[0]); ++i) 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(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(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("last/descendant:: node()"));
CHECK_XPATH_NODESET(n, STR("@attr/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(c, STR("parent:: node()"));
CHECK_XPATH_NODESET(n.child(STR("child")), STR("parent:: node()")) % 2; // 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("child/subchild/parent:: node()")) % 4; // child
CHECK_XPATH_NODESET(n, STR("@attr/parent:: node()")) % 2; // node CHECK_XPATH_NODESET(n, STR("@attr/parent:: node()")) % 2; // node
CHECK_XPATH_NODESET(n, STR("parent:: node()")) % 1; // root CHECK_XPATH_NODESET(n, STR("parent:: node()")) % 1; // root
CHECK_XPATH_NODESET(doc, STR("parent:: node()")); CHECK_XPATH_NODESET(doc, STR("parent:: node()"));
CHECK_XPATH_NODESET(na, STR("parent:: node()")) % 2; // 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(c, STR("ancestor:: node()"));
CHECK_XPATH_NODESET(n.child(STR("child")), STR("ancestor:: node()")) % 2 % 1; // node, root 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/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("child/@attr/ancestor:: node()")) % 4 % 2 % 1; // child, node, root
CHECK_XPATH_NODESET(n, STR("ancestor:: node()")) % 1; // root CHECK_XPATH_NODESET(n, STR("ancestor:: node()")) % 1; // root
CHECK_XPATH_NODESET(doc, STR("ancestor:: node()")); CHECK_XPATH_NODESET(doc, STR("ancestor:: node()"));
CHECK_XPATH_NODESET(na, STR("ancestor:: node()")) % 4 % 2 % 1; // child, node, root 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.child(STR("last")), STR("following-sibling:: node()"));
CHECK_XPATH_NODESET(n, STR("@attr1/following-sibling:: node()")); // attributes are not siblings 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>") 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.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(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>") 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(c, STR("following:: node()"));
CHECK_XPATH_NODESET(n, STR("following:: node()")); // no descendants 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")), 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("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.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(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>") 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(c, STR("preceding:: node()"));
CHECK_XPATH_NODESET(n.child(STR("child")), STR("preceding:: node()")); // no ancestors 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("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.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("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(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>") 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("child")), STR("attribute:: node()")) % 6; // child/@attr
CHECK_XPATH_NODESET(n.child(STR("last")), STR("attribute:: node()")); 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(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(n, STR("@attr1/attribute::node()"));
CHECK_XPATH_NODESET(na, STR("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(c, STR("self:: node()"));
CHECK_XPATH_NODESET(n.child(STR("child")), STR("self:: node()")) % 4; // child 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("self:: node()")) % 2; // node
CHECK_XPATH_NODESET(n, STR("child/self:: node()")) % 4; // child CHECK_XPATH_NODESET(n, STR("child/self:: node()")) % 4; // child
CHECK_XPATH_NODESET(n, STR("child/@attr/self:: node()")) % 5; // @attr CHECK_XPATH_NODESET(n, STR("child/@attr/self:: node()")) % 5; // @attr
CHECK_XPATH_NODESET(doc, STR("self:: node()")) % 1; // root CHECK_XPATH_NODESET(doc, STR("self:: node()")) % 1; // root
CHECK_XPATH_NODESET(na, STR("self:: node()")) % 3; // @attr 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>") 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(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(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("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("last/descendant-or-self:: node()")) % 9; // last
CHECK_XPATH_NODESET(n, STR("child/@attr/descendant-or-self::node()")) % 5; // @attr 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>") 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(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.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/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("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(n, STR("ancestor-or-self:: node()")) % 2 % 1; // root, node
CHECK_XPATH_NODESET(doc, STR("ancestor-or-self:: node()")) % 1; // root 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("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(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(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>") 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>") 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>") 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>") 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//para2/following::*"), true);
CHECK_XPATH_BOOLEAN(doc, STR("node//para6/following::*"), false); 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//para2/following::*)"), STR("para3"));
CHECK_XPATH_STRING(doc, STR("name(node//para6/following::*)"), STR("")); 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//para1/preceding::*"), false);
CHECK_XPATH_BOOLEAN(doc, STR("node//para6/preceding::*"), true); 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//para1/preceding::*)"), STR(""));
CHECK_XPATH_STRING(doc, STR("name(node//para6/preceding::*)"), STR("para1")); 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-or-self::*"), true);
CHECK_XPATH_BOOLEAN(doc, STR("//@attr5/ancestor::*"), true); CHECK_XPATH_BOOLEAN(doc, STR("//@attr5/ancestor::*"), true);
CHECK_XPATH_BOOLEAN(doc, STR("//@attr5/following::para6"), true); CHECK_XPATH_BOOLEAN(doc, STR("//@attr5/following::para6"), true);
CHECK_XPATH_STRING(doc, STR("name(//@attr5/following::para6)"), STR("para6")); 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-or-self::*"), true);
CHECK_XPATH_BOOLEAN(doc, STR("//para5/ancestor::*"), 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'/>") TEST_XML(xpath_paths_null_nodeset_entries, "<node attr='value'/>")
{ {
xpath_node nodes[] = xpath_node nodes[] =
{ {
xpath_node(doc.first_child()), xpath_node(doc.first_child()),
xpath_node(xml_node()), xpath_node(xml_node()),
xpath_node(doc.first_child().first_attribute(), doc.first_child()), xpath_node(doc.first_child().first_attribute(), doc.first_child()),
xpath_node(xml_attribute(), doc.first_child()), xpath_node(xml_attribute(), doc.first_child()),
xpath_node(xml_attribute(), xml_node()), 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; xpath_variable_set vars;
vars.set(STR("x"), ns); 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.size() == 2);
CHECK(rs[0] == nodes[0]); CHECK(rs[0] == nodes[0]);
CHECK(rs[1] == nodes[2]); CHECK(rs[1] == nodes[2]);
} }
TEST_XML(xpath_paths_step_leaf_coverage, "<n><n1/><n2 a='v'><child/></n2><n3/></n>") 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) TEST(xpath_variables_name_unicode)
{ {
#ifdef PUGIXML_WCHAR_MODE #ifdef PUGIXML_WCHAR_MODE
#ifdef U_LITERALS #ifdef U_LITERALS
const char_t* name = L"\u0400\u203D"; const char_t* name = L"\u0400\u203D";
#else #else
const char_t* name = L"\x0400\x203D"; const char_t* name = L"\x0400\x203D";
#endif #endif
#else #else
const char_t* name = "\xd0\x80\xe2\x80\xbd"; const char_t* name = "\xd0\x80\xe2\x80\xbd";
#endif #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("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("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("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("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("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("(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("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("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("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("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("(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>") 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 "test.hpp"
#include <string>
#include <algorithm> #include <algorithm>
#include <string>
using namespace pugi; 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(); 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")) % 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;
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")); 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; 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")); 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; 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")); xml_node chapter = doc.child(STR("chapter"));
CHECK_XPATH_NUMBER(doc, STR("count(//@*)"), 16); CHECK_XPATH_NUMBER(doc, STR("count(//@*)"), 16);
CHECK_XPATH_NUMBER(doc, STR("count(//@title)"), 12); CHECK_XPATH_NUMBER(doc, STR("count(//@title)"), 12);
CHECK_XPATH_NUMBER(doc, STR("count(//section//@*)"), 14); CHECK_XPATH_NUMBER(doc, STR("count(//section//@*)"), 14);
CHECK_XPATH_NUMBER(doc, STR("count(//section//@title)"), 11); CHECK_XPATH_NUMBER(doc, STR("count(//section//@title)"), 11);
CHECK_XPATH_NUMBER(chapter, STR("count(.//@*)"), 16); CHECK_XPATH_NUMBER(chapter, STR("count(.//@*)"), 16);
CHECK_XPATH_NUMBER(chapter, STR("count(.//@title)"), 12); 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_NODESET(d, STR("(descendant-or-self::*/@att1)[last()]")) % 11;
CHECK_XPATH_NUMBER(baz, STR("count(ancestor-or-self::*/@att1)"), 5); 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_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_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_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_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-or-self::*/@att1)[last()]")) % 11;
CHECK_XPATH_NODESET(baz, STR("(ancestor::*|self::*)/@att1[last()]")) % 3 % 5 % 7 % 9 % 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_STRING(baz, STR("string((ancestor::*|self::*)/@att1[last()])"), STR("e"));
CHECK_XPATH_NODESET(baz, STR("((ancestor::*|self::*)/@att1)[last()]")) % 11; 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()[2]")) % 34;
CHECK_XPATH_NODESET(c, STR("processing-instruction('pi')[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("comment()[2]")) % 36;
CHECK_XPATH_NODESET(c, STR("a/*[last()]")) % 5 % 8 % 11 % 15 % 18 % 21 % 25 % 29; 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/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/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/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("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("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>") 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; 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>") 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")); 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>") 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>") 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")); 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/* | 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 | 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/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/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>") 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, 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")), 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.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) 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) static bool test_narrow(const std::string& result, const char* expected, size_t length)
{ {
// check result // 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...) // 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; return true;
} }
@ -27,7 +29,7 @@ std::basic_string<wchar_t> xml_writer_string::as_wide() const
{ {
CHECK(contents.size() % sizeof(wchar_t) == 0); 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)); 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); CHECK(contents.size() % sizeof(pugi::char_t) == 0);
#endif #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)); 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> #include <string>
struct xml_writer_string: public pugi::xml_writer struct xml_writer_string : public pugi::xml_writer
{ {
std::string contents; std::string contents;