2.0.0-rc (#9)
Some checks failed
BlockStorage/repertory_osx/pipeline/head This commit looks good
BlockStorage/repertory_windows/pipeline/head This commit looks good
BlockStorage/repertory/pipeline/head There was a failure building this commit
BlockStorage/repertory_linux_builds/pipeline/head This commit looks good
BlockStorage/repertory_osx_builds/pipeline/head There was a failure building this commit

### Issues

* \#1 \[bug\] Unable to mount S3 due to 'item_not_found' exception
* \#2 Require bucket name for S3 mounts
* \#3 \[bug\] File size is not being updated in S3 mount
* \#4 Upgrade to libfuse-3.x.x
* \#5 Switch to renterd for Sia support
* \#6 Switch to cpp-httplib to further reduce dependencies
* \#7 Remove global_data and calculate used disk space per provider
* \#8 Switch to libcurl for S3 mount support

### Changes from v1.x.x

* Added read-only encrypt provider
  * Pass-through mount point that transparently encrypts source data using `XChaCha20-Poly1305`
* Added S3 encryption support via `XChaCha20-Poly1305`
* Added replay protection to remote mounts
* Added support base64 writes in remote FUSE
* Created static linked Linux binaries for `amd64` and `aarch64` using `musl-libc`
* Removed legacy Sia renter support
* Removed Skynet support
* Fixed multiple remote mount WinFSP API issues on \*NIX servers
* Implemented chunked read and write
  * Writes for non-cached files are performed in chunks of 8Mib
* Removed `repertory-ui` support
* Removed `FreeBSD` support
* Switched to `libsodium` over `CryptoPP`
* Switched to `XChaCha20-Poly1305` for remote mounts
* Updated `GoogleTest` to v1.14.0
* Updated `JSON for Modern C++` to v3.11.2
* Updated `OpenSSL` to v1.1.1w
* Updated `RocksDB` to v8.5.3
* Updated `WinFSP` to 2023
* Updated `boost` to v1.78.0
* Updated `cURL` to v8.3.0
* Updated `zlib` to v1.3
* Use `upload_manager` for all providers
  * Adds a delay to uploads to prevent excessive API calls
  * Supports re-upload after mount restart for incomplete uploads
  * NOTE: Uploads for all providers are full file (no resume support)
    * Multipart upload support is planned for S3

Reviewed-on: #9
This commit is contained in:
2023-10-29 06:55:59 +00:00
parent 3ff46723b8
commit f43c41f88a
839 changed files with 98214 additions and 92959 deletions

175
3rd_party/pugixml/tests/allocator.cpp vendored Normal file
View File

@ -0,0 +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);
}

10
3rd_party/pugixml/tests/allocator.hpp vendored Normal file
View File

@ -0,0 +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

View File

@ -0,0 +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"

View File

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1 @@
<?xml version="1.0" encoding="ISO-8859-1"?><EXAMPLE><!--This is a comment with special chars: <<3C><><EFBFBD>>--><ORDER version="1.0" xml:lang="de"><!--This is another comment with special chars: <<3C><><EFBFBD>>--><HEADER><X_ORDER_ID>0000053535</X_ORDER_ID><CUSTOMER_ID>1010</CUSTOMER_ID><NAME_1>M<EFBFBD>ller</NAME_1><NAME_2>J<EFBFBD>rg</NAME_2></HEADER><ENTRIES><ENTRY><ARTICLE>&lt;Test&gt;</ARTICLE><ENTRY_NO>10</ENTRY_NO></ENTRY><ENTRY><ARTICLE>&lt;Test 2&gt;</ARTICLE><ENTRY_NO>20</ENTRY_NO></ENTRY></ENTRIES><FOOTER><TEXT>This is a text.</TEXT></FOOTER></ORDER></EXAMPLE>

View File

@ -0,0 +1 @@
<?xml version="1.0" encoding="ISO-8859-1"?><EXAMPLE><!--This is a comment with special chars: <äöü>--><ORDER version="1.0" xml:lang="de"><!--This is another comment with special chars: <äöü>--><HEADER><X_ORDER_ID>0000053535</X_ORDER_ID><CUSTOMER_ID>1010</CUSTOMER_ID><NAME_1>Müller</NAME_1><NAME_2>Jörg</NAME_2></HEADER><ENTRIES><ENTRY><ARTICLE>&lt;Test&gt;</ARTICLE><ENTRY_NO>10</ENTRY_NO></ENTRY><ENTRY><ARTICLE>&lt;Test 2&gt;</ARTICLE><ENTRY_NO>20</ENTRY_NO></ENTRY></ENTRIES><FOOTER><TEXT>This is a text.</TEXT></FOOTER></ORDER></EXAMPLE>

View File

@ -0,0 +1,3 @@
<node1 />
<node2 />
<node3 />

View File

@ -0,0 +1 @@
<node/>

View File

@ -0,0 +1,19 @@
<?xml version="1.0"?>
<!DOCTYPE 週報 SYSTEM "weekly-utf-8.dtd">
<!-- 週報サンプル -->
<mesh name="mesh_root">
<!-- here is a mesh node -->
some text
<![CDATA[someothertext]]>
some more text
<node attr1="value1" attr2="value2" />
<node attr1="value2">
<汉语 名字="name" 价值="value">世界有很多语言𤭢</汉语>
<innernode/>
</node>
<氏名>
<氏>山田</氏>
<名>太郎</名>
</氏名>
<?include somedata?>
</mesh>

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,87 @@
<?xml version="1.0"?>
<!DOCTYPE 週報 SYSTEM "weekly-utf-8.dtd">
<!-- 週報サンプル -->
<週報>
<English name="name" value="value">The world has many languages</English>
<Russian name="название(имя)" value="ценность">Мир имеет много языков</Russian>
<Spanish name="el nombre" value="el valor">el mundo tiene muchos idiomas</Spanish>
<SimplifiedChinese name="名字" value="价值">世界有很多语言</SimplifiedChinese>
<Русский название="name" ценность="value">&lt;имеет&gt;</Русский>
<汉语 名字="name" 价值="value">世界有很多语言𤭢</汉语>
<Heavy>&quot;Mëtæl!&quot;</Heavy>
>Umlaut Element</ä>
<年月週>
<年度>1997</年度>
<月度>1</月度>
<週>1</週>
</年月週>
<氏名>
<氏>山田</氏>
<名>太郎</名>
</氏名>
<業務報告リスト>
<業務報告>
<業務名>XMLエディターの作成</業務名>
<業務コード>X3355-23</業務コード>
<工数管理>
<見積もり工数>1600</見積もり工数>
<実績工数>320</実績工数>
<当月見積もり工数>160</当月見積もり工数>
<当月実績工数>24</当月実績工数>
</工数管理>
<予定項目リスト>
<予定項目>
<P>XMLエディターの基本仕様の作成</P>
</予定項目>
</予定項目リスト>
<実施事項リスト>
<実施事項>
<P>XMLエディターの基本仕様の作成</P>
</実施事項>
<実施事項>
<P>競合他社製品の機能調査</P>
</実施事項>
</実施事項リスト>
<上長への要請事項リスト>
<上長への要請事項>
<P>特になし</P>
</上長への要請事項>
</上長への要請事項リスト>
<問題点対策>
<P>XMLとは何かわからない。</P>
</問題点対策>
</業務報告>
<業務報告>
<業務名>検索エンジンの開発</業務名>
<業務コード>S8821-76</業務コード>
<工数管理>
<見積もり工数>120</見積もり工数>
<実績工数>6</実績工数>
<当月見積もり工数>32</当月見積もり工数>
<当月実績工数>2</当月実績工数>
</工数管理>
<予定項目リスト>
<予定項目>
<P><A href="http://www.goo.ne.jp">goo</A>の機能を調べてみる</P>
</予定項目>
</予定項目リスト>
<実施事項リスト>
<実施事項>
<P>更に、どういう検索エンジンがあるか調査する</P>
</実施事項>
</実施事項リスト>
<上長への要請事項リスト>
<上長への要請事項>
<P>開発をするのはめんどうなので、Yahoo!を買収して下さい。</P>
</上長への要請事項>
</上長への要請事項リスト>
<問題点対策>
<P>検索エンジンで車を走らせることができない。(要調査)</P>
</問題点対策>
</業務報告>
</業務報告リスト>
</週報>

View File

@ -0,0 +1,87 @@
<?xml version="1.0"?>
<!DOCTYPE 週報 SYSTEM "weekly-utf-8.dtd">
<!-- 週報サンプル -->
<週報>
<English name="name" value="value">The world has many languages</English>
<Russian name="название(имя)" value="ценность">Мир имеет много языков</Russian>
<Spanish name="el nombre" value="el valor">el mundo tiene muchos idiomas</Spanish>
<SimplifiedChinese name="名字" value="价值">世界有很多语言</SimplifiedChinese>
<Русский название="name" ценность="value">&lt;имеет&gt;</Русский>
<汉语 名字="name" 价值="value">世界有很多语言𤭢</汉语>
<Heavy>&quot;Mëtæl!&quot;</Heavy>
>Umlaut Element</ä>
<年月週>
<年度>1997</年度>
<月度>1</月度>
<週>1</週>
</年月週>
<氏名>
<氏>山田</氏>
<名>太郎</名>
</氏名>
<業務報告リスト>
<業務報告>
<業務名>XMLエディターの作成</業務名>
<業務コード>X3355-23</業務コード>
<工数管理>
<見積もり工数>1600</見積もり工数>
<実績工数>320</実績工数>
<当月見積もり工数>160</当月見積もり工数>
<当月実績工数>24</当月実績工数>
</工数管理>
<予定項目リスト>
<予定項目>
<P>XMLエディターの基本仕様の作成</P>
</予定項目>
</予定項目リスト>
<実施事項リスト>
<実施事項>
<P>XMLエディターの基本仕様の作成</P>
</実施事項>
<実施事項>
<P>競合他社製品の機能調査</P>
</実施事項>
</実施事項リスト>
<上長への要請事項リスト>
<上長への要請事項>
<P>特になし</P>
</上長への要請事項>
</上長への要請事項リスト>
<問題点対策>
<P>XMLとは何かわからない。</P>
</問題点対策>
</業務報告>
<業務報告>
<業務名>検索エンジンの開発</業務名>
<業務コード>S8821-76</業務コード>
<工数管理>
<見積もり工数>120</見積もり工数>
<実績工数>6</実績工数>
<当月見積もり工数>32</当月見積もり工数>
<当月実績工数>2</当月実績工数>
</工数管理>
<予定項目リスト>
<予定項目>
<P><A href="http://www.goo.ne.jp">goo</A>の機能を調べてみる</P>
</予定項目>
</予定項目リスト>
<実施事項リスト>
<実施事項>
<P>更に、どういう検索エンジンがあるか調査する</P>
</実施事項>
</実施事項リスト>
<上長への要請事項リスト>
<上長への要請事項>
<P>開発をするのはめんどうなので、Yahoo!を買収して下さい。</P>
</上長への要請事項>
</上長への要請事項リスト>
<問題点対策>
<P>検索エンジンで車を走らせることができない。(要調査)</P>
</問題点対策>
</業務報告>
</業務報告リスト>
</週報>

View File

@ -0,0 +1,84 @@
<?xml version="1.0"?><!-- 週報サンプル --><週報>
<English name="name" value="value">The world has many languages</English>
<Russian name="название(имя)" value="ценность">Мир имеет много языков</Russian>
<Spanish name="el nombre" value="el valor">el mundo tiene muchos idiomas</Spanish>
<SimplifiedChinese name="名字" value="价值">世界有很多语言</SimplifiedChinese>
<Русский название="name" ценность="value">&lt;имеет&gt;</Русский>
<汉语 名字="name" 价值="value">世界有很多语言𤭢</汉语>
<Heavy>quot;Mëtæl!quot;</Heavy>
>Umlaut Element</ä>
<年月週>
<年度>1997</年度>
<月度>1</月度>
<週>1</週>
</年月週>
<氏名>
<氏>山田</氏>
<名>太郎</名>
</氏名>
<業務報告リスト>
<業務報告>
<業務名>XMLエディターの作成</業務名>
<業務コード>X3355-23</業務コード>
<工数管理>
<見積もり工数>1600</見積もり工数>
<実績工数>320</実績工数>
<当月見積もり工数>160</当月見積もり工数>
<当月実績工数>24</当月実績工数>
</工数管理>
<予定項目リスト>
<予定項目>
<P>XMLエディターの基本仕様の作成</P>
</予定項目>
</予定項目リスト>
<実施事項リスト>
<実施事項>
<P>XMLエディターの基本仕様の作成</P>
</実施事項>
<実施事項>
<P>競合他社製品の機能調査</P>
</実施事項>
</実施事項リスト>
<上長への要請事項リスト>
<上長への要請事項>
<P>特になし</P>
</上長への要請事項>
</上長への要請事項リスト>
<問題点対策>
<P>XMLとは何かわからない。</P>
</問題点対策>
</業務報告>
<業務報告>
<業務名>検索エンジンの開発</業務名>
<業務コード>S8821-76</業務コード>
<工数管理>
<見積もり工数>120</見積もり工数>
<実績工数>6</実績工数>
<当月見積もり工数>32</当月見積もり工数>
<当月実績工数>2</当月実績工数>
</工数管理>
<予定項目リスト>
<予定項目>
<P><A href="http://www.goo.ne.jp">goo</A>の機能を調べてみる</P>
</予定項目>
</予定項目リスト>
<実施事項リスト>
<実施事項>
<P>更に、どういう検索エンジンがあるか調査する</P>
</実施事項>
</実施事項リスト>
<上長への要請事項リスト>
<上長への要請事項>
<P>開発をするのはめんどうなので、Yahoo!を買収して下さい。</P>
</上長への要請事項>
</上長への要請事項リスト>
<問題点対策>
<P>検索エンジンで車を走らせることができない。(要調査)</P>
</問題点対策>
</業務報告>
</業務報告リスト>
</週報>

View File

@ -0,0 +1,86 @@
<!DOCTYPE 週報 SYSTEM "weekly-utf-8.dtd">
<!-- 週報サンプル -->
<週報>
<English name="name" value="value">The world has many languages</English>
<Russian name="название(имя)" value="ценность">Мир имеет много языков</Russian>
<Spanish name="el nombre" value="el valor">el mundo tiene muchos idiomas</Spanish>
<SimplifiedChinese name="名字" value="价值">世界有很多语言</SimplifiedChinese>
<Русский название="name" ценность="value">&lt;имеет&gt;</Русский>
<汉语 名字="name" 价值="value">世界有很多语言𤭢</汉语>
<Heavy>&quot;Mëtæl!&quot;</Heavy>
>Umlaut Element</ä>
<年月週>
<年度>1997</年度>
<月度>1</月度>
<週>1</週>
</年月週>
<氏名>
<氏>山田</氏>
<名>太郎</名>
</氏名>
<業務報告リスト>
<業務報告>
<業務名>XMLエディターの作成</業務名>
<業務コード>X3355-23</業務コード>
<工数管理>
<見積もり工数>1600</見積もり工数>
<実績工数>320</実績工数>
<当月見積もり工数>160</当月見積もり工数>
<当月実績工数>24</当月実績工数>
</工数管理>
<予定項目リスト>
<予定項目>
<P>XMLエディターの基本仕様の作成</P>
</予定項目>
</予定項目リスト>
<実施事項リスト>
<実施事項>
<P>XMLエディターの基本仕様の作成</P>
</実施事項>
<実施事項>
<P>競合他社製品の機能調査</P>
</実施事項>
</実施事項リスト>
<上長への要請事項リスト>
<上長への要請事項>
<P>特になし</P>
</上長への要請事項>
</上長への要請事項リスト>
<問題点対策>
<P>XMLとは何かわからない。</P>
</問題点対策>
</業務報告>
<業務報告>
<業務名>検索エンジンの開発</業務名>
<業務コード>S8821-76</業務コード>
<工数管理>
<見積もり工数>120</見積もり工数>
<実績工数>6</実績工数>
<当月見積もり工数>32</当月見積もり工数>
<当月実績工数>2</当月実績工数>
</工数管理>
<予定項目リスト>
<予定項目>
<P><A href="http://www.goo.ne.jp">goo</A>の機能を調べてみる</P>
</予定項目>
</予定項目リスト>
<実施事項リスト>
<実施事項>
<P>更に、どういう検索エンジンがあるか調査する</P>
</実施事項>
</実施事項リスト>
<上長への要請事項リスト>
<上長への要請事項>
<P>開発をするのはめんどうなので、Yahoo!を買収して下さい。</P>
</上長への要請事項>
</上長への要請事項リスト>
<問題点対策>
<P>検索エンジンで車を走らせることができない。(要調査)</P>
</問題点対策>
</業務報告>
</業務報告リスト>
</週報>

View File

@ -0,0 +1 @@
<node/>

View File

@ -0,0 +1 @@
<node attr="value" />

View File

@ -0,0 +1 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">

View File

@ -0,0 +1 @@
<?xml version='1.0'?>

View File

@ -0,0 +1 @@
<?xml version='1.0'?>

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1 @@
a/b/c

View File

