2.0.0-rc (#9)
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
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:
+175
@@ -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
@@ -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
|
||||
+87
@@ -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"
|
||||
+1
File diff suppressed because one or more lines are too long
@@ -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><Test></ARTICLE><ENTRY_NO>10</ENTRY_NO></ENTRY><ENTRY><ARTICLE><Test 2></ARTICLE><ENTRY_NO>20</ENTRY_NO></ENTRY></ENTRIES><FOOTER><TEXT>This is a text.</TEXT></FOOTER></ORDER></EXAMPLE>
|
||||
@@ -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><Test></ARTICLE><ENTRY_NO>10</ENTRY_NO></ENTRY><ENTRY><ARTICLE><Test 2></ARTICLE><ENTRY_NO>20</ENTRY_NO></ENTRY></ENTRIES><FOOTER><TEXT>This is a text.</TEXT></FOOTER></ORDER></EXAMPLE>
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
<node1 />
|
||||
<node2 />
|
||||
<node3 />
|
||||
+1
@@ -0,0 +1 @@
|
||||
<node/>
|
||||
+19
@@ -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.
+87
@@ -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"><имеет></Русский>
|
||||
<汉语 名字="name" 价值="value">世界有很多语言𤭢</汉语>
|
||||
<Heavy>"Mëtæl!"</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>
|
||||
</問題点対策>
|
||||
</業務報告>
|
||||
</業務報告リスト>
|
||||
</週報>
|
||||
@@ -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"><имеет></Русский>
|
||||
<汉语 名字="name" 价值="value">世界有很多语言𤭢</汉语>
|
||||
<Heavy>"Mëtæl!"</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>
|
||||
</問題点対策>
|
||||
</業務報告>
|
||||
</業務報告リスト>
|
||||
</週報>
|
||||
@@ -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"><имеет></Русский>
|
||||
<汉语 名字="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>
|
||||
</問題点対策>
|
||||
</業務報告>
|
||||
</業務報告リスト>
|
||||
</週報>
|
||||
@@ -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"><имеет></Русский>
|
||||
<汉语 名字="name" 价值="value">世界有很多语言𤭢</汉语>
|
||||
<Heavy>"Mëtæl!"</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>
|
||||
</問題点対策>
|
||||
</業務報告>
|
||||
</業務報告リスト>
|
||||
</週報>
|
||||
+1
@@ -0,0 +1 @@
|
||||
<node/>
|
||||
@@ -0,0 +1 @@
|
||||
<node attr="value" />
|
||||
@@ -0,0 +1 @@
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
||||
@@ -0,0 +1 @@
|
||||
<?xml version='1.0'?>
|
||||
@@ -0,0 +1 @@
|
||||
<?xml version='1.0'?>
|
||||
Binary file not shown.
Binary file not shown.
@@ -0,0 +1 @@
|
||||
a/b/c
|
||||
@@ -0,0 +1 @@
|
||||
sum(nodes) + round(concat(//a[translate(@id, 'abc', '012')]))
|
||||
@@ -0,0 +1 @@
|
||||
1+2*3 div 4 mod 5-6
|
||||
@@ -0,0 +1 @@
|
||||
@*/ancestor::*/near-north/*[4]/@*/preceding::text()
|
||||
@@ -0,0 +1 @@
|
||||
library/nodes[@id=12]/element[@type='translate'][1]
|
||||
+14
@@ -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
@@ -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="<"
|
||||
entity_decimal=""
|
||||
entity_external="&a;"
|
||||
entity_hex=""
|
||||
|
||||
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
@@ -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
@@ -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
@@ -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"
|
||||
">"
|
||||
">="
|
||||
"<"
|
||||
"<="
|
||||
"!"
|
||||
"!="
|
||||
"="
|
||||
"+"
|
||||
"-"
|
||||
"*"
|
||||
"|"
|
||||
"$"
|
||||
"("
|
||||
")"
|
||||
"["
|
||||
"]"
|
||||
","
|
||||
"//"
|
||||
"/"
|
||||
".."
|
||||
"."
|
||||
"@"
|
||||
"::"
|
||||
":"
|
||||
Vendored
+114
@@ -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
|
||||
Vendored
+218
@@ -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
|
||||
Vendored
+220
@@ -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
|
||||
}
|
||||
Vendored
+175
@@ -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
@@ -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
|
||||
+25
@@ -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
File diff suppressed because it is too large
Load Diff
+1869
File diff suppressed because it is too large
Load Diff
+487
@@ -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
|
||||
}
|
||||
+1304
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,3 @@
|
||||
// Tests header guards
|
||||
#include "../src/pugixml.hpp"
|
||||
#include "../src/pugixml.hpp"
|
||||
@@ -0,0 +1,3 @@
|
||||
// Tests compatibility with iosfwd
|
||||
#include "../src/pugixml.hpp"
|
||||
#include <iosfwd>
|
||||
@@ -0,0 +1,3 @@
|
||||
// Tests compatibility with iosfwd
|
||||
#include <iosfwd>
|
||||
#include "../src/pugixml.hpp"
|
||||
@@ -0,0 +1,3 @@
|
||||
// Tests compatibility with iostream
|
||||
#include "../src/pugixml.hpp"
|
||||
#include <iostream>
|
||||
@@ -0,0 +1,3 @@
|
||||
// Tests compatibility with iostream
|
||||
#include <iostream>
|
||||
#include "../src/pugixml.hpp"
|
||||
+21
@@ -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
|
||||
}
|
||||
+21
@@ -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
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
// Tests compatibility with string
|
||||
#include "../src/pugixml.hpp"
|
||||
#include <string>
|
||||
@@ -0,0 +1,3 @@
|
||||
// Tests compatibility with string
|
||||
#include <string>
|
||||
#include "../src/pugixml.hpp"
|
||||
@@ -0,0 +1,5 @@
|
||||
// Tests compatibility with string/iostream
|
||||
#include <string>
|
||||
#include "../src/pugixml.hpp"
|
||||
#include <istream>
|
||||
#include <ostream>
|
||||
+303
@@ -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
File diff suppressed because it is too large
Load Diff
+366
@@ -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 \"&#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; ! &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๜></X๜>\"> ]>");
|
||||
}
|
||||
|
||||
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 \"\"> ]>");
|
||||
TEST_DOCTYPE_WF("<!DOCTYPE foo [ <!ELEMENT foo (foo*)> <!ENTITY e \"abc…def\"> ]>");
|
||||
TEST_DOCTYPE_WF("<!DOCTYPE foo [ <!ELEMENT foo ANY> <!ATTLIST foo bar NMTOKENS #IMPLIED> <!ENTITY val \"abc…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&#x3c;\"> <!ATTLIST student att1 CDATA #REQUIRED> ]>");
|
||||
TEST_DOCTYPE_WF("<!DOCTYPE student [ <!ELEMENT student (#PCDATA)> <!ENTITY gewithlt \"abcd<\"> <!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 <? '''"&ent2; %ent1;\"> <!ENTITY % ent4 '\"\"''\"'> ]>");
|
||||
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�<!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='&'></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
@@ -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
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
#include "../src/pugixml.hpp"
|
||||
|
||||
#if PUGIXML_VERSION != 1130
|
||||
#error Unexpected pugixml version
|
||||
#endif
|
||||
+733
@@ -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=\"<>'"& 	\"><>'\"&\r\n\t</node>"));
|
||||
CHECK_NODE_EX(doc, STR("<node attr='<>'\"& 	'><>'\"&\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=\"<>'"& 	\"><>'\"&\n\t</node>"));
|
||||
CHECK_NODE_EX(doc, STR("<node attr='<>'\"& 	'><>'\"&\n\t</node>"), STR(""), format_raw | format_attribute_single_quote);
|
||||
}
|
||||
|
||||
TEST_XML(write_escape_unicode, "<node attr='㰀'/>")
|
||||
{
|
||||
#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
\"'>&\x14\xF0\xA4\xAD\xA2<</\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=\""\xF0\xA4\xAD\xA2 "\">&\xF0\xA4\xAD\xA2<</\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<text&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>\t\n</a>\n"), STR(""), pugi::format_default);
|
||||
}
|
||||
+815
@@ -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
|
||||
+644
@@ -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
|
||||
+844
@@ -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
|
||||
+566
@@ -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
|
||||
+416
@@ -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
|
||||
+783
@@ -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
|
||||
@@ -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
|
||||
+312
@@ -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
|
||||
+673
@@ -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
|
||||
+411
@@ -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
|
||||
+417
@@ -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
|
||||
+321
@@ -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
|
||||
+300
@@ -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
|
||||
+295
@@ -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
|
||||
+79
@@ -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();
|
||||
}
|
||||
+27
@@ -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
|
||||
Reference in New Issue
Block a user