v2.0.1-rc (#13)
All checks were successful
BlockStorage/repertory_osx_builds/pipeline/head This commit looks good
BlockStorage/repertory_linux_builds/pipeline/head This commit looks good

Reviewed-on: #13
This commit is contained in:
2023-12-10 18:11:20 +00:00
parent f43c41f88a
commit 1b8de3b097
404 changed files with 410072 additions and 146106 deletions

View File

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

View File

@ -1,10 +1,10 @@
#ifndef HEADER_TEST_ALLOCATOR_HPP
#define HEADER_TEST_ALLOCATOR_HPP
#include <stddef.h>
void* memory_allocate(size_t size);
size_t memory_size(void* ptr);
void memory_deallocate(void* ptr);
#endif
#ifndef HEADER_TEST_ALLOCATOR_HPP
#define HEADER_TEST_ALLOCATOR_HPP
#include <stddef.h>
void* memory_allocate(size_t size);
size_t memory_size(void* ptr);
void memory_deallocate(void* ptr);
#endif

View File

@ -1,87 +1,87 @@
function Invoke-CmdScript($scriptName)
{
$cmdLine = """$scriptName"" $args & set"
& $Env:SystemRoot\system32\cmd.exe /c $cmdLine |
select-string '^([^=]*)=(.*)$' | foreach-object {
$varName = $_.Matches[0].Groups[1].Value
$varValue = $_.Matches[0].Groups[2].Value
set-item Env:$varName $varValue
}
}
$sources = @("src/pugixml.cpp") + (Get-ChildItem -Path "tests/*.cpp" -Exclude "fuzz_*.cpp")
$failed = $FALSE
foreach ($vs in $args)
{
foreach ($arch in "x86","x64")
{
Write-Output "# Setting up VS$vs $arch"
if ($vs -eq 15) {
$vsdevcmdarch = if ($arch -eq "x64") { "amd64" } else { "x86" }
Invoke-CmdScript "C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\Common7\Tools\VsDevCmd.bat" "-arch=$vsdevcmdarch"
}
elseif ($vs -eq 19) {
$vsdevcmdarch = if ($arch -eq "x64") { "amd64" } else { "x86" }
Invoke-CmdScript "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\Common7\Tools\VsDevCmd.bat" "-arch=$vsdevcmdarch"
}
elseif ($vs -eq 22) {
$vsdevcmdarch = if ($arch -eq "x64") { "amd64" } else { "x86" }
Invoke-CmdScript "C:\Program Files\Microsoft Visual Studio\2022\Community\Common7\Tools\VsDevCmd.bat" "-arch=$vsdevcmdarch"
}
else
{
Invoke-CmdScript "C:\Program Files (x86)\Microsoft Visual Studio $vs.0\VC\vcvarsall.bat" $arch
}
if (! $?) { throw "Error setting up VS$vs $arch" }
foreach ($defines in "standard", "PUGIXML_WCHAR_MODE", "PUGIXML_COMPACT")
{
$target = "tests_vs${vs}_${arch}_${defines}"
$deflist = if ($defines -eq "standard") { "" } else { "/D$defines" }
Add-AppveyorTest $target -Outcome Running
Write-Output "# Building $target.exe"
& cmd /c "cl.exe /Fe$target.exe /EHsc /W4 /WX $deflist $sources 2>&1" | Tee-Object -Variable buildOutput
if ($?)
{
Write-Output "# Running $target.exe"
$sw = [Diagnostics.Stopwatch]::StartNew()
& .\$target | Tee-Object -Variable testOutput
if ($?)
{
Write-Output "# Passed"
Update-AppveyorTest $target -Outcome Passed -StdOut ($testOutput | out-string) -Duration $sw.ElapsedMilliseconds
}
else
{
Write-Output "# Failed"
Update-AppveyorTest $target -Outcome Failed -StdOut ($testOutput | out-string) -ErrorMessage "Running failed"
$failed = $TRUE
}
}
else
{
Write-Output "# Failed to build"
Update-AppveyorTest $target -Outcome Failed -StdOut ($buildOutput | out-string) -ErrorMessage "Compilation failed"
$failed = $TRUE
}
}
}
}
if ($failed) { throw "One or more build steps failed" }
Write-Output "# End"
function Invoke-CmdScript($scriptName)
{
$cmdLine = """$scriptName"" $args & set"
& $Env:SystemRoot\system32\cmd.exe /c $cmdLine |
select-string '^([^=]*)=(.*)$' | foreach-object {
$varName = $_.Matches[0].Groups[1].Value
$varValue = $_.Matches[0].Groups[2].Value
set-item Env:$varName $varValue
}
}
$sources = @("src/pugixml.cpp") + (Get-ChildItem -Path "tests/*.cpp" -Exclude "fuzz_*.cpp")
$failed = $FALSE
foreach ($vs in $args)
{
foreach ($arch in "x86","x64")
{
Write-Output "# Setting up VS$vs $arch"
if ($vs -eq 15) {
$vsdevcmdarch = if ($arch -eq "x64") { "amd64" } else { "x86" }
Invoke-CmdScript "C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\Common7\Tools\VsDevCmd.bat" "-arch=$vsdevcmdarch"
}
elseif ($vs -eq 19) {
$vsdevcmdarch = if ($arch -eq "x64") { "amd64" } else { "x86" }
Invoke-CmdScript "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\Common7\Tools\VsDevCmd.bat" "-arch=$vsdevcmdarch"
}
elseif ($vs -eq 22) {
$vsdevcmdarch = if ($arch -eq "x64") { "amd64" } else { "x86" }
Invoke-CmdScript "C:\Program Files\Microsoft Visual Studio\2022\Community\Common7\Tools\VsDevCmd.bat" "-arch=$vsdevcmdarch"
}
else
{
Invoke-CmdScript "C:\Program Files (x86)\Microsoft Visual Studio $vs.0\VC\vcvarsall.bat" $arch
}
if (! $?) { throw "Error setting up VS$vs $arch" }
foreach ($defines in "standard", "PUGIXML_WCHAR_MODE", "PUGIXML_COMPACT")
{
$target = "tests_vs${vs}_${arch}_${defines}"
$deflist = if ($defines -eq "standard") { "" } else { "/D$defines" }
Add-AppveyorTest $target -Outcome Running
Write-Output "# Building $target.exe"
& cmd /c "cl.exe /Fe$target.exe /EHsc /W4 /WX $deflist $sources 2>&1" | Tee-Object -Variable buildOutput
if ($?)
{
Write-Output "# Running $target.exe"
$sw = [Diagnostics.Stopwatch]::StartNew()
& .\$target | Tee-Object -Variable testOutput
if ($?)
{
Write-Output "# Passed"
Update-AppveyorTest $target -Outcome Passed -StdOut ($testOutput | out-string) -Duration $sw.ElapsedMilliseconds
}
else
{
Write-Output "# Failed"
Update-AppveyorTest $target -Outcome Failed -StdOut ($testOutput | out-string) -ErrorMessage "Running failed"
$failed = $TRUE
}
}
else
{
Write-Output "# Failed to build"
Update-AppveyorTest $target -Outcome Failed -StdOut ($buildOutput | out-string) -ErrorMessage "Compilation failed"
$failed = $TRUE
}
}
}
}
if ($failed) { throw "One or more build steps failed" }
Write-Output "# End"

View File

@ -1,14 +1,14 @@
#include "../src/pugixml.hpp"
#include <stdint.h>
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size)
{
pugi::xml_document doc;
doc.load_buffer(Data, Size);
doc.load_buffer(Data, Size, pugi::parse_minimal);
doc.load_buffer(Data, Size, pugi::parse_full);
return 0;
}
#include "../src/pugixml.hpp"
#include <stdint.h>
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size)
{
pugi::xml_document doc;
doc.load_buffer(Data, Size);
doc.load_buffer(Data, Size, pugi::parse_minimal);
doc.load_buffer(Data, Size, pugi::parse_full);
return 0;
}

View File

@ -1,26 +1,26 @@
#include "../src/pugixml.hpp"
#include <stdint.h>
#include <string.h>
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size)
{
char* text = new char[Size + 1];
memcpy(text, Data, Size);
text[Size] = 0;
#ifdef PUGIXML_NO_EXCEPTIONS
pugi::xpath_query q(text);
#else
try
{
pugi::xpath_query q(text);
}
catch (pugi::xpath_exception&)
{
}
#endif
delete[] text;
return 0;
}
#include "../src/pugixml.hpp"
#include <stdint.h>
#include <string.h>
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size)
{
char* text = new char[Size + 1];
memcpy(text, Data, Size);
text[Size] = 0;
#ifdef PUGIXML_NO_EXCEPTIONS
pugi::xpath_query q(text);
#else
try
{
pugi::xpath_query q(text);
}
catch (pugi::xpath_exception&)
{
}
#endif
delete[] text;
return 0;
}

View File

@ -1,114 +1,114 @@
#ifndef HEADER_TEST_HELPERS_HPP
#define HEADER_TEST_HELPERS_HPP
#include "test.hpp"
#include <utility>
template <typename T> static void generic_bool_ops_test(const T& obj)
{
T null;
CHECK(!null);
CHECK(obj);
CHECK(!!obj);
#ifdef _MSC_VER
# pragma warning(push)
# pragma warning(disable: 4800) // forcing value to bool 'true' or 'false' (performance warning) - we really want to just cast to bool instead of !!
#endif
bool b1 = null, b2 = obj;
#ifdef _MSC_VER
# pragma warning(pop)
#endif
CHECK(!b1);
CHECK(b2);
CHECK(obj && b2);
CHECK(obj || b2);
CHECK(obj && obj);
CHECK(obj || obj);
}
template <typename T> static void generic_eq_ops_test(const T& obj1, const T& obj2)
{
T null = T();
// operator==
CHECK(null == null);
CHECK(obj1 == obj1);
CHECK(!(null == obj1));
CHECK(!(null == obj2));
CHECK(T(null) == null);
CHECK(T(obj1) == obj1);
// operator!=
CHECK(!(null != null));
CHECK(!(obj1 != obj1));
CHECK(null != obj1);
CHECK(null != obj2);
CHECK(!(T(null) != null));
CHECK(!(T(obj1) != obj1));
}
template <typename T> static void generic_rel_ops_test(T obj1, T obj2)
{
T null = T();
// obj1 < obj2 (we use operator<, but there is no other choice
if (obj1 > obj2)
{
T temp = obj1;
obj1 = obj2;
obj2 = temp;
}
// operator<
CHECK(null < obj1);
CHECK(null < obj2);
CHECK(obj1 < obj2);
CHECK(!(null < null));
CHECK(!(obj1 < obj1));
CHECK(!(obj1 < null));
CHECK(!(obj2 < obj1));
// operator<=
CHECK(null <= obj1);
CHECK(null <= obj2);
CHECK(obj1 <= obj2);
CHECK(null <= null);
CHECK(obj1 <= obj1);
CHECK(!(obj1 <= null));
CHECK(!(obj2 <= obj1));
// operator>
CHECK(obj1 > null);
CHECK(obj2 > null);
CHECK(obj2 > obj1);
CHECK(!(null > null));
CHECK(!(obj1 > obj1));
CHECK(!(null > obj1));
CHECK(!(obj1 > obj2));
// operator>=
CHECK(obj1 >= null);
CHECK(obj2 >= null);
CHECK(obj2 >= obj1);
CHECK(null >= null);
CHECK(obj1 >= obj1);
CHECK(!(null >= obj1));
CHECK(!(obj1 >= obj2));
}
template <typename T> static void generic_empty_test(const T& obj)
{
T null;
CHECK(null.empty());
CHECK(!obj.empty());
}
#endif
#ifndef HEADER_TEST_HELPERS_HPP
#define HEADER_TEST_HELPERS_HPP
#include "test.hpp"
#include <utility>
template <typename T> static void generic_bool_ops_test(const T& obj)
{
T null;
CHECK(!null);
CHECK(obj);
CHECK(!!obj);
#ifdef _MSC_VER
# pragma warning(push)
# pragma warning(disable: 4800) // forcing value to bool 'true' or 'false' (performance warning) - we really want to just cast to bool instead of !!
#endif
bool b1 = null, b2 = obj;
#ifdef _MSC_VER
# pragma warning(pop)
#endif
CHECK(!b1);
CHECK(b2);
CHECK(obj && b2);
CHECK(obj || b2);
CHECK(obj && obj);
CHECK(obj || obj);
}
template <typename T> static void generic_eq_ops_test(const T& obj1, const T& obj2)
{
T null = T();
// operator==
CHECK(null == null);
CHECK(obj1 == obj1);
CHECK(!(null == obj1));
CHECK(!(null == obj2));
CHECK(T(null) == null);
CHECK(T(obj1) == obj1);
// operator!=
CHECK(!(null != null));
CHECK(!(obj1 != obj1));
CHECK(null != obj1);
CHECK(null != obj2);
CHECK(!(T(null) != null));
CHECK(!(T(obj1) != obj1));
}
template <typename T> static void generic_rel_ops_test(T obj1, T obj2)
{
T null = T();
// obj1 < obj2 (we use operator<, but there is no other choice
if (obj1 > obj2)
{
T temp = obj1;
obj1 = obj2;
obj2 = temp;
}
// operator<
CHECK(null < obj1);
CHECK(null < obj2);
CHECK(obj1 < obj2);
CHECK(!(null < null));
CHECK(!(obj1 < obj1));
CHECK(!(obj1 < null));
CHECK(!(obj2 < obj1));
// operator<=
CHECK(null <= obj1);
CHECK(null <= obj2);
CHECK(obj1 <= obj2);
CHECK(null <= null);
CHECK(obj1 <= obj1);
CHECK(!(obj1 <= null));
CHECK(!(obj2 <= obj1));
// operator>
CHECK(obj1 > null);
CHECK(obj2 > null);
CHECK(obj2 > obj1);
CHECK(!(null > null));
CHECK(!(obj1 > obj1));
CHECK(!(null > obj1));
CHECK(!(obj1 > obj2));
// operator>=
CHECK(obj1 >= null);
CHECK(obj2 >= null);
CHECK(obj2 >= obj1);
CHECK(null >= null);
CHECK(obj1 >= obj1);
CHECK(!(null >= obj1));
CHECK(!(obj1 >= obj2));
}
template <typename T> static void generic_empty_test(const T& obj)
{
T null;
CHECK(null.empty());
CHECK(!obj.empty());
}
#endif

View File

@ -1,218 +1,218 @@
#include "test.hpp"
#include "allocator.hpp"
#include <stdio.h>
#include <stdlib.h>
#include <float.h>
#include <assert.h>
#include <string>
#ifndef PUGIXML_NO_EXCEPTIONS
# include <exception>
#endif
#ifdef _WIN32_WCE
# undef DebugBreak
# pragma warning(disable: 4201) // nonstandard extension used: nameless struct/union
# include <windows.h>
#endif
test_runner* test_runner::_tests = 0;
size_t test_runner::_memory_fail_threshold = 0;
bool test_runner::_memory_fail_triggered = false;
jmp_buf test_runner::_failure_buffer;
const char* test_runner::_failure_message;
const char* test_runner::_temp_path;
static size_t g_memory_total_size = 0;
static size_t g_memory_total_count = 0;
static size_t g_memory_fail_triggered = false;
static void* custom_allocate(size_t size)
{
if (test_runner::_memory_fail_threshold > 0 && test_runner::_memory_fail_threshold < g_memory_total_size + size)
{
g_memory_fail_triggered = true;
test_runner::_memory_fail_triggered = true;
return 0;
}
else
{
void* ptr = memory_allocate(size);
if (!ptr) return 0;
g_memory_total_size += memory_size(ptr);
g_memory_total_count++;
return ptr;
}
}
#ifndef PUGIXML_NO_EXCEPTIONS
static void* custom_allocate_throw(size_t size)
{
void* result = custom_allocate(size);
if (!result)
throw std::bad_alloc();
return result;
}
#endif
static void custom_deallocate(void* ptr)
{
assert(ptr);
g_memory_total_size -= memory_size(ptr);
g_memory_total_count--;
memory_deallocate(ptr);
}
static void replace_memory_management()
{
// create some document to touch original functions
{
pugi::xml_document doc;
doc.append_child().set_name(STR("node"));
}
// replace functions
pugi::set_memory_management_functions(custom_allocate, custom_deallocate);
}
#if defined(_MSC_VER) && _MSC_VER > 1200 && _MSC_VER < 1400 && !defined(__INTEL_COMPILER) && !defined(__DMC__)
#include <exception>
namespace std
{
_CRTIMP2 _Prhand _Raise_handler;
_CRTIMP2 void __cdecl _Throw(const exception&) {}
}
#endif
static bool run_test(test_runner* test, const char* test_name, pugi::allocation_function allocate)
{
#ifndef PUGIXML_NO_EXCEPTIONS
try
{
#endif
g_memory_total_size = 0;
g_memory_total_count = 0;
g_memory_fail_triggered = false;
test_runner::_memory_fail_threshold = 0;
test_runner::_memory_fail_triggered = false;
pugi::set_memory_management_functions(allocate, custom_deallocate);
#ifdef _MSC_VER
# pragma warning(push)
# pragma warning(disable: 4611) // interaction between _setjmp and C++ object destruction is non-portable
# pragma warning(disable: 4793) // function compiled as native: presence of '_setjmp' makes a function unmanaged
#endif
volatile int result = setjmp(test_runner::_failure_buffer);
#ifdef _MSC_VER
# pragma warning(pop)
#endif
if (result)
{
printf("Test %s failed: %s\n", test_name, test_runner::_failure_message);
return false;
}
test->run();
if (test_runner::_memory_fail_triggered)
{
printf("Test %s failed: unguarded memory fail triggered\n", test_name);
return false;
}
if (g_memory_total_size != 0 || g_memory_total_count != 0)
{
printf("Test %s failed: memory leaks found (%u bytes in %u allocations)\n", test_name, static_cast<unsigned int>(g_memory_total_size), static_cast<unsigned int>(g_memory_total_count));
return false;
}
return true;
#ifndef PUGIXML_NO_EXCEPTIONS
}
catch (const std::exception& e)
{
printf("Test %s failed: exception %s\n", test_name, e.what());
return false;
}
catch (...)
{
printf("Test %s failed for unknown reason\n", test_name);
return false;
}
#endif
}
#if defined(__CELLOS_LV2__) && defined(PUGIXML_NO_EXCEPTIONS) && !defined(__SNC__)
#include <exception>
void std::exception::_Raise() const
{
abort();
}
#endif
int main(int, char** argv)
{
#ifdef __BORLANDC__
_control87(MCW_EM | PC_53, MCW_EM | MCW_PC);
#endif
// setup temp path as the executable folder
std::string temp = argv[0];
std::string::size_type slash = temp.find_last_of("\\/");
temp.erase((slash != std::string::npos) ? slash + 1 : 0);
test_runner::_temp_path = temp.c_str();
replace_memory_management();
unsigned int total = 0;
unsigned int passed = 0;
test_runner* test = 0; // gcc3 "variable might be used uninitialized in this function" bug workaround
for (test = test_runner::_tests; test; test = test->_next)
{
total++;
passed += run_test(test, test->_name, custom_allocate);
if (g_memory_fail_triggered)
{
// run tests that trigger memory failures twice - with an allocator that returns NULL and with an allocator that throws
#ifndef PUGIXML_NO_EXCEPTIONS
total++;
passed += run_test(test, (test->_name + std::string(" (throw)")).c_str(), custom_allocate_throw);
#endif
}
}
unsigned int failed = total - passed;
if (failed != 0)
printf("FAILURE: %u out of %u tests failed.\n", failed, total);
else
printf("Success: %u tests passed.\n", total);
return failed;
}
#ifdef _WIN32_WCE
int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int)
{
return main(0, NULL);
}
#endif
#include "test.hpp"
#include "allocator.hpp"
#include <stdio.h>
#include <stdlib.h>
#include <float.h>
#include <assert.h>
#include <string>
#ifndef PUGIXML_NO_EXCEPTIONS
# include <exception>
#endif
#ifdef _WIN32_WCE
# undef DebugBreak
# pragma warning(disable: 4201) // nonstandard extension used: nameless struct/union
# include <windows.h>
#endif
test_runner* test_runner::_tests = 0;
size_t test_runner::_memory_fail_threshold = 0;
bool test_runner::_memory_fail_triggered = false;
jmp_buf test_runner::_failure_buffer;
const char* test_runner::_failure_message;
const char* test_runner::_temp_path;
static size_t g_memory_total_size = 0;
static size_t g_memory_total_count = 0;
static size_t g_memory_fail_triggered = false;
static void* custom_allocate(size_t size)
{
if (test_runner::_memory_fail_threshold > 0 && test_runner::_memory_fail_threshold < g_memory_total_size + size)
{
g_memory_fail_triggered = true;
test_runner::_memory_fail_triggered = true;
return 0;
}
else
{
void* ptr = memory_allocate(size);
if (!ptr) return 0;
g_memory_total_size += memory_size(ptr);
g_memory_total_count++;
return ptr;
}
}
#ifndef PUGIXML_NO_EXCEPTIONS
static void* custom_allocate_throw(size_t size)
{
void* result = custom_allocate(size);
if (!result)
throw std::bad_alloc();
return result;
}
#endif
static void custom_deallocate(void* ptr)
{
assert(ptr);
g_memory_total_size -= memory_size(ptr);
g_memory_total_count--;
memory_deallocate(ptr);
}
static void replace_memory_management()
{
// create some document to touch original functions
{
pugi::xml_document doc;
doc.append_child().set_name(STR("node"));
}
// replace functions
pugi::set_memory_management_functions(custom_allocate, custom_deallocate);
}
#if defined(_MSC_VER) && _MSC_VER > 1200 && _MSC_VER < 1400 && !defined(__INTEL_COMPILER) && !defined(__DMC__)
#include <exception>
namespace std
{
_CRTIMP2 _Prhand _Raise_handler;
_CRTIMP2 void __cdecl _Throw(const exception&) {}
}
#endif
static bool run_test(test_runner* test, const char* test_name, pugi::allocation_function allocate)
{
#ifndef PUGIXML_NO_EXCEPTIONS
try
{
#endif
g_memory_total_size = 0;
g_memory_total_count = 0;
g_memory_fail_triggered = false;
test_runner::_memory_fail_threshold = 0;
test_runner::_memory_fail_triggered = false;
pugi::set_memory_management_functions(allocate, custom_deallocate);
#ifdef _MSC_VER
# pragma warning(push)
# pragma warning(disable: 4611) // interaction between _setjmp and C++ object destruction is non-portable
# pragma warning(disable: 4793) // function compiled as native: presence of '_setjmp' makes a function unmanaged
#endif
volatile int result = setjmp(test_runner::_failure_buffer);
#ifdef _MSC_VER
# pragma warning(pop)
#endif
if (result)
{
printf("Test %s failed: %s\n", test_name, test_runner::_failure_message);
return false;
}
test->run();
if (test_runner::_memory_fail_triggered)
{
printf("Test %s failed: unguarded memory fail triggered\n", test_name);
return false;
}
if (g_memory_total_size != 0 || g_memory_total_count != 0)
{
printf("Test %s failed: memory leaks found (%u bytes in %u allocations)\n", test_name, static_cast<unsigned int>(g_memory_total_size), static_cast<unsigned int>(g_memory_total_count));
return false;
}
return true;
#ifndef PUGIXML_NO_EXCEPTIONS
}
catch (const std::exception& e)
{
printf("Test %s failed: exception %s\n", test_name, e.what());
return false;
}
catch (...)
{
printf("Test %s failed for unknown reason\n", test_name);
return false;
}
#endif
}
#if defined(__CELLOS_LV2__) && defined(PUGIXML_NO_EXCEPTIONS) && !defined(__SNC__)
#include <exception>
void std::exception::_Raise() const
{
abort();
}
#endif
int main(int, char** argv)
{
#ifdef __BORLANDC__
_control87(MCW_EM | PC_53, MCW_EM | MCW_PC);
#endif
// setup temp path as the executable folder
std::string temp = argv[0];
std::string::size_type slash = temp.find_last_of("\\/");
temp.erase((slash != std::string::npos) ? slash + 1 : 0);
test_runner::_temp_path = temp.c_str();
replace_memory_management();
unsigned int total = 0;
unsigned int passed = 0;
test_runner* test = 0; // gcc3 "variable might be used uninitialized in this function" bug workaround
for (test = test_runner::_tests; test; test = test->_next)
{
total++;
passed += run_test(test, test->_name, custom_allocate);
if (g_memory_fail_triggered)
{
// run tests that trigger memory failures twice - with an allocator that returns NULL and with an allocator that throws
#ifndef PUGIXML_NO_EXCEPTIONS
total++;
passed += run_test(test, (test->_name + std::string(" (throw)")).c_str(), custom_allocate_throw);
#endif
}
}
unsigned int failed = total - passed;
if (failed != 0)
printf("FAILURE: %u out of %u tests failed.\n", failed, total);
else
printf("Success: %u tests passed.\n", total);
return failed;
}
#ifdef _WIN32_WCE
int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int)
{
return main(0, NULL);
}
#endif

View File

@ -1,220 +1,220 @@
#define _SCL_SECURE_NO_WARNINGS
#define _SCL_SECURE_NO_DEPRECATE
#include "test.hpp"
#include "writer_string.hpp"
#include <math.h>
#include <float.h>
#include <string.h>
#include <wchar.h>
#include <algorithm>
#include <vector>
#ifndef PUGIXML_NO_XPATH
static void build_document_order(std::vector<pugi::xpath_node>& result, pugi::xml_node root)
{
result.push_back(pugi::xpath_node());
pugi::xml_node cur = root;
for (;;)
{
result.push_back(cur);
for (pugi::xml_attribute a = cur.first_attribute(); a; a = a.next_attribute())
result.push_back(pugi::xpath_node(a, cur));
if (cur.first_child())
cur = cur.first_child();
else if (cur.next_sibling())
cur = cur.next_sibling();
else
{
while (cur && !cur.next_sibling()) cur = cur.parent();
cur = cur.next_sibling();
if (!cur) break;
}
}
}
#endif
bool test_string_equal(const pugi::char_t* lhs, const pugi::char_t* rhs)
{
return (!lhs || !rhs) ? lhs == rhs :
#ifdef PUGIXML_WCHAR_MODE
wcscmp(lhs, rhs) == 0;
#else
strcmp(lhs, rhs) == 0;
#endif
}
bool test_node(const pugi::xml_node& node, const pugi::char_t* contents, const pugi::char_t* indent, unsigned int flags)
{
xml_writer_string writer;
node.print(writer, indent, flags, get_native_encoding());
return writer.as_string() == contents;
}
bool test_double_nan(double value)
{
#if defined(_MSC_VER) || defined(__BORLANDC__)
return _isnan(value) != 0;
#else
return value != value;
#endif
}
#ifndef PUGIXML_NO_XPATH
static size_t strlength(const pugi::char_t* s)
{
#ifdef PUGIXML_WCHAR_MODE
return wcslen(s);
#else
return strlen(s);
#endif
}
bool test_xpath_string(const pugi::xpath_node& node, const pugi::char_t* query, pugi::xpath_variable_set* variables, const pugi::char_t* expected)
{
pugi::xpath_query q(query, variables);
if (!q) return false;
const size_t capacity = 64;
pugi::char_t result[capacity];
size_t size = q.evaluate_string(result, capacity, node);
if (size != strlength(expected) + 1)
return false;
if (size <= capacity)
return test_string_equal(result, expected);
std::basic_string<pugi::char_t> buffer(size, ' ');
return q.evaluate_string(&buffer[0], size, node) == size && test_string_equal(buffer.c_str(), 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);
if (!q) return false;
return q.evaluate_boolean(node) == 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);
if (!q) return false;
double value = q.evaluate_number(node);
double absolute_error = fabs(value - expected);
const double tolerance = 1e-15;
return absolute_error < tolerance || absolute_error < fabs(expected) * tolerance;
}
bool test_xpath_number_nan(const pugi::xpath_node& node, const pugi::char_t* query, pugi::xpath_variable_set* variables)
{
pugi::xpath_query q(query, variables);
if (!q) return false;
return test_double_nan(q.evaluate_number(node));
}
bool test_xpath_fail_compile(const pugi::char_t* query, pugi::xpath_variable_set* variables)
{
#ifdef PUGIXML_NO_EXCEPTIONS
return !pugi::xpath_query(query, variables);
#else
try
{
pugi::xpath_query q(query, variables);
return false;
}
catch (const pugi::xpath_exception&)
{
return true;
}
#endif
}
void xpath_node_set_tester::check(bool condition)
{
if (!condition)
{
test_runner::_failure_message = message;
longjmp(test_runner::_failure_buffer, 1);
}
}
xpath_node_set_tester::xpath_node_set_tester(const pugi::xpath_node_set& set, const char* message_): last(0), message(message_)
{
result = set;
// only sort unsorted sets so that we're able to verify reverse order for some axes
if (result.type() == pugi::xpath_node_set::type_unsorted) result.sort();
if (result.empty())
{
document_order = 0;
document_size = 0;
}
else
{
std::vector<pugi::xpath_node> order;
build_document_order(order, (result[0].attribute() ? result[0].parent() : result[0].node()).root());
document_order = new pugi::xpath_node[order.size()];
std::copy(order.begin(), order.end(), document_order);
document_size = order.size();
}
}
xpath_node_set_tester::~xpath_node_set_tester()
{
// check that we processed everything
check(last == result.size());
delete[] document_order;
}
xpath_node_set_tester& xpath_node_set_tester::operator%(unsigned int expected)
{
// check element count
check(last < result.size());
// check document order
check(expected < document_size);
check(result.begin()[last] == document_order[expected]);
// continue to the next element
last++;
return *this;
}
#endif
bool is_little_endian()
{
unsigned int ui = 1;
return *reinterpret_cast<char*>(&ui) == 1;
}
pugi::xml_encoding get_native_encoding()
{
#ifdef PUGIXML_WCHAR_MODE
return pugi::encoding_wchar;
#else
return pugi::encoding_utf8;
#endif
}
#define _SCL_SECURE_NO_WARNINGS
#define _SCL_SECURE_NO_DEPRECATE
#include "test.hpp"
#include "writer_string.hpp"
#include <math.h>
#include <float.h>
#include <string.h>
#include <wchar.h>
#include <algorithm>
#include <vector>
#ifndef PUGIXML_NO_XPATH
static void build_document_order(std::vector<pugi::xpath_node>& result, pugi::xml_node root)
{
result.push_back(pugi::xpath_node());
pugi::xml_node cur = root;
for (;;)
{
result.push_back(cur);
for (pugi::xml_attribute a = cur.first_attribute(); a; a = a.next_attribute())
result.push_back(pugi::xpath_node(a, cur));
if (cur.first_child())
cur = cur.first_child();
else if (cur.next_sibling())
cur = cur.next_sibling();
else
{
while (cur && !cur.next_sibling()) cur = cur.parent();
cur = cur.next_sibling();
if (!cur) break;
}
}
}
#endif
bool test_string_equal(const pugi::char_t* lhs, const pugi::char_t* rhs)
{
return (!lhs || !rhs) ? lhs == rhs :
#ifdef PUGIXML_WCHAR_MODE
wcscmp(lhs, rhs) == 0;
#else
strcmp(lhs, rhs) == 0;
#endif
}
bool test_node(const pugi::xml_node& node, const pugi::char_t* contents, const pugi::char_t* indent, unsigned int flags)
{
xml_writer_string writer;
node.print(writer, indent, flags, get_native_encoding());
return writer.as_string() == contents;
}
bool test_double_nan(double value)
{
#if defined(_MSC_VER) || defined(__BORLANDC__)
return _isnan(value) != 0;
#else
return value != value;
#endif
}
#ifndef PUGIXML_NO_XPATH
static size_t strlength(const pugi::char_t* s)
{
#ifdef PUGIXML_WCHAR_MODE
return wcslen(s);
#else
return strlen(s);
#endif
}
bool test_xpath_string(const pugi::xpath_node& node, const pugi::char_t* query, pugi::xpath_variable_set* variables, const pugi::char_t* expected)
{
pugi::xpath_query q(query, variables);
if (!q) return false;
const size_t capacity = 64;
pugi::char_t result[capacity];
size_t size = q.evaluate_string(result, capacity, node);
if (size != strlength(expected) + 1)
return false;
if (size <= capacity)
return test_string_equal(result, expected);
std::basic_string<pugi::char_t> buffer(size, ' ');
return q.evaluate_string(&buffer[0], size, node) == size && test_string_equal(buffer.c_str(), 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);
if (!q) return false;
return q.evaluate_boolean(node) == 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);
if (!q) return false;
double value = q.evaluate_number(node);
double absolute_error = fabs(value - expected);
const double tolerance = 1e-15;
return absolute_error < tolerance || absolute_error < fabs(expected) * tolerance;
}
bool test_xpath_number_nan(const pugi::xpath_node& node, const pugi::char_t* query, pugi::xpath_variable_set* variables)
{
pugi::xpath_query q(query, variables);
if (!q) return false;
return test_double_nan(q.evaluate_number(node));
}
bool test_xpath_fail_compile(const pugi::char_t* query, pugi::xpath_variable_set* variables)
{
#ifdef PUGIXML_NO_EXCEPTIONS
return !pugi::xpath_query(query, variables);
#else
try
{
pugi::xpath_query q(query, variables);
return false;
}
catch (const pugi::xpath_exception&)
{
return true;
}
#endif
}
void xpath_node_set_tester::check(bool condition)
{
if (!condition)
{
test_runner::_failure_message = message;
longjmp(test_runner::_failure_buffer, 1);
}
}
xpath_node_set_tester::xpath_node_set_tester(const pugi::xpath_node_set& set, const char* message_): last(0), message(message_)
{
result = set;
// only sort unsorted sets so that we're able to verify reverse order for some axes
if (result.type() == pugi::xpath_node_set::type_unsorted) result.sort();
if (result.empty())
{
document_order = 0;
document_size = 0;
}
else
{
std::vector<pugi::xpath_node> order;
build_document_order(order, (result[0].attribute() ? result[0].parent() : result[0].node()).root());
document_order = new pugi::xpath_node[order.size()];
std::copy(order.begin(), order.end(), document_order);
document_size = order.size();
}
}
xpath_node_set_tester::~xpath_node_set_tester()
{
// check that we processed everything
check(last == result.size());
delete[] document_order;
}
xpath_node_set_tester& xpath_node_set_tester::operator%(unsigned int expected)
{
// check element count
check(last < result.size());
// check document order
check(expected < document_size);
check(result.begin()[last] == document_order[expected]);
// continue to the next element
last++;
return *this;
}
#endif
bool is_little_endian()
{
unsigned int ui = 1;
return *reinterpret_cast<char*>(&ui) == 1;
}
pugi::xml_encoding get_native_encoding()
{
#ifdef PUGIXML_WCHAR_MODE
return pugi::encoding_wchar;
#else
return pugi::encoding_utf8;
#endif
}

View File

@ -1,175 +1,175 @@
#ifndef HEADER_TEST_TEST_HPP
#define HEADER_TEST_TEST_HPP
#include "../src/pugixml.hpp"
#include <setjmp.h>
#ifndef PUGIXML_NO_EXCEPTIONS
#include <new>
#endif
struct test_runner
{
test_runner(const char* name)
{
_name = name;
_next = _tests;
_tests = this;
}
virtual ~test_runner() {}
virtual void run() = 0;
const char* _name;
test_runner* _next;
static test_runner* _tests;
static size_t _memory_fail_threshold;
static bool _memory_fail_triggered;
static jmp_buf _failure_buffer;
static const char* _failure_message;
static const char* _temp_path;
};
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)
{
return test_string_equal(node.name(), name) && test_string_equal(node.value(), value);
}
bool test_node(const pugi::xml_node& node, const pugi::char_t* contents, const pugi::char_t* indent, unsigned int flags);
bool test_double_nan(double value);
#ifndef PUGIXML_NO_XPATH
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_boolean(const pugi::xpath_node& node, const pugi::char_t* query, pugi::xpath_variable_set* variables, bool expected);
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_nan(const pugi::xpath_node& node, const pugi::char_t* query, pugi::xpath_variable_set* variables);
bool test_xpath_fail_compile(const pugi::char_t* query, pugi::xpath_variable_set* variables);
struct xpath_node_set_tester
{
pugi::xpath_node* document_order;
size_t document_size;
pugi::xpath_node_set result;
unsigned int last;
const char* message;
void check(bool condition);
xpath_node_set_tester(const pugi::xpath_node_set& set, const char* message);
~xpath_node_set_tester();
xpath_node_set_tester& operator%(unsigned int expected);
};
#endif
struct dummy_fixture {};
#define TEST_FIXTURE(name, fixture) \
struct test_runner_helper_##name: fixture \
{ \
void run(); \
}; \
static struct test_runner_##name: test_runner \
{ \
test_runner_##name(): test_runner(#name) {} \
\
virtual void run() PUGIXML_OVERRIDE \
{ \
test_runner_helper_##name helper; \
helper.run(); \
} \
} test_runner_instance_##name; \
void test_runner_helper_##name::run()
#define TEST(name) TEST_FIXTURE(name, dummy_fixture)
#define TEST_XML_FLAGS(name, xml, flags) \
struct test_fixture_##name \
{ \
pugi::xml_document doc; \
\
test_fixture_##name() \
{ \
CHECK(doc.load_string(PUGIXML_TEXT(xml), flags)); \
} \
\
private: \
test_fixture_##name(const test_fixture_##name&); \
test_fixture_##name& operator=(const test_fixture_##name&); \
}; \
\
TEST_FIXTURE(name, test_fixture_##name)
#define TEST_XML(name, xml) TEST_XML_FLAGS(name, xml, pugi::parse_default)
#define CHECK_JOIN(text, file, line) text " at " file ":" #line
#define CHECK_JOIN2(text, file, line) CHECK_JOIN(text, file, line)
#define CHECK_TEXT(condition, text) if (condition) ; else test_runner::_failure_message = CHECK_JOIN2(text, __FILE__, __LINE__), longjmp(test_runner::_failure_buffer, 1)
#define CHECK_FORCE_FAIL(text) test_runner::_failure_message = CHECK_JOIN2(text, __FILE__, __LINE__), longjmp(test_runner::_failure_buffer, 1)
#if (defined(_MSC_VER) && _MSC_VER == 1200) || defined(__MWERKS__) || (defined(__BORLANDC__) && __BORLANDC__ <= 0x540)
# define STRINGIZE(value) "??" // Some compilers have issues with stringizing expressions that contain strings w/escaping inside
#else
# define STRINGIZE(value) #value
#endif
#define CHECK(condition) CHECK_TEXT(condition, STRINGIZE(condition) " is false")
#define CHECK_STRING(value, expected) CHECK_TEXT(test_string_equal(value, expected), STRINGIZE(value) " is not equal to " STRINGIZE(expected))
#define CHECK_DOUBLE(value, expected) CHECK_TEXT((value > expected ? value - expected : expected - value) < 1e-6, STRINGIZE(value) " is not equal to " STRINGIZE(expected))
#define CHECK_DOUBLE_NAN(value) CHECK_TEXT(test_double_nan(value), STRINGIZE(value) " is not equal to NaN")
#define CHECK_NAME_VALUE(node, name, value) CHECK_TEXT(test_node_name_value(node, name, value), STRINGIZE(node) " name/value do not match " STRINGIZE(name) " and " STRINGIZE(value))
#define CHECK_NODE_EX(node, expected, indent, flags) CHECK_TEXT(test_node(node, expected, indent, flags), STRINGIZE(node) " contents does not match " STRINGIZE(expected))
#define CHECK_NODE(node, expected) CHECK_NODE_EX(node, expected, PUGIXML_TEXT(""), pugi::format_raw)
#ifndef PUGIXML_NO_XPATH
#define CHECK_XPATH_STRING_VAR(node, query, variables, expected) CHECK_TEXT(test_xpath_string(node, query, variables, expected), STRINGIZE(query) " does not evaluate to " STRINGIZE(expected) " in context " STRINGIZE(node))
#define CHECK_XPATH_BOOLEAN_VAR(node, query, variables, expected) CHECK_TEXT(test_xpath_boolean(node, query, variables, expected), STRINGIZE(query) " does not evaluate to " STRINGIZE(expected) " in context " STRINGIZE(node))
#define CHECK_XPATH_NUMBER_VAR(node, query, variables, expected) CHECK_TEXT(test_xpath_number(node, query, variables, expected), STRINGIZE(query) " does not evaluate to " STRINGIZE(expected) " in context " STRINGIZE(node))
#define CHECK_XPATH_NUMBER_NAN_VAR(node, query, variables) CHECK_TEXT(test_xpath_number_nan(node, query, variables), STRINGIZE(query) " does not evaluate to NaN in context " STRINGIZE(node))
#define CHECK_XPATH_NODESET_VAR(node, query, variables) xpath_node_set_tester(pugi::xpath_query(query, variables).evaluate_node_set(node), CHECK_JOIN2(STRINGIZE(query) " does not evaluate to expected set in context " STRINGIZE(node), __FILE__, __LINE__))
#define CHECK_XPATH_FAIL_VAR(query, variables) CHECK_TEXT(test_xpath_fail_compile(query, variables), STRINGIZE(query) " should not compile")
#define CHECK_XPATH_STRING(node, query, expected) CHECK_XPATH_STRING_VAR(node, query, 0, expected)
#define CHECK_XPATH_BOOLEAN(node, query, expected) CHECK_XPATH_BOOLEAN_VAR(node, query, 0, expected)
#define CHECK_XPATH_NUMBER(node, query, expected) CHECK_XPATH_NUMBER_VAR(node, query, 0, expected)
#define CHECK_XPATH_NUMBER_NAN(node, query) CHECK_XPATH_NUMBER_NAN_VAR(node, query, 0)
#define CHECK_XPATH_NODESET(node, query) CHECK_XPATH_NODESET_VAR(node, query, 0)
#define CHECK_XPATH_FAIL(query) CHECK_XPATH_FAIL_VAR(query, 0)
#endif
#ifdef PUGIXML_NO_EXCEPTIONS
#define CHECK_ALLOC_FAIL(code) do { CHECK(!test_runner::_memory_fail_triggered); code; CHECK(test_runner::_memory_fail_triggered); test_runner::_memory_fail_triggered = false; } while (test_runner::_memory_fail_triggered)
#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)
#endif
#define STR(text) PUGIXML_TEXT(text)
#if defined(__DMC__) || defined(__BORLANDC__)
#define U_LITERALS // DMC does not understand \x01234 (it parses first three digits), but understands \u01234
#endif
#if (defined(_MSC_VER) && _MSC_VER == 1200) || (defined(__INTEL_COMPILER) && __INTEL_COMPILER == 800) || defined(__BORLANDC__)
// NaN comparison on MSVC6 is incorrect, see http://www.nabble.com/assertDoubleEquals,-NaN---Microsoft-Visual-Studio-6-td9137859.html
// IC8 and BCC are also affected by the same bug
# define MSVC6_NAN_BUG
#endif
inline wchar_t wchar_cast(unsigned int value)
{
return static_cast<wchar_t>(value); // to avoid C4310 on MSVC
}
bool is_little_endian();
pugi::xml_encoding get_native_encoding();
#endif
#ifndef HEADER_TEST_TEST_HPP
#define HEADER_TEST_TEST_HPP
#include "../src/pugixml.hpp"
#include <setjmp.h>
#ifndef PUGIXML_NO_EXCEPTIONS
#include <new>
#endif
struct test_runner
{
test_runner(const char* name)
{
_name = name;
_next = _tests;
_tests = this;
}
virtual ~test_runner() {}
virtual void run() = 0;
const char* _name;
test_runner* _next;
static test_runner* _tests;
static size_t _memory_fail_threshold;
static bool _memory_fail_triggered;
static jmp_buf _failure_buffer;
static const char* _failure_message;
static const char* _temp_path;
};
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)
{
return test_string_equal(node.name(), name) && test_string_equal(node.value(), value);
}
bool test_node(const pugi::xml_node& node, const pugi::char_t* contents, const pugi::char_t* indent, unsigned int flags);
bool test_double_nan(double value);
#ifndef PUGIXML_NO_XPATH
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_boolean(const pugi::xpath_node& node, const pugi::char_t* query, pugi::xpath_variable_set* variables, bool expected);
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_nan(const pugi::xpath_node& node, const pugi::char_t* query, pugi::xpath_variable_set* variables);
bool test_xpath_fail_compile(const pugi::char_t* query, pugi::xpath_variable_set* variables);
struct xpath_node_set_tester
{
pugi::xpath_node* document_order;
size_t document_size;
pugi::xpath_node_set result;
unsigned int last;
const char* message;
void check(bool condition);
xpath_node_set_tester(const pugi::xpath_node_set& set, const char* message);
~xpath_node_set_tester();
xpath_node_set_tester& operator%(unsigned int expected);
};
#endif
struct dummy_fixture {};
#define TEST_FIXTURE(name, fixture) \
struct test_runner_helper_##name: fixture \
{ \
void run(); \
}; \
static struct test_runner_##name: test_runner \
{ \
test_runner_##name(): test_runner(#name) {} \
\
virtual void run() PUGIXML_OVERRIDE \
{ \
test_runner_helper_##name helper; \
helper.run(); \
} \
} test_runner_instance_##name; \
void test_runner_helper_##name::run()
#define TEST(name) TEST_FIXTURE(name, dummy_fixture)
#define TEST_XML_FLAGS(name, xml, flags) \
struct test_fixture_##name \
{ \
pugi::xml_document doc; \
\
test_fixture_##name() \
{ \
CHECK(doc.load_string(PUGIXML_TEXT(xml), flags)); \
} \
\
private: \
test_fixture_##name(const test_fixture_##name&); \
test_fixture_##name& operator=(const test_fixture_##name&); \
}; \
\
TEST_FIXTURE(name, test_fixture_##name)
#define TEST_XML(name, xml) TEST_XML_FLAGS(name, xml, pugi::parse_default)
#define CHECK_JOIN(text, file, line) text " at " file ":" #line
#define CHECK_JOIN2(text, file, line) CHECK_JOIN(text, file, line)
#define CHECK_TEXT(condition, text) if (condition) ; else test_runner::_failure_message = CHECK_JOIN2(text, __FILE__, __LINE__), longjmp(test_runner::_failure_buffer, 1)
#define CHECK_FORCE_FAIL(text) test_runner::_failure_message = CHECK_JOIN2(text, __FILE__, __LINE__), longjmp(test_runner::_failure_buffer, 1)
#if (defined(_MSC_VER) && _MSC_VER == 1200) || defined(__MWERKS__) || (defined(__BORLANDC__) && __BORLANDC__ <= 0x540)
# define STRINGIZE(value) "??" // Some compilers have issues with stringizing expressions that contain strings w/escaping inside
#else
# define STRINGIZE(value) #value
#endif
#define CHECK(condition) CHECK_TEXT(condition, STRINGIZE(condition) " is false")
#define CHECK_STRING(value, expected) CHECK_TEXT(test_string_equal(value, expected), STRINGIZE(value) " is not equal to " STRINGIZE(expected))
#define CHECK_DOUBLE(value, expected) CHECK_TEXT((value > expected ? value - expected : expected - value) < 1e-6, STRINGIZE(value) " is not equal to " STRINGIZE(expected))
#define CHECK_DOUBLE_NAN(value) CHECK_TEXT(test_double_nan(value), STRINGIZE(value) " is not equal to NaN")
#define CHECK_NAME_VALUE(node, name, value) CHECK_TEXT(test_node_name_value(node, name, value), STRINGIZE(node) " name/value do not match " STRINGIZE(name) " and " STRINGIZE(value))
#define CHECK_NODE_EX(node, expected, indent, flags) CHECK_TEXT(test_node(node, expected, indent, flags), STRINGIZE(node) " contents does not match " STRINGIZE(expected))
#define CHECK_NODE(node, expected) CHECK_NODE_EX(node, expected, PUGIXML_TEXT(""), pugi::format_raw)
#ifndef PUGIXML_NO_XPATH
#define CHECK_XPATH_STRING_VAR(node, query, variables, expected) CHECK_TEXT(test_xpath_string(node, query, variables, expected), STRINGIZE(query) " does not evaluate to " STRINGIZE(expected) " in context " STRINGIZE(node))
#define CHECK_XPATH_BOOLEAN_VAR(node, query, variables, expected) CHECK_TEXT(test_xpath_boolean(node, query, variables, expected), STRINGIZE(query) " does not evaluate to " STRINGIZE(expected) " in context " STRINGIZE(node))
#define CHECK_XPATH_NUMBER_VAR(node, query, variables, expected) CHECK_TEXT(test_xpath_number(node, query, variables, expected), STRINGIZE(query) " does not evaluate to " STRINGIZE(expected) " in context " STRINGIZE(node))
#define CHECK_XPATH_NUMBER_NAN_VAR(node, query, variables) CHECK_TEXT(test_xpath_number_nan(node, query, variables), STRINGIZE(query) " does not evaluate to NaN in context " STRINGIZE(node))
#define CHECK_XPATH_NODESET_VAR(node, query, variables) xpath_node_set_tester(pugi::xpath_query(query, variables).evaluate_node_set(node), CHECK_JOIN2(STRINGIZE(query) " does not evaluate to expected set in context " STRINGIZE(node), __FILE__, __LINE__))
#define CHECK_XPATH_FAIL_VAR(query, variables) CHECK_TEXT(test_xpath_fail_compile(query, variables), STRINGIZE(query) " should not compile")
#define CHECK_XPATH_STRING(node, query, expected) CHECK_XPATH_STRING_VAR(node, query, 0, expected)
#define CHECK_XPATH_BOOLEAN(node, query, expected) CHECK_XPATH_BOOLEAN_VAR(node, query, 0, expected)
#define CHECK_XPATH_NUMBER(node, query, expected) CHECK_XPATH_NUMBER_VAR(node, query, 0, expected)
#define CHECK_XPATH_NUMBER_NAN(node, query) CHECK_XPATH_NUMBER_NAN_VAR(node, query, 0)
#define CHECK_XPATH_NODESET(node, query) CHECK_XPATH_NODESET_VAR(node, query, 0)
#define CHECK_XPATH_FAIL(query) CHECK_XPATH_FAIL_VAR(query, 0)
#endif
#ifdef PUGIXML_NO_EXCEPTIONS
#define CHECK_ALLOC_FAIL(code) do { CHECK(!test_runner::_memory_fail_triggered); code; CHECK(test_runner::_memory_fail_triggered); test_runner::_memory_fail_triggered = false; } while (test_runner::_memory_fail_triggered)
#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)
#endif
#define STR(text) PUGIXML_TEXT(text)
#if defined(__DMC__) || defined(__BORLANDC__)
#define U_LITERALS // DMC does not understand \x01234 (it parses first three digits), but understands \u01234
#endif
#if (defined(_MSC_VER) && _MSC_VER == 1200) || (defined(__INTEL_COMPILER) && __INTEL_COMPILER == 800) || defined(__BORLANDC__)
// NaN comparison on MSVC6 is incorrect, see http://www.nabble.com/assertDoubleEquals,-NaN---Microsoft-Visual-Studio-6-td9137859.html
// IC8 and BCC are also affected by the same bug
# define MSVC6_NAN_BUG
#endif
inline wchar_t wchar_cast(unsigned int value)
{
return static_cast<wchar_t>(value); // to avoid C4310 on MSVC
}
bool is_little_endian();
pugi::xml_encoding get_native_encoding();
#endif

View File

@ -1,150 +1,150 @@
#ifdef PUGIXML_COMPACT
#include "test.hpp"
using namespace pugi;
static void overflow_hash_table(xml_document& doc)
{
xml_node n = doc.child(STR("n"));
// compact encoding assumes next_sibling is a forward-only pointer so we can allocate hash entries by reordering nodes
// we allocate enough hash entries to be exactly on the edge of rehash threshold
for (int i = 0; i < 8; ++i)
CHECK(n.prepend_child(node_element));
}
TEST_XML_FLAGS(compact_out_of_memory_string, "<n a='v'/><?n v?>", parse_pi)
{
test_runner::_memory_fail_threshold = 1;
overflow_hash_table(doc);
xml_attribute a = doc.child(STR("n")).attribute(STR("a"));
xml_node pi = doc.last_child();
CHECK_ALLOC_FAIL(CHECK(!pi.set_name(STR("name"))));
CHECK_ALLOC_FAIL(CHECK(!pi.set_value(STR("value"))));
CHECK_ALLOC_FAIL(CHECK(!a.set_name(STR("name"))));
CHECK_ALLOC_FAIL(CHECK(!a.set_value(STR("value"))));
}
TEST_XML(compact_out_of_memory_attribute, "<n a='v'/>")
{
test_runner::_memory_fail_threshold = 1;
overflow_hash_table(doc);
xml_node n = doc.child(STR("n"));
xml_attribute a = n.attribute(STR("a"));
CHECK_ALLOC_FAIL(CHECK(!n.append_attribute(STR(""))));
CHECK_ALLOC_FAIL(CHECK(!n.prepend_attribute(STR(""))));
CHECK_ALLOC_FAIL(CHECK(!n.insert_attribute_after(STR(""), a)));
CHECK_ALLOC_FAIL(CHECK(!n.insert_attribute_before(STR(""), a)));
}
TEST_XML(compact_out_of_memory_attribute_copy, "<n a='v'/>")
{
test_runner::_memory_fail_threshold = 1;
overflow_hash_table(doc);
xml_node n = doc.child(STR("n"));
xml_attribute a = n.attribute(STR("a"));
CHECK_ALLOC_FAIL(CHECK(!n.append_copy(a)));
CHECK_ALLOC_FAIL(CHECK(!n.prepend_copy(a)));
CHECK_ALLOC_FAIL(CHECK(!n.insert_copy_after(a, a)));
CHECK_ALLOC_FAIL(CHECK(!n.insert_copy_before(a, a)));
}
TEST_XML(compact_out_of_memory_node, "<n/>")
{
test_runner::_memory_fail_threshold = 1;
overflow_hash_table(doc);
xml_node n = doc.child(STR("n"));
CHECK_ALLOC_FAIL(CHECK(!doc.append_child(node_element)));
CHECK_ALLOC_FAIL(CHECK(!doc.prepend_child(node_element)));
CHECK_ALLOC_FAIL(CHECK(!doc.insert_child_after(node_element, n)));
CHECK_ALLOC_FAIL(CHECK(!doc.insert_child_before(node_element, n)));
}
TEST_XML(compact_out_of_memory_node_copy, "<n/>")
{
test_runner::_memory_fail_threshold = 1;
overflow_hash_table(doc);
xml_node n = doc.child(STR("n"));
CHECK_ALLOC_FAIL(CHECK(!doc.append_copy(n)));
CHECK_ALLOC_FAIL(CHECK(!doc.prepend_copy(n)));
CHECK_ALLOC_FAIL(CHECK(!doc.insert_copy_after(n, n)));
CHECK_ALLOC_FAIL(CHECK(!doc.insert_copy_before(n, n)));
}
TEST_XML(compact_out_of_memory_node_move, "<n/><ne/>")
{
test_runner::_memory_fail_threshold = 1;
overflow_hash_table(doc);
xml_node n = doc.child(STR("n"));
xml_node ne = doc.child(STR("ne"));
CHECK_ALLOC_FAIL(CHECK(!doc.append_move(n)));
CHECK_ALLOC_FAIL(CHECK(!doc.prepend_move(n)));
CHECK_ALLOC_FAIL(CHECK(!doc.insert_move_after(n, ne)));
CHECK_ALLOC_FAIL(CHECK(!doc.insert_move_before(n, ne)));
}
TEST_XML(compact_out_of_memory_remove, "<n a='v'/>")
{
test_runner::_memory_fail_threshold = 1;
overflow_hash_table(doc);
xml_node n = doc.child(STR("n"));
xml_attribute a = n.attribute(STR("a"));
CHECK_ALLOC_FAIL(CHECK(!n.remove_attribute(a)));
CHECK_ALLOC_FAIL(CHECK(!doc.remove_child(n)));
}
TEST_XML(compact_pointer_attribute_list, "<n a='v'/>")
{
xml_node n = doc.child(STR("n"));
xml_attribute a = n.attribute(STR("a"));
// make sure we fill the page with node x
for (int i = 0; i < 1000; ++i)
doc.append_child(STR("x"));
// this requires extended encoding for prev_attribute_c/next_attribute
n.append_attribute(STR("b"));
// this requires extended encoding for first_attribute
n.remove_attribute(a);
CHECK(!n.attribute(STR("a")));
CHECK(n.attribute(STR("b")));
}
TEST_XML(compact_pointer_node_list, "<n/>")
{
xml_node n = doc.child(STR("n"));
// make sure we fill the page with node x
// this requires extended encoding for prev_sibling_c/next_sibling
for (int i = 0; i < 1000; ++i)
doc.append_child(STR("x"));
// this requires extended encoding for first_child
n.append_child(STR("child"));
CHECK(n.child(STR("child")));
}
#endif
#ifdef PUGIXML_COMPACT
#include "test.hpp"
using namespace pugi;
static void overflow_hash_table(xml_document& doc)
{
xml_node n = doc.child(STR("n"));
// compact encoding assumes next_sibling is a forward-only pointer so we can allocate hash entries by reordering nodes
// we allocate enough hash entries to be exactly on the edge of rehash threshold
for (int i = 0; i < 8; ++i)
CHECK(n.prepend_child(node_element));
}
TEST_XML_FLAGS(compact_out_of_memory_string, "<n a='v'/><?n v?>", parse_pi)
{
test_runner::_memory_fail_threshold = 1;
overflow_hash_table(doc);
xml_attribute a = doc.child(STR("n")).attribute(STR("a"));
xml_node pi = doc.last_child();
CHECK_ALLOC_FAIL(CHECK(!pi.set_name(STR("name"))));
CHECK_ALLOC_FAIL(CHECK(!pi.set_value(STR("value"))));
CHECK_ALLOC_FAIL(CHECK(!a.set_name(STR("name"))));
CHECK_ALLOC_FAIL(CHECK(!a.set_value(STR("value"))));
}
TEST_XML(compact_out_of_memory_attribute, "<n a='v'/>")
{
test_runner::_memory_fail_threshold = 1;
overflow_hash_table(doc);
xml_node n = doc.child(STR("n"));
xml_attribute a = n.attribute(STR("a"));
CHECK_ALLOC_FAIL(CHECK(!n.append_attribute(STR(""))));
CHECK_ALLOC_FAIL(CHECK(!n.prepend_attribute(STR(""))));
CHECK_ALLOC_FAIL(CHECK(!n.insert_attribute_after(STR(""), a)));
CHECK_ALLOC_FAIL(CHECK(!n.insert_attribute_before(STR(""), a)));
}
TEST_XML(compact_out_of_memory_attribute_copy, "<n a='v'/>")
{
test_runner::_memory_fail_threshold = 1;
overflow_hash_table(doc);
xml_node n = doc.child(STR("n"));
xml_attribute a = n.attribute(STR("a"));
CHECK_ALLOC_FAIL(CHECK(!n.append_copy(a)));
CHECK_ALLOC_FAIL(CHECK(!n.prepend_copy(a)));
CHECK_ALLOC_FAIL(CHECK(!n.insert_copy_after(a, a)));
CHECK_ALLOC_FAIL(CHECK(!n.insert_copy_before(a, a)));
}
TEST_XML(compact_out_of_memory_node, "<n/>")
{
test_runner::_memory_fail_threshold = 1;
overflow_hash_table(doc);
xml_node n = doc.child(STR("n"));
CHECK_ALLOC_FAIL(CHECK(!doc.append_child(node_element)));
CHECK_ALLOC_FAIL(CHECK(!doc.prepend_child(node_element)));
CHECK_ALLOC_FAIL(CHECK(!doc.insert_child_after(node_element, n)));
CHECK_ALLOC_FAIL(CHECK(!doc.insert_child_before(node_element, n)));
}
TEST_XML(compact_out_of_memory_node_copy, "<n/>")
{
test_runner::_memory_fail_threshold = 1;
overflow_hash_table(doc);
xml_node n = doc.child(STR("n"));
CHECK_ALLOC_FAIL(CHECK(!doc.append_copy(n)));
CHECK_ALLOC_FAIL(CHECK(!doc.prepend_copy(n)));
CHECK_ALLOC_FAIL(CHECK(!doc.insert_copy_after(n, n)));
CHECK_ALLOC_FAIL(CHECK(!doc.insert_copy_before(n, n)));
}
TEST_XML(compact_out_of_memory_node_move, "<n/><ne/>")
{
test_runner::_memory_fail_threshold = 1;
overflow_hash_table(doc);
xml_node n = doc.child(STR("n"));
xml_node ne = doc.child(STR("ne"));
CHECK_ALLOC_FAIL(CHECK(!doc.append_move(n)));
CHECK_ALLOC_FAIL(CHECK(!doc.prepend_move(n)));
CHECK_ALLOC_FAIL(CHECK(!doc.insert_move_after(n, ne)));
CHECK_ALLOC_FAIL(CHECK(!doc.insert_move_before(n, ne)));
}
TEST_XML(compact_out_of_memory_remove, "<n a='v'/>")
{
test_runner::_memory_fail_threshold = 1;
overflow_hash_table(doc);
xml_node n = doc.child(STR("n"));
xml_attribute a = n.attribute(STR("a"));
CHECK_ALLOC_FAIL(CHECK(!n.remove_attribute(a)));
CHECK_ALLOC_FAIL(CHECK(!doc.remove_child(n)));
}
TEST_XML(compact_pointer_attribute_list, "<n a='v'/>")
{
xml_node n = doc.child(STR("n"));
xml_attribute a = n.attribute(STR("a"));
// make sure we fill the page with node x
for (int i = 0; i < 1000; ++i)
doc.append_child(STR("x"));
// this requires extended encoding for prev_attribute_c/next_attribute
n.append_attribute(STR("b"));
// this requires extended encoding for first_attribute
n.remove_attribute(a);
CHECK(!n.attribute(STR("a")));
CHECK(n.attribute(STR("b")));
}
TEST_XML(compact_pointer_node_list, "<n/>")
{
xml_node n = doc.child(STR("n"));
// make sure we fill the page with node x
// this requires extended encoding for prev_sibling_c/next_sibling
for (int i = 0; i < 1000; ++i)
doc.append_child(STR("x"));
// this requires extended encoding for first_child
n.append_child(STR("child"));
CHECK(n.child(STR("child")));
}
#endif

View File

@ -1,25 +1,25 @@
#define PUGIXML_DEPRECATED // Suppress deprecated declarations to avoid warnings
#include "test.hpp"
using namespace pugi;
TEST(document_deprecated_load)
{
xml_document doc;
CHECK(doc.load(STR("<node/>")));
CHECK_NODE(doc, STR("<node/>"));
}
#ifndef PUGIXML_NO_XPATH
TEST_XML(xpath_api_deprecated_select_single_node, "<node><head/><foo id='1'/><foo/><tail/></node>")
{
xpath_node n1 = doc.select_single_node(STR("node/foo"));
xpath_query q(STR("node/foo"));
xpath_node n2 = doc.select_single_node(q);
CHECK(n1.node().attribute(STR("id")).as_int() == 1);
CHECK(n2.node().attribute(STR("id")).as_int() == 1);
}
#endif
#define PUGIXML_DEPRECATED // Suppress deprecated declarations to avoid warnings
#include "test.hpp"
using namespace pugi;
TEST(document_deprecated_load)
{
xml_document doc;
CHECK(doc.load(STR("<node/>")));
CHECK_NODE(doc, STR("<node/>"));
}
#ifndef PUGIXML_NO_XPATH
TEST_XML(xpath_api_deprecated_select_single_node, "<node><head/><foo id='1'/><foo/><tail/></node>")
{
xpath_node n1 = doc.select_single_node(STR("node/foo"));
xpath_query q(STR("node/foo"));
xpath_node n2 = doc.select_single_node(q);
CHECK(n1.node().attribute(STR("id")).as_int() == 1);
CHECK(n2.node().attribute(STR("id")).as_int() == 1);
}
#endif

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,487 +1,487 @@
#include "test.hpp"
#include "helpers.hpp"
#include <limits.h>
using namespace pugi;
TEST_XML_FLAGS(dom_text_empty, "<node><a>foo</a><b><![CDATA[bar]]></b><c><?pi value?></c><d/></node>", parse_default | parse_pi)
{
xml_node node = doc.child(STR("node"));
CHECK(node.child(STR("a")).text());
CHECK(node.child(STR("b")).text());
CHECK(!node.child(STR("c")).text());
CHECK(!node.child(STR("d")).text());
CHECK(!xml_node().text());
CHECK(!xml_text());
generic_empty_test(node.child(STR("a")).text());
}
TEST_XML(dom_text_bool_ops, "<node>foo</node>")
{
generic_bool_ops_test(doc.child(STR("node")).text());
}
TEST_XML_FLAGS(dom_text_get, "<node><a>foo</a><b><node/><![CDATA[bar]]></b><c><?pi value?></c><d/></node>", parse_default | parse_pi)
{
xml_node node = doc.child(STR("node"));
CHECK_STRING(node.child(STR("a")).text().get(), STR("foo"));
CHECK_STRING(node.child(STR("a")).first_child().text().get(), STR("foo"));
CHECK_STRING(node.child(STR("b")).text().get(), STR("bar"));
CHECK_STRING(node.child(STR("b")).last_child().text().get(), STR("bar"));
CHECK_STRING(node.child(STR("c")).text().get(), STR(""));
CHECK_STRING(node.child(STR("c")).first_child().text().get(), STR(""));
CHECK_STRING(node.child(STR("d")).text().get(), STR(""));
CHECK_STRING(xml_node().text().get(), STR(""));
}
TEST_XML_FLAGS(dom_text_as_string, "<node><a>foo</a><b><node/><![CDATA[bar]]></b><c><?pi value?></c><d/></node>", parse_default | parse_pi)
{
xml_node node = doc.child(STR("node"));
CHECK_STRING(node.child(STR("a")).text().as_string(), STR("foo"));
CHECK_STRING(node.child(STR("a")).first_child().text().as_string(), STR("foo"));
CHECK_STRING(node.child(STR("b")).text().as_string(), STR("bar"));
CHECK_STRING(node.child(STR("b")).last_child().text().as_string(), STR("bar"));
CHECK_STRING(node.child(STR("c")).text().as_string(), STR(""));
CHECK_STRING(node.child(STR("c")).first_child().text().as_string(), STR(""));
CHECK_STRING(node.child(STR("d")).text().as_string(), STR(""));
CHECK_STRING(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>")
{
xml_node node = doc.child(STR("node"));
CHECK(xml_text().as_int() == 0);
CHECK(node.child(STR("text1")).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("text4")).text().as_int() == 2147483647);
CHECK(node.child(STR("text5")).text().as_int() == 0);
}
TEST_XML(dom_text_as_int_hex, "<node><text1>0777</text1><text2>0x5ab</text2><text3>0XFf</text3><text4>-0x20</text4><text5>-0x80000000</text5><text6>0x</text6></node>")
{
xml_node node = doc.child(STR("node"));
CHECK(node.child(STR("text1")).text().as_int() == 777); // no octal support! intentional
CHECK(node.child(STR("text2")).text().as_int() == 1451);
CHECK(node.child(STR("text3")).text().as_int() == 255);
CHECK(node.child(STR("text4")).text().as_int() == -32);
CHECK(node.child(STR("text5")).text().as_int() == -2147483647 - 1);
CHECK(node.child(STR("text6")).text().as_int() == 0);
}
TEST_XML(dom_text_as_uint, "<node><text1>0</text1><text2>1</text2><text3>2147483647</text3><text4>4294967295</text4><text5>0</text5></node>")
{
xml_node node = doc.child(STR("node"));
CHECK(xml_text().as_uint() == 0);
CHECK(node.child(STR("text1")).text().as_uint() == 0);
CHECK(node.child(STR("text2")).text().as_uint() == 1);
CHECK(node.child(STR("text3")).text().as_uint() == 2147483647);
CHECK(node.child(STR("text4")).text().as_uint() == 4294967295u);
CHECK(node.child(STR("text5")).text().as_uint() == 0);
}
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"));
CHECK(node.child(STR("text1")).text().as_uint() == 777); // no octal support! intentional
CHECK(node.child(STR("text2")).text().as_uint() == 1451);
CHECK(node.child(STR("text3")).text().as_uint() == 255);
CHECK(node.child(STR("text4")).text().as_uint() == 32);
CHECK(node.child(STR("text5")).text().as_uint() == 4294967295u);
CHECK(node.child(STR("text6")).text().as_uint() == 0);
}
TEST_XML(dom_text_as_integer_space, "<node><text1> \t\n1234</text1><text2>\n\t 0x123</text2><text3>- 16</text3><text4>- 0x10</text4></node>")
{
xml_node node = doc.child(STR("node"));
CHECK(node.child(STR("text1")).text().as_int() == 1234);
CHECK(node.child(STR("text2")).text().as_int() == 291);
CHECK(node.child(STR("text3")).text().as_int() == 0);
CHECK(node.child(STR("text4")).text().as_int() == 0);
}
TEST_XML(dom_text_as_float, "<node><text1>0</text1><text2>1</text2><text3>0.12</text3><text4>-5.1</text4><text5>3e-4</text5><text6>3.14159265358979323846</text6></node>")
{
xml_node node = doc.child(STR("node"));
CHECK(xml_text().as_float() == 0);
CHECK_DOUBLE(double(node.child(STR("text1")).text().as_float()), 0);
CHECK_DOUBLE(double(node.child(STR("text2")).text().as_float()), 1);
CHECK_DOUBLE(double(node.child(STR("text3")).text().as_float()), 0.12);
CHECK_DOUBLE(double(node.child(STR("text4")).text().as_float()), -5.1);
CHECK_DOUBLE(double(node.child(STR("text5")).text().as_float()), 3e-4);
CHECK_DOUBLE(double(node.child(STR("text6")).text().as_float()), 3.14159265358979323846);
}
TEST_XML(dom_text_as_double, "<node><text1>0</text1><text2>1</text2><text3>0.12</text3><text4>-5.1</text4><text5>3e-4</text5><text6>3.14159265358979323846</text6></node>")
{
xml_node node = doc.child(STR("node"));
CHECK(xml_text().as_double() == 0);
CHECK_DOUBLE(node.child(STR("text1")).text().as_double(), 0);
CHECK_DOUBLE(node.child(STR("text2")).text().as_double(), 1);
CHECK_DOUBLE(node.child(STR("text3")).text().as_double(), 0.12);
CHECK_DOUBLE(node.child(STR("text4")).text().as_double(), -5.1);
CHECK_DOUBLE(node.child(STR("text5")).text().as_double(), 3e-4);
CHECK_DOUBLE(node.child(STR("text6")).text().as_double(), 3.14159265358979323846);
}
TEST_XML(dom_text_as_bool, "<node><text1>0</text1><text2>1</text2><text3>true</text3><text4>True</text4><text5>Yes</text5><text6>yes</text6><text7>false</text7></node>")
{
xml_node node = doc.child(STR("node"));
CHECK(!xml_text().as_bool());
CHECK(!node.child(STR("text1")).text().as_bool());
CHECK(node.child(STR("text2")).text().as_bool());
CHECK(node.child(STR("text3")).text().as_bool());
CHECK(node.child(STR("text4")).text().as_bool());
CHECK(node.child(STR("text5")).text().as_bool());
CHECK(node.child(STR("text6")).text().as_bool());
CHECK(!node.child(STR("text7")).text().as_bool());
}
#ifdef PUGIXML_HAS_LONG_LONG
TEST_XML(dom_text_as_llong, "<node><text1>1</text1><text2>-1</text2><text3>-9223372036854775808</text3><text4>9223372036854775807</text4><text5>0</text5></node>")
{
xml_node node = doc.child(STR("node"));
CHECK(xml_text().as_llong() == 0);
CHECK(node.child(STR("text1")).text().as_llong() == 1);
CHECK(node.child(STR("text2")).text().as_llong() == -1);
CHECK(node.child(STR("text3")).text().as_llong() == -9223372036854775807ll - 1);
CHECK(node.child(STR("text4")).text().as_llong() == 9223372036854775807ll);
CHECK(node.child(STR("text5")).text().as_llong() == 0);
}
TEST_XML(dom_text_as_llong_hex, "<node><text1>0777</text1><text2>0x5ab</text2><text3>0XFf</text3><text4>-0x20</text4><text5>-0x8000000000000000</text5><text6>0x</text6></node>")
{
xml_node node = doc.child(STR("node"));
CHECK(node.child(STR("text1")).text().as_llong() == 777); // no octal support! intentional
CHECK(node.child(STR("text2")).text().as_llong() == 1451);
CHECK(node.child(STR("text3")).text().as_llong() == 255);
CHECK(node.child(STR("text4")).text().as_llong() == -32);
CHECK(node.child(STR("text5")).text().as_llong() == -9223372036854775807ll - 1);
CHECK(node.child(STR("text6")).text().as_llong() == 0);
}
TEST_XML(dom_text_as_ullong, "<node><text1>0</text1><text2>1</text2><text3>9223372036854775807</text3><text4>18446744073709551615</text4><text5>0</text5></node>")
{
xml_node node = doc.child(STR("node"));
CHECK(xml_text().as_ullong() == 0);
CHECK(node.child(STR("text1")).text().as_ullong() == 0);
CHECK(node.child(STR("text2")).text().as_ullong() == 1);
CHECK(node.child(STR("text3")).text().as_ullong() == 9223372036854775807ll);
CHECK(node.child(STR("text4")).text().as_ullong() == 18446744073709551615ull);
CHECK(node.child(STR("text5")).text().as_ullong() == 0);
}
TEST_XML(dom_text_as_ullong_hex, "<node><text1>0777</text1><text2>0x5ab</text2><text3>0XFf</text3><text4>0x20</text4><text5>0xFFFFFFFFFFFFFFFF</text5><text6>0x</text6></node>")
{
xml_node node = doc.child(STR("node"));
CHECK(node.child(STR("text1")).text().as_ullong() == 777); // no octal support! intentional
CHECK(node.child(STR("text2")).text().as_ullong() == 1451);
CHECK(node.child(STR("text3")).text().as_ullong() == 255);
CHECK(node.child(STR("text4")).text().as_ullong() == 32);
CHECK(node.child(STR("text5")).text().as_ullong() == 18446744073709551615ull);
CHECK(node.child(STR("text6")).text().as_ullong() == 0);
}
#endif
TEST_XML(dom_text_get_no_state, "<node/>")
{
xml_node node = doc.child(STR("node"));
xml_text t = node.text();
CHECK(!t);
CHECK(t.get() && *t.get() == 0);
CHECK(!node.first_child());
node.append_child(node_pcdata);
CHECK(t);
CHECK_STRING(t.get(), STR(""));
node.first_child().set_value(STR("test"));
CHECK(t);
CHECK_STRING(t.get(), STR("test"));
}
TEST_XML(dom_text_set, "<node/>")
{
xml_node node = doc.child(STR("node"));
xml_text t = node.text();
t.set(STR(""));
CHECK(node.first_child().type() == node_pcdata);
CHECK_NODE(node, STR("<node></node>"));
t.set(STR("boo"));
CHECK(node.first_child().type() == node_pcdata);
CHECK(node.first_child() == node.last_child());
CHECK_NODE(node, STR("<node>boo</node>"));
t.set(STR("foobarfoobar"));
CHECK(node.first_child().type() == node_pcdata);
CHECK(node.first_child() == node.last_child());
CHECK_NODE(node, STR("<node>foobarfoobar</node>"));
}
TEST_XML(dom_text_set_with_size, "<node/>")
{
xml_node node = doc.child(STR("node"));
xml_text t = node.text();
t.set(STR(""), 0);
CHECK(node.first_child().type() == node_pcdata);
CHECK_NODE(node, STR("<node></node>"));
t.set(STR("boo"), 3);
CHECK(node.first_child().type() == node_pcdata);
CHECK(node.first_child() == node.last_child());
CHECK_NODE(node, STR("<node>boo</node>"));
t.set(STR("foobarfoobar"), 12);
CHECK(node.first_child().type() == node_pcdata);
CHECK(node.first_child() == node.last_child());
CHECK_NODE(node, STR("<node>foobarfoobar</node>"));
}
TEST_XML(dom_text_set_partially_with_size, "<node/>")
{
xml_node node = doc.child(STR("node"));
xml_text t = node.text();
t.set(STR("foo"), 0);
CHECK(node.first_child().type() == node_pcdata);
CHECK_NODE(node, STR("<node></node>"));
t.set(STR("boofoo"), 3);
CHECK(node.first_child().type() == node_pcdata);
CHECK(node.first_child() == node.last_child());
CHECK_NODE(node, STR("<node>boo</node>"));
t.set(STR("foobarfoobar"), 3);
CHECK(node.first_child().type() == node_pcdata);
CHECK(node.first_child() == node.last_child());
CHECK_NODE(node, STR("<node>foo</node>"));
}
TEST_XML(dom_text_assign, "<node/>")
{
xml_node node = doc.child(STR("node"));
node.append_child(STR("text1")).text() = STR("v1");
xml_text() = STR("v1");
node.append_child(STR("text2")).text() = -2147483647;
node.append_child(STR("text3")).text() = -2147483647 - 1;
xml_text() = -2147483647 - 1;
node.append_child(STR("text4")).text() = 4294967295u;
node.append_child(STR("text5")).text() = 4294967294u;
xml_text() = 4294967295u;
node.append_child(STR("text6")).text() = 0.5;
xml_text() = 0.5;
node.append_child(STR("text7")).text() = 0.25f;
xml_text() = 0.25f;
node.append_child(STR("text8")).text() = true;
xml_text() = true;
CHECK_NODE(node, STR("<node><text1>v1</text1><text2>-2147483647</text2><text3>-2147483648</text3><text4>4294967295</text4><text5>4294967294</text5><text6>0.5</text6><text7>0.25</text7><text8>true</text8></node>"));
}
TEST_XML(dom_text_set_value, "<node/>")
{
xml_node node = doc.child(STR("node"));
CHECK(node.append_child(STR("text1")).text().set(STR("v1")));
CHECK(!xml_text().set(STR("v1")));
CHECK(node.append_child(STR("text2")).text().set(-2147483647));
CHECK(node.append_child(STR("text3")).text().set(-2147483647 - 1));
CHECK(!xml_text().set(-2147483647 - 1));
CHECK(node.append_child(STR("text4")).text().set(4294967295u));
CHECK(node.append_child(STR("text5")).text().set(4294967294u));
CHECK(!xml_text().set(4294967295u));
CHECK(node.append_child(STR("text6")).text().set(0.5));
CHECK(!xml_text().set(0.5));
CHECK(node.append_child(STR("text7")).text().set(0.25f));
CHECK(!xml_text().set(0.25f));
CHECK(node.append_child(STR("text8")).text().set(true));
CHECK(!xml_text().set(true));
CHECK_NODE(node, STR("<node><text1>v1</text1><text2>-2147483647</text2><text3>-2147483648</text3><text4>4294967295</text4><text5>4294967294</text5><text6>0.5</text6><text7>0.25</text7><text8>true</text8></node>"));
}
#if LONG_MAX > 2147483647
TEST_XML(dom_text_assign_long, "<node/>")
{
xml_node node = doc.child(STR("node"));
node.append_child(STR("text1")).text() = -9223372036854775807l;
node.append_child(STR("text2")).text() = -9223372036854775807l - 1;
xml_text() = -9223372036854775807l - 1;
node.append_child(STR("text3")).text() = 18446744073709551615ul;
node.append_child(STR("text4")).text() = 18446744073709551614ul;
xml_text() = 18446744073709551615ul;
CHECK_NODE(node, STR("<node><text1>-9223372036854775807</text1><text2>-9223372036854775808</text2><text3>18446744073709551615</text3><text4>18446744073709551614</text4></node>"));
}
TEST_XML(dom_text_set_value_long, "<node/>")
{
xml_node node = doc.child(STR("node"));
CHECK(node.append_child(STR("text1")).text().set(-9223372036854775807l));
CHECK(node.append_child(STR("text2")).text().set(-9223372036854775807l - 1));
CHECK(!xml_text().set(-9223372036854775807l - 1));
CHECK(node.append_child(STR("text3")).text().set(18446744073709551615ul));
CHECK(node.append_child(STR("text4")).text().set(18446744073709551614ul));
CHECK(!xml_text().set(18446744073709551615ul));
CHECK_NODE(node, STR("<node><text1>-9223372036854775807</text1><text2>-9223372036854775808</text2><text3>18446744073709551615</text3><text4>18446744073709551614</text4></node>"));
}
#else
TEST_XML(dom_text_assign_long, "<node/>")
{
xml_node node = doc.child(STR("node"));
node.append_child(STR("text1")).text() = -2147483647l;
node.append_child(STR("text2")).text() = -2147483647l - 1;
xml_text() = -2147483647l - 1;
node.append_child(STR("text3")).text() = 4294967295ul;
node.append_child(STR("text4")).text() = 4294967294ul;
xml_text() = 4294967295ul;
CHECK_NODE(node, STR("<node><text1>-2147483647</text1><text2>-2147483648</text2><text3>4294967295</text3><text4>4294967294</text4></node>"));
}
TEST_XML(dom_text_set_value_long, "<node/>")
{
xml_node node = doc.child(STR("node"));
CHECK(node.append_child(STR("text1")).text().set(-2147483647l));
CHECK(node.append_child(STR("text2")).text().set(-2147483647l - 1));
CHECK(!xml_text().set(-2147483647l - 1));
CHECK(node.append_child(STR("text3")).text().set(4294967295ul));
CHECK(node.append_child(STR("text4")).text().set(4294967294ul));
CHECK(!xml_text().set(4294967295ul));
CHECK_NODE(node, STR("<node><text1>-2147483647</text1><text2>-2147483648</text2><text3>4294967295</text3><text4>4294967294</text4></node>"));
}
#endif
#ifdef PUGIXML_HAS_LONG_LONG
TEST_XML(dom_text_assign_llong, "<node/>")
{
xml_node node = doc.child(STR("node"));
node.append_child(STR("text1")).text() = -9223372036854775807ll;
node.append_child(STR("text2")).text() = -9223372036854775807ll - 1;
xml_text() = -9223372036854775807ll - 1;
node.append_child(STR("text3")).text() = 18446744073709551615ull;
node.append_child(STR("text4")).text() = 18446744073709551614ull;
xml_text() = 18446744073709551615ull;
CHECK_NODE(node, STR("<node><text1>-9223372036854775807</text1><text2>-9223372036854775808</text2><text3>18446744073709551615</text3><text4>18446744073709551614</text4></node>"));
}
TEST_XML(dom_text_set_value_llong, "<node/>")
{
xml_node node = doc.child(STR("node"));
CHECK(node.append_child(STR("text1")).text().set(-9223372036854775807ll));
CHECK(node.append_child(STR("text2")).text().set(-9223372036854775807ll - 1));
CHECK(!xml_text().set(-9223372036854775807ll - 1));
CHECK(node.append_child(STR("text3")).text().set(18446744073709551615ull));
CHECK(node.append_child(STR("text4")).text().set(18446744073709551614ull));
CHECK(!xml_text().set(18446744073709551615ull));
CHECK_NODE(node, STR("<node><text1>-9223372036854775807</text1><text2>-9223372036854775808</text2><text3>18446744073709551615</text3><text4>18446744073709551614</text4></node>"));
}
#endif
TEST_XML(dom_text_middle, "<node><c1>notthisone</c1>text<c2/></node>")
{
xml_node node = doc.child(STR("node"));
xml_text t = node.text();
CHECK_STRING(t.get(), STR("text"));
t.set(STR("notext"));
CHECK_NODE(node, STR("<node><c1>notthisone</c1>notext<c2/></node>"));
CHECK(node.remove_child(t.data()));
CHECK(!t);
CHECK_NODE(node, STR("<node><c1>notthisone</c1><c2/></node>"));
t.set(STR("yestext"));
CHECK(t);
CHECK_NODE(node, STR("<node><c1>notthisone</c1><c2/>yestext</node>"));
CHECK(t.data() == node.last_child());
}
TEST_XML_FLAGS(dom_text_data, "<node><a>foo</a><b><![CDATA[bar]]></b><c><?pi value?></c><d/></node>", parse_default | parse_pi)
{
xml_node node = doc.child(STR("node"));
CHECK(node.child(STR("a")).text().data() == node.child(STR("a")).first_child());
CHECK(node.child(STR("b")).text().data() == node.child(STR("b")).first_child());
CHECK(!node.child(STR("c")).text().data());
CHECK(!node.child(STR("d")).text().data());
CHECK(!xml_text().data());
}
TEST(dom_text_defaults)
{
xml_text text;
CHECK_STRING(text.as_string(STR("foo")), STR("foo"));
CHECK(text.as_int(42) == 42);
CHECK(text.as_uint(42) == 42);
CHECK(text.as_double(42) == 42);
CHECK(text.as_float(42) == 42);
CHECK(text.as_bool(true) == true);
#ifdef PUGIXML_HAS_LONG_LONG
CHECK(text.as_llong(42) == 42);
CHECK(text.as_ullong(42) == 42);
#endif
}
#include "test.hpp"
#include "helpers.hpp"
#include <limits.h>
using namespace pugi;
TEST_XML_FLAGS(dom_text_empty, "<node><a>foo</a><b><![CDATA[bar]]></b><c><?pi value?></c><d/></node>", parse_default | parse_pi)
{
xml_node node = doc.child(STR("node"));
CHECK(node.child(STR("a")).text());
CHECK(node.child(STR("b")).text());
CHECK(!node.child(STR("c")).text());
CHECK(!node.child(STR("d")).text());
CHECK(!xml_node().text());
CHECK(!xml_text());
generic_empty_test(node.child(STR("a")).text());
}
TEST_XML(dom_text_bool_ops, "<node>foo</node>")
{
generic_bool_ops_test(doc.child(STR("node")).text());
}
TEST_XML_FLAGS(dom_text_get, "<node><a>foo</a><b><node/><![CDATA[bar]]></b><c><?pi value?></c><d/></node>", parse_default | parse_pi)
{
xml_node node = doc.child(STR("node"));
CHECK_STRING(node.child(STR("a")).text().get(), STR("foo"));
CHECK_STRING(node.child(STR("a")).first_child().text().get(), STR("foo"));
CHECK_STRING(node.child(STR("b")).text().get(), STR("bar"));
CHECK_STRING(node.child(STR("b")).last_child().text().get(), STR("bar"));
CHECK_STRING(node.child(STR("c")).text().get(), STR(""));
CHECK_STRING(node.child(STR("c")).first_child().text().get(), STR(""));
CHECK_STRING(node.child(STR("d")).text().get(), STR(""));
CHECK_STRING(xml_node().text().get(), STR(""));
}
TEST_XML_FLAGS(dom_text_as_string, "<node><a>foo</a><b><node/><![CDATA[bar]]></b><c><?pi value?></c><d/></node>", parse_default | parse_pi)
{
xml_node node = doc.child(STR("node"));
CHECK_STRING(node.child(STR("a")).text().as_string(), STR("foo"));
CHECK_STRING(node.child(STR("a")).first_child().text().as_string(), STR("foo"));
CHECK_STRING(node.child(STR("b")).text().as_string(), STR("bar"));
CHECK_STRING(node.child(STR("b")).last_child().text().as_string(), STR("bar"));
CHECK_STRING(node.child(STR("c")).text().as_string(), STR(""));
CHECK_STRING(node.child(STR("c")).first_child().text().as_string(), STR(""));
CHECK_STRING(node.child(STR("d")).text().as_string(), STR(""));
CHECK_STRING(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>")
{
xml_node node = doc.child(STR("node"));
CHECK(xml_text().as_int() == 0);
CHECK(node.child(STR("text1")).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("text4")).text().as_int() == 2147483647);
CHECK(node.child(STR("text5")).text().as_int() == 0);
}
TEST_XML(dom_text_as_int_hex, "<node><text1>0777</text1><text2>0x5ab</text2><text3>0XFf</text3><text4>-0x20</text4><text5>-0x80000000</text5><text6>0x</text6></node>")
{
xml_node node = doc.child(STR("node"));
CHECK(node.child(STR("text1")).text().as_int() == 777); // no octal support! intentional
CHECK(node.child(STR("text2")).text().as_int() == 1451);
CHECK(node.child(STR("text3")).text().as_int() == 255);
CHECK(node.child(STR("text4")).text().as_int() == -32);
CHECK(node.child(STR("text5")).text().as_int() == -2147483647 - 1);
CHECK(node.child(STR("text6")).text().as_int() == 0);
}
TEST_XML(dom_text_as_uint, "<node><text1>0</text1><text2>1</text2><text3>2147483647</text3><text4>4294967295</text4><text5>0</text5></node>")
{
xml_node node = doc.child(STR("node"));
CHECK(xml_text().as_uint() == 0);
CHECK(node.child(STR("text1")).text().as_uint() == 0);
CHECK(node.child(STR("text2")).text().as_uint() == 1);
CHECK(node.child(STR("text3")).text().as_uint() == 2147483647);
CHECK(node.child(STR("text4")).text().as_uint() == 4294967295u);
CHECK(node.child(STR("text5")).text().as_uint() == 0);
}
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"));
CHECK(node.child(STR("text1")).text().as_uint() == 777); // no octal support! intentional
CHECK(node.child(STR("text2")).text().as_uint() == 1451);
CHECK(node.child(STR("text3")).text().as_uint() == 255);
CHECK(node.child(STR("text4")).text().as_uint() == 32);
CHECK(node.child(STR("text5")).text().as_uint() == 4294967295u);
CHECK(node.child(STR("text6")).text().as_uint() == 0);
}
TEST_XML(dom_text_as_integer_space, "<node><text1> \t\n1234</text1><text2>\n\t 0x123</text2><text3>- 16</text3><text4>- 0x10</text4></node>")
{
xml_node node = doc.child(STR("node"));
CHECK(node.child(STR("text1")).text().as_int() == 1234);
CHECK(node.child(STR("text2")).text().as_int() == 291);
CHECK(node.child(STR("text3")).text().as_int() == 0);
CHECK(node.child(STR("text4")).text().as_int() == 0);
}
TEST_XML(dom_text_as_float, "<node><text1>0</text1><text2>1</text2><text3>0.12</text3><text4>-5.1</text4><text5>3e-4</text5><text6>3.14159265358979323846</text6></node>")
{
xml_node node = doc.child(STR("node"));
CHECK(xml_text().as_float() == 0);
CHECK_DOUBLE(double(node.child(STR("text1")).text().as_float()), 0);
CHECK_DOUBLE(double(node.child(STR("text2")).text().as_float()), 1);
CHECK_DOUBLE(double(node.child(STR("text3")).text().as_float()), 0.12);
CHECK_DOUBLE(double(node.child(STR("text4")).text().as_float()), -5.1);
CHECK_DOUBLE(double(node.child(STR("text5")).text().as_float()), 3e-4);
CHECK_DOUBLE(double(node.child(STR("text6")).text().as_float()), 3.14159265358979323846);
}
TEST_XML(dom_text_as_double, "<node><text1>0</text1><text2>1</text2><text3>0.12</text3><text4>-5.1</text4><text5>3e-4</text5><text6>3.14159265358979323846</text6></node>")
{
xml_node node = doc.child(STR("node"));
CHECK(xml_text().as_double() == 0);
CHECK_DOUBLE(node.child(STR("text1")).text().as_double(), 0);
CHECK_DOUBLE(node.child(STR("text2")).text().as_double(), 1);
CHECK_DOUBLE(node.child(STR("text3")).text().as_double(), 0.12);
CHECK_DOUBLE(node.child(STR("text4")).text().as_double(), -5.1);
CHECK_DOUBLE(node.child(STR("text5")).text().as_double(), 3e-4);
CHECK_DOUBLE(node.child(STR("text6")).text().as_double(), 3.14159265358979323846);
}
TEST_XML(dom_text_as_bool, "<node><text1>0</text1><text2>1</text2><text3>true</text3><text4>True</text4><text5>Yes</text5><text6>yes</text6><text7>false</text7></node>")
{
xml_node node = doc.child(STR("node"));
CHECK(!xml_text().as_bool());
CHECK(!node.child(STR("text1")).text().as_bool());
CHECK(node.child(STR("text2")).text().as_bool());
CHECK(node.child(STR("text3")).text().as_bool());
CHECK(node.child(STR("text4")).text().as_bool());
CHECK(node.child(STR("text5")).text().as_bool());
CHECK(node.child(STR("text6")).text().as_bool());
CHECK(!node.child(STR("text7")).text().as_bool());
}
#ifdef PUGIXML_HAS_LONG_LONG
TEST_XML(dom_text_as_llong, "<node><text1>1</text1><text2>-1</text2><text3>-9223372036854775808</text3><text4>9223372036854775807</text4><text5>0</text5></node>")
{
xml_node node = doc.child(STR("node"));
CHECK(xml_text().as_llong() == 0);
CHECK(node.child(STR("text1")).text().as_llong() == 1);
CHECK(node.child(STR("text2")).text().as_llong() == -1);
CHECK(node.child(STR("text3")).text().as_llong() == -9223372036854775807ll - 1);
CHECK(node.child(STR("text4")).text().as_llong() == 9223372036854775807ll);
CHECK(node.child(STR("text5")).text().as_llong() == 0);
}
TEST_XML(dom_text_as_llong_hex, "<node><text1>0777</text1><text2>0x5ab</text2><text3>0XFf</text3><text4>-0x20</text4><text5>-0x8000000000000000</text5><text6>0x</text6></node>")
{
xml_node node = doc.child(STR("node"));
CHECK(node.child(STR("text1")).text().as_llong() == 777); // no octal support! intentional
CHECK(node.child(STR("text2")).text().as_llong() == 1451);
CHECK(node.child(STR("text3")).text().as_llong() == 255);
CHECK(node.child(STR("text4")).text().as_llong() == -32);
CHECK(node.child(STR("text5")).text().as_llong() == -9223372036854775807ll - 1);
CHECK(node.child(STR("text6")).text().as_llong() == 0);
}
TEST_XML(dom_text_as_ullong, "<node><text1>0</text1><text2>1</text2><text3>9223372036854775807</text3><text4>18446744073709551615</text4><text5>0</text5></node>")
{
xml_node node = doc.child(STR("node"));
CHECK(xml_text().as_ullong() == 0);
CHECK(node.child(STR("text1")).text().as_ullong() == 0);
CHECK(node.child(STR("text2")).text().as_ullong() == 1);
CHECK(node.child(STR("text3")).text().as_ullong() == 9223372036854775807ll);
CHECK(node.child(STR("text4")).text().as_ullong() == 18446744073709551615ull);
CHECK(node.child(STR("text5")).text().as_ullong() == 0);
}
TEST_XML(dom_text_as_ullong_hex, "<node><text1>0777</text1><text2>0x5ab</text2><text3>0XFf</text3><text4>0x20</text4><text5>0xFFFFFFFFFFFFFFFF</text5><text6>0x</text6></node>")
{
xml_node node = doc.child(STR("node"));
CHECK(node.child(STR("text1")).text().as_ullong() == 777); // no octal support! intentional
CHECK(node.child(STR("text2")).text().as_ullong() == 1451);
CHECK(node.child(STR("text3")).text().as_ullong() == 255);
CHECK(node.child(STR("text4")).text().as_ullong() == 32);
CHECK(node.child(STR("text5")).text().as_ullong() == 18446744073709551615ull);
CHECK(node.child(STR("text6")).text().as_ullong() == 0);
}
#endif
TEST_XML(dom_text_get_no_state, "<node/>")
{
xml_node node = doc.child(STR("node"));
xml_text t = node.text();
CHECK(!t);
CHECK(t.get() && *t.get() == 0);
CHECK(!node.first_child());
node.append_child(node_pcdata);
CHECK(t);
CHECK_STRING(t.get(), STR(""));
node.first_child().set_value(STR("test"));
CHECK(t);
CHECK_STRING(t.get(), STR("test"));
}
TEST_XML(dom_text_set, "<node/>")
{
xml_node node = doc.child(STR("node"));
xml_text t = node.text();
t.set(STR(""));
CHECK(node.first_child().type() == node_pcdata);
CHECK_NODE(node, STR("<node></node>"));
t.set(STR("boo"));
CHECK(node.first_child().type() == node_pcdata);
CHECK(node.first_child() == node.last_child());
CHECK_NODE(node, STR("<node>boo</node>"));
t.set(STR("foobarfoobar"));
CHECK(node.first_child().type() == node_pcdata);
CHECK(node.first_child() == node.last_child());
CHECK_NODE(node, STR("<node>foobarfoobar</node>"));
}
TEST_XML(dom_text_set_with_size, "<node/>")
{
xml_node node = doc.child(STR("node"));
xml_text t = node.text();
t.set(STR(""), 0);
CHECK(node.first_child().type() == node_pcdata);
CHECK_NODE(node, STR("<node></node>"));
t.set(STR("boo"), 3);
CHECK(node.first_child().type() == node_pcdata);
CHECK(node.first_child() == node.last_child());
CHECK_NODE(node, STR("<node>boo</node>"));
t.set(STR("foobarfoobar"), 12);
CHECK(node.first_child().type() == node_pcdata);
CHECK(node.first_child() == node.last_child());
CHECK_NODE(node, STR("<node>foobarfoobar</node>"));
}
TEST_XML(dom_text_set_partially_with_size, "<node/>")
{
xml_node node = doc.child(STR("node"));
xml_text t = node.text();
t.set(STR("foo"), 0);
CHECK(node.first_child().type() == node_pcdata);
CHECK_NODE(node, STR("<node></node>"));
t.set(STR("boofoo"), 3);
CHECK(node.first_child().type() == node_pcdata);
CHECK(node.first_child() == node.last_child());
CHECK_NODE(node, STR("<node>boo</node>"));
t.set(STR("foobarfoobar"), 3);
CHECK(node.first_child().type() == node_pcdata);
CHECK(node.first_child() == node.last_child());
CHECK_NODE(node, STR("<node>foo</node>"));
}
TEST_XML(dom_text_assign, "<node/>")
{
xml_node node = doc.child(STR("node"));
node.append_child(STR("text1")).text() = STR("v1");
xml_text() = STR("v1");
node.append_child(STR("text2")).text() = -2147483647;
node.append_child(STR("text3")).text() = -2147483647 - 1;
xml_text() = -2147483647 - 1;
node.append_child(STR("text4")).text() = 4294967295u;
node.append_child(STR("text5")).text() = 4294967294u;
xml_text() = 4294967295u;
node.append_child(STR("text6")).text() = 0.5;
xml_text() = 0.5;
node.append_child(STR("text7")).text() = 0.25f;
xml_text() = 0.25f;
node.append_child(STR("text8")).text() = true;
xml_text() = true;
CHECK_NODE(node, STR("<node><text1>v1</text1><text2>-2147483647</text2><text3>-2147483648</text3><text4>4294967295</text4><text5>4294967294</text5><text6>0.5</text6><text7>0.25</text7><text8>true</text8></node>"));
}
TEST_XML(dom_text_set_value, "<node/>")
{
xml_node node = doc.child(STR("node"));
CHECK(node.append_child(STR("text1")).text().set(STR("v1")));
CHECK(!xml_text().set(STR("v1")));
CHECK(node.append_child(STR("text2")).text().set(-2147483647));
CHECK(node.append_child(STR("text3")).text().set(-2147483647 - 1));
CHECK(!xml_text().set(-2147483647 - 1));
CHECK(node.append_child(STR("text4")).text().set(4294967295u));
CHECK(node.append_child(STR("text5")).text().set(4294967294u));
CHECK(!xml_text().set(4294967295u));
CHECK(node.append_child(STR("text6")).text().set(0.5));
CHECK(!xml_text().set(0.5));
CHECK(node.append_child(STR("text7")).text().set(0.25f));
CHECK(!xml_text().set(0.25f));
CHECK(node.append_child(STR("text8")).text().set(true));
CHECK(!xml_text().set(true));
CHECK_NODE(node, STR("<node><text1>v1</text1><text2>-2147483647</text2><text3>-2147483648</text3><text4>4294967295</text4><text5>4294967294</text5><text6>0.5</text6><text7>0.25</text7><text8>true</text8></node>"));
}
#if LONG_MAX > 2147483647
TEST_XML(dom_text_assign_long, "<node/>")
{
xml_node node = doc.child(STR("node"));
node.append_child(STR("text1")).text() = -9223372036854775807l;
node.append_child(STR("text2")).text() = -9223372036854775807l - 1;
xml_text() = -9223372036854775807l - 1;
node.append_child(STR("text3")).text() = 18446744073709551615ul;
node.append_child(STR("text4")).text() = 18446744073709551614ul;
xml_text() = 18446744073709551615ul;
CHECK_NODE(node, STR("<node><text1>-9223372036854775807</text1><text2>-9223372036854775808</text2><text3>18446744073709551615</text3><text4>18446744073709551614</text4></node>"));
}
TEST_XML(dom_text_set_value_long, "<node/>")
{
xml_node node = doc.child(STR("node"));
CHECK(node.append_child(STR("text1")).text().set(-9223372036854775807l));
CHECK(node.append_child(STR("text2")).text().set(-9223372036854775807l - 1));
CHECK(!xml_text().set(-9223372036854775807l - 1));
CHECK(node.append_child(STR("text3")).text().set(18446744073709551615ul));
CHECK(node.append_child(STR("text4")).text().set(18446744073709551614ul));
CHECK(!xml_text().set(18446744073709551615ul));
CHECK_NODE(node, STR("<node><text1>-9223372036854775807</text1><text2>-9223372036854775808</text2><text3>18446744073709551615</text3><text4>18446744073709551614</text4></node>"));
}
#else
TEST_XML(dom_text_assign_long, "<node/>")
{
xml_node node = doc.child(STR("node"));
node.append_child(STR("text1")).text() = -2147483647l;
node.append_child(STR("text2")).text() = -2147483647l - 1;
xml_text() = -2147483647l - 1;
node.append_child(STR("text3")).text() = 4294967295ul;
node.append_child(STR("text4")).text() = 4294967294ul;
xml_text() = 4294967295ul;
CHECK_NODE(node, STR("<node><text1>-2147483647</text1><text2>-2147483648</text2><text3>4294967295</text3><text4>4294967294</text4></node>"));
}
TEST_XML(dom_text_set_value_long, "<node/>")
{
xml_node node = doc.child(STR("node"));
CHECK(node.append_child(STR("text1")).text().set(-2147483647l));
CHECK(node.append_child(STR("text2")).text().set(-2147483647l - 1));
CHECK(!xml_text().set(-2147483647l - 1));
CHECK(node.append_child(STR("text3")).text().set(4294967295ul));
CHECK(node.append_child(STR("text4")).text().set(4294967294ul));
CHECK(!xml_text().set(4294967295ul));
CHECK_NODE(node, STR("<node><text1>-2147483647</text1><text2>-2147483648</text2><text3>4294967295</text3><text4>4294967294</text4></node>"));
}
#endif
#ifdef PUGIXML_HAS_LONG_LONG
TEST_XML(dom_text_assign_llong, "<node/>")
{
xml_node node = doc.child(STR("node"));
node.append_child(STR("text1")).text() = -9223372036854775807ll;
node.append_child(STR("text2")).text() = -9223372036854775807ll - 1;
xml_text() = -9223372036854775807ll - 1;
node.append_child(STR("text3")).text() = 18446744073709551615ull;
node.append_child(STR("text4")).text() = 18446744073709551614ull;
xml_text() = 18446744073709551615ull;
CHECK_NODE(node, STR("<node><text1>-9223372036854775807</text1><text2>-9223372036854775808</text2><text3>18446744073709551615</text3><text4>18446744073709551614</text4></node>"));
}
TEST_XML(dom_text_set_value_llong, "<node/>")
{
xml_node node = doc.child(STR("node"));
CHECK(node.append_child(STR("text1")).text().set(-9223372036854775807ll));
CHECK(node.append_child(STR("text2")).text().set(-9223372036854775807ll - 1));
CHECK(!xml_text().set(-9223372036854775807ll - 1));
CHECK(node.append_child(STR("text3")).text().set(18446744073709551615ull));
CHECK(node.append_child(STR("text4")).text().set(18446744073709551614ull));
CHECK(!xml_text().set(18446744073709551615ull));
CHECK_NODE(node, STR("<node><text1>-9223372036854775807</text1><text2>-9223372036854775808</text2><text3>18446744073709551615</text3><text4>18446744073709551614</text4></node>"));
}
#endif
TEST_XML(dom_text_middle, "<node><c1>notthisone</c1>text<c2/></node>")
{
xml_node node = doc.child(STR("node"));
xml_text t = node.text();
CHECK_STRING(t.get(), STR("text"));
t.set(STR("notext"));
CHECK_NODE(node, STR("<node><c1>notthisone</c1>notext<c2/></node>"));
CHECK(node.remove_child(t.data()));
CHECK(!t);
CHECK_NODE(node, STR("<node><c1>notthisone</c1><c2/></node>"));
t.set(STR("yestext"));
CHECK(t);
CHECK_NODE(node, STR("<node><c1>notthisone</c1><c2/>yestext</node>"));
CHECK(t.data() == node.last_child());
}
TEST_XML_FLAGS(dom_text_data, "<node><a>foo</a><b><![CDATA[bar]]></b><c><?pi value?></c><d/></node>", parse_default | parse_pi)
{
xml_node node = doc.child(STR("node"));
CHECK(node.child(STR("a")).text().data() == node.child(STR("a")).first_child());
CHECK(node.child(STR("b")).text().data() == node.child(STR("b")).first_child());
CHECK(!node.child(STR("c")).text().data());
CHECK(!node.child(STR("d")).text().data());
CHECK(!xml_text().data());
}
TEST(dom_text_defaults)
{
xml_text text;
CHECK_STRING(text.as_string(STR("foo")), STR("foo"));
CHECK(text.as_int(42) == 42);
CHECK(text.as_uint(42) == 42);
CHECK(text.as_double(42) == 42);
CHECK(text.as_float(42) == 42);
CHECK(text.as_bool(true) == true);
#ifdef PUGIXML_HAS_LONG_LONG
CHECK(text.as_llong(42) == 42);
CHECK(text.as_ullong(42) == 42);
#endif
}

File diff suppressed because it is too large Load Diff

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,21 +1,21 @@
#define PUGIXML_HEADER_ONLY
#define pugi pugih
#include "test.hpp"
// Check header guards
#include "../src/pugixml.hpp"
#include "../src/pugixml.hpp"
using namespace pugi;
TEST(header_only_1)
{
xml_document doc;
CHECK(doc.load_string(STR("<node/>")));
CHECK_STRING(doc.first_child().name(), STR("node"));
#ifndef PUGIXML_NO_XPATH
CHECK(doc.first_child() == doc.select_node(STR("//*")).node());
#endif
}
#define PUGIXML_HEADER_ONLY
#define pugi pugih
#include "test.hpp"
// Check header guards
#include "../src/pugixml.hpp"
#include "../src/pugixml.hpp"
using namespace pugi;
TEST(header_only_1)
{
xml_document doc;
CHECK(doc.load_string(STR("<node/>")));
CHECK_STRING(doc.first_child().name(), STR("node"));
#ifndef PUGIXML_NO_XPATH
CHECK(doc.first_child() == doc.select_node(STR("//*")).node());
#endif
}

View File

@ -1,21 +1,21 @@
#define PUGIXML_HEADER_ONLY
#define pugi pugih
#include "test.hpp"
// Check header guards
#include "../src/pugixml.hpp"
#include "../src/pugixml.hpp"
using namespace pugi;
TEST(header_only_2)
{
xml_document doc;
CHECK(doc.load_string(STR("<node/>")));
CHECK_STRING(doc.first_child().name(), STR("node"));
#ifndef PUGIXML_NO_XPATH
CHECK(doc.first_child() == doc.select_node(STR("//*")).node());
#endif
}
#define PUGIXML_HEADER_ONLY
#define pugi pugih
#include "test.hpp"
// Check header guards
#include "../src/pugixml.hpp"
#include "../src/pugixml.hpp"
using namespace pugi;
TEST(header_only_2)
{
xml_document doc;
CHECK(doc.load_string(STR("<node/>")));
CHECK_STRING(doc.first_child().name(), STR("node"));
#ifndef PUGIXML_NO_XPATH
CHECK(doc.first_child() == doc.select_node(STR("//*")).node());
#endif
}

View File

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

View File

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

View File

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

View File

@ -1,303 +1,303 @@
#include "test.hpp"
#include "writer_string.hpp"
#include "allocator.hpp"
#include <string>
#include <vector>
using namespace pugi;
namespace
{
int page_allocs = 0;
int page_deallocs = 0;
bool is_page(size_t size)
{
return size >= 16384;
}
void* allocate(size_t size)
{
void* ptr = memory_allocate(size);
page_allocs += is_page(memory_size(ptr));
return ptr;
}
void deallocate(void* ptr)
{
page_deallocs += is_page(memory_size(ptr));
memory_deallocate(ptr);
}
}
TEST(memory_custom_memory_management)
{
page_allocs = page_deallocs = 0;
// remember old functions
allocation_function old_allocate = get_memory_allocation_function();
deallocation_function old_deallocate = get_memory_deallocation_function();
// replace functions
set_memory_management_functions(allocate, deallocate);
{
// parse document
xml_document doc;
CHECK(page_allocs == 0 && page_deallocs == 0);
CHECK(doc.load_string(STR("<node />")));
CHECK(page_allocs == 1 && page_deallocs == 0);
// modify document (no new page)
CHECK(doc.first_child().set_name(STR("foobars")));
CHECK(page_allocs == 1 && page_deallocs == 0);
// modify document (new page)
std::basic_string<char_t> s(65536, 'x');
CHECK(doc.first_child().set_name(s.c_str()));
CHECK(page_allocs == 2 && page_deallocs == 0);
// modify document (new page, old one should die)
s += s;
CHECK(doc.first_child().set_name(s.c_str()));
CHECK(page_allocs == 3 && page_deallocs == 1);
}
CHECK(page_allocs == 3 && page_deallocs == 3);
// restore old functions
set_memory_management_functions(old_allocate, old_deallocate);
}
TEST(memory_large_allocations)
{
page_allocs = page_deallocs = 0;
// remember old functions
allocation_function old_allocate = get_memory_allocation_function();
deallocation_function old_deallocate = get_memory_deallocation_function();
// replace functions
set_memory_management_functions(allocate, deallocate);
{
xml_document doc;
CHECK(page_allocs == 0 && page_deallocs == 0);
// initial fill
for (size_t i = 0; i < 128; ++i)
{
std::basic_string<char_t> s(i * 128, 'x');
CHECK(doc.append_child(node_pcdata).set_value(s.c_str()));
}
CHECK(page_allocs > 0 && page_deallocs == 0);
// grow-prune loop
while (doc.first_child())
{
xml_node node;
// grow
for (node = doc.first_child(); node; node = node.next_sibling())
{
std::basic_string<char_t> s = node.value();
CHECK(node.set_value((s + s).c_str()));
}
// prune
for (node = doc.first_child(); node; )
{
xml_node next = node.next_sibling().next_sibling();
node.parent().remove_child(node);
node = next;
}
}
CHECK(page_allocs == page_deallocs + 1); // only one live page left (it waits for new allocations)
char buffer;
CHECK(doc.load_buffer_inplace(&buffer, 0, parse_fragment, get_native_encoding()));
CHECK(page_allocs == page_deallocs); // no live pages left
}
CHECK(page_allocs == page_deallocs); // everything is freed
// restore old functions
set_memory_management_functions(old_allocate, old_deallocate);
}
TEST(memory_page_management)
{
page_allocs = page_deallocs = 0;
// remember old functions
allocation_function old_allocate = get_memory_allocation_function();
deallocation_function old_deallocate = get_memory_deallocation_function();
// replace functions
set_memory_management_functions(allocate, deallocate);
{
xml_document doc;
CHECK(page_allocs == 0 && page_deallocs == 0);
// initial fill
std::vector<xml_node> nodes;
for (size_t i = 0; i < 4000; ++i)
{
xml_node node = doc.append_child(STR("n"));
CHECK(node);
nodes.push_back(node);
}
CHECK(page_allocs > 0 && page_deallocs == 0);
// grow-prune loop
size_t offset = 0;
size_t prime = 15485863;
while (nodes.size() > 0)
{
offset = (offset + prime) % nodes.size();
doc.remove_child(nodes[offset]);
nodes[offset] = nodes.back();
nodes.pop_back();
}
CHECK(page_allocs == page_deallocs + 1); // only one live page left (it waits for new allocations)
char buffer;
CHECK(doc.load_buffer_inplace(&buffer, 0, parse_fragment, get_native_encoding()));
CHECK(page_allocs == page_deallocs); // no live pages left
}
CHECK(page_allocs == page_deallocs); // everything is freed
// restore old functions
set_memory_management_functions(old_allocate, old_deallocate);
}
TEST(memory_string_allocate_increasing)
{
xml_document doc;
doc.append_child(node_pcdata).set_value(STR("x"));
std::basic_string<char_t> s = STR("ab");
for (int i = 0; i < 17; ++i)
{
doc.append_child(node_pcdata).set_value(s.c_str());
s += s;
}
std::string result = save_narrow(doc, format_no_declaration | format_raw, encoding_utf8);
CHECK(result.size() == 262143);
CHECK(result[0] == 'x');
for (size_t j = 1; j < result.size(); ++j)
{
CHECK(result[j] == (j % 2 ? 'a' : 'b'));
}
}
TEST(memory_string_allocate_decreasing)
{
xml_document doc;
std::basic_string<char_t> s = STR("ab");
for (int i = 0; i < 17; ++i) s += s;
for (int j = 0; j < 17; ++j)
{
s.resize(s.size() / 2);
doc.append_child(node_pcdata).set_value(s.c_str());
}
doc.append_child(node_pcdata).set_value(STR("x"));
std::string result = save_narrow(doc, format_no_declaration | format_raw, encoding_utf8);
CHECK(result.size() == 262143);
CHECK(result[result.size() - 1] == 'x');
for (size_t k = 0; k + 1 < result.size(); ++k)
{
CHECK(result[k] == (k % 2 ? 'b' : 'a'));
}
}
TEST(memory_string_allocate_increasing_inplace)
{
xml_document doc;
xml_node node = doc.append_child(node_pcdata);
node.set_value(STR("x"));
std::basic_string<char_t> s = STR("ab");
for (int i = 0; i < 17; ++i)
{
node.set_value(s.c_str());
s += s;
}
std::string result = save_narrow(doc, format_no_declaration | format_raw, encoding_utf8);
CHECK(result.size() == 131072);
for (size_t j = 0; j < result.size(); ++j)
{
CHECK(result[j] == (j % 2 ? 'b' : 'a'));
}
}
TEST(memory_string_allocate_decreasing_inplace)
{
xml_document doc;
xml_node node = doc.append_child(node_pcdata);
std::basic_string<char_t> s = STR("ab");
for (int i = 0; i < 17; ++i) s += s;
for (int j = 0; j < 17; ++j)
{
s.resize(s.size() / 2);
node.set_value(s.c_str());
}
node.set_value(STR("x"));
std::string result = save_narrow(doc, format_no_declaration | format_raw, encoding_utf8);
CHECK(result == "x");
}
#include "test.hpp"
#include "writer_string.hpp"
#include "allocator.hpp"
#include <string>
#include <vector>
using namespace pugi;
namespace
{
int page_allocs = 0;
int page_deallocs = 0;
bool is_page(size_t size)
{
return size >= 16384;
}
void* allocate(size_t size)
{
void* ptr = memory_allocate(size);
page_allocs += is_page(memory_size(ptr));
return ptr;
}
void deallocate(void* ptr)
{
page_deallocs += is_page(memory_size(ptr));
memory_deallocate(ptr);
}
}
TEST(memory_custom_memory_management)
{
page_allocs = page_deallocs = 0;
// remember old functions
allocation_function old_allocate = get_memory_allocation_function();
deallocation_function old_deallocate = get_memory_deallocation_function();
// replace functions
set_memory_management_functions(allocate, deallocate);
{
// parse document
xml_document doc;
CHECK(page_allocs == 0 && page_deallocs == 0);
CHECK(doc.load_string(STR("<node />")));
CHECK(page_allocs == 1 && page_deallocs == 0);
// modify document (no new page)
CHECK(doc.first_child().set_name(STR("foobars")));
CHECK(page_allocs == 1 && page_deallocs == 0);
// modify document (new page)
std::basic_string<char_t> s(65536, 'x');
CHECK(doc.first_child().set_name(s.c_str()));
CHECK(page_allocs == 2 && page_deallocs == 0);
// modify document (new page, old one should die)
s += s;
CHECK(doc.first_child().set_name(s.c_str()));
CHECK(page_allocs == 3 && page_deallocs == 1);
}
CHECK(page_allocs == 3 && page_deallocs == 3);
// restore old functions
set_memory_management_functions(old_allocate, old_deallocate);
}
TEST(memory_large_allocations)
{
page_allocs = page_deallocs = 0;
// remember old functions
allocation_function old_allocate = get_memory_allocation_function();
deallocation_function old_deallocate = get_memory_deallocation_function();
// replace functions
set_memory_management_functions(allocate, deallocate);
{
xml_document doc;
CHECK(page_allocs == 0 && page_deallocs == 0);
// initial fill
for (size_t i = 0; i < 128; ++i)
{
std::basic_string<char_t> s(i * 128, 'x');
CHECK(doc.append_child(node_pcdata).set_value(s.c_str()));
}
CHECK(page_allocs > 0 && page_deallocs == 0);
// grow-prune loop
while (doc.first_child())
{
xml_node node;
// grow
for (node = doc.first_child(); node; node = node.next_sibling())
{
std::basic_string<char_t> s = node.value();
CHECK(node.set_value((s + s).c_str()));
}
// prune
for (node = doc.first_child(); node; )
{
xml_node next = node.next_sibling().next_sibling();
node.parent().remove_child(node);
node = next;
}
}
CHECK(page_allocs == page_deallocs + 1); // only one live page left (it waits for new allocations)
char buffer;
CHECK(doc.load_buffer_inplace(&buffer, 0, parse_fragment, get_native_encoding()));
CHECK(page_allocs == page_deallocs); // no live pages left
}
CHECK(page_allocs == page_deallocs); // everything is freed
// restore old functions
set_memory_management_functions(old_allocate, old_deallocate);
}
TEST(memory_page_management)
{
page_allocs = page_deallocs = 0;
// remember old functions
allocation_function old_allocate = get_memory_allocation_function();
deallocation_function old_deallocate = get_memory_deallocation_function();
// replace functions
set_memory_management_functions(allocate, deallocate);
{
xml_document doc;
CHECK(page_allocs == 0 && page_deallocs == 0);
// initial fill
std::vector<xml_node> nodes;
for (size_t i = 0; i < 4000; ++i)
{
xml_node node = doc.append_child(STR("n"));
CHECK(node);
nodes.push_back(node);
}
CHECK(page_allocs > 0 && page_deallocs == 0);
// grow-prune loop
size_t offset = 0;
size_t prime = 15485863;
while (nodes.size() > 0)
{
offset = (offset + prime) % nodes.size();
doc.remove_child(nodes[offset]);
nodes[offset] = nodes.back();
nodes.pop_back();
}
CHECK(page_allocs == page_deallocs + 1); // only one live page left (it waits for new allocations)
char buffer;
CHECK(doc.load_buffer_inplace(&buffer, 0, parse_fragment, get_native_encoding()));
CHECK(page_allocs == page_deallocs); // no live pages left
}
CHECK(page_allocs == page_deallocs); // everything is freed
// restore old functions
set_memory_management_functions(old_allocate, old_deallocate);
}
TEST(memory_string_allocate_increasing)
{
xml_document doc;
doc.append_child(node_pcdata).set_value(STR("x"));
std::basic_string<char_t> s = STR("ab");
for (int i = 0; i < 17; ++i)
{
doc.append_child(node_pcdata).set_value(s.c_str());
s += s;
}
std::string result = save_narrow(doc, format_no_declaration | format_raw, encoding_utf8);
CHECK(result.size() == 262143);
CHECK(result[0] == 'x');
for (size_t j = 1; j < result.size(); ++j)
{
CHECK(result[j] == (j % 2 ? 'a' : 'b'));
}
}
TEST(memory_string_allocate_decreasing)
{
xml_document doc;
std::basic_string<char_t> s = STR("ab");
for (int i = 0; i < 17; ++i) s += s;
for (int j = 0; j < 17; ++j)
{
s.resize(s.size() / 2);
doc.append_child(node_pcdata).set_value(s.c_str());
}
doc.append_child(node_pcdata).set_value(STR("x"));
std::string result = save_narrow(doc, format_no_declaration | format_raw, encoding_utf8);
CHECK(result.size() == 262143);
CHECK(result[result.size() - 1] == 'x');
for (size_t k = 0; k + 1 < result.size(); ++k)
{
CHECK(result[k] == (k % 2 ? 'b' : 'a'));
}
}
TEST(memory_string_allocate_increasing_inplace)
{
xml_document doc;
xml_node node = doc.append_child(node_pcdata);
node.set_value(STR("x"));
std::basic_string<char_t> s = STR("ab");
for (int i = 0; i < 17; ++i)
{
node.set_value(s.c_str());
s += s;
}
std::string result = save_narrow(doc, format_no_declaration | format_raw, encoding_utf8);
CHECK(result.size() == 131072);
for (size_t j = 0; j < result.size(); ++j)
{
CHECK(result[j] == (j % 2 ? 'b' : 'a'));
}
}
TEST(memory_string_allocate_decreasing_inplace)
{
xml_document doc;
xml_node node = doc.append_child(node_pcdata);
std::basic_string<char_t> s = STR("ab");
for (int i = 0; i < 17; ++i) s += s;
for (int j = 0; j < 17; ++j)
{
s.resize(s.size() / 2);
node.set_value(s.c_str());
}
node.set_value(STR("x"));
std::string result = save_narrow(doc, format_no_declaration | format_raw, encoding_utf8);
CHECK(result == "x");
}

File diff suppressed because it is too large Load Diff

View File

@ -1,366 +1,366 @@
#define _CRT_SECURE_NO_WARNINGS
#include "test.hpp"
#include <string.h>
#include <wchar.h>
#include <string>
using namespace pugi;
static xml_parse_result load_concat(xml_document& doc, const char_t* a, const char_t* b = STR(""), const char_t* c = STR(""))
{
char_t buffer[768];
#ifdef PUGIXML_WCHAR_MODE
wcscpy(buffer, a);
wcscat(buffer, b);
wcscat(buffer, c);
#else
strcpy(buffer, a);
strcat(buffer, b);
strcat(buffer, c);
#endif
return doc.load_string(buffer, parse_fragment);
}
static bool test_doctype_wf(const char_t* decl)
{
xml_document doc;
// standalone
if (!load_concat(doc, decl) || !doc.first_child().empty()) return false;
// pcdata pre/postfix
if (!load_concat(doc, STR("a"), decl) || !test_node(doc, STR("a"), STR(""), format_raw)) return false;
if (!load_concat(doc, decl, STR("b")) || !test_node(doc, STR("b"), STR(""), format_raw)) return false;
if (!load_concat(doc, STR("a"), decl, STR("b")) || !test_node(doc, STR("ab"), STR(""), format_raw)) return false;
// node pre/postfix
if (!load_concat(doc, STR("<nodea/>"), decl) || !test_node(doc, STR("<nodea/>"), STR(""), format_raw)) return false;
if (!load_concat(doc, decl, STR("<nodeb/>")) || !test_node(doc, STR("<nodeb/>"), STR(""), format_raw)) return false;
if (!load_concat(doc, STR("<nodea/>"), decl, STR("<nodeb/>")) || !test_node(doc, STR("<nodea/><nodeb/>"), STR(""), format_raw)) return false;
// check load-store contents preservation
CHECK(doc.load_string(decl, parse_doctype | parse_fragment));
CHECK_NODE(doc, decl);
return true;
}
static bool test_doctype_nwf(const char_t* decl)
{
xml_document doc;
// standalone
if (load_concat(doc, decl).status != status_bad_doctype) return false;
// pcdata postfix
if (load_concat(doc, decl, STR("b")).status != status_bad_doctype) return false;
// node postfix
if (load_concat(doc, decl, STR("<nodeb/>")).status != status_bad_doctype) return false;
return true;
}
#define TEST_DOCTYPE_WF(contents) CHECK(test_doctype_wf(STR(contents)))
#define TEST_DOCTYPE_NWF(contents) CHECK(test_doctype_nwf(STR(contents)))
TEST(parse_doctype_skip)
{
TEST_DOCTYPE_WF("<!DOCTYPE doc>");
TEST_DOCTYPE_WF("<!DOCTYPE doc SYSTEM 'foo'>");
TEST_DOCTYPE_WF("<!DOCTYPE doc SYSTEM \"foo\">");
TEST_DOCTYPE_WF("<!DOCTYPE doc PUBLIC \"foo\" 'bar'>");
TEST_DOCTYPE_WF("<!DOCTYPE doc PUBLIC \"foo'\">");
TEST_DOCTYPE_WF("<!DOCTYPE doc SYSTEM 'foo' [<!ELEMENT foo 'ANY'>]>");
}
TEST(parse_doctype_error)
{
TEST_DOCTYPE_NWF("<!DOCTYPE");
TEST_DOCTYPE_NWF("<!DOCTYPE doc");
TEST_DOCTYPE_NWF("<!DOCTYPE doc SYSTEM 'foo");
TEST_DOCTYPE_NWF("<!DOCTYPE doc SYSTEM \"foo");
TEST_DOCTYPE_NWF("<!DOCTYPE doc PUBLIC \"foo\" 'bar");
TEST_DOCTYPE_NWF("<!DOCTYPE doc PUBLIC \"foo'\"");
TEST_DOCTYPE_NWF("<!DOCTYPE doc SYSTEM 'foo' [<!ELEMENT foo 'ANY");
TEST_DOCTYPE_NWF("<!DOCTYPE doc SYSTEM 'foo' [<!ELEMENT foo 'ANY'>");
TEST_DOCTYPE_NWF("<!DOCTYPE doc SYSTEM 'foo' [<!ELEMENT foo 'ANY'>]");
TEST_DOCTYPE_NWF("<!DOCTYPE doc SYSTEM 'foo' [<!ELEMENT foo 'ANY'>] ");
}
// Examples from W3C recommendations
TEST(parse_doctype_w3c_wf)
{
TEST_DOCTYPE_WF("<!DOCTYPE greeting SYSTEM \"hello.dtd\">");
TEST_DOCTYPE_WF("<!DOCTYPE greeting [ <!ELEMENT greeting (#PCDATA)> ]>");
TEST_DOCTYPE_WF("<!DOCTYPE greeting [ <!ATTLIST list type (bullets|ordered|glossary) \"ordered\"> <!ATTLIST form method CDATA #FIXED \"POST\"> ]>");
TEST_DOCTYPE_WF("<!DOCTYPE greeting [ <!ENTITY % draft 'INCLUDE' > <!ENTITY % final 'IGNORE' > <![%draft;[ <!ELEMENT book (comments*, title, body, supplements?)> ]]> <![%final;[ <!ELEMENT book (title, body, supplements?)> ]]>]>");
TEST_DOCTYPE_WF("<!DOCTYPE greeting [ <!ENTITY open-hatch PUBLIC \"-//Textuality//TEXT Standard open-hatch boilerplate//EN\" \"http://www.textuality.com/boilerplate/OpenHatch.xml\"> ]>");
TEST_DOCTYPE_WF("<!DOCTYPE greeting [ <!ENTITY EndAttr \"27'\" > ]>");
}
TEST(parse_doctype_w3c_nwf)
{
TEST_DOCTYPE_NWF("<!DOCTYPE greeting SYSTEM \"hello.dtd>");
TEST_DOCTYPE_NWF("<!DOCTYPE greeting SYSTEM");
TEST_DOCTYPE_NWF("<!DOCTYPE greeting [ <!ELEMENT greeting (#PCDATA)> ]");
TEST_DOCTYPE_NWF("<!DOCTYPE greeting [ <!ELEMENT greeting (#PCDATA)>");
TEST_DOCTYPE_NWF("<!DOCTYPE greeting [ <!ELEMENT greeting (#PCDATA");
TEST_DOCTYPE_NWF("<!DOCTYPE greeting [ ");
TEST_DOCTYPE_NWF("<!DOCTYPE greeting [ <!ATTLIST list type (bullets|ordered|glossary) \"ordered\"> ]");
TEST_DOCTYPE_NWF("<!DOCTYPE greeting [ <!ATTLIST list type (bullets|ordered|glossary) \"ordered\">");
TEST_DOCTYPE_NWF("<!DOCTYPE greeting [ <!ATTLIST list type (bullets|ordered|glossary) \"orde");
TEST_DOCTYPE_NWF("<!DOCTYPE greeting [ <!ATTLIST list type (bullets|ordered|glossary) ");
TEST_DOCTYPE_NWF("<!DOCTYPE greeting [ <!ENTITY open-hatch PUBLIC \"-//Textuality//TEXT Standard open-hatch boilerplate//EN\" \"http://www.textuality.com/boilerplate/OpenHatch.x");
}
// Examples from xmlsuite
TEST(parse_doctype_xmlconf_eduni_1)
{
TEST_DOCTYPE_WF("<!DOCTYPE foo [ <!ELEMENT foo ANY> <!NOTATION gif SYSTEM \"file:///usr/X11R6/bin/xv\"> <!ENTITY declared SYSTEM \"xyzzy\" NDATA gif> <!ATTLIST foo bar ENTITY \"7\"> ]>");
TEST_DOCTYPE_WF("<!DOCTYPE foo [ <!ELEMENT foo ANY> <!NOTATION gif SYSTEM \"file:///usr/X11R6/bin/xv\"> <!ENTITY declared SYSTEM \"xyzzy\" NDATA gif> <!ATTLIST foo bar ENTITY \"undeclared\"> ]>");
TEST_DOCTYPE_WF("<!DOCTYPE foo [ <!ELEMENT foo ANY> <!ENTITY % e SYSTEM \"E60.ent\"> %e; ]>");
TEST_DOCTYPE_WF("<!DOCTYPE foo [ <!ELEMENT foo ANY> <!ENTITY e \"an &unparsed; entity\"> <!NOTATION gif SYSTEM \"file:///usr/X11R6/bin/xv\"> <!ENTITY unparsed SYSTEM \"xyzzy\" NDATA gif> ]>");
TEST_DOCTYPE_WF("<!DOCTYPE foo [ <!ELEMENT foo ANY> <!ATTLIST foo bar CDATA #IMPLIED> ]>");
TEST_DOCTYPE_WF("<!DOCTYPE foo [ <!ELEMENT foo ANY> ]>");
TEST_DOCTYPE_WF("<!DOCTYPE foo [ <!ELEMENT foo ANY> <!ATTLIST foo xml:lang CDATA #IMPLIED> ]>");
TEST_DOCTYPE_WF("<!DOCTYPE foo [ <!ELEMENT foo ANY> <!ENTITY e SYSTEM \"E38.ent\"> ]>");
TEST_DOCTYPE_WF("<!DOCTYPE foo SYSTEM \"E36.dtd\">");
TEST_DOCTYPE_WF("<!DOCTYPE foo [ <!ELEMENT foo ANY> <!ELEMENT bar (foo|foo)> ]>");
TEST_DOCTYPE_WF("<!DOCTYPE foo [ <!ELEMENT foo ANY> <!NOTATION one SYSTEM \"file:///usr/bin/awk\"> <!ATTLIST foo bar NOTATION (one|one) #IMPLIED> ]>");
TEST_DOCTYPE_WF("<!DOCTYPE foo [ <!ELEMENT foo ANY> <!ATTLIST foo bar (one|one) #IMPLIED> ]>");
TEST_DOCTYPE_WF("<!DOCTYPE foo [ <!ELEMENT foo ANY> <!ATTLIST foo xml:lang NMTOKEN #IMPLIED> ]>");
TEST_DOCTYPE_WF("<!DOCTYPE foo [ <!ELEMENT foo ANY> <!ENTITY gt \">\"> ]>");
TEST_DOCTYPE_WF("<!DOCTYPE foo [ <!ELEMENT foo ANY> ]>");
TEST_DOCTYPE_WF("<!DOCTYPE foo [ <!ELEMENT foo ANY> <!ATTLIST foo bar NMTOKENS #IMPLIED> ]>");
TEST_DOCTYPE_WF("<!DOCTYPE foo [ <!ELEMENT foo ANY> <!ENTITY % pe SYSTEM \"subdir1/E18-pe\"> %pe; %intpe; ]>");
TEST_DOCTYPE_WF("<!DOCTYPE foo [ <!ELEMENT foo (PCDATA|foo)*> ]>");
TEST_DOCTYPE_WF("<!DOCTYPE foo [ <!ELEMENT foo (foo*)> ]>");
TEST_DOCTYPE_WF("<!DOCTYPE foo [ <!ELEMENT foo (foo*)> <!ENTITY space \"&#38;#32;\"> ]>");
TEST_DOCTYPE_WF("<!DOCTYPE foo [ <!ELEMENT foo (foo*)> ]>");
TEST_DOCTYPE_WF("<!DOCTYPE foo [ <!ELEMENT foo (foo*)> <!ENTITY space \" \"> ]>");
TEST_DOCTYPE_WF("<!DOCTYPE foo [ <!ELEMENT foo EMPTY> ]>");
TEST_DOCTYPE_WF("<!DOCTYPE foo [ <!ELEMENT foo EMPTY> <!ENTITY empty \"\"> ]>");
TEST_DOCTYPE_WF("<!DOCTYPE foo [ <![INCLUDE[<!ATTLIST foo bar CDATA #IMPLIED>]]> <![IGNORE[some junk]]> ]>");
TEST_DOCTYPE_WF("<!DOCTYPE foo [ <!ELEMENT foo ANY> <!ENTITY % pe \"hello\"> <!-- If forward were expanded when ent was declared, we were get an error, but it is bypassed and not expanded until ent is used in the instance --> <!ENTITY ent \"%pe; &#33; &forward;\"> <!ENTITY forward \"goodbye\"> ]>");
TEST_DOCTYPE_NWF("<!DOCTYPE foo [ <!ELEMENT foo ANY> <!ENTITY % e \"bar CDATA #IMPLIED>\"> <!ATTLIST foo %e;");
TEST_DOCTYPE_NWF("<!DOCTYPE foo [ <!ELEMENT foo ANY> <!ENTITY % e \"bar CDATA #IMPLIED>\"> <!ATTLIST foo %e; ]>");
TEST_DOCTYPE_WF("<!DOCTYPE foo [ <!ENTITY ent SYSTEM 'E18-ent'> ]>");
}
TEST(parse_doctype_xmlconf_eduni_2)
{
TEST_DOCTYPE_WF("<!DOCTYPE foo [ <!ENTITY % pe \"<!ENTITY ent1 'text'>\"> %pe; <!ELEMENT foo ANY> ]>");
TEST_DOCTYPE_WF("<!DOCTYPE foo [ <!ENTITY ent SYSTEM \"ent\"> <!ELEMENT foo ANY> <!ATTLIST foo a CDATA \"contains &ent; reference\"> ]>");
TEST_DOCTYPE_WF("<!DOCTYPE foo [ <!ELEMENT foo ANY> <!ATTLIST foo id ID #IMPLIED> <!ATTLIST foo ref IDREF \"undef\"> <!ATTLIST foo ent ENTITY \"undef\"> <!-- can't test NOTATION attribute, because if it's undeclared then we'll get an error for one of the enumerated values being undeclared. --> <!ENTITY ent SYSTEM \"foo\" NDATA not> <!NOTATION not SYSTEM \"not\"> ]>");
TEST_DOCTYPE_WF("<!DOCTYPE foo [ <!ELEMENT foo EMPTY> <!ATTLIST foo a (one|two|three) \"four\"> ]>");
TEST_DOCTYPE_WF("<!DOCTYPE foo [ <!ELEMENT foo ANY> <!ATTLIST foo a NOTATION (not) \"not2\"> <!NOTATION not SYSTEM \"not\"> <!NOTATION not2 SYSTEM \"not2\"> ]>");
TEST_DOCTYPE_WF("<!DOCTYPE foo [ <!ELEMENT foo EMPTY> <!ATTLIST foo a NMTOKENS \"34+\"> ]>");
}
TEST(parse_doctype_xmlconf_eduni_3)
{
TEST_DOCTYPE_WF("<!DOCTYPE animal [ <!ELEMENT animal ANY> <?_\xd9\x9f an only legal per 5th edition extender #x65f in PITarget ?> ]>");
TEST_DOCTYPE_WF("<!DOCTYPE root [ <!ELEMENT root ANY> <!ELEMENT \xc2\xb7_BadName EMPTY> ]>");
TEST_DOCTYPE_WF("<!DOCTYPE doc [ <!ENTITY e \"<X&#xe5c;></X&#xe5c;>\"> ]>");
}
TEST(parse_doctype_xmlconf_eduni_4)
{
TEST_DOCTYPE_WF("<!DOCTYPE foo [ <!ELEMENT foo ANY> <!ENTITY a:b \"bogus\"> ]>");
TEST_DOCTYPE_WF("<!DOCTYPE foo [ <!ELEMENT foo ANY> <!ATTLIST foo xmlns:a CDATA #IMPLIED xmlns:b NMTOKEN #IMPLIED xmlns:c CDATA #IMPLIED> <!ELEMENT bar ANY> <!ATTLIST bar a:attr CDATA #IMPLIED b:attr CDATA #IMPLIED c:attr CDATA #IMPLIED> ]>");
TEST_DOCTYPE_WF("<!DOCTYPE foo [ <!ELEMENT foo ANY> <!ATTLIST foo xmlns:a CDATA #IMPLIED xmlns:b CDATA #IMPLIED xmlns:c CDATA #IMPLIED> <!ELEMENT bar ANY> <!ATTLIST bar a:attr CDATA #IMPLIED b:attr CDATA #IMPLIED c:attr CDATA #IMPLIED> <!ENTITY tilde \"~\"> ]>");
TEST_DOCTYPE_WF("<!DOCTYPE foo [ <!ELEMENT xmlns:foo EMPTY> ]>");
}
TEST(parse_doctype_xmlconf_eduni_5)
{
TEST_DOCTYPE_WF("<!DOCTYPE foo [ <!ELEMENT foo ANY> <!ENTITY e \"&#x0c;\"> ]>");
TEST_DOCTYPE_WF("<!DOCTYPE foo [ <!ELEMENT foo (foo*)> <!ENTITY e \"abc&#x85;def\"> ]>");
TEST_DOCTYPE_WF("<!DOCTYPE foo [ <!ELEMENT foo ANY> <!ATTLIST foo bar NMTOKENS #IMPLIED> <!ENTITY val \"abc&#x85;def\"> ]>");
}
TEST(parse_doctype_xmlconf_ibm_1)
{
TEST_DOCTYPE_WF("<!DOCTYPE animal SYSTEM \"ibm32i04.dtd\" [ <!ATTLIST animal xml:space (default|preserve) 'preserve'> ]>");
TEST_DOCTYPE_WF("<!DOCTYPE root [ <!ELEMENT root (a,b)> <!ELEMENT a EMPTY> <!ELEMENT b (#PCDATA|c)* > <!ELEMENT c ANY> ]>");
TEST_DOCTYPE_WF("<!DOCTYPE root [ <!ELEMENT root (PCDATA|b)* > <!ELEMENT b (#PCDATA) > <!ATTLIST b attr1 CDATA #REQUIRED> <!ATTLIST b attr2 (abc|def) \"abc\"> <!ATTLIST b attr3 CDATA #FIXED \"fixed\"> ]>");
TEST_DOCTYPE_WF("<!DOCTYPE test [ <!ELEMENT test ANY> <!ELEMENT landscape EMPTY> <!ENTITY parsedentity1 SYSTEM \"ibm56iv01.xml\"> <!ENTITY parsedentity2 SYSTEM \"ibm56iv02.xml\"> <!ATTLIST landscape sun ENTITIES #IMPLIED> ]>");
TEST_DOCTYPE_WF("<!DOCTYPE test [ <!ELEMENT test ANY> <!ELEMENT landscape EMPTY> <!ENTITY image1 SYSTEM \"d:\\testspec\\images\\sunset.gif\" NDATA gif> <!ENTITY image2 SYSTEM \"d:\\testspec\\images\\frontpag.gif\" NDATA gif> <!ATTLIST landscape sun ENTITIES #IMPLIED> ]>");
TEST_DOCTYPE_WF("<!DOCTYPE tokenizer [ <!ELEMENT tokenizer ANY> <!ATTLIST tokenizer UniqueName ID #FIXED \"AC1999\"> ]>");
TEST_DOCTYPE_WF("<!DOCTYPE test [ <!ELEMENT test ANY> <!ELEMENT blob (#PCDATA)> <!NOTATION base64 SYSTEM \"mimecode\"> <!NOTATION uuencode SYSTEM \"uudecode\"> <!ATTLIST blob content-encoding NOTATION (base64|uuencode|raw|ascii) #REQUIRED> ]>");
TEST_DOCTYPE_WF("<!DOCTYPE test [ <!ELEMENT test ANY> <!ELEMENT a EMPTY> <!ELEMENT nametoken EMPTY> <!ATTLIST nametoken namevalue NMTOKEN \"@#$\"> ]>");
TEST_DOCTYPE_WF("<!DOCTYPE root [ <!ELEMENT root (#PCDATA)* > <!ENTITY % pe1 SYSTEM \"ibm68i04.ent\"> %pe1; ]>");
TEST_DOCTYPE_WF("<!DOCTYPE root [ <!ELEMENT a EMPTY> <!ATTLIST a attr1 CDATA \"&ge1;\"> <!--* GE reference in attr default before declaration *--> <!ENTITY ge1 \"abcdef\"> ]>");
TEST_DOCTYPE_WF("<!DOCTYPE root [ <!ENTITY ge1 \"abcdef\"> <!ELEMENT a EMPTY> <!ATTLIST a attr1 CDATA \"&ge1;\"> <!ENTITY % pe2 \"<!ATTLIST a attr2 CDATA #IMPLIED>\"> %pe3; <!--* PE reference in above doesn't match declaration *--> ]>");
TEST_DOCTYPE_WF("<!DOCTYPE root [ <!ELEMENT root (#PCDATA)> <!ATTLIST root att CDATA #IMPLIED> <!ENTITY % pe1 '<!ATTLIST root att2 CDATA \"&ge1;\">'> <!ENTITY ge1 \"attdefaultvalue\" > %pe1; <!--* notation JPGformat not declared *--> <!ENTITY ge2 SYSTEM \"image.jpg\" NDATA JPGformat> ]>");
}
TEST(parse_doctype_xmlconf_ibm_2)
{
TEST_DOCTYPE_WF("<!DOCTYPE student [ <!ELEMENT student (#PCDATA)> <!ENTITY gewithElemnetDecl \"<!ELEMENT bogus ANY>\"> <!ATTLIST student att1 CDATA #REQUIRED> ]>");
TEST_DOCTYPE_WF("<!DOCTYPE student [ <!ELEMENT student (#PCDATA)> <!ENTITY gewithlt \"abcd&#x26;&#x23;x3c;\"> <!ATTLIST student att1 CDATA #REQUIRED> ]>");
TEST_DOCTYPE_WF("<!DOCTYPE student [ <!ELEMENT student (#PCDATA)> <!ENTITY gewithlt \"abcd&#x3c;\"> <!ATTLIST student att1 CDATA #REQUIRED> ]>");
TEST_DOCTYPE_WF("<!DOCTYPE 5A_name_starts_with_digit [ <!ELEMENT 5A_name_starts_with_digit EMPTY> ]>");
TEST_DOCTYPE_WF("<!DOCTYPE student [ <!ELEMENT student (#PCDATA)> <!ENTITY FullName \"Snow&Man\"> ]>");
TEST_DOCTYPE_NWF("<!DOCTYPE student [ <!ELEMENT student (#PCDATA)> <!ENTITY FullName \"Snow\"Man\"> ]>");
TEST_DOCTYPE_WF("<!DOCTYPE student [ <!ELEMENT student (#PCDATA)> <!ATTLIST student first CDATA #REQUIRED middle CDATA #IMPLIED last CDATA #IMPLIED > <!ENTITY myfirst \"Snow\"> <!ENTITY mymiddle \"I\"> <!ENTITY mylast \"Man\"> ]>");
TEST_DOCTYPE_NWF("<!DOCTYPE student SYSTEM 'student.DTD [ <!ELEMENT student (#PCDATA)> ]>");
TEST_DOCTYPE_NWF("<!DOCTYPE student [ <!ELEMENT student (#PCDATA)> <!ENTITY info PUBLIC '..\\info.dtd> ]>");
TEST_DOCTYPE_NWF("<!DOCTYPE student [ <!ELEMENT student (#PCDATA)> <!ENTITY info PUBLIC '..\\info'.dtd'> ]>");
TEST_DOCTYPE_NWF("<!DOCTYPE student [ <!ELEMENT student (#PCDATA)> <!ENTITY info PUBLIC \"..\\info.dtd> ]>");
TEST_DOCTYPE_WF("<!DOCTYPE student [ <!ENTITY info PUBLIC \"This is a {test} \" \"student.dtd\"> ]>");
TEST_DOCTYPE_WF("<!DOCTYPE aniaml [ <!ELEMENT animal ANY> <!ENTITY generalE \"leopard\"> &generalE; <!ENTITY % parameterE \"<!ELEMENT leopard EMPTY>\"> %parameterE; ] animal>");
TEST_DOCTYPE_WF("<!DOCTYPE animal SYSTEM \"ibm28an01.dtd\" [ <!ELEMENT animal (cat|tiger|leopard)+> <!NOTATION animal_class SYSTEM \"ibm29v01.txt\"> <!ELEMENT cat ANY> <!ENTITY forcat \"This is a small cat\"> <!ELEMENT tiger (#PCDATA)> <!ELEMENT small EMPTY> <!ELEMENT big EMPTY> <!ATTLIST tiger color CDATA #REQUIRED> <?sound \"This is a PI\" ?> <!-- This is a comment --> ]>");
TEST_DOCTYPE_WF("<!DOCTYPE animal [ <!ELEMENT animal ANY> <!ENTITY % parameterE \"cat SYSTEM\"> <!NOTATION %parameterE; \"cat.txt\"> ]>");
TEST_DOCTYPE_NWF("<!DOCTYPE animal [ <!ELEMENT animal ANY> <!ENTITY % parameterE \"A music file -->\"> <!-- Parameter reference appears inside a comment in DTD --> <!-- This is %parameterE; ]>");
TEST_DOCTYPE_NWF("<!DOCTYPE animal [ <!ELEMENT animal ANY> <!ENTITY % parameterE \"A music file ?>\"> <?music %parameterE; ]>");
TEST_DOCTYPE_NWF("<!DOCTYPE animal [ <!ELEMENT animal ANY> <!ENTITY % parameterE \"leopard EMPTY>\"> <!ELEMENT %parameterE; ]>");
TEST_DOCTYPE_WF("<!DOCTYPE root [ <!ELEMENT root ANY> <!ATTLIST root attr1 CDATA #IMPLIED> <!ATTLIST root attr2 CDATA #IMPLIED> <!ENTITY withlt \"have <lessthan> inside\"> <!ENTITY aIndirect \"&withlt;\"> ]>");
TEST_DOCTYPE_WF("<!DOCTYPE root [ <!ELEMENT root (#PCDATA)> <!--* Missing Name S contentspec in elementdecl *--> <!ELEMENT > ]>");
TEST_DOCTYPE_WF("<!DOCTYPE root [ <!ELEMENT root (#PCDATA)> <!ELEMENT a ANY> <!ELEMENT b ANY> <!--* extra separator in seq *--> <!ELEMENT aElement ((a|b),,a)? > ]>");
TEST_DOCTYPE_WF("<!DOCTYPE root [ <!ELEMENT root (#PCDATA)> <!ELEMENT a ANY> <!--* Missing white space before Name in AttDef *--> <!ATTLIST a attr1 CDATA \"default\"attr2 ID #required> ]>");
TEST_DOCTYPE_WF("<!DOCTYPE test [ <!ELEMENT test ANY> <!ELEMENT one EMPTY> <!ELEMENT two EMPTY> <!NOTATION this SYSTEM \"alpha\"> <!ATTLIST three attr NOTATION (\"this\") #IMPLIED> ]>");
TEST_DOCTYPE_WF("<!DOCTYPE root [ <!-- DTD for Production 62--> <![ include [ <!ELEMENT tiger EMPTY> <!ELEMENT animal ANY> ]]> <!--Negative test with pattern1 of P62--> <!--include(Case sensitive)--> ]>");
TEST_DOCTYPE_WF("<!DOCTYPE root [ <![[INCLUDE[ <!ELEMENT tiger EMPTY> <!ELEMENT animal ANY> ]]> ]>");
TEST_DOCTYPE_NWF("<!DOCTYPE root [ <?[INCLUDE[ <!ELEMENT tiger EMPTY> <!ELEMENT animal ANY> ]]> ]>");
TEST_DOCTYPE_WF("<!DOCTYPE root [ <![[ <!ELEMENT tiger EMPTY> <!ELEMENT animal ANY> ]]> ]>");
TEST_DOCTYPE_WF("<!DOCTYPE root [ <![INCLUDE <!ELEMENT tiger EMPTY> <!ELEMENT animal ANY> ]]> ]>");
TEST_DOCTYPE_WF("<!DOCTYPE root [ <![ <!ELEMENT tiger EMPTY> <!ELEMENT animal ANY> [INCLUDE ]]> ]>");
TEST_DOCTYPE_NWF("<!DOCTYPE root [ <![ INCLUDE [ <!ELEMENT tiger EMPTY> <!ELEMENT animal ANY> ]>");
TEST_DOCTYPE_NWF("<!DOCTYPE root [ <![INCLUDE[ ]> ]>");
TEST_DOCTYPE_WF("<!DOCTYPE root [ <!ELEMENT root (#PCDATA)> <!--* PE referenced before declared, against WFC: entity declared --> %paaa; <!ENTITY % paaa \"<!ATTLIST root att CDATA #IMPLIED>\"> <!ENTITY aaa \"aString\"> ]>");
TEST_DOCTYPE_WF("<!DOCTYPE root [ <!ELEMENT root (#PCDATA)> <!ATTLIST root att CDATA #IMPLIED> <!--* missing space *--> <!ENTITY% paaa \"<!-- comments -->\"> %paaa; ]>");
TEST_DOCTYPE_NWF("<!DOCTYPE root [ <!ELEMENT root (#PCDATA)> <!ATTLIST root att CDATA #IMPLIED> <!--* missing closing bracket *--> <!ENTITY % paaa \"<!-- comments -->\" %paaa; ]>");
TEST_DOCTYPE_WF("<!DOCTYPE root PUBLIC \"-//W3C//DTD//EN\"\"empty.dtd\" [ <!ELEMENT root (#PCDATA)> <!ATTLIST root att CDATA #IMPLIED> ]>");
}
TEST(parse_doctype_xmlconf_ibm_3)
{
TEST_DOCTYPE_WF("<!DOCTYPE animal [ <!ELEMENT animal (cat|tiger|leopard)+> <!ELEMENT cat EMPTY> <!ELEMENT tiger (#PCDATA)> <!ELEMENT leopard ANY> <!ELEMENT small EMPTY> <!ELEMENT big EMPTY> <!ATTLIST tiger color CDATA #REQUIRED> ]>");
TEST_DOCTYPE_WF("<!DOCTYPE book [ <!ELEMENT book ANY> <!-- This test case covers legal character ranges plus discrete legal characters for production 02. --> <?NAME target ?> ]>");
TEST_DOCTYPE_WF("<!DOCTYPE student [ <!ELEMENT student (#PCDATA)> <!ATTLIST student first CDATA #REQUIRED middle CDATA #IMPLIED last CDATA #REQUIRED > <!ENTITY myfirst \"Snow\"> <!ENTITY mymiddle \"I\"> <!ENTITY mylast 'Man &myfirst; and &myfirst; mymiddle;.'> ]>");
TEST_DOCTYPE_WF("<!DOCTYPE student SYSTEM 'student.dtd'[ ]>");
TEST_DOCTYPE_WF("<!DOCTYPE student [ <!ELEMENT student (#PCDATA)> <!ENTITY unref SYSTEM \"\"> ]>");
TEST_DOCTYPE_WF("<!DOCTYPE student PUBLIC \"\" \"student.dtd\"[ ]>");
TEST_DOCTYPE_WF("<!DOCTYPE student PUBLIC '' 'student.dtd'[ ]>");
TEST_DOCTYPE_WF("<!DOCTYPE student PUBLIC \"The big ' in it\" \"student.dtd\"[ ]>");
TEST_DOCTYPE_WF("<!DOCTYPE student PUBLIC 'The latest version' 'student.dtd'[ ]>");
TEST_DOCTYPE_WF("<!DOCTYPE student PUBLIC \"#x20 #xD #xA abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ -'()+,./:=?;!*#@$_% \" \"student.dtd\"[ ]>");
TEST_DOCTYPE_WF("<!DOCTYPE student [ <!ELEMENT student (#PCDATA)> <!----> ]>");
TEST_DOCTYPE_NWF("<!DOCTYPE student [ <!ELEMENT student (#PCDATA)> <!---> ]>");
TEST_DOCTYPE_WF("<!DOCTYPE student [ <!ELEMENT student (#PCDATA)> <?pi?> ]>");
TEST_DOCTYPE_NWF("<!DOCTYPE student [ <!ELEMENT student (#PCDATA)> <?> ]>");
TEST_DOCTYPE_WF("<!DOCTYPE student [ <!ELEMENT student (#PCDATA)> <?MyInstruct AVOID ? BEFORE > IN PI ?> ]>");
TEST_DOCTYPE_WF("<!DOCTYPE animal SYSTEM \"ibm28v02.dtd\" [ <!NOTATION animal_class SYSTEM \"ibm28v02.txt\"> <!ENTITY forcat \"This is a small cat\"> <!ELEMENT tiger (#PCDATA)> <!ENTITY % make_small \"<!ELEMENT small EMPTY>\"> <!ENTITY % make_leopard_element \"<!ELEMENT leopard ANY>\"> <!ENTITY % make_attlist \"<!ATTLIST tiger color CDATA #REQUIRED>\"> %make_leopard_element; <!ELEMENT cat ANY> %make_small; <!ENTITY % make_big \"<!ELEMENT big EMPTY>\"> %make_big; %make_attlist; <?sound \"This is a PI\" ?> <!-- This is a valid test file for p28 --> ]>");
TEST_DOCTYPE_WF("<!DOCTYPE animal [ <![INCLUDE[ <!ENTITY % rootElement \"<!ELEMENT animal ANY>\"> ]]> %rootElement; <!-- Following is a makupdecl --> <!ENTITY % make_tiger_element \"<!ELEMENT tiger EMPTY>\"> %make_tiger_element; <![IGNORE[ <!ELEMENT animal EMPTY> ]]> ]>");
TEST_DOCTYPE_WF("<!DOCTYPE root [ <!ELEMENT root (a,b)> <!ELEMENT a EMPTY> <!ELEMENT b (#PCDATA|c)* > <!ELEMENT c ANY> <!ENTITY inContent \"<b>General entity reference in element content</b>\"> ]>");
TEST_DOCTYPE_WF("<!DOCTYPE root [ <!ELEMENT a EMPTY> <!ELEMENT b (#PCDATA|c)* > <!ELEMENT c ANY> <!--* PE replace Text have both parentheses *--> <!ENTITY % seq1 \"(a,b,c)\"> <!ELEMENT child1 %seq1; > <!--* Another legal PE replace Text *--> <!ENTITY % seq2 \"a,b\"> <!ELEMENT child2 (%seq2;,c) > ]>");
TEST_DOCTYPE_WF("<!DOCTYPE root [ <![IGNORE[ Everything is ignored within an ignored section, except the sub-section delimiters '<![' and ']]>'. These must be balanced <!ok ]]> ]>");
TEST_DOCTYPE_WF("<!DOCTYPE root [ <![IGNORE[ Everything is ignored within an ignored section, except the sub-section delimiters '<![' and ']]>'. These must be balanced <![ <!ELEMENT animal EMPTY> ]]> ]]> ]>");
TEST_DOCTYPE_WF("<!DOCTYPE root [ <![IGNORE[ begin Everything is ignored within an ignored section, except the sub-section delimiters '<![' and ']]>'. These must be balanced <![ <!ELEMENT animal EMPTY> ]]> nesting <![ <!ELEMENT tiger (#PCDATA)> ]]> nesting again <![ <!ELEMENT abc ANY> ]]> end ]]> ]>");
TEST_DOCTYPE_WF("<!DOCTYPE root [ <!DOCTYPE root SYSTEM \"ibm69v01.dtd\" [ <!ELEMENT root (#PCDATA|a)* > <!ENTITY % pe1 \"<!-- comment in PE -->\"> %pe1; ]> ]>");
}
TEST(parse_doctype_xmlconf_oasis_1)
{
TEST_DOCTYPE_WF("<!DOCTYPE root [ <!ELEMENT doc EMPTY> <!ENTITY % ent1 \"\"> <!ENTITY ent2 \"text2\"> <!ENTITY % ent3 \"<!-- <!DOCTYPE <!ELEMENT <? '''&#34;&ent2; %ent1;\"> <!ENTITY % ent4 '\"\"&#x27;&#39;\"'> ]>");
TEST_DOCTYPE_WF("<!DOCTYPE root [ <![INCLUDE[ <!ENTITY % rootel \"<!ELEMENT doc EMPTY>\"> ]]> %rootel; <!ATTLIST doc att CDATA #IMPLIED> <![IGNORE[ <!ELEMENT doc (a)> ]]> ]>");
TEST_DOCTYPE_WF("<!DOCTYPE root [ <![INCLUDE[<![INCLUDE[ <![IGNORE[ ignored ]]> <!ELEMENT doc EMPTY> ]]>]]> <![IGNORE[ ignored ]]> <![IGNORE[ <!ELEMENT doc ignored ]]> ]>");
TEST_DOCTYPE_WF("<!DOCTYPE root [ <![INCLUDE[ <![ INCLUDE [ <!ELEMENT doc EMPTY> <![IGNORE[asdfasdf]]> ]]>]]> <![INCLUDE[]]> <![INCLUDE[ ]]> <![INCLUDE[ ]]> ]>");
TEST_DOCTYPE_NWF("<!DOCTYPE root [ <!ELEMENT doc EMPTY> <![IGNORE[<![]]> ]>");
TEST_DOCTYPE_WF("<!DOCTYPE root [ <!ELEMENT doc EMPTY> <![IGNORE[ <![INCLUDE[ <!ELEMENT doc ]]>]]> <![ IGNORE [ ]]> <![IGNORE[]]> <![IGNORE[ ]]> <![IGNORE[ ]]> ]>");
TEST_DOCTYPE_NWF("<!DOCTYPE root [ <!ELEMENT doc EMPTY> <![IGNORE[ <![ starts must balance ]]> ]>");
TEST_DOCTYPE_WF("<!DOCTYPE root [ <!ELEMENT doc EMPTY> <![IGNORE[ Everything is ignored within an ignored section, except the sub-section delimiters '<![' and ']]>'. These must be balanced, but it is no section keyword is required: <![]]> <![DUNNO[ ]]> <![INCLUDE[ asdfasdfasdf <!OK ]]> ] ]> ]] > ]]> <![IGNORE[ < ![ <! [ <![]]>]]> ]>");
TEST_DOCTYPE_WF("<!DOCTYPE doc [ <!ELEMENT doc EMPTY> <!NOTATION not1 SYSTEM \"a%a&b&#0<!ELEMENT<!--<?</>?>/\''\"> <!NOTATION not2 SYSTEM 'a b\"\"\"'> <!NOTATION not3 SYSTEM \"\"> <!NOTATION not4 SYSTEM ''> ]>");
TEST_DOCTYPE_WF("<!DOCTYPE doc [ <!ELEMENT doc EMPTY> <!NOTATION not1 PUBLIC \"<\"> ]>");
TEST_DOCTYPE_WF("<!DOCTYPE doc [ <!ELEMENT doc EMPTY> <!NOTATION not1 PUBLIC \"a b cdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ\"> <!NOTATION not2 PUBLIC '0123456789-()+,./:=?;!*#@$_%'> <!NOTATION not3 PUBLIC \"0123456789-()+,.'/:=?;!*#@$_%\"> ]>");
TEST_DOCTYPE_WF("<!DOCTYPE doc SYSTEM \"p31pass1.dtd\" [<!ELEMENT doc EMPTY>]>");
// not actually a doctype :)
xml_document doc;
CHECK(doc.load_string(STR("<!--a <!DOCTYPE <?- ]]>-<[ CDATA [ \"- -'- -<doc>--> <!---->"), parse_full | parse_fragment) && doc.first_child().type() == node_comment && doc.last_child().type() == node_comment && doc.first_child().next_sibling() == doc.last_child());
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());
}
TEST(parse_doctype_xmlconf_xmltest_1)
{
TEST_DOCTYPE_NWF("<!DOCTYPE root [ <![ INCLUDE [ <!ELEMENT doc (#PCDATA)> ]> ]>");
TEST_DOCTYPE_NWF("<!DOCTYPE root [ <!ELEMENT doc (#PCDATA)> <![ IGNORE [");
TEST_DOCTYPE_NWF("<!DOCTYPE root [ <!ELEMENT doc (#PCDATA)> <![ IGNORE [ ]>");
TEST_DOCTYPE_NWF("<!DOCTYPE root [ <!ELEMENT doc (#PCDATA)> <![ INCLUDE [");
TEST_DOCTYPE_NWF("<!DOCTYPE root [ <!ELEMENT doc (#PCDATA)> <![ INCLUDE [ ]>");
TEST_DOCTYPE_WF("<!DOCTYPE root [ <!ELEMENT doc EMPTY> <!ENTITY % e \"<!--\"> %e; -->");
TEST_DOCTYPE_WF("<!DOCTYPE doc [ <!NOTATION foo PUBLIC \"[\" \"null.ent\"> ]>");
TEST_DOCTYPE_WF("<!DOCTYPE doc [ <!ELEMENT doc (#PCDATA)> <!ATTLIST doc a CDATA #IMPLIED> <!ENTITY e '\"'> ]>");
TEST_DOCTYPE_WF("<!DOCTYPE doc [ <!ENTITY e \"<foo a='&#38;'></foo>\"> ]>");
TEST_DOCTYPE_WF("<!DOCTYPE doc [ <!ELEMENT doc (#PCDATA)> <!ENTITY e \"<![CDATA[Tim & Michael]]>\"> ]>");
}
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();
CHECK(n.type() == node_doctype);
CHECK_STRING(n.value(), STR("doc [ <!ELEMENT doc (#PCDATA)> <!ENTITY e \"<![CDATA[Tim & Michael]]>\"> ]"));
}
TEST(parse_doctype_error_toplevel)
{
xml_document doc;
CHECK(doc.load_string(STR("<node><!DOCTYPE></node>")).status == status_bad_doctype);
CHECK(doc.load_string(STR("<node><!DOCTYPE></node>"), parse_doctype).status == status_bad_doctype);
}
TEST(parse_doctype_error_ignore)
{
xml_document doc;
CHECK(doc.load_string(STR("<!DOCTYPE root [ <![IGNORE[ ")).status == status_bad_doctype);
CHECK(doc.load_string(STR("<!DOCTYPE root [ <![IGNORE[ "), parse_doctype).status == status_bad_doctype);
CHECK(doc.load_string(STR("<!DOCTYPE root [ <![IGNORE[ <![INCLUDE[")).status == status_bad_doctype);
CHECK(doc.load_string(STR("<!DOCTYPE root [ <![IGNORE[ <![INCLUDE["), parse_doctype).status == status_bad_doctype);
}
TEST(parse_doctype_stackless_group)
{
std::basic_string<char_t> str;
int count = 100000;
str += STR("<!DOCTYPE ");
for (int i = 0; i < count; ++i)
str += STR("<!G ");
for (int j = 0; j < count; ++j)
str += STR(">");
str += STR(">");
xml_document doc;
CHECK(doc.load_string(str.c_str(), parse_fragment));
}
TEST(parse_doctype_stackless_ignore)
{
std::basic_string<char_t> str;
int count = 100000;
str += STR("<!DOCTYPE ");
for (int i = 0; i < count; ++i)
str += STR("<![IGNORE[ ");
for (int j = 0; j < count; ++j)
str += STR("]]>");
str += STR(">");
xml_document doc;
CHECK(doc.load_string(str.c_str(), parse_fragment));
}
#define _CRT_SECURE_NO_WARNINGS
#include "test.hpp"
#include <string.h>
#include <wchar.h>
#include <string>
using namespace pugi;
static xml_parse_result load_concat(xml_document& doc, const char_t* a, const char_t* b = STR(""), const char_t* c = STR(""))
{
char_t buffer[768];
#ifdef PUGIXML_WCHAR_MODE
wcscpy(buffer, a);
wcscat(buffer, b);
wcscat(buffer, c);
#else
strcpy(buffer, a);
strcat(buffer, b);
strcat(buffer, c);
#endif
return doc.load_string(buffer, parse_fragment);
}
static bool test_doctype_wf(const char_t* decl)
{
xml_document doc;
// standalone
if (!load_concat(doc, decl) || !doc.first_child().empty()) return false;
// pcdata pre/postfix
if (!load_concat(doc, STR("a"), decl) || !test_node(doc, STR("a"), STR(""), format_raw)) return false;
if (!load_concat(doc, decl, STR("b")) || !test_node(doc, STR("b"), STR(""), format_raw)) return false;
if (!load_concat(doc, STR("a"), decl, STR("b")) || !test_node(doc, STR("ab"), STR(""), format_raw)) return false;
// node pre/postfix
if (!load_concat(doc, STR("<nodea/>"), decl) || !test_node(doc, STR("<nodea/>"), STR(""), format_raw)) return false;
if (!load_concat(doc, decl, STR("<nodeb/>")) || !test_node(doc, STR("<nodeb/>"), STR(""), format_raw)) return false;
if (!load_concat(doc, STR("<nodea/>"), decl, STR("<nodeb/>")) || !test_node(doc, STR("<nodea/><nodeb/>"), STR(""), format_raw)) return false;
// check load-store contents preservation
CHECK(doc.load_string(decl, parse_doctype | parse_fragment));
CHECK_NODE(doc, decl);
return true;
}
static bool test_doctype_nwf(const char_t* decl)
{
xml_document doc;
// standalone
if (load_concat(doc, decl).status != status_bad_doctype) return false;
// pcdata postfix
if (load_concat(doc, decl, STR("b")).status != status_bad_doctype) return false;
// node postfix
if (load_concat(doc, decl, STR("<nodeb/>")).status != status_bad_doctype) return false;
return true;
}
#define TEST_DOCTYPE_WF(contents) CHECK(test_doctype_wf(STR(contents)))
#define TEST_DOCTYPE_NWF(contents) CHECK(test_doctype_nwf(STR(contents)))
TEST(parse_doctype_skip)
{
TEST_DOCTYPE_WF("<!DOCTYPE doc>");
TEST_DOCTYPE_WF("<!DOCTYPE doc SYSTEM 'foo'>");
TEST_DOCTYPE_WF("<!DOCTYPE doc SYSTEM \"foo\">");
TEST_DOCTYPE_WF("<!DOCTYPE doc PUBLIC \"foo\" 'bar'>");
TEST_DOCTYPE_WF("<!DOCTYPE doc PUBLIC \"foo'\">");
TEST_DOCTYPE_WF("<!DOCTYPE doc SYSTEM 'foo' [<!ELEMENT foo 'ANY'>]>");
}
TEST(parse_doctype_error)
{
TEST_DOCTYPE_NWF("<!DOCTYPE");
TEST_DOCTYPE_NWF("<!DOCTYPE doc");
TEST_DOCTYPE_NWF("<!DOCTYPE doc SYSTEM 'foo");
TEST_DOCTYPE_NWF("<!DOCTYPE doc SYSTEM \"foo");
TEST_DOCTYPE_NWF("<!DOCTYPE doc PUBLIC \"foo\" 'bar");
TEST_DOCTYPE_NWF("<!DOCTYPE doc PUBLIC \"foo'\"");
TEST_DOCTYPE_NWF("<!DOCTYPE doc SYSTEM 'foo' [<!ELEMENT foo 'ANY");
TEST_DOCTYPE_NWF("<!DOCTYPE doc SYSTEM 'foo' [<!ELEMENT foo 'ANY'>");
TEST_DOCTYPE_NWF("<!DOCTYPE doc SYSTEM 'foo' [<!ELEMENT foo 'ANY'>]");
TEST_DOCTYPE_NWF("<!DOCTYPE doc SYSTEM 'foo' [<!ELEMENT foo 'ANY'>] ");
}
// Examples from W3C recommendations
TEST(parse_doctype_w3c_wf)
{
TEST_DOCTYPE_WF("<!DOCTYPE greeting SYSTEM \"hello.dtd\">");
TEST_DOCTYPE_WF("<!DOCTYPE greeting [ <!ELEMENT greeting (#PCDATA)> ]>");
TEST_DOCTYPE_WF("<!DOCTYPE greeting [ <!ATTLIST list type (bullets|ordered|glossary) \"ordered\"> <!ATTLIST form method CDATA #FIXED \"POST\"> ]>");
TEST_DOCTYPE_WF("<!DOCTYPE greeting [ <!ENTITY % draft 'INCLUDE' > <!ENTITY % final 'IGNORE' > <![%draft;[ <!ELEMENT book (comments*, title, body, supplements?)> ]]> <![%final;[ <!ELEMENT book (title, body, supplements?)> ]]>]>");
TEST_DOCTYPE_WF("<!DOCTYPE greeting [ <!ENTITY open-hatch PUBLIC \"-//Textuality//TEXT Standard open-hatch boilerplate//EN\" \"http://www.textuality.com/boilerplate/OpenHatch.xml\"> ]>");
TEST_DOCTYPE_WF("<!DOCTYPE greeting [ <!ENTITY EndAttr \"27'\" > ]>");
}
TEST(parse_doctype_w3c_nwf)
{
TEST_DOCTYPE_NWF("<!DOCTYPE greeting SYSTEM \"hello.dtd>");
TEST_DOCTYPE_NWF("<!DOCTYPE greeting SYSTEM");
TEST_DOCTYPE_NWF("<!DOCTYPE greeting [ <!ELEMENT greeting (#PCDATA)> ]");
TEST_DOCTYPE_NWF("<!DOCTYPE greeting [ <!ELEMENT greeting (#PCDATA)>");
TEST_DOCTYPE_NWF("<!DOCTYPE greeting [ <!ELEMENT greeting (#PCDATA");
TEST_DOCTYPE_NWF("<!DOCTYPE greeting [ ");
TEST_DOCTYPE_NWF("<!DOCTYPE greeting [ <!ATTLIST list type (bullets|ordered|glossary) \"ordered\"> ]");
TEST_DOCTYPE_NWF("<!DOCTYPE greeting [ <!ATTLIST list type (bullets|ordered|glossary) \"ordered\">");
TEST_DOCTYPE_NWF("<!DOCTYPE greeting [ <!ATTLIST list type (bullets|ordered|glossary) \"orde");
TEST_DOCTYPE_NWF("<!DOCTYPE greeting [ <!ATTLIST list type (bullets|ordered|glossary) ");
TEST_DOCTYPE_NWF("<!DOCTYPE greeting [ <!ENTITY open-hatch PUBLIC \"-//Textuality//TEXT Standard open-hatch boilerplate//EN\" \"http://www.textuality.com/boilerplate/OpenHatch.x");
}
// Examples from xmlsuite
TEST(parse_doctype_xmlconf_eduni_1)
{
TEST_DOCTYPE_WF("<!DOCTYPE foo [ <!ELEMENT foo ANY> <!NOTATION gif SYSTEM \"file:///usr/X11R6/bin/xv\"> <!ENTITY declared SYSTEM \"xyzzy\" NDATA gif> <!ATTLIST foo bar ENTITY \"7\"> ]>");
TEST_DOCTYPE_WF("<!DOCTYPE foo [ <!ELEMENT foo ANY> <!NOTATION gif SYSTEM \"file:///usr/X11R6/bin/xv\"> <!ENTITY declared SYSTEM \"xyzzy\" NDATA gif> <!ATTLIST foo bar ENTITY \"undeclared\"> ]>");
TEST_DOCTYPE_WF("<!DOCTYPE foo [ <!ELEMENT foo ANY> <!ENTITY % e SYSTEM \"E60.ent\"> %e; ]>");
TEST_DOCTYPE_WF("<!DOCTYPE foo [ <!ELEMENT foo ANY> <!ENTITY e \"an &unparsed; entity\"> <!NOTATION gif SYSTEM \"file:///usr/X11R6/bin/xv\"> <!ENTITY unparsed SYSTEM \"xyzzy\" NDATA gif> ]>");
TEST_DOCTYPE_WF("<!DOCTYPE foo [ <!ELEMENT foo ANY> <!ATTLIST foo bar CDATA #IMPLIED> ]>");
TEST_DOCTYPE_WF("<!DOCTYPE foo [ <!ELEMENT foo ANY> ]>");
TEST_DOCTYPE_WF("<!DOCTYPE foo [ <!ELEMENT foo ANY> <!ATTLIST foo xml:lang CDATA #IMPLIED> ]>");
TEST_DOCTYPE_WF("<!DOCTYPE foo [ <!ELEMENT foo ANY> <!ENTITY e SYSTEM \"E38.ent\"> ]>");
TEST_DOCTYPE_WF("<!DOCTYPE foo SYSTEM \"E36.dtd\">");
TEST_DOCTYPE_WF("<!DOCTYPE foo [ <!ELEMENT foo ANY> <!ELEMENT bar (foo|foo)> ]>");
TEST_DOCTYPE_WF("<!DOCTYPE foo [ <!ELEMENT foo ANY> <!NOTATION one SYSTEM \"file:///usr/bin/awk\"> <!ATTLIST foo bar NOTATION (one|one) #IMPLIED> ]>");
TEST_DOCTYPE_WF("<!DOCTYPE foo [ <!ELEMENT foo ANY> <!ATTLIST foo bar (one|one) #IMPLIED> ]>");
TEST_DOCTYPE_WF("<!DOCTYPE foo [ <!ELEMENT foo ANY> <!ATTLIST foo xml:lang NMTOKEN #IMPLIED> ]>");
TEST_DOCTYPE_WF("<!DOCTYPE foo [ <!ELEMENT foo ANY> <!ENTITY gt \">\"> ]>");
TEST_DOCTYPE_WF("<!DOCTYPE foo [ <!ELEMENT foo ANY> ]>");
TEST_DOCTYPE_WF("<!DOCTYPE foo [ <!ELEMENT foo ANY> <!ATTLIST foo bar NMTOKENS #IMPLIED> ]>");
TEST_DOCTYPE_WF("<!DOCTYPE foo [ <!ELEMENT foo ANY> <!ENTITY % pe SYSTEM \"subdir1/E18-pe\"> %pe; %intpe; ]>");
TEST_DOCTYPE_WF("<!DOCTYPE foo [ <!ELEMENT foo (PCDATA|foo)*> ]>");
TEST_DOCTYPE_WF("<!DOCTYPE foo [ <!ELEMENT foo (foo*)> ]>");
TEST_DOCTYPE_WF("<!DOCTYPE foo [ <!ELEMENT foo (foo*)> <!ENTITY space \"&#38;#32;\"> ]>");
TEST_DOCTYPE_WF("<!DOCTYPE foo [ <!ELEMENT foo (foo*)> ]>");
TEST_DOCTYPE_WF("<!DOCTYPE foo [ <!ELEMENT foo (foo*)> <!ENTITY space \" \"> ]>");
TEST_DOCTYPE_WF("<!DOCTYPE foo [ <!ELEMENT foo EMPTY> ]>");
TEST_DOCTYPE_WF("<!DOCTYPE foo [ <!ELEMENT foo EMPTY> <!ENTITY empty \"\"> ]>");
TEST_DOCTYPE_WF("<!DOCTYPE foo [ <![INCLUDE[<!ATTLIST foo bar CDATA #IMPLIED>]]> <![IGNORE[some junk]]> ]>");
TEST_DOCTYPE_WF("<!DOCTYPE foo [ <!ELEMENT foo ANY> <!ENTITY % pe \"hello\"> <!-- If forward were expanded when ent was declared, we were get an error, but it is bypassed and not expanded until ent is used in the instance --> <!ENTITY ent \"%pe; &#33; &forward;\"> <!ENTITY forward \"goodbye\"> ]>");
TEST_DOCTYPE_NWF("<!DOCTYPE foo [ <!ELEMENT foo ANY> <!ENTITY % e \"bar CDATA #IMPLIED>\"> <!ATTLIST foo %e;");
TEST_DOCTYPE_NWF("<!DOCTYPE foo [ <!ELEMENT foo ANY> <!ENTITY % e \"bar CDATA #IMPLIED>\"> <!ATTLIST foo %e; ]>");
TEST_DOCTYPE_WF("<!DOCTYPE foo [ <!ENTITY ent SYSTEM 'E18-ent'> ]>");
}
TEST(parse_doctype_xmlconf_eduni_2)
{
TEST_DOCTYPE_WF("<!DOCTYPE foo [ <!ENTITY % pe \"<!ENTITY ent1 'text'>\"> %pe; <!ELEMENT foo ANY> ]>");
TEST_DOCTYPE_WF("<!DOCTYPE foo [ <!ENTITY ent SYSTEM \"ent\"> <!ELEMENT foo ANY> <!ATTLIST foo a CDATA \"contains &ent; reference\"> ]>");
TEST_DOCTYPE_WF("<!DOCTYPE foo [ <!ELEMENT foo ANY> <!ATTLIST foo id ID #IMPLIED> <!ATTLIST foo ref IDREF \"undef\"> <!ATTLIST foo ent ENTITY \"undef\"> <!-- can't test NOTATION attribute, because if it's undeclared then we'll get an error for one of the enumerated values being undeclared. --> <!ENTITY ent SYSTEM \"foo\" NDATA not> <!NOTATION not SYSTEM \"not\"> ]>");
TEST_DOCTYPE_WF("<!DOCTYPE foo [ <!ELEMENT foo EMPTY> <!ATTLIST foo a (one|two|three) \"four\"> ]>");
TEST_DOCTYPE_WF("<!DOCTYPE foo [ <!ELEMENT foo ANY> <!ATTLIST foo a NOTATION (not) \"not2\"> <!NOTATION not SYSTEM \"not\"> <!NOTATION not2 SYSTEM \"not2\"> ]>");
TEST_DOCTYPE_WF("<!DOCTYPE foo [ <!ELEMENT foo EMPTY> <!ATTLIST foo a NMTOKENS \"34+\"> ]>");
}
TEST(parse_doctype_xmlconf_eduni_3)
{
TEST_DOCTYPE_WF("<!DOCTYPE animal [ <!ELEMENT animal ANY> <?_\xd9\x9f an only legal per 5th edition extender #x65f in PITarget ?> ]>");
TEST_DOCTYPE_WF("<!DOCTYPE root [ <!ELEMENT root ANY> <!ELEMENT \xc2\xb7_BadName EMPTY> ]>");
TEST_DOCTYPE_WF("<!DOCTYPE doc [ <!ENTITY e \"<X&#xe5c;></X&#xe5c;>\"> ]>");
}
TEST(parse_doctype_xmlconf_eduni_4)
{
TEST_DOCTYPE_WF("<!DOCTYPE foo [ <!ELEMENT foo ANY> <!ENTITY a:b \"bogus\"> ]>");
TEST_DOCTYPE_WF("<!DOCTYPE foo [ <!ELEMENT foo ANY> <!ATTLIST foo xmlns:a CDATA #IMPLIED xmlns:b NMTOKEN #IMPLIED xmlns:c CDATA #IMPLIED> <!ELEMENT bar ANY> <!ATTLIST bar a:attr CDATA #IMPLIED b:attr CDATA #IMPLIED c:attr CDATA #IMPLIED> ]>");
TEST_DOCTYPE_WF("<!DOCTYPE foo [ <!ELEMENT foo ANY> <!ATTLIST foo xmlns:a CDATA #IMPLIED xmlns:b CDATA #IMPLIED xmlns:c CDATA #IMPLIED> <!ELEMENT bar ANY> <!ATTLIST bar a:attr CDATA #IMPLIED b:attr CDATA #IMPLIED c:attr CDATA #IMPLIED> <!ENTITY tilde \"~\"> ]>");
TEST_DOCTYPE_WF("<!DOCTYPE foo [ <!ELEMENT xmlns:foo EMPTY> ]>");
}
TEST(parse_doctype_xmlconf_eduni_5)
{
TEST_DOCTYPE_WF("<!DOCTYPE foo [ <!ELEMENT foo ANY> <!ENTITY e \"&#x0c;\"> ]>");
TEST_DOCTYPE_WF("<!DOCTYPE foo [ <!ELEMENT foo (foo*)> <!ENTITY e \"abc&#x85;def\"> ]>");
TEST_DOCTYPE_WF("<!DOCTYPE foo [ <!ELEMENT foo ANY> <!ATTLIST foo bar NMTOKENS #IMPLIED> <!ENTITY val \"abc&#x85;def\"> ]>");
}
TEST(parse_doctype_xmlconf_ibm_1)
{
TEST_DOCTYPE_WF("<!DOCTYPE animal SYSTEM \"ibm32i04.dtd\" [ <!ATTLIST animal xml:space (default|preserve) 'preserve'> ]>");
TEST_DOCTYPE_WF("<!DOCTYPE root [ <!ELEMENT root (a,b)> <!ELEMENT a EMPTY> <!ELEMENT b (#PCDATA|c)* > <!ELEMENT c ANY> ]>");
TEST_DOCTYPE_WF("<!DOCTYPE root [ <!ELEMENT root (PCDATA|b)* > <!ELEMENT b (#PCDATA) > <!ATTLIST b attr1 CDATA #REQUIRED> <!ATTLIST b attr2 (abc|def) \"abc\"> <!ATTLIST b attr3 CDATA #FIXED \"fixed\"> ]>");
TEST_DOCTYPE_WF("<!DOCTYPE test [ <!ELEMENT test ANY> <!ELEMENT landscape EMPTY> <!ENTITY parsedentity1 SYSTEM \"ibm56iv01.xml\"> <!ENTITY parsedentity2 SYSTEM \"ibm56iv02.xml\"> <!ATTLIST landscape sun ENTITIES #IMPLIED> ]>");
TEST_DOCTYPE_WF("<!DOCTYPE test [ <!ELEMENT test ANY> <!ELEMENT landscape EMPTY> <!ENTITY image1 SYSTEM \"d:\\testspec\\images\\sunset.gif\" NDATA gif> <!ENTITY image2 SYSTEM \"d:\\testspec\\images\\frontpag.gif\" NDATA gif> <!ATTLIST landscape sun ENTITIES #IMPLIED> ]>");
TEST_DOCTYPE_WF("<!DOCTYPE tokenizer [ <!ELEMENT tokenizer ANY> <!ATTLIST tokenizer UniqueName ID #FIXED \"AC1999\"> ]>");
TEST_DOCTYPE_WF("<!DOCTYPE test [ <!ELEMENT test ANY> <!ELEMENT blob (#PCDATA)> <!NOTATION base64 SYSTEM \"mimecode\"> <!NOTATION uuencode SYSTEM \"uudecode\"> <!ATTLIST blob content-encoding NOTATION (base64|uuencode|raw|ascii) #REQUIRED> ]>");
TEST_DOCTYPE_WF("<!DOCTYPE test [ <!ELEMENT test ANY> <!ELEMENT a EMPTY> <!ELEMENT nametoken EMPTY> <!ATTLIST nametoken namevalue NMTOKEN \"@#$\"> ]>");
TEST_DOCTYPE_WF("<!DOCTYPE root [ <!ELEMENT root (#PCDATA)* > <!ENTITY % pe1 SYSTEM \"ibm68i04.ent\"> %pe1; ]>");
TEST_DOCTYPE_WF("<!DOCTYPE root [ <!ELEMENT a EMPTY> <!ATTLIST a attr1 CDATA \"&ge1;\"> <!--* GE reference in attr default before declaration *--> <!ENTITY ge1 \"abcdef\"> ]>");
TEST_DOCTYPE_WF("<!DOCTYPE root [ <!ENTITY ge1 \"abcdef\"> <!ELEMENT a EMPTY> <!ATTLIST a attr1 CDATA \"&ge1;\"> <!ENTITY % pe2 \"<!ATTLIST a attr2 CDATA #IMPLIED>\"> %pe3; <!--* PE reference in above doesn't match declaration *--> ]>");
TEST_DOCTYPE_WF("<!DOCTYPE root [ <!ELEMENT root (#PCDATA)> <!ATTLIST root att CDATA #IMPLIED> <!ENTITY % pe1 '<!ATTLIST root att2 CDATA \"&ge1;\">'> <!ENTITY ge1 \"attdefaultvalue\" > %pe1; <!--* notation JPGformat not declared *--> <!ENTITY ge2 SYSTEM \"image.jpg\" NDATA JPGformat> ]>");
}
TEST(parse_doctype_xmlconf_ibm_2)
{
TEST_DOCTYPE_WF("<!DOCTYPE student [ <!ELEMENT student (#PCDATA)> <!ENTITY gewithElemnetDecl \"<!ELEMENT bogus ANY>\"> <!ATTLIST student att1 CDATA #REQUIRED> ]>");
TEST_DOCTYPE_WF("<!DOCTYPE student [ <!ELEMENT student (#PCDATA)> <!ENTITY gewithlt \"abcd&#x26;&#x23;x3c;\"> <!ATTLIST student att1 CDATA #REQUIRED> ]>");
TEST_DOCTYPE_WF("<!DOCTYPE student [ <!ELEMENT student (#PCDATA)> <!ENTITY gewithlt \"abcd&#x3c;\"> <!ATTLIST student att1 CDATA #REQUIRED> ]>");
TEST_DOCTYPE_WF("<!DOCTYPE 5A_name_starts_with_digit [ <!ELEMENT 5A_name_starts_with_digit EMPTY> ]>");
TEST_DOCTYPE_WF("<!DOCTYPE student [ <!ELEMENT student (#PCDATA)> <!ENTITY FullName \"Snow&Man\"> ]>");
TEST_DOCTYPE_NWF("<!DOCTYPE student [ <!ELEMENT student (#PCDATA)> <!ENTITY FullName \"Snow\"Man\"> ]>");
TEST_DOCTYPE_WF("<!DOCTYPE student [ <!ELEMENT student (#PCDATA)> <!ATTLIST student first CDATA #REQUIRED middle CDATA #IMPLIED last CDATA #IMPLIED > <!ENTITY myfirst \"Snow\"> <!ENTITY mymiddle \"I\"> <!ENTITY mylast \"Man\"> ]>");
TEST_DOCTYPE_NWF("<!DOCTYPE student SYSTEM 'student.DTD [ <!ELEMENT student (#PCDATA)> ]>");
TEST_DOCTYPE_NWF("<!DOCTYPE student [ <!ELEMENT student (#PCDATA)> <!ENTITY info PUBLIC '..\\info.dtd> ]>");
TEST_DOCTYPE_NWF("<!DOCTYPE student [ <!ELEMENT student (#PCDATA)> <!ENTITY info PUBLIC '..\\info'.dtd'> ]>");
TEST_DOCTYPE_NWF("<!DOCTYPE student [ <!ELEMENT student (#PCDATA)> <!ENTITY info PUBLIC \"..\\info.dtd> ]>");
TEST_DOCTYPE_WF("<!DOCTYPE student [ <!ENTITY info PUBLIC \"This is a {test} \" \"student.dtd\"> ]>");
TEST_DOCTYPE_WF("<!DOCTYPE aniaml [ <!ELEMENT animal ANY> <!ENTITY generalE \"leopard\"> &generalE; <!ENTITY % parameterE \"<!ELEMENT leopard EMPTY>\"> %parameterE; ] animal>");
TEST_DOCTYPE_WF("<!DOCTYPE animal SYSTEM \"ibm28an01.dtd\" [ <!ELEMENT animal (cat|tiger|leopard)+> <!NOTATION animal_class SYSTEM \"ibm29v01.txt\"> <!ELEMENT cat ANY> <!ENTITY forcat \"This is a small cat\"> <!ELEMENT tiger (#PCDATA)> <!ELEMENT small EMPTY> <!ELEMENT big EMPTY> <!ATTLIST tiger color CDATA #REQUIRED> <?sound \"This is a PI\" ?> <!-- This is a comment --> ]>");
TEST_DOCTYPE_WF("<!DOCTYPE animal [ <!ELEMENT animal ANY> <!ENTITY % parameterE \"cat SYSTEM\"> <!NOTATION %parameterE; \"cat.txt\"> ]>");
TEST_DOCTYPE_NWF("<!DOCTYPE animal [ <!ELEMENT animal ANY> <!ENTITY % parameterE \"A music file -->\"> <!-- Parameter reference appears inside a comment in DTD --> <!-- This is %parameterE; ]>");
TEST_DOCTYPE_NWF("<!DOCTYPE animal [ <!ELEMENT animal ANY> <!ENTITY % parameterE \"A music file ?>\"> <?music %parameterE; ]>");
TEST_DOCTYPE_NWF("<!DOCTYPE animal [ <!ELEMENT animal ANY> <!ENTITY % parameterE \"leopard EMPTY>\"> <!ELEMENT %parameterE; ]>");
TEST_DOCTYPE_WF("<!DOCTYPE root [ <!ELEMENT root ANY> <!ATTLIST root attr1 CDATA #IMPLIED> <!ATTLIST root attr2 CDATA #IMPLIED> <!ENTITY withlt \"have <lessthan> inside\"> <!ENTITY aIndirect \"&withlt;\"> ]>");
TEST_DOCTYPE_WF("<!DOCTYPE root [ <!ELEMENT root (#PCDATA)> <!--* Missing Name S contentspec in elementdecl *--> <!ELEMENT > ]>");
TEST_DOCTYPE_WF("<!DOCTYPE root [ <!ELEMENT root (#PCDATA)> <!ELEMENT a ANY> <!ELEMENT b ANY> <!--* extra separator in seq *--> <!ELEMENT aElement ((a|b),,a)? > ]>");
TEST_DOCTYPE_WF("<!DOCTYPE root [ <!ELEMENT root (#PCDATA)> <!ELEMENT a ANY> <!--* Missing white space before Name in AttDef *--> <!ATTLIST a attr1 CDATA \"default\"attr2 ID #required> ]>");
TEST_DOCTYPE_WF("<!DOCTYPE test [ <!ELEMENT test ANY> <!ELEMENT one EMPTY> <!ELEMENT two EMPTY> <!NOTATION this SYSTEM \"alpha\"> <!ATTLIST three attr NOTATION (\"this\") #IMPLIED> ]>");
TEST_DOCTYPE_WF("<!DOCTYPE root [ <!-- DTD for Production 62--> <![ include [ <!ELEMENT tiger EMPTY> <!ELEMENT animal ANY> ]]> <!--Negative test with pattern1 of P62--> <!--include(Case sensitive)--> ]>");
TEST_DOCTYPE_WF("<!DOCTYPE root [ <![[INCLUDE[ <!ELEMENT tiger EMPTY> <!ELEMENT animal ANY> ]]> ]>");
TEST_DOCTYPE_NWF("<!DOCTYPE root [ <?[INCLUDE[ <!ELEMENT tiger EMPTY> <!ELEMENT animal ANY> ]]> ]>");
TEST_DOCTYPE_WF("<!DOCTYPE root [ <![[ <!ELEMENT tiger EMPTY> <!ELEMENT animal ANY> ]]> ]>");
TEST_DOCTYPE_WF("<!DOCTYPE root [ <![INCLUDE <!ELEMENT tiger EMPTY> <!ELEMENT animal ANY> ]]> ]>");
TEST_DOCTYPE_WF("<!DOCTYPE root [ <![ <!ELEMENT tiger EMPTY> <!ELEMENT animal ANY> [INCLUDE ]]> ]>");
TEST_DOCTYPE_NWF("<!DOCTYPE root [ <![ INCLUDE [ <!ELEMENT tiger EMPTY> <!ELEMENT animal ANY> ]>");
TEST_DOCTYPE_NWF("<!DOCTYPE root [ <![INCLUDE[ ]> ]>");
TEST_DOCTYPE_WF("<!DOCTYPE root [ <!ELEMENT root (#PCDATA)> <!--* PE referenced before declared, against WFC: entity declared --> %paaa; <!ENTITY % paaa \"<!ATTLIST root att CDATA #IMPLIED>\"> <!ENTITY aaa \"aString\"> ]>");
TEST_DOCTYPE_WF("<!DOCTYPE root [ <!ELEMENT root (#PCDATA)> <!ATTLIST root att CDATA #IMPLIED> <!--* missing space *--> <!ENTITY% paaa \"<!-- comments -->\"> %paaa; ]>");
TEST_DOCTYPE_NWF("<!DOCTYPE root [ <!ELEMENT root (#PCDATA)> <!ATTLIST root att CDATA #IMPLIED> <!--* missing closing bracket *--> <!ENTITY % paaa \"<!-- comments -->\" %paaa; ]>");
TEST_DOCTYPE_WF("<!DOCTYPE root PUBLIC \"-//W3C//DTD//EN\"\"empty.dtd\" [ <!ELEMENT root (#PCDATA)> <!ATTLIST root att CDATA #IMPLIED> ]>");
}
TEST(parse_doctype_xmlconf_ibm_3)
{
TEST_DOCTYPE_WF("<!DOCTYPE animal [ <!ELEMENT animal (cat|tiger|leopard)+> <!ELEMENT cat EMPTY> <!ELEMENT tiger (#PCDATA)> <!ELEMENT leopard ANY> <!ELEMENT small EMPTY> <!ELEMENT big EMPTY> <!ATTLIST tiger color CDATA #REQUIRED> ]>");
TEST_DOCTYPE_WF("<!DOCTYPE book [ <!ELEMENT book ANY> <!-- This test case covers legal character ranges plus discrete legal characters for production 02. --> <?NAME target ?> ]>");
TEST_DOCTYPE_WF("<!DOCTYPE student [ <!ELEMENT student (#PCDATA)> <!ATTLIST student first CDATA #REQUIRED middle CDATA #IMPLIED last CDATA #REQUIRED > <!ENTITY myfirst \"Snow\"> <!ENTITY mymiddle \"I\"> <!ENTITY mylast 'Man &myfirst; and &myfirst; mymiddle;.'> ]>");
TEST_DOCTYPE_WF("<!DOCTYPE student SYSTEM 'student.dtd'[ ]>");
TEST_DOCTYPE_WF("<!DOCTYPE student [ <!ELEMENT student (#PCDATA)> <!ENTITY unref SYSTEM \"\"> ]>");
TEST_DOCTYPE_WF("<!DOCTYPE student PUBLIC \"\" \"student.dtd\"[ ]>");
TEST_DOCTYPE_WF("<!DOCTYPE student PUBLIC '' 'student.dtd'[ ]>");
TEST_DOCTYPE_WF("<!DOCTYPE student PUBLIC \"The big ' in it\" \"student.dtd\"[ ]>");
TEST_DOCTYPE_WF("<!DOCTYPE student PUBLIC 'The latest version' 'student.dtd'[ ]>");
TEST_DOCTYPE_WF("<!DOCTYPE student PUBLIC \"#x20 #xD #xA abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ -'()+,./:=?;!*#@$_% \" \"student.dtd\"[ ]>");
TEST_DOCTYPE_WF("<!DOCTYPE student [ <!ELEMENT student (#PCDATA)> <!----> ]>");
TEST_DOCTYPE_NWF("<!DOCTYPE student [ <!ELEMENT student (#PCDATA)> <!---> ]>");
TEST_DOCTYPE_WF("<!DOCTYPE student [ <!ELEMENT student (#PCDATA)> <?pi?> ]>");
TEST_DOCTYPE_NWF("<!DOCTYPE student [ <!ELEMENT student (#PCDATA)> <?> ]>");
TEST_DOCTYPE_WF("<!DOCTYPE student [ <!ELEMENT student (#PCDATA)> <?MyInstruct AVOID ? BEFORE > IN PI ?> ]>");
TEST_DOCTYPE_WF("<!DOCTYPE animal SYSTEM \"ibm28v02.dtd\" [ <!NOTATION animal_class SYSTEM \"ibm28v02.txt\"> <!ENTITY forcat \"This is a small cat\"> <!ELEMENT tiger (#PCDATA)> <!ENTITY % make_small \"<!ELEMENT small EMPTY>\"> <!ENTITY % make_leopard_element \"<!ELEMENT leopard ANY>\"> <!ENTITY % make_attlist \"<!ATTLIST tiger color CDATA #REQUIRED>\"> %make_leopard_element; <!ELEMENT cat ANY> %make_small; <!ENTITY % make_big \"<!ELEMENT big EMPTY>\"> %make_big; %make_attlist; <?sound \"This is a PI\" ?> <!-- This is a valid test file for p28 --> ]>");
TEST_DOCTYPE_WF("<!DOCTYPE animal [ <![INCLUDE[ <!ENTITY % rootElement \"<!ELEMENT animal ANY>\"> ]]> %rootElement; <!-- Following is a makupdecl --> <!ENTITY % make_tiger_element \"<!ELEMENT tiger EMPTY>\"> %make_tiger_element; <![IGNORE[ <!ELEMENT animal EMPTY> ]]> ]>");
TEST_DOCTYPE_WF("<!DOCTYPE root [ <!ELEMENT root (a,b)> <!ELEMENT a EMPTY> <!ELEMENT b (#PCDATA|c)* > <!ELEMENT c ANY> <!ENTITY inContent \"<b>General entity reference in element content</b>\"> ]>");
TEST_DOCTYPE_WF("<!DOCTYPE root [ <!ELEMENT a EMPTY> <!ELEMENT b (#PCDATA|c)* > <!ELEMENT c ANY> <!--* PE replace Text have both parentheses *--> <!ENTITY % seq1 \"(a,b,c)\"> <!ELEMENT child1 %seq1; > <!--* Another legal PE replace Text *--> <!ENTITY % seq2 \"a,b\"> <!ELEMENT child2 (%seq2;,c) > ]>");
TEST_DOCTYPE_WF("<!DOCTYPE root [ <![IGNORE[ Everything is ignored within an ignored section, except the sub-section delimiters '<![' and ']]>'. These must be balanced <!ok ]]> ]>");
TEST_DOCTYPE_WF("<!DOCTYPE root [ <![IGNORE[ Everything is ignored within an ignored section, except the sub-section delimiters '<![' and ']]>'. These must be balanced <![ <!ELEMENT animal EMPTY> ]]> ]]> ]>");
TEST_DOCTYPE_WF("<!DOCTYPE root [ <![IGNORE[ begin Everything is ignored within an ignored section, except the sub-section delimiters '<![' and ']]>'. These must be balanced <![ <!ELEMENT animal EMPTY> ]]> nesting <![ <!ELEMENT tiger (#PCDATA)> ]]> nesting again <![ <!ELEMENT abc ANY> ]]> end ]]> ]>");
TEST_DOCTYPE_WF("<!DOCTYPE root [ <!DOCTYPE root SYSTEM \"ibm69v01.dtd\" [ <!ELEMENT root (#PCDATA|a)* > <!ENTITY % pe1 \"<!-- comment in PE -->\"> %pe1; ]> ]>");
}
TEST(parse_doctype_xmlconf_oasis_1)
{
TEST_DOCTYPE_WF("<!DOCTYPE root [ <!ELEMENT doc EMPTY> <!ENTITY % ent1 \"\"> <!ENTITY ent2 \"text2\"> <!ENTITY % ent3 \"<!-- <!DOCTYPE <!ELEMENT <? '''&#34;&ent2; %ent1;\"> <!ENTITY % ent4 '\"\"&#x27;&#39;\"'> ]>");
TEST_DOCTYPE_WF("<!DOCTYPE root [ <![INCLUDE[ <!ENTITY % rootel \"<!ELEMENT doc EMPTY>\"> ]]> %rootel; <!ATTLIST doc att CDATA #IMPLIED> <![IGNORE[ <!ELEMENT doc (a)> ]]> ]>");
TEST_DOCTYPE_WF("<!DOCTYPE root [ <![INCLUDE[<![INCLUDE[ <![IGNORE[ ignored ]]> <!ELEMENT doc EMPTY> ]]>]]> <![IGNORE[ ignored ]]> <![IGNORE[ <!ELEMENT doc ignored ]]> ]>");
TEST_DOCTYPE_WF("<!DOCTYPE root [ <![INCLUDE[ <![ INCLUDE [ <!ELEMENT doc EMPTY> <![IGNORE[asdfasdf]]> ]]>]]> <![INCLUDE[]]> <![INCLUDE[ ]]> <![INCLUDE[ ]]> ]>");
TEST_DOCTYPE_NWF("<!DOCTYPE root [ <!ELEMENT doc EMPTY> <![IGNORE[<![]]> ]>");
TEST_DOCTYPE_WF("<!DOCTYPE root [ <!ELEMENT doc EMPTY> <![IGNORE[ <![INCLUDE[ <!ELEMENT doc ]]>]]> <![ IGNORE [ ]]> <![IGNORE[]]> <![IGNORE[ ]]> <![IGNORE[ ]]> ]>");
TEST_DOCTYPE_NWF("<!DOCTYPE root [ <!ELEMENT doc EMPTY> <![IGNORE[ <![ starts must balance ]]> ]>");
TEST_DOCTYPE_WF("<!DOCTYPE root [ <!ELEMENT doc EMPTY> <![IGNORE[ Everything is ignored within an ignored section, except the sub-section delimiters '<![' and ']]>'. These must be balanced, but it is no section keyword is required: <![]]> <![DUNNO[ ]]> <![INCLUDE[ asdfasdfasdf <!OK ]]> ] ]> ]] > ]]> <![IGNORE[ < ![ <! [ <![]]>]]> ]>");
TEST_DOCTYPE_WF("<!DOCTYPE doc [ <!ELEMENT doc EMPTY> <!NOTATION not1 SYSTEM \"a%a&b&#0<!ELEMENT<!--<?</>?>/\''\"> <!NOTATION not2 SYSTEM 'a b\"\"\"'> <!NOTATION not3 SYSTEM \"\"> <!NOTATION not4 SYSTEM ''> ]>");
TEST_DOCTYPE_WF("<!DOCTYPE doc [ <!ELEMENT doc EMPTY> <!NOTATION not1 PUBLIC \"<\"> ]>");
TEST_DOCTYPE_WF("<!DOCTYPE doc [ <!ELEMENT doc EMPTY> <!NOTATION not1 PUBLIC \"a b cdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ\"> <!NOTATION not2 PUBLIC '0123456789-()+,./:=?;!*#@$_%'> <!NOTATION not3 PUBLIC \"0123456789-()+,.'/:=?;!*#@$_%\"> ]>");
TEST_DOCTYPE_WF("<!DOCTYPE doc SYSTEM \"p31pass1.dtd\" [<!ELEMENT doc EMPTY>]>");
// not actually a doctype :)
xml_document doc;
CHECK(doc.load_string(STR("<!--a <!DOCTYPE <?- ]]>-<[ CDATA [ \"- -'- -<doc>--> <!---->"), parse_full | parse_fragment) && doc.first_child().type() == node_comment && doc.last_child().type() == node_comment && doc.first_child().next_sibling() == doc.last_child());
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());
}
TEST(parse_doctype_xmlconf_xmltest_1)
{
TEST_DOCTYPE_NWF("<!DOCTYPE root [ <![ INCLUDE [ <!ELEMENT doc (#PCDATA)> ]> ]>");
TEST_DOCTYPE_NWF("<!DOCTYPE root [ <!ELEMENT doc (#PCDATA)> <![ IGNORE [");
TEST_DOCTYPE_NWF("<!DOCTYPE root [ <!ELEMENT doc (#PCDATA)> <![ IGNORE [ ]>");
TEST_DOCTYPE_NWF("<!DOCTYPE root [ <!ELEMENT doc (#PCDATA)> <![ INCLUDE [");
TEST_DOCTYPE_NWF("<!DOCTYPE root [ <!ELEMENT doc (#PCDATA)> <![ INCLUDE [ ]>");
TEST_DOCTYPE_WF("<!DOCTYPE root [ <!ELEMENT doc EMPTY> <!ENTITY % e \"<!--\"> %e; -->");
TEST_DOCTYPE_WF("<!DOCTYPE doc [ <!NOTATION foo PUBLIC \"[\" \"null.ent\"> ]>");
TEST_DOCTYPE_WF("<!DOCTYPE doc [ <!ELEMENT doc (#PCDATA)> <!ATTLIST doc a CDATA #IMPLIED> <!ENTITY e '\"'> ]>");
TEST_DOCTYPE_WF("<!DOCTYPE doc [ <!ENTITY e \"<foo a='&#38;'></foo>\"> ]>");
TEST_DOCTYPE_WF("<!DOCTYPE doc [ <!ELEMENT doc (#PCDATA)> <!ENTITY e \"<![CDATA[Tim & Michael]]>\"> ]>");
}
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();
CHECK(n.type() == node_doctype);
CHECK_STRING(n.value(), STR("doc [ <!ELEMENT doc (#PCDATA)> <!ENTITY e \"<![CDATA[Tim & Michael]]>\"> ]"));
}
TEST(parse_doctype_error_toplevel)
{
xml_document doc;
CHECK(doc.load_string(STR("<node><!DOCTYPE></node>")).status == status_bad_doctype);
CHECK(doc.load_string(STR("<node><!DOCTYPE></node>"), parse_doctype).status == status_bad_doctype);
}
TEST(parse_doctype_error_ignore)
{
xml_document doc;
CHECK(doc.load_string(STR("<!DOCTYPE root [ <![IGNORE[ ")).status == status_bad_doctype);
CHECK(doc.load_string(STR("<!DOCTYPE root [ <![IGNORE[ "), parse_doctype).status == status_bad_doctype);
CHECK(doc.load_string(STR("<!DOCTYPE root [ <![IGNORE[ <![INCLUDE[")).status == status_bad_doctype);
CHECK(doc.load_string(STR("<!DOCTYPE root [ <![IGNORE[ <![INCLUDE["), parse_doctype).status == status_bad_doctype);
}
TEST(parse_doctype_stackless_group)
{
std::basic_string<char_t> str;
int count = 100000;
str += STR("<!DOCTYPE ");
for (int i = 0; i < count; ++i)
str += STR("<!G ");
for (int j = 0; j < count; ++j)
str += STR(">");
str += STR(">");
xml_document doc;
CHECK(doc.load_string(str.c_str(), parse_fragment));
}
TEST(parse_doctype_stackless_ignore)
{
std::basic_string<char_t> str;
int count = 100000;
str += STR("<!DOCTYPE ");
for (int i = 0; i < count; ++i)
str += STR("<![IGNORE[ ");
for (int j = 0; j < count; ++j)
str += STR("]]>");
str += STR(">");
xml_document doc;
CHECK(doc.load_string(str.c_str(), parse_fragment));
}

View File

@ -1,153 +1,153 @@
#ifndef PUGIXML_NO_STL
#include "test.hpp"
#include <string>
using namespace pugi;
// letters taken from http://www.utf8-chartable.de/
TEST(as_wide_empty)
{
CHECK(as_wide("") == L"");
}
TEST(as_wide_valid_basic)
{
// valid 1-byte, 2-byte and 3-byte inputs
#ifdef U_LITERALS
CHECK(as_wide("?\xd0\x80\xe2\x80\xbd") == L"?\u0400\u203D");
#else
CHECK(as_wide("?\xd0\x80\xe2\x80\xbd") == L"?\x0400\x203D");
#endif
}
TEST(as_wide_valid_astral)
{
// valid 4-byte input
std::basic_string<wchar_t> b4 = as_wide("\xf2\x97\x98\xa4 \xf4\x80\x8f\xbf");
size_t wcharsize = sizeof(wchar_t);
if (wcharsize == 4)
{
CHECK(b4.size() == 3 && b4[0] == wchar_cast(0x97624) && b4[1] == L' ' && b4[2] == wchar_cast(0x1003ff));
}
else
{
CHECK(b4.size() == 5 && b4[0] == wchar_cast(0xda1d) && b4[1] == wchar_cast(0xde24) && b4[2] == L' ' && b4[3] == wchar_cast(0xdbc0) && b4[4] == wchar_cast(0xdfff));
}
}
TEST(as_wide_invalid)
{
// invalid 1-byte input
CHECK(as_wide("a\xb0") == L"a");
CHECK(as_wide("a\xb0_") == L"a_");
// invalid 2-byte input
CHECK(as_wide("a\xc0") == L"a");
CHECK(as_wide("a\xd0") == L"a");
CHECK(as_wide("a\xc0_") == L"a_");
CHECK(as_wide("a\xd0_") == L"a_");
// invalid 3-byte input
CHECK(as_wide("a\xe2\x80") == L"a");
CHECK(as_wide("a\xe2") == L"a");
CHECK(as_wide("a\xe2\x80_") == L"a_");
CHECK(as_wide("a\xe2_") == L"a_");
// invalid 4-byte input
CHECK(as_wide("a\xf2\x97\x98") == L"a");
CHECK(as_wide("a\xf2\x97") == L"a");
CHECK(as_wide("a\xf2") == L"a");
CHECK(as_wide("a\xf2\x97\x98_") == L"a_");
CHECK(as_wide("a\xf2\x97_") == L"a_");
CHECK(as_wide("a\xf2_") == L"a_");
// invalid 5-byte input
std::basic_string<wchar_t> b5 = as_wide("\xf8\nbcd");
CHECK(b5 == L"\nbcd");
}
TEST(as_wide_string)
{
std::string s = "abcd";
CHECK(as_wide(s) == L"abcd");
}
TEST(as_utf8_empty)
{
CHECK(as_utf8(L"") == "");
}
TEST(as_utf8_valid_basic)
{
// valid 1-byte, 2-byte and 3-byte outputs
#ifdef U_LITERALS
CHECK(as_utf8(L"?\u0400\u203D") == "?\xd0\x80\xe2\x80\xbd");
#else
CHECK(as_utf8(L"?\x0400\x203D") == "?\xd0\x80\xe2\x80\xbd");
#endif
}
TEST(as_utf8_valid_astral)
{
// valid 4-byte output
size_t wcharsize = sizeof(wchar_t);
if (wcharsize == 4)
{
std::basic_string<wchar_t> s;
s.resize(3);
s[0] = wchar_cast(0x97624);
s[1] = ' ';
s[2] = wchar_cast(0x1003ff);
CHECK(as_utf8(s.c_str()) == "\xf2\x97\x98\xa4 \xf4\x80\x8f\xbf");
}
else
{
#ifdef U_LITERALS
CHECK(as_utf8(L"\uda1d\ude24 \udbc0\udfff") == "\xf2\x97\x98\xa4 \xf4\x80\x8f\xbf");
#else
CHECK(as_utf8(L"\xda1d\xde24 \xdbc0\xdfff") == "\xf2\x97\x98\xa4 \xf4\x80\x8f\xbf");
#endif
}
}
TEST(as_utf8_invalid)
{
size_t wcharsize = sizeof(wchar_t);
if (wcharsize == 2)
{
// check non-terminated degenerate handling
#ifdef U_LITERALS
CHECK(as_utf8(L"a\uda1d") == "a");
CHECK(as_utf8(L"a\uda1d_") == "a_");
#else
CHECK(as_utf8(L"a\xda1d") == "a");
CHECK(as_utf8(L"a\xda1d_") == "a_");
#endif
// check incorrect leading code
#ifdef U_LITERALS
CHECK(as_utf8(L"a\ude24") == "a");
CHECK(as_utf8(L"a\ude24_") == "a_");
#else
CHECK(as_utf8(L"a\xde24") == "a");
CHECK(as_utf8(L"a\xde24_") == "a_");
#endif
}
}
TEST(as_utf8_string)
{
std::basic_string<wchar_t> s = L"abcd";
CHECK(as_utf8(s) == "abcd");
}
#endif
#ifndef PUGIXML_NO_STL
#include "test.hpp"
#include <string>
using namespace pugi;
// letters taken from http://www.utf8-chartable.de/
TEST(as_wide_empty)
{
CHECK(as_wide("") == L"");
}
TEST(as_wide_valid_basic)
{
// valid 1-byte, 2-byte and 3-byte inputs
#ifdef U_LITERALS
CHECK(as_wide("?\xd0\x80\xe2\x80\xbd") == L"?\u0400\u203D");
#else
CHECK(as_wide("?\xd0\x80\xe2\x80\xbd") == L"?\x0400\x203D");
#endif
}
TEST(as_wide_valid_astral)
{
// valid 4-byte input
std::basic_string<wchar_t> b4 = as_wide("\xf2\x97\x98\xa4 \xf4\x80\x8f\xbf");
size_t wcharsize = sizeof(wchar_t);
if (wcharsize == 4)
{
CHECK(b4.size() == 3 && b4[0] == wchar_cast(0x97624) && b4[1] == L' ' && b4[2] == wchar_cast(0x1003ff));
}
else
{
CHECK(b4.size() == 5 && b4[0] == wchar_cast(0xda1d) && b4[1] == wchar_cast(0xde24) && b4[2] == L' ' && b4[3] == wchar_cast(0xdbc0) && b4[4] == wchar_cast(0xdfff));
}
}
TEST(as_wide_invalid)
{
// invalid 1-byte input
CHECK(as_wide("a\xb0") == L"a");
CHECK(as_wide("a\xb0_") == L"a_");
// invalid 2-byte input
CHECK(as_wide("a\xc0") == L"a");
CHECK(as_wide("a\xd0") == L"a");
CHECK(as_wide("a\xc0_") == L"a_");
CHECK(as_wide("a\xd0_") == L"a_");
// invalid 3-byte input
CHECK(as_wide("a\xe2\x80") == L"a");
CHECK(as_wide("a\xe2") == L"a");
CHECK(as_wide("a\xe2\x80_") == L"a_");
CHECK(as_wide("a\xe2_") == L"a_");
// invalid 4-byte input
CHECK(as_wide("a\xf2\x97\x98") == L"a");
CHECK(as_wide("a\xf2\x97") == L"a");
CHECK(as_wide("a\xf2") == L"a");
CHECK(as_wide("a\xf2\x97\x98_") == L"a_");
CHECK(as_wide("a\xf2\x97_") == L"a_");
CHECK(as_wide("a\xf2_") == L"a_");
// invalid 5-byte input
std::basic_string<wchar_t> b5 = as_wide("\xf8\nbcd");
CHECK(b5 == L"\nbcd");
}
TEST(as_wide_string)
{
std::string s = "abcd";
CHECK(as_wide(s) == L"abcd");
}
TEST(as_utf8_empty)
{
CHECK(as_utf8(L"") == "");
}
TEST(as_utf8_valid_basic)
{
// valid 1-byte, 2-byte and 3-byte outputs
#ifdef U_LITERALS
CHECK(as_utf8(L"?\u0400\u203D") == "?\xd0\x80\xe2\x80\xbd");
#else
CHECK(as_utf8(L"?\x0400\x203D") == "?\xd0\x80\xe2\x80\xbd");
#endif
}
TEST(as_utf8_valid_astral)
{
// valid 4-byte output
size_t wcharsize = sizeof(wchar_t);
if (wcharsize == 4)
{
std::basic_string<wchar_t> s;
s.resize(3);
s[0] = wchar_cast(0x97624);
s[1] = ' ';
s[2] = wchar_cast(0x1003ff);
CHECK(as_utf8(s.c_str()) == "\xf2\x97\x98\xa4 \xf4\x80\x8f\xbf");
}
else
{
#ifdef U_LITERALS
CHECK(as_utf8(L"\uda1d\ude24 \udbc0\udfff") == "\xf2\x97\x98\xa4 \xf4\x80\x8f\xbf");
#else
CHECK(as_utf8(L"\xda1d\xde24 \xdbc0\xdfff") == "\xf2\x97\x98\xa4 \xf4\x80\x8f\xbf");
#endif
}
}
TEST(as_utf8_invalid)
{
size_t wcharsize = sizeof(wchar_t);
if (wcharsize == 2)
{
// check non-terminated degenerate handling
#ifdef U_LITERALS
CHECK(as_utf8(L"a\uda1d") == "a");
CHECK(as_utf8(L"a\uda1d_") == "a_");
#else
CHECK(as_utf8(L"a\xda1d") == "a");
CHECK(as_utf8(L"a\xda1d_") == "a_");
#endif
// check incorrect leading code
#ifdef U_LITERALS
CHECK(as_utf8(L"a\ude24") == "a");
CHECK(as_utf8(L"a\ude24_") == "a_");
#else
CHECK(as_utf8(L"a\xde24") == "a");
CHECK(as_utf8(L"a\xde24_") == "a_");
#endif
}
}
TEST(as_utf8_string)
{
std::basic_string<wchar_t> s = L"abcd";
CHECK(as_utf8(s) == "abcd");
}
#endif

View File

@ -1,5 +1,5 @@
#include "../src/pugixml.hpp"
#if PUGIXML_VERSION != 1130
#error Unexpected pugixml version
#endif
#include "../src/pugixml.hpp"
#if PUGIXML_VERSION != 1130
#error Unexpected pugixml version
#endif

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

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

File diff suppressed because it is too large Load Diff

View File

@ -1,219 +1,219 @@
#ifndef PUGIXML_NO_XPATH
#include "test.hpp"
using namespace pugi;
TEST_XML(xpath_paths_abbrev_w3c_1, "<node><para/><foo/><para/></node>")
{
xml_node c;
xml_node n = doc.child(STR("node"));
CHECK_XPATH_NODESET(c, STR("para"));
CHECK_XPATH_NODESET(n, STR("para")) % 3 % 5;
}
TEST_XML(xpath_paths_abbrev_w3c_2, "<node><para/><foo/><para/></node>")
{
xml_node c;
xml_node n = doc.child(STR("node"));
CHECK_XPATH_NODESET(c, STR("*"));
CHECK_XPATH_NODESET(n, STR("*")) % 3 % 4 % 5;
}
TEST_XML(xpath_paths_abbrev_w3c_3, "<node>pcdata<child/><![CDATA[cdata]]></node>")
{
xml_node c;
xml_node n = doc.child(STR("node"));
CHECK_XPATH_NODESET(c, STR("text()"));
CHECK_XPATH_NODESET(n, STR("text()")) % 3 % 5;
}
TEST_XML(xpath_paths_abbrev_w3c_4, "<node name='value' foo='bar' />")
{
xml_node c;
xml_node n = doc.child(STR("node"));
CHECK_XPATH_NODESET(c, STR("@name"));
CHECK_XPATH_NODESET(n, STR("@name")) % 3;
}
TEST_XML(xpath_paths_abbrev_w3c_5, "<node name='value' foo='bar' />")
{
xml_node c;
xml_node n = doc.child(STR("node"));
CHECK_XPATH_NODESET(c, STR("@*"));
CHECK_XPATH_NODESET(n, STR("@*")) % 3 % 4;
}
TEST_XML(xpath_paths_abbrev_w3c_6, "<node><para/><para/><para/><para/></node>")
{
xml_node c;
xml_node n = doc.child(STR("node"));
CHECK_XPATH_NODESET(c, STR("para[1]"));
CHECK_XPATH_NODESET(n, STR("para[1]")) % 3;
}
TEST_XML(xpath_paths_abbrev_w3c_7, "<node><para/><para/><para/><para/></node>")
{
xml_node c;
xml_node n = doc.child(STR("node"));
CHECK_XPATH_NODESET(c, STR("para[last()]"));
CHECK_XPATH_NODESET(n, STR("para[last()]")) % 6;
}
TEST_XML(xpath_paths_abbrev_w3c_8, "<node><para><para/><para/><foo><para/></foo></para><foo/><para/></node>")
{
xml_node c;
CHECK_XPATH_NODESET(c, STR("*/para"));
CHECK_XPATH_NODESET(doc, STR("*/para")) % 3 % 9;
}
TEST_XML(xpath_paths_abbrev_w3c_9, "<doc><chapter/><chapter/><chapter/><chapter/><chapter><section/><section/><section/></chapter><chapter/></doc>")
{
xml_node c;
xml_node n = doc.child(STR("doc")).child(STR("chapter"));
CHECK_XPATH_NODESET(c, STR("/doc/chapter[5]/section[2]"));
CHECK_XPATH_NODESET(n, STR("/doc/chapter[5]/section[2]")) % 9;
CHECK_XPATH_NODESET(doc, STR("/doc/chapter[5]/section[2]")) % 9;
}
TEST_XML(xpath_paths_abbrev_w3c_10, "<chapter><para><para/><para/><foo><para/></foo></para><foo/><para/></chapter>")
{
xml_node c;
CHECK_XPATH_NODESET(c, STR("chapter//para"));
CHECK_XPATH_NODESET(doc, STR("chapter//para")) % 3 % 4 % 5 % 7 % 9;
}
TEST_XML(xpath_paths_abbrev_w3c_11, "<node><para><para/><para/><foo><para/></foo></para><foo/><para/></node>")
{
xml_node c;
xml_node n = doc.child(STR("node"));
CHECK_XPATH_NODESET(c, STR("//para"));
CHECK_XPATH_NODESET(n, STR("//para")) % 3 % 4 % 5 % 7 % 9;
CHECK_XPATH_NODESET(n.child(STR("para")), STR("//para")) % 3 % 4 % 5 % 7 % 9;
}
TEST_XML(xpath_paths_abbrev_w3c_12, "<node><olist><item/></olist><item/><olist><olist><item/><item/></olist></olist></node>")
{
xml_node c;
xml_node n = doc.child(STR("node"));
CHECK_XPATH_NODESET(c, STR("//olist/item"));
CHECK_XPATH_NODESET(n, STR("//olist/item")) % 4 % 8 % 9;
CHECK_XPATH_NODESET(n.child(STR("olist")), STR("//olist/item")) % 4 % 8 % 9;
}
TEST_XML(xpath_paths_abbrev_w3c_13, "<node><child/></node>")
{
xml_node c;
xml_node n = doc.child(STR("node"));
CHECK_XPATH_NODESET(c, STR("."));
CHECK_XPATH_NODESET(n, STR(".")) % 2;
CHECK_XPATH_NODESET(n.child(STR("child")), STR(".")) % 3;
}
TEST_XML(xpath_paths_abbrev_w3c_14, "<node><para><para/><para/><foo><para/></foo></para><foo/><para/></node>")
{
xml_node c;
xml_node n = doc.child(STR("node"));
CHECK_XPATH_NODESET(c, STR(".//para"));
CHECK_XPATH_NODESET(n, STR(".//para")) % 3 % 4 % 5 % 7 % 9;
CHECK_XPATH_NODESET(n.child(STR("para")), STR(".//para")) % 4 % 5 % 7;
}
TEST_XML(xpath_paths_abbrev_w3c_15, "<node lang='en'><child/></node>")
{
xml_node c;
xml_node n = doc.child(STR("node"));
CHECK_XPATH_NODESET(c, STR(".."));
CHECK_XPATH_NODESET(n, STR("..")) % 1;
CHECK_XPATH_NODESET(n.child(STR("child")), STR("..")) % 2;
}
TEST_XML(xpath_paths_abbrev_w3c_16, "<node lang='en'><child/></node>")
{
xml_node c;
xml_node n = doc.child(STR("node"));
CHECK_XPATH_NODESET(c, STR("../@lang"));
CHECK_XPATH_NODESET(n, STR("../@lang"));
CHECK_XPATH_NODESET(n.child(STR("child")), STR("../@lang")) % 3;
}
TEST_XML(xpath_paths_abbrev_w3c_17, "<node><para/><para type='warning'/><para type='warning'/><para/><para type='error'/><para type='warning'/><para type='warning'/><para type='warning'/></node>")
{
xml_node c;
xml_node n = doc.child(STR("node"));
CHECK_XPATH_NODESET(c, STR("para[@type=\"warning\"]"));
CHECK_XPATH_NODESET(n, STR("para[@type=\"warning\"]")) % 4 % 6 % 11 % 13 % 15;
}
TEST_XML(xpath_paths_abbrev_w3c_18, "<node><para/><para type='warning'/><para type='warning'/><para/><para type='error'/><para type='warning'/><para type='warning'/><para type='warning'/></node>")
{
xml_node c;
xml_node n = doc.child(STR("node"));
CHECK_XPATH_NODESET(c, STR("para[@type=\"warning\"][5]"));
CHECK_XPATH_NODESET(n, STR("para[@type=\"warning\"][5]")) % 15;
}
TEST_XML(xpath_paths_abbrev_w3c_19a, "<node><para/><para type='warning'/><para type='warning'/><para/><para type='error'/><para type='warning'/><para type='warning'/><para type='warning'/></node>")
{
xml_node c;
xml_node n = doc.child(STR("node"));
CHECK_XPATH_NODESET(c, STR("para[5][@type=\"warning\"]"));
CHECK_XPATH_NODESET(n, STR("para[5][@type=\"warning\"]"));
}
TEST_XML(xpath_paths_abbrev_w3c_19b, "<node><para/><para type='warning'/><para type='warning'/><para/><para type='warning'/><para type='warning'/><para type='warning'/></node>")
{
xml_node c;
xml_node n = doc.child(STR("node"));
CHECK_XPATH_NODESET(c, STR("para[5][@type=\"warning\"]"));
CHECK_XPATH_NODESET(n, STR("para[5][@type=\"warning\"]")) % 9;
}
TEST_XML(xpath_paths_abbrev_w3c_20, "<node><chapter><title>foo</title></chapter><chapter><title>Introduction</title></chapter><chapter><title>introduction</title></chapter><chapter/><chapter><title>Introduction</title><title>foo</title></chapter></node>")
{
xml_node c;
xml_node n = doc.child(STR("node"));
CHECK_XPATH_NODESET(c, STR("chapter[title=\"Introduction\"]"));
CHECK_XPATH_NODESET(n, STR("chapter[title=\"Introduction\"]")) % 6 % 13;
}
TEST_XML(xpath_paths_abbrev_w3c_21, "<node><chapter><title>foo</title></chapter><chapter><title>Introduction</title></chapter><chapter><title>introduction</title></chapter><chapter/><chapter><title>Introduction</title><title>foo</title></chapter></node>")
{
xml_node c;
xml_node n = doc.child(STR("node"));
CHECK_XPATH_NODESET(c, STR("chapter[title]"));
CHECK_XPATH_NODESET(n, STR("chapter[title]")) % 3 % 6 % 9 % 13;
}
TEST_XML(xpath_paths_abbrev_w3c_22, "<node><employee/><employee secretary=''/><employee assistant=''/><employee secretary='' assistant=''/><employee assistant='' secretary=''/></node>")
{
xml_node c;
xml_node n = doc.child(STR("node"));
CHECK_XPATH_NODESET(c, STR("employee[@secretary and @assistant]"));
CHECK_XPATH_NODESET(n, STR("employee[@secretary and @assistant]")) % 8 % 11;
}
#endif
#ifndef PUGIXML_NO_XPATH
#include "test.hpp"
using namespace pugi;
TEST_XML(xpath_paths_abbrev_w3c_1, "<node><para/><foo/><para/></node>")
{
xml_node c;
xml_node n = doc.child(STR("node"));
CHECK_XPATH_NODESET(c, STR("para"));
CHECK_XPATH_NODESET(n, STR("para")) % 3 % 5;
}
TEST_XML(xpath_paths_abbrev_w3c_2, "<node><para/><foo/><para/></node>")
{
xml_node c;
xml_node n = doc.child(STR("node"));
CHECK_XPATH_NODESET(c, STR("*"));
CHECK_XPATH_NODESET(n, STR("*")) % 3 % 4 % 5;
}
TEST_XML(xpath_paths_abbrev_w3c_3, "<node>pcdata<child/><![CDATA[cdata]]></node>")
{
xml_node c;
xml_node n = doc.child(STR("node"));
CHECK_XPATH_NODESET(c, STR("text()"));
CHECK_XPATH_NODESET(n, STR("text()")) % 3 % 5;
}
TEST_XML(xpath_paths_abbrev_w3c_4, "<node name='value' foo='bar' />")
{
xml_node c;
xml_node n = doc.child(STR("node"));
CHECK_XPATH_NODESET(c, STR("@name"));
CHECK_XPATH_NODESET(n, STR("@name")) % 3;
}
TEST_XML(xpath_paths_abbrev_w3c_5, "<node name='value' foo='bar' />")
{
xml_node c;
xml_node n = doc.child(STR("node"));
CHECK_XPATH_NODESET(c, STR("@*"));
CHECK_XPATH_NODESET(n, STR("@*")) % 3 % 4;
}
TEST_XML(xpath_paths_abbrev_w3c_6, "<node><para/><para/><para/><para/></node>")
{
xml_node c;
xml_node n = doc.child(STR("node"));
CHECK_XPATH_NODESET(c, STR("para[1]"));
CHECK_XPATH_NODESET(n, STR("para[1]")) % 3;
}
TEST_XML(xpath_paths_abbrev_w3c_7, "<node><para/><para/><para/><para/></node>")
{
xml_node c;
xml_node n = doc.child(STR("node"));
CHECK_XPATH_NODESET(c, STR("para[last()]"));
CHECK_XPATH_NODESET(n, STR("para[last()]")) % 6;
}
TEST_XML(xpath_paths_abbrev_w3c_8, "<node><para><para/><para/><foo><para/></foo></para><foo/><para/></node>")
{
xml_node c;
CHECK_XPATH_NODESET(c, STR("*/para"));
CHECK_XPATH_NODESET(doc, STR("*/para")) % 3 % 9;
}
TEST_XML(xpath_paths_abbrev_w3c_9, "<doc><chapter/><chapter/><chapter/><chapter/><chapter><section/><section/><section/></chapter><chapter/></doc>")
{
xml_node c;
xml_node n = doc.child(STR("doc")).child(STR("chapter"));
CHECK_XPATH_NODESET(c, STR("/doc/chapter[5]/section[2]"));
CHECK_XPATH_NODESET(n, STR("/doc/chapter[5]/section[2]")) % 9;
CHECK_XPATH_NODESET(doc, STR("/doc/chapter[5]/section[2]")) % 9;
}
TEST_XML(xpath_paths_abbrev_w3c_10, "<chapter><para><para/><para/><foo><para/></foo></para><foo/><para/></chapter>")
{
xml_node c;
CHECK_XPATH_NODESET(c, STR("chapter//para"));
CHECK_XPATH_NODESET(doc, STR("chapter//para")) % 3 % 4 % 5 % 7 % 9;
}
TEST_XML(xpath_paths_abbrev_w3c_11, "<node><para><para/><para/><foo><para/></foo></para><foo/><para/></node>")
{
xml_node c;
xml_node n = doc.child(STR("node"));
CHECK_XPATH_NODESET(c, STR("//para"));
CHECK_XPATH_NODESET(n, STR("//para")) % 3 % 4 % 5 % 7 % 9;
CHECK_XPATH_NODESET(n.child(STR("para")), STR("//para")) % 3 % 4 % 5 % 7 % 9;
}
TEST_XML(xpath_paths_abbrev_w3c_12, "<node><olist><item/></olist><item/><olist><olist><item/><item/></olist></olist></node>")
{
xml_node c;
xml_node n = doc.child(STR("node"));
CHECK_XPATH_NODESET(c, STR("//olist/item"));
CHECK_XPATH_NODESET(n, STR("//olist/item")) % 4 % 8 % 9;
CHECK_XPATH_NODESET(n.child(STR("olist")), STR("//olist/item")) % 4 % 8 % 9;
}
TEST_XML(xpath_paths_abbrev_w3c_13, "<node><child/></node>")
{
xml_node c;
xml_node n = doc.child(STR("node"));
CHECK_XPATH_NODESET(c, STR("."));
CHECK_XPATH_NODESET(n, STR(".")) % 2;
CHECK_XPATH_NODESET(n.child(STR("child")), STR(".")) % 3;
}
TEST_XML(xpath_paths_abbrev_w3c_14, "<node><para><para/><para/><foo><para/></foo></para><foo/><para/></node>")
{
xml_node c;
xml_node n = doc.child(STR("node"));
CHECK_XPATH_NODESET(c, STR(".//para"));
CHECK_XPATH_NODESET(n, STR(".//para")) % 3 % 4 % 5 % 7 % 9;
CHECK_XPATH_NODESET(n.child(STR("para")), STR(".//para")) % 4 % 5 % 7;
}
TEST_XML(xpath_paths_abbrev_w3c_15, "<node lang='en'><child/></node>")
{
xml_node c;
xml_node n = doc.child(STR("node"));
CHECK_XPATH_NODESET(c, STR(".."));
CHECK_XPATH_NODESET(n, STR("..")) % 1;
CHECK_XPATH_NODESET(n.child(STR("child")), STR("..")) % 2;
}
TEST_XML(xpath_paths_abbrev_w3c_16, "<node lang='en'><child/></node>")
{
xml_node c;
xml_node n = doc.child(STR("node"));
CHECK_XPATH_NODESET(c, STR("../@lang"));
CHECK_XPATH_NODESET(n, STR("../@lang"));
CHECK_XPATH_NODESET(n.child(STR("child")), STR("../@lang")) % 3;
}
TEST_XML(xpath_paths_abbrev_w3c_17, "<node><para/><para type='warning'/><para type='warning'/><para/><para type='error'/><para type='warning'/><para type='warning'/><para type='warning'/></node>")
{
xml_node c;
xml_node n = doc.child(STR("node"));
CHECK_XPATH_NODESET(c, STR("para[@type=\"warning\"]"));
CHECK_XPATH_NODESET(n, STR("para[@type=\"warning\"]")) % 4 % 6 % 11 % 13 % 15;
}
TEST_XML(xpath_paths_abbrev_w3c_18, "<node><para/><para type='warning'/><para type='warning'/><para/><para type='error'/><para type='warning'/><para type='warning'/><para type='warning'/></node>")
{
xml_node c;
xml_node n = doc.child(STR("node"));
CHECK_XPATH_NODESET(c, STR("para[@type=\"warning\"][5]"));
CHECK_XPATH_NODESET(n, STR("para[@type=\"warning\"][5]")) % 15;
}
TEST_XML(xpath_paths_abbrev_w3c_19a, "<node><para/><para type='warning'/><para type='warning'/><para/><para type='error'/><para type='warning'/><para type='warning'/><para type='warning'/></node>")
{
xml_node c;
xml_node n = doc.child(STR("node"));
CHECK_XPATH_NODESET(c, STR("para[5][@type=\"warning\"]"));
CHECK_XPATH_NODESET(n, STR("para[5][@type=\"warning\"]"));
}
TEST_XML(xpath_paths_abbrev_w3c_19b, "<node><para/><para type='warning'/><para type='warning'/><para/><para type='warning'/><para type='warning'/><para type='warning'/></node>")
{
xml_node c;
xml_node n = doc.child(STR("node"));
CHECK_XPATH_NODESET(c, STR("para[5][@type=\"warning\"]"));
CHECK_XPATH_NODESET(n, STR("para[5][@type=\"warning\"]")) % 9;
}
TEST_XML(xpath_paths_abbrev_w3c_20, "<node><chapter><title>foo</title></chapter><chapter><title>Introduction</title></chapter><chapter><title>introduction</title></chapter><chapter/><chapter><title>Introduction</title><title>foo</title></chapter></node>")
{
xml_node c;
xml_node n = doc.child(STR("node"));
CHECK_XPATH_NODESET(c, STR("chapter[title=\"Introduction\"]"));
CHECK_XPATH_NODESET(n, STR("chapter[title=\"Introduction\"]")) % 6 % 13;
}
TEST_XML(xpath_paths_abbrev_w3c_21, "<node><chapter><title>foo</title></chapter><chapter><title>Introduction</title></chapter><chapter><title>introduction</title></chapter><chapter/><chapter><title>Introduction</title><title>foo</title></chapter></node>")
{
xml_node c;
xml_node n = doc.child(STR("node"));
CHECK_XPATH_NODESET(c, STR("chapter[title]"));
CHECK_XPATH_NODESET(n, STR("chapter[title]")) % 3 % 6 % 9 % 13;
}
TEST_XML(xpath_paths_abbrev_w3c_22, "<node><employee/><employee secretary=''/><employee assistant=''/><employee secretary='' assistant=''/><employee assistant='' secretary=''/></node>")
{
xml_node c;
xml_node n = doc.child(STR("node"));
CHECK_XPATH_NODESET(c, STR("employee[@secretary and @assistant]"));
CHECK_XPATH_NODESET(n, STR("employee[@secretary and @assistant]")) % 8 % 11;
}
#endif

View File

@ -1,312 +1,312 @@
#ifndef PUGIXML_NO_XPATH
#include "test.hpp"
using namespace pugi;
TEST_XML(xpath_paths_w3c_1, "<node><para/><foo/><para/></node>")
{
xml_node c;
xml_node n = doc.child(STR("node"));
CHECK_XPATH_NODESET(c, STR("child::para"));
CHECK_XPATH_NODESET(n, STR("child::para")) % 3 % 5;
}
TEST_XML(xpath_paths_w3c_2, "<node><para/><foo/><para/></node>")
{
xml_node c;
xml_node n = doc.child(STR("node"));
CHECK_XPATH_NODESET(c, STR("child::*"));
CHECK_XPATH_NODESET(n, STR("child::*")) % 3 % 4 % 5;
}
TEST_XML(xpath_paths_w3c_3, "<node>pcdata<child/><![CDATA[cdata]]></node>")
{
xml_node c;
xml_node n = doc.child(STR("node"));
CHECK_XPATH_NODESET(c, STR("child::text()"));
CHECK_XPATH_NODESET(n, STR("child::text()")) % 3 % 5;
}
TEST_XML(xpath_paths_w3c_4, "<node>pcdata<child/><![CDATA[cdata]]></node>")
{
xml_node c;
xml_node n = doc.child(STR("node"));
CHECK_XPATH_NODESET(c, STR("child::node()"));
CHECK_XPATH_NODESET(n, STR("child::node()")) % 3 % 4 % 5;
}
TEST_XML(xpath_paths_w3c_5, "<node name='value' foo='bar' />")
{
xml_node c;
xml_node n = doc.child(STR("node"));
CHECK_XPATH_NODESET(c, STR("attribute::name"));
CHECK_XPATH_NODESET(n, STR("attribute::name")) % 3;
}
TEST_XML(xpath_paths_w3c_6, "<node name='value' foo='bar' />")
{
xml_node c;
xml_node n = doc.child(STR("node"));
CHECK_XPATH_NODESET(c, STR("attribute::*"));
CHECK_XPATH_NODESET(n, STR("attribute::*")) % 3 % 4;
}
TEST_XML(xpath_paths_w3c_7, "<node><para><para/><para/><foo><para/></foo></para><foo/><para/></node>")
{
xml_node c;
xml_node n = doc.child(STR("node"));
CHECK_XPATH_NODESET(c, STR("descendant::para"));
CHECK_XPATH_NODESET(n, STR("descendant::para")) % 3 % 4 % 5 % 7 % 9;
CHECK_XPATH_NODESET(n.child(STR("para")), STR("descendant::para")) % 4 % 5 % 7;
}
TEST_XML(xpath_paths_w3c_8, "<node><div><font><div><div/></div></font></div></node>")
{
xml_node c;
xml_node n = doc.child(STR("node"));
CHECK_XPATH_NODESET(c, STR("ancestor::div"));
CHECK_XPATH_NODESET(n.child(STR("div")).child(STR("font")).child(STR("div")).child(STR("div")), STR("ancestor::div")) % 5 % 3;
}
TEST_XML(xpath_paths_w3c_9, "<node><div><font><div><div/></div></font></div></node>")
{
xml_node c;
xml_node n = doc.child(STR("node"));
CHECK_XPATH_NODESET(c, STR("ancestor-or-self::div"));
CHECK_XPATH_NODESET(n.child(STR("div")).child(STR("font")).child(STR("div")).child(STR("div")), STR("ancestor-or-self::div")) % 6 % 5 % 3;
}
TEST_XML(xpath_paths_w3c_10, "<node><para><para/><para/><foo><para/></foo></para><foo/><para/></node>")
{
xml_node c;
xml_node n = doc.child(STR("node"));
CHECK_XPATH_NODESET(c, STR("descendant-or-self::para"));
CHECK_XPATH_NODESET(n, STR("descendant-or-self::para")) % 3 % 4 % 5 % 7 % 9;
CHECK_XPATH_NODESET(n.child(STR("para")), STR("descendant-or-self::para")) % 3 % 4 % 5 % 7;
}
TEST_XML(xpath_paths_w3c_11, "<node><para><para/><para/><foo><para/></foo></para><foo/><para/></node>")
{
xml_node c;
xml_node n = doc.child(STR("node"));
CHECK_XPATH_NODESET(c, STR("self::para"));
CHECK_XPATH_NODESET(n, STR("self::para"));
CHECK_XPATH_NODESET(n.child(STR("para")), STR("self::para")) % 3;
}
TEST_XML(xpath_paths_w3c_12, "<chapter><para><para/><para/><foo><para/></foo></para><foo/><para/></chapter>")
{
xml_node c;
CHECK_XPATH_NODESET(c, STR("child::chapter/descendant::para"));
CHECK_XPATH_NODESET(doc, STR("child::chapter/descendant::para")) % 3 % 4 % 5 % 7 % 9;
}
TEST_XML(xpath_paths_w3c_13, "<node><para><para/><para/><foo><para/></foo></para><foo/><para/></node>")
{
xml_node c;
CHECK_XPATH_NODESET(c, STR("child::*/child::para"));
CHECK_XPATH_NODESET(doc, STR("child::*/child::para")) % 3 % 9;
}
TEST_XML(xpath_paths_w3c_14, "<node><para><para/><para/><foo><para/></foo></para><foo/><para/></node>")
{
xml_node c;
xml_node n = doc.child(STR("node"));
CHECK_XPATH_NODESET(c, STR("/"));
CHECK_XPATH_NODESET(doc, STR("/")) % 1;
CHECK_XPATH_NODESET(n, STR("/")) % 1;
CHECK_XPATH_NODESET(n.child(STR("para")), STR("/")) % 1;
}
TEST_XML(xpath_paths_w3c_15, "<node><para><para/><para/><foo><para/></foo></para><foo/><para/></node>")
{
xml_node c;
xml_node n = doc.child(STR("node"));
CHECK_XPATH_NODESET(c, STR("/descendant::para"));
CHECK_XPATH_NODESET(n, STR("/descendant::para")) % 3 % 4 % 5 % 7 % 9;
CHECK_XPATH_NODESET(n.child(STR("para")), STR("/descendant::para")) % 3 % 4 % 5 % 7 % 9;
}
TEST_XML(xpath_paths_w3c_16, "<node><olist><item/></olist><item/><olist><olist><item/><item/></olist></olist></node>")
{
xml_node c;
xml_node n = doc.child(STR("node"));
CHECK_XPATH_NODESET(c, STR("/descendant::olist/child::item"));
CHECK_XPATH_NODESET(n, STR("/descendant::olist/child::item")) % 4 % 8 % 9;
CHECK_XPATH_NODESET(n.child(STR("olist")), STR("/descendant::olist/child::item")) % 4 % 8 % 9;
}
TEST_XML(xpath_paths_w3c_17, "<node><para/><para/><para/><para/></node>")
{
xml_node c;
xml_node n = doc.child(STR("node"));
CHECK_XPATH_NODESET(c, STR("child::para[position()=1]"));
CHECK_XPATH_NODESET(n, STR("child::para[position()=1]")) % 3;
}
TEST_XML(xpath_paths_w3c_18, "<node><para/><para/><para/><para/></node>")
{
xml_node c;
xml_node n = doc.child(STR("node"));
CHECK_XPATH_NODESET(c, STR("child::para[position()=last()]"));
CHECK_XPATH_NODESET(n, STR("child::para[position()=last()]")) % 6;
}
TEST_XML(xpath_paths_w3c_19, "<node><para/><para/><para/><para/></node>")
{
xml_node c;
xml_node n = doc.child(STR("node"));
CHECK_XPATH_NODESET(c, STR("child::para[position()=last()-1]"));
CHECK_XPATH_NODESET(n, STR("child::para[position()=last()-1]")) % 5;
}
TEST_XML(xpath_paths_w3c_20, "<node><para/><para/><para/><para/></node>")
{
xml_node c;
xml_node n = doc.child(STR("node"));
CHECK_XPATH_NODESET(c, STR("child::para[position()>1]"));
CHECK_XPATH_NODESET(n, STR("child::para[position()>1]")) % 4 % 5 % 6;
}
TEST_XML(xpath_paths_w3c_21, "<node><chapter/><chapter/><chapter/><chapter/><chapter/></node>")
{
xml_node c;
xml_node n = doc.child(STR("node")).child(STR("chapter")).next_sibling().next_sibling();
CHECK_XPATH_NODESET(c, STR("following-sibling::chapter[position()=1]"));
CHECK_XPATH_NODESET(n, STR("following-sibling::chapter[position()=1]")) % 6;
}
TEST_XML(xpath_paths_w3c_22, "<node><chapter/><chapter/><chapter/><chapter/><chapter/></node>")
{
xml_node c;
xml_node n = doc.child(STR("node")).child(STR("chapter")).next_sibling().next_sibling();
CHECK_XPATH_NODESET(c, STR("preceding-sibling::chapter[position()=1]"));
CHECK_XPATH_NODESET(n, STR("preceding-sibling::chapter[position()=1]")) % 4;
}
TEST_XML(xpath_paths_w3c_23, "<node><figure><figure/><figure/><foo><figure/></foo></figure><foo/><figure/></node>")
{
xml_node c;
xml_node n = doc.child(STR("node"));
CHECK_XPATH_NODESET(c, STR("/descendant::figure[position()=4]"));
CHECK_XPATH_NODESET(n, STR("/descendant::figure[position()=4]")) % 7;
CHECK_XPATH_NODESET(n.child(STR("figure")), STR("/descendant::figure[position()=4]")) % 7;
}
TEST_XML(xpath_paths_w3c_24, "<doc><chapter/><chapter/><chapter/><chapter/><chapter><section/><section/><section/></chapter><chapter/></doc>")
{
xml_node c;
xml_node n = doc.child(STR("doc")).child(STR("chapter"));
CHECK_XPATH_NODESET(c, STR("/child::doc/child::chapter[position()=5]/child::section[position()=2]"));
CHECK_XPATH_NODESET(n, STR("/child::doc/child::chapter[position()=5]/child::section[position()=2]")) % 9;
CHECK_XPATH_NODESET(doc, STR("/child::doc/child::chapter[position()=5]/child::section[position()=2]")) % 9;
}
TEST_XML(xpath_paths_w3c_25, "<node><para/><para type='warning'/><para type='warning'/><para/><para type='error'/><para type='warning'/><para type='warning'/><para type='warning'/></node>")
{
xml_node c;
xml_node n = doc.child(STR("node"));
CHECK_XPATH_NODESET(c, STR("child::para[attribute::type=\"warning\"]"));
CHECK_XPATH_NODESET(n, STR("child::para[attribute::type=\"warning\"]")) % 4 % 6 % 11 % 13 % 15;
}
TEST_XML(xpath_paths_w3c_26, "<node><para/><para type='warning'/><para type='warning'/><para/><para type='error'/><para type='warning'/><para type='warning'/><para type='warning'/></node>")
{
xml_node c;
xml_node n = doc.child(STR("node"));
CHECK_XPATH_NODESET(c, STR("child::para[attribute::type=\"warning\"][position()=5]"));
CHECK_XPATH_NODESET(n, STR("child::para[attribute::type=\"warning\"][position()=5]")) % 15;
}
TEST_XML(xpath_paths_w3c_27a, "<node><para/><para type='warning'/><para type='warning'/><para/><para type='error'/><para type='warning'/><para type='warning'/><para type='warning'/></node>")
{
xml_node c;
xml_node n = doc.child(STR("node"));
CHECK_XPATH_NODESET(c, STR("child::para[position()=5][attribute::type=\"warning\"]"));
CHECK_XPATH_NODESET(n, STR("child::para[position()=5][attribute::type=\"warning\"]"));
}
TEST_XML(xpath_paths_w3c_27b, "<node><para/><para type='warning'/><para type='warning'/><para/><para type='warning'/><para type='warning'/><para type='warning'/></node>")
{
xml_node c;
xml_node n = doc.child(STR("node"));
CHECK_XPATH_NODESET(c, STR("child::para[position()=5][attribute::type=\"warning\"]"));
CHECK_XPATH_NODESET(n, STR("child::para[position()=5][attribute::type=\"warning\"]")) % 9;
}
TEST_XML(xpath_paths_w3c_28, "<node><chapter><title>foo</title></chapter><chapter><title>Introduction</title></chapter><chapter><title>introduction</title></chapter><chapter/><chapter><title>Introduction</title><title>foo</title></chapter></node>")
{
xml_node c;
xml_node n = doc.child(STR("node"));
CHECK_XPATH_NODESET(c, STR("child::chapter[child::title='Introduction']"));
CHECK_XPATH_NODESET(n, STR("child::chapter[child::title='Introduction']")) % 6 % 13;
}
TEST_XML(xpath_paths_w3c_29, "<node><chapter><title>foo</title></chapter><chapter><title>Introduction</title></chapter><chapter><title>introduction</title></chapter><chapter/><chapter><title>Introduction</title><title>foo</title></chapter></node>")
{
xml_node c;
xml_node n = doc.child(STR("node"));
CHECK_XPATH_NODESET(c, STR("child::chapter[child::title]"));
CHECK_XPATH_NODESET(n, STR("child::chapter[child::title]")) % 3 % 6 % 9 % 13;
}
TEST_XML(xpath_paths_w3c_30, "<node><abstract/><chapter/><chapter/><references/><appendix/></node>")
{
xml_node c;
xml_node n = doc.child(STR("node"));
CHECK_XPATH_NODESET(c, STR("child::*[self::chapter or self::appendix]"));
CHECK_XPATH_NODESET(n, STR("child::*[self::chapter or self::appendix]")) % 4 % 5 % 7;
}
TEST_XML(xpath_paths_w3c_31a, "<node><abstract/><chapter/><chapter/><references/><appendix/></node>")
{
xml_node c;
xml_node n = doc.child(STR("node"));
CHECK_XPATH_NODESET(c, STR("child::*[self::chapter or self::appendix][position()=last()]"));
CHECK_XPATH_NODESET(n, STR("child::*[self::chapter or self::appendix][position()=last()]")) % 7;
}
TEST_XML(xpath_paths_w3c_31b, "<node><abstract/><chapter/><chapter/><references/><appendix/><chapter/></node>")
{
xml_node c;
xml_node n = doc.child(STR("node"));
CHECK_XPATH_NODESET(c, STR("child::*[self::chapter or self::appendix][position()=last()]"));
CHECK_XPATH_NODESET(n, STR("child::*[self::chapter or self::appendix][position()=last()]")) % 8;
}
#endif
#ifndef PUGIXML_NO_XPATH
#include "test.hpp"
using namespace pugi;
TEST_XML(xpath_paths_w3c_1, "<node><para/><foo/><para/></node>")
{
xml_node c;
xml_node n = doc.child(STR("node"));
CHECK_XPATH_NODESET(c, STR("child::para"));
CHECK_XPATH_NODESET(n, STR("child::para")) % 3 % 5;
}
TEST_XML(xpath_paths_w3c_2, "<node><para/><foo/><para/></node>")
{
xml_node c;
xml_node n = doc.child(STR("node"));
CHECK_XPATH_NODESET(c, STR("child::*"));
CHECK_XPATH_NODESET(n, STR("child::*")) % 3 % 4 % 5;
}
TEST_XML(xpath_paths_w3c_3, "<node>pcdata<child/><![CDATA[cdata]]></node>")
{
xml_node c;
xml_node n = doc.child(STR("node"));
CHECK_XPATH_NODESET(c, STR("child::text()"));
CHECK_XPATH_NODESET(n, STR("child::text()")) % 3 % 5;
}
TEST_XML(xpath_paths_w3c_4, "<node>pcdata<child/><![CDATA[cdata]]></node>")
{
xml_node c;
xml_node n = doc.child(STR("node"));
CHECK_XPATH_NODESET(c, STR("child::node()"));
CHECK_XPATH_NODESET(n, STR("child::node()")) % 3 % 4 % 5;
}
TEST_XML(xpath_paths_w3c_5, "<node name='value' foo='bar' />")
{
xml_node c;
xml_node n = doc.child(STR("node"));
CHECK_XPATH_NODESET(c, STR("attribute::name"));
CHECK_XPATH_NODESET(n, STR("attribute::name")) % 3;
}
TEST_XML(xpath_paths_w3c_6, "<node name='value' foo='bar' />")
{
xml_node c;
xml_node n = doc.child(STR("node"));
CHECK_XPATH_NODESET(c, STR("attribute::*"));
CHECK_XPATH_NODESET(n, STR("attribute::*")) % 3 % 4;
}
TEST_XML(xpath_paths_w3c_7, "<node><para><para/><para/><foo><para/></foo></para><foo/><para/></node>")
{
xml_node c;
xml_node n = doc.child(STR("node"));
CHECK_XPATH_NODESET(c, STR("descendant::para"));
CHECK_XPATH_NODESET(n, STR("descendant::para")) % 3 % 4 % 5 % 7 % 9;
CHECK_XPATH_NODESET(n.child(STR("para")), STR("descendant::para")) % 4 % 5 % 7;
}
TEST_XML(xpath_paths_w3c_8, "<node><div><font><div><div/></div></font></div></node>")
{
xml_node c;
xml_node n = doc.child(STR("node"));
CHECK_XPATH_NODESET(c, STR("ancestor::div"));
CHECK_XPATH_NODESET(n.child(STR("div")).child(STR("font")).child(STR("div")).child(STR("div")), STR("ancestor::div")) % 5 % 3;
}
TEST_XML(xpath_paths_w3c_9, "<node><div><font><div><div/></div></font></div></node>")
{
xml_node c;
xml_node n = doc.child(STR("node"));
CHECK_XPATH_NODESET(c, STR("ancestor-or-self::div"));
CHECK_XPATH_NODESET(n.child(STR("div")).child(STR("font")).child(STR("div")).child(STR("div")), STR("ancestor-or-self::div")) % 6 % 5 % 3;
}
TEST_XML(xpath_paths_w3c_10, "<node><para><para/><para/><foo><para/></foo></para><foo/><para/></node>")
{
xml_node c;
xml_node n = doc.child(STR("node"));
CHECK_XPATH_NODESET(c, STR("descendant-or-self::para"));
CHECK_XPATH_NODESET(n, STR("descendant-or-self::para")) % 3 % 4 % 5 % 7 % 9;
CHECK_XPATH_NODESET(n.child(STR("para")), STR("descendant-or-self::para")) % 3 % 4 % 5 % 7;
}
TEST_XML(xpath_paths_w3c_11, "<node><para><para/><para/><foo><para/></foo></para><foo/><para/></node>")
{
xml_node c;
xml_node n = doc.child(STR("node"));
CHECK_XPATH_NODESET(c, STR("self::para"));
CHECK_XPATH_NODESET(n, STR("self::para"));
CHECK_XPATH_NODESET(n.child(STR("para")), STR("self::para")) % 3;
}
TEST_XML(xpath_paths_w3c_12, "<chapter><para><para/><para/><foo><para/></foo></para><foo/><para/></chapter>")
{
xml_node c;
CHECK_XPATH_NODESET(c, STR("child::chapter/descendant::para"));
CHECK_XPATH_NODESET(doc, STR("child::chapter/descendant::para")) % 3 % 4 % 5 % 7 % 9;
}
TEST_XML(xpath_paths_w3c_13, "<node><para><para/><para/><foo><para/></foo></para><foo/><para/></node>")
{
xml_node c;
CHECK_XPATH_NODESET(c, STR("child::*/child::para"));
CHECK_XPATH_NODESET(doc, STR("child::*/child::para")) % 3 % 9;
}
TEST_XML(xpath_paths_w3c_14, "<node><para><para/><para/><foo><para/></foo></para><foo/><para/></node>")
{
xml_node c;
xml_node n = doc.child(STR("node"));
CHECK_XPATH_NODESET(c, STR("/"));
CHECK_XPATH_NODESET(doc, STR("/")) % 1;
CHECK_XPATH_NODESET(n, STR("/")) % 1;
CHECK_XPATH_NODESET(n.child(STR("para")), STR("/")) % 1;
}
TEST_XML(xpath_paths_w3c_15, "<node><para><para/><para/><foo><para/></foo></para><foo/><para/></node>")
{
xml_node c;
xml_node n = doc.child(STR("node"));
CHECK_XPATH_NODESET(c, STR("/descendant::para"));
CHECK_XPATH_NODESET(n, STR("/descendant::para")) % 3 % 4 % 5 % 7 % 9;
CHECK_XPATH_NODESET(n.child(STR("para")), STR("/descendant::para")) % 3 % 4 % 5 % 7 % 9;
}
TEST_XML(xpath_paths_w3c_16, "<node><olist><item/></olist><item/><olist><olist><item/><item/></olist></olist></node>")
{
xml_node c;
xml_node n = doc.child(STR("node"));
CHECK_XPATH_NODESET(c, STR("/descendant::olist/child::item"));
CHECK_XPATH_NODESET(n, STR("/descendant::olist/child::item")) % 4 % 8 % 9;
CHECK_XPATH_NODESET(n.child(STR("olist")), STR("/descendant::olist/child::item")) % 4 % 8 % 9;
}
TEST_XML(xpath_paths_w3c_17, "<node><para/><para/><para/><para/></node>")
{
xml_node c;
xml_node n = doc.child(STR("node"));
CHECK_XPATH_NODESET(c, STR("child::para[position()=1]"));
CHECK_XPATH_NODESET(n, STR("child::para[position()=1]")) % 3;
}
TEST_XML(xpath_paths_w3c_18, "<node><para/><para/><para/><para/></node>")
{
xml_node c;
xml_node n = doc.child(STR("node"));
CHECK_XPATH_NODESET(c, STR("child::para[position()=last()]"));
CHECK_XPATH_NODESET(n, STR("child::para[position()=last()]")) % 6;
}
TEST_XML(xpath_paths_w3c_19, "<node><para/><para/><para/><para/></node>")
{
xml_node c;
xml_node n = doc.child(STR("node"));
CHECK_XPATH_NODESET(c, STR("child::para[position()=last()-1]"));
CHECK_XPATH_NODESET(n, STR("child::para[position()=last()-1]")) % 5;
}
TEST_XML(xpath_paths_w3c_20, "<node><para/><para/><para/><para/></node>")
{
xml_node c;
xml_node n = doc.child(STR("node"));
CHECK_XPATH_NODESET(c, STR("child::para[position()>1]"));
CHECK_XPATH_NODESET(n, STR("child::para[position()>1]")) % 4 % 5 % 6;
}
TEST_XML(xpath_paths_w3c_21, "<node><chapter/><chapter/><chapter/><chapter/><chapter/></node>")
{
xml_node c;
xml_node n = doc.child(STR("node")).child(STR("chapter")).next_sibling().next_sibling();
CHECK_XPATH_NODESET(c, STR("following-sibling::chapter[position()=1]"));
CHECK_XPATH_NODESET(n, STR("following-sibling::chapter[position()=1]")) % 6;
}
TEST_XML(xpath_paths_w3c_22, "<node><chapter/><chapter/><chapter/><chapter/><chapter/></node>")
{
xml_node c;
xml_node n = doc.child(STR("node")).child(STR("chapter")).next_sibling().next_sibling();
CHECK_XPATH_NODESET(c, STR("preceding-sibling::chapter[position()=1]"));
CHECK_XPATH_NODESET(n, STR("preceding-sibling::chapter[position()=1]")) % 4;
}
TEST_XML(xpath_paths_w3c_23, "<node><figure><figure/><figure/><foo><figure/></foo></figure><foo/><figure/></node>")
{
xml_node c;
xml_node n = doc.child(STR("node"));
CHECK_XPATH_NODESET(c, STR("/descendant::figure[position()=4]"));
CHECK_XPATH_NODESET(n, STR("/descendant::figure[position()=4]")) % 7;
CHECK_XPATH_NODESET(n.child(STR("figure")), STR("/descendant::figure[position()=4]")) % 7;
}
TEST_XML(xpath_paths_w3c_24, "<doc><chapter/><chapter/><chapter/><chapter/><chapter><section/><section/><section/></chapter><chapter/></doc>")
{
xml_node c;
xml_node n = doc.child(STR("doc")).child(STR("chapter"));
CHECK_XPATH_NODESET(c, STR("/child::doc/child::chapter[position()=5]/child::section[position()=2]"));
CHECK_XPATH_NODESET(n, STR("/child::doc/child::chapter[position()=5]/child::section[position()=2]")) % 9;
CHECK_XPATH_NODESET(doc, STR("/child::doc/child::chapter[position()=5]/child::section[position()=2]")) % 9;
}
TEST_XML(xpath_paths_w3c_25, "<node><para/><para type='warning'/><para type='warning'/><para/><para type='error'/><para type='warning'/><para type='warning'/><para type='warning'/></node>")
{
xml_node c;
xml_node n = doc.child(STR("node"));
CHECK_XPATH_NODESET(c, STR("child::para[attribute::type=\"warning\"]"));
CHECK_XPATH_NODESET(n, STR("child::para[attribute::type=\"warning\"]")) % 4 % 6 % 11 % 13 % 15;
}
TEST_XML(xpath_paths_w3c_26, "<node><para/><para type='warning'/><para type='warning'/><para/><para type='error'/><para type='warning'/><para type='warning'/><para type='warning'/></node>")
{
xml_node c;
xml_node n = doc.child(STR("node"));
CHECK_XPATH_NODESET(c, STR("child::para[attribute::type=\"warning\"][position()=5]"));
CHECK_XPATH_NODESET(n, STR("child::para[attribute::type=\"warning\"][position()=5]")) % 15;
}
TEST_XML(xpath_paths_w3c_27a, "<node><para/><para type='warning'/><para type='warning'/><para/><para type='error'/><para type='warning'/><para type='warning'/><para type='warning'/></node>")
{
xml_node c;
xml_node n = doc.child(STR("node"));
CHECK_XPATH_NODESET(c, STR("child::para[position()=5][attribute::type=\"warning\"]"));
CHECK_XPATH_NODESET(n, STR("child::para[position()=5][attribute::type=\"warning\"]"));
}
TEST_XML(xpath_paths_w3c_27b, "<node><para/><para type='warning'/><para type='warning'/><para/><para type='warning'/><para type='warning'/><para type='warning'/></node>")
{
xml_node c;
xml_node n = doc.child(STR("node"));
CHECK_XPATH_NODESET(c, STR("child::para[position()=5][attribute::type=\"warning\"]"));
CHECK_XPATH_NODESET(n, STR("child::para[position()=5][attribute::type=\"warning\"]")) % 9;
}
TEST_XML(xpath_paths_w3c_28, "<node><chapter><title>foo</title></chapter><chapter><title>Introduction</title></chapter><chapter><title>introduction</title></chapter><chapter/><chapter><title>Introduction</title><title>foo</title></chapter></node>")
{
xml_node c;
xml_node n = doc.child(STR("node"));
CHECK_XPATH_NODESET(c, STR("child::chapter[child::title='Introduction']"));
CHECK_XPATH_NODESET(n, STR("child::chapter[child::title='Introduction']")) % 6 % 13;
}
TEST_XML(xpath_paths_w3c_29, "<node><chapter><title>foo</title></chapter><chapter><title>Introduction</title></chapter><chapter><title>introduction</title></chapter><chapter/><chapter><title>Introduction</title><title>foo</title></chapter></node>")
{
xml_node c;
xml_node n = doc.child(STR("node"));
CHECK_XPATH_NODESET(c, STR("child::chapter[child::title]"));
CHECK_XPATH_NODESET(n, STR("child::chapter[child::title]")) % 3 % 6 % 9 % 13;
}
TEST_XML(xpath_paths_w3c_30, "<node><abstract/><chapter/><chapter/><references/><appendix/></node>")
{
xml_node c;
xml_node n = doc.child(STR("node"));
CHECK_XPATH_NODESET(c, STR("child::*[self::chapter or self::appendix]"));
CHECK_XPATH_NODESET(n, STR("child::*[self::chapter or self::appendix]")) % 4 % 5 % 7;
}
TEST_XML(xpath_paths_w3c_31a, "<node><abstract/><chapter/><chapter/><references/><appendix/></node>")
{
xml_node c;
xml_node n = doc.child(STR("node"));
CHECK_XPATH_NODESET(c, STR("child::*[self::chapter or self::appendix][position()=last()]"));
CHECK_XPATH_NODESET(n, STR("child::*[self::chapter or self::appendix][position()=last()]")) % 7;
}
TEST_XML(xpath_paths_w3c_31b, "<node><abstract/><chapter/><chapter/><references/><appendix/><chapter/></node>")
{
xml_node c;
xml_node n = doc.child(STR("node"));
CHECK_XPATH_NODESET(c, STR("child::*[self::chapter or self::appendix][position()=last()]"));
CHECK_XPATH_NODESET(n, STR("child::*[self::chapter or self::appendix][position()=last()]")) % 8;
}
#endif

File diff suppressed because it is too large Load Diff

View File

@ -1,411 +1,411 @@
#ifndef PUGIXML_NO_XPATH
#include "test.hpp"
using namespace pugi;
TEST(xpath_xalan_boolean_1)
{
xml_node c;
CHECK_XPATH_BOOLEAN(c, STR("true()"), true);
CHECK_XPATH_BOOLEAN(c, STR("true() and true()"), true);
CHECK_XPATH_BOOLEAN(c, STR("true() or true()"), true);
CHECK_XPATH_BOOLEAN(c, STR("not(true())"), false);
CHECK_XPATH_BOOLEAN(c, STR("boolean('')"), false);
CHECK_XPATH_BOOLEAN(c, STR("1>2"), false);
CHECK_XPATH_BOOLEAN(c, STR("1>=2"), false);
CHECK_XPATH_BOOLEAN(c, STR("false()"), false);
CHECK_XPATH_BOOLEAN(c, STR("1=1"), true);
CHECK_XPATH_BOOLEAN(c, STR("1=2"), false);
CHECK_XPATH_BOOLEAN(c, STR("1 = 1.00"), true);
CHECK_XPATH_BOOLEAN(c, STR("0 = -0"), true);
CHECK_XPATH_BOOLEAN(c, STR("1 = '001'"), true);
CHECK_XPATH_BOOLEAN(c, STR("true()='0'"), true);
CHECK_XPATH_BOOLEAN(c, STR("false()=''"), true);
CHECK_XPATH_BOOLEAN(c, STR("true()=2"), true);
CHECK_XPATH_BOOLEAN(c, STR("false()=0"), true);
CHECK_XPATH_BOOLEAN(c, STR("false() and false()"), false);
CHECK_XPATH_BOOLEAN(c, STR("'foo' and 'fop'"), true);
CHECK_XPATH_BOOLEAN(c, STR("true() and false()"), false);
CHECK_XPATH_BOOLEAN(c, STR("false() and true()"), false);
CHECK_XPATH_BOOLEAN(c, STR("'1' and '0'"), true);
CHECK_XPATH_BOOLEAN(c, STR("true() or false()"), true);
CHECK_XPATH_BOOLEAN(c, STR("false() or true()"), true);
CHECK_XPATH_BOOLEAN(c, STR("false() or false()"), false);
CHECK_XPATH_BOOLEAN(c, STR("0 or ''"), false);
CHECK_XPATH_BOOLEAN(c, STR("not(false())"), true);
CHECK_XPATH_BOOLEAN(c, STR("not(false() = false())"), false);
CHECK_XPATH_BOOLEAN(c, STR("not(true() = false())"), true);
CHECK_XPATH_BOOLEAN(c, STR("not('')"), true);
CHECK_XPATH_BOOLEAN(c, STR("not('0')"), false);
CHECK_XPATH_BOOLEAN(c, STR("boolean('0')"), true);
CHECK_XPATH_BOOLEAN(c, STR("boolean(0)"), false);
CHECK_XPATH_BOOLEAN(c, STR("boolean(-0)"), false);
CHECK_XPATH_BOOLEAN(c, STR("boolean(1)"), true);
CHECK_XPATH_BOOLEAN(c, STR("boolean(1 div 0)"), true);
CHECK_XPATH_BOOLEAN(c, STR("boolean(0 div 0)"), false);
}
TEST_XML(xpath_xalan_boolean_2, "<doc/>")
{
CHECK_XPATH_BOOLEAN(doc, STR("boolean(doc)"), true);
CHECK_XPATH_BOOLEAN(doc, STR("boolean(foo)"), false);
}
TEST(xpath_xalan_boolean_3)
{
xml_node c;
CHECK_XPATH_BOOLEAN(c, STR("1>1"), false);
CHECK_XPATH_BOOLEAN(c, STR("2>1"), true);
CHECK_XPATH_BOOLEAN(c, STR("1<2"), true);
CHECK_XPATH_BOOLEAN(c, STR("1<1"), false);
CHECK_XPATH_BOOLEAN(c, STR("2<1"), false);
CHECK_XPATH_BOOLEAN(c, STR("'2'>'1'"), true);
CHECK_XPATH_BOOLEAN(c, STR("0 > -0"), false);
CHECK_XPATH_BOOLEAN(c, STR("2>=2"), true);
CHECK_XPATH_BOOLEAN(c, STR("2>=1"), true);
CHECK_XPATH_BOOLEAN(c, STR("1<=2"), true);
CHECK_XPATH_BOOLEAN(c, STR("1<=1"), true);
CHECK_XPATH_BOOLEAN(c, STR("2<=1"), false);
CHECK_XPATH_BOOLEAN(c, STR("false() and 1 div 0"), false);
CHECK_XPATH_BOOLEAN(c, STR("true() or 1 div 0"), true);
CHECK_XPATH_BOOLEAN(c, STR("1!=1"), false);
CHECK_XPATH_BOOLEAN(c, STR("1!=2"), true);
CHECK_XPATH_BOOLEAN(c, STR("1!=1.00"), false);
CHECK_XPATH_BOOLEAN(c, STR("false()!=true()"), true);
CHECK_XPATH_BOOLEAN(c, STR("true()!=false()"), true);
CHECK_XPATH_BOOLEAN(c, STR("false()!=false()"), false);
CHECK_XPATH_BOOLEAN(c, STR("'ace' != 'ace'"), false);
CHECK_XPATH_BOOLEAN(c, STR("'ace' != 'abc'"), true);
CHECK_XPATH_BOOLEAN(c, STR("'H' != ' H'"), true);
CHECK_XPATH_BOOLEAN(c, STR("'H' != 'H '"), true);
CHECK_XPATH_BOOLEAN(c, STR("1.9999999 < 2.0"), true);
CHECK_XPATH_BOOLEAN(c, STR("2.0000001 < 2.0"), false);
CHECK_XPATH_BOOLEAN(c, STR("1.9999999 < 2"), true);
CHECK_XPATH_BOOLEAN(c, STR("2 < 2.0"), false);
CHECK_XPATH_BOOLEAN(c, STR("'001' = 1"), true);
CHECK_XPATH_BOOLEAN(c, STR("0=false()"), true);
CHECK_XPATH_BOOLEAN(c, STR("'0'=true()"), true);
}
TEST_XML(xpath_xalan_boolean_4, "<avj><a>foo</a><b>bar</b><c>foobar</c><d>foo</d></avj>")
{
CHECK_XPATH_BOOLEAN(doc, STR("avj/*='foo'"), true);
CHECK_XPATH_BOOLEAN(doc, STR("not(avj/*='foo')"), false);
CHECK_XPATH_BOOLEAN(doc, STR("avj/*!='foo'"), true);
CHECK_XPATH_BOOLEAN(doc, STR("not(avj/*!='foo')"), false);
CHECK_XPATH_BOOLEAN(doc, STR("avj/k='foo'"), false);
CHECK_XPATH_BOOLEAN(doc, STR("not(avj/k='foo')"), true);
CHECK_XPATH_BOOLEAN(doc, STR("avj/k!='foo'"), false);
CHECK_XPATH_BOOLEAN(doc, STR("not(avj/k!='foo')"), true);
}
TEST_XML(xpath_xalan_boolean_5, "<doc><j l='12' w='33'>first</j><j l='17' w='45'>second</j><j l='16' w='78'>third</j><j l='12' w='33'>fourth</j></doc>")
{
xml_node c = doc.child(STR("doc"));
CHECK_XPATH_BOOLEAN(c, STR("j[@l='12'] = j[@w='33']"), true);
CHECK_XPATH_BOOLEAN(c, STR("j[@l='12'] = j[@l='17']"), false);
CHECK_XPATH_BOOLEAN(c, STR("j[@l='12'] = j[.='first' or @w='45']"), true);
CHECK_XPATH_BOOLEAN(c, STR("j[@l='12'] != j[@w='33']"), true);
CHECK_XPATH_BOOLEAN(c, STR("j[@l='12'] != j[@l='17']"), true);
CHECK_XPATH_BOOLEAN(c, STR("j[@l='12'] != j[.='first' or @w='45']"), true);
CHECK_XPATH_BOOLEAN(c, STR("j[@l='16'] != j[@w='78']"), false);
}
TEST_XML(xpath_xalan_boolean_6, "<doc><avj><good><b>12</b><c>34</c><d>56</d><e>78</e></good></avj></doc>")
{
xml_node c = doc.child(STR("doc"));
CHECK_XPATH_BOOLEAN(c, STR("avj/good/*=34"), true);
CHECK_XPATH_BOOLEAN(c, STR("not(avj/good/*=34)"), false);
CHECK_XPATH_BOOLEAN(c, STR("avj/good/*!=34"), true);
CHECK_XPATH_BOOLEAN(c, STR("not(avj/good/*!=34)"), false);
CHECK_XPATH_BOOLEAN(c, STR("34=avj/good/*"), true);
CHECK_XPATH_BOOLEAN(c, STR("not(34=avj/good/*)"), false);
CHECK_XPATH_BOOLEAN(c, STR("34!=avj/good/*"), true);
CHECK_XPATH_BOOLEAN(c, STR("not(34!=avj/good/*)"), false);
}
TEST_XML(xpath_xalan_boolean_7, "<doc><avj><bool><b>true</b><c></c><d>false?</d><e>1</e><f>0</f></bool></avj></doc>")
{
xml_node c = doc.child(STR("doc"));
CHECK_XPATH_BOOLEAN(c, STR("avj/bool/*=true()"), true);
CHECK_XPATH_BOOLEAN(c, STR("not(avj/bool/*=true())"), false);
CHECK_XPATH_BOOLEAN(c, STR("avj/bool/*!=true()"), false);
CHECK_XPATH_BOOLEAN(c, STR("not(avj/bool/*!=true())"), true);
CHECK_XPATH_BOOLEAN(c, STR("true()=avj/bool/*"), true);
CHECK_XPATH_BOOLEAN(c, STR("not(true()=avj/bool/*)"), false);
CHECK_XPATH_BOOLEAN(c, STR("true()!=avj/bool/*"), false);
CHECK_XPATH_BOOLEAN(c, STR("not(true()!=avj/bool/*)"), true);
CHECK_XPATH_BOOLEAN(c, STR("avj/none/*=true()"), false);
CHECK_XPATH_BOOLEAN(c, STR("not(avj/none/*=true())"), true);
CHECK_XPATH_BOOLEAN(c, STR("avj/none/*!=true()"), true);
CHECK_XPATH_BOOLEAN(c, STR("not(avj/none/*!=true())"), false);
CHECK_XPATH_BOOLEAN(c, STR("true()=avj/none/*"), false);
CHECK_XPATH_BOOLEAN(c, STR("not(true()=avj/none/*)"), true);
CHECK_XPATH_BOOLEAN(c, STR("true()!=avj/none/*"), true);
CHECK_XPATH_BOOLEAN(c, STR("not(true()!=avj/none/*)"), false);
}
TEST_XML(xpath_xalan_conditional, "<letters>b</letters>")
{
xml_node c;
CHECK_XPATH_BOOLEAN(c, STR("(round(3.7) > 3)"), true);
CHECK_XPATH_BOOLEAN(c, STR("2 > 1"), true);
CHECK_XPATH_BOOLEAN(c, STR("9 mod 3 = 0"), true);
CHECK_XPATH_BOOLEAN(c, STR("'a'='a'"), true);
CHECK_XPATH_BOOLEAN(c, STR("2+2=4"), true);
xml_node b = doc.child(STR("letters")).first_child();
CHECK_XPATH_BOOLEAN(b, STR(".='b'"), true);
CHECK_XPATH_BOOLEAN(b, STR("name(..)='letters'"), true);
}
TEST_XML(xpath_xalan_math_1, "<a>3</a>")
{
xml_node c;
CHECK_XPATH_NUMBER(c, STR("number('1')"), 1);
CHECK_XPATH_NUMBER(c, STR("floor(0.0)"), 0);
CHECK_XPATH_NUMBER(c, STR("ceiling(0.0)"), 0);
CHECK_XPATH_NUMBER(c, STR("round(0.0)"), 0);
CHECK_XPATH_NUMBER(c, STR("2*3"), 6);
CHECK_XPATH_NUMBER(c, STR("3+6"), 9);
CHECK_XPATH_NUMBER(c, STR("3-1"), 2);
CHECK_XPATH_NUMBER_NAN(doc, STR("a-1")); // a-1 is a name test, not arithmetic expression
CHECK_XPATH_NUMBER(doc, STR("a -1"), 2);
CHECK_XPATH_NUMBER(c, STR("6 div 2"), 3);
CHECK_XPATH_NUMBER(c, STR("5 mod 2"), 1);
CHECK_XPATH_NUMBER_NAN(c, STR("number(n)"));
CHECK_XPATH_NUMBER(c, STR("number(2)"), 2);
CHECK_XPATH_NUMBER(c, STR("number('3')"), 3);
CHECK_XPATH_NUMBER_NAN(c, STR("number('')"));
CHECK_XPATH_NUMBER_NAN(c, STR("number('abc')"));
CHECK_XPATH_BOOLEAN(c, STR("number(string(1.0))=1"), true);
CHECK_XPATH_BOOLEAN(c, STR("number(true())=1"), true);
CHECK_XPATH_BOOLEAN(c, STR("number(false())=0"), true);
#ifndef MSVC6_NAN_BUG
CHECK_XPATH_BOOLEAN(c, STR("number('xxx')=number('xxx')"), false);
CHECK_XPATH_BOOLEAN(c, STR("number('xxx')=0"), false);
#endif
CHECK_XPATH_NUMBER(doc, STR("floor(a)"), 3);
CHECK_XPATH_NUMBER(c, STR("floor(1.9)"), 1);
CHECK_XPATH_NUMBER(c, STR("floor(2.999999)"), 2);
CHECK_XPATH_NUMBER(c, STR("floor(-1.5)"), -2);
CHECK_XPATH_BOOLEAN(c, STR("floor(1)=1"), true);
CHECK_XPATH_BOOLEAN(c, STR("floor(1.9)=1"), true);
CHECK_XPATH_BOOLEAN(c, STR("floor(-1.5)=-2"), true);
CHECK_XPATH_NUMBER(doc, STR("ceiling(a)"), 3);
CHECK_XPATH_NUMBER(c, STR("ceiling(1.54)"), 2);
CHECK_XPATH_NUMBER(c, STR("ceiling(2.999999)"), 3);
CHECK_XPATH_NUMBER(c, STR("ceiling(3.000001)"), 4);
CHECK_XPATH_BOOLEAN(c, STR("ceiling(1)=1"), true);
CHECK_XPATH_BOOLEAN(c, STR("ceiling(1.1)=2"), true);
CHECK_XPATH_BOOLEAN(c, STR("ceiling(-1.5)=-1"), true);
}
TEST_XML(xpath_xalan_math_2, "<a>3</a>")
{
xml_node c;
CHECK_XPATH_NUMBER(doc, STR("round(a)"), 3);
CHECK_XPATH_NUMBER(c, STR("round(1.24)"), 1);
CHECK_XPATH_NUMBER(c, STR("round(2.999999)"), 3);
CHECK_XPATH_NUMBER(c, STR("round(3.000001)"), 3);
CHECK_XPATH_NUMBER(c, STR("round(1.1)"), 1);
CHECK_XPATH_NUMBER(c, STR("round(-1.1)"), -1);
CHECK_XPATH_NUMBER(c, STR("round(1.9)"), 2);
CHECK_XPATH_NUMBER(c, STR("round(-1.9)"), -2);
CHECK_XPATH_NUMBER(c, STR("round(1.5)"), 2);
CHECK_XPATH_NUMBER(c, STR("round(-1.5)"), -1);
CHECK_XPATH_NUMBER(c, STR("round(1.4999999)"), 1);
CHECK_XPATH_NUMBER(c, STR("round(-1.4999999)"), -1);
CHECK_XPATH_NUMBER(c, STR("round(1.5000001)"), 2);
CHECK_XPATH_NUMBER(c, STR("round(-1.5000001)"), -2);
}
TEST_XML(xpath_xalan_math_3, "<doc><n v='1'/><n>2</n><n v='3'/><n>4</n><n v='5'>5</n><e>17</e><e>-5</e><e>8</e><e>-37</e></doc>")
{
CHECK_XPATH_NUMBER(doc, STR("sum(doc/x)"), 0);
CHECK_XPATH_NUMBER_NAN(doc, STR("sum(doc/n)"));
CHECK_XPATH_NUMBER(doc, STR("sum(doc/n[text()])"), 11);
CHECK_XPATH_NUMBER(doc, STR("sum(doc/n/@v)"), 9);
CHECK_XPATH_NUMBER(doc, STR("sum(doc/e)"), -17);
}
TEST_XML(xpath_xalan_math_4, "<doc><n1 a='1'>2</n1><n2 a='2'>3</n2><n1-n2>123</n1-n2><n-1>72</n-1><n-2>12</n-2><div a='2'>5</div><mod a='5'>2</mod></doc>")
{
xml_node c = doc.child(STR("doc"));
CHECK_XPATH_NUMBER(c, STR("n1*n2"), 6);
CHECK_XPATH_NUMBER(c, STR("n1/@a*n2/@a"), 2);
CHECK_XPATH_NUMBER(c, STR("(n1/@a)*(n2/@a)"), 2);
CHECK_XPATH_NUMBER(c, STR("n1+n2"), 5);
CHECK_XPATH_NUMBER(c, STR("n1/@a+n2/@a"), 3);
CHECK_XPATH_NUMBER(c, STR("(n1/@a)+(n2/@a)"), 3);
CHECK_XPATH_NUMBER(c, STR("1-2"), -1);
CHECK_XPATH_NUMBER(c, STR("n1 - n2"), -1);
CHECK_XPATH_NUMBER(c, STR("n1-n2"), 123);
CHECK_XPATH_NUMBER(c, STR("n-1 - n-2"), 60);
CHECK_XPATH_NUMBER(c, STR("n-1 -n-2"), 60);
CHECK_XPATH_NUMBER(c, STR("7+-3"), 4);
CHECK_XPATH_NUMBER(c, STR("n-1+-n-2"), 60);
CHECK_XPATH_NUMBER(c, STR("7 - -3"), 10);
CHECK_XPATH_NUMBER(c, STR("n-1 - -n-2"), 84);
CHECK_XPATH_NUMBER(c, STR("-7 --3"), -4);
CHECK_XPATH_NUMBER(c, STR("-n-1 --n-2"), -60);
CHECK_XPATH_FAIL(STR("+7"));
CHECK_XPATH_FAIL(STR("7++3"));
CHECK_XPATH_FAIL(STR("7-+3"));
CHECK_XPATH_NUMBER(c, STR("6 div -2"), -3);
CHECK_XPATH_NUMBER(c, STR("n1 div n2"), 2.0 / 3.0);
CHECK_XPATH_NUMBER(c, STR("div div mod"), 2.5);
CHECK_XPATH_NUMBER(c, STR("div/@a div mod/@a"), 0.4);
CHECK_XPATH_BOOLEAN(c, STR("1 div -0 = 2 div -0"), true);
CHECK_XPATH_BOOLEAN(c, STR("1 div -0 = 1 div 0"), false);
CHECK_XPATH_BOOLEAN(c, STR("1 div -0 = -1 div 0"), true);
#ifndef MSVC6_NAN_BUG
CHECK_XPATH_BOOLEAN(c, STR("0 div 0 >= 0"), false);
CHECK_XPATH_BOOLEAN(c, STR("0 div 0 < 0"), false);
#endif
CHECK_XPATH_NUMBER(c, STR("n1 mod n2"), 2);
CHECK_XPATH_NUMBER(c, STR("div mod mod"), 1);
CHECK_XPATH_NUMBER(c, STR("div/@a mod mod/@a"), 2);
CHECK_XPATH_BOOLEAN(c, STR("(5 mod 2 = 1) and (5 mod -2 = 1) and (-5 mod 2 = -1) and (-5 mod -2 = -1)"), true);
}
TEST(xpath_xalan_math_5)
{
xml_node c;
CHECK_XPATH_NUMBER(c, STR("(((((('3'+5)*(3)+((('2')+2)*('1' - 6)))-('4' - '2'))+(-(4-6)))))"), 4);
CHECK_XPATH_NUMBER(c, STR("1*1*2*2*2*3*3*1*1*1*0.5*0.5"), 18);
CHECK_XPATH_NUMBER(c, STR("1440 div 2 div 2 div 6"), 60);
CHECK_XPATH_NUMBER(c, STR("1440 div 2 div 2 div 6 div 10"), 6);
CHECK_XPATH_NUMBER(c, STR("1440 div 2 div 2 div 6 div 10 div 3"), 2);
CHECK_XPATH_NUMBER(c, STR("(1*2*3*4*5*6)div 2 div 6 div 10 div 3"), 2);
CHECK_XPATH_NUMBER_NAN(c, STR("(2 + number('xxx'))"));
CHECK_XPATH_NUMBER_NAN(c, STR("2 * -number('xxx')"));
CHECK_XPATH_NUMBER_NAN(c, STR("2 - number('xxx')"));
CHECK_XPATH_NUMBER_NAN(c, STR("number('xxx') - 3"));
CHECK_XPATH_NUMBER_NAN(c, STR("2 div number('xxx')"));
CHECK_XPATH_NUMBER_NAN(c, STR("number('xxx') div 3"));
#ifndef __BORLANDC__ // BCC fmod does not propagate NaN correctly
CHECK_XPATH_NUMBER_NAN(c, STR("2 mod number('xxx')"));
CHECK_XPATH_NUMBER_NAN(c, STR("number('xxx') mod 3"));
#endif
CHECK_XPATH_NUMBER_NAN(c, STR("floor(number('xxx'))"));
CHECK_XPATH_NUMBER_NAN(c, STR("ceiling(number('xxx'))"));
CHECK_XPATH_NUMBER_NAN(c, STR("round(number('xxx'))"));
CHECK_XPATH_NUMBER(c, STR("10+5+25+20+15+50+35+40"), 200);
CHECK_XPATH_NUMBER(c, STR("100-9-7-4-17-18-5"), 40);
CHECK_XPATH_NUMBER(c, STR("3*2+5*4-4*2-1"), 17);
CHECK_XPATH_NUMBER(c, STR("6*5-8*2+5*2"), 24);
CHECK_XPATH_NUMBER(c, STR("10*5-4*2+6*1 -3*3"), 39);
CHECK_XPATH_NUMBER(c, STR("(24 div 3 +2) div (40 div 8 -3)"), 5);
CHECK_XPATH_NUMBER(c, STR("80 div 2 + 12 div 2 - 4 div 2"), 44);
CHECK_XPATH_NUMBER(c, STR("70 div 10 - 18 div 6 + 10 div 2"), 9);
CHECK_XPATH_NUMBER(c, STR("48 mod 17 - 2 mod 9 + 13 mod 5"), 15);
CHECK_XPATH_NUMBER(c, STR("56 mod round(5*2+1.444) - 6 mod 4 + 7 mod 4"), 2);
CHECK_XPATH_NUMBER(c, STR("(77 mod 10 + 5 mod 8) mod 10"), 2);
}
TEST_XML(xpath_xalan_math_6, "<doc><n1>3</n1><n2>7</n2><n3>x</n3></doc>")
{
xml_node c = doc.child(STR("doc"));
CHECK_XPATH_NUMBER(c, STR("-(n1|n2)"), -3);
CHECK_XPATH_NUMBER(c, STR("-(n2|n1)"), -3);
CHECK_XPATH_BOOLEAN(c, STR("contains(number(n1), 'NaN')"), false);
CHECK_XPATH_BOOLEAN(c, STR("contains(number(n3), 'NaN')"), true);
}
TEST_XML(xpath_xalan_math_7, "<doc><n1>3</n1><n2>7</n2><n3>x</n3></doc>")
{
xml_node c = doc.child(STR("doc"));
CHECK_XPATH_NUMBER(c, STR("-(n1|n2)"), -3);
CHECK_XPATH_NUMBER(c, STR("-(n2|n1)"), -3);
CHECK_XPATH_BOOLEAN(c, STR("contains(number(n1), 'NaN')"), false);
CHECK_XPATH_BOOLEAN(c, STR("contains(number(n3), 'NaN')"), true);
}
TEST_XML(xpath_xalan_math_8, "<k>0.0004</k>")
{
CHECK_XPATH_NUMBER(doc, STR("number(1.75)"), 1.75);
CHECK_XPATH_NUMBER(doc, STR("number(7 div 4)"), 1.75);
CHECK_XPATH_BOOLEAN(doc, STR("(number(1.75) = (7 div 4))"), true);
CHECK_XPATH_NUMBER(doc, STR("number(0.109375 * 16)"), 1.75);
CHECK_XPATH_BOOLEAN(doc, STR("(number(1.75) = (0.109375 * 16))"), true);
CHECK_XPATH_NUMBER(doc, STR("number(k)"), 0.0004);
CHECK_XPATH_NUMBER(doc, STR("number(4 div 10000)"), 0.0004);
// +0 works around extended precision in div on x86 (this is needed for some configurations in MinGW 3.4)
CHECK_XPATH_BOOLEAN(doc, STR("(number(k) = (4 div 10000 + 0))"), true);
CHECK_XPATH_NUMBER(doc, STR("number(0.0001 * 4)"), 0.0004);
CHECK_XPATH_BOOLEAN(doc, STR("(number(k) = (0.0001 * 4))"), true);
}
TEST(xpath_xalan_math_9)
{
xml_node c;
CHECK_XPATH_STRING(c, STR("string(number('0.0'))"), STR("0"));
CHECK_XPATH_STRING(c, STR("string(-1 * number('0.0'))"), STR("0"));
CHECK_XPATH_STRING(c, STR("string(number('0.4'))"), STR("0.4"));
CHECK_XPATH_STRING(c, STR("string(-1 * number('0.4'))"), STR("-0.4"));
CHECK_XPATH_STRING(c, STR("string(number('4.0'))"), STR("4"));
CHECK_XPATH_STRING(c, STR("string(-1 * number('4.0'))"), STR("-4"));
CHECK_XPATH_STRING(c, STR("string(number('0.04'))"), STR("0.04"));
CHECK_XPATH_STRING(c, STR("string(-1 * number('0.04'))"), STR("-0.04"));
CHECK_XPATH_STRING(c, STR("string(number('0.004'))"), STR("0.004"));
CHECK_XPATH_STRING(c, STR("string(-1 * number('0.004'))"), STR("-0.004"));
CHECK_XPATH_STRING(c, STR("string(number('0.0004'))"), STR("0.0004"));
CHECK_XPATH_STRING(c, STR("string(-1 * number('0.0004'))"), STR("-0.0004"));
CHECK_XPATH_STRING(c, STR("string(number('0.0000000000001'))"), STR("0.0000000000001"));
CHECK_XPATH_STRING(c, STR("string(-1 * number('0.0000000000001'))"), STR("-0.0000000000001"));
CHECK_XPATH_STRING(c, STR("string(number('0.0000000000000000000000000001'))"), STR("0.0000000000000000000000000001"));
CHECK_XPATH_STRING(c, STR("string(-1 * number('0.0000000000000000000000000001'))"), STR("-0.0000000000000000000000000001"));
CHECK_XPATH_STRING(c, STR("string(number('0.0000000000001000000000000001'))"), STR("0.0000000000001000000000000001"));
CHECK_XPATH_STRING(c, STR("string(-1 * number('0.0000000000001000000000000001'))"), STR("-0.0000000000001000000000000001"));
CHECK_XPATH_STRING(c, STR("string(number('0.0012'))"), STR("0.0012"));
CHECK_XPATH_STRING(c, STR("string(-1 * number('0.0012'))"), STR("-0.0012"));
CHECK_XPATH_STRING(c, STR("string(number('0.012'))"), STR("0.012"));
CHECK_XPATH_STRING(c, STR("string(-1 * number('0.012'))"), STR("-0.012"));
}
#endif
#ifndef PUGIXML_NO_XPATH
#include "test.hpp"
using namespace pugi;
TEST(xpath_xalan_boolean_1)
{
xml_node c;
CHECK_XPATH_BOOLEAN(c, STR("true()"), true);
CHECK_XPATH_BOOLEAN(c, STR("true() and true()"), true);
CHECK_XPATH_BOOLEAN(c, STR("true() or true()"), true);
CHECK_XPATH_BOOLEAN(c, STR("not(true())"), false);
CHECK_XPATH_BOOLEAN(c, STR("boolean('')"), false);
CHECK_XPATH_BOOLEAN(c, STR("1>2"), false);
CHECK_XPATH_BOOLEAN(c, STR("1>=2"), false);
CHECK_XPATH_BOOLEAN(c, STR("false()"), false);
CHECK_XPATH_BOOLEAN(c, STR("1=1"), true);
CHECK_XPATH_BOOLEAN(c, STR("1=2"), false);
CHECK_XPATH_BOOLEAN(c, STR("1 = 1.00"), true);
CHECK_XPATH_BOOLEAN(c, STR("0 = -0"), true);
CHECK_XPATH_BOOLEAN(c, STR("1 = '001'"), true);
CHECK_XPATH_BOOLEAN(c, STR("true()='0'"), true);
CHECK_XPATH_BOOLEAN(c, STR("false()=''"), true);
CHECK_XPATH_BOOLEAN(c, STR("true()=2"), true);
CHECK_XPATH_BOOLEAN(c, STR("false()=0"), true);
CHECK_XPATH_BOOLEAN(c, STR("false() and false()"), false);
CHECK_XPATH_BOOLEAN(c, STR("'foo' and 'fop'"), true);
CHECK_XPATH_BOOLEAN(c, STR("true() and false()"), false);
CHECK_XPATH_BOOLEAN(c, STR("false() and true()"), false);
CHECK_XPATH_BOOLEAN(c, STR("'1' and '0'"), true);
CHECK_XPATH_BOOLEAN(c, STR("true() or false()"), true);
CHECK_XPATH_BOOLEAN(c, STR("false() or true()"), true);
CHECK_XPATH_BOOLEAN(c, STR("false() or false()"), false);
CHECK_XPATH_BOOLEAN(c, STR("0 or ''"), false);
CHECK_XPATH_BOOLEAN(c, STR("not(false())"), true);
CHECK_XPATH_BOOLEAN(c, STR("not(false() = false())"), false);
CHECK_XPATH_BOOLEAN(c, STR("not(true() = false())"), true);
CHECK_XPATH_BOOLEAN(c, STR("not('')"), true);
CHECK_XPATH_BOOLEAN(c, STR("not('0')"), false);
CHECK_XPATH_BOOLEAN(c, STR("boolean('0')"), true);
CHECK_XPATH_BOOLEAN(c, STR("boolean(0)"), false);
CHECK_XPATH_BOOLEAN(c, STR("boolean(-0)"), false);
CHECK_XPATH_BOOLEAN(c, STR("boolean(1)"), true);
CHECK_XPATH_BOOLEAN(c, STR("boolean(1 div 0)"), true);
CHECK_XPATH_BOOLEAN(c, STR("boolean(0 div 0)"), false);
}
TEST_XML(xpath_xalan_boolean_2, "<doc/>")
{
CHECK_XPATH_BOOLEAN(doc, STR("boolean(doc)"), true);
CHECK_XPATH_BOOLEAN(doc, STR("boolean(foo)"), false);
}
TEST(xpath_xalan_boolean_3)
{
xml_node c;
CHECK_XPATH_BOOLEAN(c, STR("1>1"), false);
CHECK_XPATH_BOOLEAN(c, STR("2>1"), true);
CHECK_XPATH_BOOLEAN(c, STR("1<2"), true);
CHECK_XPATH_BOOLEAN(c, STR("1<1"), false);
CHECK_XPATH_BOOLEAN(c, STR("2<1"), false);
CHECK_XPATH_BOOLEAN(c, STR("'2'>'1'"), true);
CHECK_XPATH_BOOLEAN(c, STR("0 > -0"), false);
CHECK_XPATH_BOOLEAN(c, STR("2>=2"), true);
CHECK_XPATH_BOOLEAN(c, STR("2>=1"), true);
CHECK_XPATH_BOOLEAN(c, STR("1<=2"), true);
CHECK_XPATH_BOOLEAN(c, STR("1<=1"), true);
CHECK_XPATH_BOOLEAN(c, STR("2<=1"), false);
CHECK_XPATH_BOOLEAN(c, STR("false() and 1 div 0"), false);
CHECK_XPATH_BOOLEAN(c, STR("true() or 1 div 0"), true);
CHECK_XPATH_BOOLEAN(c, STR("1!=1"), false);
CHECK_XPATH_BOOLEAN(c, STR("1!=2"), true);
CHECK_XPATH_BOOLEAN(c, STR("1!=1.00"), false);
CHECK_XPATH_BOOLEAN(c, STR("false()!=true()"), true);
CHECK_XPATH_BOOLEAN(c, STR("true()!=false()"), true);
CHECK_XPATH_BOOLEAN(c, STR("false()!=false()"), false);
CHECK_XPATH_BOOLEAN(c, STR("'ace' != 'ace'"), false);
CHECK_XPATH_BOOLEAN(c, STR("'ace' != 'abc'"), true);
CHECK_XPATH_BOOLEAN(c, STR("'H' != ' H'"), true);
CHECK_XPATH_BOOLEAN(c, STR("'H' != 'H '"), true);
CHECK_XPATH_BOOLEAN(c, STR("1.9999999 < 2.0"), true);
CHECK_XPATH_BOOLEAN(c, STR("2.0000001 < 2.0"), false);
CHECK_XPATH_BOOLEAN(c, STR("1.9999999 < 2"), true);
CHECK_XPATH_BOOLEAN(c, STR("2 < 2.0"), false);
CHECK_XPATH_BOOLEAN(c, STR("'001' = 1"), true);
CHECK_XPATH_BOOLEAN(c, STR("0=false()"), true);
CHECK_XPATH_BOOLEAN(c, STR("'0'=true()"), true);
}
TEST_XML(xpath_xalan_boolean_4, "<avj><a>foo</a><b>bar</b><c>foobar</c><d>foo</d></avj>")
{
CHECK_XPATH_BOOLEAN(doc, STR("avj/*='foo'"), true);
CHECK_XPATH_BOOLEAN(doc, STR("not(avj/*='foo')"), false);
CHECK_XPATH_BOOLEAN(doc, STR("avj/*!='foo'"), true);
CHECK_XPATH_BOOLEAN(doc, STR("not(avj/*!='foo')"), false);
CHECK_XPATH_BOOLEAN(doc, STR("avj/k='foo'"), false);
CHECK_XPATH_BOOLEAN(doc, STR("not(avj/k='foo')"), true);
CHECK_XPATH_BOOLEAN(doc, STR("avj/k!='foo'"), false);
CHECK_XPATH_BOOLEAN(doc, STR("not(avj/k!='foo')"), true);
}
TEST_XML(xpath_xalan_boolean_5, "<doc><j l='12' w='33'>first</j><j l='17' w='45'>second</j><j l='16' w='78'>third</j><j l='12' w='33'>fourth</j></doc>")
{
xml_node c = doc.child(STR("doc"));
CHECK_XPATH_BOOLEAN(c, STR("j[@l='12'] = j[@w='33']"), true);
CHECK_XPATH_BOOLEAN(c, STR("j[@l='12'] = j[@l='17']"), false);
CHECK_XPATH_BOOLEAN(c, STR("j[@l='12'] = j[.='first' or @w='45']"), true);
CHECK_XPATH_BOOLEAN(c, STR("j[@l='12'] != j[@w='33']"), true);
CHECK_XPATH_BOOLEAN(c, STR("j[@l='12'] != j[@l='17']"), true);
CHECK_XPATH_BOOLEAN(c, STR("j[@l='12'] != j[.='first' or @w='45']"), true);
CHECK_XPATH_BOOLEAN(c, STR("j[@l='16'] != j[@w='78']"), false);
}
TEST_XML(xpath_xalan_boolean_6, "<doc><avj><good><b>12</b><c>34</c><d>56</d><e>78</e></good></avj></doc>")
{
xml_node c = doc.child(STR("doc"));
CHECK_XPATH_BOOLEAN(c, STR("avj/good/*=34"), true);
CHECK_XPATH_BOOLEAN(c, STR("not(avj/good/*=34)"), false);
CHECK_XPATH_BOOLEAN(c, STR("avj/good/*!=34"), true);
CHECK_XPATH_BOOLEAN(c, STR("not(avj/good/*!=34)"), false);
CHECK_XPATH_BOOLEAN(c, STR("34=avj/good/*"), true);
CHECK_XPATH_BOOLEAN(c, STR("not(34=avj/good/*)"), false);
CHECK_XPATH_BOOLEAN(c, STR("34!=avj/good/*"), true);
CHECK_XPATH_BOOLEAN(c, STR("not(34!=avj/good/*)"), false);
}
TEST_XML(xpath_xalan_boolean_7, "<doc><avj><bool><b>true</b><c></c><d>false?</d><e>1</e><f>0</f></bool></avj></doc>")
{
xml_node c = doc.child(STR("doc"));
CHECK_XPATH_BOOLEAN(c, STR("avj/bool/*=true()"), true);
CHECK_XPATH_BOOLEAN(c, STR("not(avj/bool/*=true())"), false);
CHECK_XPATH_BOOLEAN(c, STR("avj/bool/*!=true()"), false);
CHECK_XPATH_BOOLEAN(c, STR("not(avj/bool/*!=true())"), true);
CHECK_XPATH_BOOLEAN(c, STR("true()=avj/bool/*"), true);
CHECK_XPATH_BOOLEAN(c, STR("not(true()=avj/bool/*)"), false);
CHECK_XPATH_BOOLEAN(c, STR("true()!=avj/bool/*"), false);
CHECK_XPATH_BOOLEAN(c, STR("not(true()!=avj/bool/*)"), true);
CHECK_XPATH_BOOLEAN(c, STR("avj/none/*=true()"), false);
CHECK_XPATH_BOOLEAN(c, STR("not(avj/none/*=true())"), true);
CHECK_XPATH_BOOLEAN(c, STR("avj/none/*!=true()"), true);
CHECK_XPATH_BOOLEAN(c, STR("not(avj/none/*!=true())"), false);
CHECK_XPATH_BOOLEAN(c, STR("true()=avj/none/*"), false);
CHECK_XPATH_BOOLEAN(c, STR("not(true()=avj/none/*)"), true);
CHECK_XPATH_BOOLEAN(c, STR("true()!=avj/none/*"), true);
CHECK_XPATH_BOOLEAN(c, STR("not(true()!=avj/none/*)"), false);
}
TEST_XML(xpath_xalan_conditional, "<letters>b</letters>")
{
xml_node c;
CHECK_XPATH_BOOLEAN(c, STR("(round(3.7) > 3)"), true);
CHECK_XPATH_BOOLEAN(c, STR("2 > 1"), true);
CHECK_XPATH_BOOLEAN(c, STR("9 mod 3 = 0"), true);
CHECK_XPATH_BOOLEAN(c, STR("'a'='a'"), true);
CHECK_XPATH_BOOLEAN(c, STR("2+2=4"), true);
xml_node b = doc.child(STR("letters")).first_child();
CHECK_XPATH_BOOLEAN(b, STR(".='b'"), true);
CHECK_XPATH_BOOLEAN(b, STR("name(..)='letters'"), true);
}
TEST_XML(xpath_xalan_math_1, "<a>3</a>")
{
xml_node c;
CHECK_XPATH_NUMBER(c, STR("number('1')"), 1);
CHECK_XPATH_NUMBER(c, STR("floor(0.0)"), 0);
CHECK_XPATH_NUMBER(c, STR("ceiling(0.0)"), 0);
CHECK_XPATH_NUMBER(c, STR("round(0.0)"), 0);
CHECK_XPATH_NUMBER(c, STR("2*3"), 6);
CHECK_XPATH_NUMBER(c, STR("3+6"), 9);
CHECK_XPATH_NUMBER(c, STR("3-1"), 2);
CHECK_XPATH_NUMBER_NAN(doc, STR("a-1")); // a-1 is a name test, not arithmetic expression
CHECK_XPATH_NUMBER(doc, STR("a -1"), 2);
CHECK_XPATH_NUMBER(c, STR("6 div 2"), 3);
CHECK_XPATH_NUMBER(c, STR("5 mod 2"), 1);
CHECK_XPATH_NUMBER_NAN(c, STR("number(n)"));
CHECK_XPATH_NUMBER(c, STR("number(2)"), 2);
CHECK_XPATH_NUMBER(c, STR("number('3')"), 3);
CHECK_XPATH_NUMBER_NAN(c, STR("number('')"));
CHECK_XPATH_NUMBER_NAN(c, STR("number('abc')"));
CHECK_XPATH_BOOLEAN(c, STR("number(string(1.0))=1"), true);
CHECK_XPATH_BOOLEAN(c, STR("number(true())=1"), true);
CHECK_XPATH_BOOLEAN(c, STR("number(false())=0"), true);
#ifndef MSVC6_NAN_BUG
CHECK_XPATH_BOOLEAN(c, STR("number('xxx')=number('xxx')"), false);
CHECK_XPATH_BOOLEAN(c, STR("number('xxx')=0"), false);
#endif
CHECK_XPATH_NUMBER(doc, STR("floor(a)"), 3);
CHECK_XPATH_NUMBER(c, STR("floor(1.9)"), 1);
CHECK_XPATH_NUMBER(c, STR("floor(2.999999)"), 2);
CHECK_XPATH_NUMBER(c, STR("floor(-1.5)"), -2);
CHECK_XPATH_BOOLEAN(c, STR("floor(1)=1"), true);
CHECK_XPATH_BOOLEAN(c, STR("floor(1.9)=1"), true);
CHECK_XPATH_BOOLEAN(c, STR("floor(-1.5)=-2"), true);
CHECK_XPATH_NUMBER(doc, STR("ceiling(a)"), 3);
CHECK_XPATH_NUMBER(c, STR("ceiling(1.54)"), 2);
CHECK_XPATH_NUMBER(c, STR("ceiling(2.999999)"), 3);
CHECK_XPATH_NUMBER(c, STR("ceiling(3.000001)"), 4);
CHECK_XPATH_BOOLEAN(c, STR("ceiling(1)=1"), true);
CHECK_XPATH_BOOLEAN(c, STR("ceiling(1.1)=2"), true);
CHECK_XPATH_BOOLEAN(c, STR("ceiling(-1.5)=-1"), true);
}
TEST_XML(xpath_xalan_math_2, "<a>3</a>")
{
xml_node c;
CHECK_XPATH_NUMBER(doc, STR("round(a)"), 3);
CHECK_XPATH_NUMBER(c, STR("round(1.24)"), 1);
CHECK_XPATH_NUMBER(c, STR("round(2.999999)"), 3);
CHECK_XPATH_NUMBER(c, STR("round(3.000001)"), 3);
CHECK_XPATH_NUMBER(c, STR("round(1.1)"), 1);
CHECK_XPATH_NUMBER(c, STR("round(-1.1)"), -1);
CHECK_XPATH_NUMBER(c, STR("round(1.9)"), 2);
CHECK_XPATH_NUMBER(c, STR("round(-1.9)"), -2);
CHECK_XPATH_NUMBER(c, STR("round(1.5)"), 2);
CHECK_XPATH_NUMBER(c, STR("round(-1.5)"), -1);
CHECK_XPATH_NUMBER(c, STR("round(1.4999999)"), 1);
CHECK_XPATH_NUMBER(c, STR("round(-1.4999999)"), -1);
CHECK_XPATH_NUMBER(c, STR("round(1.5000001)"), 2);
CHECK_XPATH_NUMBER(c, STR("round(-1.5000001)"), -2);
}
TEST_XML(xpath_xalan_math_3, "<doc><n v='1'/><n>2</n><n v='3'/><n>4</n><n v='5'>5</n><e>17</e><e>-5</e><e>8</e><e>-37</e></doc>")
{
CHECK_XPATH_NUMBER(doc, STR("sum(doc/x)"), 0);
CHECK_XPATH_NUMBER_NAN(doc, STR("sum(doc/n)"));
CHECK_XPATH_NUMBER(doc, STR("sum(doc/n[text()])"), 11);
CHECK_XPATH_NUMBER(doc, STR("sum(doc/n/@v)"), 9);
CHECK_XPATH_NUMBER(doc, STR("sum(doc/e)"), -17);
}
TEST_XML(xpath_xalan_math_4, "<doc><n1 a='1'>2</n1><n2 a='2'>3</n2><n1-n2>123</n1-n2><n-1>72</n-1><n-2>12</n-2><div a='2'>5</div><mod a='5'>2</mod></doc>")
{
xml_node c = doc.child(STR("doc"));
CHECK_XPATH_NUMBER(c, STR("n1*n2"), 6);
CHECK_XPATH_NUMBER(c, STR("n1/@a*n2/@a"), 2);
CHECK_XPATH_NUMBER(c, STR("(n1/@a)*(n2/@a)"), 2);
CHECK_XPATH_NUMBER(c, STR("n1+n2"), 5);
CHECK_XPATH_NUMBER(c, STR("n1/@a+n2/@a"), 3);
CHECK_XPATH_NUMBER(c, STR("(n1/@a)+(n2/@a)"), 3);
CHECK_XPATH_NUMBER(c, STR("1-2"), -1);
CHECK_XPATH_NUMBER(c, STR("n1 - n2"), -1);
CHECK_XPATH_NUMBER(c, STR("n1-n2"), 123);
CHECK_XPATH_NUMBER(c, STR("n-1 - n-2"), 60);
CHECK_XPATH_NUMBER(c, STR("n-1 -n-2"), 60);
CHECK_XPATH_NUMBER(c, STR("7+-3"), 4);
CHECK_XPATH_NUMBER(c, STR("n-1+-n-2"), 60);
CHECK_XPATH_NUMBER(c, STR("7 - -3"), 10);
CHECK_XPATH_NUMBER(c, STR("n-1 - -n-2"), 84);
CHECK_XPATH_NUMBER(c, STR("-7 --3"), -4);
CHECK_XPATH_NUMBER(c, STR("-n-1 --n-2"), -60);
CHECK_XPATH_FAIL(STR("+7"));
CHECK_XPATH_FAIL(STR("7++3"));
CHECK_XPATH_FAIL(STR("7-+3"));
CHECK_XPATH_NUMBER(c, STR("6 div -2"), -3);
CHECK_XPATH_NUMBER(c, STR("n1 div n2"), 2.0 / 3.0);
CHECK_XPATH_NUMBER(c, STR("div div mod"), 2.5);
CHECK_XPATH_NUMBER(c, STR("div/@a div mod/@a"), 0.4);
CHECK_XPATH_BOOLEAN(c, STR("1 div -0 = 2 div -0"), true);
CHECK_XPATH_BOOLEAN(c, STR("1 div -0 = 1 div 0"), false);
CHECK_XPATH_BOOLEAN(c, STR("1 div -0 = -1 div 0"), true);
#ifndef MSVC6_NAN_BUG
CHECK_XPATH_BOOLEAN(c, STR("0 div 0 >= 0"), false);
CHECK_XPATH_BOOLEAN(c, STR("0 div 0 < 0"), false);
#endif
CHECK_XPATH_NUMBER(c, STR("n1 mod n2"), 2);
CHECK_XPATH_NUMBER(c, STR("div mod mod"), 1);
CHECK_XPATH_NUMBER(c, STR("div/@a mod mod/@a"), 2);
CHECK_XPATH_BOOLEAN(c, STR("(5 mod 2 = 1) and (5 mod -2 = 1) and (-5 mod 2 = -1) and (-5 mod -2 = -1)"), true);
}
TEST(xpath_xalan_math_5)
{
xml_node c;
CHECK_XPATH_NUMBER(c, STR("(((((('3'+5)*(3)+((('2')+2)*('1' - 6)))-('4' - '2'))+(-(4-6)))))"), 4);
CHECK_XPATH_NUMBER(c, STR("1*1*2*2*2*3*3*1*1*1*0.5*0.5"), 18);
CHECK_XPATH_NUMBER(c, STR("1440 div 2 div 2 div 6"), 60);
CHECK_XPATH_NUMBER(c, STR("1440 div 2 div 2 div 6 div 10"), 6);
CHECK_XPATH_NUMBER(c, STR("1440 div 2 div 2 div 6 div 10 div 3"), 2);
CHECK_XPATH_NUMBER(c, STR("(1*2*3*4*5*6)div 2 div 6 div 10 div 3"), 2);
CHECK_XPATH_NUMBER_NAN(c, STR("(2 + number('xxx'))"));
CHECK_XPATH_NUMBER_NAN(c, STR("2 * -number('xxx')"));
CHECK_XPATH_NUMBER_NAN(c, STR("2 - number('xxx')"));
CHECK_XPATH_NUMBER_NAN(c, STR("number('xxx') - 3"));
CHECK_XPATH_NUMBER_NAN(c, STR("2 div number('xxx')"));
CHECK_XPATH_NUMBER_NAN(c, STR("number('xxx') div 3"));
#ifndef __BORLANDC__ // BCC fmod does not propagate NaN correctly
CHECK_XPATH_NUMBER_NAN(c, STR("2 mod number('xxx')"));
CHECK_XPATH_NUMBER_NAN(c, STR("number('xxx') mod 3"));
#endif
CHECK_XPATH_NUMBER_NAN(c, STR("floor(number('xxx'))"));
CHECK_XPATH_NUMBER_NAN(c, STR("ceiling(number('xxx'))"));
CHECK_XPATH_NUMBER_NAN(c, STR("round(number('xxx'))"));
CHECK_XPATH_NUMBER(c, STR("10+5+25+20+15+50+35+40"), 200);
CHECK_XPATH_NUMBER(c, STR("100-9-7-4-17-18-5"), 40);
CHECK_XPATH_NUMBER(c, STR("3*2+5*4-4*2-1"), 17);
CHECK_XPATH_NUMBER(c, STR("6*5-8*2+5*2"), 24);
CHECK_XPATH_NUMBER(c, STR("10*5-4*2+6*1 -3*3"), 39);
CHECK_XPATH_NUMBER(c, STR("(24 div 3 +2) div (40 div 8 -3)"), 5);
CHECK_XPATH_NUMBER(c, STR("80 div 2 + 12 div 2 - 4 div 2"), 44);
CHECK_XPATH_NUMBER(c, STR("70 div 10 - 18 div 6 + 10 div 2"), 9);
CHECK_XPATH_NUMBER(c, STR("48 mod 17 - 2 mod 9 + 13 mod 5"), 15);
CHECK_XPATH_NUMBER(c, STR("56 mod round(5*2+1.444) - 6 mod 4 + 7 mod 4"), 2);
CHECK_XPATH_NUMBER(c, STR("(77 mod 10 + 5 mod 8) mod 10"), 2);
}
TEST_XML(xpath_xalan_math_6, "<doc><n1>3</n1><n2>7</n2><n3>x</n3></doc>")
{
xml_node c = doc.child(STR("doc"));
CHECK_XPATH_NUMBER(c, STR("-(n1|n2)"), -3);
CHECK_XPATH_NUMBER(c, STR("-(n2|n1)"), -3);
CHECK_XPATH_BOOLEAN(c, STR("contains(number(n1), 'NaN')"), false);
CHECK_XPATH_BOOLEAN(c, STR("contains(number(n3), 'NaN')"), true);
}
TEST_XML(xpath_xalan_math_7, "<doc><n1>3</n1><n2>7</n2><n3>x</n3></doc>")
{
xml_node c = doc.child(STR("doc"));
CHECK_XPATH_NUMBER(c, STR("-(n1|n2)"), -3);
CHECK_XPATH_NUMBER(c, STR("-(n2|n1)"), -3);
CHECK_XPATH_BOOLEAN(c, STR("contains(number(n1), 'NaN')"), false);
CHECK_XPATH_BOOLEAN(c, STR("contains(number(n3), 'NaN')"), true);
}
TEST_XML(xpath_xalan_math_8, "<k>0.0004</k>")
{
CHECK_XPATH_NUMBER(doc, STR("number(1.75)"), 1.75);
CHECK_XPATH_NUMBER(doc, STR("number(7 div 4)"), 1.75);
CHECK_XPATH_BOOLEAN(doc, STR("(number(1.75) = (7 div 4))"), true);
CHECK_XPATH_NUMBER(doc, STR("number(0.109375 * 16)"), 1.75);
CHECK_XPATH_BOOLEAN(doc, STR("(number(1.75) = (0.109375 * 16))"), true);
CHECK_XPATH_NUMBER(doc, STR("number(k)"), 0.0004);
CHECK_XPATH_NUMBER(doc, STR("number(4 div 10000)"), 0.0004);
// +0 works around extended precision in div on x86 (this is needed for some configurations in MinGW 3.4)
CHECK_XPATH_BOOLEAN(doc, STR("(number(k) = (4 div 10000 + 0))"), true);
CHECK_XPATH_NUMBER(doc, STR("number(0.0001 * 4)"), 0.0004);
CHECK_XPATH_BOOLEAN(doc, STR("(number(k) = (0.0001 * 4))"), true);
}
TEST(xpath_xalan_math_9)
{
xml_node c;
CHECK_XPATH_STRING(c, STR("string(number('0.0'))"), STR("0"));
CHECK_XPATH_STRING(c, STR("string(-1 * number('0.0'))"), STR("0"));
CHECK_XPATH_STRING(c, STR("string(number('0.4'))"), STR("0.4"));
CHECK_XPATH_STRING(c, STR("string(-1 * number('0.4'))"), STR("-0.4"));
CHECK_XPATH_STRING(c, STR("string(number('4.0'))"), STR("4"));
CHECK_XPATH_STRING(c, STR("string(-1 * number('4.0'))"), STR("-4"));
CHECK_XPATH_STRING(c, STR("string(number('0.04'))"), STR("0.04"));
CHECK_XPATH_STRING(c, STR("string(-1 * number('0.04'))"), STR("-0.04"));
CHECK_XPATH_STRING(c, STR("string(number('0.004'))"), STR("0.004"));
CHECK_XPATH_STRING(c, STR("string(-1 * number('0.004'))"), STR("-0.004"));
CHECK_XPATH_STRING(c, STR("string(number('0.0004'))"), STR("0.0004"));
CHECK_XPATH_STRING(c, STR("string(-1 * number('0.0004'))"), STR("-0.0004"));
CHECK_XPATH_STRING(c, STR("string(number('0.0000000000001'))"), STR("0.0000000000001"));
CHECK_XPATH_STRING(c, STR("string(-1 * number('0.0000000000001'))"), STR("-0.0000000000001"));
CHECK_XPATH_STRING(c, STR("string(number('0.0000000000000000000000000001'))"), STR("0.0000000000000000000000000001"));
CHECK_XPATH_STRING(c, STR("string(-1 * number('0.0000000000000000000000000001'))"), STR("-0.0000000000000000000000000001"));
CHECK_XPATH_STRING(c, STR("string(number('0.0000000000001000000000000001'))"), STR("0.0000000000001000000000000001"));
CHECK_XPATH_STRING(c, STR("string(-1 * number('0.0000000000001000000000000001'))"), STR("-0.0000000000001000000000000001"));
CHECK_XPATH_STRING(c, STR("string(number('0.0012'))"), STR("0.0012"));
CHECK_XPATH_STRING(c, STR("string(-1 * number('0.0012'))"), STR("-0.0012"));
CHECK_XPATH_STRING(c, STR("string(number('0.012'))"), STR("0.012"));
CHECK_XPATH_STRING(c, STR("string(-1 * number('0.012'))"), STR("-0.012"));
}
#endif

View File

@ -1,417 +1,417 @@
#define _CRT_SECURE_NO_WARNINGS
#ifndef PUGIXML_NO_XPATH
#include "test.hpp"
#include <string>
#include <algorithm>
using namespace pugi;
TEST_XML(xpath_xalan_string_1, "<doc a='test'>ENCYCLOPEDIA</doc>")
{
xml_node c;
CHECK_XPATH_NUMBER(c, STR("string-length('This is a test')"), 14);
CHECK_XPATH_BOOLEAN(c, STR("starts-with('ENCYCLOPEDIA', 'ENCY')"), true);
CHECK_XPATH_BOOLEAN(c, STR("contains('ENCYCLOPEDIA', 'CYCL')"), true);
CHECK_XPATH_STRING(c, STR("substring-before('1999/04/01', '/')"), STR("1999"));
CHECK_XPATH_STRING(c, STR("substring-after('1999/04/01', '/')"), STR("04/01"));
CHECK_XPATH_STRING(c, STR("normalize-space('\t\n\r\n ab\n cd\t\n\r\n ef\t\n\r ')"), STR("ab cd ef"));
CHECK_XPATH_STRING(c, STR("translate(\"bar\",\"abc\",\"ABC\")"), STR("BAr"));
CHECK_XPATH_STRING(c, STR("concat(\"x\",\"yz\")"), STR("xyz"));
CHECK_XPATH_STRING(c, STR("substring('1999/04/01', 1, 4)"), STR("1999"));
CHECK_XPATH_STRING(c, STR("substring('12345', 1.5, 2.6)"), STR("234"));
CHECK_XPATH_STRING(c, STR("substring('12345', 0, 3)"), STR("12"));
CHECK_XPATH_STRING(c, STR("substring('12345', 0 div 0, 3)"), STR(""));
CHECK_XPATH_STRING(c, STR("substring('12345', 1, 0 div 0)"), STR(""));
CHECK_XPATH_STRING(c, STR("substring('12345', -42, 1 div 0)"), STR("12345"));
CHECK_XPATH_STRING(c, STR("substring('12345', -1 div 0, 1 div 0)"), STR(""));
CHECK_XPATH_STRING(c, STR("substring(foo, 12, 3)"), STR(""));
CHECK_XPATH_STRING(c, STR("string(foo)"), STR(""));
CHECK_XPATH_STRING(c, STR("string(0)"), STR("0"));
CHECK_XPATH_STRING(c, STR("string(2)"), STR("2"));
CHECK_XPATH_STRING(c, STR("string('test')"), STR("test"));
CHECK_XPATH_STRING(c, STR("string('')"), STR(""));
CHECK_XPATH_BOOLEAN(c, STR("starts-with('ENCYCLOPEDIA', 'EN')"), true);
CHECK_XPATH_BOOLEAN(c, STR("starts-with('ENCYCLOPEDIA', 'en')"), false);
CHECK_XPATH_BOOLEAN(c, STR("starts-with('ab', 'abc')"), false);
CHECK_XPATH_BOOLEAN(c, STR("starts-with('abc', 'bc')"), false);
CHECK_XPATH_BOOLEAN(c, STR("starts-with('abc', '')"), true);
CHECK_XPATH_BOOLEAN(c, STR("starts-with('', '')"), true);
CHECK_XPATH_BOOLEAN(c, STR("starts-with('', 'abc')"), false);
CHECK_XPATH_BOOLEAN(c, STR("starts-with('true()', 'tr')"), true);
CHECK_XPATH_BOOLEAN(c, STR("starts-with(foo, 'EN')"), false);
CHECK_XPATH_BOOLEAN(doc, STR("starts-with(doc, 'EN')"), true);
CHECK_XPATH_BOOLEAN(doc, STR("starts-with(doc/@a, 'EN')"), false);
CHECK_XPATH_BOOLEAN(doc, STR("starts-with(doc/@a, 'te')"), true);
}
TEST_XML_FLAGS(xpath_xalan_string_2, "<doc>\n <av>\n <a>\n <b>b</b>\n <c>c</c>\n <d>d</d>\n <e>e</e>\n </a>\n <v>\n <w>w</w>\n <x>x</x>\n <y>y</y>\n <z>z</z>\n </v>\n </av>\n</doc>", parse_default | parse_ws_pcdata)
{
CHECK_XPATH_STRING(doc, STR("string(doc/av//*)"), STR("\n b\n c\n d\n e\n "));
CHECK_XPATH_STRING(doc, STR("normalize-space(string(doc/av//*))"), STR("b c d e"));
CHECK_XPATH_STRING(doc, STR("normalize-space('This is a test')"), STR("This is a test"));
}
TEST_XML(xpath_xalan_string_3, "<doc a='test'>ENCYCLOPEDIA</doc>")
{
xml_node c;
CHECK_XPATH_BOOLEAN(c, STR("contains('ENCYCLOPEDIA', 'TEST')"), false);
CHECK_XPATH_BOOLEAN(c, STR("contains('ENCYCLOPEDIA', 'CYCL')"), true);
CHECK_XPATH_BOOLEAN(c, STR("contains('ENCYCLOPEDIA', 'cycl')"), false);
CHECK_XPATH_BOOLEAN(doc, STR("contains(concat(.,'BC'),concat('A','B','C'))"), true);
CHECK_XPATH_BOOLEAN(c, STR("contains('ab', 'abc')"), false);
CHECK_XPATH_BOOLEAN(c, STR("contains('abc', 'bc')"), true);
CHECK_XPATH_BOOLEAN(c, STR("contains('abc', 'bcd')"), false);
CHECK_XPATH_BOOLEAN(c, STR("contains('abc', '')"), true);
CHECK_XPATH_BOOLEAN(c, STR("contains('', '')"), true);
CHECK_XPATH_BOOLEAN(c, STR("contains('', 'abc')"), false);
CHECK_XPATH_BOOLEAN(c, STR("contains('true()', 'e')"), true);
CHECK_XPATH_BOOLEAN(doc, STR("contains(., 'CYCL')"), true);
CHECK_XPATH_BOOLEAN(doc, STR("contains(., 'TEST')"), false);
CHECK_XPATH_BOOLEAN(doc, STR("contains(doc/@a, 'es')"), true);
CHECK_XPATH_BOOLEAN(doc, STR("contains(doc/@a, 'T')"), false);
CHECK_XPATH_STRING(c, STR("substring-before('ENCYCLOPEDIA', '/')"), STR(""));
CHECK_XPATH_STRING(c, STR("substring-before('ENCYCLOPEDIA', 'C')"), STR("EN"));
CHECK_XPATH_STRING(c, STR("substring-before('ENCYCLOPEDIA', 'c')"), STR(""));
CHECK_XPATH_STRING(c, STR("substring-before('ENCYCLOPEDIA', '')"), STR(""));
CHECK_XPATH_STRING(doc, STR("substring-before(., '/')"), STR(""));
CHECK_XPATH_STRING(doc, STR("substring-before(., 'C')"), STR("EN"));
CHECK_XPATH_STRING(doc, STR("substring-before(foo, '')"), STR(""));
CHECK_XPATH_STRING(doc, STR("substring-before(doc/@a, '/')"), STR(""));
CHECK_XPATH_STRING(doc, STR("substring-before(doc/@a, 'e')"), STR("t"));
CHECK_XPATH_STRING(doc, STR("substring-before(doc/@a, 't')"), STR(""));
CHECK_XPATH_STRING(c, STR("substring-after('ENCYCLOPEDIA', '/')"), STR(""));
CHECK_XPATH_STRING(c, STR("substring-after('ENCYCLOPEDIA', 'C')"), STR("YCLOPEDIA"));
CHECK_XPATH_STRING(c, STR("substring-after('ENCYCLOPEDIA', 'c')"), STR(""));
CHECK_XPATH_STRING(c, STR("substring-after('ENCYCLOPEDIA', '')"), STR("ENCYCLOPEDIA"));
CHECK_XPATH_STRING(doc, STR("substring-after(., '/')"), STR(""));
CHECK_XPATH_STRING(doc, STR("substring-after(., 'C')"), STR("YCLOPEDIA"));
CHECK_XPATH_STRING(doc, STR("substring-after(foo, '')"), STR(""));
CHECK_XPATH_STRING(doc, STR("substring-after(doc/@a, '/')"), STR(""));
CHECK_XPATH_STRING(doc, STR("substring-after(doc/@a, 'e')"), STR("st"));
CHECK_XPATH_STRING(doc, STR("substring-after(doc/@a, 't')"), STR("est"));
CHECK_XPATH_STRING(doc, STR("substring-after(doc/@a, 'st')"), STR(""));
}
TEST_XML(xpath_xalan_string_4, "<doc><a>a</a><b>b</b><c>c</c><d>d</d><e>ef</e><f attr='whatsup'>what's up</f></doc><cd><![CDATA[qua'lit\"y]]></cd>")
{
xml_node c;
CHECK_XPATH_STRING(c, STR("translate('BAR','abc','ABC')"), STR("BAR"));
CHECK_XPATH_STRING(c, STR("translate('bar','RAB','xyz')"), STR("bar"));
CHECK_XPATH_STRING(c, STR("translate('BAR','Rab','TxX')"), STR("BAT"));
CHECK_XPATH_STRING(c, STR("translate('zzaaazzz','abcz','ABC')"), STR("AAA"));
CHECK_XPATH_STRING(c, STR("translate('ddaaadddd','abcd','ABCxy')"), STR("xxAAAxxxx"));
CHECK_XPATH_STRING(c, STR("concat('a','b','c','d','ef')"), STR("abcdef"));
CHECK_XPATH_STRING(c, STR("concat(a, b)"), STR(""));
CHECK_XPATH_STRING(doc.child(STR("doc")), STR("concat(a, b)"), STR("ab"));
CHECK_XPATH_STRING(doc.child(STR("doc")), STR("concat(a, b, c, d, e)"), STR("abcdef"));
CHECK_XPATH_STRING(c, STR("concat('cd','34')"), STR("cd34"));
CHECK_XPATH_STRING(c, STR("concat('cd',34)"), STR("cd34"));
CHECK_XPATH_STRING(c, STR("concat('bc',string(23))"), STR("bc23"));
CHECK_XPATH_STRING(c, STR("concat(a,34)"), STR("34"));
CHECK_XPATH_STRING(doc.child(STR("doc")), STR("concat(a,34)"), STR("a34"));
CHECK_XPATH_STRING(c, STR("concat(false(),'ly')"), STR("falsely"));
CHECK_XPATH_FAIL(STR("concat(/*)"));
CHECK_XPATH_STRING(doc.child(STR("doc")), STR("concat(/*, '')"), STR("abcdefwhat's up"));
CHECK_XPATH_STRING(doc.child(STR("doc")), STR("concat(/*, /*[@attr='whatsup'])"), STR("abcdefwhat's up"));
CHECK_XPATH_STRING(doc.child(STR("doc")), STR("concat(/*, //*[@attr='whatsup'])"), STR("abcdefwhat's upwhat's up"));
CHECK_XPATH_STRING(c, STR("substring('ENCYCLOPEDIA', 8, 3)"), STR("PED"));
CHECK_XPATH_STRING(c, STR("substring('ENCYCLOPEDIA', 8)"), STR("PEDIA"));
CHECK_XPATH_STRING(c, STR("substring('abcdefghijk',0 div 0, 5)"), STR(""));
CHECK_XPATH_STRING(c, STR("substring('abcdefghijk',4, 6)"), STR("defghi"));
CHECK_XPATH_STRING(c, STR("substring('1999/04/01', 1, 0)"), STR(""));
CHECK_XPATH_STRING(c, STR("translate(normalize-space(' bar fly '), ' ', '_')"), STR("bar_fly"));
CHECK_XPATH_STRING(c, STR("translate('barter','abe','bao')"), STR("abrtor"));
CHECK_XPATH_STRING(c, STR("translate('barbarity', 'aeiouy', '******')"), STR("b*rb*r*t*"));
CHECK_XPATH_STRING(doc, STR("translate(cd, concat(\"aqu'\", '\"eos'), 'AQU-+EOS')"), STR("QUA-lit+y"));
CHECK_XPATH_STRING(c, STR("translate('quan+ti-ty', 'AQU-+EOS', concat(\"aqu'\", '\"eos'))"), STR("quan\"ti'ty"));
}
static const char_t* number_to_string_unsafe(int number)
{
static char_t buffer[16];
// construct number in reverse
char_t* it = buffer;
while (number)
{
*it++ = static_cast<char_t>('0' + number % 10);
number /= 10;
}
// zero terminate
*it = 0;
// reverse to get final result
std::reverse(buffer, it);
return buffer;
}
TEST(xpath_xalan_string_5)
{
const int count = 1000;
std::basic_string<char_t> query;
query.reserve(17 * count);
query += STR("concat(");
for (int i = 1; i < count; ++i)
{
query += STR("concat('t',");
query += number_to_string_unsafe(i);
query += STR("), ");
}
query += STR("'')");
std::basic_string<char_t> expected;
expected.reserve(4 * count);
for (int j = 1; j < count; ++j)
{
expected += STR("t");
expected += number_to_string_unsafe(j);
}
CHECK_XPATH_STRING(xml_node(), query.c_str(), expected.c_str());
}
TEST(xpath_xalan_string_6)
{
xml_node c;
CHECK_XPATH_STRING(c, STR("string(1)"), STR("1"));
CHECK_XPATH_STRING(c, STR("string(12)"), STR("12"));
CHECK_XPATH_STRING(c, STR("string(123)"), STR("123"));
CHECK_XPATH_STRING(c, STR("string(1234)"), STR("1234"));
CHECK_XPATH_STRING(c, STR("string(12345)"), STR("12345"));
CHECK_XPATH_STRING(c, STR("string(123456)"), STR("123456"));
CHECK_XPATH_STRING(c, STR("string(1234567)"), STR("1234567"));
CHECK_XPATH_STRING(c, STR("string(12345678)"), STR("12345678"));
CHECK_XPATH_STRING(c, STR("string(123456789)"), STR("123456789"));
CHECK_XPATH_STRING(c, STR("string(1234567890)"), STR("1234567890"));
CHECK_XPATH_STRING(c, STR("string(12345678901)"), STR("12345678901"));
CHECK_XPATH_STRING(c, STR("string(123456789012)"), STR("123456789012"));
CHECK_XPATH_STRING(c, STR("string(1234567890123)"), STR("1234567890123"));
CHECK_XPATH_STRING(c, STR("string(12345678901234)"), STR("12345678901234"));
CHECK_XPATH_STRING(c, STR("string(123456789012345)"), STR("123456789012345"));
CHECK_XPATH_STRING(c, STR("string(1234567890123456)"), STR("1234567890123456"));
CHECK_XPATH_STRING(c, STR("string(-1)"), STR("-1"));
CHECK_XPATH_STRING(c, STR("string(-12)"), STR("-12"));
CHECK_XPATH_STRING(c, STR("string(-123)"), STR("-123"));
CHECK_XPATH_STRING(c, STR("string(-1234)"), STR("-1234"));
CHECK_XPATH_STRING(c, STR("string(-12345)"), STR("-12345"));
CHECK_XPATH_STRING(c, STR("string(-123456)"), STR("-123456"));
CHECK_XPATH_STRING(c, STR("string(-1234567)"), STR("-1234567"));
CHECK_XPATH_STRING(c, STR("string(-12345678)"), STR("-12345678"));
CHECK_XPATH_STRING(c, STR("string(-123456789)"), STR("-123456789"));
CHECK_XPATH_STRING(c, STR("string(-1234567890)"), STR("-1234567890"));
CHECK_XPATH_STRING(c, STR("string(-12345678901)"), STR("-12345678901"));
CHECK_XPATH_STRING(c, STR("string(-123456789012)"), STR("-123456789012"));
CHECK_XPATH_STRING(c, STR("string(-1234567890123)"), STR("-1234567890123"));
CHECK_XPATH_STRING(c, STR("string(-12345678901234)"), STR("-12345678901234"));
CHECK_XPATH_STRING(c, STR("string(-123456789012345)"), STR("-123456789012345"));
CHECK_XPATH_STRING(c, STR("string(-1234567890123456)"), STR("-1234567890123456"));
}
#if 0 // $ this test requires round-to-nearest behavior in string->number conversion during parsing; atof gives us truncation
TEST(xpath_xalan_string_6_rounding)
{
xml_node c;
CHECK_XPATH_STRING(c, STR("string(12345678901234567)"), STR("12345678901234568"));
CHECK_XPATH_STRING(c, STR("string(123456789012345678)"), STR("123456789012345680"));
CHECK_XPATH_STRING(c, STR("string(-12345678901234567)"), STR("-12345678901234568"));
CHECK_XPATH_STRING(c, STR("string(-123456789012345678)"), STR("-123456789012345680"));
}
#endif
TEST(xpath_xalan_string_7)
{
xml_node c;
CHECK_XPATH_STRING(c, STR("string(.1)"), STR("0.1"));
CHECK_XPATH_STRING(c, STR("string(.01)"), STR("0.01"));
CHECK_XPATH_STRING(c, STR("string(.012)"), STR("0.012"));
CHECK_XPATH_STRING(c, STR("string(.0123)"), STR("0.0123"));
CHECK_XPATH_STRING(c, STR("string(.01234)"), STR("0.01234"));
CHECK_XPATH_STRING(c, STR("string(.012345)"), STR("0.012345"));
CHECK_XPATH_STRING(c, STR("string(.0123456)"), STR("0.0123456"));
CHECK_XPATH_STRING(c, STR("string(.01234567)"), STR("0.01234567"));
CHECK_XPATH_STRING(c, STR("string(.012345678)"), STR("0.012345678"));
CHECK_XPATH_STRING(c, STR("string(.0123456789)"), STR("0.0123456789"));
CHECK_XPATH_STRING(c, STR("string(.10123456789)"), STR("0.10123456789"));
CHECK_XPATH_STRING(c, STR("string(.101234567892)"), STR("0.101234567892"));
CHECK_XPATH_STRING(c, STR("string(.1012345678923)"), STR("0.1012345678923"));
CHECK_XPATH_STRING(c, STR("string(.10123456789234)"), STR("0.10123456789234"));
CHECK_XPATH_STRING(c, STR("string(.101234567892345)"), STR("0.101234567892345"));
CHECK_XPATH_STRING(c, STR("string(.1012345678923456)"), STR("0.1012345678923456"));
CHECK_XPATH_STRING(c, STR("string(-.1)"), STR("-0.1"));
CHECK_XPATH_STRING(c, STR("string(-.01)"), STR("-0.01"));
CHECK_XPATH_STRING(c, STR("string(-.012)"), STR("-0.012"));
CHECK_XPATH_STRING(c, STR("string(-.0123)"), STR("-0.0123"));
CHECK_XPATH_STRING(c, STR("string(-.01234)"), STR("-0.01234"));
CHECK_XPATH_STRING(c, STR("string(-.012345)"), STR("-0.012345"));
CHECK_XPATH_STRING(c, STR("string(-.0123456)"), STR("-0.0123456"));
CHECK_XPATH_STRING(c, STR("string(-.01234567)"), STR("-0.01234567"));
CHECK_XPATH_STRING(c, STR("string(-.012345678)"), STR("-0.012345678"));
CHECK_XPATH_STRING(c, STR("string(-.0123456789)"), STR("-0.0123456789"));
CHECK_XPATH_STRING(c, STR("string(-.10123456789)"), STR("-0.10123456789"));
CHECK_XPATH_STRING(c, STR("string(-.101234567892)"), STR("-0.101234567892"));
CHECK_XPATH_STRING(c, STR("string(-.1012345678923)"), STR("-0.1012345678923"));
CHECK_XPATH_STRING(c, STR("string(-.10123456789234)"), STR("-0.10123456789234"));
CHECK_XPATH_STRING(c, STR("string(-.101234567892345)"), STR("-0.101234567892345"));
CHECK_XPATH_STRING(c, STR("string(-.1012345678923456)"), STR("-0.1012345678923456"));
}
#if 0 // $ this test requires 16 decimal digits of mantissa in number->string conversion; we have 15 since only 15 is guaranteed, and 16 introduces 'garbage' digits in common cases like 0.4
TEST(xpath_xalan_string_7_precision)
{
xml_node c;
CHECK_XPATH_STRING(c, STR("string(.10123456789234567)"), STR("0.10123456789234567"));
CHECK_XPATH_STRING(c, STR("string(.101234567892345678)"), STR("0.10123456789234568"));
CHECK_XPATH_STRING(c, STR("string(.1012345678923456789)"), STR("0.10123456789234568"));
CHECK_XPATH_STRING(c, STR("string(.10123456789234567893)"), STR("0.10123456789234568"));
CHECK_XPATH_STRING(c, STR("string(-.10123456789234567)"), STR("-0.10123456789234567"));
CHECK_XPATH_STRING(c, STR("string(-.101234567892345678)"), STR("-0.10123456789234568"));
CHECK_XPATH_STRING(c, STR("string(-.1012345678923456789)"), STR("-0.10123456789234568"));
CHECK_XPATH_STRING(c, STR("string(-.10123456789234567893)"), STR("-0.10123456789234568"));
}
#endif
TEST(xpath_xalan_string_8)
{
xml_node c;
// $ originally all last digits were 5's; a fully compliant implementation should correctly convert those as well,
// however some of these failed because of atof truncation
CHECK_XPATH_STRING(c, STR("string(9.87654321012344)"), STR("9.87654321012344"));
CHECK_XPATH_STRING(c, STR("string(98.7654321012345)"), STR("98.7654321012345"));
CHECK_XPATH_STRING(c, STR("string(987.654321012345)"), STR("987.654321012345"));
CHECK_XPATH_STRING(c, STR("string(9876.54321012344)"), STR("9876.54321012344"));
CHECK_XPATH_STRING(c, STR("string(98765.4321012345)"), STR("98765.4321012345"));
CHECK_XPATH_STRING(c, STR("string(987654.321012345)"), STR("987654.321012345"));
CHECK_XPATH_STRING(c, STR("string(9876543.21012345)"), STR("9876543.21012345"));
CHECK_XPATH_STRING(c, STR("string(98765432.1012345)"), STR("98765432.1012345"));
CHECK_XPATH_STRING(c, STR("string(987654321.012345)"), STR("987654321.012345"));
CHECK_XPATH_STRING(c, STR("string(9876543210.12344)"), STR("9876543210.12344"));
CHECK_XPATH_STRING(c, STR("string(98765432101.2345)"), STR("98765432101.2345"));
CHECK_XPATH_STRING(c, STR("string(987654321012.345)"), STR("987654321012.345"));
CHECK_XPATH_STRING(c, STR("string(9876543210123.43)"), STR("9876543210123.43"));
CHECK_XPATH_STRING(c, STR("string(98765432101234.5)"), STR("98765432101234.5"));
CHECK_XPATH_STRING(c, STR("string(-9.87654321012344)"), STR("-9.87654321012344"));
CHECK_XPATH_STRING(c, STR("string(-98.7654321012345)"), STR("-98.7654321012345"));
CHECK_XPATH_STRING(c, STR("string(-987.654321012345)"), STR("-987.654321012345"));
CHECK_XPATH_STRING(c, STR("string(-9876.54321012344)"), STR("-9876.54321012344"));
CHECK_XPATH_STRING(c, STR("string(-98765.4321012345)"), STR("-98765.4321012345"));
CHECK_XPATH_STRING(c, STR("string(-987654.321012345)"), STR("-987654.321012345"));
CHECK_XPATH_STRING(c, STR("string(-9876543.21012345)"), STR("-9876543.21012345"));
CHECK_XPATH_STRING(c, STR("string(-98765432.1012345)"), STR("-98765432.1012345"));
CHECK_XPATH_STRING(c, STR("string(-987654321.012345)"), STR("-987654321.012345"));
CHECK_XPATH_STRING(c, STR("string(-9876543210.12344)"), STR("-9876543210.12344"));
CHECK_XPATH_STRING(c, STR("string(-98765432101.2345)"), STR("-98765432101.2345"));
CHECK_XPATH_STRING(c, STR("string(-987654321012.345)"), STR("-987654321012.345"));
CHECK_XPATH_STRING(c, STR("string(-9876543210123.43)"), STR("-9876543210123.43"));
CHECK_XPATH_STRING(c, STR("string(-98765432101234.5)"), STR("-98765432101234.5"));
}
TEST(xpath_xalan_string_9)
{
xml_node c;
CHECK_XPATH_STRING(c, STR("string(.123456789)"), STR("0.123456789"));
CHECK_XPATH_STRING(c, STR("string(.0123456789)"), STR("0.0123456789"));
CHECK_XPATH_STRING(c, STR("string(.00123456789)"), STR("0.00123456789"));
CHECK_XPATH_STRING(c, STR("string(.000123456789)"), STR("0.000123456789"));
CHECK_XPATH_STRING(c, STR("string(.0000123456789)"), STR("0.0000123456789"));
CHECK_XPATH_STRING(c, STR("string(.00000123456789)"), STR("0.00000123456789"));
CHECK_XPATH_STRING(c, STR("string(.000000123456789)"), STR("0.000000123456789"));
CHECK_XPATH_STRING(c, STR("string(.0000000123456789)"), STR("0.0000000123456789"));
CHECK_XPATH_STRING(c, STR("string(.00000000123456789)"), STR("0.00000000123456789"));
CHECK_XPATH_STRING(c, STR("string(.000000000123456789)"), STR("0.000000000123456789"));
CHECK_XPATH_STRING(c, STR("string(.0000000000123456789)"), STR("0.0000000000123456789"));
CHECK_XPATH_STRING(c, STR("string(.00000000000123456789)"), STR("0.00000000000123456789"));
CHECK_XPATH_STRING(c, STR("string(.000000000000123456789)"), STR("0.000000000000123456789"));
CHECK_XPATH_STRING(c, STR("string(.0000000000000123456789)"), STR("0.0000000000000123456789"));
CHECK_XPATH_STRING(c, STR("string(.00000000000000123456789)"), STR("0.00000000000000123456789"));
CHECK_XPATH_STRING(c, STR("string(.000000000000000123456789)"), STR("0.000000000000000123456789"));
CHECK_XPATH_STRING(c, STR("string(.0000000000000000123456789)"), STR("0.0000000000000000123456789"));
CHECK_XPATH_STRING(c, STR("string(.00000000000000000123456789)"), STR("0.00000000000000000123456789"));
CHECK_XPATH_STRING(c, STR("string(.000000000000000000123456789)"), STR("0.000000000000000000123456789"));
CHECK_XPATH_STRING(c, STR("string(.0000000000000000000123456789)"), STR("0.0000000000000000000123456789"));
CHECK_XPATH_STRING(c, STR("string(.00000000000000000000123456789)"), STR("0.00000000000000000000123456789"));
CHECK_XPATH_STRING(c, STR("string(.000000000000000000000123456789)"), STR("0.000000000000000000000123456789"));
CHECK_XPATH_STRING(c, STR("string(.0000000000000000000000123456789)"), STR("0.0000000000000000000000123456789"));
CHECK_XPATH_STRING(c, STR("string(.00000000000000000000000123456789)"), STR("0.00000000000000000000000123456789"));
CHECK_XPATH_STRING(c, STR("string(.000000000000000000000000123456789)"), STR("0.000000000000000000000000123456789"));
CHECK_XPATH_STRING(c, STR("string(.0000000000000000000000000123456789)"), STR("0.0000000000000000000000000123456789"));
CHECK_XPATH_STRING(c, STR("string(.00000000000000000000000000123456789)"), STR("0.00000000000000000000000000123456789"));
CHECK_XPATH_STRING(c, STR("string(.000000000000000000000000000123456789)"), STR("0.000000000000000000000000000123456789"));
CHECK_XPATH_STRING(c, STR("string(.0000000000000000000000000000123456789)"), STR("0.0000000000000000000000000000123456789"));
CHECK_XPATH_STRING(c, STR("string(.00000000000000000000000000000123456789)"), STR("0.00000000000000000000000000000123456789"));
CHECK_XPATH_STRING(c, STR("string(.000000000000000000000000000000123456789)"), STR("0.000000000000000000000000000000123456789"));
CHECK_XPATH_STRING(c, STR("string(.0000000000000000000000000000000123456789)"), STR("0.0000000000000000000000000000000123456789"));
CHECK_XPATH_STRING(c, STR("string(.00000000000000000000000000000000123456789)"), STR("0.00000000000000000000000000000000123456789"));
CHECK_XPATH_STRING(c, STR("string(.000000000000000000000000000000000123456789)"), STR("0.000000000000000000000000000000000123456789"));
CHECK_XPATH_STRING(c, STR("string(.0000000000000000000000000000000000123456789)"), STR("0.0000000000000000000000000000000000123456789"));
CHECK_XPATH_STRING(c, STR("string(.00000000000000000000000000000000000123456789)"), STR("0.00000000000000000000000000000000000123456789"));
CHECK_XPATH_STRING(c, STR("string(.000000000000000000000000000000000000123456789)"), STR("0.000000000000000000000000000000000000123456789"));
CHECK_XPATH_STRING(c, STR("string(.0000000000000000000000000000000000000123456789)"), STR("0.0000000000000000000000000000000000000123456789"));
CHECK_XPATH_STRING(c, STR("string(.00000000000000000000000000000000000000123456789)"), STR("0.00000000000000000000000000000000000000123456789"));
CHECK_XPATH_STRING(c, STR("string(.000000000000000000000000000000000000000123456789)"), STR("0.000000000000000000000000000000000000000123456789"));
CHECK_XPATH_STRING(c, STR("string(.0000000000000000000000000000000000000000123456789)"), STR("0.0000000000000000000000000000000000000000123456789"));
CHECK_XPATH_STRING(c, STR("string(-.123456789)"), STR("-0.123456789"));
CHECK_XPATH_STRING(c, STR("string(-.0123456789)"), STR("-0.0123456789"));
CHECK_XPATH_STRING(c, STR("string(-.00123456789)"), STR("-0.00123456789"));
CHECK_XPATH_STRING(c, STR("string(-.000123456789)"), STR("-0.000123456789"));
CHECK_XPATH_STRING(c, STR("string(-.0000123456789)"), STR("-0.0000123456789"));
CHECK_XPATH_STRING(c, STR("string(-.00000123456789)"), STR("-0.00000123456789"));
CHECK_XPATH_STRING(c, STR("string(-.000000123456789)"), STR("-0.000000123456789"));
CHECK_XPATH_STRING(c, STR("string(-.0000000123456789)"), STR("-0.0000000123456789"));
CHECK_XPATH_STRING(c, STR("string(-.00000000123456789)"), STR("-0.00000000123456789"));
CHECK_XPATH_STRING(c, STR("string(-.000000000123456789)"), STR("-0.000000000123456789"));
CHECK_XPATH_STRING(c, STR("string(-.0000000000123456789)"), STR("-0.0000000000123456789"));
CHECK_XPATH_STRING(c, STR("string(-.00000000000123456789)"), STR("-0.00000000000123456789"));
CHECK_XPATH_STRING(c, STR("string(-.000000000000123456789)"), STR("-0.000000000000123456789"));
CHECK_XPATH_STRING(c, STR("string(-.0000000000000123456789)"), STR("-0.0000000000000123456789"));
CHECK_XPATH_STRING(c, STR("string(-.00000000000000123456789)"), STR("-0.00000000000000123456789"));
CHECK_XPATH_STRING(c, STR("string(-.000000000000000123456789)"), STR("-0.000000000000000123456789"));
CHECK_XPATH_STRING(c, STR("string(-.0000000000000000123456789)"), STR("-0.0000000000000000123456789"));
CHECK_XPATH_STRING(c, STR("string(-.00000000000000000123456789)"), STR("-0.00000000000000000123456789"));
CHECK_XPATH_STRING(c, STR("string(-.000000000000000000123456789)"), STR("-0.000000000000000000123456789"));
CHECK_XPATH_STRING(c, STR("string(-.0000000000000000000123456789)"), STR("-0.0000000000000000000123456789"));
CHECK_XPATH_STRING(c, STR("string(-.00000000000000000000123456789)"), STR("-0.00000000000000000000123456789"));
CHECK_XPATH_STRING(c, STR("string(-.000000000000000000000123456789)"), STR("-0.000000000000000000000123456789"));
CHECK_XPATH_STRING(c, STR("string(-.0000000000000000000000123456789)"), STR("-0.0000000000000000000000123456789"));
CHECK_XPATH_STRING(c, STR("string(-.00000000000000000000000123456789)"), STR("-0.00000000000000000000000123456789"));
CHECK_XPATH_STRING(c, STR("string(-.000000000000000000000000123456789)"), STR("-0.000000000000000000000000123456789"));
CHECK_XPATH_STRING(c, STR("string(-.0000000000000000000000000123456789)"), STR("-0.0000000000000000000000000123456789"));
CHECK_XPATH_STRING(c, STR("string(-.00000000000000000000000000123456789)"), STR("-0.00000000000000000000000000123456789"));
CHECK_XPATH_STRING(c, STR("string(-.000000000000000000000000000123456789)"), STR("-0.000000000000000000000000000123456789"));
CHECK_XPATH_STRING(c, STR("string(-.0000000000000000000000000000123456789)"), STR("-0.0000000000000000000000000000123456789"));
CHECK_XPATH_STRING(c, STR("string(-.00000000000000000000000000000123456789)"), STR("-0.00000000000000000000000000000123456789"));
CHECK_XPATH_STRING(c, STR("string(-.000000000000000000000000000000123456789)"), STR("-0.000000000000000000000000000000123456789"));
CHECK_XPATH_STRING(c, STR("string(-.0000000000000000000000000000000123456789)"), STR("-0.0000000000000000000000000000000123456789"));
CHECK_XPATH_STRING(c, STR("string(-.00000000000000000000000000000000123456789)"), STR("-0.00000000000000000000000000000000123456789"));
CHECK_XPATH_STRING(c, STR("string(-.000000000000000000000000000000000123456789)"), STR("-0.000000000000000000000000000000000123456789"));
CHECK_XPATH_STRING(c, STR("string(-.0000000000000000000000000000000000123456789)"), STR("-0.0000000000000000000000000000000000123456789"));
CHECK_XPATH_STRING(c, STR("string(-.00000000000000000000000000000000000123456789)"), STR("-0.00000000000000000000000000000000000123456789"));
CHECK_XPATH_STRING(c, STR("string(-.000000000000000000000000000000000000123456789)"), STR("-0.000000000000000000000000000000000000123456789"));
CHECK_XPATH_STRING(c, STR("string(-.0000000000000000000000000000000000000123456789)"), STR("-0.0000000000000000000000000000000000000123456789"));
CHECK_XPATH_STRING(c, STR("string(-.00000000000000000000000000000000000000123456789)"), STR("-0.00000000000000000000000000000000000000123456789"));
CHECK_XPATH_STRING(c, STR("string(-.000000000000000000000000000000000000000123456789)"), STR("-0.000000000000000000000000000000000000000123456789"));
CHECK_XPATH_STRING(c, STR("string(-.0000000000000000000000000000000000000000123456789)"), STR("-0.0000000000000000000000000000000000000000123456789"));
}
#endif
#define _CRT_SECURE_NO_WARNINGS
#ifndef PUGIXML_NO_XPATH
#include "test.hpp"
#include <string>
#include <algorithm>
using namespace pugi;
TEST_XML(xpath_xalan_string_1, "<doc a='test'>ENCYCLOPEDIA</doc>")
{
xml_node c;
CHECK_XPATH_NUMBER(c, STR("string-length('This is a test')"), 14);
CHECK_XPATH_BOOLEAN(c, STR("starts-with('ENCYCLOPEDIA', 'ENCY')"), true);
CHECK_XPATH_BOOLEAN(c, STR("contains('ENCYCLOPEDIA', 'CYCL')"), true);
CHECK_XPATH_STRING(c, STR("substring-before('1999/04/01', '/')"), STR("1999"));
CHECK_XPATH_STRING(c, STR("substring-after('1999/04/01', '/')"), STR("04/01"));
CHECK_XPATH_STRING(c, STR("normalize-space('\t\n\r\n ab\n cd\t\n\r\n ef\t\n\r ')"), STR("ab cd ef"));
CHECK_XPATH_STRING(c, STR("translate(\"bar\",\"abc\",\"ABC\")"), STR("BAr"));
CHECK_XPATH_STRING(c, STR("concat(\"x\",\"yz\")"), STR("xyz"));
CHECK_XPATH_STRING(c, STR("substring('1999/04/01', 1, 4)"), STR("1999"));
CHECK_XPATH_STRING(c, STR("substring('12345', 1.5, 2.6)"), STR("234"));
CHECK_XPATH_STRING(c, STR("substring('12345', 0, 3)"), STR("12"));
CHECK_XPATH_STRING(c, STR("substring('12345', 0 div 0, 3)"), STR(""));
CHECK_XPATH_STRING(c, STR("substring('12345', 1, 0 div 0)"), STR(""));
CHECK_XPATH_STRING(c, STR("substring('12345', -42, 1 div 0)"), STR("12345"));
CHECK_XPATH_STRING(c, STR("substring('12345', -1 div 0, 1 div 0)"), STR(""));
CHECK_XPATH_STRING(c, STR("substring(foo, 12, 3)"), STR(""));
CHECK_XPATH_STRING(c, STR("string(foo)"), STR(""));
CHECK_XPATH_STRING(c, STR("string(0)"), STR("0"));
CHECK_XPATH_STRING(c, STR("string(2)"), STR("2"));
CHECK_XPATH_STRING(c, STR("string('test')"), STR("test"));
CHECK_XPATH_STRING(c, STR("string('')"), STR(""));
CHECK_XPATH_BOOLEAN(c, STR("starts-with('ENCYCLOPEDIA', 'EN')"), true);
CHECK_XPATH_BOOLEAN(c, STR("starts-with('ENCYCLOPEDIA', 'en')"), false);
CHECK_XPATH_BOOLEAN(c, STR("starts-with('ab', 'abc')"), false);
CHECK_XPATH_BOOLEAN(c, STR("starts-with('abc', 'bc')"), false);
CHECK_XPATH_BOOLEAN(c, STR("starts-with('abc', '')"), true);
CHECK_XPATH_BOOLEAN(c, STR("starts-with('', '')"), true);
CHECK_XPATH_BOOLEAN(c, STR("starts-with('', 'abc')"), false);
CHECK_XPATH_BOOLEAN(c, STR("starts-with('true()', 'tr')"), true);
CHECK_XPATH_BOOLEAN(c, STR("starts-with(foo, 'EN')"), false);
CHECK_XPATH_BOOLEAN(doc, STR("starts-with(doc, 'EN')"), true);
CHECK_XPATH_BOOLEAN(doc, STR("starts-with(doc/@a, 'EN')"), false);
CHECK_XPATH_BOOLEAN(doc, STR("starts-with(doc/@a, 'te')"), true);
}
TEST_XML_FLAGS(xpath_xalan_string_2, "<doc>\n <av>\n <a>\n <b>b</b>\n <c>c</c>\n <d>d</d>\n <e>e</e>\n </a>\n <v>\n <w>w</w>\n <x>x</x>\n <y>y</y>\n <z>z</z>\n </v>\n </av>\n</doc>", parse_default | parse_ws_pcdata)
{
CHECK_XPATH_STRING(doc, STR("string(doc/av//*)"), STR("\n b\n c\n d\n e\n "));
CHECK_XPATH_STRING(doc, STR("normalize-space(string(doc/av//*))"), STR("b c d e"));
CHECK_XPATH_STRING(doc, STR("normalize-space('This is a test')"), STR("This is a test"));
}
TEST_XML(xpath_xalan_string_3, "<doc a='test'>ENCYCLOPEDIA</doc>")
{
xml_node c;
CHECK_XPATH_BOOLEAN(c, STR("contains('ENCYCLOPEDIA', 'TEST')"), false);
CHECK_XPATH_BOOLEAN(c, STR("contains('ENCYCLOPEDIA', 'CYCL')"), true);
CHECK_XPATH_BOOLEAN(c, STR("contains('ENCYCLOPEDIA', 'cycl')"), false);
CHECK_XPATH_BOOLEAN(doc, STR("contains(concat(.,'BC'),concat('A','B','C'))"), true);
CHECK_XPATH_BOOLEAN(c, STR("contains('ab', 'abc')"), false);
CHECK_XPATH_BOOLEAN(c, STR("contains('abc', 'bc')"), true);
CHECK_XPATH_BOOLEAN(c, STR("contains('abc', 'bcd')"), false);
CHECK_XPATH_BOOLEAN(c, STR("contains('abc', '')"), true);
CHECK_XPATH_BOOLEAN(c, STR("contains('', '')"), true);
CHECK_XPATH_BOOLEAN(c, STR("contains('', 'abc')"), false);
CHECK_XPATH_BOOLEAN(c, STR("contains('true()', 'e')"), true);
CHECK_XPATH_BOOLEAN(doc, STR("contains(., 'CYCL')"), true);
CHECK_XPATH_BOOLEAN(doc, STR("contains(., 'TEST')"), false);
CHECK_XPATH_BOOLEAN(doc, STR("contains(doc/@a, 'es')"), true);
CHECK_XPATH_BOOLEAN(doc, STR("contains(doc/@a, 'T')"), false);
CHECK_XPATH_STRING(c, STR("substring-before('ENCYCLOPEDIA', '/')"), STR(""));
CHECK_XPATH_STRING(c, STR("substring-before('ENCYCLOPEDIA', 'C')"), STR("EN"));
CHECK_XPATH_STRING(c, STR("substring-before('ENCYCLOPEDIA', 'c')"), STR(""));
CHECK_XPATH_STRING(c, STR("substring-before('ENCYCLOPEDIA', '')"), STR(""));
CHECK_XPATH_STRING(doc, STR("substring-before(., '/')"), STR(""));
CHECK_XPATH_STRING(doc, STR("substring-before(., 'C')"), STR("EN"));
CHECK_XPATH_STRING(doc, STR("substring-before(foo, '')"), STR(""));
CHECK_XPATH_STRING(doc, STR("substring-before(doc/@a, '/')"), STR(""));
CHECK_XPATH_STRING(doc, STR("substring-before(doc/@a, 'e')"), STR("t"));
CHECK_XPATH_STRING(doc, STR("substring-before(doc/@a, 't')"), STR(""));
CHECK_XPATH_STRING(c, STR("substring-after('ENCYCLOPEDIA', '/')"), STR(""));
CHECK_XPATH_STRING(c, STR("substring-after('ENCYCLOPEDIA', 'C')"), STR("YCLOPEDIA"));
CHECK_XPATH_STRING(c, STR("substring-after('ENCYCLOPEDIA', 'c')"), STR(""));
CHECK_XPATH_STRING(c, STR("substring-after('ENCYCLOPEDIA', '')"), STR("ENCYCLOPEDIA"));
CHECK_XPATH_STRING(doc, STR("substring-after(., '/')"), STR(""));
CHECK_XPATH_STRING(doc, STR("substring-after(., 'C')"), STR("YCLOPEDIA"));
CHECK_XPATH_STRING(doc, STR("substring-after(foo, '')"), STR(""));
CHECK_XPATH_STRING(doc, STR("substring-after(doc/@a, '/')"), STR(""));
CHECK_XPATH_STRING(doc, STR("substring-after(doc/@a, 'e')"), STR("st"));
CHECK_XPATH_STRING(doc, STR("substring-after(doc/@a, 't')"), STR("est"));
CHECK_XPATH_STRING(doc, STR("substring-after(doc/@a, 'st')"), STR(""));
}
TEST_XML(xpath_xalan_string_4, "<doc><a>a</a><b>b</b><c>c</c><d>d</d><e>ef</e><f attr='whatsup'>what's up</f></doc><cd><![CDATA[qua'lit\"y]]></cd>")
{
xml_node c;
CHECK_XPATH_STRING(c, STR("translate('BAR','abc','ABC')"), STR("BAR"));
CHECK_XPATH_STRING(c, STR("translate('bar','RAB','xyz')"), STR("bar"));
CHECK_XPATH_STRING(c, STR("translate('BAR','Rab','TxX')"), STR("BAT"));
CHECK_XPATH_STRING(c, STR("translate('zzaaazzz','abcz','ABC')"), STR("AAA"));
CHECK_XPATH_STRING(c, STR("translate('ddaaadddd','abcd','ABCxy')"), STR("xxAAAxxxx"));
CHECK_XPATH_STRING(c, STR("concat('a','b','c','d','ef')"), STR("abcdef"));
CHECK_XPATH_STRING(c, STR("concat(a, b)"), STR(""));
CHECK_XPATH_STRING(doc.child(STR("doc")), STR("concat(a, b)"), STR("ab"));
CHECK_XPATH_STRING(doc.child(STR("doc")), STR("concat(a, b, c, d, e)"), STR("abcdef"));
CHECK_XPATH_STRING(c, STR("concat('cd','34')"), STR("cd34"));
CHECK_XPATH_STRING(c, STR("concat('cd',34)"), STR("cd34"));
CHECK_XPATH_STRING(c, STR("concat('bc',string(23))"), STR("bc23"));
CHECK_XPATH_STRING(c, STR("concat(a,34)"), STR("34"));
CHECK_XPATH_STRING(doc.child(STR("doc")), STR("concat(a,34)"), STR("a34"));
CHECK_XPATH_STRING(c, STR("concat(false(),'ly')"), STR("falsely"));
CHECK_XPATH_FAIL(STR("concat(/*)"));
CHECK_XPATH_STRING(doc.child(STR("doc")), STR("concat(/*, '')"), STR("abcdefwhat's up"));
CHECK_XPATH_STRING(doc.child(STR("doc")), STR("concat(/*, /*[@attr='whatsup'])"), STR("abcdefwhat's up"));
CHECK_XPATH_STRING(doc.child(STR("doc")), STR("concat(/*, //*[@attr='whatsup'])"), STR("abcdefwhat's upwhat's up"));
CHECK_XPATH_STRING(c, STR("substring('ENCYCLOPEDIA', 8, 3)"), STR("PED"));
CHECK_XPATH_STRING(c, STR("substring('ENCYCLOPEDIA', 8)"), STR("PEDIA"));
CHECK_XPATH_STRING(c, STR("substring('abcdefghijk',0 div 0, 5)"), STR(""));
CHECK_XPATH_STRING(c, STR("substring('abcdefghijk',4, 6)"), STR("defghi"));
CHECK_XPATH_STRING(c, STR("substring('1999/04/01', 1, 0)"), STR(""));
CHECK_XPATH_STRING(c, STR("translate(normalize-space(' bar fly '), ' ', '_')"), STR("bar_fly"));
CHECK_XPATH_STRING(c, STR("translate('barter','abe','bao')"), STR("abrtor"));
CHECK_XPATH_STRING(c, STR("translate('barbarity', 'aeiouy', '******')"), STR("b*rb*r*t*"));
CHECK_XPATH_STRING(doc, STR("translate(cd, concat(\"aqu'\", '\"eos'), 'AQU-+EOS')"), STR("QUA-lit+y"));
CHECK_XPATH_STRING(c, STR("translate('quan+ti-ty', 'AQU-+EOS', concat(\"aqu'\", '\"eos'))"), STR("quan\"ti'ty"));
}
static const char_t* number_to_string_unsafe(int number)
{
static char_t buffer[16];
// construct number in reverse
char_t* it = buffer;
while (number)
{
*it++ = static_cast<char_t>('0' + number % 10);
number /= 10;
}
// zero terminate
*it = 0;
// reverse to get final result
std::reverse(buffer, it);
return buffer;
}
TEST(xpath_xalan_string_5)
{
const int count = 1000;
std::basic_string<char_t> query;
query.reserve(17 * count);
query += STR("concat(");
for (int i = 1; i < count; ++i)
{
query += STR("concat('t',");
query += number_to_string_unsafe(i);
query += STR("), ");
}
query += STR("'')");
std::basic_string<char_t> expected;
expected.reserve(4 * count);
for (int j = 1; j < count; ++j)
{
expected += STR("t");
expected += number_to_string_unsafe(j);
}
CHECK_XPATH_STRING(xml_node(), query.c_str(), expected.c_str());
}
TEST(xpath_xalan_string_6)
{
xml_node c;
CHECK_XPATH_STRING(c, STR("string(1)"), STR("1"));
CHECK_XPATH_STRING(c, STR("string(12)"), STR("12"));
CHECK_XPATH_STRING(c, STR("string(123)"), STR("123"));
CHECK_XPATH_STRING(c, STR("string(1234)"), STR("1234"));
CHECK_XPATH_STRING(c, STR("string(12345)"), STR("12345"));
CHECK_XPATH_STRING(c, STR("string(123456)"), STR("123456"));
CHECK_XPATH_STRING(c, STR("string(1234567)"), STR("1234567"));
CHECK_XPATH_STRING(c, STR("string(12345678)"), STR("12345678"));
CHECK_XPATH_STRING(c, STR("string(123456789)"), STR("123456789"));
CHECK_XPATH_STRING(c, STR("string(1234567890)"), STR("1234567890"));
CHECK_XPATH_STRING(c, STR("string(12345678901)"), STR("12345678901"));
CHECK_XPATH_STRING(c, STR("string(123456789012)"), STR("123456789012"));
CHECK_XPATH_STRING(c, STR("string(1234567890123)"), STR("1234567890123"));
CHECK_XPATH_STRING(c, STR("string(12345678901234)"), STR("12345678901234"));
CHECK_XPATH_STRING(c, STR("string(123456789012345)"), STR("123456789012345"));
CHECK_XPATH_STRING(c, STR("string(1234567890123456)"), STR("1234567890123456"));
CHECK_XPATH_STRING(c, STR("string(-1)"), STR("-1"));
CHECK_XPATH_STRING(c, STR("string(-12)"), STR("-12"));
CHECK_XPATH_STRING(c, STR("string(-123)"), STR("-123"));
CHECK_XPATH_STRING(c, STR("string(-1234)"), STR("-1234"));
CHECK_XPATH_STRING(c, STR("string(-12345)"), STR("-12345"));
CHECK_XPATH_STRING(c, STR("string(-123456)"), STR("-123456"));
CHECK_XPATH_STRING(c, STR("string(-1234567)"), STR("-1234567"));
CHECK_XPATH_STRING(c, STR("string(-12345678)"), STR("-12345678"));
CHECK_XPATH_STRING(c, STR("string(-123456789)"), STR("-123456789"));
CHECK_XPATH_STRING(c, STR("string(-1234567890)"), STR("-1234567890"));
CHECK_XPATH_STRING(c, STR("string(-12345678901)"), STR("-12345678901"));
CHECK_XPATH_STRING(c, STR("string(-123456789012)"), STR("-123456789012"));
CHECK_XPATH_STRING(c, STR("string(-1234567890123)"), STR("-1234567890123"));
CHECK_XPATH_STRING(c, STR("string(-12345678901234)"), STR("-12345678901234"));
CHECK_XPATH_STRING(c, STR("string(-123456789012345)"), STR("-123456789012345"));
CHECK_XPATH_STRING(c, STR("string(-1234567890123456)"), STR("-1234567890123456"));
}
#if 0 // $ this test requires round-to-nearest behavior in string->number conversion during parsing; atof gives us truncation
TEST(xpath_xalan_string_6_rounding)
{
xml_node c;
CHECK_XPATH_STRING(c, STR("string(12345678901234567)"), STR("12345678901234568"));
CHECK_XPATH_STRING(c, STR("string(123456789012345678)"), STR("123456789012345680"));
CHECK_XPATH_STRING(c, STR("string(-12345678901234567)"), STR("-12345678901234568"));
CHECK_XPATH_STRING(c, STR("string(-123456789012345678)"), STR("-123456789012345680"));
}
#endif
TEST(xpath_xalan_string_7)
{
xml_node c;
CHECK_XPATH_STRING(c, STR("string(.1)"), STR("0.1"));
CHECK_XPATH_STRING(c, STR("string(.01)"), STR("0.01"));
CHECK_XPATH_STRING(c, STR("string(.012)"), STR("0.012"));
CHECK_XPATH_STRING(c, STR("string(.0123)"), STR("0.0123"));
CHECK_XPATH_STRING(c, STR("string(.01234)"), STR("0.01234"));
CHECK_XPATH_STRING(c, STR("string(.012345)"), STR("0.012345"));
CHECK_XPATH_STRING(c, STR("string(.0123456)"), STR("0.0123456"));
CHECK_XPATH_STRING(c, STR("string(.01234567)"), STR("0.01234567"));
CHECK_XPATH_STRING(c, STR("string(.012345678)"), STR("0.012345678"));
CHECK_XPATH_STRING(c, STR("string(.0123456789)"), STR("0.0123456789"));
CHECK_XPATH_STRING(c, STR("string(.10123456789)"), STR("0.10123456789"));
CHECK_XPATH_STRING(c, STR("string(.101234567892)"), STR("0.101234567892"));
CHECK_XPATH_STRING(c, STR("string(.1012345678923)"), STR("0.1012345678923"));
CHECK_XPATH_STRING(c, STR("string(.10123456789234)"), STR("0.10123456789234"));
CHECK_XPATH_STRING(c, STR("string(.101234567892345)"), STR("0.101234567892345"));
CHECK_XPATH_STRING(c, STR("string(.1012345678923456)"), STR("0.1012345678923456"));
CHECK_XPATH_STRING(c, STR("string(-.1)"), STR("-0.1"));
CHECK_XPATH_STRING(c, STR("string(-.01)"), STR("-0.01"));
CHECK_XPATH_STRING(c, STR("string(-.012)"), STR("-0.012"));
CHECK_XPATH_STRING(c, STR("string(-.0123)"), STR("-0.0123"));
CHECK_XPATH_STRING(c, STR("string(-.01234)"), STR("-0.01234"));
CHECK_XPATH_STRING(c, STR("string(-.012345)"), STR("-0.012345"));
CHECK_XPATH_STRING(c, STR("string(-.0123456)"), STR("-0.0123456"));
CHECK_XPATH_STRING(c, STR("string(-.01234567)"), STR("-0.01234567"));
CHECK_XPATH_STRING(c, STR("string(-.012345678)"), STR("-0.012345678"));
CHECK_XPATH_STRING(c, STR("string(-.0123456789)"), STR("-0.0123456789"));
CHECK_XPATH_STRING(c, STR("string(-.10123456789)"), STR("-0.10123456789"));
CHECK_XPATH_STRING(c, STR("string(-.101234567892)"), STR("-0.101234567892"));
CHECK_XPATH_STRING(c, STR("string(-.1012345678923)"), STR("-0.1012345678923"));
CHECK_XPATH_STRING(c, STR("string(-.10123456789234)"), STR("-0.10123456789234"));
CHECK_XPATH_STRING(c, STR("string(-.101234567892345)"), STR("-0.101234567892345"));
CHECK_XPATH_STRING(c, STR("string(-.1012345678923456)"), STR("-0.1012345678923456"));
}
#if 0 // $ this test requires 16 decimal digits of mantissa in number->string conversion; we have 15 since only 15 is guaranteed, and 16 introduces 'garbage' digits in common cases like 0.4
TEST(xpath_xalan_string_7_precision)
{
xml_node c;
CHECK_XPATH_STRING(c, STR("string(.10123456789234567)"), STR("0.10123456789234567"));
CHECK_XPATH_STRING(c, STR("string(.101234567892345678)"), STR("0.10123456789234568"));
CHECK_XPATH_STRING(c, STR("string(.1012345678923456789)"), STR("0.10123456789234568"));
CHECK_XPATH_STRING(c, STR("string(.10123456789234567893)"), STR("0.10123456789234568"));
CHECK_XPATH_STRING(c, STR("string(-.10123456789234567)"), STR("-0.10123456789234567"));
CHECK_XPATH_STRING(c, STR("string(-.101234567892345678)"), STR("-0.10123456789234568"));
CHECK_XPATH_STRING(c, STR("string(-.1012345678923456789)"), STR("-0.10123456789234568"));
CHECK_XPATH_STRING(c, STR("string(-.10123456789234567893)"), STR("-0.10123456789234568"));
}
#endif
TEST(xpath_xalan_string_8)
{
xml_node c;
// $ originally all last digits were 5's; a fully compliant implementation should correctly convert those as well,
// however some of these failed because of atof truncation
CHECK_XPATH_STRING(c, STR("string(9.87654321012344)"), STR("9.87654321012344"));
CHECK_XPATH_STRING(c, STR("string(98.7654321012345)"), STR("98.7654321012345"));
CHECK_XPATH_STRING(c, STR("string(987.654321012345)"), STR("987.654321012345"));
CHECK_XPATH_STRING(c, STR("string(9876.54321012344)"), STR("9876.54321012344"));
CHECK_XPATH_STRING(c, STR("string(98765.4321012345)"), STR("98765.4321012345"));
CHECK_XPATH_STRING(c, STR("string(987654.321012345)"), STR("987654.321012345"));
CHECK_XPATH_STRING(c, STR("string(9876543.21012345)"), STR("9876543.21012345"));
CHECK_XPATH_STRING(c, STR("string(98765432.1012345)"), STR("98765432.1012345"));
CHECK_XPATH_STRING(c, STR("string(987654321.012345)"), STR("987654321.012345"));
CHECK_XPATH_STRING(c, STR("string(9876543210.12344)"), STR("9876543210.12344"));
CHECK_XPATH_STRING(c, STR("string(98765432101.2345)"), STR("98765432101.2345"));
CHECK_XPATH_STRING(c, STR("string(987654321012.345)"), STR("987654321012.345"));
CHECK_XPATH_STRING(c, STR("string(9876543210123.43)"), STR("9876543210123.43"));
CHECK_XPATH_STRING(c, STR("string(98765432101234.5)"), STR("98765432101234.5"));
CHECK_XPATH_STRING(c, STR("string(-9.87654321012344)"), STR("-9.87654321012344"));
CHECK_XPATH_STRING(c, STR("string(-98.7654321012345)"), STR("-98.7654321012345"));
CHECK_XPATH_STRING(c, STR("string(-987.654321012345)"), STR("-987.654321012345"));
CHECK_XPATH_STRING(c, STR("string(-9876.54321012344)"), STR("-9876.54321012344"));
CHECK_XPATH_STRING(c, STR("string(-98765.4321012345)"), STR("-98765.4321012345"));
CHECK_XPATH_STRING(c, STR("string(-987654.321012345)"), STR("-987654.321012345"));
CHECK_XPATH_STRING(c, STR("string(-9876543.21012345)"), STR("-9876543.21012345"));
CHECK_XPATH_STRING(c, STR("string(-98765432.1012345)"), STR("-98765432.1012345"));
CHECK_XPATH_STRING(c, STR("string(-987654321.012345)"), STR("-987654321.012345"));
CHECK_XPATH_STRING(c, STR("string(-9876543210.12344)"), STR("-9876543210.12344"));
CHECK_XPATH_STRING(c, STR("string(-98765432101.2345)"), STR("-98765432101.2345"));
CHECK_XPATH_STRING(c, STR("string(-987654321012.345)"), STR("-987654321012.345"));
CHECK_XPATH_STRING(c, STR("string(-9876543210123.43)"), STR("-9876543210123.43"));
CHECK_XPATH_STRING(c, STR("string(-98765432101234.5)"), STR("-98765432101234.5"));
}
TEST(xpath_xalan_string_9)
{
xml_node c;
CHECK_XPATH_STRING(c, STR("string(.123456789)"), STR("0.123456789"));
CHECK_XPATH_STRING(c, STR("string(.0123456789)"), STR("0.0123456789"));
CHECK_XPATH_STRING(c, STR("string(.00123456789)"), STR("0.00123456789"));
CHECK_XPATH_STRING(c, STR("string(.000123456789)"), STR("0.000123456789"));
CHECK_XPATH_STRING(c, STR("string(.0000123456789)"), STR("0.0000123456789"));
CHECK_XPATH_STRING(c, STR("string(.00000123456789)"), STR("0.00000123456789"));
CHECK_XPATH_STRING(c, STR("string(.000000123456789)"), STR("0.000000123456789"));
CHECK_XPATH_STRING(c, STR("string(.0000000123456789)"), STR("0.0000000123456789"));
CHECK_XPATH_STRING(c, STR("string(.00000000123456789)"), STR("0.00000000123456789"));
CHECK_XPATH_STRING(c, STR("string(.000000000123456789)"), STR("0.000000000123456789"));
CHECK_XPATH_STRING(c, STR("string(.0000000000123456789)"), STR("0.0000000000123456789"));
CHECK_XPATH_STRING(c, STR("string(.00000000000123456789)"), STR("0.00000000000123456789"));
CHECK_XPATH_STRING(c, STR("string(.000000000000123456789)"), STR("0.000000000000123456789"));
CHECK_XPATH_STRING(c, STR("string(.0000000000000123456789)"), STR("0.0000000000000123456789"));
CHECK_XPATH_STRING(c, STR("string(.00000000000000123456789)"), STR("0.00000000000000123456789"));
CHECK_XPATH_STRING(c, STR("string(.000000000000000123456789)"), STR("0.000000000000000123456789"));
CHECK_XPATH_STRING(c, STR("string(.0000000000000000123456789)"), STR("0.0000000000000000123456789"));
CHECK_XPATH_STRING(c, STR("string(.00000000000000000123456789)"), STR("0.00000000000000000123456789"));
CHECK_XPATH_STRING(c, STR("string(.000000000000000000123456789)"), STR("0.000000000000000000123456789"));
CHECK_XPATH_STRING(c, STR("string(.0000000000000000000123456789)"), STR("0.0000000000000000000123456789"));
CHECK_XPATH_STRING(c, STR("string(.00000000000000000000123456789)"), STR("0.00000000000000000000123456789"));
CHECK_XPATH_STRING(c, STR("string(.000000000000000000000123456789)"), STR("0.000000000000000000000123456789"));
CHECK_XPATH_STRING(c, STR("string(.0000000000000000000000123456789)"), STR("0.0000000000000000000000123456789"));
CHECK_XPATH_STRING(c, STR("string(.00000000000000000000000123456789)"), STR("0.00000000000000000000000123456789"));
CHECK_XPATH_STRING(c, STR("string(.000000000000000000000000123456789)"), STR("0.000000000000000000000000123456789"));
CHECK_XPATH_STRING(c, STR("string(.0000000000000000000000000123456789)"), STR("0.0000000000000000000000000123456789"));
CHECK_XPATH_STRING(c, STR("string(.00000000000000000000000000123456789)"), STR("0.00000000000000000000000000123456789"));
CHECK_XPATH_STRING(c, STR("string(.000000000000000000000000000123456789)"), STR("0.000000000000000000000000000123456789"));
CHECK_XPATH_STRING(c, STR("string(.0000000000000000000000000000123456789)"), STR("0.0000000000000000000000000000123456789"));
CHECK_XPATH_STRING(c, STR("string(.00000000000000000000000000000123456789)"), STR("0.00000000000000000000000000000123456789"));
CHECK_XPATH_STRING(c, STR("string(.000000000000000000000000000000123456789)"), STR("0.000000000000000000000000000000123456789"));
CHECK_XPATH_STRING(c, STR("string(.0000000000000000000000000000000123456789)"), STR("0.0000000000000000000000000000000123456789"));
CHECK_XPATH_STRING(c, STR("string(.00000000000000000000000000000000123456789)"), STR("0.00000000000000000000000000000000123456789"));
CHECK_XPATH_STRING(c, STR("string(.000000000000000000000000000000000123456789)"), STR("0.000000000000000000000000000000000123456789"));
CHECK_XPATH_STRING(c, STR("string(.0000000000000000000000000000000000123456789)"), STR("0.0000000000000000000000000000000000123456789"));
CHECK_XPATH_STRING(c, STR("string(.00000000000000000000000000000000000123456789)"), STR("0.00000000000000000000000000000000000123456789"));
CHECK_XPATH_STRING(c, STR("string(.000000000000000000000000000000000000123456789)"), STR("0.000000000000000000000000000000000000123456789"));
CHECK_XPATH_STRING(c, STR("string(.0000000000000000000000000000000000000123456789)"), STR("0.0000000000000000000000000000000000000123456789"));
CHECK_XPATH_STRING(c, STR("string(.00000000000000000000000000000000000000123456789)"), STR("0.00000000000000000000000000000000000000123456789"));
CHECK_XPATH_STRING(c, STR("string(.000000000000000000000000000000000000000123456789)"), STR("0.000000000000000000000000000000000000000123456789"));
CHECK_XPATH_STRING(c, STR("string(.0000000000000000000000000000000000000000123456789)"), STR("0.0000000000000000000000000000000000000000123456789"));
CHECK_XPATH_STRING(c, STR("string(-.123456789)"), STR("-0.123456789"));
CHECK_XPATH_STRING(c, STR("string(-.0123456789)"), STR("-0.0123456789"));
CHECK_XPATH_STRING(c, STR("string(-.00123456789)"), STR("-0.00123456789"));
CHECK_XPATH_STRING(c, STR("string(-.000123456789)"), STR("-0.000123456789"));
CHECK_XPATH_STRING(c, STR("string(-.0000123456789)"), STR("-0.0000123456789"));
CHECK_XPATH_STRING(c, STR("string(-.00000123456789)"), STR("-0.00000123456789"));
CHECK_XPATH_STRING(c, STR("string(-.000000123456789)"), STR("-0.000000123456789"));
CHECK_XPATH_STRING(c, STR("string(-.0000000123456789)"), STR("-0.0000000123456789"));
CHECK_XPATH_STRING(c, STR("string(-.00000000123456789)"), STR("-0.00000000123456789"));
CHECK_XPATH_STRING(c, STR("string(-.000000000123456789)"), STR("-0.000000000123456789"));
CHECK_XPATH_STRING(c, STR("string(-.0000000000123456789)"), STR("-0.0000000000123456789"));
CHECK_XPATH_STRING(c, STR("string(-.00000000000123456789)"), STR("-0.00000000000123456789"));
CHECK_XPATH_STRING(c, STR("string(-.000000000000123456789)"), STR("-0.000000000000123456789"));
CHECK_XPATH_STRING(c, STR("string(-.0000000000000123456789)"), STR("-0.0000000000000123456789"));
CHECK_XPATH_STRING(c, STR("string(-.00000000000000123456789)"), STR("-0.00000000000000123456789"));
CHECK_XPATH_STRING(c, STR("string(-.000000000000000123456789)"), STR("-0.000000000000000123456789"));
CHECK_XPATH_STRING(c, STR("string(-.0000000000000000123456789)"), STR("-0.0000000000000000123456789"));
CHECK_XPATH_STRING(c, STR("string(-.00000000000000000123456789)"), STR("-0.00000000000000000123456789"));
CHECK_XPATH_STRING(c, STR("string(-.000000000000000000123456789)"), STR("-0.000000000000000000123456789"));
CHECK_XPATH_STRING(c, STR("string(-.0000000000000000000123456789)"), STR("-0.0000000000000000000123456789"));
CHECK_XPATH_STRING(c, STR("string(-.00000000000000000000123456789)"), STR("-0.00000000000000000000123456789"));
CHECK_XPATH_STRING(c, STR("string(-.000000000000000000000123456789)"), STR("-0.000000000000000000000123456789"));
CHECK_XPATH_STRING(c, STR("string(-.0000000000000000000000123456789)"), STR("-0.0000000000000000000000123456789"));
CHECK_XPATH_STRING(c, STR("string(-.00000000000000000000000123456789)"), STR("-0.00000000000000000000000123456789"));
CHECK_XPATH_STRING(c, STR("string(-.000000000000000000000000123456789)"), STR("-0.000000000000000000000000123456789"));
CHECK_XPATH_STRING(c, STR("string(-.0000000000000000000000000123456789)"), STR("-0.0000000000000000000000000123456789"));
CHECK_XPATH_STRING(c, STR("string(-.00000000000000000000000000123456789)"), STR("-0.00000000000000000000000000123456789"));
CHECK_XPATH_STRING(c, STR("string(-.000000000000000000000000000123456789)"), STR("-0.000000000000000000000000000123456789"));
CHECK_XPATH_STRING(c, STR("string(-.0000000000000000000000000000123456789)"), STR("-0.0000000000000000000000000000123456789"));
CHECK_XPATH_STRING(c, STR("string(-.00000000000000000000000000000123456789)"), STR("-0.00000000000000000000000000000123456789"));
CHECK_XPATH_STRING(c, STR("string(-.000000000000000000000000000000123456789)"), STR("-0.000000000000000000000000000000123456789"));
CHECK_XPATH_STRING(c, STR("string(-.0000000000000000000000000000000123456789)"), STR("-0.0000000000000000000000000000000123456789"));
CHECK_XPATH_STRING(c, STR("string(-.00000000000000000000000000000000123456789)"), STR("-0.00000000000000000000000000000000123456789"));
CHECK_XPATH_STRING(c, STR("string(-.000000000000000000000000000000000123456789)"), STR("-0.000000000000000000000000000000000123456789"));
CHECK_XPATH_STRING(c, STR("string(-.0000000000000000000000000000000000123456789)"), STR("-0.0000000000000000000000000000000000123456789"));
CHECK_XPATH_STRING(c, STR("string(-.00000000000000000000000000000000000123456789)"), STR("-0.00000000000000000000000000000000000123456789"));
CHECK_XPATH_STRING(c, STR("string(-.000000000000000000000000000000000000123456789)"), STR("-0.000000000000000000000000000000000000123456789"));
CHECK_XPATH_STRING(c, STR("string(-.0000000000000000000000000000000000000123456789)"), STR("-0.0000000000000000000000000000000000000123456789"));
CHECK_XPATH_STRING(c, STR("string(-.00000000000000000000000000000000000000123456789)"), STR("-0.00000000000000000000000000000000000000123456789"));
CHECK_XPATH_STRING(c, STR("string(-.000000000000000000000000000000000000000123456789)"), STR("-0.000000000000000000000000000000000000000123456789"));
CHECK_XPATH_STRING(c, STR("string(-.0000000000000000000000000000000000000000123456789)"), STR("-0.0000000000000000000000000000000000000000123456789"));
}
#endif

View File

@ -1,321 +1,321 @@
#ifndef PUGIXML_NO_XPATH
#include "test.hpp"
using namespace pugi;
TEST_XML(xpath_xalan_axes_1, "<far-north><north-north-west1/><north-north-west2/><north><near-north><far-west/><west/><near-west/><center center-attr-1='c1' center-attr-2='c2' center-attr-3='c3'><near-south-west/><near-south><south><far-south/></south></near-south><near-south-east/></center><near-east/><east/><far-east/></near-north></north><north-north-east1/><north-north-east2/></far-north>")
{
xml_node center = doc.select_node(STR("//center")).node();
CHECK_XPATH_NODESET(center, STR("self::*[near-south]")) % 10;
CHECK_XPATH_NODESET(center, STR("self::*[@center-attr-2]")) % 10;
CHECK_XPATH_NODESET(center, STR("preceding-sibling::*")) % 9 % 8 % 7;
CHECK_XPATH_NODESET(center, STR("preceding-sibling::*/following-sibling::*")) % 8 % 9 % 10 % 19 % 20 % 21;
CHECK_XPATH_NODESET(center, STR("preceding-sibling::*[2]/following-sibling::*")) % 9 % 10 % 19 % 20 % 21;
CHECK_XPATH_NODESET(center, STR("preceding-sibling::*[2]/following-sibling::*[4]")) % 20;
CHECK_XPATH_NODESET(center, STR("preceding-sibling::*[2]/following-sibling::*[4]/preceding-sibling::*[5]/following-sibling::*[4]/following-sibling::*[2]")) % 21;
CHECK_XPATH_NODESET(center, STR("following-sibling::*")) % 19 % 20 % 21;
CHECK_XPATH_NODESET(center, STR("following-sibling::*/preceding-sibling::*")) % 7 % 8 % 9 % 10 % 19 % 20;
CHECK_XPATH_NODESET(center, STR("following-sibling::*[2]/preceding-sibling::*")) % 19 % 10 % 9 % 8 % 7;
CHECK_XPATH_NODESET(center, STR("following-sibling::*[2]/preceding-sibling::*[4]")) % 8;
CHECK_XPATH_NODESET(center, STR("following-sibling::*[2]/preceding-sibling::*[4]/following-sibling::*[5]/preceding-sibling::*[4]/preceding-sibling::*[2]")) % 7;
CHECK_XPATH_NODESET(center, STR("following::*[4]/../*[2]")) % 4;
CHECK_XPATH_NODESET(center, STR("preceding::*[2]/../following::*")) % 22 % 23;
CHECK_XPATH_NODESET(center, STR("preceding::*[2]/../descendant::*[10]/following-sibling::east")) % 20;
CHECK_XPATH_NODESET(center, STR("//*")) % 2 % 3 % 4 % 5 % 6 % 7 % 8 % 9 % 10 % 14 % 15 % 16 % 17 % 18 % 19 % 20 % 21 % 22 % 23;
CHECK_XPATH_NODESET(center, STR("//ancestor::*")) % 2 % 5 % 6 % 10 % 15 % 16;
CHECK_XPATH_NODESET(center, STR("//*[count(ancestor::*) >= 2]/../parent::*")) % 2 % 5 % 6 % 10 % 15;
CHECK_XPATH_NODESET(center, STR("//*[count(./*/*) > 0]")) % 2 % 5 % 6 % 10 % 15;
CHECK_XPATH_NODESET(center, STR("@*/ancestor::*")) % 2 % 5 % 6 % 10;
CHECK_XPATH_NODESET(center, STR("@*/following::*")) % 14 % 15 % 16 % 17 % 18 % 19 % 20 % 21 % 22 % 23;
CHECK_XPATH_NODESET(center, STR("@*/preceding::*")) % 3 % 4 % 7 % 8 % 9;
CHECK_XPATH_NODESET(center, STR("preceding-sibling::*|following-sibling::*")) % 7 % 8 % 9 % 19 % 20 % 21;
CHECK_XPATH_NODESET(center, STR("(preceding-sibling::*|following-sibling::*)/ancestor::*[last()]/*[last()]")) % 23;
CHECK_XPATH_NODESET(center, STR(".//near-south/preceding-sibling::*|following-sibling::east/ancestor-or-self::*[2]")) % 6 % 14;
}
TEST_XML_FLAGS(xpath_xalan_axes_2, "<far-north> Level-1<north-north-west1/><north-north-west2/><!-- Comment-2 --> Level-2<?a-pi pi-2?><north><!-- Comment-3 --> Level-3<?a-pi pi-3?><near-north><far-west/><west/><near-west/><!-- Comment-4 --> Level-4<?a-pi pi-4?><center center-attr-1='c1' center-attr-2='c2' center-attr-3='c3'><near-south-west/><!--Comment-5--> Level-5<?a-pi pi-5?><near-south><!--Comment-6--> Level-6<?a-pi pi-6?><south attr1='First' attr2='Last'> <far-south/></south></near-south><near-south-east/></center><near-east/><east/><far-east/></near-north></north><north-north-east1/><north-north-east2/></far-north>", parse_default | parse_comments | parse_pi)
{
xml_node center = doc.select_node(STR("//center")).node();
CHECK_XPATH_NODESET(center, STR("@*")) % 21 % 22 % 23;
CHECK_XPATH_NODESET(center, STR("@*/child::*"));
CHECK_XPATH_NODESET(center, STR("@*/descendant::node()"));
CHECK_XPATH_NODESET(center, STR("@*/parent::node()")) % 20;
CHECK_XPATH_NODESET(center, STR("@*/ancestor::node()")) % 1 % 2 % 9 % 13 % 20;
CHECK_XPATH_NODESET(center, STR("@*/self::node()")) % 21 % 22 % 23;
CHECK_XPATH_NODESET(center, STR("@*/.")) % 21 % 22 % 23;
CHECK_XPATH_NODESET(center, STR("@*/descendant-or-self::node()")) % 21 % 22 % 23;
CHECK_XPATH_NODESET(center, STR("@*/ancestor-or-self::node()")) % 1 % 2 % 9 % 13 % 20 % 21 % 22 % 23;
CHECK_XPATH_NODESET(center, STR("@*/ancestor-or-self::*")) % 2 % 9 % 13 % 20;
CHECK_XPATH_NODESET(center, STR("@*/preceding-sibling::node()"));
CHECK_XPATH_NODESET(center, STR("@*/following-sibling::*"));
CHECK_XPATH_NODESET(center, STR("@*/ancestor::*/near-north/*[4]/@*/preceding::*")) % 4 % 5 % 14 % 15 % 16;
CHECK_XPATH_NODESET(center, STR("@*/ancestor::*/near-north/*[4]/@*/preceding::comment()")) % 6 % 10 % 17;
CHECK_XPATH_NODESET(center, STR("@*/ancestor::*/near-north/*[4]/@*/preceding::text()")) % 3 % 7 % 11 % 18;
CHECK_XPATH_NODESET(center, STR("@*/ancestor::*/near-north/*[4]/@*/preceding::processing-instruction()")) % 8 % 12 % 19;
CHECK_XPATH_NODESET(center, STR("@*/following::comment()")) % 25 % 29;
CHECK_XPATH_NODESET(center, STR("@*/following::processing-instruction()")) % 27 % 31;
CHECK_XPATH_NODESET(center, STR("@*/following::text()")) % 26 % 30;
CHECK_XPATH_NODESET(center, STR("@*/ancestor::*/near-north/*[4]/@*/preceding::node()")) % 3 % 4 % 5 % 6 % 7 % 8 % 10 % 11 % 12 % 14 % 15 % 16 % 17 % 18 % 19;
CHECK_XPATH_NODESET(center, STR("@*/ancestor::*/near-north/*[4]/@*/following::node()")) % 24 % 25 % 26 % 27 % 28 % 29 % 30 % 31 % 32 % 35 % 36 % 37 % 38 % 39 % 40 % 41;
CHECK_XPATH_NODESET(center, STR("(//comment())[1]/..")) % 2;
CHECK_XPATH_NODESET(center, STR("(//attribute::*)[1]/../..")) % 13;
}
TEST_XML(xpath_xalan_axes_3, "<far-north><north><near-north><far-west/><west/><near-west/><center><near-south><south><far-south/></south></near-south></center><near-east/><east/><far-east/></near-north></north></far-north>")
{
xml_node center = doc.select_node(STR("//center")).node();
CHECK_XPATH_NODESET(center, STR("ancestor-or-self::*")) % 8 % 4 % 3 % 2;
CHECK_XPATH_NODESET(center, STR("ancestor::*[3]")) % 2;
CHECK_XPATH_NODESET(center, STR("ancestor-or-self::*[1]")) % 8;
CHECK_XPATH_NODESET(center, STR("@*[2]"));
CHECK_XPATH_NODESET(center, STR("child::*[2]"));
CHECK_XPATH_NODESET(center, STR("child::near-south-west"));
CHECK_XPATH_NODESET(center, STR("descendant::*[3]")) % 11;
CHECK_XPATH_NODESET(center, STR("descendant::far-south")) % 11;
CHECK_XPATH_NODESET(center, STR("descendant-or-self::*[3]")) % 10;
CHECK_XPATH_NODESET(center, STR("descendant-or-self::far-south")) % 11;
CHECK_XPATH_NODESET(center, STR("descendant-or-self::center")) % 8;
CHECK_XPATH_NODESET(center, STR("following::*[4]"));
CHECK_XPATH_NODESET(center, STR("following::out-yonder-east"));
CHECK_XPATH_NODESET(center, STR("preceding::*[4]"));
CHECK_XPATH_NODESET(center, STR("preceding::out-yonder-west"));
CHECK_XPATH_NODESET(center, STR("following-sibling::*[2]")) % 13;
CHECK_XPATH_NODESET(center, STR("following-sibling::east")) % 13;
CHECK_XPATH_NODESET(center, STR("preceding-sibling::*[2]")) % 6;
CHECK_XPATH_NODESET(center, STR("preceding-sibling::west")) % 6;
CHECK_XPATH_NODESET(center, STR("parent::near-north")) % 4;
CHECK_XPATH_NODESET(center, STR("parent::*[1]")) % 4;
CHECK_XPATH_NODESET(center, STR("parent::foo"));
CHECK_XPATH_NODESET(center, STR("..")) % 4;
CHECK_XPATH_NODESET(center, STR("self::center")) % 8;
CHECK_XPATH_NODESET(center, STR("self::*[1]")) % 8;
CHECK_XPATH_NODESET(center, STR("self::foo"));
CHECK_XPATH_NODESET(center, STR(".")) % 8;
CHECK_XPATH_NODESET(center, STR("/far-north/north/near-north/center/ancestor-or-self::*")) % 8 % 4 % 3 % 2;
}
TEST_XML(xpath_xalan_axes_4, "<far-north><north><near-north><far-west/><west/><near-west/><center><near-south><south><far-south/></south></near-south></center><near-east/><east/><far-east/></near-north></north></far-north>")
{
xml_node north = doc.select_node(STR("//north")).node();
CHECK_XPATH_STRING(north, STR("name(/descendant-or-self::north)"), STR("north"));
CHECK_XPATH_STRING(north, STR("name(/descendant::near-north)"), STR("near-north"));
CHECK_XPATH_STRING(north, STR("name(self::node()/descendant-or-self::north)"), STR("north"));
CHECK_XPATH_STRING(north, STR("name(self::node()/descendant::near-north)"), STR("near-north"));
CHECK_XPATH_STRING(north, STR("name(descendant-or-self::north/descendant-or-self::north)"), STR("north"));
CHECK_XPATH_STRING(north, STR("name(descendant-or-self::north/descendant::near-north)"), STR("near-north"));
CHECK_XPATH_STRING(north, STR("name(descendant-or-self::north/child::near-north)"), STR("near-north"));
CHECK_XPATH_STRING(north, STR("name(descendant::near-north/descendant-or-self::near-north)"), STR("near-north"));
CHECK_XPATH_STRING(north, STR("name(descendant::near-north/descendant::far-west)"), STR("far-west"));
CHECK_XPATH_STRING(north, STR("name(/descendant-or-self::north/descendant-or-self::north)"), STR("north"));
CHECK_XPATH_STRING(north, STR("name(/descendant-or-self::north/child::near-north)"), STR("near-north"));
CHECK_XPATH_STRING(north, STR("name(/descendant::near-north/descendant-or-self::near-north)"), STR("near-north"));
CHECK_XPATH_STRING(north, STR("name(self::node()/descendant-or-self::north/descendant-or-self::north)"), STR("north"));
CHECK_XPATH_STRING(north, STR("name(self::node()/descendant-or-self::north/child::near-north)"), STR("near-north"));
CHECK_XPATH_STRING(north, STR("name(self::node()/descendant::near-north/descendant-or-self::far-west)"), STR("far-west"));
CHECK_XPATH_STRING(north, STR("name(self::node()/descendant::near-north/child::far-west)"), STR("far-west"));
CHECK_XPATH_STRING(north, STR("name(descendant-or-self::north/descendant-or-self::north/descendant-or-self::north)"), STR("north"));
CHECK_XPATH_STRING(north, STR("name(descendant-or-self::north/descendant-or-self::north/child::near-north)"), STR("near-north"));
CHECK_XPATH_STRING(north, STR("name(descendant-or-self::north/descendant::near-north/descendant-or-self::near-north)"), STR("near-north"));
CHECK_XPATH_STRING(north, STR("name(descendant-or-self::north/descendant::near-north/child::far-west)"), STR("far-west"));
CHECK_XPATH_STRING(north, STR("name(descendant-or-self::north/child::near-north/descendant-or-self::near-north)"), STR("near-north"));
CHECK_XPATH_STRING(north, STR("name(descendant-or-self::north/child::near-north/child::far-west)"), STR("far-west"));
CHECK_XPATH_STRING(north, STR("name(descendant::near-north/descendant-or-self::near-north/descendant-or-self::near-north)"), STR("near-north"));
CHECK_XPATH_STRING(north, STR("name(descendant::near-north/descendant-or-self::near-north/child::far-west)"), STR("far-west"));
CHECK_XPATH_STRING(north, STR("name(descendant::near-north/descendant::far-west/descendant-or-self::far-west)"), STR("far-west"));
CHECK_XPATH_STRING(north, STR("name(descendant-or-self::node()/descendant-or-self::north)"), STR("north"));
CHECK_XPATH_STRING(north, STR("name(descendant-or-self::node()/descendant::near-north)"), STR("near-north"));
CHECK_XPATH_STRING(north, STR("name(descendant-or-self::node()/child::near-north)"), STR("near-north"));
CHECK_XPATH_STRING(north, STR("name(descendant::node()/descendant-or-self::near-north)"), STR("near-north"));
CHECK_XPATH_STRING(north, STR("name(descendant::node()/descendant::far-west)"), STR("far-west"));
CHECK_XPATH_STRING(north, STR("name(/descendant-or-self::node()/descendant-or-self::north)"), STR("north"));
CHECK_XPATH_STRING(north, STR("name(/descendant-or-self::node()/child::near-north)"), STR("near-north"));
CHECK_XPATH_STRING(north, STR("name(/descendant::node()/descendant-or-self::near-north)"), STR("near-north"));
CHECK_XPATH_STRING(north, STR("name(self::node()/descendant-or-self::node()/descendant-or-self::north)"), STR("north"));
CHECK_XPATH_STRING(north, STR("name(self::node()/descendant-or-self::node()/child::near-north)"), STR("near-north"));
CHECK_XPATH_STRING(north, STR("name(self::node()/descendant::node()/descendant-or-self::far-west)"), STR("far-west"));
CHECK_XPATH_STRING(north, STR("name(self::node()/descendant::node()/child::far-west)"), STR("far-west"));
CHECK_XPATH_STRING(north, STR("name(descendant-or-self::node()/descendant-or-self::node()/descendant-or-self::north)"), STR("north"));
CHECK_XPATH_STRING(north, STR("name(descendant-or-self::node()/descendant-or-self::node()/child::near-north)"), STR("near-north"));
CHECK_XPATH_STRING(north, STR("name(descendant-or-self::node()/descendant::node()/descendant-or-self::near-north)"), STR("near-north"));
CHECK_XPATH_STRING(north, STR("name(descendant-or-self::node()/descendant::node()/child::far-west)"), STR("far-west"));
CHECK_XPATH_STRING(north, STR("name(descendant-or-self::node()/child::node()/descendant-or-self::near-north)"), STR("near-north"));
CHECK_XPATH_STRING(north, STR("name(descendant-or-self::node()/child::node()/child::far-west)"), STR("far-west"));
CHECK_XPATH_STRING(north, STR("name(descendant::node()/descendant-or-self::node()/descendant-or-self::near-north)"), STR("near-north"));
CHECK_XPATH_STRING(north, STR("name(descendant::node()/descendant-or-self::node()/child::far-west)"), STR("far-west"));
CHECK_XPATH_STRING(north, STR("name(descendant::node()/descendant::node()/descendant-or-self::far-west)"), STR("far-west"));
}
TEST_XML_FLAGS(xpath_xalan_axes_5, "<text>text</text><comment><!--comment--></comment><pi><?pi?></pi>", parse_default | parse_comments | parse_pi)
{
CHECK_XPATH_NODESET(doc, STR("text/self::text()"));
CHECK_XPATH_NODESET(doc, STR("comment/self::comment()"));
CHECK_XPATH_NODESET(doc, STR("pi/self::processing-instruction()"));
}
TEST_XML(xpath_xalan_axes_6, "<doc><T>Test for source tree depth</T><a><T>A</T><b><T>B</T><c><T>C</T><d><T>D</T><e><T>E</T><f><T>F</T><g><T>G</T><h><T>H</T><i><T>I</T><j><T>J</T><k><T>K</T><l><T>L</T><m><T>M</T><n><T>N</T><o><T>O</T></o></n></m></l></k></j></i></h></g></f></e></d></c></b></a></doc>")
{
CHECK_XPATH_NODESET(doc, STR("//T")) % 3 % 6 % 9 % 12 % 15 % 18 % 21 % 24 % 27 % 30 % 33 % 36 % 39 % 42 % 45 % 48;
}
TEST_XML(xpath_xalan_axes_7, "<far-north><north><near-north><far-west/><west/><near-west/><center center-attr-1='c1' center-attr-2='c2' center-attr-3='c3'><near-south><south><far-south/></south></near-south></center><near-east/><east/><far-east/></near-north></north></far-north>")
{
xml_node center = doc.select_node(STR("//center")).node();
CHECK_XPATH_NODESET(center, STR("attribute::*[2]")) % 10;
CHECK_XPATH_NODESET(center, STR("@*")) % 9 % 10 % 11;
CHECK_XPATH_NODESET(center, STR("child::*/child::*")) % 13;
CHECK_XPATH_NODESET(center, STR("child::*/descendant::*")) % 13 % 14;
CHECK_XPATH_NODESET(center, STR("descendant::*/child::*")) % 13 % 14;
}
TEST_XML(xpath_xalan_axes_8, "<far-north><north><near-north><far-west/><west/><near-west/><center center-attr-1='c1' center-attr-2='c2' center-attr-3='c3'><near-south-east/><near-south><south><far-south/></south></near-south><near-south-west/></center><near-east/><east/><far-east/></near-north></north></far-north>")
{
xml_node near_north = doc.select_node(STR("//near-north")).node();
CHECK_XPATH_NODESET(near_north, STR("center//child::*")) % 12 % 13 % 14 % 15 % 16;
CHECK_XPATH_NODESET(near_north, STR("center//descendant::*")) % 12 % 13 % 14 % 15 % 16;
CHECK_XPATH_NODESET(near_north, STR("center/descendant::*")) % 12 % 13 % 14 % 15 % 16;
CHECK_XPATH_NODESET(near_north, STR("center/child::*")) % 12 % 13 % 16;
CHECK_XPATH_NODESET(near_north, STR("center//*")) % 12 % 13 % 14 % 15 % 16;
}
TEST_XML(xpath_xalan_axes_9, "<doc><foo att1='c'><foo att1='b'><foo att1='a'><baz/></foo></foo></foo><bar/></doc>")
{
xml_node baz = doc.select_node(STR("//baz")).node();
CHECK_XPATH_NODESET(baz, STR("ancestor-or-self::*[@att1][1]/@att1")) % 8;
CHECK_XPATH_NODESET(baz, STR("(ancestor-or-self::*)[@att1][1]/@att1")) % 4;
CHECK_XPATH_NODESET(baz, STR("ancestor::foo[1]/@att1")) % 8;
CHECK_XPATH_NODESET(baz, STR("(ancestor::foo[1])/@att1")) % 8;
CHECK_XPATH_NODESET(baz, STR("(ancestor::foo)[1]/@att1")) % 4;
CHECK_XPATH_NODESET(baz, STR("((ancestor::foo))[1]/@att1")) % 4;
CHECK_XPATH_NODESET(baz, STR("(((ancestor::foo)[1])/@att1)")) % 4;
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")) % 4;
}
TEST_XML(xpath_xalan_axes_10, "<doc><foo att1='c'/><foo att1='b'/><foo att1='a'/><baz/></doc>")
{
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")) % 4;
}
TEST_XML(xpath_xalan_axes_11, "<chapter title='A' x='0'><section title='A1' x='1'><subsection title='A1a' x='2'>hello</subsection><subsection title='A1b'>ahoy</subsection></section><section title='A2'><subsection title='A2a'>goodbye</subsection><subsection title='A2b'>sayonara</subsection><subsection title='A2c'>adios</subsection></section><section title='A3'><subsection title='A3a'>aloha</subsection><subsection title='A3b'><footnote x='3'>A3b-1</footnote><footnote>A3b-2</footnote></subsection><subsection title='A3c'>shalom</subsection></section></chapter>")
{
xml_node chapter = doc.child(STR("chapter"));
CHECK_XPATH_NUMBER(doc, STR("count(//@*)"), 16);
CHECK_XPATH_NUMBER(doc, STR("count(//@title)"), 12);
CHECK_XPATH_NUMBER(doc, STR("count(//section//@*)"), 14);
CHECK_XPATH_NUMBER(doc, STR("count(//section//@title)"), 11);
CHECK_XPATH_NUMBER(chapter, STR("count(.//@*)"), 16);
CHECK_XPATH_NUMBER(chapter, STR("count(.//@title)"), 12);
CHECK_XPATH_NUMBER(chapter, STR("count(section[1]//@*)"), 5);
CHECK_XPATH_NUMBER(chapter, STR("count(section[1]//@title)"), 3);
CHECK_XPATH_NUMBER(chapter, STR("count(section[2]//@*)"), 4);
CHECK_XPATH_NUMBER(chapter, STR("count(section[2]//@title)"), 4);
CHECK_XPATH_NUMBER(chapter, STR("count(section[3]//@*)"), 5);
CHECK_XPATH_NUMBER(chapter, STR("count(section[3]//@title)"), 4);
}
TEST_XML_FLAGS(xpath_xalan_axes_12, "<far-north><north>north-text1<near-north><far-west/><west><!-- Western comment --></west><near-west/><center>center-text1<near-south><south>south-text</south></near-south><near-south-west/>center-text2</center><near-east/><east><!-- Eastern comment --></east><far-east/></near-north>north-text2</north></far-north>", parse_default | parse_comments)
{
CHECK_XPATH_NODESET(doc, STR("/descendant::*")) % 2 % 3 % 5 % 6 % 7 % 9 % 10 % 12 % 13 % 15 % 17 % 18 % 20;
CHECK_XPATH_NODESET(doc, STR("far-north/..//*")) % 2 % 3 % 5 % 6 % 7 % 9 % 10 % 12 % 13 % 15 % 17 % 18 % 20;
CHECK_XPATH_NODESET(doc, STR("far-north/north/..//*")) % 3 % 5 % 6 % 7 % 9 % 10 % 12 % 13 % 15 % 17 % 18 % 20;
CHECK_XPATH_NODESET(doc, STR("far-north/north-yonder/..//*"));
}
TEST_XML(xpath_xalan_axes_13, "<doc att1='e'><foo att1='d'><foo att1='c'><foo att1='b'><baz att1='a'/></foo></foo></foo></doc>")
{
xml_node d = doc.child(STR("doc"));
xml_node baz = doc.select_node(STR("//baz")).node();
CHECK_XPATH_NUMBER(d, STR("count(descendant-or-self::*/@att1)"), 5);
CHECK_XPATH_NODESET(d, STR("descendant-or-self::*/@att1[last()]")) % 3 % 5 % 7 % 9 % 11;
CHECK_XPATH_STRING(d, STR("string(descendant-or-self::*/@att1[last()])"), STR("e"));
CHECK_XPATH_NODESET(d, STR("descendant-or-self::*[last()]/@att1")) % 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_NODESET(baz, STR("ancestor-or-self::*/@att1[last()]")) % 3 % 5 % 7 % 9 % 11;
CHECK_XPATH_STRING(baz, STR("string(ancestor-or-self::*/@att1[last()])"), STR("e"));
CHECK_XPATH_NODESET(baz, STR("(ancestor-or-self::*)/@att1[last()]")) % 3 % 5 % 7 % 9 % 11;
CHECK_XPATH_STRING(baz, STR("string((ancestor-or-self::*)/@att1[last()])"), STR("e"));
CHECK_XPATH_NODESET(baz, STR("(ancestor-or-self::*/@att1)[last()]")) % 11;
CHECK_XPATH_NODESET(baz, STR("(ancestor::*|self::*)/@att1[last()]")) % 3 % 5 % 7 % 9 % 11;
CHECK_XPATH_STRING(baz, STR("string((ancestor::*|self::*)/@att1[last()])"), STR("e"));
CHECK_XPATH_NODESET(baz, STR("((ancestor::*|self::*)/@att1)[last()]")) % 11;
}
TEST_XML_FLAGS(xpath_xalan_axes_14, "<doc><n a='v'/><?pi?><!--comment-->text<center/>text<!--comment--><?pi?><n a='v'/></doc>", parse_default | parse_comments | parse_pi)
{
CHECK_XPATH_NODESET(doc, STR("//center/preceding::node()")) % 7 % 6 % 5 % 3;
CHECK_XPATH_NODESET(doc, STR("//center/following::node()")) % 9 % 10 % 11 % 12;
}
TEST_XML(xpath_xalan_axes_15, "<doc><foo new='true'><baz>is new</baz></foo><foo new='true'>xyz<baz>is new but has text</baz></foo><foo new='false'><baz>is not new</baz></foo></doc>")
{
CHECK_XPATH_NODESET(doc, STR("//text()[ancestor::*[@new='true'][not(text())]]")) % 6;
CHECK_XPATH_NODESET(doc, STR("//text()[ancestor::*[2][@new]]")) % 6 % 11 % 15;
xml_node foo = doc.child(STR("doc")).child(STR("foo")).child(STR("baz")).first_child();
CHECK_XPATH_STRING(foo, STR("name(ancestor::*[3])"), STR("doc"));
CHECK_XPATH_STRING(foo, STR("name(ancestor::*[2])"), STR("foo"));
CHECK_XPATH_STRING(foo, STR("name(ancestor::*[1])"), STR("baz"));
}
TEST_XML(xpath_xalan_axes_16, "<doc><child><grandchild><greatgrandchild/></grandchild><grandchild><greatgrandchild><greatgreatgreatgrandchild/></greatgrandchild><greatgrandchild/></grandchild></child><child><grandchild><greatgrandchild/><greatgrandchild/><greatgrandchild/></grandchild></child><child><grandchild><greatgrandchild/></grandchild></child><child><grandchild/></child><child><grandchild/><grandchild/></child><child/></doc>")
{
xml_node c1 = doc.child(STR("doc")).child(STR("child")), c2 = c1.next_sibling(), c3 = c2.next_sibling(), c4 = c3.next_sibling(), c5 = c4.next_sibling(), c6 = c5.next_sibling();
CHECK_XPATH_STRING(c1.first_child(), STR("concat(count(descendant::*), ',', count(descendant-or-self::*))"), STR("1,2"));
CHECK_XPATH_STRING(c1.last_child(), STR("concat(count(descendant::*), ',', count(descendant-or-self::*))"), STR("3,4"));
CHECK_XPATH_STRING(c2.first_child(), STR("concat(count(descendant::*), ',', count(descendant-or-self::*))"), STR("3,4"));
CHECK_XPATH_STRING(c3.first_child(), STR("concat(count(descendant::*), ',', count(descendant-or-self::*))"), STR("1,2"));
CHECK_XPATH_STRING(c4.first_child(), STR("concat(count(descendant::*), ',', count(descendant-or-self::*))"), STR("0,1"));
CHECK_XPATH_STRING(c5.first_child(), STR("concat(count(descendant::*), ',', count(descendant-or-self::*))"), STR("0,1"));
CHECK_XPATH_STRING(c5.last_child(), STR("concat(count(descendant::*), ',', count(descendant-or-self::*))"), STR("0,1"));
CHECK_XPATH_STRING(c6, STR("concat(count(descendant::*), ',', count(descendant-or-self::*))"), STR("0,1"));
CHECK_XPATH_STRING(xml_node(), STR("concat(count(descendant::*), ',', count(descendant-or-self::*))"), STR("0,0"));
}
TEST_XML(xpath_xalan_axes_17, "<doc><a><asub><asubsub><yy/></asubsub></asub></a><b><bsub><xx><xxchild/></xx></bsub></b><xx>here</xx><d><dsub><dsubsub><xx/></dsubsub></dsub></d><e><esub><xx><xxchild/></xx></esub><esubsib><sibchild/></esubsib></e><xx><childofxx/></xx><xx><xxsub><xxsubsub/></xxsub></xx></doc>")
{
CHECK_XPATH_NODESET(doc, STR("//xx/descendant::*")) % 10 % 20 % 24 % 26 % 27;
}
TEST_XML(xpath_xalan_axes_18, "<north><center center-attr='here'><south/></center></north>")
{
xml_node center = doc.child(STR("north")).child(STR("center"));
CHECK_XPATH_NODESET(center, STR("@*/self::node()")) % 4;
CHECK_XPATH_NODESET(center, STR("@*/self::*")); // * tests for principal node type
CHECK_XPATH_NODESET(center, STR("@*/self::text()"));
CHECK_XPATH_NODESET(center, STR("@*/self::center-attr")); // * tests for principal node type
}
#endif
#ifndef PUGIXML_NO_XPATH
#include "test.hpp"
using namespace pugi;
TEST_XML(xpath_xalan_axes_1, "<far-north><north-north-west1/><north-north-west2/><north><near-north><far-west/><west/><near-west/><center center-attr-1='c1' center-attr-2='c2' center-attr-3='c3'><near-south-west/><near-south><south><far-south/></south></near-south><near-south-east/></center><near-east/><east/><far-east/></near-north></north><north-north-east1/><north-north-east2/></far-north>")
{
xml_node center = doc.select_node(STR("//center")).node();
CHECK_XPATH_NODESET(center, STR("self::*[near-south]")) % 10;
CHECK_XPATH_NODESET(center, STR("self::*[@center-attr-2]")) % 10;
CHECK_XPATH_NODESET(center, STR("preceding-sibling::*")) % 9 % 8 % 7;
CHECK_XPATH_NODESET(center, STR("preceding-sibling::*/following-sibling::*")) % 8 % 9 % 10 % 19 % 20 % 21;
CHECK_XPATH_NODESET(center, STR("preceding-sibling::*[2]/following-sibling::*")) % 9 % 10 % 19 % 20 % 21;
CHECK_XPATH_NODESET(center, STR("preceding-sibling::*[2]/following-sibling::*[4]")) % 20;
CHECK_XPATH_NODESET(center, STR("preceding-sibling::*[2]/following-sibling::*[4]/preceding-sibling::*[5]/following-sibling::*[4]/following-sibling::*[2]")) % 21;
CHECK_XPATH_NODESET(center, STR("following-sibling::*")) % 19 % 20 % 21;
CHECK_XPATH_NODESET(center, STR("following-sibling::*/preceding-sibling::*")) % 7 % 8 % 9 % 10 % 19 % 20;
CHECK_XPATH_NODESET(center, STR("following-sibling::*[2]/preceding-sibling::*")) % 19 % 10 % 9 % 8 % 7;
CHECK_XPATH_NODESET(center, STR("following-sibling::*[2]/preceding-sibling::*[4]")) % 8;
CHECK_XPATH_NODESET(center, STR("following-sibling::*[2]/preceding-sibling::*[4]/following-sibling::*[5]/preceding-sibling::*[4]/preceding-sibling::*[2]")) % 7;
CHECK_XPATH_NODESET(center, STR("following::*[4]/../*[2]")) % 4;
CHECK_XPATH_NODESET(center, STR("preceding::*[2]/../following::*")) % 22 % 23;
CHECK_XPATH_NODESET(center, STR("preceding::*[2]/../descendant::*[10]/following-sibling::east")) % 20;
CHECK_XPATH_NODESET(center, STR("//*")) % 2 % 3 % 4 % 5 % 6 % 7 % 8 % 9 % 10 % 14 % 15 % 16 % 17 % 18 % 19 % 20 % 21 % 22 % 23;
CHECK_XPATH_NODESET(center, STR("//ancestor::*")) % 2 % 5 % 6 % 10 % 15 % 16;
CHECK_XPATH_NODESET(center, STR("//*[count(ancestor::*) >= 2]/../parent::*")) % 2 % 5 % 6 % 10 % 15;
CHECK_XPATH_NODESET(center, STR("//*[count(./*/*) > 0]")) % 2 % 5 % 6 % 10 % 15;
CHECK_XPATH_NODESET(center, STR("@*/ancestor::*")) % 2 % 5 % 6 % 10;
CHECK_XPATH_NODESET(center, STR("@*/following::*")) % 14 % 15 % 16 % 17 % 18 % 19 % 20 % 21 % 22 % 23;
CHECK_XPATH_NODESET(center, STR("@*/preceding::*")) % 3 % 4 % 7 % 8 % 9;
CHECK_XPATH_NODESET(center, STR("preceding-sibling::*|following-sibling::*")) % 7 % 8 % 9 % 19 % 20 % 21;
CHECK_XPATH_NODESET(center, STR("(preceding-sibling::*|following-sibling::*)/ancestor::*[last()]/*[last()]")) % 23;
CHECK_XPATH_NODESET(center, STR(".//near-south/preceding-sibling::*|following-sibling::east/ancestor-or-self::*[2]")) % 6 % 14;
}
TEST_XML_FLAGS(xpath_xalan_axes_2, "<far-north> Level-1<north-north-west1/><north-north-west2/><!-- Comment-2 --> Level-2<?a-pi pi-2?><north><!-- Comment-3 --> Level-3<?a-pi pi-3?><near-north><far-west/><west/><near-west/><!-- Comment-4 --> Level-4<?a-pi pi-4?><center center-attr-1='c1' center-attr-2='c2' center-attr-3='c3'><near-south-west/><!--Comment-5--> Level-5<?a-pi pi-5?><near-south><!--Comment-6--> Level-6<?a-pi pi-6?><south attr1='First' attr2='Last'> <far-south/></south></near-south><near-south-east/></center><near-east/><east/><far-east/></near-north></north><north-north-east1/><north-north-east2/></far-north>", parse_default | parse_comments | parse_pi)
{
xml_node center = doc.select_node(STR("//center")).node();
CHECK_XPATH_NODESET(center, STR("@*")) % 21 % 22 % 23;
CHECK_XPATH_NODESET(center, STR("@*/child::*"));
CHECK_XPATH_NODESET(center, STR("@*/descendant::node()"));
CHECK_XPATH_NODESET(center, STR("@*/parent::node()")) % 20;
CHECK_XPATH_NODESET(center, STR("@*/ancestor::node()")) % 1 % 2 % 9 % 13 % 20;
CHECK_XPATH_NODESET(center, STR("@*/self::node()")) % 21 % 22 % 23;
CHECK_XPATH_NODESET(center, STR("@*/.")) % 21 % 22 % 23;
CHECK_XPATH_NODESET(center, STR("@*/descendant-or-self::node()")) % 21 % 22 % 23;
CHECK_XPATH_NODESET(center, STR("@*/ancestor-or-self::node()")) % 1 % 2 % 9 % 13 % 20 % 21 % 22 % 23;
CHECK_XPATH_NODESET(center, STR("@*/ancestor-or-self::*")) % 2 % 9 % 13 % 20;
CHECK_XPATH_NODESET(center, STR("@*/preceding-sibling::node()"));
CHECK_XPATH_NODESET(center, STR("@*/following-sibling::*"));
CHECK_XPATH_NODESET(center, STR("@*/ancestor::*/near-north/*[4]/@*/preceding::*")) % 4 % 5 % 14 % 15 % 16;
CHECK_XPATH_NODESET(center, STR("@*/ancestor::*/near-north/*[4]/@*/preceding::comment()")) % 6 % 10 % 17;
CHECK_XPATH_NODESET(center, STR("@*/ancestor::*/near-north/*[4]/@*/preceding::text()")) % 3 % 7 % 11 % 18;
CHECK_XPATH_NODESET(center, STR("@*/ancestor::*/near-north/*[4]/@*/preceding::processing-instruction()")) % 8 % 12 % 19;
CHECK_XPATH_NODESET(center, STR("@*/following::comment()")) % 25 % 29;
CHECK_XPATH_NODESET(center, STR("@*/following::processing-instruction()")) % 27 % 31;
CHECK_XPATH_NODESET(center, STR("@*/following::text()")) % 26 % 30;
CHECK_XPATH_NODESET(center, STR("@*/ancestor::*/near-north/*[4]/@*/preceding::node()")) % 3 % 4 % 5 % 6 % 7 % 8 % 10 % 11 % 12 % 14 % 15 % 16 % 17 % 18 % 19;
CHECK_XPATH_NODESET(center, STR("@*/ancestor::*/near-north/*[4]/@*/following::node()")) % 24 % 25 % 26 % 27 % 28 % 29 % 30 % 31 % 32 % 35 % 36 % 37 % 38 % 39 % 40 % 41;
CHECK_XPATH_NODESET(center, STR("(//comment())[1]/..")) % 2;
CHECK_XPATH_NODESET(center, STR("(//attribute::*)[1]/../..")) % 13;
}
TEST_XML(xpath_xalan_axes_3, "<far-north><north><near-north><far-west/><west/><near-west/><center><near-south><south><far-south/></south></near-south></center><near-east/><east/><far-east/></near-north></north></far-north>")
{
xml_node center = doc.select_node(STR("//center")).node();
CHECK_XPATH_NODESET(center, STR("ancestor-or-self::*")) % 8 % 4 % 3 % 2;
CHECK_XPATH_NODESET(center, STR("ancestor::*[3]")) % 2;
CHECK_XPATH_NODESET(center, STR("ancestor-or-self::*[1]")) % 8;
CHECK_XPATH_NODESET(center, STR("@*[2]"));
CHECK_XPATH_NODESET(center, STR("child::*[2]"));
CHECK_XPATH_NODESET(center, STR("child::near-south-west"));
CHECK_XPATH_NODESET(center, STR("descendant::*[3]")) % 11;
CHECK_XPATH_NODESET(center, STR("descendant::far-south")) % 11;
CHECK_XPATH_NODESET(center, STR("descendant-or-self::*[3]")) % 10;
CHECK_XPATH_NODESET(center, STR("descendant-or-self::far-south")) % 11;
CHECK_XPATH_NODESET(center, STR("descendant-or-self::center")) % 8;
CHECK_XPATH_NODESET(center, STR("following::*[4]"));
CHECK_XPATH_NODESET(center, STR("following::out-yonder-east"));
CHECK_XPATH_NODESET(center, STR("preceding::*[4]"));
CHECK_XPATH_NODESET(center, STR("preceding::out-yonder-west"));
CHECK_XPATH_NODESET(center, STR("following-sibling::*[2]")) % 13;
CHECK_XPATH_NODESET(center, STR("following-sibling::east")) % 13;
CHECK_XPATH_NODESET(center, STR("preceding-sibling::*[2]")) % 6;
CHECK_XPATH_NODESET(center, STR("preceding-sibling::west")) % 6;
CHECK_XPATH_NODESET(center, STR("parent::near-north")) % 4;
CHECK_XPATH_NODESET(center, STR("parent::*[1]")) % 4;
CHECK_XPATH_NODESET(center, STR("parent::foo"));
CHECK_XPATH_NODESET(center, STR("..")) % 4;
CHECK_XPATH_NODESET(center, STR("self::center")) % 8;
CHECK_XPATH_NODESET(center, STR("self::*[1]")) % 8;
CHECK_XPATH_NODESET(center, STR("self::foo"));
CHECK_XPATH_NODESET(center, STR(".")) % 8;
CHECK_XPATH_NODESET(center, STR("/far-north/north/near-north/center/ancestor-or-self::*")) % 8 % 4 % 3 % 2;
}
TEST_XML(xpath_xalan_axes_4, "<far-north><north><near-north><far-west/><west/><near-west/><center><near-south><south><far-south/></south></near-south></center><near-east/><east/><far-east/></near-north></north></far-north>")
{
xml_node north = doc.select_node(STR("//north")).node();
CHECK_XPATH_STRING(north, STR("name(/descendant-or-self::north)"), STR("north"));
CHECK_XPATH_STRING(north, STR("name(/descendant::near-north)"), STR("near-north"));
CHECK_XPATH_STRING(north, STR("name(self::node()/descendant-or-self::north)"), STR("north"));
CHECK_XPATH_STRING(north, STR("name(self::node()/descendant::near-north)"), STR("near-north"));
CHECK_XPATH_STRING(north, STR("name(descendant-or-self::north/descendant-or-self::north)"), STR("north"));
CHECK_XPATH_STRING(north, STR("name(descendant-or-self::north/descendant::near-north)"), STR("near-north"));
CHECK_XPATH_STRING(north, STR("name(descendant-or-self::north/child::near-north)"), STR("near-north"));
CHECK_XPATH_STRING(north, STR("name(descendant::near-north/descendant-or-self::near-north)"), STR("near-north"));
CHECK_XPATH_STRING(north, STR("name(descendant::near-north/descendant::far-west)"), STR("far-west"));
CHECK_XPATH_STRING(north, STR("name(/descendant-or-self::north/descendant-or-self::north)"), STR("north"));
CHECK_XPATH_STRING(north, STR("name(/descendant-or-self::north/child::near-north)"), STR("near-north"));
CHECK_XPATH_STRING(north, STR("name(/descendant::near-north/descendant-or-self::near-north)"), STR("near-north"));
CHECK_XPATH_STRING(north, STR("name(self::node()/descendant-or-self::north/descendant-or-self::north)"), STR("north"));
CHECK_XPATH_STRING(north, STR("name(self::node()/descendant-or-self::north/child::near-north)"), STR("near-north"));
CHECK_XPATH_STRING(north, STR("name(self::node()/descendant::near-north/descendant-or-self::far-west)"), STR("far-west"));
CHECK_XPATH_STRING(north, STR("name(self::node()/descendant::near-north/child::far-west)"), STR("far-west"));
CHECK_XPATH_STRING(north, STR("name(descendant-or-self::north/descendant-or-self::north/descendant-or-self::north)"), STR("north"));
CHECK_XPATH_STRING(north, STR("name(descendant-or-self::north/descendant-or-self::north/child::near-north)"), STR("near-north"));
CHECK_XPATH_STRING(north, STR("name(descendant-or-self::north/descendant::near-north/descendant-or-self::near-north)"), STR("near-north"));
CHECK_XPATH_STRING(north, STR("name(descendant-or-self::north/descendant::near-north/child::far-west)"), STR("far-west"));
CHECK_XPATH_STRING(north, STR("name(descendant-or-self::north/child::near-north/descendant-or-self::near-north)"), STR("near-north"));
CHECK_XPATH_STRING(north, STR("name(descendant-or-self::north/child::near-north/child::far-west)"), STR("far-west"));
CHECK_XPATH_STRING(north, STR("name(descendant::near-north/descendant-or-self::near-north/descendant-or-self::near-north)"), STR("near-north"));
CHECK_XPATH_STRING(north, STR("name(descendant::near-north/descendant-or-self::near-north/child::far-west)"), STR("far-west"));
CHECK_XPATH_STRING(north, STR("name(descendant::near-north/descendant::far-west/descendant-or-self::far-west)"), STR("far-west"));
CHECK_XPATH_STRING(north, STR("name(descendant-or-self::node()/descendant-or-self::north)"), STR("north"));
CHECK_XPATH_STRING(north, STR("name(descendant-or-self::node()/descendant::near-north)"), STR("near-north"));
CHECK_XPATH_STRING(north, STR("name(descendant-or-self::node()/child::near-north)"), STR("near-north"));
CHECK_XPATH_STRING(north, STR("name(descendant::node()/descendant-or-self::near-north)"), STR("near-north"));
CHECK_XPATH_STRING(north, STR("name(descendant::node()/descendant::far-west)"), STR("far-west"));
CHECK_XPATH_STRING(north, STR("name(/descendant-or-self::node()/descendant-or-self::north)"), STR("north"));
CHECK_XPATH_STRING(north, STR("name(/descendant-or-self::node()/child::near-north)"), STR("near-north"));
CHECK_XPATH_STRING(north, STR("name(/descendant::node()/descendant-or-self::near-north)"), STR("near-north"));
CHECK_XPATH_STRING(north, STR("name(self::node()/descendant-or-self::node()/descendant-or-self::north)"), STR("north"));
CHECK_XPATH_STRING(north, STR("name(self::node()/descendant-or-self::node()/child::near-north)"), STR("near-north"));
CHECK_XPATH_STRING(north, STR("name(self::node()/descendant::node()/descendant-or-self::far-west)"), STR("far-west"));
CHECK_XPATH_STRING(north, STR("name(self::node()/descendant::node()/child::far-west)"), STR("far-west"));
CHECK_XPATH_STRING(north, STR("name(descendant-or-self::node()/descendant-or-self::node()/descendant-or-self::north)"), STR("north"));
CHECK_XPATH_STRING(north, STR("name(descendant-or-self::node()/descendant-or-self::node()/child::near-north)"), STR("near-north"));
CHECK_XPATH_STRING(north, STR("name(descendant-or-self::node()/descendant::node()/descendant-or-self::near-north)"), STR("near-north"));
CHECK_XPATH_STRING(north, STR("name(descendant-or-self::node()/descendant::node()/child::far-west)"), STR("far-west"));
CHECK_XPATH_STRING(north, STR("name(descendant-or-self::node()/child::node()/descendant-or-self::near-north)"), STR("near-north"));
CHECK_XPATH_STRING(north, STR("name(descendant-or-self::node()/child::node()/child::far-west)"), STR("far-west"));
CHECK_XPATH_STRING(north, STR("name(descendant::node()/descendant-or-self::node()/descendant-or-self::near-north)"), STR("near-north"));
CHECK_XPATH_STRING(north, STR("name(descendant::node()/descendant-or-self::node()/child::far-west)"), STR("far-west"));
CHECK_XPATH_STRING(north, STR("name(descendant::node()/descendant::node()/descendant-or-self::far-west)"), STR("far-west"));
}
TEST_XML_FLAGS(xpath_xalan_axes_5, "<text>text</text><comment><!--comment--></comment><pi><?pi?></pi>", parse_default | parse_comments | parse_pi)
{
CHECK_XPATH_NODESET(doc, STR("text/self::text()"));
CHECK_XPATH_NODESET(doc, STR("comment/self::comment()"));
CHECK_XPATH_NODESET(doc, STR("pi/self::processing-instruction()"));
}
TEST_XML(xpath_xalan_axes_6, "<doc><T>Test for source tree depth</T><a><T>A</T><b><T>B</T><c><T>C</T><d><T>D</T><e><T>E</T><f><T>F</T><g><T>G</T><h><T>H</T><i><T>I</T><j><T>J</T><k><T>K</T><l><T>L</T><m><T>M</T><n><T>N</T><o><T>O</T></o></n></m></l></k></j></i></h></g></f></e></d></c></b></a></doc>")
{
CHECK_XPATH_NODESET(doc, STR("//T")) % 3 % 6 % 9 % 12 % 15 % 18 % 21 % 24 % 27 % 30 % 33 % 36 % 39 % 42 % 45 % 48;
}
TEST_XML(xpath_xalan_axes_7, "<far-north><north><near-north><far-west/><west/><near-west/><center center-attr-1='c1' center-attr-2='c2' center-attr-3='c3'><near-south><south><far-south/></south></near-south></center><near-east/><east/><far-east/></near-north></north></far-north>")
{
xml_node center = doc.select_node(STR("//center")).node();
CHECK_XPATH_NODESET(center, STR("attribute::*[2]")) % 10;
CHECK_XPATH_NODESET(center, STR("@*")) % 9 % 10 % 11;
CHECK_XPATH_NODESET(center, STR("child::*/child::*")) % 13;
CHECK_XPATH_NODESET(center, STR("child::*/descendant::*")) % 13 % 14;
CHECK_XPATH_NODESET(center, STR("descendant::*/child::*")) % 13 % 14;
}
TEST_XML(xpath_xalan_axes_8, "<far-north><north><near-north><far-west/><west/><near-west/><center center-attr-1='c1' center-attr-2='c2' center-attr-3='c3'><near-south-east/><near-south><south><far-south/></south></near-south><near-south-west/></center><near-east/><east/><far-east/></near-north></north></far-north>")
{
xml_node near_north = doc.select_node(STR("//near-north")).node();
CHECK_XPATH_NODESET(near_north, STR("center//child::*")) % 12 % 13 % 14 % 15 % 16;
CHECK_XPATH_NODESET(near_north, STR("center//descendant::*")) % 12 % 13 % 14 % 15 % 16;
CHECK_XPATH_NODESET(near_north, STR("center/descendant::*")) % 12 % 13 % 14 % 15 % 16;
CHECK_XPATH_NODESET(near_north, STR("center/child::*")) % 12 % 13 % 16;
CHECK_XPATH_NODESET(near_north, STR("center//*")) % 12 % 13 % 14 % 15 % 16;
}
TEST_XML(xpath_xalan_axes_9, "<doc><foo att1='c'><foo att1='b'><foo att1='a'><baz/></foo></foo></foo><bar/></doc>")
{
xml_node baz = doc.select_node(STR("//baz")).node();
CHECK_XPATH_NODESET(baz, STR("ancestor-or-self::*[@att1][1]/@att1")) % 8;
CHECK_XPATH_NODESET(baz, STR("(ancestor-or-self::*)[@att1][1]/@att1")) % 4;
CHECK_XPATH_NODESET(baz, STR("ancestor::foo[1]/@att1")) % 8;
CHECK_XPATH_NODESET(baz, STR("(ancestor::foo[1])/@att1")) % 8;
CHECK_XPATH_NODESET(baz, STR("(ancestor::foo)[1]/@att1")) % 4;
CHECK_XPATH_NODESET(baz, STR("((ancestor::foo))[1]/@att1")) % 4;
CHECK_XPATH_NODESET(baz, STR("(((ancestor::foo)[1])/@att1)")) % 4;
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")) % 4;
}
TEST_XML(xpath_xalan_axes_10, "<doc><foo att1='c'/><foo att1='b'/><foo att1='a'/><baz/></doc>")
{
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")) % 4;
}
TEST_XML(xpath_xalan_axes_11, "<chapter title='A' x='0'><section title='A1' x='1'><subsection title='A1a' x='2'>hello</subsection><subsection title='A1b'>ahoy</subsection></section><section title='A2'><subsection title='A2a'>goodbye</subsection><subsection title='A2b'>sayonara</subsection><subsection title='A2c'>adios</subsection></section><section title='A3'><subsection title='A3a'>aloha</subsection><subsection title='A3b'><footnote x='3'>A3b-1</footnote><footnote>A3b-2</footnote></subsection><subsection title='A3c'>shalom</subsection></section></chapter>")
{
xml_node chapter = doc.child(STR("chapter"));
CHECK_XPATH_NUMBER(doc, STR("count(//@*)"), 16);
CHECK_XPATH_NUMBER(doc, STR("count(//@title)"), 12);
CHECK_XPATH_NUMBER(doc, STR("count(//section//@*)"), 14);
CHECK_XPATH_NUMBER(doc, STR("count(//section//@title)"), 11);
CHECK_XPATH_NUMBER(chapter, STR("count(.//@*)"), 16);
CHECK_XPATH_NUMBER(chapter, STR("count(.//@title)"), 12);
CHECK_XPATH_NUMBER(chapter, STR("count(section[1]//@*)"), 5);
CHECK_XPATH_NUMBER(chapter, STR("count(section[1]//@title)"), 3);
CHECK_XPATH_NUMBER(chapter, STR("count(section[2]//@*)"), 4);
CHECK_XPATH_NUMBER(chapter, STR("count(section[2]//@title)"), 4);
CHECK_XPATH_NUMBER(chapter, STR("count(section[3]//@*)"), 5);
CHECK_XPATH_NUMBER(chapter, STR("count(section[3]//@title)"), 4);
}
TEST_XML_FLAGS(xpath_xalan_axes_12, "<far-north><north>north-text1<near-north><far-west/><west><!-- Western comment --></west><near-west/><center>center-text1<near-south><south>south-text</south></near-south><near-south-west/>center-text2</center><near-east/><east><!-- Eastern comment --></east><far-east/></near-north>north-text2</north></far-north>", parse_default | parse_comments)
{
CHECK_XPATH_NODESET(doc, STR("/descendant::*")) % 2 % 3 % 5 % 6 % 7 % 9 % 10 % 12 % 13 % 15 % 17 % 18 % 20;
CHECK_XPATH_NODESET(doc, STR("far-north/..//*")) % 2 % 3 % 5 % 6 % 7 % 9 % 10 % 12 % 13 % 15 % 17 % 18 % 20;
CHECK_XPATH_NODESET(doc, STR("far-north/north/..//*")) % 3 % 5 % 6 % 7 % 9 % 10 % 12 % 13 % 15 % 17 % 18 % 20;
CHECK_XPATH_NODESET(doc, STR("far-north/north-yonder/..//*"));
}
TEST_XML(xpath_xalan_axes_13, "<doc att1='e'><foo att1='d'><foo att1='c'><foo att1='b'><baz att1='a'/></foo></foo></foo></doc>")
{
xml_node d = doc.child(STR("doc"));
xml_node baz = doc.select_node(STR("//baz")).node();
CHECK_XPATH_NUMBER(d, STR("count(descendant-or-self::*/@att1)"), 5);
CHECK_XPATH_NODESET(d, STR("descendant-or-self::*/@att1[last()]")) % 3 % 5 % 7 % 9 % 11;
CHECK_XPATH_STRING(d, STR("string(descendant-or-self::*/@att1[last()])"), STR("e"));
CHECK_XPATH_NODESET(d, STR("descendant-or-self::*[last()]/@att1")) % 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_NODESET(baz, STR("ancestor-or-self::*/@att1[last()]")) % 3 % 5 % 7 % 9 % 11;
CHECK_XPATH_STRING(baz, STR("string(ancestor-or-self::*/@att1[last()])"), STR("e"));
CHECK_XPATH_NODESET(baz, STR("(ancestor-or-self::*)/@att1[last()]")) % 3 % 5 % 7 % 9 % 11;
CHECK_XPATH_STRING(baz, STR("string((ancestor-or-self::*)/@att1[last()])"), STR("e"));
CHECK_XPATH_NODESET(baz, STR("(ancestor-or-self::*/@att1)[last()]")) % 11;
CHECK_XPATH_NODESET(baz, STR("(ancestor::*|self::*)/@att1[last()]")) % 3 % 5 % 7 % 9 % 11;
CHECK_XPATH_STRING(baz, STR("string((ancestor::*|self::*)/@att1[last()])"), STR("e"));
CHECK_XPATH_NODESET(baz, STR("((ancestor::*|self::*)/@att1)[last()]")) % 11;
}
TEST_XML_FLAGS(xpath_xalan_axes_14, "<doc><n a='v'/><?pi?><!--comment-->text<center/>text<!--comment--><?pi?><n a='v'/></doc>", parse_default | parse_comments | parse_pi)
{
CHECK_XPATH_NODESET(doc, STR("//center/preceding::node()")) % 7 % 6 % 5 % 3;
CHECK_XPATH_NODESET(doc, STR("//center/following::node()")) % 9 % 10 % 11 % 12;
}
TEST_XML(xpath_xalan_axes_15, "<doc><foo new='true'><baz>is new</baz></foo><foo new='true'>xyz<baz>is new but has text</baz></foo><foo new='false'><baz>is not new</baz></foo></doc>")
{
CHECK_XPATH_NODESET(doc, STR("//text()[ancestor::*[@new='true'][not(text())]]")) % 6;
CHECK_XPATH_NODESET(doc, STR("//text()[ancestor::*[2][@new]]")) % 6 % 11 % 15;
xml_node foo = doc.child(STR("doc")).child(STR("foo")).child(STR("baz")).first_child();
CHECK_XPATH_STRING(foo, STR("name(ancestor::*[3])"), STR("doc"));
CHECK_XPATH_STRING(foo, STR("name(ancestor::*[2])"), STR("foo"));
CHECK_XPATH_STRING(foo, STR("name(ancestor::*[1])"), STR("baz"));
}
TEST_XML(xpath_xalan_axes_16, "<doc><child><grandchild><greatgrandchild/></grandchild><grandchild><greatgrandchild><greatgreatgreatgrandchild/></greatgrandchild><greatgrandchild/></grandchild></child><child><grandchild><greatgrandchild/><greatgrandchild/><greatgrandchild/></grandchild></child><child><grandchild><greatgrandchild/></grandchild></child><child><grandchild/></child><child><grandchild/><grandchild/></child><child/></doc>")
{
xml_node c1 = doc.child(STR("doc")).child(STR("child")), c2 = c1.next_sibling(), c3 = c2.next_sibling(), c4 = c3.next_sibling(), c5 = c4.next_sibling(), c6 = c5.next_sibling();
CHECK_XPATH_STRING(c1.first_child(), STR("concat(count(descendant::*), ',', count(descendant-or-self::*))"), STR("1,2"));
CHECK_XPATH_STRING(c1.last_child(), STR("concat(count(descendant::*), ',', count(descendant-or-self::*))"), STR("3,4"));
CHECK_XPATH_STRING(c2.first_child(), STR("concat(count(descendant::*), ',', count(descendant-or-self::*))"), STR("3,4"));
CHECK_XPATH_STRING(c3.first_child(), STR("concat(count(descendant::*), ',', count(descendant-or-self::*))"), STR("1,2"));
CHECK_XPATH_STRING(c4.first_child(), STR("concat(count(descendant::*), ',', count(descendant-or-self::*))"), STR("0,1"));
CHECK_XPATH_STRING(c5.first_child(), STR("concat(count(descendant::*), ',', count(descendant-or-self::*))"), STR("0,1"));
CHECK_XPATH_STRING(c5.last_child(), STR("concat(count(descendant::*), ',', count(descendant-or-self::*))"), STR("0,1"));
CHECK_XPATH_STRING(c6, STR("concat(count(descendant::*), ',', count(descendant-or-self::*))"), STR("0,1"));
CHECK_XPATH_STRING(xml_node(), STR("concat(count(descendant::*), ',', count(descendant-or-self::*))"), STR("0,0"));
}
TEST_XML(xpath_xalan_axes_17, "<doc><a><asub><asubsub><yy/></asubsub></asub></a><b><bsub><xx><xxchild/></xx></bsub></b><xx>here</xx><d><dsub><dsubsub><xx/></dsubsub></dsub></d><e><esub><xx><xxchild/></xx></esub><esubsib><sibchild/></esubsib></e><xx><childofxx/></xx><xx><xxsub><xxsubsub/></xxsub></xx></doc>")
{
CHECK_XPATH_NODESET(doc, STR("//xx/descendant::*")) % 10 % 20 % 24 % 26 % 27;
}
TEST_XML(xpath_xalan_axes_18, "<north><center center-attr='here'><south/></center></north>")
{
xml_node center = doc.child(STR("north")).child(STR("center"));
CHECK_XPATH_NODESET(center, STR("@*/self::node()")) % 4;
CHECK_XPATH_NODESET(center, STR("@*/self::*")); // * tests for principal node type
CHECK_XPATH_NODESET(center, STR("@*/self::text()"));
CHECK_XPATH_NODESET(center, STR("@*/self::center-attr")); // * tests for principal node type
}
#endif

View File

@ -1,300 +1,300 @@
#ifndef PUGIXML_NO_XPATH
#include "test.hpp"
using namespace pugi;
TEST_XML(xpath_xalan_position_1, "<doc><a>1</a><a>2</a><a>3</a><a>4</a></doc>")
{
xml_node c = doc.child(STR("doc"));
CHECK_XPATH_BOOLEAN(c, STR("position()=1"), true);
CHECK_XPATH_NODESET(c, STR("*[position()=4]")) % 9;
}
TEST_XML_FLAGS(xpath_xalan_position_2, "<doc><a test='true'><num>1</num></a><a><num>1191</num></a><a><num>263</num></a><a test='true'><num>2</num></a><a><num>827</num></a><a><num>256</num></a><a test='true'><num>3</num></a><a test='true'><num>4<x/>5</num></a><?pi?><?pi?><!--comment--><!--comment--></doc>", parse_default | parse_comments | parse_pi)
{
xml_node c = doc.child(STR("doc"));
CHECK_XPATH_NODESET(c, STR("*[@test and position()=8]")) % 27;
CHECK_XPATH_NODESET(c, STR("*[@test][position()=4]/num")) % 29;
CHECK_XPATH_NUMBER(c, STR("count(*)"), 8);
CHECK_XPATH_NODESET(c, STR("*[last()=position()]")) % 27;
CHECK_XPATH_NODESET(c, STR("a[position()=2]")) % 7;
CHECK_XPATH_NODESET(c, STR("a[3]/../a[position()=4]/num/../@test")) % 14;
CHECK_XPATH_BOOLEAN(c, STR("not(position()=last())"), false);
CHECK_XPATH_BOOLEAN(c, STR("position()=2"), false);
CHECK_XPATH_BOOLEAN(c, STR("last()=1"), true);
CHECK_XPATH_BOOLEAN(c, STR("last()+2=3"), true);
CHECK_XPATH_NODESET(c, STR("a[position()=5 mod 3]")) % 7;
CHECK_XPATH_NODESET(c, STR("a/num/text()[position()=1]")) % 6 % 9 % 12 % 16 % 19 % 22 % 26 % 30;
CHECK_XPATH_NODESET(c, STR("a/num/text()[position()=2]")) % 32;
CHECK_XPATH_NODESET(c, STR("a/num/text()[position()=last()]")) % 6 % 9 % 12 % 16 % 19 % 22 % 26 % 32;
CHECK_XPATH_NODESET(c, STR("a/num/text()[1]")) % 6 % 9 % 12 % 16 % 19 % 22 % 26 % 30;
CHECK_XPATH_NODESET(c, STR("a/num/text()[2]")) % 32;
CHECK_XPATH_NODESET(c, STR("a/num/text()[last()]")) % 6 % 9 % 12 % 16 % 19 % 22 % 26 % 32;
CHECK_XPATH_NODESET(c, STR("a[floor(last() div 3)]")) % 7;
CHECK_XPATH_NODESET(c, STR("a[ceiling(last() div 3)]")) % 10;
CHECK_XPATH_NODESET(c, STR("a[round(last() div 3)]")) % 10;
CHECK_XPATH_NODESET(c, STR("a[last() div 3]"));
CHECK_XPATH_NODESET(c, STR("a[last() div 2]")) % 13;
CHECK_XPATH_NODESET(c, STR("a[3]/../a[position()>=2 and position()<=4]")) % 7 % 10 % 13;
CHECK_XPATH_NUMBER(c, STR("count(a[position()>=2 and position()<=4]/num)"), 3);
CHECK_XPATH_NUMBER(c, STR("count(a/@*)"), 4);
CHECK_XPATH_NUMBER(c, STR("count(a/attribute::*)"), 4);
CHECK_XPATH_NODESET(c, STR("*[not(@test)][position()=last()]")) % 20;
CHECK_XPATH_NODESET(c, STR("*[not(@test)][last()]")) % 20;
CHECK_XPATH_NODESET(c, STR("a[3-2]")) % 3;
CHECK_XPATH_NODESET(c, STR("a[0]"));
CHECK_XPATH_NODESET(c, STR("a[9]"));
CHECK_XPATH_NODESET(c, STR("a['3']")) % 3 % 7 % 10 % 13 % 17 % 20 % 23 % 27;
CHECK_XPATH_NODESET(c, STR("a[number('3')]")) % 10;
CHECK_XPATH_NODESET(c, STR("processing-instruction()[2]")) % 34;
CHECK_XPATH_NODESET(c, STR("processing-instruction('pi')[2]")) % 34;
CHECK_XPATH_NODESET(c, STR("comment()[2]")) % 36;
CHECK_XPATH_NODESET(c, STR("a/*[last()]")) % 5 % 8 % 11 % 15 % 18 % 21 % 25 % 29;
CHECK_XPATH_NODESET(c, STR("a/child::*[last()]")) % 5 % 8 % 11 % 15 % 18 % 21 % 25 % 29;
CHECK_XPATH_NODESET(c, STR("a/descendant::*[last()]")) % 5 % 8 % 11 % 15 % 18 % 21 % 25 % 31;
CHECK_XPATH_NODESET(c, STR("a/child::node()[last()]")) % 5 % 8 % 11 % 15 % 18 % 21 % 25 % 29;
CHECK_XPATH_NODESET(c, STR("a/descendant::text()[last()]")) % 6 % 9 % 12 % 16 % 19 % 22 % 26 % 32;
CHECK_XPATH_NODESET(c, STR("child::comment()[last()]")) % 36;
}
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>")
{
CHECK_XPATH_NODESET(doc, STR("(article//section/title|/articleinfo/title|article/section/para)[last()]")) % 28;
CHECK_XPATH_NODESET(doc, STR("(article//section/title|/articleinfo/title|article/section/para)[1]")) % 10;
CHECK_XPATH_NUMBER(doc, STR("count(article/articleinfo/section[last()])"), 1);
CHECK_XPATH_NUMBER(doc, STR("count(article/articleinfo/section[last()][title='BBB'])"), 1);
}
TEST_XML(xpath_xalan_position_4, "<chapter><section><footnote>hello</footnote></section><section><footnote>goodbye</footnote><footnote>sayonara</footnote></section><section><footnote>aloha</footnote></section></chapter>")
{
CHECK_XPATH_NODESET(doc, STR("chapter//footnote[1]")) % 4 % 7 % 12;
}
TEST_XML(xpath_xalan_position_5, "<chapter><section><footnote>hello</footnote><footnote>ahoy</footnote></section><section><footnote>goodbye</footnote><footnote>sayonara</footnote><footnote>adios</footnote></section><section><footnote>aloha</footnote><subsection><footnote>shalom</footnote><footnote>yo</footnote></subsection><footnote>ciao</footnote></section></chapter>")
{
CHECK_XPATH_NODESET(doc, STR("chapter//footnote[2]")) % 6 % 11 % 21 % 23;
CHECK_XPATH_NODESET(doc, STR("(chapter//footnote)[2]")) % 6;
CHECK_XPATH_NODESET(doc, STR("(child::chapter/descendant-or-self::node())/footnote[2]")) % 6 % 11 % 21 % 23;
CHECK_XPATH_NODESET(doc, STR("chapter/descendant::footnote[6]")) % 16;
CHECK_XPATH_NODESET(doc, STR("chapter/descendant::footnote[6][1][last()]")) % 16;
}
TEST_XML_FLAGS(xpath_xalan_position_6, "<node attr='value'>pcdata<child/><?pi1 value?><?pi2 value?><!--comment--><![CDATA[cdata]]></node>", parse_default | parse_pi | parse_comments)
{
CHECK_XPATH_NUMBER(doc, STR("count(/node/@attr/ancestor-or-self::node())"), 3);
CHECK_XPATH_NUMBER(doc, STR("count(/node/text()/ancestor-or-self::node())"), 4);
CHECK_XPATH_NUMBER(doc, STR("count(/node/processing-instruction()/ancestor-or-self::node())"), 4);
CHECK_XPATH_NUMBER(doc, STR("count(/node/processing-instruction('pi1')/ancestor-or-self::node())"), 3);
CHECK_XPATH_NUMBER(doc, STR("count(/node/comment()/ancestor-or-self::node())"), 3);
}
TEST_XML(xpath_xalan_position_7, "<chapter title='A'><section title='A1'><subsection title='A1a'>hello</subsection><subsection title='A1b'>ahoy</subsection></section><section title='A2'><subsection title='A2a'>goodbye</subsection><subsection title='A2b'>sayonara</subsection><subsection title='A2c'>adios</subsection></section><section title='A3'><subsection title='A3a'>aloha</subsection><subsection title='A3b'><footnote>A3b-1</footnote><footnote>A3b-2</footnote></subsection><subsection title='A3c'>shalom</subsection></section></chapter>")
{
CHECK_XPATH_NODESET(doc, STR("chapter/section//@title[7]"));
CHECK_XPATH_NODESET(doc, STR("(chapter/section//@title)[7]")) % 21;
}
TEST_XML(xpath_xalan_match_1, "<root><x spot='a' num='1'/><x spot='b' num='2'/><x spot='c' num='3'/><x spot='d' num='4'/><x spot='e' num='5'/><x spot='f' num='6'/><x spot='g' num='7'/><x spot='h' num='8'/><x spot='i' num='9'/><x spot='j' num='10'/><x spot='k' num='11'/><x spot='l' num='12'/></root>")
{
xml_node c = doc.child(STR("root"));
CHECK_XPATH_NODESET(c, STR("x[(position() mod 2)=1][position() > 3]")) % 21 % 27 % 33;
CHECK_XPATH_NODESET(c, STR("x[(position() mod 2)=1][position() > 3][position()=2]")) % 27;
CHECK_XPATH_NODESET(c, STR("x[(position() mod 2) > 0][position() > 3][2]")) % 27;
CHECK_XPATH_NODESET(c, STR("x[(position() mod 2)=1][position() > 3][last()]")) % 33;
CHECK_XPATH_NODESET(c, STR("x[(position() mod 2)=1][@num > 5][last()]")) % 33;
CHECK_XPATH_NODESET(c, STR("x[(@num mod 3)=2][position() > 2][last()]")) % 33;
CHECK_XPATH_NODESET(c, STR("x[(position() mod 2)=1][2][@num < 10]")) % 9;
CHECK_XPATH_NODESET(c, STR("x[(((((2*10)-4)+9) div 5) mod 3)]")) % 6;
}
TEST_XML(xpath_xalan_match_2, "<doc><l1><v2>doc-l1-v2</v2><x2>doc-l1-x2</x2><l2><v3>doc-l1-l2-v3</v3><w3>doc-l1-l2-w3</w3><x3>doc-l1-l2-x3</x3><y3>doc-l1-l2-y3</y3><l3><v4>doc-l1-l2-l3-v4</v4><x4>doc-l1-l2-l3-x4</x4></l3></l2></l1></doc>")
{
CHECK_XPATH_STRING(doc, STR("doc/l1/v2"), STR("doc-l1-v2"));
CHECK_XPATH_STRING(doc, STR("doc/child::l1/x2"), STR("doc-l1-x2"));
CHECK_XPATH_STRING(doc, STR("doc/l1//v3"), STR("doc-l1-l2-v3"));
CHECK_XPATH_STRING(doc, STR("doc//l2/w3"), STR("doc-l1-l2-w3"));
CHECK_XPATH_STRING(doc, STR("doc/child::l1//x3"), STR("doc-l1-l2-x3"));
CHECK_XPATH_STRING(doc, STR("doc//child::l2/y3"), STR("doc-l1-l2-y3"));
CHECK_XPATH_STRING(doc, STR("doc//l2//v4"), STR("doc-l1-l2-l3-v4"));
CHECK_XPATH_STRING(doc, STR("doc//child::l2//x4"), STR("doc-l1-l2-l3-x4"));
CHECK_XPATH_STRING(doc, STR("doc/l1/v2"), STR("doc-l1-v2"));
CHECK_XPATH_STRING(doc, STR("doc/l1/child::x2"), STR("doc-l1-x2"));
CHECK_XPATH_STRING(doc, STR("doc/l1//v3"), STR("doc-l1-l2-v3"));
CHECK_XPATH_STRING(doc, STR("doc//l2/w3"), STR("doc-l1-l2-w3"));
CHECK_XPATH_STRING(doc, STR("doc/l1//child::x3"), STR("doc-l1-l2-x3"));
CHECK_XPATH_STRING(doc, STR("doc//l2/child::y3"), STR("doc-l1-l2-y3"));
CHECK_XPATH_STRING(doc, STR("doc//l2//v4"), STR("doc-l1-l2-l3-v4"));
CHECK_XPATH_STRING(doc, STR("doc//l2//child::x4"), STR("doc-l1-l2-l3-x4"));
CHECK_XPATH_STRING(doc, STR("doc/l1/v2"), STR("doc-l1-v2"));
CHECK_XPATH_STRING(doc, STR("doc/child::l1/child::x2"), STR("doc-l1-x2"));
CHECK_XPATH_STRING(doc, STR("doc/l1//v3"), STR("doc-l1-l2-v3"));
CHECK_XPATH_STRING(doc, STR("doc//l2/w3"), STR("doc-l1-l2-w3"));
CHECK_XPATH_STRING(doc, STR("doc/child::l1//child::x3"), STR("doc-l1-l2-x3"));
CHECK_XPATH_STRING(doc, STR("doc//child::l2/child::y3"), STR("doc-l1-l2-y3"));
CHECK_XPATH_STRING(doc, STR("doc//l2//v4"), STR("doc-l1-l2-l3-v4"));
CHECK_XPATH_STRING(doc, STR("doc//child::l2//child::x4"), STR("doc-l1-l2-l3-x4"));
}
TEST_XML(xpath_xalan_match_3, "<doc><child><child-foo><name id='1'>John Doe</name><child><name id='2'>Jane Doe</name></child></child-foo></child></doc>")
{
CHECK_XPATH_NODESET(doc, STR("doc/child/*[starts-with(name(),'child-')]//name")) % 5 % 9;
CHECK_XPATH_NODESET(doc, STR("//@*")) % 6 % 10;
}
TEST_XML(xpath_xalan_expression_1, "<doc><para id='1' xml:lang='en'>en</para><div xml:lang='en'><para>en</para></div><para id='3' xml:lang='EN'>EN</para><para id='4' xml:lang='en-us'>en-us</para></doc>")
{
CHECK_XPATH_NODESET(doc, STR("doc/para[@id='1' and lang('en')]")) % 3;
CHECK_XPATH_NODESET(doc, STR("doc/para[@id='4' and lang('en')]")) % 15;
CHECK_XPATH_NODESET(doc, STR("doc/div/para[lang('en')]")) % 9;
CHECK_XPATH_NODESET(doc, STR("doc/para[@id='3' and lang('en')]")) % 11;
CHECK_XPATH_NODESET(doc, STR("//para[lang('en')]/ancestor-or-self::*[@xml:lang]/@xml:lang")) % 5 % 8 % 13 % 17;
}
TEST_XML(xpath_xalan_predicate_1, "<doc><a>1</a><a>2</a><a>3</a><a>4</a></doc>")
{
xml_node c = doc.child(STR("doc"));
CHECK_XPATH_NODESET(c, STR("a[true()=4]")) % 3 % 5 % 7 % 9;
CHECK_XPATH_NODESET(c, STR("a[true()='stringwithchars']")) % 3 % 5 % 7 % 9;
CHECK_XPATH_NODESET(c, STR("a[true()=following-sibling::*]")) % 3 % 5 % 7;
CHECK_XPATH_NODESET(c, STR("a[true()=preceding-sibling::*]")) % 5 % 7 % 9;
CHECK_XPATH_NODESET(c, STR("a[3=following-sibling::*]")) % 3 % 5;
CHECK_XPATH_NODESET(c, STR("a[0 < true()]")) % 3 % 5 % 7 % 9;
CHECK_XPATH_NODESET(c, STR("a['3.5' < 4]")) % 3 % 5 % 7 % 9;
CHECK_XPATH_NODESET(c, STR("a[3 < following-sibling::*]")) % 3 % 5 % 7;
CHECK_XPATH_NODESET(c, STR("a[following-sibling::*>3]")) % 3 % 5 % 7;
CHECK_XPATH_NODESET(c, STR("a[3 > following-sibling::*]")) % 3;
CHECK_XPATH_NODESET(c, STR("a[following-sibling::*<3]")) % 3;
CHECK_XPATH_NODESET(c, STR("a[1 < 2 < 3]")) % 3 % 5 % 7 % 9;
CHECK_XPATH_NODESET(c, STR("a[1 < 3 < 2]")) % 3 % 5 % 7 % 9;
CHECK_XPATH_NODESET(c, STR("a[following-sibling::*=true()]")) % 3 % 5 % 7;
CHECK_XPATH_NODESET(c, STR("a[false()!=following-sibling::*]")) % 3 % 5 % 7;
CHECK_XPATH_NODESET(c, STR("a[following-sibling::*!=false()]")) % 3 % 5 % 7;
CHECK_XPATH_NODESET(c, STR("a[following-sibling::*=3]")) % 3 % 5;
CHECK_XPATH_NODESET(c, STR("a[3=following-sibling::*]")) % 3 % 5;
CHECK_XPATH_NODESET(c, STR("a[4!=following-sibling::*]")) % 3 % 5;
CHECK_XPATH_NODESET(c, STR("a[following-sibling::*!=4]")) % 3 % 5;
CHECK_XPATH_NODESET(c, STR("a[3>=following-sibling::*]")) % 3 % 5;
CHECK_XPATH_NODESET(c, STR("a[3<=following-sibling::*]")) % 3 % 5 % 7;
CHECK_XPATH_NODESET(c, STR("a[following-sibling::*<=3]")) % 3 % 5;
CHECK_XPATH_NODESET(c, STR("a[following-sibling::*>=3]")) % 3 % 5 % 7;
}
TEST_XML(xpath_xalan_predicate_2, "<foo><bar a='0' b='0' c='0' d='0' seq='0'/><bar a='0' b='0' c='0' d='1' seq='1'/><bar a='0' b='0' c='1' d='0' seq='2'/><bar a='0' b='0' c='1' d='1' seq='3'/><bar a='0' b='1' c='0' d='0' seq='4'/><bar a='0' b='1' c='0' d='1' seq='5'/><bar a='0' b='1' c='1' d='0' seq='6'/><bar a='0' b='1' c='1' d='1' seq='7'/><bar a='1' b='0' c='0' d='0' seq='8'/><bar a='1' b='0' c='0' d='1' seq='9'/><bar a='1' b='0' c='1' d='0' seq='a'/><bar a='1' b='0' c='1' d='1' seq='b'/><bar a='1' b='1' c='0' d='0' seq='c'/><bar a='1' b='1' c='0' d='1' seq='d'/><bar a='1' b='1' c='1' d='0' seq='e'/><bar a='1' b='1' c='1' d='1' seq='f'/></foo>")
{
xml_node c = doc.child(STR("foo"));
CHECK_XPATH_NODESET(c, STR("bar[@a='1' and @b='1']")) % 75 % 81 % 87 % 93;
CHECK_XPATH_NODESET(c, STR("bar[(@a='1' or @b='1') and @c='1']")) % 39 % 45 % 63 % 69 % 87 % 93;
CHECK_XPATH_NODESET(c, STR("bar[@a='1' and (@b='1' or @c='1') and @d='1']")) % 69 % 81 % 93;
CHECK_XPATH_NODESET(c, STR("bar[@a='1' and @b='1' or @c='1' and @d='1']")) % 21 % 45 % 69 % 75 % 81 % 87 % 93;
CHECK_XPATH_NODESET(c, STR("bar[(@a='1' and @b='1') or (@c='1' and @d='1')]")) % 21 % 45 % 69 % 75 % 81 % 87 % 93;
CHECK_XPATH_NODESET(c, STR("bar[@a='1' or (@b='1' and @c='1') or @d='1']")) % 9 % 21 % 33 % 39 % 45 % 51 % 57 % 63 % 69 % 75 % 81 % 87 % 93;
CHECK_XPATH_NODESET(c, STR("bar[(@a='1' or @b='1') and (@c='1' or @d='1')]")) % 33 % 39 % 45 % 57 % 63 % 69 % 81 % 87 % 93;
CHECK_XPATH_NODESET(c, STR("bar[@a='1' or @b='1' and @c='1' or @d='1']")) % 9 % 21 % 33 % 39 % 45 % 51 % 57 % 63 % 69 % 75 % 81 % 87 % 93;
CHECK_XPATH_NODESET(c, STR("bar[@a='1' or @b='1' or @c='1']")) % 15 % 21 % 27 % 33 % 39 % 45 % 51 % 57 % 63 % 69 % 75 % 81 % 87 % 93;
}
TEST_XML(xpath_xalan_predicate_3, "<doc><a>1</a><a ex=''>2</a><a ex='value'>3</a><a why=''>4</a><a why='value'>5</a></doc>")
{
xml_node c = doc.child(STR("doc"));
CHECK_XPATH_NUMBER(c, STR("count(a[@ex])"), 2);
CHECK_XPATH_NUMBER(c, STR("count(a[@ex=''])"), 1);
CHECK_XPATH_NUMBER(c, STR("count(a[string-length(@ex)=0])"), 4);
CHECK_XPATH_NUMBER(c, STR("count(a[@ex!=''])"), 1);
CHECK_XPATH_NUMBER(c, STR("count(a[string-length(@ex) > 0])"), 1);
CHECK_XPATH_NUMBER(c, STR("count(a[not(@ex)])"), 3);
CHECK_XPATH_NUMBER(c, STR("count(a[not(@ex='')])"), 4);
CHECK_XPATH_NUMBER(c, STR("count(a[not(string-length(@ex)=0)])"), 1);
CHECK_XPATH_NUMBER(c, STR("count(a[@why='value'])"), 1);
CHECK_XPATH_NUMBER(c, STR("count(a[@why!='value'])"), 1);
}
TEST_XML(xpath_xalan_predicate_4, "<table><tr><td>1.1</td><td>1.2</td></tr><tr><td>2.1</td><td>2.2</td><td>2.3</td></tr><tr><td>3.1</td><td>3.2<td>3.2.1</td></td></tr><tr><td>4<td>4.1<td>4.1.1</td></td></td></tr><tr><td>5.1</td><td>5.2</td><td>5.3</td><td>5.4</td></tr><tr><ta/><td>6.1</td><td>6.2</td></tr><tr><ta/><td>7.1</td><td>7.2</td><td>7.3</td></tr><tr><ta/><td>8.1</td><td>8.2</td><td>8.3</td><td>8.4</td></tr></table>")
{
CHECK_XPATH_NUMBER(doc, STR("count(//tr)"), 8);
CHECK_XPATH_NUMBER(doc, STR("count(//tr[count(./td)=3])"), 2);
}
TEST_XML(xpath_xalan_predicate_5, "<doc><element1>Wrong node selected!!</element1><element1>Test executed successfully</element1><element1>Wrong node selected!!</element1></doc>")
{
CHECK_XPATH_STRING(doc, STR("doc/element1[(((((2*10)-4)+9) div 5) mod 3 )]"), STR("Test executed successfully"));
CHECK_XPATH_STRING(doc, STR("doc/element1[(((((2*10)-4)+9) div 5) mod floor(3))]"), STR("Test executed successfully"));
CHECK_XPATH_STRING(doc, STR("doc/element1[floor(2)]"), STR("Test executed successfully"));
}
TEST_XML(xpath_xalan_predicate_6, "<doc><a>1</a><a>2<achild>target</achild></a><a>3</a><a>4</a></doc>")
{
CHECK_XPATH_STRING(doc, STR("doc/a['target'=descendant::*]"), STR("2target"));
CHECK_XPATH_STRING(doc, STR("doc/a[descendant::*='target']"), STR("2target"));
}
TEST_XML(xpath_xalan_predicate_7, "<doc><a>1</a><a>2<achild>target</achild></a><a>3</a><a>4<achild>missed</achild></a></doc>")
{
CHECK_XPATH_STRING(doc, STR("doc/a['target'!=descendant::*]"), STR("4missed"));
CHECK_XPATH_STRING(doc, STR("doc/a[descendant::*!='target']"), STR("4missed"));
}
TEST_XML(xpath_xalan_predicate_8, "<doc><foo><bar attr='1'>this</bar><bar attr='2'>2</bar><bar attr='3'>3</bar></foo><foo><bar attr='4'>this</bar><bar attr='5'>this</bar><bar1 attr='6'>that</bar1></foo><foo><bar attr='7'><baz attr='a'>hello</baz><baz attr='b'>goodbye</baz></bar><bar2 attr='8'>this</bar2><bar2 attr='9'>that</bar2></foo><foo><bar attr='10'>this</bar><bar attr='11'><baz attr='a'>hello</baz><baz attr='b'>goodbye</baz></bar><bar attr='12'>other</bar></foo></doc>")
{
xml_node c = doc.child(STR("doc"));
CHECK_XPATH_NODESET(c, STR("foo[(bar[2])='this']")) % 13;
CHECK_XPATH_NODESET(c, STR("foo[(bar[(baz[2])='goodbye'])]")) % 23 % 38;
CHECK_XPATH_NODESET(c, STR("foo[(bar[2][(baz[2])='goodbye'])]")) % 38;
}
TEST_XML(xpath_xalan_predicate_9, "<doc><a><asub><asubsub/></asub></a><b><bsub><foo><child/></foo></bsub></b><c>f-inside</c><d><dsub><dsubsub><foundnode/></dsubsub></dsub></d><e>f-inside<esub>f-inside</esub><esubsib>f-inside</esubsib>f-inside</e><f><fsub/></f></doc>")
{
CHECK_XPATH_NODESET(doc, STR("doc/*[starts-with(name(.),'f')]")) % 23;
CHECK_XPATH_NODESET(doc, STR("//*[starts-with(name(.),'f')]")) % 8 % 15 % 23 % 24;
}
TEST_XML(xpath_xalan_predicate_10, "<doc><element1>Text from first element<child1>Text from child1 of first element</child1><child2>Text from child2 of first element</child2></element1><element2>Text from second element<child1>Text from child1 of second element</child1><child2 attr1='yes'>Text from child2 of second element (correct execution)</child2></element2></doc>")
{
xml_node c = doc.child(STR("doc"));
CHECK_XPATH_STRING(c, STR("//child2[ancestor::element2]"), STR("Text from child2 of second element (correct execution)"));
CHECK_XPATH_STRING(c, STR("//child2[ancestor-or-self::element2]"), STR("Text from child2 of second element (correct execution)"));
CHECK_XPATH_STRING(c, STR("//child2[attribute::attr1]"), STR("Text from child2 of second element (correct execution)"));
}
TEST_XML(xpath_xalan_predicate_11, "<doc><a squish='heavy' squash='butternut'>1</a><a squish='heavy' squeesh='virus'>2</a><a squash='butternut' squeesh='virus'>3</a><a squish='heavy'>4</a><a squeesh='virus'>5</a><a squash='butternut'>6</a></doc>")
{
xml_node c = doc.child(STR("doc"));
CHECK_XPATH_NODESET(c, STR("a[@squeesh or (@squish and @squash)]")) % 3 % 7 % 11 % 18;
CHECK_XPATH_NODESET(c, STR("a[(@squeesh or @squish) and @squash]")) % 3 % 11;
CHECK_XPATH_NODESET(c, STR("a[@squeesh or @squish and @squash]")) % 3 % 7 % 11 % 18;
}
TEST_XML(xpath_xalan_predicate_12, "<doc><a>1</a><a>2<achild>target</achild></a><a>3</a><a>target</a></doc>")
{
CHECK_XPATH_STRING(doc, STR("doc/a[following-sibling::*=descendant::*]"), STR("2target"));
}
TEST_XML(xpath_xalan_predicate_13, "<doc><a squish='heavy'>1</a><a>2<achild>target</achild></a><a>3</a></doc>")
{
CHECK_XPATH_NODESET(doc, STR("doc/a[('target'=descendant::*) or @squish]")) % 3 % 6;
CHECK_XPATH_NODESET(doc, STR("doc/a[not(('target'=descendant::*) or @squish)]")) % 10;
}
TEST_XML(xpath_xalan_predicate_14, "<doc><a squish='heavy'>1</a><a>2<achild size='large'>child2</achild></a><a>3</a><a attrib='present'>4<achild>child4</achild></a></doc>")
{
CHECK_XPATH_NODESET(doc, STR("doc/a[not(@*)]")) % 6 % 11;
}
TEST_XML(xpath_xalan_predicate_15, "<doc><a><asub><asubsub/></asub></a><b><bsub>x</bsub></b><c>inside</c><d><dsub><q><foundnode/></q></dsub></d></doc>")
{
CHECK_XPATH_NODESET(doc, STR("doc/descendant::*[string-length(name(.))=1]")) % 3 % 6 % 9 % 11 % 13;
}
#endif
#ifndef PUGIXML_NO_XPATH
#include "test.hpp"
using namespace pugi;
TEST_XML(xpath_xalan_position_1, "<doc><a>1</a><a>2</a><a>3</a><a>4</a></doc>")
{
xml_node c = doc.child(STR("doc"));
CHECK_XPATH_BOOLEAN(c, STR("position()=1"), true);
CHECK_XPATH_NODESET(c, STR("*[position()=4]")) % 9;
}
TEST_XML_FLAGS(xpath_xalan_position_2, "<doc><a test='true'><num>1</num></a><a><num>1191</num></a><a><num>263</num></a><a test='true'><num>2</num></a><a><num>827</num></a><a><num>256</num></a><a test='true'><num>3</num></a><a test='true'><num>4<x/>5</num></a><?pi?><?pi?><!--comment--><!--comment--></doc>", parse_default | parse_comments | parse_pi)
{
xml_node c = doc.child(STR("doc"));
CHECK_XPATH_NODESET(c, STR("*[@test and position()=8]")) % 27;
CHECK_XPATH_NODESET(c, STR("*[@test][position()=4]/num")) % 29;
CHECK_XPATH_NUMBER(c, STR("count(*)"), 8);
CHECK_XPATH_NODESET(c, STR("*[last()=position()]")) % 27;
CHECK_XPATH_NODESET(c, STR("a[position()=2]")) % 7;
CHECK_XPATH_NODESET(c, STR("a[3]/../a[position()=4]/num/../@test")) % 14;
CHECK_XPATH_BOOLEAN(c, STR("not(position()=last())"), false);
CHECK_XPATH_BOOLEAN(c, STR("position()=2"), false);
CHECK_XPATH_BOOLEAN(c, STR("last()=1"), true);
CHECK_XPATH_BOOLEAN(c, STR("last()+2=3"), true);
CHECK_XPATH_NODESET(c, STR("a[position()=5 mod 3]")) % 7;
CHECK_XPATH_NODESET(c, STR("a/num/text()[position()=1]")) % 6 % 9 % 12 % 16 % 19 % 22 % 26 % 30;
CHECK_XPATH_NODESET(c, STR("a/num/text()[position()=2]")) % 32;
CHECK_XPATH_NODESET(c, STR("a/num/text()[position()=last()]")) % 6 % 9 % 12 % 16 % 19 % 22 % 26 % 32;
CHECK_XPATH_NODESET(c, STR("a/num/text()[1]")) % 6 % 9 % 12 % 16 % 19 % 22 % 26 % 30;
CHECK_XPATH_NODESET(c, STR("a/num/text()[2]")) % 32;
CHECK_XPATH_NODESET(c, STR("a/num/text()[last()]")) % 6 % 9 % 12 % 16 % 19 % 22 % 26 % 32;
CHECK_XPATH_NODESET(c, STR("a[floor(last() div 3)]")) % 7;
CHECK_XPATH_NODESET(c, STR("a[ceiling(last() div 3)]")) % 10;
CHECK_XPATH_NODESET(c, STR("a[round(last() div 3)]")) % 10;
CHECK_XPATH_NODESET(c, STR("a[last() div 3]"));
CHECK_XPATH_NODESET(c, STR("a[last() div 2]")) % 13;
CHECK_XPATH_NODESET(c, STR("a[3]/../a[position()>=2 and position()<=4]")) % 7 % 10 % 13;
CHECK_XPATH_NUMBER(c, STR("count(a[position()>=2 and position()<=4]/num)"), 3);
CHECK_XPATH_NUMBER(c, STR("count(a/@*)"), 4);
CHECK_XPATH_NUMBER(c, STR("count(a/attribute::*)"), 4);
CHECK_XPATH_NODESET(c, STR("*[not(@test)][position()=last()]")) % 20;
CHECK_XPATH_NODESET(c, STR("*[not(@test)][last()]")) % 20;
CHECK_XPATH_NODESET(c, STR("a[3-2]")) % 3;
CHECK_XPATH_NODESET(c, STR("a[0]"));
CHECK_XPATH_NODESET(c, STR("a[9]"));
CHECK_XPATH_NODESET(c, STR("a['3']")) % 3 % 7 % 10 % 13 % 17 % 20 % 23 % 27;
CHECK_XPATH_NODESET(c, STR("a[number('3')]")) % 10;
CHECK_XPATH_NODESET(c, STR("processing-instruction()[2]")) % 34;
CHECK_XPATH_NODESET(c, STR("processing-instruction('pi')[2]")) % 34;
CHECK_XPATH_NODESET(c, STR("comment()[2]")) % 36;
CHECK_XPATH_NODESET(c, STR("a/*[last()]")) % 5 % 8 % 11 % 15 % 18 % 21 % 25 % 29;
CHECK_XPATH_NODESET(c, STR("a/child::*[last()]")) % 5 % 8 % 11 % 15 % 18 % 21 % 25 % 29;
CHECK_XPATH_NODESET(c, STR("a/descendant::*[last()]")) % 5 % 8 % 11 % 15 % 18 % 21 % 25 % 31;
CHECK_XPATH_NODESET(c, STR("a/child::node()[last()]")) % 5 % 8 % 11 % 15 % 18 % 21 % 25 % 29;
CHECK_XPATH_NODESET(c, STR("a/descendant::text()[last()]")) % 6 % 9 % 12 % 16 % 19 % 22 % 26 % 32;
CHECK_XPATH_NODESET(c, STR("child::comment()[last()]")) % 36;
}
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>")
{
CHECK_XPATH_NODESET(doc, STR("(article//section/title|/articleinfo/title|article/section/para)[last()]")) % 28;
CHECK_XPATH_NODESET(doc, STR("(article//section/title|/articleinfo/title|article/section/para)[1]")) % 10;
CHECK_XPATH_NUMBER(doc, STR("count(article/articleinfo/section[last()])"), 1);
CHECK_XPATH_NUMBER(doc, STR("count(article/articleinfo/section[last()][title='BBB'])"), 1);
}
TEST_XML(xpath_xalan_position_4, "<chapter><section><footnote>hello</footnote></section><section><footnote>goodbye</footnote><footnote>sayonara</footnote></section><section><footnote>aloha</footnote></section></chapter>")
{
CHECK_XPATH_NODESET(doc, STR("chapter//footnote[1]")) % 4 % 7 % 12;
}
TEST_XML(xpath_xalan_position_5, "<chapter><section><footnote>hello</footnote><footnote>ahoy</footnote></section><section><footnote>goodbye</footnote><footnote>sayonara</footnote><footnote>adios</footnote></section><section><footnote>aloha</footnote><subsection><footnote>shalom</footnote><footnote>yo</footnote></subsection><footnote>ciao</footnote></section></chapter>")
{
CHECK_XPATH_NODESET(doc, STR("chapter//footnote[2]")) % 6 % 11 % 21 % 23;
CHECK_XPATH_NODESET(doc, STR("(chapter//footnote)[2]")) % 6;
CHECK_XPATH_NODESET(doc, STR("(child::chapter/descendant-or-self::node())/footnote[2]")) % 6 % 11 % 21 % 23;
CHECK_XPATH_NODESET(doc, STR("chapter/descendant::footnote[6]")) % 16;
CHECK_XPATH_NODESET(doc, STR("chapter/descendant::footnote[6][1][last()]")) % 16;
}
TEST_XML_FLAGS(xpath_xalan_position_6, "<node attr='value'>pcdata<child/><?pi1 value?><?pi2 value?><!--comment--><![CDATA[cdata]]></node>", parse_default | parse_pi | parse_comments)
{
CHECK_XPATH_NUMBER(doc, STR("count(/node/@attr/ancestor-or-self::node())"), 3);
CHECK_XPATH_NUMBER(doc, STR("count(/node/text()/ancestor-or-self::node())"), 4);
CHECK_XPATH_NUMBER(doc, STR("count(/node/processing-instruction()/ancestor-or-self::node())"), 4);
CHECK_XPATH_NUMBER(doc, STR("count(/node/processing-instruction('pi1')/ancestor-or-self::node())"), 3);
CHECK_XPATH_NUMBER(doc, STR("count(/node/comment()/ancestor-or-self::node())"), 3);
}
TEST_XML(xpath_xalan_position_7, "<chapter title='A'><section title='A1'><subsection title='A1a'>hello</subsection><subsection title='A1b'>ahoy</subsection></section><section title='A2'><subsection title='A2a'>goodbye</subsection><subsection title='A2b'>sayonara</subsection><subsection title='A2c'>adios</subsection></section><section title='A3'><subsection title='A3a'>aloha</subsection><subsection title='A3b'><footnote>A3b-1</footnote><footnote>A3b-2</footnote></subsection><subsection title='A3c'>shalom</subsection></section></chapter>")
{
CHECK_XPATH_NODESET(doc, STR("chapter/section//@title[7]"));
CHECK_XPATH_NODESET(doc, STR("(chapter/section//@title)[7]")) % 21;
}
TEST_XML(xpath_xalan_match_1, "<root><x spot='a' num='1'/><x spot='b' num='2'/><x spot='c' num='3'/><x spot='d' num='4'/><x spot='e' num='5'/><x spot='f' num='6'/><x spot='g' num='7'/><x spot='h' num='8'/><x spot='i' num='9'/><x spot='j' num='10'/><x spot='k' num='11'/><x spot='l' num='12'/></root>")
{
xml_node c = doc.child(STR("root"));
CHECK_XPATH_NODESET(c, STR("x[(position() mod 2)=1][position() > 3]")) % 21 % 27 % 33;
CHECK_XPATH_NODESET(c, STR("x[(position() mod 2)=1][position() > 3][position()=2]")) % 27;
CHECK_XPATH_NODESET(c, STR("x[(position() mod 2) > 0][position() > 3][2]")) % 27;
CHECK_XPATH_NODESET(c, STR("x[(position() mod 2)=1][position() > 3][last()]")) % 33;
CHECK_XPATH_NODESET(c, STR("x[(position() mod 2)=1][@num > 5][last()]")) % 33;
CHECK_XPATH_NODESET(c, STR("x[(@num mod 3)=2][position() > 2][last()]")) % 33;
CHECK_XPATH_NODESET(c, STR("x[(position() mod 2)=1][2][@num < 10]")) % 9;
CHECK_XPATH_NODESET(c, STR("x[(((((2*10)-4)+9) div 5) mod 3)]")) % 6;
}
TEST_XML(xpath_xalan_match_2, "<doc><l1><v2>doc-l1-v2</v2><x2>doc-l1-x2</x2><l2><v3>doc-l1-l2-v3</v3><w3>doc-l1-l2-w3</w3><x3>doc-l1-l2-x3</x3><y3>doc-l1-l2-y3</y3><l3><v4>doc-l1-l2-l3-v4</v4><x4>doc-l1-l2-l3-x4</x4></l3></l2></l1></doc>")
{
CHECK_XPATH_STRING(doc, STR("doc/l1/v2"), STR("doc-l1-v2"));
CHECK_XPATH_STRING(doc, STR("doc/child::l1/x2"), STR("doc-l1-x2"));
CHECK_XPATH_STRING(doc, STR("doc/l1//v3"), STR("doc-l1-l2-v3"));
CHECK_XPATH_STRING(doc, STR("doc//l2/w3"), STR("doc-l1-l2-w3"));
CHECK_XPATH_STRING(doc, STR("doc/child::l1//x3"), STR("doc-l1-l2-x3"));
CHECK_XPATH_STRING(doc, STR("doc//child::l2/y3"), STR("doc-l1-l2-y3"));
CHECK_XPATH_STRING(doc, STR("doc//l2//v4"), STR("doc-l1-l2-l3-v4"));
CHECK_XPATH_STRING(doc, STR("doc//child::l2//x4"), STR("doc-l1-l2-l3-x4"));
CHECK_XPATH_STRING(doc, STR("doc/l1/v2"), STR("doc-l1-v2"));
CHECK_XPATH_STRING(doc, STR("doc/l1/child::x2"), STR("doc-l1-x2"));
CHECK_XPATH_STRING(doc, STR("doc/l1//v3"), STR("doc-l1-l2-v3"));
CHECK_XPATH_STRING(doc, STR("doc//l2/w3"), STR("doc-l1-l2-w3"));
CHECK_XPATH_STRING(doc, STR("doc/l1//child::x3"), STR("doc-l1-l2-x3"));
CHECK_XPATH_STRING(doc, STR("doc//l2/child::y3"), STR("doc-l1-l2-y3"));
CHECK_XPATH_STRING(doc, STR("doc//l2//v4"), STR("doc-l1-l2-l3-v4"));
CHECK_XPATH_STRING(doc, STR("doc//l2//child::x4"), STR("doc-l1-l2-l3-x4"));
CHECK_XPATH_STRING(doc, STR("doc/l1/v2"), STR("doc-l1-v2"));
CHECK_XPATH_STRING(doc, STR("doc/child::l1/child::x2"), STR("doc-l1-x2"));
CHECK_XPATH_STRING(doc, STR("doc/l1//v3"), STR("doc-l1-l2-v3"));
CHECK_XPATH_STRING(doc, STR("doc//l2/w3"), STR("doc-l1-l2-w3"));
CHECK_XPATH_STRING(doc, STR("doc/child::l1//child::x3"), STR("doc-l1-l2-x3"));
CHECK_XPATH_STRING(doc, STR("doc//child::l2/child::y3"), STR("doc-l1-l2-y3"));
CHECK_XPATH_STRING(doc, STR("doc//l2//v4"), STR("doc-l1-l2-l3-v4"));
CHECK_XPATH_STRING(doc, STR("doc//child::l2//child::x4"), STR("doc-l1-l2-l3-x4"));
}
TEST_XML(xpath_xalan_match_3, "<doc><child><child-foo><name id='1'>John Doe</name><child><name id='2'>Jane Doe</name></child></child-foo></child></doc>")
{
CHECK_XPATH_NODESET(doc, STR("doc/child/*[starts-with(name(),'child-')]//name")) % 5 % 9;
CHECK_XPATH_NODESET(doc, STR("//@*")) % 6 % 10;
}
TEST_XML(xpath_xalan_expression_1, "<doc><para id='1' xml:lang='en'>en</para><div xml:lang='en'><para>en</para></div><para id='3' xml:lang='EN'>EN</para><para id='4' xml:lang='en-us'>en-us</para></doc>")
{
CHECK_XPATH_NODESET(doc, STR("doc/para[@id='1' and lang('en')]")) % 3;
CHECK_XPATH_NODESET(doc, STR("doc/para[@id='4' and lang('en')]")) % 15;
CHECK_XPATH_NODESET(doc, STR("doc/div/para[lang('en')]")) % 9;
CHECK_XPATH_NODESET(doc, STR("doc/para[@id='3' and lang('en')]")) % 11;
CHECK_XPATH_NODESET(doc, STR("//para[lang('en')]/ancestor-or-self::*[@xml:lang]/@xml:lang")) % 5 % 8 % 13 % 17;
}
TEST_XML(xpath_xalan_predicate_1, "<doc><a>1</a><a>2</a><a>3</a><a>4</a></doc>")
{
xml_node c = doc.child(STR("doc"));
CHECK_XPATH_NODESET(c, STR("a[true()=4]")) % 3 % 5 % 7 % 9;
CHECK_XPATH_NODESET(c, STR("a[true()='stringwithchars']")) % 3 % 5 % 7 % 9;
CHECK_XPATH_NODESET(c, STR("a[true()=following-sibling::*]")) % 3 % 5 % 7;
CHECK_XPATH_NODESET(c, STR("a[true()=preceding-sibling::*]")) % 5 % 7 % 9;
CHECK_XPATH_NODESET(c, STR("a[3=following-sibling::*]")) % 3 % 5;
CHECK_XPATH_NODESET(c, STR("a[0 < true()]")) % 3 % 5 % 7 % 9;
CHECK_XPATH_NODESET(c, STR("a['3.5' < 4]")) % 3 % 5 % 7 % 9;
CHECK_XPATH_NODESET(c, STR("a[3 < following-sibling::*]")) % 3 % 5 % 7;
CHECK_XPATH_NODESET(c, STR("a[following-sibling::*>3]")) % 3 % 5 % 7;
CHECK_XPATH_NODESET(c, STR("a[3 > following-sibling::*]")) % 3;
CHECK_XPATH_NODESET(c, STR("a[following-sibling::*<3]")) % 3;
CHECK_XPATH_NODESET(c, STR("a[1 < 2 < 3]")) % 3 % 5 % 7 % 9;
CHECK_XPATH_NODESET(c, STR("a[1 < 3 < 2]")) % 3 % 5 % 7 % 9;
CHECK_XPATH_NODESET(c, STR("a[following-sibling::*=true()]")) % 3 % 5 % 7;
CHECK_XPATH_NODESET(c, STR("a[false()!=following-sibling::*]")) % 3 % 5 % 7;
CHECK_XPATH_NODESET(c, STR("a[following-sibling::*!=false()]")) % 3 % 5 % 7;
CHECK_XPATH_NODESET(c, STR("a[following-sibling::*=3]")) % 3 % 5;
CHECK_XPATH_NODESET(c, STR("a[3=following-sibling::*]")) % 3 % 5;
CHECK_XPATH_NODESET(c, STR("a[4!=following-sibling::*]")) % 3 % 5;
CHECK_XPATH_NODESET(c, STR("a[following-sibling::*!=4]")) % 3 % 5;
CHECK_XPATH_NODESET(c, STR("a[3>=following-sibling::*]")) % 3 % 5;
CHECK_XPATH_NODESET(c, STR("a[3<=following-sibling::*]")) % 3 % 5 % 7;
CHECK_XPATH_NODESET(c, STR("a[following-sibling::*<=3]")) % 3 % 5;
CHECK_XPATH_NODESET(c, STR("a[following-sibling::*>=3]")) % 3 % 5 % 7;
}
TEST_XML(xpath_xalan_predicate_2, "<foo><bar a='0' b='0' c='0' d='0' seq='0'/><bar a='0' b='0' c='0' d='1' seq='1'/><bar a='0' b='0' c='1' d='0' seq='2'/><bar a='0' b='0' c='1' d='1' seq='3'/><bar a='0' b='1' c='0' d='0' seq='4'/><bar a='0' b='1' c='0' d='1' seq='5'/><bar a='0' b='1' c='1' d='0' seq='6'/><bar a='0' b='1' c='1' d='1' seq='7'/><bar a='1' b='0' c='0' d='0' seq='8'/><bar a='1' b='0' c='0' d='1' seq='9'/><bar a='1' b='0' c='1' d='0' seq='a'/><bar a='1' b='0' c='1' d='1' seq='b'/><bar a='1' b='1' c='0' d='0' seq='c'/><bar a='1' b='1' c='0' d='1' seq='d'/><bar a='1' b='1' c='1' d='0' seq='e'/><bar a='1' b='1' c='1' d='1' seq='f'/></foo>")
{
xml_node c = doc.child(STR("foo"));
CHECK_XPATH_NODESET(c, STR("bar[@a='1' and @b='1']")) % 75 % 81 % 87 % 93;
CHECK_XPATH_NODESET(c, STR("bar[(@a='1' or @b='1') and @c='1']")) % 39 % 45 % 63 % 69 % 87 % 93;
CHECK_XPATH_NODESET(c, STR("bar[@a='1' and (@b='1' or @c='1') and @d='1']")) % 69 % 81 % 93;
CHECK_XPATH_NODESET(c, STR("bar[@a='1' and @b='1' or @c='1' and @d='1']")) % 21 % 45 % 69 % 75 % 81 % 87 % 93;
CHECK_XPATH_NODESET(c, STR("bar[(@a='1' and @b='1') or (@c='1' and @d='1')]")) % 21 % 45 % 69 % 75 % 81 % 87 % 93;
CHECK_XPATH_NODESET(c, STR("bar[@a='1' or (@b='1' and @c='1') or @d='1']")) % 9 % 21 % 33 % 39 % 45 % 51 % 57 % 63 % 69 % 75 % 81 % 87 % 93;
CHECK_XPATH_NODESET(c, STR("bar[(@a='1' or @b='1') and (@c='1' or @d='1')]")) % 33 % 39 % 45 % 57 % 63 % 69 % 81 % 87 % 93;
CHECK_XPATH_NODESET(c, STR("bar[@a='1' or @b='1' and @c='1' or @d='1']")) % 9 % 21 % 33 % 39 % 45 % 51 % 57 % 63 % 69 % 75 % 81 % 87 % 93;
CHECK_XPATH_NODESET(c, STR("bar[@a='1' or @b='1' or @c='1']")) % 15 % 21 % 27 % 33 % 39 % 45 % 51 % 57 % 63 % 69 % 75 % 81 % 87 % 93;
}
TEST_XML(xpath_xalan_predicate_3, "<doc><a>1</a><a ex=''>2</a><a ex='value'>3</a><a why=''>4</a><a why='value'>5</a></doc>")
{
xml_node c = doc.child(STR("doc"));
CHECK_XPATH_NUMBER(c, STR("count(a[@ex])"), 2);
CHECK_XPATH_NUMBER(c, STR("count(a[@ex=''])"), 1);
CHECK_XPATH_NUMBER(c, STR("count(a[string-length(@ex)=0])"), 4);
CHECK_XPATH_NUMBER(c, STR("count(a[@ex!=''])"), 1);
CHECK_XPATH_NUMBER(c, STR("count(a[string-length(@ex) > 0])"), 1);
CHECK_XPATH_NUMBER(c, STR("count(a[not(@ex)])"), 3);
CHECK_XPATH_NUMBER(c, STR("count(a[not(@ex='')])"), 4);
CHECK_XPATH_NUMBER(c, STR("count(a[not(string-length(@ex)=0)])"), 1);
CHECK_XPATH_NUMBER(c, STR("count(a[@why='value'])"), 1);
CHECK_XPATH_NUMBER(c, STR("count(a[@why!='value'])"), 1);
}
TEST_XML(xpath_xalan_predicate_4, "<table><tr><td>1.1</td><td>1.2</td></tr><tr><td>2.1</td><td>2.2</td><td>2.3</td></tr><tr><td>3.1</td><td>3.2<td>3.2.1</td></td></tr><tr><td>4<td>4.1<td>4.1.1</td></td></td></tr><tr><td>5.1</td><td>5.2</td><td>5.3</td><td>5.4</td></tr><tr><ta/><td>6.1</td><td>6.2</td></tr><tr><ta/><td>7.1</td><td>7.2</td><td>7.3</td></tr><tr><ta/><td>8.1</td><td>8.2</td><td>8.3</td><td>8.4</td></tr></table>")
{
CHECK_XPATH_NUMBER(doc, STR("count(//tr)"), 8);
CHECK_XPATH_NUMBER(doc, STR("count(//tr[count(./td)=3])"), 2);
}
TEST_XML(xpath_xalan_predicate_5, "<doc><element1>Wrong node selected!!</element1><element1>Test executed successfully</element1><element1>Wrong node selected!!</element1></doc>")
{
CHECK_XPATH_STRING(doc, STR("doc/element1[(((((2*10)-4)+9) div 5) mod 3 )]"), STR("Test executed successfully"));
CHECK_XPATH_STRING(doc, STR("doc/element1[(((((2*10)-4)+9) div 5) mod floor(3))]"), STR("Test executed successfully"));
CHECK_XPATH_STRING(doc, STR("doc/element1[floor(2)]"), STR("Test executed successfully"));
}
TEST_XML(xpath_xalan_predicate_6, "<doc><a>1</a><a>2<achild>target</achild></a><a>3</a><a>4</a></doc>")
{
CHECK_XPATH_STRING(doc, STR("doc/a['target'=descendant::*]"), STR("2target"));
CHECK_XPATH_STRING(doc, STR("doc/a[descendant::*='target']"), STR("2target"));
}
TEST_XML(xpath_xalan_predicate_7, "<doc><a>1</a><a>2<achild>target</achild></a><a>3</a><a>4<achild>missed</achild></a></doc>")
{
CHECK_XPATH_STRING(doc, STR("doc/a['target'!=descendant::*]"), STR("4missed"));
CHECK_XPATH_STRING(doc, STR("doc/a[descendant::*!='target']"), STR("4missed"));
}
TEST_XML(xpath_xalan_predicate_8, "<doc><foo><bar attr='1'>this</bar><bar attr='2'>2</bar><bar attr='3'>3</bar></foo><foo><bar attr='4'>this</bar><bar attr='5'>this</bar><bar1 attr='6'>that</bar1></foo><foo><bar attr='7'><baz attr='a'>hello</baz><baz attr='b'>goodbye</baz></bar><bar2 attr='8'>this</bar2><bar2 attr='9'>that</bar2></foo><foo><bar attr='10'>this</bar><bar attr='11'><baz attr='a'>hello</baz><baz attr='b'>goodbye</baz></bar><bar attr='12'>other</bar></foo></doc>")
{
xml_node c = doc.child(STR("doc"));
CHECK_XPATH_NODESET(c, STR("foo[(bar[2])='this']")) % 13;
CHECK_XPATH_NODESET(c, STR("foo[(bar[(baz[2])='goodbye'])]")) % 23 % 38;
CHECK_XPATH_NODESET(c, STR("foo[(bar[2][(baz[2])='goodbye'])]")) % 38;
}
TEST_XML(xpath_xalan_predicate_9, "<doc><a><asub><asubsub/></asub></a><b><bsub><foo><child/></foo></bsub></b><c>f-inside</c><d><dsub><dsubsub><foundnode/></dsubsub></dsub></d><e>f-inside<esub>f-inside</esub><esubsib>f-inside</esubsib>f-inside</e><f><fsub/></f></doc>")
{
CHECK_XPATH_NODESET(doc, STR("doc/*[starts-with(name(.),'f')]")) % 23;
CHECK_XPATH_NODESET(doc, STR("//*[starts-with(name(.),'f')]")) % 8 % 15 % 23 % 24;
}
TEST_XML(xpath_xalan_predicate_10, "<doc><element1>Text from first element<child1>Text from child1 of first element</child1><child2>Text from child2 of first element</child2></element1><element2>Text from second element<child1>Text from child1 of second element</child1><child2 attr1='yes'>Text from child2 of second element (correct execution)</child2></element2></doc>")
{
xml_node c = doc.child(STR("doc"));
CHECK_XPATH_STRING(c, STR("//child2[ancestor::element2]"), STR("Text from child2 of second element (correct execution)"));
CHECK_XPATH_STRING(c, STR("//child2[ancestor-or-self::element2]"), STR("Text from child2 of second element (correct execution)"));
CHECK_XPATH_STRING(c, STR("//child2[attribute::attr1]"), STR("Text from child2 of second element (correct execution)"));
}
TEST_XML(xpath_xalan_predicate_11, "<doc><a squish='heavy' squash='butternut'>1</a><a squish='heavy' squeesh='virus'>2</a><a squash='butternut' squeesh='virus'>3</a><a squish='heavy'>4</a><a squeesh='virus'>5</a><a squash='butternut'>6</a></doc>")
{
xml_node c = doc.child(STR("doc"));
CHECK_XPATH_NODESET(c, STR("a[@squeesh or (@squish and @squash)]")) % 3 % 7 % 11 % 18;
CHECK_XPATH_NODESET(c, STR("a[(@squeesh or @squish) and @squash]")) % 3 % 11;
CHECK_XPATH_NODESET(c, STR("a[@squeesh or @squish and @squash]")) % 3 % 7 % 11 % 18;
}
TEST_XML(xpath_xalan_predicate_12, "<doc><a>1</a><a>2<achild>target</achild></a><a>3</a><a>target</a></doc>")
{
CHECK_XPATH_STRING(doc, STR("doc/a[following-sibling::*=descendant::*]"), STR("2target"));
}
TEST_XML(xpath_xalan_predicate_13, "<doc><a squish='heavy'>1</a><a>2<achild>target</achild></a><a>3</a></doc>")
{
CHECK_XPATH_NODESET(doc, STR("doc/a[('target'=descendant::*) or @squish]")) % 3 % 6;
CHECK_XPATH_NODESET(doc, STR("doc/a[not(('target'=descendant::*) or @squish)]")) % 10;
}
TEST_XML(xpath_xalan_predicate_14, "<doc><a squish='heavy'>1</a><a>2<achild size='large'>child2</achild></a><a>3</a><a attrib='present'>4<achild>child4</achild></a></doc>")
{
CHECK_XPATH_NODESET(doc, STR("doc/a[not(@*)]")) % 6 % 11;
}
TEST_XML(xpath_xalan_predicate_15, "<doc><a><asub><asubsub/></asub></a><b><bsub>x</bsub></b><c>inside</c><d><dsub><q><foundnode/></q></dsub></d></doc>")
{
CHECK_XPATH_NODESET(doc, STR("doc/descendant::*[string-length(name(.))=1]")) % 3 % 6 % 9 % 11 % 13;
}
#endif

View File

@ -1,295 +1,295 @@
#ifndef PUGIXML_NO_XPATH
#include "test.hpp"
using namespace pugi;
TEST_XML(xpath_xalan_select_1, "<doc><a><b attr='test'/></a><c><d><e/></d></c></doc>")
{
CHECK_XPATH_STRING(doc, STR("/doc/a/b/@attr"), STR("test"));
}
TEST_XML(xpath_xalan_select_2, "<doc><do do='-do-'>do</do><re>re</re><mi mi1='-mi1-' mi2='mi2'>mi</mi><fa fa='-fa-'>fa<so so='-so-'>so<la>la<ti>ti</ti>do</la></so></fa><Gsharp so='so+'>G#</Gsharp><Aflat><natural><la>A</la></natural>Ab</Aflat><Bflat>Bb</Bflat><Csharp><natural>C</natural>C#<doublesharp>D</doublesharp></Csharp></doc>")
{
xml_node c = doc.child(STR("doc"));
// This should come out fasolatido:
CHECK_XPATH_NODESET(c, STR("fa")) % 12;
// This should come out doremifasolatido:
CHECK_XPATH_NODESET(c, STR("mi | do | fa | re")) % 3 % 6 % 8 % 12;
// This should come out do-do-remi-mi1-mi2fasolatido-fa--so-:
CHECK_XPATH_NODESET(c, STR("mi[@mi2='mi2'] | do | fa/so/@so | fa | mi/@* | re | fa/@fa | do/@do")) % 3 % 4 % 6 % 8 % 9 % 10 % 12 % 13 % 16;
// This should come out solatidoG#:
CHECK_XPATH_NODESET(c, STR(".//*[@so]")) % 15 % 23;
// This should come out relatidoABb:
CHECK_XPATH_NODESET(c, STR("*//la | //Bflat | re")) % 6 % 18 % 28 % 31;
// This should come out domitiACD:
CHECK_XPATH_NODESET(c, STR("fa/../mi | Aflat/natural/la | Csharp//* | /doc/do | *//ti")) % 3 % 8 % 20 % 28 % 34 % 37;
}
TEST_XML(xpath_xalan_select_3, "<doc><sub1><child1>preceding sibling number 1</child1><child2>current node</child2><child3>following sibling number 3</child3></sub1><sub2><c>cousin 1</c><c>cousin 2</c><child3>cousin 3</child3></sub2></doc>")
{
CHECK_XPATH_NODESET(doc.child(STR("doc")).child(STR("sub1")).child(STR("child2")), STR("preceding-sibling::child1|//child3")) % 4 % 8 % 15;
}
TEST_XML(xpath_xalan_select_4, "<doc><child>bad1<sub>bad2</sub></child><c>bad3<sub>bad4</sub></c><sub>OK<nogo>bad5</nogo></sub></doc>")
{
xml_node c = doc.child(STR("doc"));
CHECK_XPATH_NODESET(c, STR("child::sub")) % 11;
CHECK_XPATH_NODESET(c, STR("child ::sub")) % 11;
CHECK_XPATH_NODESET(c, STR("child:: sub")) % 11;
CHECK_XPATH_NODESET(c, STR("child :: sub")) % 11;
}
TEST_XML_FLAGS(xpath_xalan_select_5, "<doc>bad0<!-- Good --><comment>bad1<sub>bad2</sub></comment></doc>", parse_default | parse_comments)
{
xml_node c = doc.child(STR("doc"));
CHECK_XPATH_NODESET(c, STR("comment()")) % 4;
CHECK_XPATH_NODESET(c, STR("comment ()")) % 4;
CHECK_XPATH_NODESET(c, STR("comment ( ) ")) % 4;
CHECK_XPATH_NUMBER(c, STR("string-length()"), 12);
CHECK_XPATH_NUMBER(c, STR("string-length ()"), 12);
CHECK_XPATH_NUMBER(c, STR("string-length ( ) "), 12);
}
TEST_XML(xpath_xalan_select_6, "<div div='20' div-5='12'>9</div>")
{
xml_node c = doc.child(STR("div"));
CHECK_XPATH_NUMBER(doc, STR("div +3"), 12);
CHECK_XPATH_NUMBER(doc, STR("* +3"), 12);
CHECK_XPATH_NUMBER(c, STR("@div - 5"), 15);
CHECK_XPATH_NUMBER(c, STR("@div -5"), 15);
CHECK_XPATH_NUMBER(c, STR("@div-5"), 12);
CHECK_XPATH_NUMBER(c, STR("@*-5"), 15);
CHECK_XPATH_NUMBER(doc, STR("16-div"), 7);
CHECK_XPATH_NUMBER(doc, STR("25-*"), 16);
CHECK_XPATH_NUMBER(doc, STR("54 div*"), 6);
CHECK_XPATH_NUMBER(doc, STR("(* - 4) div 2"), 2.5);
CHECK_XPATH_NUMBER(doc, STR("' 6 ' div 2"), 3);
CHECK_XPATH_NUMBER(doc, STR("' 6 '*div"), 54);
CHECK_XPATH_NUMBER(doc, STR("5.*."), 45);
CHECK_XPATH_NUMBER(doc, STR("5.+."), 14);
}
TEST_XML(xpath_xalan_select_7, "<doc div='20'><div>9</div><attribute>8</attribute></doc>")
{
xml_node c = doc.child(STR("doc"));
CHECK_XPATH_NUMBER(c, STR("attribute :: div"), 20);
CHECK_XPATH_NUMBER(c, STR("attribute :: *"), 20);
CHECK_XPATH_NUMBER(c, STR("attribute*(div - 4)"), 40);
CHECK_XPATH_NUMBER(c, STR("(* - 4)**"), 45);
}
TEST_XML(xpath_xalan_select_8, "<doc><a>x<div>7</div></a><a>y<div>9</div></a><a>z<div>5</div></a></doc>")
{
CHECK_XPATH_NODESET(doc, STR("doc/a[div=9]")) % 7;
}
TEST_XML(xpath_xalan_select_9, "<doc><a s='v'><b>7</b><c>3</c></a><a s='w'><b>7</b><c>9</c></a><a s='x'><b>9</b><c>2</c></a><a s='y'><b>9</b><c>9</c></a><a s='z'><b>2</b><c>0</c></a></doc>")
{
CHECK_XPATH_NODESET(doc, STR("doc/a[*=9]")) % 9 % 15 % 21;
}
TEST_XML(xpath_xalan_select_10, "<doc><sub1><child1>child1</child1></sub1><sub2><child2>child2</child2></sub2><sub3><child3/></sub3></doc>")
{
CHECK_XPATH_NODESET(doc, STR("/doc/sub1/child1|/doc/sub2/child2")) % 4 % 7;
CHECK_XPATH_NODESET(doc.child(STR("doc")), STR("sub1/child1|/doc/sub2/child2")) % 4 % 7;
CHECK_XPATH_NODESET(doc.child(STR("doc")), STR("sub1/child1|sub2/child2")) % 4 % 7;
CHECK_XPATH_NODESET(doc, STR("//self::child1|//self::child2")) % 4 % 7;
CHECK_XPATH_NODESET(doc, STR("//child1|//child2")) % 4 % 7;
CHECK_XPATH_NODESET(doc, STR("//child1|//child2|//child3")) % 4 % 7 % 10;
}
TEST_XML(xpath_xalan_select_11, "<doc><sub1 pos='1'><child1>descendant number 1</child1></sub1><sub2 pos='2'><child1>descendant number 2</child1></sub2></doc>")
{
CHECK_XPATH_NODESET(doc, STR("//child1/ancestor::sub1|//child1/ancestor::sub2")) % 3 % 7;
}
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;
}
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>")
{
CHECK_XPATH_NODESET(doc, STR("doc/book/author[name/@real='no']|doc/book/author[name/@real='yes']")) % 4 % 20;
CHECK_XPATH_NODESET(doc, STR("doc/book/author[(name/@real='no' and position()=1)]|doc/book/author[(name/@real='yes' and position()=last())]")) % 4 % 20;
CHECK_XPATH_NODESET(doc, STR("doc/book/author[name='Mary Brady']|doc/book/author[name/@real='no']")) % 4 % 20;
CHECK_XPATH_NODESET(doc, STR("doc/book/author/name|doc/book/author/bibliography/author/name")) % 5 % 13 % 21 % 28;
CHECK_XPATH_NODESET(doc, STR("doc/book/author/name|doc/book/author/bibliography/author/chapters")) % 5 % 13 % 21 % 30;
CHECK_XPATH_NODESET(doc, STR("doc/book/author/name|doc/book/author/noElement")) % 5 % 13 % 21;
CHECK_XPATH_NODESET(doc, STR("//noChild1|//noChild2"));
}
TEST_XML(xpath_xalan_select_14, "<doc><sub1 pos='1'><child1>child number 1</child1></sub1><sub2 pos='2'><child2>child number 2</child2></sub2><sub3/></doc>")
{
xml_node c = doc.child(STR("doc"));
CHECK_XPATH_NODESET(c, STR("child::sub1|child::sub2")) % 3 % 7;
CHECK_XPATH_NODESET(c, STR("descendant::child1|descendant::child2")) % 5 % 9;
CHECK_XPATH_NODESET(c, STR("descendant-or-self::sub1|descendant-or-self::sub2")) % 3 % 7;
CHECK_XPATH_NODESET(c.child(STR("sub2")), STR("preceding-sibling::sub1|following-sibling::sub3")) % 3 % 11;
}
TEST_XML(xpath_xalan_select_15, "<doc><child>Selection of this child is an error.</child><child high='3'>Selection of this child is an error.</child><child wide='4'>Selection of this child is an error.</child><child wide='4' high='3'>Selection of this child is an error.</child><child wide='3'>E</child><child wide='3' high='3'>F</child><child wide='3' deep='3'>G</child><child wide='4' deep='2'>Selection of this child is an error.</child><child wide='4' deep='2' high='3'>Selection of this child is an error.</child><child wide='3' deep='2'>J</child><child wide='3' deep='3' high='3'>K</child><child deep='2'>Selection of this child is an error.</child><child deep='2' high='3'>Selection of this child is an error.</child><child deep='3'>N</child><child deep='3' high='3'>O</child><child wide='4' deep='3'>P</child></doc>")
{
xml_node c = doc.child(STR("doc"));
CHECK_XPATH_NODESET(c, STR("child[@wide='3']|child[@deep='3']")) % 15 % 18 % 22 % 35 % 39 % 51 % 54 % 58;
CHECK_XPATH_NODESET(c, STR("child[@deep='3']|child[@wide='3']")) % 15 % 18 % 22 % 35 % 39 % 51 % 54 % 58;
}
TEST_XML(xpath_xalan_select_16, "<doc><a squish='light' squash='butternut'>1</a><a squeesh='' squish='extreme'>2</a><a squash='butternut' squeesh=''>3</a><a squish='heavy' squash='sport' squeesh=''>4</a></doc>")
{
CHECK_XPATH_NUMBER(doc, STR("count(doc/a/attribute::*)"), 9);
CHECK_XPATH_NUMBER(doc, STR("count(//@*)"), 9);
CHECK_XPATH_NUMBER(doc, STR("count(//@squish)"), 3);
}
TEST_XML(xpath_xalan_select_17, "<directions><north><dup1/><dup2/><south/><east/><west/></north><north1/><north2><dup1/><dup2/><dup3/><dup4/></north2><north3><dup1/><dup2/><south-north/><east-north/><west-north/></north3><south/><east><dup1/><dup2/><north-east/><south-east/><west-east/></east><west/></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/dup2 | north/dup1 | north/*")) % 4 % 5 % 6 % 7 % 8;
CHECK_XPATH_NODESET(c, STR("//north/dup2 | south/preceding-sibling::*[4]/* | north/dup1 | north/*")) % 4 % 5 % 6 % 7 % 8;
CHECK_XPATH_NODESET(c, STR("north/dup2 | south/preceding-sibling::*[4]/* | north/*")) % 4 % 5 % 6 % 7 % 8;
}
TEST_XML(xpath_xalan_select_18, "<para><font color='red'>Hello</font><font color='green'>There</font><font color='blue'>World</font></para>")
{
CHECK_XPATH_NODESET(doc, STR("/para/font[@color='green']")) % 6;
CHECK_XPATH_NODESET(doc.child(STR("para")), STR("/para/font[@color='green']")) % 6;
CHECK_XPATH_NODESET(doc.child(STR("para")).last_child(), STR("/para/font[@color='green']")) % 6;
}
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)
{
CHECK_XPATH_NODESET(doc, STR("//*")) % 2 % 4 % 8 % 10 % 12 % 18;
CHECK_XPATH_NODESET(doc, STR("//node()")) % 2 % 3 % 4 % 5 % 6 % 7 % 8 % 9 % 10 % 11 % 12 % 13 % 14 % 15 % 16 % 17 % 18 % 19 % 20 % 21;
CHECK_XPATH_NODESET(doc, STR("//text()")) % 3 % 5 % 6 % 9 % 11 % 13 % 14 % 15 % 17 % 19 % 20;
CHECK_XPATH_NODESET(doc, STR("//comment()")) % 7 % 16;
CHECK_XPATH_NODESET(doc, STR("//processing-instruction()")) % 21;
}
TEST_XML(xpath_xalan_bugzilla_1, "<report><colData colId='F'>1</colData><colData colId='L'>5</colData><colData colId='F'>1</colData><colData colId='L'>5</colData><colData colId='L'>2</colData><colData colId='F'>2</colData><colData colId='L'>5</colData><colData colId='F'>2</colData></report>")
{
CHECK_XPATH_NODESET(doc, STR("/report/colData[@colId='F' and not(.=preceding::colData)]")) % 3;
}
TEST(xpath_xalan_error_boolean)
{
CHECK_XPATH_FAIL(STR("nt(true())"));
CHECK_XPATH_FAIL(STR("not(troo())"));
CHECK_XPATH_FAIL(STR("troo() and (2 = 2)"));
CHECK_XPATH_FAIL(STR("troo() or (2 = 2)"));
CHECK_XPATH_FAIL(STR("2 = troo()"));
CHECK_XPATH_FAIL(STR("boolean(troo())"));
CHECK_XPATH_FAIL(STR("true(doc)"));
CHECK_XPATH_FAIL(STR("false(doc)"));
CHECK_XPATH_FAIL(STR("not()"));
CHECK_XPATH_FAIL(STR("not(false(), doc)"));
CHECK_XPATH_FAIL(STR("boolean()"));
CHECK_XPATH_FAIL(STR("boolean(false(), doc)"));
CHECK_XPATH_FAIL(STR("lang()"));
CHECK_XPATH_FAIL(STR("lang('en','us')"));
}
TEST(xpath_xalan_error_conditional)
{
CHECK_XPATH_FAIL(STR(""));
CHECK_XPATH_FAIL(STR("@name='John' | @name='Joe'"));
CHECK_XPATH_FAIL(STR("\x95not(name(.)='')"));
}
TEST(xpath_xalan_error_match)
{
CHECK_XPATH_FAIL(STR("//"));
CHECK_XPATH_FAIL(STR("section1|"));
CHECK_XPATH_FAIL(STR("|section1"));
}
TEST(xpath_xalan_error_math)
{
CHECK_XPATH_FAIL(STR("6 quo 4"));
CHECK_XPATH_FAIL(STR("-troo()"));
CHECK_XPATH_FAIL(STR("number(troo())"));
CHECK_XPATH_FAIL(STR("5 * troo()"));
CHECK_XPATH_FAIL(STR("12 div troo()"));
CHECK_XPATH_FAIL(STR("number(8,doc)"));
CHECK_XPATH_FAIL(STR("sum(doc, 8)"));
CHECK_XPATH_FAIL(STR("sum()"));
CHECK_XPATH_FAIL(STR("floor(8,7)"));
CHECK_XPATH_FAIL(STR("floor()"));
CHECK_XPATH_FAIL(STR("ceiling(8,7)"));
CHECK_XPATH_FAIL(STR("ceiling()"));
CHECK_XPATH_FAIL(STR("round(8,7)"));
CHECK_XPATH_FAIL(STR("round()"));
}
TEST(xpath_xalan_error_namespace)
{
CHECK_XPATH_FAIL(STR("local-name(baz2:b,..)"));
CHECK_XPATH_FAIL(STR("namespace-uri(baz2:b,..)"));
CHECK_XPATH_FAIL(STR("name(a,b)"));
CHECK_XPATH_FAIL(STR(":foo"));
CHECK_XPATH_FAIL(STR("*:foo"));
}
TEST(xpath_xalan_error_position)
{
CHECK_XPATH_FAIL(STR("*[last(*,2)]"));
CHECK_XPATH_FAIL(STR("position(b)=1"));
CHECK_XPATH_FAIL(STR("count()"));
CHECK_XPATH_FAIL(STR("count(*,4)"));
CHECK_XPATH_FAIL(STR("position()=last(a)"));
}
TEST(xpath_xalan_error_select)
{
CHECK_XPATH_FAIL(STR(""));
CHECK_XPATH_FAIL(STR("count(troo())"));
CHECK_XPATH_FAIL(STR("c::sub"));
CHECK_XPATH_FAIL(STR("c()"));
CHECK_XPATH_FAIL(STR("(* - 4) foo 2"));
CHECK_XPATH_FAIL(STR("5 . + *"));
CHECK_XPATH_FAIL(STR("4/."));
CHECK_XPATH_FAIL(STR("true()/."));
CHECK_XPATH_FAIL(STR("item//[@type='x']"));
CHECK_XPATH_FAIL(STR("//"));
CHECK_XPATH_FAIL(STR("item//"));
CHECK_XPATH_FAIL(STR("count(//)"));
CHECK_XPATH_FAIL(STR("substring-after(//,'0')"));
CHECK_XPATH_FAIL(STR("//+17"));
CHECK_XPATH_FAIL(STR("//|subitem"));
CHECK_XPATH_FAIL(STR("..[near-north]"));
}
TEST(xpath_xalan_error_string)
{
CHECK_XPATH_FAIL(STR("string(troo())"));
CHECK_XPATH_FAIL(STR("string-length(troo())"));
CHECK_XPATH_FAIL(STR("normalize-space(a,'\t\r\n ab cd ')"));
CHECK_XPATH_FAIL(STR("contains('ENCYCLOPEDIA')"));
CHECK_XPATH_FAIL(STR("contains('ENCYCLOPEDIA','LOPE',doc)"));
CHECK_XPATH_FAIL(STR("starts-with('ENCYCLOPEDIA')"));
CHECK_XPATH_FAIL(STR("starts-with('ENCYCLOPEDIA','LOPE',doc)"));
CHECK_XPATH_FAIL(STR("substring-before('ENCYCLOPEDIA')"));
CHECK_XPATH_FAIL(STR("substring-before('ENCYCLOPEDIA','LOPE',doc)"));
CHECK_XPATH_FAIL(STR("substring-after('ENCYCLOPEDIA')"));
CHECK_XPATH_FAIL(STR("substring-after('ENCYCLOPEDIA','LOPE',doc)"));
CHECK_XPATH_FAIL(STR("substring('ENCYCLOPEDIA')"));
CHECK_XPATH_FAIL(STR("substring('ENCYCLOPEDIA',4,5,2)"));
CHECK_XPATH_FAIL(STR("concat('x')"));
CHECK_XPATH_FAIL(STR("string-length('ENCYCLOPEDIA','PEDI')"));
CHECK_XPATH_FAIL(STR("translate('bar','abc')"));
CHECK_XPATH_FAIL(STR("translate('bar','abc','ABC','output')"));
CHECK_XPATH_FAIL(STR("string(22,44)"));
CHECK_XPATH_FAIL(STR("concat(/*)"));
}
#endif
#ifndef PUGIXML_NO_XPATH
#include "test.hpp"
using namespace pugi;
TEST_XML(xpath_xalan_select_1, "<doc><a><b attr='test'/></a><c><d><e/></d></c></doc>")
{
CHECK_XPATH_STRING(doc, STR("/doc/a/b/@attr"), STR("test"));
}
TEST_XML(xpath_xalan_select_2, "<doc><do do='-do-'>do</do><re>re</re><mi mi1='-mi1-' mi2='mi2'>mi</mi><fa fa='-fa-'>fa<so so='-so-'>so<la>la<ti>ti</ti>do</la></so></fa><Gsharp so='so+'>G#</Gsharp><Aflat><natural><la>A</la></natural>Ab</Aflat><Bflat>Bb</Bflat><Csharp><natural>C</natural>C#<doublesharp>D</doublesharp></Csharp></doc>")
{
xml_node c = doc.child(STR("doc"));
// This should come out fasolatido:
CHECK_XPATH_NODESET(c, STR("fa")) % 12;
// This should come out doremifasolatido:
CHECK_XPATH_NODESET(c, STR("mi | do | fa | re")) % 3 % 6 % 8 % 12;
// This should come out do-do-remi-mi1-mi2fasolatido-fa--so-:
CHECK_XPATH_NODESET(c, STR("mi[@mi2='mi2'] | do | fa/so/@so | fa | mi/@* | re | fa/@fa | do/@do")) % 3 % 4 % 6 % 8 % 9 % 10 % 12 % 13 % 16;
// This should come out solatidoG#:
CHECK_XPATH_NODESET(c, STR(".//*[@so]")) % 15 % 23;
// This should come out relatidoABb:
CHECK_XPATH_NODESET(c, STR("*//la | //Bflat | re")) % 6 % 18 % 28 % 31;
// This should come out domitiACD:
CHECK_XPATH_NODESET(c, STR("fa/../mi | Aflat/natural/la | Csharp//* | /doc/do | *//ti")) % 3 % 8 % 20 % 28 % 34 % 37;
}
TEST_XML(xpath_xalan_select_3, "<doc><sub1><child1>preceding sibling number 1</child1><child2>current node</child2><child3>following sibling number 3</child3></sub1><sub2><c>cousin 1</c><c>cousin 2</c><child3>cousin 3</child3></sub2></doc>")
{
CHECK_XPATH_NODESET(doc.child(STR("doc")).child(STR("sub1")).child(STR("child2")), STR("preceding-sibling::child1|//child3")) % 4 % 8 % 15;
}
TEST_XML(xpath_xalan_select_4, "<doc><child>bad1<sub>bad2</sub></child><c>bad3<sub>bad4</sub></c><sub>OK<nogo>bad5</nogo></sub></doc>")
{
xml_node c = doc.child(STR("doc"));
CHECK_XPATH_NODESET(c, STR("child::sub")) % 11;
CHECK_XPATH_NODESET(c, STR("child ::sub")) % 11;
CHECK_XPATH_NODESET(c, STR("child:: sub")) % 11;
CHECK_XPATH_NODESET(c, STR("child :: sub")) % 11;
}
TEST_XML_FLAGS(xpath_xalan_select_5, "<doc>bad0<!-- Good --><comment>bad1<sub>bad2</sub></comment></doc>", parse_default | parse_comments)
{
xml_node c = doc.child(STR("doc"));
CHECK_XPATH_NODESET(c, STR("comment()")) % 4;
CHECK_XPATH_NODESET(c, STR("comment ()")) % 4;
CHECK_XPATH_NODESET(c, STR("comment ( ) ")) % 4;
CHECK_XPATH_NUMBER(c, STR("string-length()"), 12);
CHECK_XPATH_NUMBER(c, STR("string-length ()"), 12);
CHECK_XPATH_NUMBER(c, STR("string-length ( ) "), 12);
}
TEST_XML(xpath_xalan_select_6, "<div div='20' div-5='12'>9</div>")
{
xml_node c = doc.child(STR("div"));
CHECK_XPATH_NUMBER(doc, STR("div +3"), 12);
CHECK_XPATH_NUMBER(doc, STR("* +3"), 12);
CHECK_XPATH_NUMBER(c, STR("@div - 5"), 15);
CHECK_XPATH_NUMBER(c, STR("@div -5"), 15);
CHECK_XPATH_NUMBER(c, STR("@div-5"), 12);
CHECK_XPATH_NUMBER(c, STR("@*-5"), 15);
CHECK_XPATH_NUMBER(doc, STR("16-div"), 7);
CHECK_XPATH_NUMBER(doc, STR("25-*"), 16);
CHECK_XPATH_NUMBER(doc, STR("54 div*"), 6);
CHECK_XPATH_NUMBER(doc, STR("(* - 4) div 2"), 2.5);
CHECK_XPATH_NUMBER(doc, STR("' 6 ' div 2"), 3);
CHECK_XPATH_NUMBER(doc, STR("' 6 '*div"), 54);
CHECK_XPATH_NUMBER(doc, STR("5.*."), 45);
CHECK_XPATH_NUMBER(doc, STR("5.+."), 14);
}
TEST_XML(xpath_xalan_select_7, "<doc div='20'><div>9</div><attribute>8</attribute></doc>")
{
xml_node c = doc.child(STR("doc"));
CHECK_XPATH_NUMBER(c, STR("attribute :: div"), 20);
CHECK_XPATH_NUMBER(c, STR("attribute :: *"), 20);
CHECK_XPATH_NUMBER(c, STR("attribute*(div - 4)"), 40);
CHECK_XPATH_NUMBER(c, STR("(* - 4)**"), 45);
}
TEST_XML(xpath_xalan_select_8, "<doc><a>x<div>7</div></a><a>y<div>9</div></a><a>z<div>5</div></a></doc>")
{
CHECK_XPATH_NODESET(doc, STR("doc/a[div=9]")) % 7;
}
TEST_XML(xpath_xalan_select_9, "<doc><a s='v'><b>7</b><c>3</c></a><a s='w'><b>7</b><c>9</c></a><a s='x'><b>9</b><c>2</c></a><a s='y'><b>9</b><c>9</c></a><a s='z'><b>2</b><c>0</c></a></doc>")
{
CHECK_XPATH_NODESET(doc, STR("doc/a[*=9]")) % 9 % 15 % 21;
}
TEST_XML(xpath_xalan_select_10, "<doc><sub1><child1>child1</child1></sub1><sub2><child2>child2</child2></sub2><sub3><child3/></sub3></doc>")
{
CHECK_XPATH_NODESET(doc, STR("/doc/sub1/child1|/doc/sub2/child2")) % 4 % 7;
CHECK_XPATH_NODESET(doc.child(STR("doc")), STR("sub1/child1|/doc/sub2/child2")) % 4 % 7;
CHECK_XPATH_NODESET(doc.child(STR("doc")), STR("sub1/child1|sub2/child2")) % 4 % 7;
CHECK_XPATH_NODESET(doc, STR("//self::child1|//self::child2")) % 4 % 7;
CHECK_XPATH_NODESET(doc, STR("//child1|//child2")) % 4 % 7;
CHECK_XPATH_NODESET(doc, STR("//child1|//child2|//child3")) % 4 % 7 % 10;
}
TEST_XML(xpath_xalan_select_11, "<doc><sub1 pos='1'><child1>descendant number 1</child1></sub1><sub2 pos='2'><child1>descendant number 2</child1></sub2></doc>")
{
CHECK_XPATH_NODESET(doc, STR("//child1/ancestor::sub1|//child1/ancestor::sub2")) % 3 % 7;
}
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;
}
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>")
{
CHECK_XPATH_NODESET(doc, STR("doc/book/author[name/@real='no']|doc/book/author[name/@real='yes']")) % 4 % 20;
CHECK_XPATH_NODESET(doc, STR("doc/book/author[(name/@real='no' and position()=1)]|doc/book/author[(name/@real='yes' and position()=last())]")) % 4 % 20;
CHECK_XPATH_NODESET(doc, STR("doc/book/author[name='Mary Brady']|doc/book/author[name/@real='no']")) % 4 % 20;
CHECK_XPATH_NODESET(doc, STR("doc/book/author/name|doc/book/author/bibliography/author/name")) % 5 % 13 % 21 % 28;
CHECK_XPATH_NODESET(doc, STR("doc/book/author/name|doc/book/author/bibliography/author/chapters")) % 5 % 13 % 21 % 30;
CHECK_XPATH_NODESET(doc, STR("doc/book/author/name|doc/book/author/noElement")) % 5 % 13 % 21;
CHECK_XPATH_NODESET(doc, STR("//noChild1|//noChild2"));
}
TEST_XML(xpath_xalan_select_14, "<doc><sub1 pos='1'><child1>child number 1</child1></sub1><sub2 pos='2'><child2>child number 2</child2></sub2><sub3/></doc>")
{
xml_node c = doc.child(STR("doc"));
CHECK_XPATH_NODESET(c, STR("child::sub1|child::sub2")) % 3 % 7;
CHECK_XPATH_NODESET(c, STR("descendant::child1|descendant::child2")) % 5 % 9;
CHECK_XPATH_NODESET(c, STR("descendant-or-self::sub1|descendant-or-self::sub2")) % 3 % 7;
CHECK_XPATH_NODESET(c.child(STR("sub2")), STR("preceding-sibling::sub1|following-sibling::sub3")) % 3 % 11;
}
TEST_XML(xpath_xalan_select_15, "<doc><child>Selection of this child is an error.</child><child high='3'>Selection of this child is an error.</child><child wide='4'>Selection of this child is an error.</child><child wide='4' high='3'>Selection of this child is an error.</child><child wide='3'>E</child><child wide='3' high='3'>F</child><child wide='3' deep='3'>G</child><child wide='4' deep='2'>Selection of this child is an error.</child><child wide='4' deep='2' high='3'>Selection of this child is an error.</child><child wide='3' deep='2'>J</child><child wide='3' deep='3' high='3'>K</child><child deep='2'>Selection of this child is an error.</child><child deep='2' high='3'>Selection of this child is an error.</child><child deep='3'>N</child><child deep='3' high='3'>O</child><child wide='4' deep='3'>P</child></doc>")
{
xml_node c = doc.child(STR("doc"));
CHECK_XPATH_NODESET(c, STR("child[@wide='3']|child[@deep='3']")) % 15 % 18 % 22 % 35 % 39 % 51 % 54 % 58;
CHECK_XPATH_NODESET(c, STR("child[@deep='3']|child[@wide='3']")) % 15 % 18 % 22 % 35 % 39 % 51 % 54 % 58;
}
TEST_XML(xpath_xalan_select_16, "<doc><a squish='light' squash='butternut'>1</a><a squeesh='' squish='extreme'>2</a><a squash='butternut' squeesh=''>3</a><a squish='heavy' squash='sport' squeesh=''>4</a></doc>")
{
CHECK_XPATH_NUMBER(doc, STR("count(doc/a/attribute::*)"), 9);
CHECK_XPATH_NUMBER(doc, STR("count(//@*)"), 9);
CHECK_XPATH_NUMBER(doc, STR("count(//@squish)"), 3);
}
TEST_XML(xpath_xalan_select_17, "<directions><north><dup1/><dup2/><south/><east/><west/></north><north1/><north2><dup1/><dup2/><dup3/><dup4/></north2><north3><dup1/><dup2/><south-north/><east-north/><west-north/></north3><south/><east><dup1/><dup2/><north-east/><south-east/><west-east/></east><west/></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/dup2 | north/dup1 | north/*")) % 4 % 5 % 6 % 7 % 8;
CHECK_XPATH_NODESET(c, STR("//north/dup2 | south/preceding-sibling::*[4]/* | north/dup1 | north/*")) % 4 % 5 % 6 % 7 % 8;
CHECK_XPATH_NODESET(c, STR("north/dup2 | south/preceding-sibling::*[4]/* | north/*")) % 4 % 5 % 6 % 7 % 8;
}
TEST_XML(xpath_xalan_select_18, "<para><font color='red'>Hello</font><font color='green'>There</font><font color='blue'>World</font></para>")
{
CHECK_XPATH_NODESET(doc, STR("/para/font[@color='green']")) % 6;
CHECK_XPATH_NODESET(doc.child(STR("para")), STR("/para/font[@color='green']")) % 6;
CHECK_XPATH_NODESET(doc.child(STR("para")).last_child(), STR("/para/font[@color='green']")) % 6;
}
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)
{
CHECK_XPATH_NODESET(doc, STR("//*")) % 2 % 4 % 8 % 10 % 12 % 18;
CHECK_XPATH_NODESET(doc, STR("//node()")) % 2 % 3 % 4 % 5 % 6 % 7 % 8 % 9 % 10 % 11 % 12 % 13 % 14 % 15 % 16 % 17 % 18 % 19 % 20 % 21;
CHECK_XPATH_NODESET(doc, STR("//text()")) % 3 % 5 % 6 % 9 % 11 % 13 % 14 % 15 % 17 % 19 % 20;
CHECK_XPATH_NODESET(doc, STR("//comment()")) % 7 % 16;
CHECK_XPATH_NODESET(doc, STR("//processing-instruction()")) % 21;
}
TEST_XML(xpath_xalan_bugzilla_1, "<report><colData colId='F'>1</colData><colData colId='L'>5</colData><colData colId='F'>1</colData><colData colId='L'>5</colData><colData colId='L'>2</colData><colData colId='F'>2</colData><colData colId='L'>5</colData><colData colId='F'>2</colData></report>")
{
CHECK_XPATH_NODESET(doc, STR("/report/colData[@colId='F' and not(.=preceding::colData)]")) % 3;
}
TEST(xpath_xalan_error_boolean)
{
CHECK_XPATH_FAIL(STR("nt(true())"));
CHECK_XPATH_FAIL(STR("not(troo())"));
CHECK_XPATH_FAIL(STR("troo() and (2 = 2)"));
CHECK_XPATH_FAIL(STR("troo() or (2 = 2)"));
CHECK_XPATH_FAIL(STR("2 = troo()"));
CHECK_XPATH_FAIL(STR("boolean(troo())"));
CHECK_XPATH_FAIL(STR("true(doc)"));
CHECK_XPATH_FAIL(STR("false(doc)"));
CHECK_XPATH_FAIL(STR("not()"));
CHECK_XPATH_FAIL(STR("not(false(), doc)"));
CHECK_XPATH_FAIL(STR("boolean()"));
CHECK_XPATH_FAIL(STR("boolean(false(), doc)"));
CHECK_XPATH_FAIL(STR("lang()"));
CHECK_XPATH_FAIL(STR("lang('en','us')"));
}
TEST(xpath_xalan_error_conditional)
{
CHECK_XPATH_FAIL(STR(""));
CHECK_XPATH_FAIL(STR("@name='John' | @name='Joe'"));
CHECK_XPATH_FAIL(STR("\x95not(name(.)='')"));
}
TEST(xpath_xalan_error_match)
{
CHECK_XPATH_FAIL(STR("//"));
CHECK_XPATH_FAIL(STR("section1|"));
CHECK_XPATH_FAIL(STR("|section1"));
}
TEST(xpath_xalan_error_math)
{
CHECK_XPATH_FAIL(STR("6 quo 4"));
CHECK_XPATH_FAIL(STR("-troo()"));
CHECK_XPATH_FAIL(STR("number(troo())"));
CHECK_XPATH_FAIL(STR("5 * troo()"));
CHECK_XPATH_FAIL(STR("12 div troo()"));
CHECK_XPATH_FAIL(STR("number(8,doc)"));
CHECK_XPATH_FAIL(STR("sum(doc, 8)"));
CHECK_XPATH_FAIL(STR("sum()"));
CHECK_XPATH_FAIL(STR("floor(8,7)"));
CHECK_XPATH_FAIL(STR("floor()"));
CHECK_XPATH_FAIL(STR("ceiling(8,7)"));
CHECK_XPATH_FAIL(STR("ceiling()"));
CHECK_XPATH_FAIL(STR("round(8,7)"));
CHECK_XPATH_FAIL(STR("round()"));
}
TEST(xpath_xalan_error_namespace)
{
CHECK_XPATH_FAIL(STR("local-name(baz2:b,..)"));
CHECK_XPATH_FAIL(STR("namespace-uri(baz2:b,..)"));
CHECK_XPATH_FAIL(STR("name(a,b)"));
CHECK_XPATH_FAIL(STR(":foo"));
CHECK_XPATH_FAIL(STR("*:foo"));
}
TEST(xpath_xalan_error_position)
{
CHECK_XPATH_FAIL(STR("*[last(*,2)]"));
CHECK_XPATH_FAIL(STR("position(b)=1"));
CHECK_XPATH_FAIL(STR("count()"));
CHECK_XPATH_FAIL(STR("count(*,4)"));
CHECK_XPATH_FAIL(STR("position()=last(a)"));
}
TEST(xpath_xalan_error_select)
{
CHECK_XPATH_FAIL(STR(""));
CHECK_XPATH_FAIL(STR("count(troo())"));
CHECK_XPATH_FAIL(STR("c::sub"));
CHECK_XPATH_FAIL(STR("c()"));
CHECK_XPATH_FAIL(STR("(* - 4) foo 2"));
CHECK_XPATH_FAIL(STR("5 . + *"));
CHECK_XPATH_FAIL(STR("4/."));
CHECK_XPATH_FAIL(STR("true()/."));
CHECK_XPATH_FAIL(STR("item//[@type='x']"));
CHECK_XPATH_FAIL(STR("//"));
CHECK_XPATH_FAIL(STR("item//"));
CHECK_XPATH_FAIL(STR("count(//)"));
CHECK_XPATH_FAIL(STR("substring-after(//,'0')"));
CHECK_XPATH_FAIL(STR("//+17"));
CHECK_XPATH_FAIL(STR("//|subitem"));
CHECK_XPATH_FAIL(STR("..[near-north]"));
}
TEST(xpath_xalan_error_string)
{
CHECK_XPATH_FAIL(STR("string(troo())"));
CHECK_XPATH_FAIL(STR("string-length(troo())"));
CHECK_XPATH_FAIL(STR("normalize-space(a,'\t\r\n ab cd ')"));
CHECK_XPATH_FAIL(STR("contains('ENCYCLOPEDIA')"));
CHECK_XPATH_FAIL(STR("contains('ENCYCLOPEDIA','LOPE',doc)"));
CHECK_XPATH_FAIL(STR("starts-with('ENCYCLOPEDIA')"));
CHECK_XPATH_FAIL(STR("starts-with('ENCYCLOPEDIA','LOPE',doc)"));
CHECK_XPATH_FAIL(STR("substring-before('ENCYCLOPEDIA')"));
CHECK_XPATH_FAIL(STR("substring-before('ENCYCLOPEDIA','LOPE',doc)"));
CHECK_XPATH_FAIL(STR("substring-after('ENCYCLOPEDIA')"));
CHECK_XPATH_FAIL(STR("substring-after('ENCYCLOPEDIA','LOPE',doc)"));
CHECK_XPATH_FAIL(STR("substring('ENCYCLOPEDIA')"));
CHECK_XPATH_FAIL(STR("substring('ENCYCLOPEDIA',4,5,2)"));
CHECK_XPATH_FAIL(STR("concat('x')"));
CHECK_XPATH_FAIL(STR("string-length('ENCYCLOPEDIA','PEDI')"));
CHECK_XPATH_FAIL(STR("translate('bar','abc')"));
CHECK_XPATH_FAIL(STR("translate('bar','abc','ABC','output')"));
CHECK_XPATH_FAIL(STR("string(22,44)"));
CHECK_XPATH_FAIL(STR("concat(/*)"));
}
#endif

View File

@ -1,79 +1,79 @@
#include "writer_string.hpp"
#include "test.hpp"
static bool test_narrow(const std::string& result, const char* expected, size_t length)
{
// check result
if (result != std::string(expected, expected + length)) return false;
// check comparison operator (incorrect implementation can theoretically early-out on zero terminators...)
if (length > 0 && result == std::string(expected, expected + length - 1) + "?") return false;
return true;
}
void xml_writer_string::write(const void* data, size_t size)
{
contents.append(static_cast<const char*>(data), size);
}
std::string xml_writer_string::as_narrow() const
{
return contents;
}
std::basic_string<wchar_t> xml_writer_string::as_wide() const
{
CHECK(contents.size() % sizeof(wchar_t) == 0);
// round-trip pointer through void* to avoid pointer alignment warnings; contents data should be heap allocated => safe to cast
return std::basic_string<wchar_t>(static_cast<const wchar_t*>(static_cast<const void*>(contents.data())), contents.size() / sizeof(wchar_t));
}
std::basic_string<pugi::char_t> xml_writer_string::as_string() const
{
#ifdef PUGIXML_WCHAR_MODE // to avoid "condition is always true" warning in BCC
CHECK(contents.size() % sizeof(pugi::char_t) == 0);
#endif
// round-trip pointer through void* to avoid pointer alignment warnings; contents data should be heap allocated => safe to cast
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));
}
std::string save_narrow(const pugi::xml_document& doc, unsigned int flags, pugi::xml_encoding encoding)
{
xml_writer_string writer;
doc.save(writer, STR("\t"), flags, encoding);
return writer.as_narrow();
}
bool test_save_narrow(const pugi::xml_document& doc, unsigned int flags, pugi::xml_encoding encoding, const char* expected, size_t length)
{
return test_narrow(save_narrow(doc, flags, encoding), expected, length);
}
std::string write_narrow(pugi::xml_node node, unsigned int flags, pugi::xml_encoding encoding)
{
xml_writer_string writer;
node.print(writer, STR("\t"), flags, encoding);
return writer.as_narrow();
}
bool test_write_narrow(pugi::xml_node node, unsigned int flags, pugi::xml_encoding encoding, const char* expected, size_t length)
{
return test_narrow(write_narrow(node, flags, encoding), expected, length);
}
std::basic_string<wchar_t> write_wide(pugi::xml_node node, unsigned int flags, pugi::xml_encoding encoding)
{
xml_writer_string writer;
node.print(writer, STR("\t"), flags, encoding);
return writer.as_wide();
}
#include "writer_string.hpp"
#include "test.hpp"
static bool test_narrow(const std::string& result, const char* expected, size_t length)
{
// check result
if (result != std::string(expected, expected + length)) return false;
// check comparison operator (incorrect implementation can theoretically early-out on zero terminators...)
if (length > 0 && result == std::string(expected, expected + length - 1) + "?") return false;
return true;
}
void xml_writer_string::write(const void* data, size_t size)
{
contents.append(static_cast<const char*>(data), size);
}
std::string xml_writer_string::as_narrow() const
{
return contents;
}
std::basic_string<wchar_t> xml_writer_string::as_wide() const
{
CHECK(contents.size() % sizeof(wchar_t) == 0);
// round-trip pointer through void* to avoid pointer alignment warnings; contents data should be heap allocated => safe to cast
return std::basic_string<wchar_t>(static_cast<const wchar_t*>(static_cast<const void*>(contents.data())), contents.size() / sizeof(wchar_t));
}
std::basic_string<pugi::char_t> xml_writer_string::as_string() const
{
#ifdef PUGIXML_WCHAR_MODE // to avoid "condition is always true" warning in BCC
CHECK(contents.size() % sizeof(pugi::char_t) == 0);
#endif
// round-trip pointer through void* to avoid pointer alignment warnings; contents data should be heap allocated => safe to cast
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));
}
std::string save_narrow(const pugi::xml_document& doc, unsigned int flags, pugi::xml_encoding encoding)
{
xml_writer_string writer;
doc.save(writer, STR("\t"), flags, encoding);
return writer.as_narrow();
}
bool test_save_narrow(const pugi::xml_document& doc, unsigned int flags, pugi::xml_encoding encoding, const char* expected, size_t length)
{
return test_narrow(save_narrow(doc, flags, encoding), expected, length);
}
std::string write_narrow(pugi::xml_node node, unsigned int flags, pugi::xml_encoding encoding)
{
xml_writer_string writer;
node.print(writer, STR("\t"), flags, encoding);
return writer.as_narrow();
}
bool test_write_narrow(pugi::xml_node node, unsigned int flags, pugi::xml_encoding encoding, const char* expected, size_t length)
{
return test_narrow(write_narrow(node, flags, encoding), expected, length);
}
std::basic_string<wchar_t> write_wide(pugi::xml_node node, unsigned int flags, pugi::xml_encoding encoding)
{
xml_writer_string writer;
node.print(writer, STR("\t"), flags, encoding);
return writer.as_wide();
}

View File

@ -1,27 +1,27 @@
#ifndef HEADER_TEST_WRITER_STRING_HPP
#define HEADER_TEST_WRITER_STRING_HPP
#include "../src/pugixml.hpp"
#include <string>
struct xml_writer_string: public pugi::xml_writer
{
std::string contents;
virtual void write(const void* data, size_t size) PUGIXML_OVERRIDE;
std::string as_narrow() const;
std::basic_string<wchar_t> as_wide() const;
std::basic_string<pugi::char_t> as_string() const;
};
std::string save_narrow(const pugi::xml_document& doc, unsigned int flags, pugi::xml_encoding encoding);
bool test_save_narrow(const pugi::xml_document& doc, unsigned int flags, pugi::xml_encoding encoding, const char* expected, size_t length);
std::string write_narrow(pugi::xml_node node, unsigned int flags, pugi::xml_encoding encoding);
bool test_write_narrow(pugi::xml_node node, unsigned int flags, pugi::xml_encoding encoding, const char* expected, size_t length);
std::basic_string<wchar_t> write_wide(pugi::xml_node node, unsigned int flags, pugi::xml_encoding encoding);
#endif
#ifndef HEADER_TEST_WRITER_STRING_HPP
#define HEADER_TEST_WRITER_STRING_HPP
#include "../src/pugixml.hpp"
#include <string>
struct xml_writer_string: public pugi::xml_writer
{
std::string contents;
virtual void write(const void* data, size_t size) PUGIXML_OVERRIDE;
std::string as_narrow() const;
std::basic_string<wchar_t> as_wide() const;
std::basic_string<pugi::char_t> as_string() const;
};
std::string save_narrow(const pugi::xml_document& doc, unsigned int flags, pugi::xml_encoding encoding);
bool test_save_narrow(const pugi::xml_document& doc, unsigned int flags, pugi::xml_encoding encoding, const char* expected, size_t length);
std::string write_narrow(pugi::xml_node node, unsigned int flags, pugi::xml_encoding encoding);
bool test_write_narrow(pugi::xml_node node, unsigned int flags, pugi::xml_encoding encoding, const char* expected, size_t length);
std::basic_string<wchar_t> write_wide(pugi::xml_node node, unsigned int flags, pugi::xml_encoding encoding);
#endif