@ -0,0 +1 @@
sum(nodes) + round(concat(//a[translate(@id, 'abc', '012')]))

View File

@ -0,0 +1 @@
1+2*3 div 4 mod 5-6

View File

@ -0,0 +1 @@
@*/ancestor::*/near-north/*[4]/@*/preceding::text()

View File

@ -0,0 +1 @@
library/nodes[@id=12]/element[@type='translate'][1]

14
3rd_party/pugixml/tests/fuzz_parse.cpp vendored Normal file
View File

@ -0,0 +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;
}

72
3rd_party/pugixml/tests/fuzz_parse.dict vendored Normal file
View File

@ -0,0 +1,72 @@
#
# AFL dictionary for XML
# ----------------------
#
# Several basic syntax elements and attributes, modeled on libxml2.
#
# Created by Michal Zalewski <lcamtuf@google.com>
#
attr_encoding=" encoding=\"1\""
attr_generic=" a=\"1\""
attr_href=" href=\"1\""
attr_standalone=" standalone=\"no\""
attr_version=" version=\"1\""
attr_xml_base=" xml:base=\"1\""
attr_xml_id=" xml:id=\"1\""
attr_xml_lang=" xml:lang=\"1\""
attr_xml_space=" xml:space=\"1\""
attr_xmlns=" xmlns=\"1\""
entity_builtin="&lt;"
entity_decimal="&#1;"
entity_external="&a;"
entity_hex="&#x1;"
string_any="ANY"
string_brackets="[]"
string_cdata="CDATA"
string_col_fallback=":fallback"
string_col_generic=":a"
string_col_include=":include"
string_dashes="--"
string_empty="EMPTY"
string_empty_dblquotes="\"\""
string_empty_quotes="''"
string_entities="ENTITIES"
string_entity="ENTITY"
string_fixed="#FIXED"
string_id="ID"
string_idref="IDREF"
string_idrefs="IDREFS"
string_implied="#IMPLIED"
string_nmtoken="NMTOKEN"
string_nmtokens="NMTOKENS"
string_notation="NOTATION"
string_parentheses="()"
string_pcdata="#PCDATA"
string_percent="%a"
string_public="PUBLIC"
string_required="#REQUIRED"
string_schema=":schema"
string_system="SYSTEM"
string_ucs4="UCS-4"
string_utf16="UTF-16"
string_utf8="UTF-8"
string_xmlns="xmlns:"
tag_attlist="<!ATTLIST"
tag_cdata="<![CDATA["
tag_close="</a>"
tag_doctype="<!DOCTYPE"
tag_element="<!ELEMENT"
tag_entity="<!ENTITY"
tag_ignore="<![IGNORE["
tag_include="<![INCLUDE["
tag_notation="<!NOTATION"
tag_open="<a>"
tag_open_close="<a />"
tag_open_exclamation="<!"
tag_open_q="<?"
tag_sq2_close="]]>"
tag_xml_q="<?xml?>"

11
3rd_party/pugixml/tests/fuzz_setup.sh vendored Executable file
View File

@ -0,0 +1,11 @@
#!/bin/bash
sudo apt-get --yes install subversion screen gcc g++ cmake ninja-build golang autoconf libtool apache2 python-dev pkg-config zlib1g-dev libgcrypt11-dev
mkdir -p clang
cd clang
git clone https://chromium.googlesource.com/chromium/src/tools/clang
cd ..
clang/clang/scripts/update.py
sudo cp -rf third_party/llvm-build/Release+Asserts/lib/* /usr/local/lib/
sudo cp -rf third_party/llvm-build/Release+Asserts/bin/* /usr/local/bin

26
3rd_party/pugixml/tests/fuzz_xpath.cpp vendored Normal file
View File

@ -0,0 +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;
}

72
3rd_party/pugixml/tests/fuzz_xpath.dict vendored Normal file
View File

@ -0,0 +1,72 @@
"boolean"
"count"
"contains"
"concat"
"ceiling"
"false"
"floor"
"id"
"last"
"lang"
"local-name"
"name"
"namespace-uri"
"normalize-space"
"not"
"number"
"position"
"round"
"string"
"string-length"
"starts-with"
"substring-before"
"substring-after"
"substring"
"sum"
"translate"
"true"
"ancestor"
"ancestor-or-self"
"attribute"
"child"
"descendant"
"descendant-or-self"
"following"
"following-sibling"
"namespace"
"parent"
"preceding"
"preceding-sibling"
"self"
"comment"
"node"
"processing-instruction"
"text"
"or"
"and"
"div"
"mod"
">"
">="
"<"
"<="
"!"
"!="
"="
"+"
"-"
"*"
"|"
"$"
"("
")"
"["
"]"
","
"//"
"/"
".."
"."
"@"
"::"
":"

114
3rd_party/pugixml/tests/helpers.hpp vendored Normal file
View File

@ -0,0 +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

218
3rd_party/pugixml/tests/main.cpp vendored Normal file
View File

@ -0,0 +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

220
3rd_party/pugixml/tests/test.cpp vendored Normal file
View File

@ -0,0 +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
}

175
3rd_party/pugixml/tests/test.hpp vendored Normal file
View File

@ -0,0 +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

150
3rd_party/pugixml/tests/test_compact.cpp vendored Normal file
View File

@ -0,0 +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

View File

@ -0,0 +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

1860
3rd_party/pugixml/tests/test_document.cpp vendored Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +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
}

File diff suppressed because it is too large Load Diff

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -0,0 +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
}

View File

@ -0,0 +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
}

View File

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

View File

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

View File

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

303
3rd_party/pugixml/tests/test_memory.cpp vendored Normal file
View File

@ -0,0 +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");
}

1357
3rd_party/pugixml/tests/test_parse.cpp vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +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));
}

153
3rd_party/pugixml/tests/test_unicode.cpp vendored Normal file
View File

@ -0,0 +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

View File

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

733
3rd_party/pugixml/tests/test_write.cpp vendored Normal file
View File

@ -0,0 +1,733 @@
#include "test.hpp"
#include "writer_string.hpp"
#include <string>
#include <sstream>
#include <stdexcept>
using namespace pugi;
TEST_XML(write_simple, "<node attr='1'><child>text</child></node>")
{
CHECK_NODE_EX(doc, STR("<node attr=\"1\">\n<child>text</child>\n</node>\n"), STR(""), 0);
}
TEST_XML(write_raw, "<node attr='1'><child>text</child></node>")
{
CHECK_NODE_EX(doc, STR("<node attr=\"1\"><child>text</child></node>"), STR(""), format_raw);
}
TEST_XML(write_indent, "<node attr='1'><child><sub>text</sub></child></node>")
{
CHECK_NODE_EX(doc, STR("<node attr=\"1\">\n\t<child>\n\t\t<sub>text</sub>\n\t</child>\n</node>\n"), STR("\t"), format_indent);
}
TEST_XML(write_indent_attributes, "<node attr='1' other='2'><child><sub>text</sub></child></node>")
{
CHECK_NODE_EX(doc, STR("<node\n\tattr=\"1\"\n\tother=\"2\">\n\t<child>\n\t\t<sub>text</sub>\n\t</child>\n</node>\n"), STR("\t"), format_indent_attributes);
}
TEST_XML(write_indent_attributes_empty_element, "<node attr='1' other='2' />")
{
CHECK_NODE_EX(doc, STR("<node\n\tattr=\"1\"\n\tother=\"2\" />\n"), STR("\t"), format_indent_attributes);
}
TEST_XML_FLAGS(write_indent_attributes_declaration, "<?xml version=\"1.0\" encoding=\"UTF-8\"?><node attr='1' other='2' />", parse_full)
{
CHECK_NODE_EX(doc, STR("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<node\n\tattr=\"1\"\n\tother=\"2\" />\n"), STR("\t"), format_indent_attributes);
}
TEST_XML(write_indent_attributes_raw, "<node attr='1' other='2'><child><sub>text</sub></child></node>")
{
CHECK_NODE_EX(doc, STR("<node attr=\"1\" other=\"2\"><child><sub>text</sub></child></node>"), STR("\t"), format_indent_attributes | format_raw);
}
TEST_XML(write_indent_attributes_empty_indent, "<node attr='1' other='2'><child><sub>text</sub></child></node>")
{
CHECK_NODE_EX(doc, STR("<node\nattr=\"1\"\nother=\"2\">\n<child>\n<sub>text</sub>\n</child>\n</node>\n"), STR(""), format_indent_attributes);
}
TEST_XML(write_pcdata, "<node attr='1'><child><sub/>text</child></node>")
{
CHECK_NODE_EX(doc, STR("<node attr=\"1\">\n\t<child>\n\t\t<sub />text</child>\n</node>\n"), STR("\t"), format_indent);
}
TEST_XML_FLAGS(write_cdata, "<![CDATA[value]]>", parse_cdata | parse_fragment)
{
CHECK_NODE(doc, STR("<![CDATA[value]]>"));
CHECK_NODE_EX(doc, STR("<![CDATA[value]]>"), STR(""), 0);
}
TEST_XML_FLAGS(write_cdata_empty, "<![CDATA[]]>", parse_cdata | parse_fragment)
{
CHECK_NODE(doc, STR("<![CDATA[]]>"));
CHECK_NODE_EX(doc, STR("<![CDATA[]]>"), STR(""), 0);
}
TEST_XML_FLAGS(write_cdata_escape, "<![CDATA[value]]>", parse_cdata | parse_fragment)
{
CHECK_NODE(doc, STR("<![CDATA[value]]>"));
doc.first_child().set_value(STR("1]]>2]]>3"));
CHECK_NODE(doc, STR("<![CDATA[1]]]]><![CDATA[>2]]]]><![CDATA[>3]]>"));
doc.first_child().set_value(STR("1]"));
CHECK_NODE(doc, STR("<![CDATA[1]]]>"));
doc.first_child().set_value(STR("1]]"));
CHECK_NODE(doc, STR("<![CDATA[1]]]]>"));
}
TEST_XML(write_cdata_inner, "<node><![CDATA[value]]></node>")
{
CHECK_NODE(doc, STR("<node><![CDATA[value]]></node>"));
CHECK_NODE_EX(doc, STR("<node><![CDATA[value]]></node>\n"), STR(""), 0);
}
TEST(write_cdata_null)
{
xml_document doc;
doc.append_child(node_cdata);
doc.append_child(STR("node")).append_child(node_cdata);
CHECK_NODE(doc, STR("<![CDATA[]]><node><![CDATA[]]></node>"));
}
TEST_XML_FLAGS(write_comment, "<!--text-->", parse_comments | parse_fragment)
{
CHECK_NODE(doc, STR("<!--text-->"));
CHECK_NODE_EX(doc, STR("<!--text-->\n"), STR(""), 0);
}
TEST(write_comment_invalid)
{
xml_document doc;
xml_node child = doc.append_child(node_comment);
CHECK_NODE(doc, STR("<!---->"));
child.set_value(STR("-"));
CHECK_NODE(doc, STR("<!--- -->"));
child.set_value(STR("--"));
CHECK_NODE(doc, STR("<!--- - -->"));
child.set_value(STR("---"));
CHECK_NODE(doc, STR("<!--- - - -->"));
child.set_value(STR("-->"));
CHECK_NODE(doc, STR("<!--- ->-->"));
child.set_value(STR("-->-"));
CHECK_NODE(doc, STR("<!--- ->- -->"));
}
TEST(write_comment_null)
{
xml_document doc;
doc.append_child(node_comment);
CHECK_NODE(doc, STR("<!---->"));
}
TEST_XML_FLAGS(write_pi, "<?name value?>", parse_pi | parse_fragment)
{
CHECK_NODE(doc, STR("<?name value?>"));
CHECK_NODE_EX(doc, STR("<?name value?>\n"), STR(""), 0);
}
TEST(write_pi_null)
{
xml_document doc;
xml_node node = doc.append_child(node_pi);
CHECK_NODE(doc, STR("<?:anonymous?>"));
node.set_value(STR("value"));
CHECK_NODE(doc, STR("<?:anonymous value?>"));
}
TEST(write_pi_invalid)
{
xml_document doc;
xml_node node = doc.append_child(node_pi);
node.set_name(STR("test"));
node.set_value(STR("?"));
CHECK_NODE(doc, STR("<?test ?") STR("?>"));
node.set_value(STR("?>"));
CHECK_NODE(doc, STR("<?test ? >?>"));
node.set_value(STR("<?foo?>"));
CHECK_NODE(doc, STR("<?test <?foo? >?>"));
}
TEST_XML_FLAGS(write_declaration, "<?xml version='2.0'?>", parse_declaration | parse_fragment)
{
CHECK_NODE(doc, STR("<?xml version=\"2.0\"?>"));
CHECK_NODE_EX(doc, STR("<?xml version=\"2.0\"?>\n"), STR(""), 0);
}
TEST_XML_FLAGS(write_doctype, "<!DOCTYPE id [ foo ]>", parse_doctype | parse_fragment)
{
CHECK_NODE(doc, STR("<!DOCTYPE id [ foo ]>"));
CHECK_NODE_EX(doc, STR("<!DOCTYPE id [ foo ]>\n"), STR(""), 0);
}
TEST(write_doctype_null)
{
xml_document doc;
doc.append_child(node_doctype);
CHECK_NODE(doc, STR("<!DOCTYPE>"));
}
TEST_XML(write_escape, "<node attr=''>text</node>")
{
doc.child(STR("node")).attribute(STR("attr")) = STR("<>'\"&\x04\r\n\t");
doc.child(STR("node")).first_child().set_value(STR("<>'\"&\x04\r\n\t"));
CHECK_NODE(doc, STR("<node attr=\"&lt;>'&quot;&amp;&#04;&#13;&#10;&#09;\">&lt;&gt;'\"&amp;&#04;\r\n\t</node>"));
CHECK_NODE_EX(doc, STR("<node attr='&lt;>&apos;\"&amp;&#04;&#13;&#10;&#09;'>&lt;&gt;'\"&amp;&#04;\r\n\t</node>"), STR(""), format_raw | format_attribute_single_quote);
}
TEST_XML(write_escape_roundtrip, "<node attr=''>text</node>")
{
doc.child(STR("node")).attribute(STR("attr")) = STR("<>'\"&\x04\r\n\t");
doc.child(STR("node")).first_child().set_value(STR("<>'\"&\x04\r\n\t"));
std::string contents = write_narrow(doc, format_raw, encoding_utf8);
CHECK(doc.load_buffer(contents.c_str(), contents.size()));
// Note: this string is almost identical to the string from write_escape with the exception of \r
// \r in PCDATA doesn't roundtrip because it has to go through newline conversion (which could be disabled, but is active by default)
CHECK_NODE(doc, STR("<node attr=\"&lt;>'&quot;&amp;&#04;&#13;&#10;&#09;\">&lt;&gt;'\"&amp;&#04;\n\t</node>"));
CHECK_NODE_EX(doc, STR("<node attr='&lt;>&apos;\"&amp;&#04;&#13;&#10;&#09;'>&lt;&gt;'\"&amp;&#04;\n\t</node>"), STR(""), format_raw | format_attribute_single_quote);
}
TEST_XML(write_escape_unicode, "<node attr='&#x3c00;'/>")
{
#ifdef PUGIXML_WCHAR_MODE
#ifdef U_LITERALS
CHECK_NODE(doc, STR("<node attr=\"\u3c00\"/>"));
#else
CHECK_NODE(doc, STR("<node attr=\"\x3c00\"/>"));
#endif
#else
CHECK_NODE(doc, STR("<node attr=\"\xe3\xb0\x80\"/>"));
#endif
}
TEST_XML(write_no_escapes, "<node attr=''>text</node>")
{
doc.child(STR("node")).attribute(STR("attr")) = STR("<>'\"&\x04\r\n\t");
doc.child(STR("node")).first_child().set_value(STR("<>'\"&\x04\r\n\t"));
CHECK_NODE_EX(doc, STR("<node attr=\"<>'\"&\x04\r\n\t\"><>'\"&\x04\r\n\t</node>"), STR(""), format_raw | format_no_escapes);
}
struct test_writer: xml_writer
{
std::basic_string<char_t> contents;
virtual void write(const void* data, size_t size) PUGIXML_OVERRIDE
{
CHECK(size % sizeof(char_t) == 0);
contents.append(static_cast<const char_t*>(data), size / sizeof(char_t));
}
};
TEST_XML(write_print_writer, "<node/>")
{
test_writer writer;
doc.print(writer, STR(""), format_default, get_native_encoding());
CHECK(writer.contents == STR("<node />\n"));
}
#ifndef PUGIXML_NO_STL
TEST_XML(write_print_stream, "<node/>")
{
std::ostringstream oss;
doc.print(oss, STR(""), format_default, encoding_utf8);
CHECK(oss.str() == "<node />\n");
}
TEST_XML(write_print_stream_encode, "<n/>")
{
std::ostringstream oss;
doc.print(oss, STR(""), format_default, encoding_utf16_be);
CHECK(oss.str() == std::string("\x00<\x00n\x00 \x00/\x00>\x00\n", 12));
}
TEST_XML(write_print_stream_wide, "<node/>")
{
std::basic_ostringstream<wchar_t> oss;
doc.print(oss, STR(""), format_default, encoding_utf8);
CHECK(oss.str() == L"<node />\n");
}
#endif
TEST_XML(write_huge_chunk, "<node/>")
{
std::basic_string<char_t> name(10000, STR('n'));
doc.child(STR("node")).set_name(name.c_str());
test_writer writer;
doc.print(writer, STR(""), format_default, get_native_encoding());
CHECK(writer.contents == STR("<") + name + STR(" />\n"));
}
TEST(write_encodings)
{
static char s_utf8[] = "<\x54\xC2\xA2\xE2\x82\xAC\xF0\xA4\xAD\xA2/>";
xml_document doc;
CHECK(doc.load_buffer(s_utf8, sizeof(s_utf8), parse_default, encoding_utf8));
CHECK(write_narrow(doc, format_default, encoding_utf8) == "<\x54\xC2\xA2\xE2\x82\xAC\xF0\xA4\xAD\xA2 />\n");
CHECK(test_write_narrow(doc, format_default, encoding_utf32_le, "<\x00\x00\x00\x54\x00\x00\x00\xA2\x00\x00\x00\xAC\x20\x00\x00\x62\x4B\x02\x00 \x00\x00\x00/\x00\x00\x00>\x00\x00\x00\n\x00\x00\x00", 36));
CHECK(test_write_narrow(doc, format_default, encoding_utf32_be, "\x00\x00\x00<\x00\x00\x00\x54\x00\x00\x00\xA2\x00\x00\x20\xAC\x00\x02\x4B\x62\x00\x00\x00 \x00\x00\x00/\x00\x00\x00>\x00\x00\x00\n", 36));
CHECK(write_narrow(doc, format_default, encoding_utf32) == write_narrow(doc, format_default, is_little_endian() ? encoding_utf32_le : encoding_utf32_be));
CHECK(test_write_narrow(doc, format_default, encoding_utf16_le, "<\x00\x54\x00\xA2\x00\xAC\x20\x52\xd8\x62\xdf \x00/\x00>\x00\n\x00", 20));
CHECK(test_write_narrow(doc, format_default, encoding_utf16_be, "\x00<\x00\x54\x00\xA2\x20\xAC\xd8\x52\xdf\x62\x00 \x00/\x00>\x00\n", 20));
CHECK(write_narrow(doc, format_default, encoding_utf16) == write_narrow(doc, format_default, is_little_endian() ? encoding_utf16_le : encoding_utf16_be));
size_t wcharsize = sizeof(wchar_t);
std::basic_string<wchar_t> v = write_wide(doc, format_default, encoding_wchar);
if (wcharsize == 4)
{
CHECK(v.size() == 9 && v[0] == '<' && v[1] == 0x54 && v[2] == 0xA2 && v[3] == 0x20AC && v[4] == wchar_cast(0x24B62) && v[5] == ' ' && v[6] == '/' && v[7] == '>' && v[8] == '\n');
}
else
{
CHECK(v.size() == 10 && v[0] == '<' && v[1] == 0x54 && v[2] == 0xA2 && v[3] == 0x20AC && v[4] == wchar_cast(0xd852) && v[5] == wchar_cast(0xdf62) && v[6] == ' ' && v[7] == '/' && v[8] == '>' && v[9] == '\n');
}
CHECK(test_write_narrow(doc, format_default, encoding_latin1, "<\x54\xA2?? />\n", 9));
}
#ifdef PUGIXML_WCHAR_MODE
TEST(write_encoding_huge)
{
const unsigned int N = 16000;
// make a large utf16 name consisting of 6-byte char pairs (6 does not divide internal buffer size, so will need split correction)
std::string s_utf16 = std::string("\x00<", 2);
for (unsigned int i = 0; i < N; ++i) s_utf16 += "\x20\xAC\xd8\x52\xdf\x62";
s_utf16 += std::string("\x00/\x00>", 4);
xml_document doc;
CHECK(doc.load_buffer(&s_utf16[0], s_utf16.length(), parse_default, encoding_utf16_be));
std::string s_utf8 = "<";
for (unsigned int j = 0; j < N; ++j) s_utf8 += "\xE2\x82\xAC\xF0\xA4\xAD\xA2";
s_utf8 += " />\n";
CHECK(test_write_narrow(doc, format_default, encoding_utf8, s_utf8.c_str(), s_utf8.length()));
}
TEST(write_encoding_huge_invalid)
{
size_t wcharsize = sizeof(wchar_t);
if (wcharsize == 2)
{
const unsigned int N = 16000;
// make a large utf16 name consisting of leading surrogate chars
std::basic_string<wchar_t> s_utf16;
for (unsigned int i = 0; i < N; ++i) s_utf16 += static_cast<wchar_t>(0xd852);
xml_document doc;
doc.append_child().set_name(s_utf16.c_str());
CHECK(test_write_narrow(doc, format_default, encoding_utf8, "< />\n", 5));
}
}
#else
TEST(write_encoding_huge)
{
const unsigned int N = 16000;
// make a large utf8 name consisting of 3-byte chars (3 does not divide internal buffer size, so will need split correction)
std::string s_utf8 = "<";
for (unsigned int i = 0; i < N; ++i) s_utf8 += "\xE2\x82\xAC";
s_utf8 += "/>";
xml_document doc;
CHECK(doc.load_buffer(&s_utf8[0], s_utf8.length(), parse_default, encoding_utf8));
std::string s_utf16 = std::string("\x00<", 2);
for (unsigned int j = 0; j < N; ++j) s_utf16 += "\x20\xAC";
s_utf16 += std::string("\x00 \x00/\x00>\x00\n", 8);
CHECK(test_write_narrow(doc, format_default, encoding_utf16_be, s_utf16.c_str(), s_utf16.length()));
}
TEST(write_encoding_huge_invalid)
{
const unsigned int N = 16000;
// make a large utf8 name consisting of non-leading chars
std::string s_utf8;
for (unsigned int i = 0; i < N; ++i) s_utf8 += "\x82";
xml_document doc;
doc.append_child().set_name(s_utf8.c_str());
std::string s_utf16 = std::string("\x00<\x00 \x00/\x00>\x00\n", 10);
CHECK(test_write_narrow(doc, format_default, encoding_utf16_be, s_utf16.c_str(), s_utf16.length()));
}
#endif
TEST(write_unicode_escape)
{
char s_utf8[] = "<\xE2\x82\xAC \xC2\xA2='\"\xF0\xA4\xAD\xA2&#x0a;\"'>&amp;\x14\xF0\xA4\xAD\xA2&lt;</\xE2\x82\xAC>";
xml_document doc;
CHECK(doc.load_buffer(s_utf8, sizeof(s_utf8), parse_default, encoding_utf8));
CHECK(write_narrow(doc, format_default, encoding_utf8) == "<\xE2\x82\xAC \xC2\xA2=\"&quot;\xF0\xA4\xAD\xA2&#10;&quot;\">&amp;&#20;\xF0\xA4\xAD\xA2&lt;</\xE2\x82\xAC>\n");
}
#ifdef PUGIXML_WCHAR_MODE
static bool test_write_unicode_invalid(const wchar_t* name, const char* expected)
{
xml_document doc;
doc.append_child(node_pcdata).set_value(name);
return write_narrow(doc, format_raw, encoding_utf8) == expected;
}
TEST(write_unicode_invalid_utf16)
{
size_t wcharsize = sizeof(wchar_t);
if (wcharsize == 2)
{
// check non-terminated degenerate handling
#ifdef U_LITERALS
CHECK(test_write_unicode_invalid(L"a\uda1d", "a"));
CHECK(test_write_unicode_invalid(L"a\uda1d_", "a_"));
#else
CHECK(test_write_unicode_invalid(L"a\xda1d", "a"));
CHECK(test_write_unicode_invalid(L"a\xda1d_", "a_"));
#endif
// check incorrect leading code
#ifdef U_LITERALS
CHECK(test_write_unicode_invalid(L"a\ude24", "a"));
CHECK(test_write_unicode_invalid(L"a\ude24_", "a_"));
#else
CHECK(test_write_unicode_invalid(L"a\xde24", "a"));
CHECK(test_write_unicode_invalid(L"a\xde24_", "a_"));
#endif
}
}
#else
static bool test_write_unicode_invalid(const char* name, const wchar_t* expected)
{
xml_document doc;
doc.append_child(node_pcdata).set_value(name);
return write_wide(doc, format_raw, encoding_wchar) == expected;
}
TEST(write_unicode_invalid_utf8)
{
// invalid 1-byte input
CHECK(test_write_unicode_invalid("a\xb0", L"a"));
CHECK(test_write_unicode_invalid("a\xb0_", L"a_"));
// invalid 2-byte input
CHECK(test_write_unicode_invalid("a\xc0", L"a"));
CHECK(test_write_unicode_invalid("a\xd0", L"a"));
CHECK(test_write_unicode_invalid("a\xc0_", L"a_"));
CHECK(test_write_unicode_invalid("a\xd0_", L"a_"));
// invalid 3-byte input
CHECK(test_write_unicode_invalid("a\xe2\x80", L"a"));
CHECK(test_write_unicode_invalid("a\xe2", L"a"));
CHECK(test_write_unicode_invalid("a\xe2\x80_", L"a_"));
CHECK(test_write_unicode_invalid("a\xe2_", L"a_"));
// invalid 4-byte input
CHECK(test_write_unicode_invalid("a\xf2\x97\x98", L"a"));
CHECK(test_write_unicode_invalid("a\xf2\x97", L"a"));
CHECK(test_write_unicode_invalid("a\xf2", L"a"));
CHECK(test_write_unicode_invalid("a\xf2\x97\x98_", L"a_"));
CHECK(test_write_unicode_invalid("a\xf2\x97_", L"a_"));
CHECK(test_write_unicode_invalid("a\xf2_", L"a_"));
// invalid 5-byte input
CHECK(test_write_unicode_invalid("a\xf8_", L"a_"));
}
#endif
TEST(write_no_name_element)
{
xml_document doc;
xml_node root = doc.append_child();
root.append_child();
root.append_child().append_child(node_pcdata).set_value(STR("text"));
CHECK_NODE(doc, STR("<:anonymous><:anonymous/><:anonymous>text</:anonymous></:anonymous>"));
CHECK_NODE_EX(doc, STR("<:anonymous>\n\t<:anonymous />\n\t<:anonymous>text</:anonymous>\n</:anonymous>\n"), STR("\t"), format_default);
}
TEST(write_no_name_pi)
{
xml_document doc;
doc.append_child(node_pi);
CHECK_NODE(doc, STR("<?:anonymous?>"));
}
TEST(write_no_name_attribute)
{
xml_document doc;
doc.append_child().set_name(STR("root"));
doc.child(STR("root")).append_attribute(STR(""));
CHECK_NODE(doc, STR("<root :anonymous=\"\"/>"));
}
TEST(write_print_empty)
{
test_writer writer;
xml_node().print(writer);
}
#ifndef PUGIXML_NO_STL
TEST(write_print_stream_empty)
{
std::ostringstream oss;
xml_node().print(oss);
}
TEST(write_print_stream_empty_wide)
{
std::basic_ostringstream<wchar_t> oss;
xml_node().print(oss);
}
#endif
TEST(write_stackless)
{
unsigned int count = 20000;
std::basic_string<char_t> data;
for (unsigned int i = 0; i < count; ++i)
data += STR("<a>");
data += STR("text");
for (unsigned int j = 0; j < count; ++j)
data += STR("</a>");
xml_document doc;
CHECK(doc.load_string(data.c_str()));
CHECK_NODE(doc, data.c_str());
}
TEST_XML(write_indent_custom, "<node attr='1'><child><sub>text</sub></child></node>")
{
CHECK_NODE_EX(doc, STR("<node attr=\"1\">\n<child>\n<sub>text</sub>\n</child>\n</node>\n"), STR(""), format_indent);
CHECK_NODE_EX(doc, STR("<node attr=\"1\">\nA<child>\nAA<sub>text</sub>\nA</child>\n</node>\n"), STR("A"), format_indent);
CHECK_NODE_EX(doc, STR("<node attr=\"1\">\nAB<child>\nABAB<sub>text</sub>\nAB</child>\n</node>\n"), STR("AB"), format_indent);
CHECK_NODE_EX(doc, STR("<node attr=\"1\">\nABC<child>\nABCABC<sub>text</sub>\nABC</child>\n</node>\n"), STR("ABC"), format_indent);
CHECK_NODE_EX(doc, STR("<node attr=\"1\">\nABCD<child>\nABCDABCD<sub>text</sub>\nABCD</child>\n</node>\n"), STR("ABCD"), format_indent);
CHECK_NODE_EX(doc, STR("<node attr=\"1\">\nABCDE<child>\nABCDEABCDE<sub>text</sub>\nABCDE</child>\n</node>\n"), STR("ABCDE"), format_indent);
}
TEST(write_pcdata_null)
{
xml_document doc;
doc.append_child(STR("node")).append_child(node_pcdata);
CHECK_NODE(doc, STR("<node></node>"));
CHECK_NODE_EX(doc, STR("<node></node>\n"), STR("\t"), format_indent);
doc.first_child().append_child(node_pcdata);
CHECK_NODE_EX(doc, STR("<node></node>\n"), STR("\t"), format_indent);
}
TEST(write_pcdata_whitespace_fixedpoint)
{
const char_t* data = STR("<node> test <child>\n <sub/>\n </child>\n</node>");
static const unsigned int flags_parse[] =
{
0,
parse_ws_pcdata,
parse_ws_pcdata_single,
parse_trim_pcdata
};
static const unsigned int flags_format[] =
{
0,
format_raw,
format_indent
};
for (unsigned int i = 0; i < sizeof(flags_parse) / sizeof(flags_parse[0]); ++i)
{
xml_document doc;
CHECK(doc.load_string(data, flags_parse[i]));
for (unsigned int j = 0; j < sizeof(flags_format) / sizeof(flags_format[0]); ++j)
{
std::string saved = write_narrow(doc, flags_format[j], encoding_auto);
xml_document rdoc;
CHECK(rdoc.load_buffer(&saved[0], saved.size(), flags_parse[i]));
std::string rsaved = write_narrow(rdoc, flags_format[j], encoding_auto);
CHECK(saved == rsaved);
}
}
}
TEST_XML_FLAGS(write_mixed, "<node><child1/><child2>pre<![CDATA[data]]>mid<!--comment--><test/>post<?pi value?>fin</child2><child3/></node>", parse_full)
{
CHECK_NODE(doc, STR("<node><child1/><child2>pre<![CDATA[data]]>mid<!--comment--><test/>post<?pi value?>fin</child2><child3/></node>"));
CHECK_NODE_EX(doc, STR("<node>\n<child1 />\n<child2>pre<![CDATA[data]]>mid<!--comment-->\n<test />post<?pi value?>fin</child2>\n<child3 />\n</node>\n"), STR("\t"), 0);
CHECK_NODE_EX(doc, STR("<node>\n\t<child1 />\n\t<child2>pre<![CDATA[data]]>mid<!--comment-->\n\t\t<test />post<?pi value?>fin</child2>\n\t<child3 />\n</node>\n"), STR("\t"), format_indent);
}
TEST_XML(write_no_empty_element_tags, "<node><child1/><child2>text</child2><child3></child3></node>")
{
CHECK_NODE(doc, STR("<node><child1/><child2>text</child2><child3/></node>"));
CHECK_NODE_EX(doc, STR("<node><child1></child1><child2>text</child2><child3></child3></node>"), STR("\t"), format_raw | format_no_empty_element_tags);
CHECK_NODE_EX(doc, STR("<node>\n\t<child1></child1>\n\t<child2>text</child2>\n\t<child3></child3>\n</node>\n"), STR("\t"), format_indent | format_no_empty_element_tags);
}
TEST_XML_FLAGS(write_roundtrip, "<node><child1 attr1='value1' attr2='value2'/><child2 attr='value'>pre<![CDATA[data]]>mid&lt;text&amp;escape<!--comment--><test/>post<?pi value?>fin</child2><child3/></node>", parse_full)
{
const unsigned int flagset[] = { format_indent, format_raw, format_no_declaration, format_indent_attributes, format_no_empty_element_tags, format_attribute_single_quote };
size_t flagcount = sizeof(flagset) / sizeof(flagset[0]);
for (size_t i = 0; i < (size_t(1) << flagcount); ++i)
{
unsigned int flags = 0;
for (size_t j = 0; j < flagcount; ++j)
if (i & (size_t(1) << j))
flags |= flagset[j];
std::string contents = write_narrow(doc, flags, encoding_utf8);
xml_document verify;
CHECK(verify.load_buffer(contents.c_str(), contents.size(), parse_full));
CHECK(test_write_narrow(verify, flags, encoding_utf8, contents.c_str(), contents.size()));
xml_document verifyws;
CHECK(verifyws.load_buffer(contents.c_str(), contents.size(), parse_full | parse_ws_pcdata));
CHECK(test_write_narrow(verifyws, flags, encoding_utf8, contents.c_str(), contents.size()));
}
}
TEST(write_flush_coverage)
{
xml_document doc;
// this creates a node that uses short sequences of lengths 1-6 for output
xml_node n = doc.append_child(STR("n"));
xml_attribute a = n.append_attribute(STR("a"));
xml_attribute b = n.append_attribute(STR("b"));
b.set_value(STR("<&\""));
n.append_child(node_comment);
size_t basel = save_narrow(doc, format_raw, encoding_auto).size();
size_t bufl = 2048;
for (size_t l = 0; l <= basel; ++l)
{
std::basic_string<char_t> pad(bufl - l, STR('v'));
a.set_value(pad.c_str());
std::string s = save_narrow(doc, format_raw, encoding_auto);
CHECK(s.size() == basel + bufl - l);
}
}
#ifndef PUGIXML_NO_EXCEPTIONS
struct throwing_writer: xml_writer
{
virtual void write(const void*, size_t) PUGIXML_OVERRIDE
{
throw std::runtime_error("write failed");
}
};
TEST_XML(write_throw_simple, "<node><child/></node>")
{
try
{
throwing_writer w;
doc.print(w);
CHECK_FORCE_FAIL("Expected exception");
}
catch (std::runtime_error&)
{
}
}
TEST_XML(write_throw_encoding, "<node><child/></node>")
{
try
{
throwing_writer w;
doc.print(w, STR("\t"), format_default, encoding_utf32_be);
CHECK_FORCE_FAIL("Expected exception");
}
catch (std::runtime_error&)
{
}
}
#endif
TEST_XML(write_skip_control_chars, "<a>\f\t\n\x0F\x19</a>")
{
CHECK_NODE_EX(doc.first_child(), STR("<a>\t\n</a>\n"), STR(""), pugi::format_default | pugi::format_skip_control_chars);
}
TEST_XML(write_keep_control_chars, "<a>\f\t\n\x0F\x19</a>")
{
CHECK_NODE_EX(doc.first_child(), STR("<a>&#12;\t\n&#15;&#25;</a>\n"), STR(""), pugi::format_default);
}

815
3rd_party/pugixml/tests/test_xpath.cpp vendored Normal file
View File

@ -0,0 +1,815 @@
#ifndef PUGIXML_NO_XPATH
#include "test.hpp"
#include <string.h>
#include <wchar.h>
#include <string>
#include <vector>
#include <algorithm>
#include <limits>
using namespace pugi;
static void load_document_copy(xml_document& doc, const char_t* text)
{
xml_document source;
CHECK(source.load_string(text));
doc.append_copy(source.first_child());
}
template <typename T>
static void random_shuffle(std::vector<T>& v)
{
size_t rng = 2147483647;
for (size_t i = v.size() - 1; i > 0; --i)
{
// Fisher-Yates shuffle
size_t j = rng % (i + 1);
std::swap(v[j], v[i]);
// LCG RNG, constants from Numerical Recipes
rng = rng * 1664525 + 1013904223;
}
}
TEST(xpath_allocator_many_pages)
{
std::basic_string<char_t> query = STR("0");
for (int i = 0; i < 128; ++i) query += STR("+string-length('abcdefgh')");
CHECK_XPATH_NUMBER(xml_node(), query.c_str(), 1024);
}
TEST(xpath_allocator_large_page)
{
std::basic_string<char_t> query;
for (int i = 0; i < 1024; ++i) query += STR("abcdefgh");
CHECK_XPATH_NUMBER(xml_node(), (STR("string-length('") + query + STR("')")).c_str(), 8192);
}
TEST_XML(xpath_sort_complex, "<node><child1 attr1='value1' attr2='value2'/><child2 attr1='value1'>test</child2></node>")
{
// just some random union order, it should not matter probably?
xpath_node_set ns = doc.child(STR("node")).select_nodes(STR("child1 | child2 | child1/@* | . | child2/@* | child2/text()"));
ns.sort(false);
xpath_node_set sorted = ns;
ns.sort(true);
xpath_node_set reverse_sorted = ns;
xpath_node_set_tester(sorted, "sorted order failed") % 2 % 3 % 4 % 5 % 6 % 7 % 8;
xpath_node_set_tester(reverse_sorted, "reverse sorted order failed") % 8 % 7 % 6 % 5 % 4 % 3 % 2;
}
TEST(xpath_sort_complex_copy) // copy the document so that document order optimization does not work
{
xml_document doc;
load_document_copy(doc, STR("<node><child1 attr1='value1' attr2='value2'/><child2 attr1='value1'>test</child2></node>"));
// just some random union order, it should not matter probably?
xpath_node_set ns = doc.child(STR("node")).select_nodes(STR("child1 | child2 | child1/@* | . | child2/@* | child2/text()"));
ns.sort(false);
xpath_node_set sorted = ns;
ns.sort(true);
xpath_node_set reverse_sorted = ns;
xpath_node_set_tester(sorted, "sorted order failed") % 2 % 3 % 4 % 5 % 6 % 7 % 8;
xpath_node_set_tester(reverse_sorted, "reverse sorted order failed") % 8 % 7 % 6 % 5 % 4 % 3 % 2;
}
TEST_XML(xpath_sort_children, "<node><child><subchild id='1'/></child><child><subchild id='2'/></child></node>")
{
xpath_node_set ns = doc.child(STR("node")).select_nodes(STR("child/subchild[@id=1] | child/subchild[@id=2]"));
ns.sort(false);
xpath_node_set sorted = ns;
ns.sort(true);
xpath_node_set reverse_sorted = ns;
xpath_node_set_tester(sorted, "sorted order failed") % 4 % 7;
xpath_node_set_tester(reverse_sorted, "reverse sorted order failed") % 7 % 4;
}
TEST(xpath_sort_children_copy) // copy the document so that document order optimization does not work
{
xml_document doc;
load_document_copy(doc, STR("<node><child><subchild id='1'/></child><child><subchild id='2'/></child></node>"));
xpath_node_set ns = doc.child(STR("node")).select_nodes(STR("child/subchild[@id=1] | child/subchild[@id=2]"));
ns.sort(false);
xpath_node_set sorted = ns;
ns.sort(true);
xpath_node_set reverse_sorted = ns;
xpath_node_set_tester(sorted, "sorted order failed") % 4 % 7;
xpath_node_set_tester(reverse_sorted, "reverse sorted order failed") % 7 % 4;
}
TEST_XML(xpath_sort_attributes, "<node/>")
{
xml_node n = doc.child(STR("node"));
// we need to insert attributes manually since unsorted node sets are (always?) sorted via pointers because of remove_duplicates,
// so we need to have different document and pointer order to cover all comparator cases
n.append_attribute(STR("attr2"));
n.append_attribute(STR("attr3"));
n.insert_attribute_before(STR("attr1"), n.attribute(STR("attr2")));
xpath_node_set ns = n.select_nodes(STR("@* | @*"));
ns.sort(true);
xpath_node_set reverse_sorted = ns;
ns.sort(false);
xpath_node_set sorted = ns;
xpath_node_set_tester(sorted, "sorted order failed") % 3 % 4 % 5;
xpath_node_set_tester(reverse_sorted, "reverse sorted order failed") % 5 % 4 % 3;
}
TEST_XML(xpath_sort_attributes_docorder, "<node attr1='' attr2='value' attr4='value' />")
{
xml_node n = doc.child(STR("node"));
n.first_attribute().set_name(STR("attribute1"));
n.insert_attribute_after(STR("attr3"), n.attribute(STR("attr2")));
xpath_node_set ns = n.select_nodes(STR("@* | @*"));
ns.sort(true);
xpath_node_set reverse_sorted = ns;
ns.sort(false);
xpath_node_set sorted = ns;
xpath_node_set_tester(sorted, "sorted order failed") % 3 % 4 % 5 % 6;
xpath_node_set_tester(reverse_sorted, "reverse sorted order failed") % 6 % 5 % 4 % 3;
}
TEST(xpath_sort_random_medium)
{
xml_document doc;
load_document_copy(doc, STR("<node>")
STR("<child1 attr1='value1' attr2='value2'/><child2 attr1='value1'>test</child2><child1 attr1='value1' attr2='value2'/><child2 attr1='value1'>test</child2>")
STR("<child1 attr1='value1' attr2='value2'/><child2 attr1='value1'>test</child2><child1 attr1='value1' attr2='value2'/><child2 attr1='value1'>test</child2>")
STR("<child1 attr1='value1' attr2='value2'/><child2 attr1='value1'>test</child2><child1 attr1='value1' attr2='value2'/><child2 attr1='value1'>test</child2>")
STR("</node>"));
xpath_node_set ns = doc.select_nodes(STR("//node() | //@*"));
std::vector<xpath_node> nsv(ns.begin(), ns.end());
random_shuffle(nsv);
xpath_node_set copy(&nsv[0], &nsv[0] + nsv.size());
copy.sort();
xpath_node_set_tester tester(copy, "sorted order failed");
for (unsigned int i = 2; i < 39; ++i) tester % i;
}
TEST(xpath_sort_random_large)
{
xml_document doc;
load_document_copy(doc, STR("<node>")
STR("<child1 attr1='value1' attr2='value2'/><child2 attr1='value1'>test</child2><child1 attr1='value1' attr2='value2'/><child2 attr1='value1'>test</child2>")
STR("<child1 attr1='value1' attr2='value2'/><child2 attr1='value1'>test</child2><child1 attr1='value1' attr2='value2'/><child2 attr1='value1'>test</child2>")
STR("<child1 attr1='value1' attr2='value2'/><child2 attr1='value1'>test</child2><child1 attr1='value1' attr2='value2'/><child2 attr1='value1'>test</child2>")
STR("<child1 attr1='value1' attr2='value2'/><child2 attr1='value1'>test</child2><child1 attr1='value1' attr2='value2'/><child2 attr1='value1'>test</child2>")
STR("<child1 attr1='value1' attr2='value2'/><child2 attr1='value1'>test</child2><child1 attr1='value1' attr2='value2'/><child2 attr1='value1'>test</child2>")
STR("<child1 attr1='value1' attr2='value2'/><child2 attr1='value1'>test</child2><child1 attr1='value1' attr2='value2'/><child2 attr1='value1'>test</child2>")
STR("<child1 attr1='value1' attr2='value2'/><child2 attr1='value1'>test</child2><child1 attr1='value1' attr2='value2'/><child2 attr1='value1'>test</child2>")
STR("<child1 attr1='value1' attr2='value2'/><child2 attr1='value1'>test</child2><child1 attr1='value1' attr2='value2'/><child2 attr1='value1'>test</child2>")
STR("<child1 attr1='value1' attr2='value2'/><child2 attr1='value1'>test</child2><child1 attr1='value1' attr2='value2'/><child2 attr1='value1'>test</child2>")
STR("<child1 attr1='value1' attr2='value2'/><child2 attr1='value1'>test</child2><child1 attr1='value1' attr2='value2'/><child2 attr1='value1'>test</child2>")
STR("<child1 attr1='value1' attr2='value2'/><child2 attr1='value1'>test</child2></node>"));
xpath_node_set ns = doc.select_nodes(STR("//node() | //@*"));
std::vector<xpath_node> nsv(ns.begin(), ns.end());
random_shuffle(nsv);
xpath_node_set copy(&nsv[0], &nsv[0] + nsv.size());
copy.sort();
xpath_node_set_tester tester(copy, "sorted order failed");
for (unsigned int i = 2; i < 129; ++i) tester % i;
}
TEST(xpath_long_numbers_parse)
{
const char_t* str_flt_max = STR("340282346638528860000000000000000000000");
const char_t* str_flt_max_dec = STR("340282346638528860000000000000000000000.000000");
const char_t* str_dbl_max = STR("179769313486231570000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000");
const char_t* str_dbl_max_dec = STR("179769313486231570000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.000000");
xml_node c;
// check parsing
CHECK_XPATH_NUMBER(c, str_flt_max, double(std::numeric_limits<float>::max()));
CHECK_XPATH_NUMBER(c, str_flt_max_dec, double(std::numeric_limits<float>::max()));
CHECK_XPATH_NUMBER(c, str_dbl_max, std::numeric_limits<double>::max());
CHECK_XPATH_NUMBER(c, str_dbl_max_dec, std::numeric_limits<double>::max());
}
static bool test_xpath_string_prefix(const xml_node& node, const char_t* query, const char_t* expected, size_t match_length)
{
xpath_query q(query);
char_t result[32];
size_t size = q.evaluate_string(result, sizeof(result) / sizeof(result[0]), node);
size_t expected_length = std::char_traits<char_t>::length(expected);
return size == expected_length + 1 && std::char_traits<char_t>::compare(result, expected, match_length) == 0;
}
TEST(xpath_long_numbers_stringize)
{
const char_t* str_flt_max = STR("340282346638528860000000000000000000000");
const char_t* str_flt_max_dec = STR("340282346638528860000000000000000000000.000000");
const char_t* str_dbl_max = STR("179769313486231570000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000");
const char_t* str_dbl_max_dec = STR("179769313486231570000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.000000");
xml_node c;
CHECK(test_xpath_string_prefix(c, str_flt_max, str_flt_max, 15));
CHECK(test_xpath_string_prefix(c, str_flt_max_dec, str_flt_max, 15));
CHECK(test_xpath_string_prefix(c, str_dbl_max, str_dbl_max, 15));
CHECK(test_xpath_string_prefix(c, str_dbl_max_dec, str_dbl_max, 15));
}
TEST(xpath_denorm_numbers)
{
std::basic_string<char_t> query;
// 10^-318 - double denormal
for (int i = 0; i < 106; ++i)
{
if (i != 0) query += STR(" * ");
query += STR("0.001");
}
// check if current fpu setup supports denormals
double denorm = xpath_query(query.c_str()).evaluate_number(xml_node());
if (denorm != 0.0)
{
CHECK_XPATH_STRING(xml_node(), query.c_str(), STR("0.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000009999987484955998"));
}
}
TEST_XML(xpath_rexml_1, "<a><b><c id='a'/></b><c id='b'/></a>")
{
CHECK_XPATH_NODESET(doc, STR("//*[local-name()='c' and @id='b']")) % 6;
CHECK_XPATH_NODESET(doc, STR("//*[ local-name()='c' and @id='b' ]")) % 6;
CHECK_XPATH_NODESET(doc, STR("/a/c[@id]")) % 6;
CHECK_XPATH_NODESET(doc, STR("/a/c[(@id)]")) % 6;
CHECK_XPATH_NODESET(doc, STR("/a/c[ @id ]")) % 6;
CHECK_XPATH_NODESET(doc, STR("/a/c[ (@id) ]")) % 6;
CHECK_XPATH_NODESET(doc, STR("/a/c[( @id )]")) % 6;
CHECK_XPATH_NODESET(doc, STR("/a/c[ ( @id ) ]")) % 6;
CHECK_XPATH_NODESET(doc, STR("/a/c [ ( @id ) ] ")) % 6;
CHECK_XPATH_NODESET(doc, STR(" / a / c [ ( @id ) ] ")) % 6;
}
TEST_XML(xpath_rexml_2, "<a:x xmlns:a='1'><a:y p='p' q='q'><a:z>zzz</a:z></a:y></a:x>")
{
CHECK_XPATH_NODESET(doc, STR("a:x/a:y[@p='p' and @q='q']/a:z/text()")) % 8;
}
TEST_XML(xpath_rexml_3, "<article><section role='subdivision' id='1'><para>free flowing text.</para></section><section role='division'><section role='subdivision' id='2'><para>free flowing text.</para></section><section role='division'><para>free flowing text.</para></section></section></article>")
{
CHECK_XPATH_NODESET(doc, STR("//section[../self::section[@role=\"division\"]]")) % 10 % 15;
CHECK_XPATH_NODESET(doc, STR("//section[@role=\"subdivision\" and not(../self::section[@role=\"division\"])]")) % 3;
CHECK_XPATH_NODESET(doc, STR("//section[@role=\"subdivision\"][not(../self::section[@role=\"division\"])]")) % 3;
}
TEST_XML_FLAGS(xpath_rexml_4, "<a><b number='1' str='abc'>TEXT1</b><c number='1'/><c number='2' str='def'><b number='3'/><d number='1' str='abc'>TEXT2</d><b number='2'><!--COMMENT--></b></c></a>", parse_default | parse_comments)
{
CHECK_XPATH_NODESET(doc, STR("/descendant-or-self::node()[count(child::node()|following-sibling::node()|preceding-sibling::node())=0]")) % 6 % 17 % 20;
}
TEST_XML(xpath_rexml_5, "<a><b><c id='a'/></b><c id='b'/></a>")
{
CHECK_XPATH_FAIL(STR(".//[@id]"));
CHECK_XPATH_NODESET(doc, STR(".//self::*[@id]")) % 4 % 6;
CHECK_XPATH_NODESET(doc, STR(".//node()[@id]")) % 4 % 6;
}
TEST_XML(xpath_rexml_6, "<div><span><strong>a</strong></span><em>b</em></div>")
{
CHECK_XPATH_NODESET(doc, STR("//em|//strong")) % 4 % 6;
CHECK_XPATH_NODESET(doc, STR("//*[self::em | self::strong]")) % 4 % 6;
CHECK_XPATH_NODESET(doc, STR("//*[name()=\"em\" or name()=\"strong\"]")) % 4 % 6;
CHECK_XPATH_NODESET(doc, STR("//*[self::em or self::strong]")) % 4 % 6;
}
TEST_XML(xpath_xsl_list_1, "<input><type>whatever</type></input><input><type>text</type></input><input><type>select</type></input><input><type>something</type></input>")
{
// if I'm not last, and the next input/type isn't select
CHECK_XPATH_NODESET(doc, STR("input[type[parent::input/following-sibling::input[1]/type != 'select']]")) % 2 % 8;
CHECK_XPATH_NODESET(doc, STR("input[type[../following-sibling::input[1]/type != 'select']]")) % 2 % 8;
CHECK_XPATH_NODESET(doc, STR("input[position()+1]"));
}
TEST_XML(xpath_xsl_list_2, "<TR><TD id='1'>text1</TD><TD id='2'>text2</TD><TD id='3'>text3</TD><TD id='4'>text4</TD></TR>")
{
CHECK_XPATH_FAIL(STR(".[not(.=ancestor::TR/TD[15]/node())]"));
CHECK_XPATH_NODESET(doc.child(STR("TR")).find_child_by_attribute(STR("TD"), STR("id"), STR("1")).first_child(), STR("self::node()[not(.=ancestor::TR/TD[3]/node())]")) % 5;
CHECK_XPATH_NODESET(doc.child(STR("TR")).find_child_by_attribute(STR("TD"), STR("id"), STR("2")).first_child(), STR("self::node()[not(.=ancestor::TR/TD[3]/node())]")) % 8;
CHECK_XPATH_NODESET(doc.child(STR("TR")).find_child_by_attribute(STR("TD"), STR("id"), STR("3")).first_child(), STR("self::node()[not(.=ancestor::TR/TD[3]/node())]"));
CHECK_XPATH_NODESET(doc.child(STR("TR")).find_child_by_attribute(STR("TD"), STR("id"), STR("4")).first_child(), STR("self::node()[not(.=ancestor::TR/TD[3]/node())]")) % 14;
CHECK_XPATH_NODESET(doc.child(STR("TR")).find_child_by_attribute(STR("TD"), STR("id"), STR("1")), STR("node()[not(.=ancestor::TR/TD[3]/node())]")) % 5;
CHECK_XPATH_NODESET(doc.child(STR("TR")).find_child_by_attribute(STR("TD"), STR("id"), STR("2")), STR("node()[not(.=ancestor::TR/TD[3]/node())]")) % 8;
CHECK_XPATH_NODESET(doc.child(STR("TR")).find_child_by_attribute(STR("TD"), STR("id"), STR("3")), STR("node()[not(.=ancestor::TR/TD[3]/node())]"));
CHECK_XPATH_NODESET(doc.child(STR("TR")).find_child_by_attribute(STR("TD"), STR("id"), STR("4")), STR("node()[not(.=ancestor::TR/TD[3]/node())]")) % 14;
}
TEST_XML(xpath_star_token, "<node>0.5<section><child/><child/><child/><child/></section><section/></node>")
{
CHECK_XPATH_NODESET(doc, STR("//*[/* * 4]")) % 6 % 9;
CHECK_XPATH_NODESET(doc, STR("//*[/**4]")) % 6 % 9;
CHECK_XPATH_FAIL(STR("//*[/***4]"));
}
TEST(xpath_miscellaneous)
{
CHECK_XPATH_FAIL(STR("/root/child[a=3]/substring(child::text())"));
CHECK_XPATH_NODESET(xml_node(), STR("foo/@FOO/@bar"));
}
TEST_XML(xpath_context_node, "<node>5</node>")
{
CHECK_XPATH_NODESET(doc, STR("node")) % 2;
CHECK_XPATH_BOOLEAN(doc, STR("node"), true);
CHECK_XPATH_NUMBER(doc, STR("node"), 5);
CHECK_XPATH_STRING(doc, STR("node"), STR("5"));
}
TEST_XML(xpath_context_position, "<node>5</node>")
{
CHECK_XPATH_NODESET(doc, STR("id(position() + last())"));
CHECK_XPATH_BOOLEAN(doc, STR("position() + last() = 2"), true);
CHECK_XPATH_NUMBER(doc, STR("position() + last()"), 2);
CHECK_XPATH_STRING(doc, STR("position() + last()"), STR("2"));
}
TEST(xpath_lexer_unknown_lexeme)
{
CHECK_XPATH_FAIL(STR("(^3))"));
CHECK_XPATH_FAIL(STR("(!3))"));
}
TEST(xpath_large_node_set)
{
xml_document doc;
CHECK(doc.load_file("tests/data/large.xml"));
xpath_node_set ns = doc.select_nodes(STR("//*"));
CHECK(ns.size() == 10001);
}
TEST(xpath_out_of_memory_query)
{
test_runner::_memory_fail_threshold = 1;
CHECK_ALLOC_FAIL(xpath_query q(STR("node")));
}
TEST_XML(xpath_out_of_memory_evaluate, "<n/>")
{
test_runner::_memory_fail_threshold = 4196 * sizeof(char_t) + 4096 * 2 + 32768;
std::basic_string<char_t> query = STR("*[concat(\"a\", \"");
query.resize(4196, 'a');
query += STR("\")]");
xpath_query q(query.c_str());
CHECK_ALLOC_FAIL(CHECK(q.evaluate_boolean(doc) == false));
CHECK_ALLOC_FAIL(CHECK_DOUBLE_NAN(q.evaluate_number(doc)));
#ifndef PUGIXML_NO_STL
CHECK_ALLOC_FAIL(CHECK(q.evaluate_string(doc).empty()));
#endif
CHECK_ALLOC_FAIL(CHECK(q.evaluate_string(0, 0, doc) == 1));
CHECK_ALLOC_FAIL(CHECK(q.evaluate_node(doc) == xpath_node()));
CHECK_ALLOC_FAIL(CHECK(q.evaluate_node_set(doc).empty()));
}
TEST(xpath_out_of_memory_evaluate_concat)
{
test_runner::_memory_fail_threshold = 4196 * sizeof(char_t) + 4096 * 2;
std::basic_string<char_t> query = STR("concat(\"a\", \"");
query.resize(4196, 'a');
query += STR("\")");
xpath_query q(query.c_str());
CHECK_ALLOC_FAIL(CHECK(q.evaluate_string(0, 0, xml_node()) == 1));
}
TEST(xpath_out_of_memory_evaluate_concat_list)
{
std::basic_string<char_t> query = STR("concat(");
for (size_t i = 0; i < 500; ++i)
query += STR("\"\",");
query += STR("\"\")");
xpath_query q(query.c_str());
test_runner::_memory_fail_threshold = 1;
CHECK_ALLOC_FAIL(CHECK(q.evaluate_string(0, 0, xml_node()) == 1));
}
TEST(xpath_out_of_memory_evaluate_substring)
{
test_runner::_memory_fail_threshold = 4196 * sizeof(char_t) + 4096 * 2;
std::basic_string<char_t> query = STR("substring(\"");
query.resize(4196, 'a');
query += STR("\", 1, 4097)");
xpath_query q(query.c_str());
CHECK_ALLOC_FAIL(CHECK(q.evaluate_string(0, 0, xml_node()) == 1));
}
TEST_XML(xpath_out_of_memory_evaluate_union, "<node />")
{
// left hand side: size * sizeof(xpath_node) (8 on 32-bit, 16 on 64-bit)
// right hand side: same
// to make sure that when we append right hand side to left hand side, we run out of an XPath stack page (4K), we need slightly more than 2K/8 = 256 nodes on 32-bit, 128 nodes on 64-bit
size_t count = sizeof(void*) == 4 ? 300 : 150;
for (size_t i = 0; i < count; ++i)
doc.first_child().append_child(STR("a"));
xpath_query q(STR("a|a"));
test_runner::_memory_fail_threshold = 1;
CHECK_ALLOC_FAIL(CHECK(q.evaluate_node_set(doc.child(STR("node"))).empty()));
}
TEST_XML(xpath_out_of_memory_evaluate_union_hash, "<node />")
{
// left hand side: size * sizeof(xpath_node) (8 on 32-bit, 16 on 64-bit)
// right hand side: same
// hash table: size * 1.5 * sizeof(void*)
// to make sure that when we append right hand side to left hand side, we do *not* run out of an XPath stack page (4K), we need slightly less than 2K/8 = 256 nodes on 32-bit, 128 nodes on 64-bit
size_t count = sizeof(void*) == 4 ? 200 : 100;
for (size_t i = 0; i < count; ++i)
doc.first_child().append_child(STR("a"));
xpath_query q(STR("a|a"));
test_runner::_memory_fail_threshold = 1;
CHECK_ALLOC_FAIL(CHECK(q.evaluate_node_set(doc.child(STR("node"))).empty()));
}
TEST_XML(xpath_out_of_memory_evaluate_predicate, "<node><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/><a/></node>")
{
test_runner::_memory_fail_threshold = 32768 + 4096 * 2;
xpath_query q(STR("//a[//a[//a[//a[true()]]]]"));
CHECK_ALLOC_FAIL(CHECK(q.evaluate_node_set(doc).empty()));
}
TEST_XML(xpath_out_of_memory_evaluate_normalize_space_0, "<node> a b c d e f g h i j k l m n o p q r s t u v w x y z a b c d e f g h i j k l m n o p q r s t u v w x y z a b c d e f g h i j k l m n o p q r s t u v w x y z a b c d e f g h i j k l m n o p q r s t u v w x y z a b c d e f g h i j k l m n o p q r s t u v w x y z a b c d e f g h i j k l m n o p q r s t u v w x y z a b c d e f g h i j k l m n o p q r s t u v w x y z a b c d e f g h i j k l m n o p q r s t u v w x y z a b c d e f g h i j k l m n o p q r s t u v w x y z a b c d e f g h i j k l m n o p q r s t u v w x y z </node>")
{
test_runner::_memory_fail_threshold = 32768 + 4096 * 2;
xpath_query q(STR("concat(normalize-space(), normalize-space(), normalize-space(), normalize-space(), normalize-space(), normalize-space(), normalize-space(), normalize-space())"));
CHECK_ALLOC_FAIL(CHECK(q.evaluate_string(0, 0, doc.first_child()) == 1));
}
TEST_XML(xpath_out_of_memory_evaluate_normalize_space_1, "<node> a b c d e f g h i j k l m n o p q r s t u v w x y z a b c d e f g h i j k l m n o p q r s t u v w x y z a b c d e f g h i j k l m n o p q r s t u v w x y z a b c d e f g h i j k l m n o p q r s t u v w x y z a b c d e f g h i j k l m n o p q r s t u v w x y z a b c d e f g h i j k l m n o p q r s t u v w x y z a b c d e f g h i j k l m n o p q r s t u v w x y z a b c d e f g h i j k l m n o p q r s t u v w x y z a b c d e f g h i j k l m n o p q r s t u v w x y z a b c d e f g h i j k l m n o p q r s t u v w x y z </node>")
{
test_runner::_memory_fail_threshold = 32768 + 4096 * 2;
xpath_query q(STR("concat(normalize-space(node), normalize-space(node), normalize-space(node), normalize-space(node), normalize-space(node), normalize-space(node), normalize-space(node), normalize-space(node))"));
CHECK_ALLOC_FAIL(CHECK(q.evaluate_string(0, 0, doc) == 1));
}
TEST_XML(xpath_out_of_memory_evaluate_translate, "<node> a b c d e f g h i j k l m n o p q r s t u v w x y z a b c d e f g h i j k l m n o p q r s t u v w x y z a b c d e f g h i j k l m n o p q r s t u v w x y z a b c d e f g h i j k l m n o p q r s t u v w x y z a b c d e f g h i j k l m n o p q r s t u v w x y z a b c d e f g h i j k l m n o p q r s t u v w x y z a b c d e f g h i j k l m n o p q r s t u v w x y z a b c d e f g h i j k l m n o p q r s t u v w x y z a b c d e f g h i j k l m n o p q r s t u v w x y z a b c d e f g h i j k l m n o p q r s t u v w x y z </node>")
{
test_runner::_memory_fail_threshold = 32768 + 4096 * 2;
xpath_query q(STR("concat(translate(node, 'a', '\xe9'), translate(node, 'a', '\xe9'), translate(node, 'a', '\xe9'), translate(node, 'a', '\xe9'), translate(node, 'a', '\xe9'), translate(node, 'a', '\xe9'), translate(node, 'a', '\xe9'), translate(node, 'a', '\xe9'))"));
CHECK_ALLOC_FAIL(CHECK(q.evaluate_string(0, 0, doc) == 1));
}
TEST_XML(xpath_out_of_memory_evaluate_translate_table, "<node> a b c d e f g h i j k l m n o p q r s t u v w x y z a b c d e f g h i j k l m n o p q r s t u v w x y z a b c d e f g h i j k l m n o p q r s t u v w x y z a b c d e f g h i j k l m n o p q r s t u v w x y z a b c d e f g h i j k l m n o p q r s t u v w x y z a b c d e f g h i j k l m n o p q r s t u v w x y z a b c d e f g h i j k l m n o p q r s t u v w x y z a b c d e f g h i j k l m n o p q r s t u v w x y z a b c d e f g h i j k l m n o p q r s t u v w x y z a b c d e f g h i j k l m n o p q r s t u v w x y z </node>")
{
test_runner::_memory_fail_threshold = 32768 + 4096 * 2;
xpath_query q(STR("concat(translate(node, 'a', 'A'), translate(node, 'a', 'A'), translate(node, 'a', 'A'), translate(node, 'a', 'A'), translate(node, 'a', 'A'), translate(node, 'a', 'A'), translate(node, 'a', 'A'), translate(node, 'a', 'A'))"));
CHECK_ALLOC_FAIL(CHECK(q.evaluate_string(0, 0, doc) == 1));
}
TEST(xpath_out_of_memory_evaluate_string_append)
{
test_runner::_memory_fail_threshold = 32768 + 4096 * 2;
std::basic_string<char_t> literal(5000, 'a');
std::basic_string<char_t> buf;
buf += STR("<n><c>text</c><c>");
buf += literal;
buf += STR("</c></n>");
xml_document doc;
CHECK(doc.load_buffer_inplace(&buf[0], buf.size() * sizeof(char_t)));
xpath_query q(STR("string(n)"));
CHECK(q);
CHECK_ALLOC_FAIL(CHECK(q.evaluate_string(0, 0, doc) == 1));
}
TEST(xpath_out_of_memory_evaluate_number_to_string)
{
test_runner::_memory_fail_threshold = 4096 + 128;
xpath_variable_set vars;
vars.set(STR("x"), 1e+308);
xpath_query q(STR("concat($x, $x, $x, $x, $x, $x, $x, $x, $x, $x, $x, $x, $x, $x, $x, $x, $x)"), &vars);
CHECK_ALLOC_FAIL(CHECK(q.evaluate_string(0, 0, xml_node()) == 1));
}
TEST(xpath_memory_concat_massive)
{
xml_document doc;
xml_node node = doc.append_child(STR("node"));
for (int i = 0; i < 5000; ++i)
node.append_child(STR("c")).text().set(i % 10);
xpath_query q(STR("/"));
size_t size = q.evaluate_string(0, 0, node);
CHECK(size == 5001);
}
TEST_XML(xpath_memory_translate_table, "<node>a</node>")
{
test_runner::_memory_fail_threshold = 32768 + 4096 + 128;
// 128b per table => we need 32+ translate calls to exhaust a page
std::basic_string<char_t> query = STR("concat(");
for (int i = 0; i < 64; ++i)
query += STR("translate(.,'a','A'),");
query += STR("'')");
CHECK_ALLOC_FAIL(CHECK(!xpath_query(query.c_str())));
}
TEST_XML(xpath_sort_copy_share, "<node><child1 attr1='value1' attr2='value2'/><child2 attr1='value1'>test</child2></node>")
{
// copy sharing shares the name/value data for nodes that can potentially make document order optimization invalid (silently)
xml_node node = doc.child(STR("node"));
xml_node child1 = node.child(STR("child1"));
xml_node child2 = node.child(STR("child2"));
// swap child1 & child2
node.prepend_copy(child2);
node.append_copy(child1);
node.remove_child(child1);
node.remove_child(child2);
// just some random union order, it should not matter probably?
xpath_node_set ns = doc.child(STR("node")).select_nodes(STR("child1 | child2 | child1/@* | . | child2/@* | child2/text()"));
ns.sort(false);
xpath_node_set sorted = ns;
ns.sort(true);
xpath_node_set reverse_sorted = ns;
xpath_node_set_tester(sorted, "sorted order failed") % 2 % 3 % 4 % 5 % 6 % 7 % 8;
xpath_node_set_tester(reverse_sorted, "reverse sorted order failed") % 8 % 7 % 6 % 5 % 4 % 3 % 2;
}
TEST_XML(xpath_sort_move_share, "<node><child1 attr1='value1' attr2='value2'/><child2 attr1='value1'>test</child2></node>")
{
// moving changes the relation between name/value data and document order, this can potentially make document order optimization invalid (silently)
xml_node node = doc.child(STR("node"));
xml_node child1 = node.child(STR("child1"));
xml_node child2 = node.child(STR("child2"));
// swap child1 & child2
node.prepend_move(child2);
node.append_move(child1);
// just some random union order, it should not matter probably?
xpath_node_set ns = doc.child(STR("node")).select_nodes(STR("child1 | child2 | child1/@* | . | child2/@* | child2/text()"));
ns.sort(false);
xpath_node_set sorted = ns;
ns.sort(true);
xpath_node_set reverse_sorted = ns;
xpath_node_set_tester(sorted, "sorted order failed") % 2 % 3 % 4 % 5 % 6 % 7 % 8;
xpath_node_set_tester(reverse_sorted, "reverse sorted order failed") % 8 % 7 % 6 % 5 % 4 % 3 % 2;
}
TEST_XML(xpath_sort_append_buffer, "<node /><node />")
{
// append_buffer changes the relation between name/value data and document order, this can potentially make document order optimization invalid (silently)
const char* child1 = "<child1 attr1='value1' attr2='value2'/>";
const char* child2 = "<child2 attr1='value1'>test </child2>";
doc.last_child().append_buffer(child2, strlen(child2));
doc.first_child().append_buffer(child1, strlen(child1));
// just some random union order, it should not matter probably?
xpath_node_set ns = doc.select_nodes(STR("node/child1 | node/child2 | node/child1/@* | node/. | node/child2/@* | node/child2/text()"));
ns.sort(false);
xpath_node_set sorted = ns;
ns.sort(true);
xpath_node_set reverse_sorted = ns;
xpath_node_set_tester(sorted, "sorted order failed") % 2 % 3 % 4 % 5 % 6 % 7 % 8 % 9;
xpath_node_set_tester(reverse_sorted, "reverse sorted order failed") % 9 % 8 % 7 % 6 % 5 % 4 % 3 % 2;
}
TEST(xpath_sort_crossdoc)
{
xml_document doc1;
CHECK(doc1.load_string(STR("<node />")));
xml_document doc2;
CHECK(doc2.load_string(STR("<node />")));
xpath_node_set ns1 = doc1.select_nodes(STR("*"));
CHECK(ns1.size() == 1);
xpath_node_set ns2 = doc2.select_nodes(STR("*"));
CHECK(ns2.size() == 1);
xpath_variable_set set;
set.set(STR("ns1"), ns1);
set.set(STR("ns2"), ns2);
xpath_node_set ns = xpath_query(STR("$ns1 | $ns2"), &set).evaluate_node_set(xpath_node());
ns.sort();
CHECK(ns.size() == 2);
CHECK((ns[0] == ns1[0] && ns[1] == ns2[0]) || (ns[0] == ns2[0] && ns[1] == ns1[0]));
}
TEST(xpath_sort_crossdoc_dynamic)
{
xml_document doc1;
doc1.append_child(STR("node"));
xml_document doc2;
doc2.append_child(STR("node"));
xpath_node_set ns1 = doc1.select_nodes(STR("*"));
CHECK(ns1.size() == 1);
xpath_node_set ns2 = doc2.select_nodes(STR("*"));
CHECK(ns2.size() == 1);
xpath_variable_set set;
set.set(STR("ns1"), ns1);
set.set(STR("ns2"), ns2);
xpath_node_set ns = xpath_query(STR("$ns1 | $ns2"), &set).evaluate_node_set(xpath_node());
ns.sort();
CHECK(ns.size() == 2);
CHECK((ns[0] == ns1[0] && ns[1] == ns2[0]) || (ns[0] == ns2[0] && ns[1] == ns1[0]));
}
TEST(xpath_sort_crossdoc_different_depth)
{
xml_document doc1;
doc1.append_child(STR("node"));
xml_document doc2;
doc2.append_child(STR("node")).append_child(STR("node"));
xpath_node_set ns1 = doc1.select_nodes(STR("*"));
CHECK(ns1.size() == 1);
xpath_node_set ns2 = doc2.select_nodes(STR("*/*"));
CHECK(ns2.size() == 1);
xpath_variable_set set;
set.set(STR("ns1"), ns1);
set.set(STR("ns2"), ns2);
xpath_node_set ns = xpath_query(STR("$ns1 | $ns2"), &set).evaluate_node_set(xpath_node());
ns.sort();
CHECK(ns.size() == 2);
CHECK((ns[0] == ns1[0] && ns[1] == ns2[0]) || (ns[0] == ns2[0] && ns[1] == ns1[0]));
}
TEST_XML(xpath_sort_empty_node, "<node><child1/><child2/></node>")
{
xml_node n = doc.child(STR("node"));
xpath_node nodes[] = { n.child(STR("child2")), xml_node(), n.child(STR("child1")), xml_node() };
xpath_node_set ns(nodes, nodes + sizeof(nodes) / sizeof(nodes[0]));
ns.sort();
CHECK(!ns[0] && !ns[1] && ns[2] == nodes[2] && ns[3] == nodes[0]);
}
TEST(xpath_allocate_string_out_of_memory)
{
std::basic_string<char_t> query;
for (int i = 0; i < 1024; ++i) query += STR("abcdefgh");
test_runner::_memory_fail_threshold = 8*1024;
#ifndef __DMC__ // DigitalMars exception handling crashes instead of catching the exception...
CHECK_ALLOC_FAIL(CHECK(!xpath_query(query.c_str())));
#endif
}
TEST(xpath_remove_duplicates)
{
xml_document doc;
for (int i = 0; i < 20; ++i)
{
doc.append_child(STR("node2"));
doc.prepend_child(STR("node1"));
}
xpath_node_set ns = doc.select_nodes(STR("/node2/preceding::* | //node1 | /node() | /* | /node1/following-sibling::*"));
ns.sort();
{
xpath_node_set_tester tester(ns, "sorted order failed");
for (int i = 0; i < 40; ++i)
tester % (2 + i);
}
}
TEST(xpath_anonymous_nodes)
{
xml_document doc;
doc.append_child(node_element);
doc.append_child(node_pi);
CHECK_XPATH_NODESET(doc, STR("/name"));
CHECK_XPATH_NODESET(doc, STR("/processing-instruction('a')"));
CHECK_XPATH_NODESET(doc, STR("/ns:*"));
}
#endif

View File

@ -0,0 +1,644 @@
#ifndef PUGIXML_NO_XPATH
#include <string.h> // because Borland's STL is braindead, we have to include <string.h> _before_ <string> in order to get memcmp
#include "test.hpp"
#include "helpers.hpp"
#include <string>
#include <vector>
using namespace pugi;
TEST_XML(xpath_api_select_nodes, "<node><head/><foo/><foo/><tail/></node>")
{
xpath_node_set ns1 = doc.select_nodes(STR("node/foo"));
xpath_query q(STR("node/foo"));
xpath_node_set ns2 = doc.select_nodes(q);
xpath_node_set_tester(ns1, "ns1") % 4 % 5;
xpath_node_set_tester(ns2, "ns2") % 4 % 5;
}
TEST_XML(xpath_api_select_node, "<node><head/><foo id='1'/><foo/><tail/></node>")
{
xpath_node n1 = doc.select_node(STR("node/foo"));
xpath_query q(STR("node/foo"));
xpath_node n2 = doc.select_node(q);
CHECK(n1.node().attribute(STR("id")).as_int() == 1);
CHECK(n2.node().attribute(STR("id")).as_int() == 1);
xpath_node n3 = doc.select_node(STR("node/bar"));
CHECK(!n3);
xpath_node n4 = doc.select_node(STR("node/head/following-sibling::foo"));
xpath_node n5 = doc.select_node(STR("node/tail/preceding-sibling::foo"));
CHECK(n4.node().attribute(STR("id")).as_int() == 1);
CHECK(n5.node().attribute(STR("id")).as_int() == 1);
}
TEST_XML(xpath_api_node_bool_ops, "<node attr='value'/>")
{
generic_bool_ops_test(doc.select_node(STR("node")));
generic_bool_ops_test(doc.select_node(STR("node/@attr")));
}
TEST_XML(xpath_api_node_eq_ops, "<node attr='value'/>")
{
generic_eq_ops_test(doc.select_node(STR("node")), doc.select_node(STR("node/@attr")));
}
TEST_XML(xpath_api_node_accessors, "<node attr='value'/>")
{
xpath_node null;
xpath_node node = doc.select_node(STR("node"));
xpath_node attr = doc.select_node(STR("node/@attr"));
CHECK(!null.node());
CHECK(!null.attribute());
CHECK(!null.parent());
CHECK(node.node() == doc.child(STR("node")));
CHECK(!node.attribute());
CHECK(node.parent() == doc);
CHECK(!attr.node());
CHECK(attr.attribute() == doc.child(STR("node")).attribute(STR("attr")));
CHECK(attr.parent() == doc.child(STR("node")));
}
inline void xpath_api_node_accessors_helper(const xpath_node_set& set)
{
CHECK(set.size() == 2);
CHECK(set.type() == xpath_node_set::type_sorted);
CHECK(!set.empty());
CHECK_STRING(set[0].node().name(), STR("foo"));
CHECK_STRING(set[1].node().name(), STR("foo"));
CHECK(set.first() == set[0]);
CHECK(set.begin() + 2 == set.end());
CHECK(set.begin()[0] == set[0] && set.begin()[1] == set[1]);
}
TEST_XML(xpath_api_nodeset_accessors, "<node><foo/><foo/></node>")
{
xpath_node_set null;
CHECK(null.size() == 0);
CHECK(null.type() == xpath_node_set::type_unsorted);
CHECK(null.empty());
CHECK(!null.first());
CHECK(null.begin() == null.end());
xpath_node_set set = doc.select_nodes(STR("node/foo"));
xpath_api_node_accessors_helper(set);
xpath_node_set copy = set;
xpath_api_node_accessors_helper(copy);
xpath_node_set assigned;
assigned = set;
xpath_api_node_accessors_helper(assigned);
xpath_node_set nullcopy = null;
}
TEST_XML(xpath_api_nodeset_copy, "<node><foo/><foo/></node>")
{
xpath_node_set empty;
xpath_node_set set = doc.select_nodes(STR("node/foo"));
xpath_node_set copy1 = set;
CHECK(copy1.size() == 2);
CHECK_STRING(copy1[0].node().name(), STR("foo"));
xpath_node_set copy2;
copy2 = set;
CHECK(copy2.size() == 2);
CHECK_STRING(copy2[0].node().name(), STR("foo"));
xpath_node_set copy3;
copy3 = set;
copy3 = xpath_node_set(copy3);
CHECK(copy3.size() == 2);
CHECK_STRING(copy3[0].node().name(), STR("foo"));
xpath_node_set copy4;
copy4 = set;
copy4 = copy1;
CHECK(copy4.size() == 2);
CHECK_STRING(copy4[0].node().name(), STR("foo"));
xpath_node_set copy5;
copy5 = set;
copy5 = empty;
CHECK(copy5.size() == 0);
}
TEST(xpath_api_nodeset_copy_empty)
{
xpath_node_set set;
xpath_node_set set2 = set;
xpath_node_set set3;
set3 = set;
}
TEST_XML(xpath_api_evaluate, "<node attr='3'/>")
{
xpath_query q(STR("node/@attr"));
CHECK(q.evaluate_boolean(doc));
CHECK(q.evaluate_number(doc) == 3);
char_t string[3];
CHECK(q.evaluate_string(string, 3, doc) == 2 && string[0] == '3' && string[1] == 0);
#ifndef PUGIXML_NO_STL
CHECK(q.evaluate_string(doc) == STR("3"));
#endif
xpath_node_set ns = q.evaluate_node_set(doc);
CHECK(ns.size() == 1 && ns[0].attribute() == doc.child(STR("node")).attribute(STR("attr")));
xpath_node nr = q.evaluate_node(doc);
CHECK(nr.attribute() == doc.child(STR("node")).attribute(STR("attr")));
}
TEST_XML(xpath_api_evaluate_attr, "<node attr='3'/>")
{
xpath_query q(STR("."));
xpath_node n(doc.child(STR("node")).attribute(STR("attr")), doc.child(STR("node")));
CHECK(q.evaluate_boolean(n));
CHECK(q.evaluate_number(n) == 3);
char_t string[3];
CHECK(q.evaluate_string(string, 3, n) == 2 && string[0] == '3' && string[1] == 0);
#ifndef PUGIXML_NO_STL
CHECK(q.evaluate_string(n) == STR("3"));
#endif
xpath_node_set ns = q.evaluate_node_set(n);
CHECK(ns.size() == 1 && ns[0] == n);
xpath_node nr = q.evaluate_node(n);
CHECK(nr == n);
}
#ifdef PUGIXML_NO_EXCEPTIONS
TEST_XML(xpath_api_evaluate_fail, "<node attr='3'/>")
{
xpath_query q(STR(""));
CHECK(q.evaluate_boolean(doc) == false);
CHECK_DOUBLE_NAN(q.evaluate_number(doc));
CHECK(q.evaluate_string(0, 0, doc) == 1); // null terminator
#ifndef PUGIXML_NO_STL
CHECK(q.evaluate_string(doc).empty());
#endif
CHECK(q.evaluate_node_set(doc).empty());
CHECK(!q.evaluate_node(doc));
}
#endif
TEST(xpath_api_evaluate_node_set_fail)
{
xpath_query q(STR("1"));
#ifdef PUGIXML_NO_EXCEPTIONS
CHECK(q.evaluate_node_set(xml_node()).empty());
#else
try
{
q.evaluate_node_set(xml_node());
CHECK_FORCE_FAIL("Expected exception");
}
catch (const xpath_exception&)
{
}
#endif
}
TEST(xpath_api_evaluate_node_fail)
{
xpath_query q(STR("1"));
#ifdef PUGIXML_NO_EXCEPTIONS
CHECK(!q.evaluate_node(xml_node()));
#else
try
{
q.evaluate_node(xml_node());
CHECK_FORCE_FAIL("Expected exception");
}
catch (const xpath_exception&)
{
}
#endif
}
TEST(xpath_api_evaluate_string)
{
xpath_query q(STR("\"0123456789\""));
std::basic_string<char_t> base = STR("xxxxxxxxxxxxxxxx");
// test for enough space
std::basic_string<char_t> s0 = base;
CHECK(q.evaluate_string(&s0[0], 16, xml_node()) == 11 && memcmp(&s0[0], STR("0123456789\0xxxxx"), 16 * sizeof(char_t)) == 0);
// test for just enough space
std::basic_string<char_t> s1 = base;
CHECK(q.evaluate_string(&s1[0], 11, xml_node()) == 11 && memcmp(&s1[0], STR("0123456789\0xxxxx"), 16 * sizeof(char_t)) == 0);
// test for just not enough space
std::basic_string<char_t> s2 = base;
CHECK(q.evaluate_string(&s2[0], 10, xml_node()) == 11 && memcmp(&s2[0], STR("012345678\0xxxxxx"), 16 * sizeof(char_t)) == 0);
// test for not enough space
std::basic_string<char_t> s3 = base;
CHECK(q.evaluate_string(&s3[0], 5, xml_node()) == 11 && memcmp(&s3[0], STR("0123\0xxxxxxxxxxx"), 16 * sizeof(char_t)) == 0);
// test for single character buffer
std::basic_string<char_t> s4 = base;
CHECK(q.evaluate_string(&s4[0], 1, xml_node()) == 11 && memcmp(&s4[0], STR("\0xxxxxxxxxxxxxxx"), 16 * sizeof(char_t)) == 0);
// test for empty buffer
std::basic_string<char_t> s5 = base;
CHECK(q.evaluate_string(&s5[0], 0, xml_node()) == 11 && memcmp(&s5[0], STR("xxxxxxxxxxxxxxxx"), 16 * sizeof(char_t)) == 0);
CHECK(q.evaluate_string(0, 0, xml_node()) == 11);
}
TEST(xpath_api_return_type)
{
#ifdef PUGIXML_NO_EXCEPTIONS
CHECK(xpath_query(STR("")).return_type() == xpath_type_none);
#endif
CHECK(xpath_query(STR("node")).return_type() == xpath_type_node_set);
CHECK(xpath_query(STR("1")).return_type() == xpath_type_number);
CHECK(xpath_query(STR("'s'")).return_type() == xpath_type_string);
CHECK(xpath_query(STR("true()")).return_type() == xpath_type_boolean);
}
TEST(xpath_api_query_bool)
{
xpath_query q(STR("node"));
CHECK(q);
CHECK((!q) == false);
}
#ifdef PUGIXML_NO_EXCEPTIONS
TEST(xpath_api_query_bool_fail)
{
xpath_query q(STR(""));
CHECK((q ? true : false) == false);
CHECK((!q) == true);
}
#endif
TEST(xpath_api_query_result)
{
xpath_query q(STR("node"));
CHECK(q.result());
CHECK(q.result().error == 0);
CHECK(q.result().offset == 0);
CHECK(strcmp(q.result().description(), "No error") == 0);
}
TEST(xpath_api_query_result_fail)
{
#ifndef PUGIXML_NO_EXCEPTIONS
try
{
#endif
xpath_query q(STR("//foo/child::/bar"));
#ifndef PUGIXML_NO_EXCEPTIONS
CHECK_FORCE_FAIL("Expected exception");
}
catch (const xpath_exception& q)
{
#endif
xpath_parse_result result = q.result();
CHECK(!result);
CHECK(result.error != 0 && result.error[0] != 0);
CHECK(result.description() == result.error);
CHECK(result.offset == 13);
#ifndef PUGIXML_NO_EXCEPTIONS
}
#endif
}
#ifndef PUGIXML_NO_EXCEPTIONS
TEST(xpath_api_exception_what)
{
try
{
xpath_query q(STR(""));
CHECK_FORCE_FAIL("Expected exception");
}
catch (const xpath_exception& e)
{
CHECK(e.what()[0] != 0);
}
}
#endif
TEST(xpath_api_node_set_ctor_out_of_memory)
{
test_runner::_memory_fail_threshold = 1;
xpath_node data[2];
CHECK_ALLOC_FAIL(xpath_node_set ns(data, data + 2));
}
TEST(xpath_api_node_set_copy_ctor_out_of_memory)
{
xpath_node data[2];
xpath_node_set ns(data, data + 2);
test_runner::_memory_fail_threshold = 1;
CHECK_ALLOC_FAIL(xpath_node_set copy = ns);
}
TEST_XML(xpath_api_node_set_assign_out_of_memory_preserve, "<node><a/><b/></node>")
{
xpath_node_set ns = doc.select_nodes(STR("node/*"));
CHECK(ns.size() == 2);
CHECK(ns.type() == xpath_node_set::type_sorted);
xpath_node_set nsall = doc.select_nodes(STR("//*"));
nsall.sort(true);
CHECK(nsall.size() == 3);
CHECK(nsall.type() == xpath_node_set::type_sorted_reverse);
test_runner::_memory_fail_threshold = 1;
CHECK_ALLOC_FAIL(ns = nsall);
CHECK(ns.size() == 2);
CHECK(ns.type() == xpath_node_set::type_sorted);
CHECK(ns[0] == doc.child(STR("node")).child(STR("a")) && ns[1] == doc.child(STR("node")).child(STR("b")));
}
TEST(xpath_api_empty)
{
xml_node c;
xpath_query q;
CHECK(!q);
CHECK(!q.evaluate_boolean(c));
}
#ifdef PUGIXML_HAS_MOVE
TEST_XML(xpath_api_nodeset_move_ctor, "<node><foo/><foo/><bar/></node>")
{
xpath_node_set set = doc.select_nodes(STR("node/bar/preceding::*"));
CHECK(set.size() == 2);
CHECK(set.type() == xpath_node_set::type_sorted_reverse);
test_runner::_memory_fail_threshold = 1;
xpath_node_set move = std::move(set);
CHECK(set.size() == 0);
CHECK(set.type() == xpath_node_set::type_unsorted);
CHECK(move.size() == 2);
CHECK(move.type() == xpath_node_set::type_sorted_reverse);
CHECK(move[1] == doc.first_child().first_child());
}
TEST_XML(xpath_api_nodeset_move_ctor_single, "<node><foo/><foo/><bar/></node>")
{
xpath_node_set set = doc.select_nodes(STR("node/bar"));
CHECK(set.size() == 1);
CHECK(set.type() == xpath_node_set::type_sorted);
test_runner::_memory_fail_threshold = 1;
xpath_node_set move = std::move(set);
CHECK(set.size() == 0);
CHECK(set.type() == xpath_node_set::type_unsorted);
CHECK(move.size() == 1);
CHECK(move.type() == xpath_node_set::type_sorted);
CHECK(move[0] == doc.first_child().last_child());
}
TEST(xpath_api_nodeset_move_ctor_empty)
{
xpath_node_set set;
set.sort();
CHECK(set.size() == 0);
CHECK(set.type() == xpath_node_set::type_sorted);
test_runner::_memory_fail_threshold = 1;
xpath_node_set move = std::move(set);
CHECK(set.size() == 0);
CHECK(set.type() == xpath_node_set::type_unsorted);
CHECK(move.size() == 0);
CHECK(move.type() == xpath_node_set::type_sorted);
}
TEST_XML(xpath_api_nodeset_move_assign, "<node><foo/><foo/><bar/></node>")
{
xpath_node_set set = doc.select_nodes(STR("node/bar/preceding::*"));
CHECK(set.size() == 2);
CHECK(set.type() == xpath_node_set::type_sorted_reverse);
test_runner::_memory_fail_threshold = 1;
xpath_node_set move;
CHECK(move.size() == 0);
CHECK(move.type() == xpath_node_set::type_unsorted);
move = std::move(set);
CHECK(set.size() == 0);
CHECK(set.type() == xpath_node_set::type_unsorted);
CHECK(move.size() == 2);
CHECK(move.type() == xpath_node_set::type_sorted_reverse);
CHECK(move[1] == doc.first_child().first_child());
}
TEST_XML(xpath_api_nodeset_move_assign_destroy, "<node><foo/><foo/><bar/></node>")
{
xpath_node_set set = doc.select_nodes(STR("node/bar/preceding::*"));
CHECK(set.size() == 2);
CHECK(set.type() == xpath_node_set::type_sorted_reverse);
xpath_node_set all = doc.select_nodes(STR("//*"));
CHECK(all.size() == 4);
test_runner::_memory_fail_threshold = 1;
all = std::move(set);
CHECK(set.size() == 0);
CHECK(set.type() == xpath_node_set::type_unsorted);
CHECK(all.size() == 2);
CHECK(all.type() == xpath_node_set::type_sorted_reverse);
CHECK(all[1] == doc.first_child().first_child());
}
TEST_XML(xpath_api_nodeset_move_assign_single, "<node><foo/><foo/><bar/></node>")
{
xpath_node_set set = doc.select_nodes(STR("node/bar"));
CHECK(set.size() == 1);
CHECK(set.type() == xpath_node_set::type_sorted);
test_runner::_memory_fail_threshold = 1;
xpath_node_set move;
CHECK(move.size() == 0);
CHECK(move.type() == xpath_node_set::type_unsorted);
move = std::move(set);
CHECK(set.size() == 0);
CHECK(set.type() == xpath_node_set::type_unsorted);
CHECK(move.size() == 1);
CHECK(move.type() == xpath_node_set::type_sorted);
CHECK(move[0] == doc.first_child().last_child());
}
TEST(xpath_api_nodeset_move_assign_empty)
{
xpath_node_set set;
set.sort();
CHECK(set.size() == 0);
CHECK(set.type() == xpath_node_set::type_sorted);
test_runner::_memory_fail_threshold = 1;
xpath_node_set move;
CHECK(move.size() == 0);
CHECK(move.type() == xpath_node_set::type_unsorted);
move = std::move(set);
CHECK(set.size() == 0);
CHECK(set.type() == xpath_node_set::type_unsorted);
CHECK(move.size() == 0);
CHECK(move.type() == xpath_node_set::type_sorted);
}
TEST_XML(xpath_api_nodeset_move_assign_self, "<node><foo/><foo/><bar/></node>")
{
xpath_node_set set = doc.select_nodes(STR("node/bar"));
CHECK(set.size() == 1);
CHECK(set.type() == xpath_node_set::type_sorted);
test_runner::_memory_fail_threshold = 1;
set = std::move(*&set);
}
TEST(xpath_api_query_move)
{
xml_node c;
xpath_query q1(STR("true()"));
xpath_query q4(STR("true() and false()"));
test_runner::_memory_fail_threshold = 1;
CHECK(q1);
CHECK(q1.evaluate_boolean(c));
xpath_query q2 = std::move(q1);
CHECK(!q1);
CHECK(!q1.evaluate_boolean(c));
CHECK(q2);
CHECK(q2.evaluate_boolean(c));
xpath_query q3;
CHECK(!q3);
CHECK(!q3.evaluate_boolean(c));
q3 = std::move(q2);
CHECK(!q2);
CHECK(!q2.evaluate_boolean(c));
CHECK(q3);
CHECK(q3.evaluate_boolean(c));
CHECK(q4);
CHECK(!q4.evaluate_boolean(c));
q4 = std::move(q3);
CHECK(!q3);
CHECK(!q3.evaluate_boolean(c));
CHECK(q4);
CHECK(q4.evaluate_boolean(c));
q4 = std::move(*&q4);
CHECK(q4);
CHECK(q4.evaluate_boolean(c));
}
TEST(xpath_api_query_vector)
{
std::vector<xpath_query> qv;
for (int i = 0; i < 10; ++i)
{
char_t expr[2];
expr[0] = char_t('0' + i);
expr[1] = 0;
qv.push_back(xpath_query(expr));
}
double result = 0;
for (size_t i = 0; i < qv.size(); ++i)
result += qv[i].evaluate_number(xml_node());
CHECK(result == 45);
}
#endif
#endif

View File

@ -0,0 +1,844 @@
#ifndef PUGIXML_NO_XPATH
#include "test.hpp"
#include <string>
using namespace pugi;
TEST_XML(xpath_number_number, "<node>123</node>")
{
xml_node c;
xml_node n = doc.child(STR("node")).first_child();
// number with 0 arguments
CHECK_XPATH_NUMBER_NAN(c, STR("number()"));
CHECK_XPATH_NUMBER(n, STR("number()"), 123);
// number with 1 string argument
CHECK_XPATH_NUMBER(c, STR("number(' -123.456 ')"), -123.456);
CHECK_XPATH_NUMBER(c, STR("number(' -123.')"), -123);
CHECK_XPATH_NUMBER(c, STR("number('123.')"), 123);
CHECK_XPATH_NUMBER(c, STR("number('.56')"), 0.56);
CHECK_XPATH_NUMBER(c, STR("number('123 ')"), 123);
CHECK_XPATH_NUMBER_NAN(c, STR("number('foobar')"));
CHECK_XPATH_NUMBER_NAN(c, STR("number('f1')"));
CHECK_XPATH_NUMBER_NAN(c, STR("number('1f')"));
CHECK_XPATH_NUMBER_NAN(c, STR("number('1.f')"));
CHECK_XPATH_NUMBER_NAN(c, STR("number('1.0f')"));
CHECK_XPATH_NUMBER_NAN(c, STR("number('123 f')"));
CHECK_XPATH_NUMBER_NAN(c, STR("number('')"));
CHECK_XPATH_NUMBER_NAN(c, STR("number('.')"));
// number with 1 bool argument
CHECK_XPATH_NUMBER(c, STR("number(true())"), 1);
CHECK_XPATH_NUMBER(c, STR("number(false())"), 0);
// number with 1 node set argument
CHECK_XPATH_NUMBER(n, STR("number(.)"), 123);
// number with 1 number argument
CHECK_XPATH_NUMBER(c, STR("number(1)"), 1);
// number with 2 arguments
CHECK_XPATH_FAIL(STR("number(1, 2)"));
}
TEST_XML(xpath_number_sum, "<node>123<child>789</child></node><node/>")
{
xml_node c;
xml_node n = doc.child(STR("node"));
// sum with 0 arguments
CHECK_XPATH_FAIL(STR("sum()"));
// sum with 1 argument
CHECK_XPATH_NUMBER(c, STR("sum(.)"), 0);
CHECK_XPATH_NUMBER(n, STR("sum(.)"), 123789); // 123 .. 789
CHECK_XPATH_NUMBER(n, STR("sum(./descendant-or-self::node())"), 125490); // node + 123 + child + 789 = 123789 + 123 + 789 + 789 = 125490
CHECK_XPATH_NUMBER(n, STR("sum(.//node())"), 1701); // 123 + child + 789 = 123 + 789 + 789
CHECK_XPATH_NUMBER_NAN(doc.last_child(), STR("sum(.)"));
// sum with 2 arguments
CHECK_XPATH_FAIL(STR("sum(1, 2)"));
// sum with 1 non-node-set argument
CHECK_XPATH_FAIL(STR("sum(1)"));
}
TEST(xpath_number_floor)
{
xml_node c;
// floor with 0 arguments
CHECK_XPATH_FAIL(STR("floor()"));
// floor with 1 argument
CHECK_XPATH_NUMBER(c, STR("floor(0)"), 0);
CHECK_XPATH_NUMBER(c, STR("floor(1.2)"), 1);
CHECK_XPATH_NUMBER(c, STR("floor(1)"), 1);
CHECK_XPATH_NUMBER(c, STR("floor(-1.2)"), -2);
CHECK_XPATH_NUMBER_NAN(c, STR("floor(string('nan'))"));
CHECK_XPATH_STRING(c, STR("string(floor(1 div 0))"), STR("Infinity"));
CHECK_XPATH_STRING(c, STR("string(floor(-1 div 0))"), STR("-Infinity"));
// floor with 2 arguments
CHECK_XPATH_FAIL(STR("floor(1, 2)"));
// floor with argument 0 should return 0
CHECK_XPATH_STRING(c, STR("string(1 div floor(0))"), STR("Infinity"));
// floor with argument -0 should return -0
#if !(defined(__APPLE__) && defined(__MACH__)) // MacOS X gcc 4.0.1 implements floor incorrectly (floor never returns -0)
CHECK_XPATH_STRING(c, STR("string(1 div floor(-0))"), STR("-Infinity"));
#endif
}
TEST(xpath_number_ceiling)
{
xml_node c;
// ceiling with 0 arguments
CHECK_XPATH_FAIL(STR("ceiling()"));
// ceiling with 1 argument
CHECK_XPATH_NUMBER(c, STR("ceiling(0)"), 0);
CHECK_XPATH_NUMBER(c, STR("ceiling(1.2)"), 2);
CHECK_XPATH_NUMBER(c, STR("ceiling(1)"), 1);
CHECK_XPATH_NUMBER(c, STR("ceiling(-1.2)"), -1);
CHECK_XPATH_NUMBER_NAN(c, STR("ceiling(string('nan'))"));
CHECK_XPATH_STRING(c, STR("string(ceiling(1 div 0))"), STR("Infinity"));
CHECK_XPATH_STRING(c, STR("string(ceiling(-1 div 0))"), STR("-Infinity"));
// ceiling with 2 arguments
CHECK_XPATH_FAIL(STR("ceiling(1, 2)"));
// ceiling with argument 0 should return 0
CHECK_XPATH_STRING(c, STR("string(1 div ceiling(0))"), STR("Infinity"));
// ceiling with argument in range (-1, -0] should result in minus zero
#if !(defined(__APPLE__) && defined(__MACH__)) && !defined(__CLR_VER) // MacOS X gcc 4.0.1 and x64 CLR implement ceil incorrectly (ceil never returns -0)
CHECK_XPATH_STRING(c, STR("string(1 div ceiling(-0))"), STR("-Infinity"));
CHECK_XPATH_STRING(c, STR("string(1 div ceiling(-0.1))"), STR("-Infinity"));
#endif
}
TEST(xpath_number_round)
{
xml_node c;
// round with 0 arguments
CHECK_XPATH_FAIL(STR("round()"));
// round with 1 argument
CHECK_XPATH_NUMBER(c, STR("round(1.2)"), 1);
CHECK_XPATH_NUMBER(c, STR("round(1.5)"), 2);
CHECK_XPATH_NUMBER(c, STR("round(1.8)"), 2);
CHECK_XPATH_NUMBER(c, STR("round(1)"), 1);
CHECK_XPATH_NUMBER(c, STR("round(-1.2)"), -1);
CHECK_XPATH_NUMBER(c, STR("round(-1.5)"), -1);
CHECK_XPATH_NUMBER(c, STR("round(-1.6)"), -2);
CHECK_XPATH_NUMBER_NAN(c, STR("round(string('nan'))"));
CHECK_XPATH_STRING(c, STR("string(round(1 div 0))"), STR("Infinity"));
CHECK_XPATH_STRING(c, STR("string(round(-1 div 0))"), STR("-Infinity"));
// round with 2 arguments
CHECK_XPATH_FAIL(STR("round(1, 2)"));
// round with argument in range [-0.5, -0] should result in minus zero
CHECK_XPATH_STRING(c, STR("string(1 div round(0))"), STR("Infinity"));
#if !(defined(__APPLE__) && defined(__MACH__)) && !defined(__CLR_VER) // MacOS X gcc 4.0.1 and x64 CLR implement ceil incorrectly (ceil never returns -0)
CHECK_XPATH_STRING(c, STR("string(1 div round(-0.5))"), STR("-Infinity"));
CHECK_XPATH_STRING(c, STR("string(1 div round(-0))"), STR("-Infinity"));
CHECK_XPATH_STRING(c, STR("string(1 div round(-0.1))"), STR("-Infinity"));
#endif
}
TEST_XML(xpath_boolean_boolean, "<node />")
{
xml_node c;
// boolean with 0 arguments
CHECK_XPATH_FAIL(STR("boolean()"));
// boolean with 1 number argument
CHECK_XPATH_BOOLEAN(c, STR("boolean(0)"), false);
CHECK_XPATH_BOOLEAN(c, STR("boolean(1)"), true);
CHECK_XPATH_BOOLEAN(c, STR("boolean(-1)"), true);
CHECK_XPATH_BOOLEAN(c, STR("boolean(0.1)"), true);
CHECK_XPATH_BOOLEAN(c, STR("boolean(number('nan'))"), false);
// boolean with 1 string argument
CHECK_XPATH_BOOLEAN(c, STR("boolean('x')"), true);
CHECK_XPATH_BOOLEAN(c, STR("boolean('')"), false);
// boolean with 1 node set argument
CHECK_XPATH_BOOLEAN(c, STR("boolean(.)"), false);
CHECK_XPATH_BOOLEAN(doc, STR("boolean(.)"), true);
CHECK_XPATH_BOOLEAN(doc, STR("boolean(foo)"), false);
// boolean with 2 arguments
CHECK_XPATH_FAIL(STR("boolean(1, 2)"));
}
TEST(xpath_boolean_not)
{
xml_node c;
// not with 0 arguments
CHECK_XPATH_FAIL(STR("not()"));
// not with 1 argument
CHECK_XPATH_BOOLEAN(c, STR("not(true())"), false);
CHECK_XPATH_BOOLEAN(c, STR("not(false())"), true);
// boolean with 2 arguments
CHECK_XPATH_FAIL(STR("not(1, 2)"));
}
TEST(xpath_boolean_true)
{
xml_node c;
// true with 0 arguments
CHECK_XPATH_BOOLEAN(c, STR("true()"), true);
// true with 1 argument
CHECK_XPATH_FAIL(STR("true(1)"));
}
TEST(xpath_boolean_false)
{
xml_node c;
// false with 0 arguments
CHECK_XPATH_BOOLEAN(c, STR("false()"), false);
// false with 1 argument
CHECK_XPATH_FAIL(STR("false(1)"));
}
TEST_XML(xpath_boolean_lang, "<node xml:lang='en'><child xml:lang='zh-UK'><subchild attr=''/></child></node><foo><bar/></foo>")
{
xml_node c;
// lang with 0 arguments
CHECK_XPATH_FAIL(STR("lang()"));
// lang with 1 argument, no language
CHECK_XPATH_BOOLEAN(c, STR("lang('en')"), false);
CHECK_XPATH_BOOLEAN(doc.child(STR("foo")), STR("lang('en')"), false);
CHECK_XPATH_BOOLEAN(doc.child(STR("foo")), STR("lang('')"), false);
CHECK_XPATH_BOOLEAN(doc.child(STR("foo")).child(STR("bar")), STR("lang('en')"), false);
// lang with 1 argument, same language/prefix
CHECK_XPATH_BOOLEAN(doc.child(STR("node")), STR("lang('en')"), true);
CHECK_XPATH_BOOLEAN(doc.child(STR("node")).child(STR("child")), STR("lang('zh-uk')"), true);
CHECK_XPATH_BOOLEAN(doc.child(STR("node")).child(STR("child")), STR("lang('zh')"), true);
CHECK_XPATH_BOOLEAN(doc.child(STR("node")).child(STR("child")).child(STR("subchild")), STR("lang('zh')"), true);
CHECK_XPATH_BOOLEAN(doc.child(STR("node")).child(STR("child")).child(STR("subchild")), STR("lang('ZH')"), true);
// lang with 1 argument, different language/prefix
CHECK_XPATH_BOOLEAN(doc.child(STR("node")), STR("lang('')"), false);
CHECK_XPATH_BOOLEAN(doc.child(STR("node")), STR("lang('e')"), false);
CHECK_XPATH_BOOLEAN(doc.child(STR("node")).child(STR("child")), STR("lang('en')"), false);
CHECK_XPATH_BOOLEAN(doc.child(STR("node")).child(STR("child")), STR("lang('zh-gb')"), false);
CHECK_XPATH_BOOLEAN(doc.child(STR("node")).child(STR("child")), STR("lang('r')"), false);
CHECK_XPATH_BOOLEAN(doc.child(STR("node")).child(STR("child")).child(STR("subchild")), STR("lang('en')"), false);
// lang with 1 attribute argument
CHECK_XPATH_NODESET(doc, STR("//@*[lang('en')]"));
// lang with 2 arguments
CHECK_XPATH_FAIL(STR("lang(1, 2)"));
}
TEST_XML(xpath_string_string, "<node>123<child id='1'>789</child><child><subchild><![CDATA[200]]></subchild></child>100</node>")
{
xml_node c;
xml_node n = doc.child(STR("node"));
// string with 0 arguments
CHECK_XPATH_STRING(c, STR("string()"), STR(""));
CHECK_XPATH_STRING(n.child(STR("child")), STR("string()"), STR("789"));
// string with 1 node-set argument
CHECK_XPATH_STRING(n, STR("string(child)"), STR("789"));
CHECK_XPATH_STRING(n, STR("string(child/@id)"), STR("1"));
CHECK_XPATH_STRING(n, STR("string(.)"), STR("123789200100"));
// string with 1 number argument
CHECK_XPATH_STRING(c, STR("string(0 div 0)"), STR("NaN"));
CHECK_XPATH_STRING(c, STR("string(0)"), STR("0"));
CHECK_XPATH_STRING(c, STR("string(-0)"), STR("0"));
CHECK_XPATH_STRING(c, STR("string(1 div 0)"), STR("Infinity"));
CHECK_XPATH_STRING(c, STR("string(-1 div -0)"), STR("Infinity"));
CHECK_XPATH_STRING(c, STR("string(-1 div 0)"), STR("-Infinity"));
CHECK_XPATH_STRING(c, STR("string(1 div -0)"), STR("-Infinity"));
CHECK_XPATH_STRING(c, STR("string(1234567)"), STR("1234567"));
CHECK_XPATH_STRING(c, STR("string(-1234567)"), STR("-1234567"));
CHECK_XPATH_STRING(c, STR("string(1234.5678)"), STR("1234.5678"));
CHECK_XPATH_STRING(c, STR("string(-1234.5678)"), STR("-1234.5678"));
CHECK_XPATH_STRING(c, STR("string(0.5678)"), STR("0.5678"));
CHECK_XPATH_STRING(c, STR("string(-0.5678)"), STR("-0.5678"));
CHECK_XPATH_STRING(c, STR("string(0.0)"), STR("0"));
CHECK_XPATH_STRING(c, STR("string(-0.0)"), STR("0"));
// string with 1 boolean argument
CHECK_XPATH_STRING(c, STR("string(true())"), STR("true"));
CHECK_XPATH_STRING(c, STR("string(false())"), STR("false"));
// string with 1 string argument
CHECK_XPATH_STRING(c, STR("string('abc')"), STR("abc"));
// string with 2 arguments
CHECK_XPATH_FAIL(STR("string(1, 2)"));
}
TEST(xpath_string_concat)
{
xml_node c;
// concat with 0 arguments
CHECK_XPATH_FAIL(STR("concat()"));
// concat with 1 argument
CHECK_XPATH_FAIL(STR("concat('')"));
// concat with exactly 2 arguments
CHECK_XPATH_STRING(c, STR("concat('prev','next')"), STR("prevnext"));
CHECK_XPATH_STRING(c, STR("concat('','next')"), STR("next"));
CHECK_XPATH_STRING(c, STR("concat('prev','')"), STR("prev"));
// concat with 3 or more arguments
CHECK_XPATH_STRING(c, STR("concat('a', 'b', 'c')"), STR("abc"));
CHECK_XPATH_STRING(c, STR("concat('a', 'b', 'c', 'd')"), STR("abcd"));
CHECK_XPATH_STRING(c, STR("concat('a', 'b', 'c', 'd', 'e')"), STR("abcde"));
CHECK_XPATH_STRING(c, STR("concat('a', 'b', 'c', 'd', 'e', 'f')"), STR("abcdef"));
CHECK_XPATH_STRING(c, STR("concat('a', 'b', 'c', 'd', 'e', 'f', 'g')"), STR("abcdefg"));
CHECK_XPATH_STRING(c, STR("concat(1, 2, 3, 4, 5, 6, 7, 8)"), STR("12345678"));
}
TEST(xpath_string_starts_with)
{
xml_node c;
// starts-with with 0 arguments
CHECK_XPATH_FAIL(STR("starts-with()"));
// starts-with with 1 argument
CHECK_XPATH_FAIL(STR("starts-with('a')"));
// starts-with with 2 arguments
CHECK_XPATH_BOOLEAN(c, STR("starts-with('abc', '')"), true);
CHECK_XPATH_BOOLEAN(c, STR("starts-with('abc', 'a')"), true);
CHECK_XPATH_BOOLEAN(c, STR("starts-with('abc', 'abc')"), true);
CHECK_XPATH_BOOLEAN(c, STR("starts-with('abc', 'abcd')"), false);
CHECK_XPATH_BOOLEAN(c, STR("starts-with('bc', 'c')"), false);
CHECK_XPATH_BOOLEAN(c, STR("starts-with('', 'c')"), false);
CHECK_XPATH_BOOLEAN(c, STR("starts-with('', '')"), true);
// starts-with with 3 arguments
CHECK_XPATH_FAIL(STR("starts-with('a', 'b', 'c')"));
}
TEST(xpath_string_contains)
{
xml_node c;
// contains with 0 arguments
CHECK_XPATH_FAIL(STR("contains()"));
// contains with 1 argument
CHECK_XPATH_FAIL(STR("contains('a')"));
// contains with 2 arguments
CHECK_XPATH_BOOLEAN(c, STR("contains('abc', '')"), true);
CHECK_XPATH_BOOLEAN(c, STR("contains('abc', 'a')"), true);
CHECK_XPATH_BOOLEAN(c, STR("contains('abc', 'abc')"), true);
CHECK_XPATH_BOOLEAN(c, STR("contains('abcd', 'bc')"), true);
CHECK_XPATH_BOOLEAN(c, STR("contains('abc', 'abcd')"), false);
CHECK_XPATH_BOOLEAN(c, STR("contains('b', 'bc')"), false);
CHECK_XPATH_BOOLEAN(c, STR("contains('', 'c')"), false);
CHECK_XPATH_BOOLEAN(c, STR("contains('', '')"), true);
// contains with 3 arguments
CHECK_XPATH_FAIL(STR("contains('a', 'b', 'c')"));
}
TEST(xpath_string_substring_before)
{
xml_node c;
// substring-before with 0 arguments
CHECK_XPATH_FAIL(STR("substring-before()"));
// substring-before with 1 argument
CHECK_XPATH_FAIL(STR("substring-before('a')"));
// substring-before with 2 arguments
CHECK_XPATH_STRING(c, STR("substring-before('abc', 'abc')"), STR(""));
CHECK_XPATH_STRING(c, STR("substring-before('abc', 'a')"), STR(""));
CHECK_XPATH_STRING(c, STR("substring-before('abc', 'cd')"), STR(""));
CHECK_XPATH_STRING(c, STR("substring-before('abc', 'b')"), STR("a"));
CHECK_XPATH_STRING(c, STR("substring-before('abc', 'c')"), STR("ab"));
CHECK_XPATH_STRING(c, STR("substring-before('abc', '')"), STR(""));
CHECK_XPATH_STRING(c, STR("substring-before('', '')"), STR(""));
// substring-before with 2 arguments, from W3C standard
CHECK_XPATH_STRING(c, STR("substring-before(\"1999/04/01\",\"/\")"), STR("1999"));
// substring-before with 3 arguments
CHECK_XPATH_FAIL(STR("substring-before('a', 'b', 'c')"));
}
TEST(xpath_string_substring_after)
{
xml_node c;
// substring-after with 0 arguments
CHECK_XPATH_FAIL(STR("substring-after()"));
// substring-after with 1 argument
CHECK_XPATH_FAIL(STR("substring-after('a')"));
// substring-after with 2 arguments
CHECK_XPATH_STRING(c, STR("substring-after('abc', 'abc')"), STR(""));
CHECK_XPATH_STRING(c, STR("substring-after('abc', 'a')"), STR("bc"));
CHECK_XPATH_STRING(c, STR("substring-after('abc', 'cd')"), STR(""));
CHECK_XPATH_STRING(c, STR("substring-after('abc', 'b')"), STR("c"));
CHECK_XPATH_STRING(c, STR("substring-after('abc', 'c')"), STR(""));
CHECK_XPATH_STRING(c, STR("substring-after('abc', '')"), STR("abc"));
CHECK_XPATH_STRING(c, STR("substring-after('', '')"), STR(""));
// substring-before with 2 arguments, from W3C standard
CHECK_XPATH_STRING(c, STR("substring-after(\"1999/04/01\",\"/\")"), STR("04/01"));
CHECK_XPATH_STRING(c, STR("substring-after(\"1999/04/01\",\"19\")"), STR("99/04/01"));
// substring-after with 3 arguments
CHECK_XPATH_FAIL(STR("substring-after('a', 'b', 'c')"));
}
TEST_XML(xpath_string_substring_after_heap, "<node>foo<child/>bar</node>")
{
CHECK_XPATH_STRING(doc, STR("substring-after(node, 'fo')"), STR("obar"));
CHECK_XPATH_STRING(doc, STR("substring-after(node, 'fooba')"), STR("r"));
CHECK_XPATH_STRING(doc, STR("substring-after(node, 'foobar')"), STR(""));
}
TEST(xpath_string_substring)
{
xml_node c;
// substring with 0 arguments
CHECK_XPATH_FAIL(STR("substring()"));
// substring with 1 argument
CHECK_XPATH_FAIL(STR("substring('')"));
// substring with 2 arguments
CHECK_XPATH_STRING(c, STR("substring('abcd', 2)"), STR("bcd"));
CHECK_XPATH_STRING(c, STR("substring('abcd', 1)"), STR("abcd"));
CHECK_XPATH_STRING(c, STR("substring('abcd', 1.1)"), STR("abcd"));
CHECK_XPATH_STRING(c, STR("substring('abcd', 1.5)"), STR("bcd"));
CHECK_XPATH_STRING(c, STR("substring('abcd', 1.8)"), STR("bcd"));
CHECK_XPATH_STRING(c, STR("substring('abcd', 10)"), STR(""));
CHECK_XPATH_STRING(c, STR("substring('abcd', 0)"), STR("abcd"));
CHECK_XPATH_STRING(c, STR("substring('abcd', -100)"), STR("abcd"));
CHECK_XPATH_STRING(c, STR("substring('abcd', -1 div 0)"), STR("abcd"));
CHECK_XPATH_STRING(c, STR("substring('abcd', 1 div 0)"), STR(""));
CHECK_XPATH_STRING(c, STR("substring('abcd', 0 div 0)"), STR(""));
CHECK_XPATH_STRING(c, STR("substring('', 1)"), STR(""));
CHECK_XPATH_STRING(c, STR("substring('', 0)"), STR(""));
CHECK_XPATH_STRING(c, STR("substring(substring('internalexternalcorrect substring',9),9)"), STR("correct substring"));
// substring with 3 arguments
CHECK_XPATH_STRING(c, STR("substring('abcd', 2, 1)"), STR("b"));
CHECK_XPATH_STRING(c, STR("substring('abcd', 2, 2)"), STR("bc"));
CHECK_XPATH_STRING(c, STR("substring('abcd', 1, 0)"), STR(""));
CHECK_XPATH_STRING(c, STR("substring('abcd', 1, 0.4)"), STR(""));
CHECK_XPATH_STRING(c, STR("substring('abcd', 1, 0.5)"), STR("a"));
CHECK_XPATH_STRING(c, STR("substring('abcd', 10, -5)"), STR(""));
CHECK_XPATH_STRING(c, STR("substring('abcd', 0, -1)"), STR(""));
CHECK_XPATH_STRING(c, STR("substring('abcd', -100, 100)"), STR(""));
CHECK_XPATH_STRING(c, STR("substring('abcd', -100, 101)"), STR(""));
CHECK_XPATH_STRING(c, STR("substring('abcd', -100, 102)"), STR("a"));
CHECK_XPATH_STRING(c, STR("substring('abcd', -100, 103)"), STR("ab"));
CHECK_XPATH_STRING(c, STR("substring('abcd', -100, 104)"), STR("abc"));
CHECK_XPATH_STRING(c, STR("substring('abcd', -100, 105)"), STR("abcd"));
CHECK_XPATH_STRING(c, STR("substring('abcd', -100, 106)"), STR("abcd"));
CHECK_XPATH_STRING(c, STR("substring('abcd', -100, 1 div 0)"), STR("abcd"));
CHECK_XPATH_STRING(c, STR("substring('abcd', -1 div 0, 4)"), STR(""));
CHECK_XPATH_STRING(c, STR("substring('abcd', 1 div 0, 0 div 0)"), STR(""));
CHECK_XPATH_STRING(c, STR("substring('abcd', 0 div 0, 1)"), STR(""));
CHECK_XPATH_STRING(c, STR("substring('', 1, 2)"), STR(""));
CHECK_XPATH_STRING(c, STR("substring('', 0, 0)"), STR(""));
// substring with 3 arguments, from W3C standard
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(""));
// substring with 4 arguments
CHECK_XPATH_FAIL(STR("substring('', 1, 2, 3)"));
}
TEST_XML(xpath_string_substring_heap, "<node>foo<child/>bar</node>")
{
CHECK_XPATH_STRING(doc, STR("substring(node, 3)"), STR("obar"));
CHECK_XPATH_STRING(doc, STR("substring(node, 6)"), STR("r"));
CHECK_XPATH_STRING(doc, STR("substring(node, 7)"), STR(""));
}
TEST_XML(xpath_string_string_length, "<node>123</node>")
{
xml_node c;
xml_node n = doc.child(STR("node"));
// string-length with 0 arguments
CHECK_XPATH_NUMBER(c, STR("string-length()"), 0);
CHECK_XPATH_NUMBER(n, STR("string-length()"), 3);
// string-length with 1 argument
CHECK_XPATH_NUMBER(c, STR("string-length('')"), 0);
CHECK_XPATH_NUMBER(c, STR("string-length('a')"), 1);
CHECK_XPATH_NUMBER(c, STR("string-length('abcdef')"), 6);
// string-length with 2 arguments
CHECK_XPATH_FAIL(STR("string-length(1, 2)"));
}
TEST_XML_FLAGS(xpath_string_normalize_space, "<node> \t\r\rval1 \rval2\r\nval3\nval4\r\r</node>", parse_minimal)
{
xml_node c;
xml_node n = doc.child(STR("node"));
// normalize-space with 0 arguments
CHECK_XPATH_STRING(c, STR("normalize-space()"), STR(""));
CHECK_XPATH_STRING(n, STR("normalize-space()"), STR("val1 val2 val3 val4"));
// normalize-space with 1 argument
CHECK_XPATH_STRING(c, STR("normalize-space('')"), STR(""));
CHECK_XPATH_STRING(c, STR("normalize-space('abcd')"), STR("abcd"));
CHECK_XPATH_STRING(c, STR("normalize-space(' \r\nabcd')"), STR("abcd"));
CHECK_XPATH_STRING(c, STR("normalize-space('abcd \n\r')"), STR("abcd"));
CHECK_XPATH_STRING(c, STR("normalize-space('ab\r\n\tcd')"), STR("ab cd"));
CHECK_XPATH_STRING(c, STR("normalize-space('ab cd')"), STR("ab cd"));
CHECK_XPATH_STRING(c, STR("normalize-space('\07')"), STR("\07"));
// normalize-space with 2 arguments
CHECK_XPATH_FAIL(STR("normalize-space(1, 2)"));
}
TEST(xpath_string_translate)
{
xml_node c;
// translate with 0 arguments
CHECK_XPATH_FAIL(STR("translate()"));
// translate with 1 argument
CHECK_XPATH_FAIL(STR("translate('a')"));
// translate with 2 arguments
CHECK_XPATH_FAIL(STR("translate('a', 'b')"));
// translate with 3 arguments
CHECK_XPATH_STRING(c, STR("translate('abc', '', '')"), STR("abc"));
CHECK_XPATH_STRING(c, STR("translate('abc', '', 'foo')"), STR("abc"));
CHECK_XPATH_STRING(c, STR("translate('abc', 'ab', 'ba')"), STR("bac"));
CHECK_XPATH_STRING(c, STR("translate('abc', 'ab', 'f')"), STR("fc"));
CHECK_XPATH_STRING(c, STR("translate('abc', 'aabb', '1234')"), STR("13c"));
CHECK_XPATH_STRING(c, STR("translate('', 'abc', 'bac')"), STR(""));
// translate with 3 arguments, from W3C standard
CHECK_XPATH_STRING(c, STR("translate('bar','abc','ABC')"), STR("BAr"));
CHECK_XPATH_STRING(c, STR("translate('--aaa--','abc-','ABC')"), STR("AAA"));
// translate with 4 arguments
CHECK_XPATH_FAIL(STR("translate('a', 'b', 'c', 'd')"));
}
TEST(xpath_string_translate_table)
{
xml_node c;
CHECK_XPATH_STRING(c, STR("translate('abcd\xe9 ', 'abc', 'ABC')"), STR("ABCd\xe9 "));
CHECK_XPATH_STRING(c, STR("translate('abcd\xe9 ', 'abc\xe9', 'ABC!')"), STR("ABCd! "));
CHECK_XPATH_STRING(c, STR("translate('abcd! ', 'abc!', 'ABC\xe9')"), STR("ABCd\xe9 "));
CHECK_XPATH_STRING(c, STR("translate('abcde', concat('abc', 'd'), 'ABCD')"), STR("ABCDe"));
CHECK_XPATH_STRING(c, STR("translate('abcde', 'abcd', concat('ABC', 'D'))"), STR("ABCDe"));
}
TEST(xpath_string_translate_remove)
{
xml_node c;
CHECK_XPATH_STRING(c, STR("translate('000000755', '0', '')"), STR("755"));
CHECK_XPATH_STRING(c, STR("translate('000000755', concat('0', ''), '')"), STR("755"));
}
TEST_XML(xpath_nodeset_last, "<node><c1/><c1/><c2/><c3/><c3/><c3/><c3/></node>")
{
xml_node n = doc.child(STR("node"));
// last with 0 arguments
CHECK_XPATH_NUMBER(n, STR("last()"), 1);
CHECK_XPATH_NODESET(n, STR("c1[last() = 1]"));
CHECK_XPATH_NODESET(n, STR("c1[last() = 2]")) % 3 % 4; // c1, c1
CHECK_XPATH_NODESET(n, STR("c2/preceding-sibling::node()[last() = 2]")) % 4 % 3; // c1, c1
// last with 1 argument
CHECK_XPATH_FAIL(STR("last(c)"));
}
TEST_XML(xpath_nodeset_position, "<node><c1/><c1/><c2/><c3/><c3/><c3/><c3/></node>")
{
xml_node n = doc.child(STR("node"));
// position with 0 arguments
CHECK_XPATH_NUMBER(n, STR("position()"), 1);
CHECK_XPATH_NODESET(n, STR("c1[position() = 0]"));
CHECK_XPATH_NODESET(n, STR("c1[position() = 1]")) % 3;
CHECK_XPATH_NODESET(n, STR("c1[position() = 2]")) % 4;
CHECK_XPATH_NODESET(n, STR("c1[position() = 3]"));
CHECK_XPATH_NODESET(n, STR("c2/preceding-sibling::node()[position() = 1]")) % 4;
CHECK_XPATH_NODESET(n, STR("c2/preceding-sibling::node()[position() = 2]")) % 3;
// position with 1 argument
CHECK_XPATH_FAIL(STR("position(c)"));
}
TEST_XML(xpath_nodeset_count, "<node><c1/><c1/><c2/><c3/><c3/><c3/><c3/></node>")
{
xml_node c;
xml_node n = doc.child(STR("node"));
// count with 0 arguments
CHECK_XPATH_FAIL(STR("count()"));
// count with 1 non-node-set argument
CHECK_XPATH_FAIL(STR("count(1)"));
CHECK_XPATH_FAIL(STR("count(true())"));
CHECK_XPATH_FAIL(STR("count('')"));
// count with 1 node-set argument
CHECK_XPATH_NUMBER(c, STR("count(.)"), 0);
CHECK_XPATH_NUMBER(n, STR("count(.)"), 1);
CHECK_XPATH_NUMBER(n, STR("count(c1)"), 2);
CHECK_XPATH_NUMBER(n, STR("count(c2)"), 1);
CHECK_XPATH_NUMBER(n, STR("count(c3)"), 4);
CHECK_XPATH_NUMBER(n, STR("count(c4)"), 0);
// count with 2 arguments
CHECK_XPATH_FAIL(STR("count(x, y)"));
}
TEST_XML(xpath_nodeset_id, "<node id='foo'/>")
{
xml_node n = doc.child(STR("node"));
// id with 0 arguments
CHECK_XPATH_FAIL(STR("id()"));
// id with 1 argument - no DTD => no id
CHECK_XPATH_NODESET(n, STR("id('foo')"));
// id with 2 arguments
CHECK_XPATH_FAIL(STR("id(1, 2)"));
}
TEST_XML_FLAGS(xpath_nodeset_local_name, "<node xmlns:foo='http://foo'><c1>text</c1><c2 xmlns:foo='http://foo2' foo:attr='value'><foo:child/></c2><c3 xmlns='http://def' attr='value'><child/></c3><c4><?target stuff?></c4></node>", parse_default | parse_pi)
{
xml_node c;
xml_node n = doc.child(STR("node"));
// local-name with 0 arguments
CHECK_XPATH_STRING(c, STR("local-name()"), STR(""));
CHECK_XPATH_STRING(n, STR("local-name()"), STR("node"));
// local-name with 1 non-node-set argument
CHECK_XPATH_FAIL(STR("local-name(1)"));
// local-name with 1 node-set argument
CHECK_XPATH_STRING(n, STR("local-name(c1)"), STR("c1"));
CHECK_XPATH_STRING(n, STR("local-name(c2/node())"), STR("child"));
CHECK_XPATH_STRING(n, STR("local-name(c2/attribute::node())"), STR("attr"));
CHECK_XPATH_STRING(n, STR("local-name(c1/node())"), STR(""));
CHECK_XPATH_STRING(n, STR("local-name(c4/node())"), STR("target"));
CHECK_XPATH_STRING(n, STR("local-name(c1/following-sibling::node())"), STR("c2"));
CHECK_XPATH_STRING(n, STR("local-name(c4/preceding-sibling::node())"), STR("c1"));
// local-name with 2 arguments
CHECK_XPATH_FAIL(STR("local-name(c1, c2)"));
}
TEST_XML_FLAGS(xpath_nodeset_namespace_uri, "<node xmlns:foo='http://foo'><c1>text</c1><c2 xmlns:foo='http://foo2' foo:attr='value'><foo:child/></c2><c3 xmlns='http://def' attr='value'><child/></c3><c4><?target stuff?></c4><c5><foo:child/></c5><c6 bar:attr=''/><c7><node foo:attr=''/></c7></node>", parse_default | parse_pi)
{
xml_node c;
xml_node n = doc.child(STR("node"));
// namespace-uri with 0 arguments
CHECK_XPATH_STRING(c, STR("namespace-uri()"), STR(""));
CHECK_XPATH_STRING(n.child(STR("c2")).child(STR("foo:child")), STR("namespace-uri()"), STR("http://foo2"));
// namespace-uri with 1 non-node-set argument
CHECK_XPATH_FAIL(STR("namespace-uri(1)"));
// namespace-uri with 1 node-set argument
CHECK_XPATH_STRING(n, STR("namespace-uri(c1)"), STR(""));
CHECK_XPATH_STRING(n, STR("namespace-uri(c5/child::node())"), STR("http://foo"));
CHECK_XPATH_STRING(n, STR("namespace-uri(c2/attribute::node())"), STR("http://foo2"));
CHECK_XPATH_STRING(n, STR("namespace-uri(c2/child::node())"), STR("http://foo2"));
CHECK_XPATH_STRING(n, STR("namespace-uri(c1/child::node())"), STR(""));
CHECK_XPATH_STRING(n, STR("namespace-uri(c4/child::node())"), STR(""));
CHECK_XPATH_STRING(n, STR("namespace-uri(c3)"), STR("http://def"));
CHECK_XPATH_STRING(n, STR("namespace-uri(c3/@attr)"), STR("")); // the namespace name for an unprefixed attribute name always has no value (Namespaces in XML 1.0)
CHECK_XPATH_STRING(n, STR("namespace-uri(c3/child::node())"), STR("http://def"));
CHECK_XPATH_STRING(n, STR("namespace-uri(c6/@bar:attr)"), STR(""));
CHECK_XPATH_STRING(n, STR("namespace-uri(c7/node/@foo:attr)"), STR("http://foo"));
// namespace-uri with 2 arguments
CHECK_XPATH_FAIL(STR("namespace-uri(c1, c2)"));
}
TEST_XML_FLAGS(xpath_nodeset_name, "<node xmlns:foo='http://foo'><c1>text</c1><c2 xmlns:foo='http://foo2' foo:attr='value'><foo:child/></c2><c3 xmlns='http://def' attr='value'><child/></c3><c4><?target stuff?></c4></node>", parse_default | parse_pi)
{
xml_node c;
xml_node n = doc.child(STR("node"));
// name with 0 arguments
CHECK_XPATH_STRING(c, STR("name()"), STR(""));
CHECK_XPATH_STRING(n, STR("name()"), STR("node"));
// name with 1 non-node-set argument
CHECK_XPATH_FAIL(STR("name(1)"));
// name with 1 node-set argument
CHECK_XPATH_STRING(n, STR("name(c1)"), STR("c1"));
CHECK_XPATH_STRING(n, STR("name(c2/node())"), STR("foo:child"));
CHECK_XPATH_STRING(n, STR("name(c2/attribute::node())"), STR("foo:attr"));
CHECK_XPATH_STRING(n, STR("name(c1/node())"), STR(""));
CHECK_XPATH_STRING(n, STR("name(c4/node())"), STR("target"));
CHECK_XPATH_STRING(n, STR("name(c1/following-sibling::node())"), STR("c2"));
CHECK_XPATH_STRING(n, STR("name(c4/preceding-sibling::node())"), STR("c1"));
// name with 2 arguments
CHECK_XPATH_FAIL(STR("name(c1, c2)"));
}
TEST(xpath_function_arguments)
{
xml_node c;
// conversion to string
CHECK_XPATH_NUMBER(c, STR("string-length(12)"), 2);
// conversion to number
CHECK_XPATH_NUMBER(c, STR("round('1.2')"), 1);
CHECK_XPATH_NUMBER(c, STR("round('1.7')"), 2);
// conversion to boolean
CHECK_XPATH_BOOLEAN(c, STR("not('1')"), false);
CHECK_XPATH_BOOLEAN(c, STR("not('')"), true);
// conversion to node set
CHECK_XPATH_FAIL(STR("sum(1)"));
// expression evaluation
CHECK_XPATH_NUMBER(c, STR("round((2 + 2 * 2) div 4)"), 2);
// empty expressions
CHECK_XPATH_FAIL(STR("round(,)"));
CHECK_XPATH_FAIL(STR("substring(,)"));
CHECK_XPATH_FAIL(STR("substring('a',)"));
CHECK_XPATH_FAIL(STR("substring(,'a')"));
// extra commas
CHECK_XPATH_FAIL(STR("round(,1)"));
CHECK_XPATH_FAIL(STR("round(1,)"));
// lack of commas
CHECK_XPATH_FAIL(STR("substring(1 2)"));
// whitespace after function name
CHECK_XPATH_BOOLEAN(c, STR("true ()"), true);
// too many arguments
CHECK_XPATH_FAIL(STR("round(1, 2, 3, 4, 5, 6)"));
}
TEST_XML_FLAGS(xpath_string_value, "<node><c1>pcdata</c1><c2><child/></c2><c3 attr='avalue'/><c4><?target pivalue?></c4><c5><!--comment--></c5><c6><![CDATA[cdata]]></c6></node>", parse_default | parse_pi | parse_comments)
{
xml_node c;
xml_node n = doc.child(STR("node"));
CHECK_XPATH_STRING(c, STR("string()"), STR(""));
CHECK_XPATH_STRING(doc, STR("string()"), STR("pcdatacdata"));
CHECK_XPATH_STRING(n, STR("string()"), STR("pcdatacdata"));
CHECK_XPATH_STRING(n, STR("string(c1/node())"), STR("pcdata"));
CHECK_XPATH_STRING(n, STR("string(c2/node())"), STR(""));
CHECK_XPATH_STRING(n, STR("string(c3/@attr)"), STR("avalue"));
CHECK_XPATH_STRING(n, STR("string(c4/node())"), STR("pivalue"));
CHECK_XPATH_STRING(n, STR("string(c5/node())"), STR("comment"));
CHECK_XPATH_STRING(n, STR("string(c6/node())"), STR("cdata"));
}
TEST(xpath_string_value_empty)
{
xml_document doc;
doc.append_child(node_pcdata).set_value(STR("head"));
doc.append_child(node_pcdata);
doc.append_child(node_pcdata).set_value(STR("tail"));
CHECK_XPATH_STRING(doc, STR("string()"), STR("headtail"));
}
TEST_XML(xpath_string_concat_translate, "<node>foobar</node>")
{
CHECK_XPATH_STRING(doc, STR("concat('a', 'b', 'c', translate(node, 'o', 'a'), 'd')"), STR("abcfaabard"));
}
TEST(xpath_unknown_functions)
{
char_t query[] = STR("a()");
for (char ch = 'a'; ch <= 'z'; ++ch)
{
query[0] = ch;
CHECK_XPATH_FAIL(query);
query[0] = char_t(ch - 32);
CHECK_XPATH_FAIL(query);
}
}
TEST(xpath_string_translate_table_out_of_memory)
{
xml_node c;
// our goal is to generate translate table OOM without generating query OOM
std::basic_string<char_t> query = STR("concat(");
size_t count = 20;
for (size_t i = 0; i < count; ++i)
{
if (i != 0) query += STR(",");
query += STR("translate('a','a','A')");
}
query += STR(")");
std::basic_string<char_t> result(count, 'A');
test_runner::_memory_fail_threshold = 5000;
CHECK_ALLOC_FAIL(CHECK_XPATH_STRING(c, query.c_str(), result.c_str()));
}
#endif

View File

@ -0,0 +1,566 @@
#ifndef PUGIXML_NO_XPATH
#include "test.hpp"
using namespace pugi;
TEST(xpath_operators_arithmetic)
{
xml_node c;
// incorrect unary operator
CHECK_XPATH_FAIL(STR("-"));
// correct unary operator
CHECK_XPATH_NUMBER(c, STR("-1"), -1);
CHECK_XPATH_NUMBER(c, STR("--1"), 1);
CHECK_XPATH_NUMBER(c, STR("---1"), -1);
// incorrect binary operators
CHECK_XPATH_FAIL(STR("5+"));
CHECK_XPATH_FAIL(STR("5-"));
CHECK_XPATH_FAIL(STR("5*"));
CHECK_XPATH_FAIL(STR("+5"));
CHECK_XPATH_FAIL(STR("*5"));
CHECK_XPATH_FAIL(STR("1div2"));
CHECK_XPATH_FAIL(STR("1mod"));
CHECK_XPATH_FAIL(STR("1div"));
// correct trivial binary operators
CHECK_XPATH_NUMBER(c, STR("1 + 2"), 3);
CHECK_XPATH_NUMBER(c, STR("1+2"), 3);
CHECK_XPATH_NUMBER(c, STR("1 * 2"), 2);
CHECK_XPATH_NUMBER(c, STR("1*2"), 2);
CHECK_XPATH_NUMBER(c, STR("1 div 2"), 0.5);
// operator precedence
CHECK_XPATH_NUMBER(c, STR("2 + 2 * 2 div 1 mod 3"), 3);
CHECK_XPATH_NUMBER(c, STR("2 + 2 * 2 div (1 mod 3)"), 6);
CHECK_XPATH_NUMBER(c, STR("(2 + 2) * 2 div (1 mod 3)"), 8);
CHECK_XPATH_NUMBER(c, STR("(2 + 2) * (2 div 1) mod 3"), 2);
CHECK_XPATH_NUMBER(c, STR("2 - -2"), 4);
CHECK_XPATH_NUMBER(c, STR("2 + -2"), 0);
CHECK_XPATH_NUMBER(c, STR("2--2"), 4);
CHECK_XPATH_NUMBER(c, STR("2+-2"), 0);
CHECK_XPATH_NUMBER(c, STR("1-2-3"), -4);
// mod, from W3C standard
CHECK_XPATH_NUMBER(c, STR("5 mod 2"), 1);
CHECK_XPATH_NUMBER(c, STR("5 mod -2"), 1);
CHECK_XPATH_NUMBER(c, STR("-5 mod 2"), -1);
CHECK_XPATH_NUMBER(c, STR("-5 mod -2"), -1);
}
TEST(xpath_operators_arithmetic_specials)
{
xml_node c;
// infinity/nan
CHECK_XPATH_STRING(c, STR("1 div 0"), STR("Infinity"));
CHECK_XPATH_STRING(c, STR("-1 div 0"), STR("-Infinity"));
CHECK_XPATH_STRING(c, STR("-1 div 0 + 1 div 0"), STR("NaN"));
CHECK_XPATH_STRING(c, STR("0 div 0"), STR("NaN"));
CHECK_XPATH_STRING(c, STR("1 div 0 + 1 div 0"), STR("Infinity"));
CHECK_XPATH_STRING(c, STR("-1 div 0 + -1 div 0"), STR("-Infinity"));
CHECK_XPATH_STRING(c, STR("1 div 0 + 100"), STR("Infinity"));
CHECK_XPATH_STRING(c, STR("-1 div 0 + 100"), STR("-Infinity"));
CHECK_XPATH_STRING(c, STR("0 div 0 + 100"), STR("NaN"));
// unary - and multiplication clarifications from recommendations errata
CHECK_XPATH_STRING(c, STR("1 div -0"), STR("-Infinity"));
CHECK_XPATH_STRING(c, STR("-1 div -0"), STR("Infinity"));
CHECK_XPATH_STRING(c, STR("1 div (-0 * 1)"), STR("-Infinity"));
CHECK_XPATH_STRING(c, STR("-1 div (0 * -1)"), STR("Infinity"));
CHECK_XPATH_STRING(c, STR("1 div (-0 div 1)"), STR("-Infinity"));
CHECK_XPATH_STRING(c, STR("-1 div (0 div -1)"), STR("Infinity"));
}
TEST_XML(xpath_operators_arithmetic_subtraction_parse, "<node><foo-bar>10</foo-bar><foo>2</foo><bar>3</bar></node>")
{
xml_node n = doc.child(STR("node"));
// correct subtraction parsing, from W3C standard
CHECK_XPATH_NUMBER(n, STR("foo-bar"), 10);
CHECK_XPATH_NUMBER(n, STR("foo -bar"), -1);
CHECK_XPATH_NUMBER(n, STR("foo - bar"), -1);
CHECK_XPATH_NUMBER(n, STR("-foo-bar"), -10);
CHECK_XPATH_NUMBER(n, STR("-foo -bar"), -5);
}
TEST(xpath_operators_logical)
{
xml_node c;
// boolean arithmetic
CHECK_XPATH_BOOLEAN(c, STR("true() or true()"), true);
CHECK_XPATH_BOOLEAN(c, STR("true() or false()"), true);
CHECK_XPATH_BOOLEAN(c, STR("false() or false()"), false);
CHECK_XPATH_BOOLEAN(c, STR("false() or true()"), true);
CHECK_XPATH_BOOLEAN(c, STR("true() and true()"), true);
CHECK_XPATH_BOOLEAN(c, STR("true() and false()"), false);
CHECK_XPATH_BOOLEAN(c, STR("false() and false()"), false);
CHECK_XPATH_BOOLEAN(c, STR("false() and true()"), false);
// boolean conversion
CHECK_XPATH_BOOLEAN(c, STR("1 or ''"), true);
CHECK_XPATH_BOOLEAN(c, STR("1 and ''"), false);
CHECK_XPATH_BOOLEAN(c, STR("0 or ''"), false);
CHECK_XPATH_BOOLEAN(c, STR("0 or 'a'"), true);
}
TEST(xpath_operators_equality_primitive_boolean)
{
xml_node c;
// boolean vs boolan
CHECK_XPATH_BOOLEAN(c, STR("true() = true()"), true);
CHECK_XPATH_BOOLEAN(c, STR("false() = false()"), true);
CHECK_XPATH_BOOLEAN(c, STR("true() != false()"), true);
CHECK_XPATH_BOOLEAN(c, STR("false() != false()"), false);
// upcast to boolean
CHECK_XPATH_BOOLEAN(c, STR("true() = 2"), true);
CHECK_XPATH_BOOLEAN(c, STR("true() != 2"), false);
CHECK_XPATH_BOOLEAN(c, STR("false() = 2"), false);
CHECK_XPATH_BOOLEAN(c, STR("false() != 2"), true);
CHECK_XPATH_BOOLEAN(c, STR("false() = 0"), true);
CHECK_XPATH_BOOLEAN(c, STR("false() != 0"), false);
CHECK_XPATH_BOOLEAN(c, STR("2 = true()"), true);
CHECK_XPATH_BOOLEAN(c, STR("2 != true()"), false);
CHECK_XPATH_BOOLEAN(c, STR("2 = false()"), false);
CHECK_XPATH_BOOLEAN(c, STR("2 != false()"), true);
CHECK_XPATH_BOOLEAN(c, STR("0 = false()"), true);
CHECK_XPATH_BOOLEAN(c, STR("0 != false()"), false);
}
TEST(xpath_operators_equality_primitive_number)
{
xml_node c;
// number vs number
CHECK_XPATH_BOOLEAN(c, STR("1 = 1"), true);
CHECK_XPATH_BOOLEAN(c, STR("0.5 = 0.5"), true);
CHECK_XPATH_BOOLEAN(c, STR("1 != 2"), true);
CHECK_XPATH_BOOLEAN(c, STR("1 = -1"), false);
// infinity/nan
CHECK_XPATH_BOOLEAN(c, STR("1 div 0 = 2 div 0"), true);
CHECK_XPATH_BOOLEAN(c, STR("-1 div 0 != 2 div 0"), true);
#ifndef MSVC6_NAN_BUG
CHECK_XPATH_BOOLEAN(c, STR("0 div 0 = 1"), false);
CHECK_XPATH_BOOLEAN(c, STR("0 div 0 != 1"), true);
CHECK_XPATH_BOOLEAN(c, STR("0 div 0 = 0 div 0"), false);
#endif
// upcast to number
CHECK_XPATH_BOOLEAN(c, STR("2 = '2'"), true);
CHECK_XPATH_BOOLEAN(c, STR("2 != '2'"), false);
CHECK_XPATH_BOOLEAN(c, STR("'1' != 2"), true);
CHECK_XPATH_BOOLEAN(c, STR("'1' = 2"), false);
}
TEST(xpath_operators_equality_primitive_string)
{
xml_node c;
// string vs string
CHECK_XPATH_BOOLEAN(c, STR("'a' = 'a'"), true);
CHECK_XPATH_BOOLEAN(c, STR("'a' = 'b'"), false);
CHECK_XPATH_BOOLEAN(c, STR("'ab' != 'a'"), true);
CHECK_XPATH_BOOLEAN(c, STR("'' != 'a'"), true);
CHECK_XPATH_BOOLEAN(c, STR("'a' != ''"), true);
CHECK_XPATH_BOOLEAN(c, STR("'' != ''"), false);
}
TEST_XML(xpath_operators_equality_node_set_node_set, "<node><c1><v>a</v><v>b</v></c1><c2><v>a</v><v>c</v></c2><c3><v>b</v></c3><c4><v>d</v></c4><c5><v>a</v><v>b</v></c5><c6><v>b</v></c6></node>")
{
xml_node c;
xml_node n = doc.child(STR("node"));
// node set vs node set
CHECK_XPATH_BOOLEAN(c, STR("x = x"), false); // empty node set compares as false with any other object via any comparison operator, as per XPath spec
CHECK_XPATH_BOOLEAN(c, STR("x != x"), false);
CHECK_XPATH_BOOLEAN(n, STR("c1/v = c2/v"), true);
CHECK_XPATH_BOOLEAN(n, STR("c1/v = c3/v"), true);
CHECK_XPATH_BOOLEAN(n, STR("c2/v = c3/v"), false);
CHECK_XPATH_BOOLEAN(n, STR("c1/v = c4/v"), false);
CHECK_XPATH_BOOLEAN(n, STR("c1/v = x"), false);
CHECK_XPATH_BOOLEAN(n, STR("x = c1"), false);
CHECK_XPATH_BOOLEAN(n, STR("c1/v != c2/v"), true);
CHECK_XPATH_BOOLEAN(n, STR("c1/v != c3/v"), true);
CHECK_XPATH_BOOLEAN(n, STR("c2/v != c3/v"), true);
CHECK_XPATH_BOOLEAN(n, STR("c1/v != c4/v"), true);
CHECK_XPATH_BOOLEAN(n, STR("c1/v != c5/v"), true); // (a, b) != (a, b), since a != b, as per XPath spec (comparison operators are so not intuitive)
CHECK_XPATH_BOOLEAN(n, STR("c3/v != c6/v"), false);
CHECK_XPATH_BOOLEAN(n, STR("c1/v != x"), false);
CHECK_XPATH_BOOLEAN(n, STR("x != c1/v"), false);
}
TEST_XML(xpath_operators_equality_node_set_primitive, "<node><c1><v>1</v><v>-1</v><v>100</v></c1><c2><v>1</v><v>nan</v></c2></node>")
{
xml_node c;
xml_node n = doc.child(STR("node"));
// node set vs number
CHECK_XPATH_BOOLEAN(c, STR("x = 1"), false);
CHECK_XPATH_BOOLEAN(c, STR("x != 1"), false);
CHECK_XPATH_BOOLEAN(c, STR("1 = x"), false);
CHECK_XPATH_BOOLEAN(c, STR("1 != x"), false);
CHECK_XPATH_BOOLEAN(n, STR("c1/v = 1"), true);
CHECK_XPATH_BOOLEAN(n, STR("c1/v = -1"), true);
CHECK_XPATH_BOOLEAN(n, STR("c1/v != 1"), true);
CHECK_XPATH_BOOLEAN(n, STR("c1/v = 5"), false);
CHECK_XPATH_BOOLEAN(n, STR("c2/v = 1"), true);
CHECK_XPATH_BOOLEAN(n, STR("1 = c1/v"), true);
CHECK_XPATH_BOOLEAN(n, STR("-1 = c1/v"), true);
CHECK_XPATH_BOOLEAN(n, STR("1 != c1/v"), true);
CHECK_XPATH_BOOLEAN(n, STR("5 = c1/v"), false);
CHECK_XPATH_BOOLEAN(n, STR("1 = c2/v"), true);
#ifndef MSVC6_NAN_BUG
CHECK_XPATH_BOOLEAN(n, STR("c2/v != 1"), true);
CHECK_XPATH_BOOLEAN(n, STR("1 != c2/v"), true);
#endif
// node set vs string
CHECK_XPATH_BOOLEAN(c, STR("x = '1'"), false);
CHECK_XPATH_BOOLEAN(c, STR("x != '1'"), false);
CHECK_XPATH_BOOLEAN(c, STR("'1' = x"), false);
CHECK_XPATH_BOOLEAN(c, STR("'1' != x"), false);
CHECK_XPATH_BOOLEAN(n, STR("c1/v = '1'"), true);
CHECK_XPATH_BOOLEAN(n, STR("c1/v = '-1'"), true);
CHECK_XPATH_BOOLEAN(n, STR("c1/v != '1'"), true);
CHECK_XPATH_BOOLEAN(n, STR("c1/v = '5'"), false);
CHECK_XPATH_BOOLEAN(n, STR("c2/v = '1'"), true);
CHECK_XPATH_BOOLEAN(n, STR("c2/v != '1'"), true);
CHECK_XPATH_BOOLEAN(n, STR("'1' = c1/v"), true);
CHECK_XPATH_BOOLEAN(n, STR("'-1' = c1/v"), true);
CHECK_XPATH_BOOLEAN(n, STR("'1' != c1/v"), true);
CHECK_XPATH_BOOLEAN(n, STR("'5' = c1/v"), false);
CHECK_XPATH_BOOLEAN(n, STR("'1' = c2/v"), true);
CHECK_XPATH_BOOLEAN(n, STR("'1' != c2/v"), true);
// node set vs almost-numeric string just in case
CHECK_XPATH_BOOLEAN(n, STR("c1/v = '1.0'"), false);
// node set vs boolean - special rules! empty sets are equal to true()
CHECK_XPATH_BOOLEAN(n, STR("x = true()"), false);
CHECK_XPATH_BOOLEAN(n, STR("x != true()"), true);
CHECK_XPATH_BOOLEAN(n, STR("x = false()"), true);
CHECK_XPATH_BOOLEAN(n, STR("c1/v = true()"), true);
CHECK_XPATH_BOOLEAN(n, STR("c1/v != true()"), false);
CHECK_XPATH_BOOLEAN(n, STR("c1/v = false()"), false);
CHECK_XPATH_BOOLEAN(n, STR("true() = x"), false);
CHECK_XPATH_BOOLEAN(n, STR("true() != x"), true);
CHECK_XPATH_BOOLEAN(n, STR("false() = x"), true);
CHECK_XPATH_BOOLEAN(n, STR("true() = c1/v"), true);
CHECK_XPATH_BOOLEAN(n, STR("true() != c1/v"), false);
CHECK_XPATH_BOOLEAN(n, STR("false() = c1/v"), false);
}
TEST(xpath_operators_inequality_primitive)
{
xml_node c;
// number vs number
CHECK_XPATH_BOOLEAN(c, STR("1 < 2"), true);
CHECK_XPATH_BOOLEAN(c, STR("1 <= 2"), true);
CHECK_XPATH_BOOLEAN(c, STR("1 > 2"), false);
CHECK_XPATH_BOOLEAN(c, STR("1 >= 2"), false);
CHECK_XPATH_BOOLEAN(c, STR("1 < 1"), false);
CHECK_XPATH_BOOLEAN(c, STR("1 <= 1"), true);
CHECK_XPATH_BOOLEAN(c, STR("1 > 1"), false);
CHECK_XPATH_BOOLEAN(c, STR("1 >= 1"), true);
// infinity/nan
CHECK_XPATH_BOOLEAN(c, STR("1 div 0 <= 2 div 0"), true);
CHECK_XPATH_BOOLEAN(c, STR("1 div 0 < 2 div 0"), false);
CHECK_XPATH_BOOLEAN(c, STR("-1 div 0 < 2 div 0"), true);
CHECK_XPATH_BOOLEAN(c, STR("-1 div 0 > 2 div 0"), false);
#ifndef MSVC6_NAN_BUG
CHECK_XPATH_BOOLEAN(c, STR("0 div 0 < 1"), false);
CHECK_XPATH_BOOLEAN(c, STR("0 div 0 <= 1"), false);
CHECK_XPATH_BOOLEAN(c, STR("0 div 0 > 1"), false);
CHECK_XPATH_BOOLEAN(c, STR("0 div 0 >= 1"), false);
#endif
// upcast to number
CHECK_XPATH_BOOLEAN(c, STR("2 < '2'"), false);
CHECK_XPATH_BOOLEAN(c, STR("1 < '2'"), true);
CHECK_XPATH_BOOLEAN(c, STR("2 <= '2'"), true);
CHECK_XPATH_BOOLEAN(c, STR("3 <= '2'"), false);
CHECK_XPATH_BOOLEAN(c, STR("2 > '2'"), false);
CHECK_XPATH_BOOLEAN(c, STR("3 > '2'"), true);
CHECK_XPATH_BOOLEAN(c, STR("2 >= '2'"), true);
CHECK_XPATH_BOOLEAN(c, STR("3 >= '2'"), true);
CHECK_XPATH_BOOLEAN(c, STR("1 >= true()"), true);
CHECK_XPATH_BOOLEAN(c, STR("1 > true()"), false);
}
TEST_XML(xpath_operators_inequality_node_set_node_set, "<node><c1><v>1</v><v>-1</v><v>-100</v></c1><c2><v>1</v><v>nan</v></c2><c3><v>1</v><v>-4</v></c3></node>")
{
xml_node c;
xml_node n = doc.child(STR("node"));
// node set vs node set
CHECK_XPATH_BOOLEAN(c, STR("x < x"), false);
CHECK_XPATH_BOOLEAN(c, STR("x > x"), false);
CHECK_XPATH_BOOLEAN(c, STR("x <= x"), false);
CHECK_XPATH_BOOLEAN(c, STR("x >= x"), false);
CHECK_XPATH_BOOLEAN(n, STR("c1/v > x"), false);
CHECK_XPATH_BOOLEAN(n, STR("c1/v < x"), false);
CHECK_XPATH_BOOLEAN(n, STR("c1/v >= x"), false);
CHECK_XPATH_BOOLEAN(n, STR("c1/v <= x"), false);
CHECK_XPATH_BOOLEAN(n, STR("x > c1/v"), false);
CHECK_XPATH_BOOLEAN(n, STR("x < c1/v"), false);
CHECK_XPATH_BOOLEAN(n, STR("x >= c1/v"), false);
CHECK_XPATH_BOOLEAN(n, STR("x <= c1/v"), false);
CHECK_XPATH_BOOLEAN(n, STR("c1/v > c3/v"), true);
CHECK_XPATH_BOOLEAN(n, STR("c1/v >= c3/v"), true);
CHECK_XPATH_BOOLEAN(n, STR("c1/v < c3/v"), true);
CHECK_XPATH_BOOLEAN(n, STR("c1/v <= c3/v"), true);
CHECK_XPATH_BOOLEAN(n, STR("c1/v[1] > c1/v[1]"), false);
CHECK_XPATH_BOOLEAN(n, STR("c1/v[1] < c1/v[1]"), false);
CHECK_XPATH_BOOLEAN(n, STR("c1/v[1] >= c1/v[1]"), true);
CHECK_XPATH_BOOLEAN(n, STR("c1/v[1] <= c1/v[1]"), true);
#ifndef MSVC6_NAN_BUG
CHECK_XPATH_BOOLEAN(n, STR("c1/v > c2/v"), false);
CHECK_XPATH_BOOLEAN(n, STR("c1/v >= c2/v"), true);
CHECK_XPATH_BOOLEAN(n, STR("c1/v < c2/v"), true);
CHECK_XPATH_BOOLEAN(n, STR("c1/v <= c2/v"), true);
CHECK_XPATH_BOOLEAN(n, STR("c2/v[2] < c2/v[2]"), false);
CHECK_XPATH_BOOLEAN(n, STR("c2/v[2] > c2/v[2]"), false);
CHECK_XPATH_BOOLEAN(n, STR("c2/v[2] <= c2/v[2]"), false);
CHECK_XPATH_BOOLEAN(n, STR("c2/v[2] >= c2/v[2]"), false);
#endif
}
TEST_XML(xpath_operators_inequality_node_set_primitive, "<node><c1><v>1</v><v>-1</v><v>-100</v></c1><c2><v>1</v><v>nan</v></c2></node>")
{
xml_node c;
xml_node n = doc.child(STR("node"));
// node set vs number
CHECK_XPATH_BOOLEAN(c, STR("x < 0"), false);
CHECK_XPATH_BOOLEAN(c, STR("x > 0"), false);
CHECK_XPATH_BOOLEAN(c, STR("x <= 0"), false);
CHECK_XPATH_BOOLEAN(c, STR("x >= 0"), false);
CHECK_XPATH_BOOLEAN(c, STR("0 < x"), false);
CHECK_XPATH_BOOLEAN(c, STR("0 > x"), false);
CHECK_XPATH_BOOLEAN(c, STR("0 <= x"), false);
CHECK_XPATH_BOOLEAN(c, STR("0 >= x"), false);
CHECK_XPATH_BOOLEAN(n, STR("c1/v > 0"), true);
CHECK_XPATH_BOOLEAN(n, STR("c1/v > 1"), false);
CHECK_XPATH_BOOLEAN(n, STR("c1/v >= 0"), true);
CHECK_XPATH_BOOLEAN(n, STR("c1/v < 0"), true);
CHECK_XPATH_BOOLEAN(n, STR("c1/v <= 0"), true);
CHECK_XPATH_BOOLEAN(n, STR("0 < c1/v"), true);
CHECK_XPATH_BOOLEAN(n, STR("1 < c1/v"), false);
CHECK_XPATH_BOOLEAN(n, STR("0 <= c1/v"), true);
CHECK_XPATH_BOOLEAN(n, STR("0 > c1/v"), true);
CHECK_XPATH_BOOLEAN(n, STR("0 >= c1/v"), true);
// node set vs string
CHECK_XPATH_BOOLEAN(n, STR("c1/v > '0'"), true);
CHECK_XPATH_BOOLEAN(n, STR("c1/v > '1'"), false);
CHECK_XPATH_BOOLEAN(n, STR("c1/v >= '0'"), true);
CHECK_XPATH_BOOLEAN(n, STR("c1/v < '0'"), true);
CHECK_XPATH_BOOLEAN(n, STR("c1/v <= '0'"), true);
CHECK_XPATH_BOOLEAN(n, STR("'0' < c1/v"), true);
CHECK_XPATH_BOOLEAN(n, STR("'1' < c1/v"), false);
CHECK_XPATH_BOOLEAN(n, STR("'0' <= c1/v"), true);
CHECK_XPATH_BOOLEAN(n, STR("'0' > c1/v"), true);
CHECK_XPATH_BOOLEAN(n, STR("'0' >= c1/v"), true);
// node set vs boolean
CHECK_XPATH_BOOLEAN(n, STR("c1/v > false()"), true);
CHECK_XPATH_BOOLEAN(n, STR("c1/v > true()"), false);
CHECK_XPATH_BOOLEAN(n, STR("c1/v >= false()"), true);
CHECK_XPATH_BOOLEAN(n, STR("c1/v < false()"), true);
CHECK_XPATH_BOOLEAN(n, STR("c1/v <= false()"), true);
CHECK_XPATH_BOOLEAN(n, STR("false() < c1/v"), true);
CHECK_XPATH_BOOLEAN(n, STR("true() < c1/v"), false);
CHECK_XPATH_BOOLEAN(n, STR("false() <= c1/v"), true);
CHECK_XPATH_BOOLEAN(n, STR("false() > c1/v"), true);
CHECK_XPATH_BOOLEAN(n, STR("false() >= c1/v"), true);
}
TEST(xpath_operators_boolean_precedence)
{
xml_node c;
CHECK_XPATH_BOOLEAN(c, STR("1 = 0 or 2 = 2"), true);
CHECK_XPATH_BOOLEAN(c, STR("1 = (0 or 2) = false()"), false);
CHECK_XPATH_BOOLEAN(c, STR("1 < 0 or 2 > 2"), false);
CHECK_XPATH_BOOLEAN(c, STR("2 < 1 = false()"), true);
CHECK_XPATH_BOOLEAN(c, STR("2 < (1 = false())"), false);
CHECK_XPATH_BOOLEAN(c, STR("3 > 2 > 1"), false);
CHECK_XPATH_BOOLEAN(c, STR("(3 > 2) > 1"), false);
CHECK_XPATH_BOOLEAN(c, STR("3 > (2 > 1)"), true);
}
TEST_XML(xpath_operators_union, "<node><employee/><employee secretary=''/><employee assistant=''/><employee secretary='' assistant=''/><employee assistant='' secretary=''/><tail/></node>")
{
xml_node c;
xml_node n = doc.child(STR("node"));
CHECK_XPATH_NODESET(n, STR("employee | .")) % 2 % 3 % 4 % 6 % 8 % 11;
CHECK_XPATH_NODESET(n, STR("employee[@secretary] | employee[@assistant]")) % 4 % 6 % 8 % 11;
CHECK_XPATH_NODESET(n, STR("employee[@assistant] | employee[@secretary]")) % 4 % 6 % 8 % 11;
CHECK_XPATH_NODESET(n, STR("employee[@secretary] | employee[@nobody]")) % 4 % 8 % 11;
CHECK_XPATH_NODESET(n, STR("employee[@nobody] | employee[@secretary]")) % 4 % 8 % 11;
CHECK_XPATH_NODESET(n, STR("tail/preceding-sibling::employee | .")) % 2 % 3 % 4 % 6 % 8 % 11;
CHECK_XPATH_NODESET(n, STR(". | tail/preceding-sibling::employee | .")) % 2 % 3 % 4 % 6 % 8 % 11;
}
TEST_XML(xpath_operators_union_order, "<node />")
{
xml_node n = doc.child(STR("node"));
n.append_child(STR("c"));
n.prepend_child(STR("b"));
n.append_child(STR("d"));
n.prepend_child(STR("a"));
xpath_node_set ns = n.select_nodes(STR("d | d | b | c | b | a | c | d | b"));
CHECK(ns.size() == 4);
CHECK_STRING(ns[0].node().name(), STR("d"));
CHECK_STRING(ns[1].node().name(), STR("b"));
CHECK_STRING(ns[2].node().name(), STR("c"));
CHECK_STRING(ns[3].node().name(), STR("a"));
}
TEST(xpath_operators_union_error)
{
CHECK_XPATH_FAIL(STR(". | true()"));
CHECK_XPATH_FAIL(STR(". | 1"));
CHECK_XPATH_FAIL(STR(". | '1'"));
CHECK_XPATH_FAIL(STR(". | count(.)"));
CHECK_XPATH_FAIL(STR("true() | ."));
CHECK_XPATH_FAIL(STR("1 | ."));
CHECK_XPATH_FAIL(STR("'1' | ."));
CHECK_XPATH_FAIL(STR("count(.) | ."));
}
TEST_XML(xpath_operators_union_minus, "<node1>3</node1><node2>4</node2>")
{
CHECK_XPATH_FAIL(STR("(-node1) | node2"));
CHECK_XPATH_FAIL(STR("node1 | -node2"));
CHECK_XPATH_NUMBER(doc, STR("-(node1 | node2)"), -3);
CHECK_XPATH_NUMBER(doc, STR("-node1 | node2"), -3);
CHECK_XPATH_NUMBER(doc, STR("--node1 | node2"), 3);
CHECK_XPATH_NUMBER(doc, STR("-(-node1 | node2)"), 3);
CHECK_XPATH_NUMBER(doc, STR("--(-node1 | node2)"), -3);
}
TEST(xpath_operators_associativity_boolean)
{
xml_node c;
CHECK_XPATH_BOOLEAN(c, STR("false() or true() and true() and false()"), false);
CHECK_XPATH_BOOLEAN(c, STR("3 > 2 > 1"), false);
CHECK_XPATH_BOOLEAN(c, STR("4 > 3 > 2 > 1"), false);
CHECK_XPATH_BOOLEAN(c, STR("5 > 4 > 3 > 2 > 1"), false);
CHECK_XPATH_BOOLEAN(c, STR("1 < 2 < 3 < 4 < 5"), true);
CHECK_XPATH_BOOLEAN(c, STR("1 <= 2 <= 3 <= 4 <= 5"), true);
CHECK_XPATH_BOOLEAN(c, STR("5 >= 4 >= 3 >= 2 >= 1"), false);
CHECK_XPATH_BOOLEAN(c, STR("3 >= 2 >= 1"), true);
CHECK_XPATH_BOOLEAN(c, STR("2 >= 1"), true);
CHECK_XPATH_BOOLEAN(c, STR("4 >= 3 >= 2 >= 1"), false);
CHECK_XPATH_BOOLEAN(c, STR("((((5 > 4) > 3) > 2) > 1)"), false);
CHECK_XPATH_BOOLEAN(c, STR("2 != 3 != 1 != 4 != 0"), true);
CHECK_XPATH_BOOLEAN(c, STR("(((2 != 3) != 1) != 4) != 0"), true);
CHECK_XPATH_BOOLEAN(c, STR("2 != 3 != 1 != 4 != 1"), false);
CHECK_XPATH_BOOLEAN(c, STR("(((2 != 3) != 1) != 4) != 1"), false);
CHECK_XPATH_BOOLEAN(c, STR("2 = 3 = 1 = 4 = 0"), true);
CHECK_XPATH_BOOLEAN(c, STR("(((2 = 3) = 1) = 4) = 0"), true);
CHECK_XPATH_BOOLEAN(c, STR("2 = 3 = 1 = 4 = 1"), false);
CHECK_XPATH_BOOLEAN(c, STR("(((2 = 3) = 1) = 4) = 1"), false);
}
TEST(xpath_operators_associativity_arithmetic)
{
xml_node c;
CHECK_XPATH_NUMBER(c, STR("2+1-1+1"), 3);
CHECK_XPATH_NUMBER(c, STR("1+2+1-1+1"), 4);
CHECK_XPATH_NUMBER(c, STR("1+1+2+1-1+1"), 5);
CHECK_XPATH_NUMBER(c, STR("1-1+1"), 1);
}
TEST(xpath_operators_mod)
{
// Check that mod operator conforms to Java spec (since this is the only concrete source of information about XPath mod)
xml_node c;
// Basic tests from spec
CHECK_XPATH_NUMBER(c, STR("5 mod 3"), 2);
CHECK_XPATH_NUMBER(c, STR("5 mod -3"), 2);
CHECK_XPATH_NUMBER(c, STR("-5 mod 3"), -2);
CHECK_XPATH_NUMBER(c, STR("-5 mod -3"), -2);
#if !defined(__BORLANDC__)
// If either operand is NaN, the result is NaN
CHECK_XPATH_NUMBER_NAN(c, STR("(0 div 0) mod 3"));
CHECK_XPATH_NUMBER_NAN(c, STR("3 mod (0 div 0)"));
CHECK_XPATH_NUMBER_NAN(c, STR("(0 div 0) mod (0 div 0)"));
// If the dividend is an infinity, or the divisor is a zero, or both, the result is NaN
CHECK_XPATH_NUMBER_NAN(c, STR("(1 div 0) mod 3"));
CHECK_XPATH_NUMBER_NAN(c, STR("(1 div 0) mod -3"));
CHECK_XPATH_NUMBER_NAN(c, STR("(-1 div 0) mod 3"));
CHECK_XPATH_NUMBER_NAN(c, STR("1 mod 0"));
CHECK_XPATH_NUMBER_NAN(c, STR("-1 mod 0"));
CHECK_XPATH_NUMBER_NAN(c, STR("(1 div 0) mod 0"));
CHECK_XPATH_NUMBER_NAN(c, STR("(-1 div 0) mod 0"));
#endif
// If the dividend is finite and the divisor is an infinity, the result equals the dividend
#if !defined(_MSC_VER) && !defined(__MINGW32__)
CHECK_XPATH_NUMBER(c, STR("1 mod (1 div 0)"), 1);
CHECK_XPATH_NUMBER(c, STR("1 mod (-1 div 0)"), 1);
CHECK_XPATH_NUMBER(c, STR("-1 mod (1 div 0)"), -1);
CHECK_XPATH_NUMBER(c, STR("0 mod (1 div 0)"), 0);
CHECK_XPATH_NUMBER(c, STR("0 mod (-1 div 0)"), 0);
CHECK_XPATH_NUMBER(c, STR("100000 mod (1 div 0)"), 100000);
#endif
// If the dividend is a zero and the divisor is finite, the result equals the dividend.
CHECK_XPATH_NUMBER(c, STR("0 mod 1000000"), 0);
CHECK_XPATH_NUMBER(c, STR("0 mod -1000000"), 0);
// In the remaining cases ... the floating-point remainder r from the division of a dividend n by a divisor d
// is defined by the mathematical relation r = n - (d * q) where q is an integer that is negative only if n/d is
// negative and positive only if n/d is positive, and whose magnitude is as large as possible without exceeding the magnitude of the true
// mathematical quotient of n and d.
CHECK_XPATH_NUMBER(c, STR("9007199254740991 mod 2"), 1);
CHECK_XPATH_NUMBER(c, STR("9007199254740991 mod 3"), 1);
CHECK_XPATH_NUMBER(c, STR("18446744073709551615 mod 2"), 0);
CHECK_XPATH_NUMBER(c, STR("18446744073709551615 mod 3"), 1);
CHECK_XPATH_NUMBER(c, STR("115792089237316195423570985008687907853269984665640564039457584007913129639935 mod 2"), 0);
CHECK_XPATH_NUMBER(c, STR("115792089237316195423570985008687907853269984665640564039457584007913129639935 mod 3"), 1);
}
#endif

View File

@ -0,0 +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

View File

@ -0,0 +1,783 @@
#ifndef PUGIXML_NO_XPATH
#include "test.hpp"
using namespace pugi;
TEST_XML(xpath_paths_axes_child, "<node attr='value'><child attr='value'><subchild/></child><another/><last/></node>")
{
xml_node c;
xml_node n = doc.child(STR("node"));
xpath_node na(n.attribute(STR("attr")), n);
CHECK_XPATH_NODESET(c, STR("child:: node()"));
CHECK_XPATH_NODESET(n, STR("child:: node()")) % 4 % 7 % 8; // child, another, last
CHECK_XPATH_NODESET(n, STR("another/child:: node()"));
CHECK_XPATH_NODESET(n, STR("@attr/child::node()"));
CHECK_XPATH_NODESET(na, STR("child::node()"));
}
TEST_XML(xpath_paths_axes_descendant, "<node attr='value'><child attr='value'><subchild/></child><another><subchild/></another><last/></node>")
{
xml_node c;
xml_node n = doc.child(STR("node"));
xpath_node na(n.attribute(STR("attr")), n);
CHECK_XPATH_NODESET(c, STR("descendant:: node()"));
CHECK_XPATH_NODESET(n, STR("descendant:: node()")) % 4 % 6 % 7 % 8 % 9; // child, subchild, another, subchild, last
CHECK_XPATH_NODESET(doc, STR("descendant:: node()")) % 2 % 4 % 6 % 7 % 8 % 9; // node, child, subchild, another, subchild, last
CHECK_XPATH_NODESET(n, STR("another/descendant:: node()")) % 8; // subchild
CHECK_XPATH_NODESET(n, STR("last/descendant:: node()"));
CHECK_XPATH_NODESET(n, STR("@attr/descendant::node()"));
CHECK_XPATH_NODESET(na, STR("descendant::node()"));
}
TEST_XML(xpath_paths_axes_parent, "<node attr='value'><child attr='value'><subchild/></child><another><subchild/></another><last/></node>")
{
xml_node c;
xml_node n = doc.child(STR("node"));
xpath_node na(n.attribute(STR("attr")), n);
CHECK_XPATH_NODESET(c, STR("parent:: node()"));
CHECK_XPATH_NODESET(n.child(STR("child")), STR("parent:: node()")) % 2; // node
CHECK_XPATH_NODESET(n, STR("child/subchild/parent:: node()")) % 4; // child
CHECK_XPATH_NODESET(n, STR("@attr/parent:: node()")) % 2; // node
CHECK_XPATH_NODESET(n, STR("parent:: node()")) % 1; // root
CHECK_XPATH_NODESET(doc, STR("parent:: node()"));
CHECK_XPATH_NODESET(na, STR("parent:: node()")) % 2; // node
}
TEST_XML(xpath_paths_axes_ancestor, "<node attr='value'><child attr='value'><subchild/></child><another><subchild/></another><last/></node>")
{
xml_node c;
xml_node n = doc.child(STR("node"));
xpath_node na(n.child(STR("child")).attribute(STR("attr")), n.child(STR("child")));
CHECK_XPATH_NODESET(c, STR("ancestor:: node()"));
CHECK_XPATH_NODESET(n.child(STR("child")), STR("ancestor:: node()")) % 2 % 1; // node, root
CHECK_XPATH_NODESET(n, STR("child/subchild/ancestor:: node()")) % 4 % 2 % 1; // child, node, root
CHECK_XPATH_NODESET(n, STR("child/@attr/ancestor:: node()")) % 4 % 2 % 1; // child, node, root
CHECK_XPATH_NODESET(n, STR("ancestor:: node()")) % 1; // root
CHECK_XPATH_NODESET(doc, STR("ancestor:: node()"));
CHECK_XPATH_NODESET(na, STR("ancestor:: node()")) % 4 % 2 % 1; // child, node, root
}
TEST_XML(xpath_paths_axes_following_sibling, "<node attr1='value' attr2='value'><child attr='value'><subchild/></child><another><subchild/></another><last/></node>")
{
xml_node c;
xml_node n = doc.child(STR("node"));
xpath_node na(n.attribute(STR("attr1")), n);
CHECK_XPATH_NODESET(c, STR("following-sibling:: node()"));
CHECK_XPATH_NODESET(n.child(STR("child")), STR("following-sibling:: node()")) % 8 % 10; // another, last
CHECK_XPATH_NODESET(n.child(STR("last")), STR("following-sibling:: node()"));
CHECK_XPATH_NODESET(n, STR("@attr1/following-sibling:: node()")); // attributes are not siblings
CHECK_XPATH_NODESET(na, STR("following-sibling:: node()")); // attributes are not siblings
}
TEST_XML(xpath_paths_axes_preceding_sibling, "<node attr1='value' attr2='value'><child attr='value'><subchild/></child><another><subchild/></another><last/></node>")
{
xml_node c;
xml_node n = doc.child(STR("node"));
xpath_node na(n.attribute(STR("attr2")), n);
CHECK_XPATH_NODESET(c, STR("preceding-sibling:: node()"));
CHECK_XPATH_NODESET(n.child(STR("child")), STR("preceding-sibling:: node()"));
CHECK_XPATH_NODESET(n.child(STR("last")), STR("preceding-sibling:: node()")) % 8 % 5; // another, child
CHECK_XPATH_NODESET(n, STR("@attr2/following-sibling:: node()")); // attributes are not siblings
CHECK_XPATH_NODESET(na, STR("following-sibling:: node()")); // attributes are not siblings
}
TEST_XML(xpath_paths_axes_following, "<node attr1='value' attr2='value'><child attr='value'><subchild/></child><another><subchild/></another><almost/><last/></node>")
{
xml_node c;
xml_node n = doc.child(STR("node"));
xpath_node na(n.attribute(STR("attr1")), n);
CHECK_XPATH_NODESET(c, STR("following:: node()"));
CHECK_XPATH_NODESET(n, STR("following:: node()")); // no descendants
CHECK_XPATH_NODESET(n.child(STR("child")), STR("following:: node()")) % 8 % 9 % 10 % 11; // another, subchild, almost, last
CHECK_XPATH_NODESET(n.child(STR("child")).child(STR("subchild")), STR("following:: node()")) % 8 % 9 % 10 % 11; // another, subchild, almost, last
CHECK_XPATH_NODESET(n.child(STR("last")), STR("following:: node()"));
CHECK_XPATH_NODESET(n, STR("@attr1/following::node()")) % 5 % 7 % 8 % 9 % 10 % 11; // child, subchild, another, subchild, almost, last - because @/following
CHECK_XPATH_NODESET(n, STR("child/@attr/following::node()")) % 7 % 8 % 9 % 10 % 11; // subchild, another, subchild, almost, last
CHECK_XPATH_NODESET(na, STR("following::node()")) % 5 % 7 % 8 % 9 % 10 % 11; // child, subchild, another, subchild, almost, last - because @/following
}
TEST_XML(xpath_paths_axes_preceding, "<node attr1='value' attr2='value'><child attr='value'><subchild/></child><another><subchild id='1'/></another><almost/><last/></node>")
{
xml_node c;
xml_node n = doc.child(STR("node"));
xpath_node na(n.child(STR("child")).attribute(STR("attr")), n.child(STR("child")));
CHECK_XPATH_NODESET(c, STR("preceding:: node()"));
CHECK_XPATH_NODESET(n.child(STR("child")), STR("preceding:: node()")); // no ancestors
CHECK_XPATH_NODESET(n.child(STR("last")), STR("preceding:: node()")) % 11 % 9 % 8 % 7 % 5; // almost, subchild, another, subchild, child
CHECK_XPATH_NODESET(n.child(STR("another")).child(STR("subchild")), STR("preceding:: node()")) % 7 % 5; // subchild, child
CHECK_XPATH_NODESET(n, STR("preceding:: node()"));
CHECK_XPATH_NODESET(n, STR("child/@attr/preceding::node()")); // no ancestors
CHECK_XPATH_NODESET(n, STR("//subchild[@id]/@id/preceding::node()")) % 7 % 5; // subchild, child
CHECK_XPATH_NODESET(na, STR("preceding::node()")); // no ancestors
}
TEST_XML(xpath_paths_axes_attribute, "<node attr1='value' attr2='value'><child attr='value'><subchild/></child><another xmlns:foo='bar'><subchild/></another><last/></node>")
{
xml_node c;
xml_node n = doc.child(STR("node"));
xpath_node na(n.attribute(STR("attr1")), n);
CHECK_XPATH_NODESET(c, STR("attribute:: node()"));
CHECK_XPATH_NODESET(n.child(STR("child")), STR("attribute:: node()")) % 6; // child/@attr
CHECK_XPATH_NODESET(n.child(STR("last")), STR("attribute:: node()"));
CHECK_XPATH_NODESET(n, STR("attribute:: node()")) % 3 % 4; // node/@attr1 node/@attr2
CHECK_XPATH_NODESET(doc, STR("descendant-or-self:: node()/attribute:: node()")) % 3 % 4 % 6; // all attributes
CHECK_XPATH_NODESET(n.child(STR("another")), STR("attribute:: node()")); // namespace nodes are not attributes
CHECK_XPATH_NODESET(n, STR("@attr1/attribute::node()"));
CHECK_XPATH_NODESET(na, STR("attribute::node()"));
}
TEST_XML(xpath_paths_axes_namespace, "<node xmlns:foo='bar' attr='value'/>")
{
xml_node n = doc.child(STR("node"));
xpath_node na(n.attribute(STR("attr")), n);
// namespace nodes are not supported
CHECK_XPATH_NODESET(n, STR("namespace:: node()"));
CHECK_XPATH_NODESET(n, STR("@attr/attribute::node()"));
CHECK_XPATH_NODESET(na, STR("attribute::node()"));
}
TEST_XML(xpath_paths_axes_self, "<node attr='value'><child attr='value'><subchild/></child><another><subchild/></another><last/></node>")
{
xml_node c;
xml_node n = doc.child(STR("node"));
xpath_node na(n.attribute(STR("attr")), n);
CHECK_XPATH_NODESET(c, STR("self:: node()"));
CHECK_XPATH_NODESET(n.child(STR("child")), STR("self:: node()")) % 4; // child
CHECK_XPATH_NODESET(n, STR("self:: node()")) % 2; // node
CHECK_XPATH_NODESET(n, STR("child/self:: node()")) % 4; // child
CHECK_XPATH_NODESET(n, STR("child/@attr/self:: node()")) % 5; // @attr
CHECK_XPATH_NODESET(doc, STR("self:: node()")) % 1; // root
CHECK_XPATH_NODESET(na, STR("self:: node()")) % 3; // @attr
}
TEST_XML(xpath_paths_axes_descendant_or_self, "<node attr='value'><child attr='value'><subchild/></child><another><subchild/></another><last/></node>")
{
xml_node c;
xml_node n = doc.child(STR("node"));
xpath_node na(n.child(STR("child")).attribute(STR("attr")), n.child(STR("child")));
CHECK_XPATH_NODESET(c, STR("descendant-or-self:: node()"));
CHECK_XPATH_NODESET(n, STR("descendant-or-self:: node()")) % 2 % 4 % 6 % 7 % 8 % 9; // node, child, subchild, another, subchild, last
CHECK_XPATH_NODESET(doc, STR("descendant-or-self:: node()")) % 1 % 2 % 4 % 6 % 7 % 8 % 9; // root, node, child, subchild, another, subchild, last
CHECK_XPATH_NODESET(n, STR("another/descendant-or-self:: node()")) % 7 % 8; // another, subchild
CHECK_XPATH_NODESET(n, STR("last/descendant-or-self:: node()")) % 9; // last
CHECK_XPATH_NODESET(n, STR("child/@attr/descendant-or-self::node()")) % 5; // @attr
CHECK_XPATH_NODESET(na, STR("descendant-or-self::node()")) % 5; // @attr
}
TEST_XML(xpath_paths_axes_ancestor_or_self, "<node attr='value'><child attr='value'><subchild/></child><another><subchild/></another><last/></node>")
{
xml_node c;
xml_node n = doc.child(STR("node"));
xpath_node na(n.child(STR("child")).attribute(STR("attr")), n.child(STR("child")));
CHECK_XPATH_NODESET(c, STR("ancestor-or-self:: node()"));
CHECK_XPATH_NODESET(n.child(STR("child")), STR("ancestor-or-self:: node()")) % 4 % 2 % 1; // child, node, root
CHECK_XPATH_NODESET(n, STR("child/subchild/ancestor-or-self:: node()")) % 6 % 4 % 2 % 1; // subchild, child, node, root
CHECK_XPATH_NODESET(n, STR("child/@attr/ancestor-or-self:: node()")) % 5 % 4 % 2 % 1; // @attr, child, node, root
CHECK_XPATH_NODESET(n, STR("ancestor-or-self:: node()")) % 2 % 1; // root, node
CHECK_XPATH_NODESET(doc, STR("ancestor-or-self:: node()")) % 1; // root
CHECK_XPATH_NODESET(n, STR("ancestor-or-self:: node()")) % 2 % 1; // root, node
CHECK_XPATH_NODESET(n, STR("last/ancestor-or-self::node()")) % 9 % 2 % 1; // root, node, last
CHECK_XPATH_NODESET(na, STR("ancestor-or-self:: node()")) % 5 % 4 % 2 % 1; // @attr, child, node, root
}
TEST_XML(xpath_paths_axes_abbrev, "<node attr='value'><foo/></node>")
{
xml_node c;
xml_node n = doc.child(STR("node"));
// @ axis
CHECK_XPATH_NODESET(c, STR("@attr"));
CHECK_XPATH_NODESET(n, STR("@attr")) % 3;
// no axis - child implied
CHECK_XPATH_NODESET(c, STR("foo"));
CHECK_XPATH_NODESET(n, STR("foo")) % 4;
CHECK_XPATH_NODESET(doc, STR("node()")) % 2;
// @ axis should disable all other axis specifiers
CHECK_XPATH_FAIL(STR("@child::foo"));
CHECK_XPATH_FAIL(STR("@attribute::foo"));
}
TEST_XML(xpath_paths_nodetest_all, "<node a1='v1' x:a2='v2'><c1/><x:c2/><c3/><x:c4/></node>")
{
xml_node c;
xml_node n = doc.child(STR("node"));
CHECK_XPATH_NODESET(c, STR("*"));
CHECK_XPATH_NODESET(c, STR("child::*"));
CHECK_XPATH_NODESET(n, STR("*")) % 5 % 6 % 7 % 8;
CHECK_XPATH_NODESET(n, STR("child::*")) % 5 % 6 % 7 % 8;
CHECK_XPATH_NODESET(n, STR("attribute::*")) % 3 % 4;
}
TEST_XML_FLAGS(xpath_paths_nodetest_name, "<node a1='v1' x:a2='v2'><c1/><x:c2/><c3/><x:c4/><?c1?></node>", parse_default | parse_pi)
{
xml_node c;
xml_node n = doc.child(STR("node"));
CHECK_XPATH_NODESET(c, STR("c1"));
CHECK_XPATH_NODESET(c, STR("child::c1"));
CHECK_XPATH_NODESET(n, STR("c1")) % 5;
CHECK_XPATH_NODESET(n, STR("x:c2")) % 6;
CHECK_XPATH_NODESET(n, STR("child::c1")) % 5;
CHECK_XPATH_NODESET(n, STR("child::x:c2")) % 6;
CHECK_XPATH_NODESET(n, STR("attribute::a1")) % 3;
CHECK_XPATH_NODESET(n, STR("attribute::x:a2")) % 4;
CHECK_XPATH_NODESET(n, STR("@x:a2")) % 4;
}
TEST_XML(xpath_paths_nodetest_all_in_namespace, "<node a1='v1' x:a2='v2'><c1/><x:c2/><c3/><x:c4/></node>")
{
xml_node c;
xml_node n = doc.child(STR("node"));
CHECK_XPATH_NODESET(c, STR("x:*"));
CHECK_XPATH_NODESET(c, STR("child::x:*"));
CHECK_XPATH_NODESET(n, STR("x:*")) % 6 % 8;
CHECK_XPATH_NODESET(n, STR("child::x:*")) % 6 % 8;
CHECK_XPATH_NODESET(n, STR("attribute::x:*")) % 4;
CHECK_XPATH_NODESET(n, STR("@x:*")) % 4;
CHECK_XPATH_FAIL(STR(":*"));
CHECK_XPATH_FAIL(STR("@:*"));
}
TEST_XML_FLAGS(xpath_paths_nodetest_type, "<node attr='value'>pcdata<child/><?pi1 value?><?pi2 value?><!--comment--><![CDATA[cdata]]></node>", parse_default | parse_pi | parse_comments)
{
xml_node c;
xml_node n = doc.child(STR("node"));
// check on empty nodes
CHECK_XPATH_NODESET(c, STR("node()"));
CHECK_XPATH_NODESET(c, STR("text()"));
CHECK_XPATH_NODESET(c, STR("comment()"));
CHECK_XPATH_NODESET(c, STR("processing-instruction()"));
CHECK_XPATH_NODESET(c, STR("processing-instruction('foobar')"));
// child axis
CHECK_XPATH_NODESET(n, STR("node()")) % 4 % 5 % 6 % 7 % 8 % 9;
CHECK_XPATH_NODESET(n, STR("text()")) % 4 % 9;
CHECK_XPATH_NODESET(n, STR("comment()")) % 8;
CHECK_XPATH_NODESET(n, STR("processing-instruction()")) % 6 % 7;
CHECK_XPATH_NODESET(n, STR("processing-instruction('pi2')")) % 7;
// attribute axis
CHECK_XPATH_NODESET(n, STR("@node()")) % 3;
CHECK_XPATH_NODESET(n, STR("@text()"));
CHECK_XPATH_NODESET(n, STR("@comment()"));
CHECK_XPATH_NODESET(n, STR("@processing-instruction()"));
CHECK_XPATH_NODESET(n, STR("@processing-instruction('pi2')"));
// incorrect 'argument' number
CHECK_XPATH_FAIL(STR("node('')"));
CHECK_XPATH_FAIL(STR("text('')"));
CHECK_XPATH_FAIL(STR("comment('')"));
CHECK_XPATH_FAIL(STR("processing-instruction(1)"));
CHECK_XPATH_FAIL(STR("processing-instruction('', '')"));
CHECK_XPATH_FAIL(STR("processing-instruction(concat('a', 'b'))"));
}
TEST_XML_FLAGS(xpath_paths_nodetest_principal, "<node attr='value'>pcdata<child/><?pi1 value?><?pi2 value?><!--comment--><![CDATA[cdata]]></node><abra:cadabra abra:arba=''/>", parse_default | parse_pi | parse_comments)
{
// node() test is true for any node type
CHECK_XPATH_NODESET(doc, STR("//node()")) % 2 % 4 % 5 % 6 % 7 % 8 % 9 % 10;
CHECK_XPATH_NODESET(doc, STR("//attribute::node()")) % 3 % 11;
CHECK_XPATH_NODESET(doc, STR("//attribute::node()/ancestor-or-self::node()")) % 1 % 2 % 3 % 10 % 11;
// name test is true only for node with principal node type (depends on axis)
CHECK_XPATH_NODESET(doc, STR("node/child::child")) % 5;
CHECK_XPATH_NODESET(doc, STR("node/attribute::attr")) % 3;
CHECK_XPATH_NODESET(doc, STR("node/child::pi1"));
CHECK_XPATH_NODESET(doc, STR("node/child::attr"));
CHECK_XPATH_NODESET(doc, STR("node/child::child/self::child")) % 5;
CHECK_XPATH_NODESET(doc, STR("node/attribute::attr/self::attr")); // attribute is not of element type
CHECK_XPATH_NODESET(doc, STR("node/child::child/ancestor-or-self::child")) % 5;
CHECK_XPATH_NODESET(doc, STR("node/attribute::attr/ancestor-or-self::attr")); // attribute is not of element type
CHECK_XPATH_NODESET(doc, STR("node/child::child/descendant-or-self::child")) % 5;
CHECK_XPATH_NODESET(doc, STR("node/attribute::attr/descendant-or-self::attr")); // attribute is not of element type
// any name test is true only for node with principal node type (depends on axis)
CHECK_XPATH_NODESET(doc, STR("node/child::*")) % 5;
CHECK_XPATH_NODESET(doc, STR("node/attribute::*")) % 3;
CHECK_XPATH_NODESET(doc, STR("node/child::*/self::*")) % 5;
CHECK_XPATH_NODESET(doc, STR("node/attribute::*/self::*")); // attribute is not of element type
CHECK_XPATH_NODESET(doc, STR("node/child::*/ancestor-or-self::*")) % 5 % 2;
CHECK_XPATH_NODESET(doc, STR("node/attribute::*/ancestor-or-self::*")) % 2; // attribute is not of element type
CHECK_XPATH_NODESET(doc, STR("node/child::*/descendant-or-self::*")) % 5;
CHECK_XPATH_NODESET(doc, STR("node/attribute::*/descendant-or-self::*")); // attribute is not of element type
// namespace test is true only for node with principal node type (depends on axis)
CHECK_XPATH_NODESET(doc, STR("child::abra:*")) % 10;
CHECK_XPATH_NODESET(doc, STR("child::abra:*/attribute::abra:*")) % 11;
CHECK_XPATH_NODESET(doc, STR("child::abra:*/self::abra:*")) % 10;
CHECK_XPATH_NODESET(doc, STR("child::abra:*/attribute::abra:*/self::abra:*")); // attribute is not of element type
CHECK_XPATH_NODESET(doc, STR("child::abra:*/ancestor-or-self::abra:*")) % 10;
CHECK_XPATH_NODESET(doc, STR("child::abra:*/attribute::abra:*/ancestor-or-self::abra:*")) % 10; // attribute is not of element type
CHECK_XPATH_NODESET(doc, STR("child::abra:*/descendant-or-self::abra:*")) % 10;
CHECK_XPATH_NODESET(doc, STR("child::abra:*/attribute::abra:*/descendant-or-self::abra:*")); // attribute is not of element type
}
TEST_XML(xpath_paths_nodetest_attribute_namespace, "<node a1='v1' xmlns:x='?' />")
{
CHECK_XPATH_NODESET(doc, STR("node/attribute::node()")) % 3;
CHECK_XPATH_NODESET(doc, STR("node/attribute::xmlns:x"));
CHECK_XPATH_NODESET(doc, STR("node/attribute::xmlns:*"));
}
TEST_XML(xpath_paths_absolute, "<node attr='value'><foo><foo/><foo/></foo></node>")
{
xml_node c;
xml_node n = doc.child(STR("node"));
xpath_node na(n.attribute(STR("attr")), n);
CHECK_XPATH_NODESET(c, STR("/foo"));
CHECK_XPATH_NODESET(n, STR("/foo"));
CHECK_XPATH_NODESET(n, STR("/node/foo")) % 4;
CHECK_XPATH_NODESET(n.child(STR("foo")), STR("/node/foo")) % 4;
CHECK_XPATH_NODESET(na, STR("/node/foo")) % 4;
CHECK_XPATH_NODESET(c, STR("/"));
CHECK_XPATH_NODESET(n, STR("/")) % 1;
CHECK_XPATH_NODESET(n.child(STR("foo")), STR("/")) % 1;
CHECK_XPATH_NODESET(na, STR("/")) % 1;
}
TEST_XML(xpath_paths_step_abbrev, "<node><foo/></node>")
{
xml_node c;
xml_node n = doc.child(STR("node"));
CHECK_XPATH_NODESET(c, STR("."));
CHECK_XPATH_NODESET(c, STR(".."));
CHECK_XPATH_NODESET(n, STR(".")) % 2;
CHECK_XPATH_NODESET(n, STR("..")) % 1;
CHECK_XPATH_NODESET(n, STR("../node")) % 2;
CHECK_XPATH_NODESET(n.child(STR("foo")), STR("..")) % 2;
CHECK_XPATH_FAIL(STR(".node"));
CHECK_XPATH_FAIL(STR("..node"));
}
TEST_XML(xpath_paths_relative_abbrev, "<node><foo><foo/><foo/></foo></node>")
{
xml_node c;
xml_node n = doc.child(STR("node"));
CHECK_XPATH_NODESET(c, STR("foo//bar"));
CHECK_XPATH_NODESET(n, STR("foo/foo")) % 4 % 5;
CHECK_XPATH_NODESET(n, STR("foo//foo")) % 4 % 5;
CHECK_XPATH_NODESET(n, STR(".//foo")) % 3 % 4 % 5;
}
TEST_XML(xpath_paths_absolute_abbrev, "<node><foo><foo/><foo/></foo></node>")
{
xml_node c;
xml_node n = doc.child(STR("node"));
CHECK_XPATH_NODESET(c, STR("//bar"));
CHECK_XPATH_NODESET(n, STR("//foo")) % 3 % 4 % 5;
CHECK_XPATH_NODESET(n.child(STR("foo")), STR("//foo")) % 3 % 4 % 5;
CHECK_XPATH_NODESET(doc, STR("//foo")) % 3 % 4 % 5;
}
TEST_XML(xpath_paths_predicate_boolean, "<node><chapter/><chapter/><chapter/><chapter/><chapter/></node>")
{
xml_node n = doc.child(STR("node")).child(STR("chapter")).next_sibling().next_sibling();
CHECK_XPATH_NODESET(n, STR("following-sibling::chapter[position()=1]")) % 6;
CHECK_XPATH_NODESET(n, STR("following-sibling::chapter[position()=2]")) % 7;
CHECK_XPATH_NODESET(n, STR("preceding-sibling::chapter[position()=1]")) % 4;
CHECK_XPATH_NODESET(n, STR("preceding-sibling::chapter[position()=2]")) % 3;
}
TEST_XML(xpath_paths_predicate_number, "<node><chapter/><chapter/><chapter/><chapter/><chapter/></node>")
{
xml_node n = doc.child(STR("node")).child(STR("chapter")).next_sibling().next_sibling();
CHECK_XPATH_NODESET(n, STR("following-sibling::chapter[1]")) % 6;
CHECK_XPATH_NODESET(n, STR("following-sibling::chapter[2]")) % 7;
CHECK_XPATH_NODESET(n, STR("preceding-sibling::chapter[1]")) % 4;
CHECK_XPATH_NODESET(n, STR("preceding-sibling::chapter[2]")) % 3;
}
TEST_XML(xpath_paths_predicate_number_boundary, "<node><chapter/><chapter/><chapter/><chapter/><chapter/></node>")
{
CHECK_XPATH_NODESET(doc, STR("node/chapter[0.999999999999999]"));
CHECK_XPATH_NODESET(doc, STR("node/chapter[1]")) % 3;
CHECK_XPATH_NODESET(doc, STR("node/chapter[1.000000000000001]"));
CHECK_XPATH_NODESET(doc, STR("node/chapter[1.999999999999999]"));
CHECK_XPATH_NODESET(doc, STR("node/chapter[2]")) % 4;
CHECK_XPATH_NODESET(doc, STR("node/chapter[2.000000000000001]"));
CHECK_XPATH_NODESET(doc, STR("node/chapter[4.999999999999999]"));
CHECK_XPATH_NODESET(doc, STR("node/chapter[5]")) % 7;
CHECK_XPATH_NODESET(doc, STR("node/chapter[5.000000000000001]"));
}
TEST_XML(xpath_paths_predicate_number_out_of_range, "<node><chapter/><chapter/><chapter/><chapter/><chapter/></node>")
{
xml_node n = doc.child(STR("node")).child(STR("chapter")).next_sibling().next_sibling();
CHECK_XPATH_NODESET(n, STR("following-sibling::chapter[0]"));
CHECK_XPATH_NODESET(n, STR("following-sibling::chapter[-1]"));
CHECK_XPATH_NODESET(n, STR("following-sibling::chapter[-1000000000000]"));
CHECK_XPATH_NODESET(n, STR("following-sibling::chapter[-1 div 0]"));
CHECK_XPATH_NODESET(n, STR("following-sibling::chapter[1000000000000]"));
CHECK_XPATH_NODESET(n, STR("following-sibling::chapter[1 div 0]"));
#ifndef MSVC6_NAN_BUG
CHECK_XPATH_NODESET(n, STR("following-sibling::chapter[0 div 0]"));
#endif
}
TEST_XML(xpath_paths_predicate_constant_boolean, "<node><chapter/><chapter/><chapter/><chapter/><chapter/></node>")
{
xml_node n = doc.child(STR("node")).child(STR("chapter")).next_sibling().next_sibling();
xpath_variable_set set;
set.set(STR("true"), true);
set.set(STR("false"), false);
CHECK_XPATH_NODESET_VAR(n, STR("following-sibling::chapter[$false]"), &set);
CHECK_XPATH_NODESET_VAR(n, STR("following-sibling::chapter[$true]"), &set) % 6 % 7;
}
TEST_XML(xpath_paths_predicate_position_eq, "<node><chapter/><chapter/><chapter>3</chapter><chapter/><chapter/></node>")
{
CHECK_XPATH_NODESET(doc, STR("node/chapter[position()=1]")) % 3;
CHECK_XPATH_NODESET(doc, STR("node/chapter[position()=2+2]")) % 7;
CHECK_XPATH_NODESET(doc, STR("node/chapter[position()=last()]")) % 8;
#ifndef MSVC6_NAN_BUG
CHECK_XPATH_NODESET(doc, STR("node/chapter[position()=string()]")) % 5;
#endif
}
TEST_XML(xpath_paths_predicate_several, "<node><employee/><employee secretary=''/><employee assistant=''/><employee secretary='' assistant=''/><employee assistant='' secretary=''/></node>")
{
xml_node n = doc.child(STR("node"));
CHECK_XPATH_NODESET(n, STR("employee")) % 3 % 4 % 6 % 8 % 11;
CHECK_XPATH_NODESET(n, STR("employee[@secretary]")) % 4 % 8 % 11;
CHECK_XPATH_NODESET(n, STR("employee[@assistant]")) % 6 % 8 % 11;
CHECK_XPATH_NODESET(n, STR("employee[@secretary][@assistant]")) % 8 % 11;
CHECK_XPATH_NODESET(n, STR("employee[@assistant][@secretary]")) % 8 % 11;
CHECK_XPATH_NODESET(n, STR("employee[@secretary and @assistant]")) % 8 % 11;
}
TEST_XML(xpath_paths_predicate_filter_boolean, "<node><chapter/><chapter/><chapter/><chapter/><chapter/></node>")
{
xml_node n = doc.child(STR("node")).child(STR("chapter")).next_sibling().next_sibling();
CHECK_XPATH_NODESET(n, STR("(following-sibling::chapter)[position()=1]")) % 6;
CHECK_XPATH_NODESET(n, STR("(following-sibling::chapter)[position()=2]")) % 7;
CHECK_XPATH_NODESET(n, STR("(preceding-sibling::chapter)[position()=1]")) % 3;
CHECK_XPATH_NODESET(n, STR("(preceding-sibling::chapter)[position()=2]")) % 4;
}
TEST_XML(xpath_paths_predicate_filter_number, "<node><chapter/><chapter/><chapter/><chapter/><chapter/></node>")
{
xml_node n = doc.child(STR("node")).child(STR("chapter")).next_sibling().next_sibling();
CHECK_XPATH_NODESET(n, STR("(following-sibling::chapter)[1]")) % 6;
CHECK_XPATH_NODESET(n, STR("(following-sibling::chapter)[2]")) % 7;
CHECK_XPATH_NODESET(n, STR("(preceding-sibling::chapter)[1]")) % 3;
CHECK_XPATH_NODESET(n, STR("(preceding-sibling::chapter)[2]")) % 4;
}
TEST_XML(xpath_paths_predicate_filter_posinv, "<node><employee/><employee secretary=''/><employee assistant=''/><employee secretary='' assistant=''/><employee assistant='' secretary=''/></node>")
{
xml_node n = doc.child(STR("node"));
CHECK_XPATH_NODESET(n, STR("employee")) % 3 % 4 % 6 % 8 % 11;
CHECK_XPATH_NODESET(n, STR("(employee[@secretary])[@assistant]")) % 8 % 11;
CHECK_XPATH_NODESET(n, STR("((employee)[@assistant])[@secretary]")) % 8 % 11;
}
TEST_XML(xpath_paths_step_compose, "<node><foo><foo/><foo/></foo><foo/></node>")
{
xml_node n = doc.child(STR("node"));
CHECK_XPATH_NODESET(n, STR("(.)/foo")) % 3 % 6;
CHECK_XPATH_NODESET(n, STR("(.)//foo")) % 3 % 4 % 5 % 6;
CHECK_XPATH_NODESET(n, STR("(./..)//*")) % 2 % 3 % 4 % 5 % 6;
CHECK_XPATH_FAIL(STR("(1)/foo"));
CHECK_XPATH_FAIL(STR("(1)//foo"));
}
TEST_XML(xpath_paths_descendant_double_slash_w3c, "<node><para><para/><para/><para><para/></para></para><para/></node>")
{
CHECK_XPATH_NODESET(doc, STR("//para")) % 3 % 4 % 5 % 6 % 7 % 8;
CHECK_XPATH_NODESET(doc, STR("/descendant::para")) % 3 % 4 % 5 % 6 % 7 % 8;
CHECK_XPATH_NODESET(doc, STR("//para[1]")) % 3 % 4 % 7;
CHECK_XPATH_NODESET(doc, STR("/descendant::para[1]")) % 3;
}
TEST_XML(xpath_paths_needs_sorting, "<node><child/><child/><child><subchild/><subchild/></child></node>")
{
CHECK_XPATH_NODESET(doc, STR("(node/child/subchild)[2]")) % 7;
}
TEST_XML(xpath_paths_descendant_filters, "<node><para><para/><para/><para><para/></para></para><para/></node>")
{
CHECK_XPATH_NODESET(doc, STR("//para[1]")) % 3 % 4 % 7;
CHECK_XPATH_NODESET(doc, STR("/descendant::para[1]")) % 3;
CHECK_XPATH_NODESET(doc, STR("//para[true()][1]")) % 3 % 4 % 7;
CHECK_XPATH_NODESET(doc, STR("/descendant::para[true()][1]")) % 3;
CHECK_XPATH_NODESET(doc, STR("//para[1][true()]")) % 3 % 4 % 7;
CHECK_XPATH_NODESET(doc, STR("/descendant::para[1][true()]")) % 3;
CHECK_XPATH_NODESET(doc, STR("//para[1][2]"));
CHECK_XPATH_NODESET(doc, STR("/descendant::para[1][2]"));
CHECK_XPATH_NODESET(doc, STR("//para[true()]")) % 3 % 4 % 5 % 6 % 7 % 8;
CHECK_XPATH_NODESET(doc, STR("/descendant::para[true()]")) % 3 % 4 % 5 % 6 % 7 % 8;
CHECK_XPATH_NODESET(doc, STR("//para[position()=1][true()]")) % 3 % 4 % 7;
CHECK_XPATH_NODESET(doc, STR("/descendant::para[position()=1][true()]")) % 3;
CHECK_XPATH_NODESET(doc, STR("//para[true()][position()=1]")) % 3 % 4 % 7;
CHECK_XPATH_NODESET(doc, STR("/descendant::para[true()][position()=1]")) % 3;
CHECK_XPATH_NODESET(doc, STR("//node()[self::para]")) % 3 % 4 % 5 % 6 % 7 % 8;
}
TEST_XML(xpath_paths_descendant_optimize, "<node><para><para/><para/><para><para/></para></para><para/></node>")
{
CHECK_XPATH_NODESET(doc, STR("//para")) % 3 % 4 % 5 % 6 % 7 % 8;
CHECK_XPATH_NODESET(doc, STR("/descendant-or-self::node()/child::para")) % 3 % 4 % 5 % 6 % 7 % 8;
CHECK_XPATH_NODESET(doc, STR("/descendant-or-self::node()[name()='para']/child::para")) % 4 % 5 % 6 % 7;
CHECK_XPATH_NODESET(doc, STR("/descendant-or-self::node()[name()='para']/child::para[1]")) % 4 % 7;
CHECK_XPATH_NODESET(doc, STR("/descendant-or-self::node()[3]/child::para")) % 4 % 5 % 6;
}
TEST_XML(xpath_paths_descendant_optimize_axes, "<node><para><para/><para/><para><para/></para></para><para/></node>")
{
CHECK_XPATH_NODESET(doc, STR("//.")) % 1 % 2 % 3 % 4 % 5 % 6 % 7 % 8;
CHECK_XPATH_NODESET(doc, STR("//descendant::*")) % 2 % 3 % 4 % 5 % 6 % 7 % 8;
CHECK_XPATH_NODESET(doc, STR("//descendant-or-self::*")) % 2 % 3 % 4 % 5 % 6 % 7 % 8;
CHECK_XPATH_NODESET(doc, STR("//..")) % 1 % 2 % 3 % 6;
CHECK_XPATH_NODESET(doc, STR("//ancestor::*")) % 2 % 3 % 6;
CHECK_XPATH_NODESET(doc, STR("//ancestor-or-self::*")) % 2 % 3 % 4 % 5 % 6 % 7 % 8;
CHECK_XPATH_NODESET(doc, STR("//preceding-sibling::*")) % 3 % 4 % 5;
CHECK_XPATH_NODESET(doc, STR("//following-sibling::*")) % 5 % 6 % 8;
CHECK_XPATH_NODESET(doc, STR("//preceding::*")) % 3 % 4 % 5 % 6 % 7;
CHECK_XPATH_NODESET(doc, STR("//following::*")) % 5 % 6 % 7 % 8;
}
TEST_XML(xpath_paths_descendant_optimize_last, "<node><para><para/><para/><para><para/></para></para><para/></node>")
{
CHECK_XPATH_NODESET(doc, STR("//para[last()]")) % 6 % 7 % 8;
CHECK_XPATH_NODESET(doc, STR("//para[last() = 1]")) % 7;
}
TEST_XML(xpath_paths_precision, "<node><para/><para/><para/><para/><para/></node>")
{
CHECK_XPATH_NODESET(doc, STR("//para[1]")) % 3;
CHECK_XPATH_NODESET(doc, STR("//para[3 div 3]")) % 3;
CHECK_XPATH_NODESET(doc, STR("//para[6 div 3 - 1]")) % 3;
CHECK_XPATH_NODESET(doc, STR("//para[6 * (1 div 3) - 1]")) % 3;
}
TEST_XML(xpath_paths_unsorted_child, "<node><foo><bar/></foo><node><foo><bar/></foo></node><foo><bar/></foo></node>")
{
CHECK_XPATH_NODESET(doc, STR("//node/foo")) % 3 % 6 % 8;
CHECK_XPATH_NODESET(doc, STR("//node/foo/bar")) % 4 % 7 % 9;
xpath_node_set ns = doc.select_nodes(STR("//node/foo/bar"));
CHECK(ns.type() == xpath_node_set::type_unsorted);
xpath_node_set nss = ns;
nss.sort();
CHECK(ns[0] == nss[0]);
CHECK(ns[1] == nss[2]);
CHECK(ns[2] == nss[1]);
}
TEST_XML(xpath_paths_optimize_compare_attribute, "<node id='1' /><node id='2' /><node xmlns='3' />")
{
CHECK_XPATH_NODESET(doc, STR("node[@id = '1']")) % 2;
CHECK_XPATH_NODESET(doc, STR("node[@id = '2']")) % 4;
CHECK_XPATH_NODESET(doc, STR("node[@id = 2]")) % 4;
CHECK_XPATH_NODESET(doc, STR("node[@id[. > 3] = '2']"));
CHECK_XPATH_NODESET(doc, STR("node['1' = @id]")) % 2;
xpath_variable_set set;
set.set(STR("var1"), STR("2"));
set.set(STR("var2"), 2.0);
CHECK_XPATH_NODESET_VAR(doc, STR("node[@id = $var1]"), &set) % 4;
CHECK_XPATH_NODESET_VAR(doc, STR("node[@id = $var2]"), &set) % 4;
CHECK_XPATH_NODESET(doc, STR("node[@xmlns = '3']"));
}
TEST_XML(xpath_paths_optimize_step_once, "<node><para1><para2/><para3/><para4><para5 attr5=''/></para4></para1><para6/></node>")
{
CHECK_XPATH_BOOLEAN(doc, STR("node//para2/following::*"), true);
CHECK_XPATH_BOOLEAN(doc, STR("node//para6/following::*"), false);
CHECK_XPATH_STRING(doc, STR("name(node//para2/following::*)"), STR("para3"));
CHECK_XPATH_STRING(doc, STR("name(node//para6/following::*)"), STR(""));
CHECK_XPATH_BOOLEAN(doc, STR("node//para1/preceding::*"), false);
CHECK_XPATH_BOOLEAN(doc, STR("node//para6/preceding::*"), true);
CHECK_XPATH_STRING(doc, STR("name(node//para1/preceding::*)"), STR(""));
CHECK_XPATH_STRING(doc, STR("name(node//para6/preceding::*)"), STR("para1"));
CHECK_XPATH_BOOLEAN(doc, STR("node//para6/preceding::para4"), true);
CHECK_XPATH_BOOLEAN(doc, STR("//@attr5/ancestor-or-self::*"), true);
CHECK_XPATH_BOOLEAN(doc, STR("//@attr5/ancestor::*"), true);
CHECK_XPATH_BOOLEAN(doc, STR("//@attr5/following::para6"), true);
CHECK_XPATH_STRING(doc, STR("name(//@attr5/following::para6)"), STR("para6"));
CHECK_XPATH_BOOLEAN(doc, STR("//para5/ancestor-or-self::*"), true);
CHECK_XPATH_BOOLEAN(doc, STR("//para5/ancestor::*"), true);
CHECK_XPATH_BOOLEAN(doc, STR("//@attr5/ancestor-or-self::node()"), true);
}
TEST_XML(xpath_paths_null_nodeset_entries, "<node attr='value'/>")
{
xpath_node nodes[] =
{
xpath_node(doc.first_child()),
xpath_node(xml_node()),
xpath_node(doc.first_child().first_attribute(), doc.first_child()),
xpath_node(xml_attribute(), doc.first_child()),
xpath_node(xml_attribute(), xml_node()),
};
xpath_node_set ns(nodes, nodes + sizeof(nodes) / sizeof(nodes[0]));
xpath_variable_set vars;
vars.set(STR("x"), ns);
xpath_node_set rs = xpath_query(STR("$x/."), &vars).evaluate_node_set(xml_node());
CHECK(rs.size() == 2);
CHECK(rs[0] == nodes[0]);
CHECK(rs[1] == nodes[2]);
}
TEST_XML(xpath_paths_step_leaf_coverage, "<n><n1/><n2 a='v'><child/></n2><n3/></n>")
{
xml_node n = doc.child(STR("n")).child(STR("n2"));
CHECK_XPATH_NODESET(n, STR("ancestor::node()")) % 2 % 1;
CHECK_XPATH_NODESET(n, STR("ancestor-or-self::node()")) % 4 % 2 % 1;
CHECK_XPATH_NODESET(n, STR("attribute::node()")) % 5;
CHECK_XPATH_NODESET(n, STR("child::node()")) % 6;
CHECK_XPATH_NODESET(n, STR("descendant::node()")) % 6;
CHECK_XPATH_NODESET(n, STR("descendant-or-self::node()")) % 4 % 6;
CHECK_XPATH_NODESET(n, STR("following::node()")) % 7;
CHECK_XPATH_NODESET(n, STR("following-sibling::node()")) % 7;
CHECK_XPATH_NODESET(n, STR("namespace::node()"));
CHECK_XPATH_NODESET(n, STR("parent::node()")) % 2;
CHECK_XPATH_NODESET(n, STR("preceding::node()")) % 3;
CHECK_XPATH_NODESET(n, STR("preceding-sibling::node()")) % 3;
CHECK_XPATH_NODESET(n, STR("self::node()")) % 4;
}
TEST_XML(xpath_paths_step_leaf_predicate_coverage, "<n><n1/><n2 a='v'><child/></n2><n3/></n>")
{
xml_node n = doc.child(STR("n")).child(STR("n2"));
CHECK_XPATH_NODESET(n, STR("ancestor::node()[1]")) % 2;
CHECK_XPATH_NODESET(n, STR("ancestor-or-self::node()[1]")) % 4;
CHECK_XPATH_NODESET(n, STR("attribute::node()[1]")) % 5;
CHECK_XPATH_NODESET(n, STR("child::node()[1]")) % 6;
CHECK_XPATH_NODESET(n, STR("descendant::node()[1]")) % 6;
CHECK_XPATH_NODESET(n, STR("descendant-or-self::node()[1]")) % 4;
CHECK_XPATH_NODESET(n, STR("following::node()[1]")) % 7;
CHECK_XPATH_NODESET(n, STR("following-sibling::node()[1]")) % 7;
CHECK_XPATH_NODESET(n, STR("namespace::node()[1]"));
CHECK_XPATH_NODESET(n, STR("parent::node()[1]")) % 2;
CHECK_XPATH_NODESET(n, STR("preceding::node()[1]")) % 3;
CHECK_XPATH_NODESET(n, STR("preceding-sibling::node()[1]")) % 3;
CHECK_XPATH_NODESET(n, STR("self::node()[1]")) % 4;
}
TEST_XML(xpath_paths_step_step_coverage, "<n><n1/><n2 a='v'><child/></n2><n3/></n>")
{
xml_node n = doc.child(STR("n")).child(STR("n2"));
CHECK_XPATH_NODESET(n, STR("./ancestor::node()")) % 2 % 1;
CHECK_XPATH_NODESET(n, STR("./ancestor-or-self::node()")) % 4 % 2 % 1;
CHECK_XPATH_NODESET(n, STR("./attribute::node()")) % 5;
CHECK_XPATH_NODESET(n, STR("./child::node()")) % 6;
CHECK_XPATH_NODESET(n, STR("./descendant::node()")) % 6;
CHECK_XPATH_NODESET(n, STR("./descendant-or-self::node()")) % 4 % 6;
CHECK_XPATH_NODESET(n, STR("./following::node()")) % 7;
CHECK_XPATH_NODESET(n, STR("./following-sibling::node()")) % 7;
CHECK_XPATH_NODESET(n, STR("./namespace::node()"));
CHECK_XPATH_NODESET(n, STR("./parent::node()")) % 2;
CHECK_XPATH_NODESET(n, STR("./preceding::node()")) % 3;
CHECK_XPATH_NODESET(n, STR("./preceding-sibling::node()")) % 3;
CHECK_XPATH_NODESET(n, STR("./self::node()")) % 4;
}
TEST_XML(xpath_paths_step_step_predicate_coverage, "<n><n1/><n2 a='v'><child/></n2><n3/></n>")
{
xml_node n = doc.child(STR("n")).child(STR("n2"));
CHECK_XPATH_NODESET(n, STR("./ancestor::node()[1]")) % 2;
CHECK_XPATH_NODESET(n, STR("./ancestor-or-self::node()[1]")) % 4;
CHECK_XPATH_NODESET(n, STR("./attribute::node()[1]")) % 5;
CHECK_XPATH_NODESET(n, STR("./child::node()[1]")) % 6;
CHECK_XPATH_NODESET(n, STR("./descendant::node()[1]")) % 6;
CHECK_XPATH_NODESET(n, STR("./descendant-or-self::node()[1]")) % 4;
CHECK_XPATH_NODESET(n, STR("./following::node()[1]")) % 7;
CHECK_XPATH_NODESET(n, STR("./following-sibling::node()[1]")) % 7;
CHECK_XPATH_NODESET(n, STR("./namespace::node()[1]"));
CHECK_XPATH_NODESET(n, STR("./parent::node()[1]")) % 2;
CHECK_XPATH_NODESET(n, STR("./preceding::node()[1]")) % 3;
CHECK_XPATH_NODESET(n, STR("./preceding-sibling::node()[1]")) % 3;
CHECK_XPATH_NODESET(n, STR("./self::node()[1]")) % 4;
}
#endif

View File

@ -0,0 +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

View File

@ -0,0 +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

View File

@ -0,0 +1,673 @@
#ifndef PUGIXML_NO_XPATH
#include "test.hpp"
#include <string>
using namespace pugi;
TEST(xpath_variables_type_none)
{
xpath_variable_set set;
xpath_variable* var = set.add(STR("target"), xpath_type_none);
CHECK(!var);
}
TEST(xpath_variables_type_boolean)
{
xpath_variable_set set;
xpath_variable* var = set.add(STR("target"), xpath_type_boolean);
CHECK(var);
CHECK(var->type() == xpath_type_boolean);
CHECK_STRING(var->name(), STR("target"));
CHECK(var->get_boolean() == false);
CHECK_DOUBLE_NAN(var->get_number());
CHECK_STRING(var->get_string(), STR(""));
CHECK(var->get_node_set().empty());
CHECK(var->set(true));
CHECK(!var->set(1.0));
CHECK(!var->set(STR("abc")));
CHECK(!var->set(xpath_node_set()));
CHECK(var->get_boolean() == true);
CHECK_DOUBLE_NAN(var->get_number());
CHECK_STRING(var->get_string(), STR(""));
CHECK(var->get_node_set().empty());
}
TEST(xpath_variables_type_number)
{
xpath_variable_set set;
xpath_variable* var = set.add(STR("target"), xpath_type_number);
CHECK(var);
CHECK(var->type() == xpath_type_number);
CHECK_STRING(var->name(), STR("target"));
CHECK(var->get_boolean() == false);
CHECK_DOUBLE(var->get_number(), 0);
CHECK_STRING(var->get_string(), STR(""));
CHECK(var->get_node_set().empty());
CHECK(!var->set(true));
CHECK(var->set(1.0));
CHECK(!var->set(STR("abc")));
CHECK(!var->set(xpath_node_set()));
CHECK(var->get_boolean() == false);
CHECK_DOUBLE(var->get_number(), 1);
CHECK_STRING(var->get_string(), STR(""));
CHECK(var->get_node_set().empty());
}
TEST(xpath_variables_type_string)
{
xpath_variable_set set;
xpath_variable* var = set.add(STR("target"), xpath_type_string);
CHECK(var);
CHECK(var->type() == xpath_type_string);
CHECK_STRING(var->name(), STR("target"));
CHECK(var->get_boolean() == false);
CHECK_DOUBLE_NAN(var->get_number());
CHECK_STRING(var->get_string(), STR(""));
CHECK(var->get_node_set().empty());
CHECK(!var->set(true));
CHECK(!var->set(1.0));
CHECK(var->set(STR("abc")));
CHECK(!var->set(xpath_node_set()));
CHECK(var->get_boolean() == false);
CHECK_DOUBLE_NAN(var->get_number());
CHECK_STRING(var->get_string(), STR("abc"));
CHECK(var->get_node_set().empty());
CHECK(var->set(STR("abcdef")));
CHECK_STRING(var->get_string(), STR("abcdef"));
}
TEST_XML(xpath_variables_type_node_set, "<node/>")
{
xpath_variable_set set;
xpath_variable* var = set.add(STR("target"), xpath_type_node_set);
CHECK(var);
CHECK(var->type() == xpath_type_node_set);
CHECK_STRING(var->name(), STR("target"));
CHECK(var->get_boolean() == false);
CHECK_DOUBLE_NAN(var->get_number());
CHECK_STRING(var->get_string(), STR(""));
CHECK(var->get_node_set().empty());
CHECK(!var->set(true));
CHECK(!var->set(1.0));
CHECK(!var->set(STR("abc")));
CHECK(var->set(doc.select_nodes(STR("*"))));
CHECK(var->get_boolean() == false);
CHECK_DOUBLE_NAN(var->get_number());
CHECK_STRING(var->get_string(), STR(""));
CHECK(var->get_node_set().size() == 1 && var->get_node_set()[0] == doc.first_child());
}
TEST(xpath_variables_set_operations)
{
xpath_variable_set set;
xpath_variable* v1 = set.add(STR("var1"), xpath_type_number);
CHECK(v1);
xpath_variable* v2 = set.add(STR("var2"), xpath_type_string);
CHECK(v2);
CHECK(v1 != v2);
CHECK(set.add(STR("var1"), xpath_type_number) == v1);
CHECK(set.add(STR("var2"), xpath_type_string) == v2);
CHECK(set.add(STR("var2"), xpath_type_node_set) == 0);
CHECK(set.get(STR("var1")) == v1);
CHECK(set.get(STR("var2")) == v2);
CHECK(set.get(STR("var")) == 0);
CHECK(set.get(STR("var11")) == 0);
CHECK(static_cast<const xpath_variable_set&>(set).get(STR("var1")) == v1);
CHECK(static_cast<const xpath_variable_set&>(set).get(STR("var3")) == 0);
}
TEST_XML(xpath_variables_set_operations_set, "<node/>")
{
xpath_variable_set set;
xpath_variable* v1 = set.add(STR("var1"), xpath_type_number);
CHECK(v1);
xpath_variable* v2 = set.add(STR("var2"), xpath_type_string);
CHECK(v2);
CHECK(set.set(STR("var1"), 1.0));
CHECK_DOUBLE(v1->get_number(), 1.0);
CHECK(set.set(STR("var2"), STR("value")));
CHECK_STRING(v2->get_string(), STR("value"));
CHECK(!set.set(STR("var1"), true));
CHECK(set.set(STR("var3"), doc.select_nodes(STR("*"))));
xpath_variable* v3 = set.get(STR("var3"));
CHECK(v3);
CHECK(v3->type() == xpath_type_node_set);
CHECK(v3->get_node_set().size() == 1);
}
TEST(xpath_variables_set_out_of_memory)
{
test_runner::_memory_fail_threshold = 1;
xpath_variable_set set;
xpath_variable* var = 0;
CHECK_ALLOC_FAIL(var = set.add(STR("target"), xpath_type_number));
CHECK(!var);
}
TEST(xpath_variables_out_of_memory)
{
test_runner::_memory_fail_threshold = 64;
xpath_variable_set set;
xpath_variable* var = set.add(STR("target"), xpath_type_string);
CHECK(var);
CHECK_ALLOC_FAIL(CHECK(!var->set(STR("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"))));
}
TEST_XML(xpath_variables_evaluate, "<node/>")
{
xpath_variable_set set;
set.set(STR("var1"), true);
set.set(STR("var2"), 0.5);
set.set(STR("var3"), STR("value"));
set.set(STR("var4"), doc.select_nodes(STR("*")));
CHECK_XPATH_BOOLEAN_VAR(doc, STR("$var1"), &set, true);
CHECK_XPATH_NUMBER_VAR(doc, STR("$var2"), &set, 0.5);
CHECK_XPATH_STRING_VAR(doc, STR("$var3"), &set, STR("value"));
CHECK_XPATH_NODESET_VAR(doc, STR("$var4"), &set) % 2;
}
TEST_XML(xpath_variables_evaluate_conversion, "<node>3</node>")
{
xpath_variable_set set;
set.set(STR("var"), doc.select_nodes(STR("*")));
CHECK_XPATH_BOOLEAN_VAR(doc, STR("$var"), &set, true);
CHECK_XPATH_NUMBER_VAR(doc, STR("$var"), &set, 3);
CHECK_XPATH_STRING_VAR(doc, STR("$var"), &set, STR("3"));
CHECK_XPATH_NODESET_VAR(doc, STR("$var"), &set) % 2;
}
TEST(xpath_variables_evaluate_node_set_fail)
{
xpath_variable_set set;
set.set(STR("var"), false);
xpath_query q(STR("$var"), &set);
#ifdef PUGIXML_NO_EXCEPTIONS
CHECK(q.evaluate_node_set(xml_node()).empty());
#else
try
{
q.evaluate_node_set(xml_node());
CHECK_FORCE_FAIL("Expected exception");
}
catch (const xpath_exception&)
{
}
#endif
}
TEST(xpath_variables_multiple_documents)
{
xml_document doc;
doc.append_child().set_name(STR("node"));
xml_document doc1;
doc1.append_child().set_name(STR("node"));
xml_document doc2;
doc2.append_child().set_name(STR("node"));
xpath_variable_set set;
set.set(STR("var1"), doc1.select_nodes(STR("*")));
set.set(STR("var2"), doc2.select_nodes(STR("*")));
xpath_node_set ns = doc.select_nodes(STR("$var1 | $var2 | node"), &set);
ns.sort();
CHECK(ns.size() == 3);
CHECK(ns[0] != ns[1] && ns[0] != ns[2]);
xml_node n0 = doc.child(STR("node")), n1 = doc1.child(STR("node")), n2 = doc2.child(STR("node"));
CHECK(n0 == ns[0].node() || n0 == ns[1].node() || n0 == ns[2].node());
CHECK(n1 == ns[0].node() || n1 == ns[1].node() || n1 == ns[2].node());
CHECK(n2 == ns[0].node() || n2 == ns[1].node() || n2 == ns[2].node());
}
TEST(xpath_variables_long_name)
{
xpath_variable_set set;
set.set(STR("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"), true);
CHECK_XPATH_BOOLEAN_VAR(xml_node(), STR("$abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"), &set, true);
}
TEST(xpath_variables_long_name_out_of_memory)
{
xpath_variable_set set;
set.set(STR("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"), true);
test_runner::_memory_fail_threshold = 4096 + 64 + 52 * sizeof(char_t);
CHECK_ALLOC_FAIL(CHECK(!xpath_query(STR("$abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"), &set)));
}
TEST_XML(xpath_variables_select, "<node attr='1'/><node attr='2'/>")
{
xpath_variable_set set;
set.set(STR("one"), 1.0);
xpath_node_set ns = doc.select_nodes(STR("node[@attr=$one+1]"), &set);
CHECK(ns.size() == 1 && ns[0].node() == doc.last_child());
xpath_node n = doc.select_node(STR("node[@attr=$one+1]"), &set);
CHECK(n == ns[0]);
}
TEST(xpath_variables_empty_name)
{
xpath_variable_set set;
CHECK(!set.add(STR(""), xpath_type_node_set));
CHECK(!set.add(STR(""), xpath_type_number));
CHECK(!set.add(STR(""), xpath_type_string));
CHECK(!set.add(STR(""), xpath_type_boolean));
}
TEST(xpath_variables_long_name_out_of_memory_add)
{
std::basic_string<char_t> name(1000, 'a');
test_runner::_memory_fail_threshold = 1000;
xpath_variable_set set;
CHECK_ALLOC_FAIL(CHECK(!set.add(name.c_str(), xpath_type_node_set)));
CHECK_ALLOC_FAIL(CHECK(!set.add(name.c_str(), xpath_type_number)));
CHECK_ALLOC_FAIL(CHECK(!set.add(name.c_str(), xpath_type_string)));
CHECK_ALLOC_FAIL(CHECK(!set.add(name.c_str(), xpath_type_boolean)));
}
TEST_XML(xpath_variables_inside_filter, "<node key='1' value='2'/><node key='2' value='1'/><node key='1' value='1'/>")
{
xpath_variable_set set;
set.set(STR("one"), 1.0);
xpath_node_set ns = doc.select_nodes(STR("(node[@key = $one])[@value = $one]"), &set);
CHECK(ns.size() == 1 && ns[0].node() == doc.last_child());
}
TEST_XML(xpath_variables_step, "<node><child/><child/><child><child/></child></node>")
{
xpath_variable_set set;
set.set(STR("root"), doc.select_nodes(STR("node")));
CHECK_XPATH_NODESET_VAR(xml_node(), STR("$root/child"), &set) % 3 % 4 % 5;
CHECK_XPATH_NODESET_VAR(xml_node(), STR("$root//child"), &set) % 3 % 4 % 5 % 6;
}
TEST_XML(xpath_variables_index, "<node><child/><child/><child><child/></child></node>")
{
xpath_variable_set set;
set.set(STR("index"), 2.0);
CHECK_XPATH_NODESET_VAR(doc, STR("node/child[$index]"), &set) % 4;
CHECK_XPATH_NODESET_VAR(doc, STR("node/child[position()=$index]"), &set) % 4;
}
TEST(xpath_variables_qname)
{
xpath_variable_set set;
set.set(STR("foo:bar"), true);
CHECK_XPATH_BOOLEAN_VAR(xml_node(), STR("$foo:bar"), &set, true);
}
TEST(xpath_variables_name_error)
{
xpath_variable_set set;
set.set(STR("foo:"), true);
set.set(STR(":bar"), true);
set.set(STR("foo:*"), true);
set.set(STR("foo"), true);
set.set(STR("3"), true);
CHECK_XPATH_FAIL_VAR(STR("$foo:"), &set);
CHECK_XPATH_FAIL_VAR(STR("$:bar"), &set);
CHECK_XPATH_FAIL_VAR(STR("$foo:*"), &set);
CHECK_XPATH_FAIL_VAR(STR("$foo:bar:baz"), &set);
CHECK_XPATH_FAIL_VAR(STR("$ foo"), &set);
CHECK_XPATH_FAIL_VAR(STR("$3"), &set);
}
TEST(xpath_variables_empty_string)
{
xpath_variable_set set;
set.add(STR("empty"), xpath_type_string);
CHECK_XPATH_BOOLEAN_VAR(xml_node(), STR("$empty = substring-before('a', 'z')"), &set, true);
}
TEST(xpath_variables_name_underscore)
{
xpath_variable_set set;
set.set(STR("_foo_bar"), true);
CHECK_XPATH_BOOLEAN_VAR(xml_node(), STR("$_foo_bar"), &set, true);
}
TEST(xpath_variables_name_case)
{
xpath_variable_set set;
set.set(STR("i"), 5.0);
set.set(STR("I"), 2.0);
CHECK_XPATH_NUMBER_VAR(xml_node(), STR("$i div $I"), &set, 2.5);
}
TEST(xpath_variables_name_unicode)
{
#ifdef PUGIXML_WCHAR_MODE
#ifdef U_LITERALS
const char_t* name = L"\u0400\u203D";
#else
const char_t* name = L"\x0400\x203D";
#endif
#else
const char_t* name = "\xd0\x80\xe2\x80\xbd";
#endif
xpath_variable_set set;
set.set(name, STR("value"));
std::basic_string<char_t> var = STR("$");
var += name;
CHECK_XPATH_STRING_VAR(xml_node(), var.c_str(), &set, STR("value"));
}
TEST_XML(xpath_variables_count_sum, "<node><c1>12</c1><c2>23</c2><c3>34</c3></node>")
{
xpath_variable_set set;
set.set(STR("c12"), doc.select_nodes(STR("node/c1 | node/c2")));
set.set(STR("c3"), doc.select_nodes(STR("node/c3")));
set.set(STR("c"), doc.select_nodes(STR("node/*")));
CHECK_XPATH_NUMBER_VAR(xml_node(), STR("sum($c12) * count($c) - sum($c3)"), &set, 71);
}
TEST_XML(xpath_variables_copy, "<node />")
{
xpath_variable_set set1;
set1.set(STR("a"), true);
set1.set(STR("b"), 2.0);
set1.set(STR("c"), STR("string"));
set1.set(STR("d"), doc.select_nodes(STR("//*")));
CHECK_XPATH_STRING_VAR(xml_node(), STR("substring($c, count($d[$a]) + $b)"), &set1, STR("ring"));
xpath_variable_set set2 = set1;
CHECK_XPATH_STRING_VAR(xml_node(), STR("substring($c, count($d[$a]) + $b)"), &set2, STR("ring"));
xpath_variable_set set3;
CHECK(!set3.get(STR("a")));
set3 = set1;
CHECK_XPATH_STRING_VAR(xml_node(), STR("substring($c, count($d[$a]) + $b)"), &set2, STR("ring"));
set3 = xpath_variable_set(set3);
CHECK_XPATH_STRING_VAR(xml_node(), STR("substring($c, count($d[$a]) + $b)"), &set2, STR("ring"));
set3 = xpath_variable_set();
CHECK(!set3.get(STR("a")));
}
TEST_XML(xpath_variables_copy_out_of_memory, "<node1 /><node2 />")
{
xpath_variable_set set1;
set1.set(STR("a"), true);
set1.set(STR("b"), 2.0);
set1.set(STR("c"), STR("string"));
set1.set(STR("d"), doc.select_nodes(STR("//*")));
xpath_variable_set set2 = set1;
test_runner::_memory_fail_threshold = 32768 + 75 * sizeof(void*);
CHECK_ALLOC_FAIL(xpath_variable_set set3 = set1);
xpath_variable_set set4;
CHECK_ALLOC_FAIL(set4 = set1);
CHECK(!set4.get(STR("a")) && !set4.get(STR("b")) && !set4.get(STR("c")) && !set4.get(STR("d")));
CHECK_ALLOC_FAIL(set2 = set1);
CHECK(set2.get(STR("a")) && set2.get(STR("b")) && set2.get(STR("c")) && set2.get(STR("d")));
CHECK(set2.get(STR("a"))->get_boolean() == true);
CHECK(set2.get(STR("b"))->get_number() == 2.0);
CHECK_STRING(set2.get(STR("c"))->get_string(), STR("string"));
CHECK(set2.get(STR("d"))->get_node_set().size() == 2);
}
TEST(xpath_variables_copy_out_of_memory_clone)
{
xpath_variable_set set1;
set1.set(STR("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"), true);
xpath_variable_set set2 = set1;
test_runner::_memory_fail_threshold = 60;
CHECK_ALLOC_FAIL(xpath_variable_set set3 = set1);
}
#ifdef PUGIXML_HAS_MOVE
TEST_XML(xpath_variables_move, "<node />")
{
xpath_variable_set set;
set.set(STR("a"), true);
set.set(STR("b"), 2.0);
set.set(STR("c"), STR("string"));
set.set(STR("d"), doc.select_nodes(STR("//*")));
xpath_variable_set copy = set;
copy.set(STR("e"), 42.0);
test_runner::_memory_fail_threshold = 1;
xpath_variable_set move1 = std::move(set);
CHECK(!set.get(STR("a")) && !set.get(STR("b")) && !set.get(STR("c")) && !set.get(STR("d")));
CHECK(move1.get(STR("a")) && move1.get(STR("b")) && move1.get(STR("c")) && move1.get(STR("d")));
CHECK(move1.get(STR("a"))->get_boolean() == true);
CHECK(move1.get(STR("b"))->get_number() == 2.0);
CHECK_STRING(move1.get(STR("c"))->get_string(), STR("string"));
CHECK(move1.get(STR("d"))->get_node_set().size() == 1);
xpath_variable_set move2;
move2 = std::move(move1);
CHECK(!move1.get(STR("a")) && !move1.get(STR("b")) && !move1.get(STR("c")) && !move1.get(STR("d")));
CHECK(move2.get(STR("a")) && move2.get(STR("b")) && move2.get(STR("c")) && move2.get(STR("d")));
CHECK(copy.get(STR("e")));
copy = std::move(move2);
CHECK(!move2.get(STR("a")) && !move2.get(STR("b")) && !move2.get(STR("c")) && !move2.get(STR("d")));
CHECK(copy.get(STR("a")) && copy.get(STR("b")) && copy.get(STR("c")) && copy.get(STR("d")));
CHECK(!copy.get(STR("e")));
CHECK(copy.get(STR("a"))->get_boolean() == true);
CHECK(copy.get(STR("b"))->get_number() == 2.0);
CHECK_STRING(copy.get(STR("c"))->get_string(), STR("string"));
CHECK(copy.get(STR("d"))->get_node_set().size() == 1);
}
#endif
TEST(xpath_variables_copy_big)
{
xpath_variable_set set;
for (int i = 0; i < 100; ++i)
{
char_t name[4];
name[0] = 'a';
name[1] = char_t('0' + i / 10);
name[2] = char_t('0' + i % 10);
name[3] = 0;
set.set(name, double(i));
}
xpath_variable_set copy = set;
for (int j = 0; j < 100; ++j)
{
char_t name[4];
name[0] = 'a';
name[1] = char_t('0' + j / 10);
name[2] = char_t('0' + j % 10);
name[3] = 0;
CHECK(copy.get(name) && copy.get(name)->get_number() == j);
}
}
TEST(xpath_variables_copy_big_out_of_memory)
{
xpath_variable_set set;
for (int i = 0; i < 100; ++i)
{
char_t name[4];
name[0] = 'a';
name[1] = char_t('0' + i / 10);
name[2] = char_t('0' + i % 10);
name[3] = 0;
set.set(name, double(i));
}
test_runner::_memory_fail_threshold = 1;
xpath_variable_set copy;
CHECK_ALLOC_FAIL(copy = set);
for (int j = 0; j < 100; ++j)
{
char_t name[4];
name[0] = 'a';
name[1] = char_t('0' + j / 10);
name[2] = char_t('0' + j % 10);
name[3] = 0;
CHECK(!copy.get(name));
}
}
TEST(xpath_variables_copy_big_value_out_of_memory)
{
xpath_variable_set set;
std::basic_string<char_t> var(10000, 'a');
set.set(STR("x"), var.c_str());
test_runner::_memory_fail_threshold = 15000;
xpath_variable_set copy;
CHECK_ALLOC_FAIL(copy = set);
CHECK(!copy.get(STR("x")));
}
TEST_XML(xpath_variables_evaluate_node_set_out_of_memory, "<node />")
{
for (size_t i = 0; i < 600; ++i)
doc.append_child(STR("node"));
xpath_node_set ns = doc.select_nodes(STR("node"));
CHECK(ns.size() == 601);
xpath_variable_set set;
set.set(STR("nodes"), ns);
xpath_query q(STR("$nodes"), &set);
test_runner::_memory_fail_threshold = 1;
CHECK_ALLOC_FAIL(q.evaluate_node_set(xml_node()).empty());
}
TEST_XML(xpath_variables_type_conversion, "<node>15</node>")
{
xpath_variable_set set;
set.set(STR("a"), true);
set.set(STR("b"), 42.0);
set.set(STR("c"), STR("test"));
set.set(STR("d"), doc.select_nodes(STR("node")));
CHECK_XPATH_BOOLEAN_VAR(xml_node(), STR("boolean($a) = true()"), &set, true);
CHECK_XPATH_BOOLEAN_VAR(xml_node(), STR("number($a) = 1"), &set, true);
CHECK_XPATH_BOOLEAN_VAR(xml_node(), STR("string($a) = 'true'"), &set, true);
CHECK_XPATH_BOOLEAN_VAR(xml_node(), STR("boolean($b) = true()"), &set, true);
CHECK_XPATH_BOOLEAN_VAR(xml_node(), STR("number($b) = 42"), &set, true);
CHECK_XPATH_BOOLEAN_VAR(xml_node(), STR("string($b) = '42'"), &set, true);
CHECK_XPATH_BOOLEAN_VAR(xml_node(), STR("boolean($c) = true()"), &set, true);
#ifndef MSVC6_NAN_BUG
CHECK_XPATH_BOOLEAN_VAR(xml_node(), STR("number($c) = 0"), &set, false);
#endif
CHECK_XPATH_BOOLEAN_VAR(xml_node(), STR("string($c) = 'test'"), &set, true);
CHECK_XPATH_BOOLEAN_VAR(xml_node(), STR("boolean($d) = true()"), &set, true);
CHECK_XPATH_BOOLEAN_VAR(xml_node(), STR("number($d) = 15"), &set, true);
CHECK_XPATH_BOOLEAN_VAR(xml_node(), STR("string($d) = '15'"), &set, true);
}
#endif

View File

@ -0,0 +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

View File

@ -0,0 +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

View File

@ -0,0 +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

View File

@ -0,0 +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

View File

@ -0,0 +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

View File

@ -0,0 +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();
}

View File

@ -0,0 +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