From 7d24b9b5655d584b6dc8b89df7cbd58d2e940a81 Mon Sep 17 00:00:00 2001 From: "arseny.kapoulkine" Date: Mon, 19 Jul 2010 09:57:32 +0000 Subject: Set svn:eol-style to native for all text files git-svn-id: http://pugixml.googlecode.com/svn/trunk@607 99668b35-9821-0410-8761-19e4c4f06640 --- tests/allocator.cpp | 188 ++-- tests/allocator.hpp | 20 +- tests/archive.pl | 120 +-- tests/autotest-local.pl | 252 +++--- tests/autotest-report.pl | 398 ++++----- tests/common.hpp | 16 +- tests/data/multiline.xml | 6 +- tests/gcov-filter.pl | 26 +- tests/helpers.hpp | 194 ++--- tests/main.cpp | 298 +++---- tests/test.cpp | 362 ++++---- tests/test.hpp | 302 +++---- tests/test_deprecated.cpp | 406 ++++----- tests/test_document.cpp | 1420 +++++++++++++++---------------- tests/test_dom_modify.cpp | 1318 ++++++++++++++-------------- tests/test_dom_traverse.cpp | 1512 ++++++++++++++++----------------- tests/test_header_guard.cpp | 6 +- tests/test_header_iosfwd_1.cpp | 6 +- tests/test_header_iosfwd_2.cpp | 6 +- tests/test_header_iostream_1.cpp | 6 +- tests/test_header_iostream_2.cpp | 6 +- tests/test_header_string_1.cpp | 6 +- tests/test_header_string_2.cpp | 6 +- tests/test_memory.cpp | 258 +++--- tests/test_parse.cpp | 1366 ++++++++++++++--------------- tests/test_parse_doctype.cpp | 550 ++++++------ tests/test_unicode.cpp | 274 +++--- tests/test_write.cpp | 708 +++++++-------- tests/test_xpath.cpp | 454 +++++----- tests/test_xpath_api.cpp | 300 +++---- tests/test_xpath_functions.cpp | 1494 ++++++++++++++++---------------- tests/test_xpath_operators.cpp | 946 ++++++++++----------- tests/test_xpath_parse.cpp | 544 ++++++------ tests/test_xpath_paths.cpp | 944 ++++++++++---------- tests/test_xpath_paths_abbrev_w3c.cpp | 434 +++++----- tests/test_xpath_paths_w3c.cpp | 620 +++++++------- tests/test_xpath_xalan_1.cpp | 814 +++++++++--------- tests/test_xpath_xalan_2.cpp | 798 ++++++++--------- tests/test_xpath_xalan_3.cpp | 638 +++++++------- tests/test_xpath_xalan_4.cpp | 596 ++++++------- tests/test_xpath_xalan_5.cpp | 586 ++++++------- tests/writer_string.cpp | 154 ++-- tests/writer_string.hpp | 54 +- 43 files changed, 9706 insertions(+), 9706 deletions(-) (limited to 'tests') diff --git a/tests/allocator.cpp b/tests/allocator.cpp index e0efeef..234f95c 100644 --- a/tests/allocator.cpp +++ b/tests/allocator.cpp @@ -1,94 +1,94 @@ -#include "allocator.hpp" - -#include - -// Low-level allocation functions -#if defined(_WIN32) || defined(_WIN64) -# ifdef __MWERKS__ -# pragma ANSI_strict off // disable ANSI strictness to include windows.h -# pragma cpp_extensions on // enable some extensions to include windows.h -# endif - -# ifdef _XBOX_VER -# define NOD3D -# include -# else -# include -# endif - -namespace -{ - const size_t PAGE_SIZE = 4096; - - void* allocate(size_t size) - { - size_t aligned_size = (size + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1); - - void* ptr = VirtualAlloc(0, aligned_size + PAGE_SIZE, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); - if (!ptr) return 0; - - void* end = (char*)ptr + aligned_size; - - DWORD old_flags; - VirtualProtect(end, PAGE_SIZE, PAGE_NOACCESS, &old_flags); - - return (char*)end - size; - } - - void deallocate(void* ptr, size_t size) - { - size_t aligned_size = (size + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1); - - void* rptr = (char*)ptr + size - aligned_size; - - DWORD old_flags; - VirtualProtect(rptr, aligned_size + PAGE_SIZE, PAGE_NOACCESS, &old_flags); - } -} -#else -# include - -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 -void* memory_allocate(size_t size) -{ - void* result = allocate(size + sizeof(size_t)); - if (!result) return 0; - - memcpy(result, &size, sizeof(size_t)); - - return (size_t*)result + 1; -} - -size_t memory_size(void* ptr) -{ - size_t result; - memcpy(&result, (size_t*)ptr - 1, sizeof(size_t)); - - return result; -} - -void memory_deallocate(void* ptr) -{ - if (!ptr) return; - - size_t size = memory_size(ptr); - - deallocate((size_t*)ptr - 1, size + sizeof(size_t)); -} - +#include "allocator.hpp" + +#include + +// Low-level allocation functions +#if defined(_WIN32) || defined(_WIN64) +# ifdef __MWERKS__ +# pragma ANSI_strict off // disable ANSI strictness to include windows.h +# pragma cpp_extensions on // enable some extensions to include windows.h +# endif + +# ifdef _XBOX_VER +# define NOD3D +# include +# else +# include +# endif + +namespace +{ + const size_t PAGE_SIZE = 4096; + + void* allocate(size_t size) + { + size_t aligned_size = (size + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1); + + void* ptr = VirtualAlloc(0, aligned_size + PAGE_SIZE, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); + if (!ptr) return 0; + + void* end = (char*)ptr + aligned_size; + + DWORD old_flags; + VirtualProtect(end, PAGE_SIZE, PAGE_NOACCESS, &old_flags); + + return (char*)end - size; + } + + void deallocate(void* ptr, size_t size) + { + size_t aligned_size = (size + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1); + + void* rptr = (char*)ptr + size - aligned_size; + + DWORD old_flags; + VirtualProtect(rptr, aligned_size + PAGE_SIZE, PAGE_NOACCESS, &old_flags); + } +} +#else +# include + +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 +void* memory_allocate(size_t size) +{ + void* result = allocate(size + sizeof(size_t)); + if (!result) return 0; + + memcpy(result, &size, sizeof(size_t)); + + return (size_t*)result + 1; +} + +size_t memory_size(void* ptr) +{ + size_t result; + memcpy(&result, (size_t*)ptr - 1, sizeof(size_t)); + + return result; +} + +void memory_deallocate(void* ptr) +{ + if (!ptr) return; + + size_t size = memory_size(ptr); + + deallocate((size_t*)ptr - 1, size + sizeof(size_t)); +} + diff --git a/tests/allocator.hpp b/tests/allocator.hpp index 677fbe4..cb52c91 100644 --- a/tests/allocator.hpp +++ b/tests/allocator.hpp @@ -1,10 +1,10 @@ -#ifndef HEADER_TEST_ALLOCATOR_HPP -#define HEADER_TEST_ALLOCATOR_HPP - -#include - -void* memory_allocate(size_t size); -size_t memory_size(void* ptr); -void memory_deallocate(void* ptr); - -#endif +#ifndef HEADER_TEST_ALLOCATOR_HPP +#define HEADER_TEST_ALLOCATOR_HPP + +#include + +void* memory_allocate(size_t size); +size_t memory_size(void* ptr); +void memory_deallocate(void* ptr); + +#endif diff --git a/tests/archive.pl b/tests/archive.pl index 240dd02..4ede302 100644 --- a/tests/archive.pl +++ b/tests/archive.pl @@ -1,60 +1,60 @@ -#!/usr/bin/perl - -use Archive::Tar; -use Archive::Zip; - -my $target = shift @ARGV; -my @sources = @ARGV; - -my $zip = $target =~ /\.zip$/; - -my $arch = $zip ? Archive::Zip->new : Archive::Tar->new; - -for $source (sort {$a cmp $b} @sources) -{ - my $contents = &readfile_contents($source); - my $meta = &readfile_meta($source); - - if ($zip) - { - my $path = $source; - $arch->addDirectory($path) if $path =~ s/\/[^\/]+$/\// && !defined($arch->memberNamed($path)); - - my $member = $arch->addString($contents, $source); - - $member->desiredCompressionMethod(COMPRESSION_DEFLATED); - $member->desiredCompressionLevel(9); - - $member->setLastModFileDateTimeFromUnix($$meta{mtime}); - } - else - { - # tgz releases are for Unix people, Unix people like Unix newlines - $contents =~ s/\r//g if (-T $source); - - $arch->add_data($source, $contents, $meta); - } -} - -$zip ? $arch->overwriteAs($target) : $arch->write($target, 9); - -sub readfile_contents -{ - my $file = shift; - - open FILE, $file or die "Can't open $file: $!"; - binmode FILE; - my @contents = ; - close FILE; - - return join('', @contents); -} - -sub readfile_meta -{ - my $file = shift; - - my ($dev, $ino, $mode, $nlink, $uid, $gid, $rdev, $size, $atime, $mtime, $ctime, $blksize, $blocks) = stat($file); - - return {mtime => $mtime}; -} +#!/usr/bin/perl + +use Archive::Tar; +use Archive::Zip; + +my $target = shift @ARGV; +my @sources = @ARGV; + +my $zip = $target =~ /\.zip$/; + +my $arch = $zip ? Archive::Zip->new : Archive::Tar->new; + +for $source (sort {$a cmp $b} @sources) +{ + my $contents = &readfile_contents($source); + my $meta = &readfile_meta($source); + + if ($zip) + { + my $path = $source; + $arch->addDirectory($path) if $path =~ s/\/[^\/]+$/\// && !defined($arch->memberNamed($path)); + + my $member = $arch->addString($contents, $source); + + $member->desiredCompressionMethod(COMPRESSION_DEFLATED); + $member->desiredCompressionLevel(9); + + $member->setLastModFileDateTimeFromUnix($$meta{mtime}); + } + else + { + # tgz releases are for Unix people, Unix people like Unix newlines + $contents =~ s/\r//g if (-T $source); + + $arch->add_data($source, $contents, $meta); + } +} + +$zip ? $arch->overwriteAs($target) : $arch->write($target, 9); + +sub readfile_contents +{ + my $file = shift; + + open FILE, $file or die "Can't open $file: $!"; + binmode FILE; + my @contents = ; + close FILE; + + return join('', @contents); +} + +sub readfile_meta +{ + my $file = shift; + + my ($dev, $ino, $mode, $nlink, $uid, $gid, $rdev, $size, $atime, $mtime, $ctime, $blksize, $blocks) = stat($file); + + return {mtime => $mtime}; +} diff --git a/tests/autotest-local.pl b/tests/autotest-local.pl index 86e5114..b0e9a6c 100644 --- a/tests/autotest-local.pl +++ b/tests/autotest-local.pl @@ -1,126 +1,126 @@ -#!/usr/bin/perl - -use Config; - -sub permute -{ - my @defines = @_; - my @result = (''); - - foreach $define (@defines) - { - push @result, map { length($_) == 0 ? $define : "$_,$define" } @result; - } - - @result; -} - -sub gcctoolset -{ - my $gccversion = `gcc -dumpversion`; - chomp($gccversion); - - my $gcc = "gcc$gccversion"; - - return ($^O =~ /darwin/) ? ($gcc, "${gcc}_x64", "${gcc}_ppc") : (`uname -m` =~ /64/) ? ("${gcc}_x64") : ($gcc); -} - -$fast = (shift eq 'fast'); -@toolsets = ($^O =~ /MSWin/) ? (bcc, cw, dmc, ic8, ic9, ic9_x64, ic10, ic10_x64, ic11, ic11_x64, mingw34, mingw44, mingw45, mingw45_0x, mingw46_x64, msvc6, msvc7, msvc71, msvc8, msvc8_x64, msvc9, msvc9_x64, msvc10, msvc10_x64, xbox360, ps3_gcc, ps3_snc) : ($^O =~ /solaris/) ? (suncc, suncc_x64) : &gcctoolset(); -@configurations = (debug, release); -@defines = (PUGIXML_NO_XPATH, PUGIXML_NO_EXCEPTIONS, PUGIXML_NO_STL, PUGIXML_WCHAR_MODE); -$stddefine = 'PUGIXML_STANDARD'; - -if ($fast) -{ - @defines = (PUGIXML_WCHAR_MODE); - @configurations = (debug); -} - -@definesets = permute(@defines); - -print "### autotest begin " . scalar localtime() . "\n"; - -# print SVN revision info -print "### autotest revision $1\n" if (`svn info` =~ /Revision:\s+(\d+)/); - -# build all configurations -%results = (); - -foreach $toolset (@toolsets) -{ - my $cmdline = "jam"; - - # parallel build on non-windows platforms (since jam can't detect processor count) - $cmdline .= " -j6" if ($^O !~ /MSWin/); - - # add toolset - $cmdline .= " toolset=$toolset"; - - # add configurations - $cmdline .= " configuration=" . join(',', @configurations); - - # add definesets - $cmdline .= " defines=$stddefine"; - - foreach $defineset (@definesets) - { - if ($defineset !~ /NO_XPATH/ && $defineset =~ /NO_EXCEPTIONS/) { next; } - if ($defineset !~ /NO_XPATH/ && $defineset =~ /NO_STL/) { next; } - - $cmdline .= ":$defineset" if ($defineset ne ''); - - # any configuration with prepare but without result is treated as failed - foreach $configuration (@configurations) - { - print "### autotest $Config{archname} $toolset $configuration [$defineset] prepare\n"; - } - } - - print STDERR "*** testing $toolset... ***\n"; - - # launch command - print "### autotest launch $cmdline\n"; - - open PIPE, "$cmdline autotest=on coverage |" || die "$cmdline failed: $!\n"; - - # parse build output - while () - { - # ... autotest release [wchar] success - if (/^\.\.\. autotest (\S+) \[(.*?)\] success/) - { - my $configuration = $1; - my $defineset = ($2 eq $stddefine) ? '' : $2; - - print "### autotest $Config{archname} $toolset $configuration [$defineset] success\n"; - } - # ... autotest release [wchar] gcov - elsif (/^\.\.\. autotest (\S+) \[(.*?)\] gcov/) - { - my $configuration = $1; - my $defineset = ($2 eq $stddefine) ? '' : $2; - my $file; - - $file = "pugixml $1" if (/pugixml\.cpp' executed:([^%]+)%/); - $file = "pugixpath $1" if (/pugixpath\.cpp' executed:([^%]+)%/); - - if (defined($file)) - { - print "### autotest $Config{archname} $toolset $configuration [$defineset] coverage $file\n"; - } - else - { - print; - } - } - else - { - print; - } - } - - close PIPE; -} - -print "### autotest end " . scalar localtime() . "\n"; +#!/usr/bin/perl + +use Config; + +sub permute +{ + my @defines = @_; + my @result = (''); + + foreach $define (@defines) + { + push @result, map { length($_) == 0 ? $define : "$_,$define" } @result; + } + + @result; +} + +sub gcctoolset +{ + my $gccversion = `gcc -dumpversion`; + chomp($gccversion); + + my $gcc = "gcc$gccversion"; + + return ($^O =~ /darwin/) ? ($gcc, "${gcc}_x64", "${gcc}_ppc") : (`uname -m` =~ /64/) ? ("${gcc}_x64") : ($gcc); +} + +$fast = (shift eq 'fast'); +@toolsets = ($^O =~ /MSWin/) ? (bcc, cw, dmc, ic8, ic9, ic9_x64, ic10, ic10_x64, ic11, ic11_x64, mingw34, mingw44, mingw45, mingw45_0x, mingw46_x64, msvc6, msvc7, msvc71, msvc8, msvc8_x64, msvc9, msvc9_x64, msvc10, msvc10_x64, xbox360, ps3_gcc, ps3_snc) : ($^O =~ /solaris/) ? (suncc, suncc_x64) : &gcctoolset(); +@configurations = (debug, release); +@defines = (PUGIXML_NO_XPATH, PUGIXML_NO_EXCEPTIONS, PUGIXML_NO_STL, PUGIXML_WCHAR_MODE); +$stddefine = 'PUGIXML_STANDARD'; + +if ($fast) +{ + @defines = (PUGIXML_WCHAR_MODE); + @configurations = (debug); +} + +@definesets = permute(@defines); + +print "### autotest begin " . scalar localtime() . "\n"; + +# print SVN revision info +print "### autotest revision $1\n" if (`svn info` =~ /Revision:\s+(\d+)/); + +# build all configurations +%results = (); + +foreach $toolset (@toolsets) +{ + my $cmdline = "jam"; + + # parallel build on non-windows platforms (since jam can't detect processor count) + $cmdline .= " -j6" if ($^O !~ /MSWin/); + + # add toolset + $cmdline .= " toolset=$toolset"; + + # add configurations + $cmdline .= " configuration=" . join(',', @configurations); + + # add definesets + $cmdline .= " defines=$stddefine"; + + foreach $defineset (@definesets) + { + if ($defineset !~ /NO_XPATH/ && $defineset =~ /NO_EXCEPTIONS/) { next; } + if ($defineset !~ /NO_XPATH/ && $defineset =~ /NO_STL/) { next; } + + $cmdline .= ":$defineset" if ($defineset ne ''); + + # any configuration with prepare but without result is treated as failed + foreach $configuration (@configurations) + { + print "### autotest $Config{archname} $toolset $configuration [$defineset] prepare\n"; + } + } + + print STDERR "*** testing $toolset... ***\n"; + + # launch command + print "### autotest launch $cmdline\n"; + + open PIPE, "$cmdline autotest=on coverage |" || die "$cmdline failed: $!\n"; + + # parse build output + while () + { + # ... autotest release [wchar] success + if (/^\.\.\. autotest (\S+) \[(.*?)\] success/) + { + my $configuration = $1; + my $defineset = ($2 eq $stddefine) ? '' : $2; + + print "### autotest $Config{archname} $toolset $configuration [$defineset] success\n"; + } + # ... autotest release [wchar] gcov + elsif (/^\.\.\. autotest (\S+) \[(.*?)\] gcov/) + { + my $configuration = $1; + my $defineset = ($2 eq $stddefine) ? '' : $2; + my $file; + + $file = "pugixml $1" if (/pugixml\.cpp' executed:([^%]+)%/); + $file = "pugixpath $1" if (/pugixpath\.cpp' executed:([^%]+)%/); + + if (defined($file)) + { + print "### autotest $Config{archname} $toolset $configuration [$defineset] coverage $file\n"; + } + else + { + print; + } + } + else + { + print; + } + } + + close PIPE; +} + +print "### autotest end " . scalar localtime() . "\n"; diff --git a/tests/autotest-report.pl b/tests/autotest-report.pl index a01a907..993674a 100644 --- a/tests/autotest-report.pl +++ b/tests/autotest-report.pl @@ -1,199 +1,199 @@ -#!/usr/bin/perl - -# pretty-printing -sub prettysuffix -{ - my $suffix = shift; - - return " C++0x" if ($suffix eq '_0x'); - return " x64" if ($suffix eq '_x64'); - return " PPC" if ($suffix eq '_ppc'); - - return ""; -} - -sub prettytoolset -{ - my $toolset = shift; - - return "Borland C++ 5.82" if ($toolset eq 'bcc'); - return "Metrowerks CodeWarrior 8" if ($toolset eq 'cw'); - return "Digital Mars C++ 8.51" if ($toolset eq 'dmc'); - return "Sun C++ 5.10" . prettysuffix($1) if ($toolset =~ /^suncc(.*)$/); - - return "Intel C++ Compiler $1.0" . prettysuffix($2) if ($toolset =~ /^ic(\d+)(.*)$/); - return "MinGW (GCC $1.$2)" . prettysuffix($3) if ($toolset =~ /^mingw(\d)(\d)(.*)$/); - return "Microsoft Visual C++ 7.1" if ($toolset eq 'msvc71'); - return "Microsoft Visual C++ $1.0" . prettysuffix($2) if ($toolset =~ /^msvc(\d+)(.*)$/); - return "GNU C++ Compiler $1" . prettysuffix($2) if ($toolset =~ /^gcc([\d.]*)(.*)$/); - - return "Microsoft Xbox360 Compiler" if ($toolset =~ /^xbox360/); - return "Sony PlayStation3 GCC" if ($toolset =~ /^ps3_gcc/); - return "Sony PlayStation3 SNC" if ($toolset =~ /^ps3_snc/); - - $toolset; -} - -sub prettyplatform -{ - my ($platform, $toolset) = @_; - - return "solaris" if ($platform =~ /solaris/); - - return "macos" if ($platform =~ /darwin/); - - return "linux64" if ($platform =~ /64-linux/); - return "linux32" if ($platform =~ /86-linux/); - - return "fbsd64" if ($platform =~ /64-freebsd/); - return "fbsd32" if ($platform =~ /86-freebsd/); - - return "x360" if ($toolset =~ /^xbox360/); - return "ps3" if ($toolset =~ /^ps3/); - - return "win64" if ($platform =~ /MSWin32-x64/); - return "win32" if ($platform =~ /MSWin32/); - - $platform; -} - -# parse build log -%results = (); -%toolsets = (); -%defines = (); -%configurations = (); - -sub insertindex -{ - my ($hash, $key) = @_; - - $$hash{$key} = scalar(keys %$hash) unless defined $$hash{$key}; -} - -while (<>) -{ - ### autotest i386-freebsd-64int gcc release [wchar] result 0 97.78 98.85 - if (/^### autotest (\S+) (\S+) (\S+) \[(.*?)\] (.*)/) - { - my ($platform, $toolset, $configuration, $defineset, $info) = ($1, $2, $3, $4, $5); - - my $fulltool = &prettyplatform($platform, $toolset) . ' ' . &prettytoolset($toolset); - my $fullconf = "$configuration $defineset"; - - if ($info =~ /^prepare/) - { - $results{$fulltool}{$fullconf}{result} = 1; - } - elsif ($info =~ /^success/) - { - $results{$fulltool}{$fullconf}{result} = 0; - } - elsif ($info =~ /^coverage (\S+) (\S+)/) - { - $results{$fulltool}{$fullconf}{"coverage_$1"} = $2; - } - else - { - print STDERR "Unrecognized autotest infoline $_"; - } - - &insertindex(\%toolsets, $fulltool); - - $defines{$_} = 1 foreach (split /,/, $defineset); - &insertindex(\%configurations, $fullconf); - } - elsif (/^### autotest revision (\d+)/) - { - if (defined $revision && $revision != $1) - { - print STDERR "Autotest build report contains several revisions: $revision, $1\n"; - } - else - { - $revision = $1; - } - } -} - -# make arrays of toolsets and configurations -@toolsetarray = (); -@configurationarray = (); - -$toolsetarray[$toolsets{$_}] = $_ foreach (keys %toolsets); -$configurationarray[$configurations{$_}] = $_ foreach (keys %configurations); - -# print header -$stylesheet = <pugixml autotest report -

pugixml autotest report

- -END - -# print configuration header (release/debug) -print ""; -print "" foreach (@configurationarray); -print "\n"; - -# print defines header (one row for each define) -foreach $define (sort {$a cmp $b} keys %defines) -{ - print ""; - - foreach (@configurationarray) - { - my $present = ($_ =~ /\b$define\b/); - my $color = $present ? "#cccccc" : "#ffffff"; - print ""; - } - print "\n"; -} - -# print data (one row for each toolset) -foreach $tool (@toolsetarray) -{ - my ($platform, $toolset) = split(/\s+/, $tool, 2); - print ""; - - foreach (@configurationarray) - { - my $info = $results{$tool}{$_}; - - if (!defined $$info{result}) - { - print ""; - } - elsif ($$info{result} == 0) - { - my ($coverage_pugixml, $coverage_pugixpath) = ($$info{coverage_pugixml}, $$info{coverage_pugixpath}); - - print ""; - } - else - { - print "" - } - } - - print "\n"; -} - -# print footer -$date = localtime; - -print <
-Generated on $date from Subversion r$revision - -END +#!/usr/bin/perl + +# pretty-printing +sub prettysuffix +{ + my $suffix = shift; + + return " C++0x" if ($suffix eq '_0x'); + return " x64" if ($suffix eq '_x64'); + return " PPC" if ($suffix eq '_ppc'); + + return ""; +} + +sub prettytoolset +{ + my $toolset = shift; + + return "Borland C++ 5.82" if ($toolset eq 'bcc'); + return "Metrowerks CodeWarrior 8" if ($toolset eq 'cw'); + return "Digital Mars C++ 8.51" if ($toolset eq 'dmc'); + return "Sun C++ 5.10" . prettysuffix($1) if ($toolset =~ /^suncc(.*)$/); + + return "Intel C++ Compiler $1.0" . prettysuffix($2) if ($toolset =~ /^ic(\d+)(.*)$/); + return "MinGW (GCC $1.$2)" . prettysuffix($3) if ($toolset =~ /^mingw(\d)(\d)(.*)$/); + return "Microsoft Visual C++ 7.1" if ($toolset eq 'msvc71'); + return "Microsoft Visual C++ $1.0" . prettysuffix($2) if ($toolset =~ /^msvc(\d+)(.*)$/); + return "GNU C++ Compiler $1" . prettysuffix($2) if ($toolset =~ /^gcc([\d.]*)(.*)$/); + + return "Microsoft Xbox360 Compiler" if ($toolset =~ /^xbox360/); + return "Sony PlayStation3 GCC" if ($toolset =~ /^ps3_gcc/); + return "Sony PlayStation3 SNC" if ($toolset =~ /^ps3_snc/); + + $toolset; +} + +sub prettyplatform +{ + my ($platform, $toolset) = @_; + + return "solaris" if ($platform =~ /solaris/); + + return "macos" if ($platform =~ /darwin/); + + return "linux64" if ($platform =~ /64-linux/); + return "linux32" if ($platform =~ /86-linux/); + + return "fbsd64" if ($platform =~ /64-freebsd/); + return "fbsd32" if ($platform =~ /86-freebsd/); + + return "x360" if ($toolset =~ /^xbox360/); + return "ps3" if ($toolset =~ /^ps3/); + + return "win64" if ($platform =~ /MSWin32-x64/); + return "win32" if ($platform =~ /MSWin32/); + + $platform; +} + +# parse build log +%results = (); +%toolsets = (); +%defines = (); +%configurations = (); + +sub insertindex +{ + my ($hash, $key) = @_; + + $$hash{$key} = scalar(keys %$hash) unless defined $$hash{$key}; +} + +while (<>) +{ + ### autotest i386-freebsd-64int gcc release [wchar] result 0 97.78 98.85 + if (/^### autotest (\S+) (\S+) (\S+) \[(.*?)\] (.*)/) + { + my ($platform, $toolset, $configuration, $defineset, $info) = ($1, $2, $3, $4, $5); + + my $fulltool = &prettyplatform($platform, $toolset) . ' ' . &prettytoolset($toolset); + my $fullconf = "$configuration $defineset"; + + if ($info =~ /^prepare/) + { + $results{$fulltool}{$fullconf}{result} = 1; + } + elsif ($info =~ /^success/) + { + $results{$fulltool}{$fullconf}{result} = 0; + } + elsif ($info =~ /^coverage (\S+) (\S+)/) + { + $results{$fulltool}{$fullconf}{"coverage_$1"} = $2; + } + else + { + print STDERR "Unrecognized autotest infoline $_"; + } + + &insertindex(\%toolsets, $fulltool); + + $defines{$_} = 1 foreach (split /,/, $defineset); + &insertindex(\%configurations, $fullconf); + } + elsif (/^### autotest revision (\d+)/) + { + if (defined $revision && $revision != $1) + { + print STDERR "Autotest build report contains several revisions: $revision, $1\n"; + } + else + { + $revision = $1; + } + } +} + +# make arrays of toolsets and configurations +@toolsetarray = (); +@configurationarray = (); + +$toolsetarray[$toolsets{$_}] = $_ foreach (keys %toolsets); +$configurationarray[$configurations{$_}] = $_ foreach (keys %configurations); + +# print header +$stylesheet = <pugixml autotest report +

pugixml autotest report

+
configuration".(split /\s+/)[0]."
$define" . ($present ? "+" : " ") . "
$platform$toolset pass"; - - if ($coverage_pugixml > 0 || $coverage_pugixpath > 0) - { - print "
" . ($coverage_pugixml + 0) . "%
" . ($coverage_pugixpath + 0) . "%
"; - } - - print "
fail
+END + +# print configuration header (release/debug) +print ""; +print "" foreach (@configurationarray); +print "\n"; + +# print defines header (one row for each define) +foreach $define (sort {$a cmp $b} keys %defines) +{ + print ""; + + foreach (@configurationarray) + { + my $present = ($_ =~ /\b$define\b/); + my $color = $present ? "#cccccc" : "#ffffff"; + print ""; + } + print "\n"; +} + +# print data (one row for each toolset) +foreach $tool (@toolsetarray) +{ + my ($platform, $toolset) = split(/\s+/, $tool, 2); + print ""; + + foreach (@configurationarray) + { + my $info = $results{$tool}{$_}; + + if (!defined $$info{result}) + { + print ""; + } + elsif ($$info{result} == 0) + { + my ($coverage_pugixml, $coverage_pugixpath) = ($$info{coverage_pugixml}, $$info{coverage_pugixpath}); + + print ""; + } + else + { + print "" + } + } + + print "\n"; +} + +# print footer +$date = localtime; + +print <
+Generated on $date from Subversion r$revision + +END diff --git a/tests/common.hpp b/tests/common.hpp index b466c09..35e4717 100644 --- a/tests/common.hpp +++ b/tests/common.hpp @@ -1,8 +1,8 @@ -#ifndef HEADER_TEST_COMMON_HPP -#define HEADER_TEST_COMMON_HPP - -#include "test.hpp" - -using namespace pugi; - -#endif +#ifndef HEADER_TEST_COMMON_HPP +#define HEADER_TEST_COMMON_HPP + +#include "test.hpp" + +using namespace pugi; + +#endif diff --git a/tests/data/multiline.xml b/tests/data/multiline.xml index 3607e7f..0f0fe3c 100644 --- a/tests/data/multiline.xml +++ b/tests/data/multiline.xml @@ -1,3 +1,3 @@ - - - + + + diff --git a/tests/gcov-filter.pl b/tests/gcov-filter.pl index 8cbccc5..c68aa1f 100644 --- a/tests/gcov-filter.pl +++ b/tests/gcov-filter.pl @@ -1,13 +1,13 @@ -#!/usr/bin/perl - -$prefix = join(' ', @ARGV); -$prefix .= ' ' if ($prefix ne ''); - -$lines = join('', ); -$lines =~ s/File (.+)\nLines (.+)\n(.+\n)*\n/$1 $2\n/g; -$lines =~ s/.+include\/c\+\+.+\n//g; - -foreach $line (split /\n/, $lines) -{ - print "$prefix$line\n"; -} +#!/usr/bin/perl + +$prefix = join(' ', @ARGV); +$prefix .= ' ' if ($prefix ne ''); + +$lines = join('', ); +$lines =~ s/File (.+)\nLines (.+)\n(.+\n)*\n/$1 $2\n/g; +$lines =~ s/.+include\/c\+\+.+\n//g; + +foreach $line (split /\n/, $lines) +{ + print "$prefix$line\n"; +} diff --git a/tests/helpers.hpp b/tests/helpers.hpp index b160a85..abe6626 100644 --- a/tests/helpers.hpp +++ b/tests/helpers.hpp @@ -1,97 +1,97 @@ -#ifndef HEADER_TEST_HELPERS_HPP -#define HEADER_TEST_HELPERS_HPP - -#include "common.hpp" - -#include - -template static void generic_bool_ops_test(const T& obj) -{ - T null; - - CHECK(!null); - CHECK(obj); - CHECK(!!obj); - - bool b1 = null, b2 = obj; - - CHECK(!b1); - CHECK(b2); - - CHECK(obj && b2); - CHECK(obj || b2); - CHECK(obj && obj); - CHECK(obj || obj); -} - -template 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 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)); -} - -#endif +#ifndef HEADER_TEST_HELPERS_HPP +#define HEADER_TEST_HELPERS_HPP + +#include "common.hpp" + +#include + +template static void generic_bool_ops_test(const T& obj) +{ + T null; + + CHECK(!null); + CHECK(obj); + CHECK(!!obj); + + bool b1 = null, b2 = obj; + + CHECK(!b1); + CHECK(b2); + + CHECK(obj && b2); + CHECK(obj || b2); + CHECK(obj && obj); + CHECK(obj || obj); +} + +template 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 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)); +} + +#endif diff --git a/tests/main.cpp b/tests/main.cpp index 4330009..021c253 100644 --- a/tests/main.cpp +++ b/tests/main.cpp @@ -1,149 +1,149 @@ -#include "test.hpp" -#include "allocator.hpp" - -#include -#include -#include - -test_runner* test_runner::_tests = 0; -size_t test_runner::_memory_fail_threshold = 0; -jmp_buf test_runner::_failure_buffer; -const char* test_runner::_failure_message; - -static size_t g_memory_total_size = 0; -static size_t g_memory_total_count = 0; - -static void* custom_allocate(size_t size) -{ - if (test_runner::_memory_fail_threshold > 0 && test_runner::_memory_fail_threshold < g_memory_total_size + size) - return 0; - else - { - void* ptr = memory_allocate(size); - - g_memory_total_size += memory_size(ptr); - g_memory_total_count++; - - return ptr; - } -} - -static void custom_deallocate(void* ptr) -{ - if (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__) -namespace std -{ - _CRTIMP2 _Prhand _Raise_handler; - _CRTIMP2 void __cdecl _Throw(const exception&) {} -} -#endif - -static bool run_test(test_runner* test) -{ -#ifndef PUGIXML_NO_EXCEPTIONS - try - { -#endif - g_memory_total_size = 0; - g_memory_total_count = 0; - test_runner::_memory_fail_threshold = 0; - -#ifdef _MSC_VER -# pragma warning(push) -# pragma warning(disable: 4611) // interaction between _setjmp and C++ object destruction is non-portable -#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 (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, (unsigned int)g_memory_total_size, (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 - -void std::exception::_Raise() const -{ - abort(); -} -#endif - -int main() -{ -#ifdef __BORLANDC__ - _control87(MCW_EM | PC_53, MCW_EM | MCW_PC); -#endif - - 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); - } - - 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; -} +#include "test.hpp" +#include "allocator.hpp" + +#include +#include +#include + +test_runner* test_runner::_tests = 0; +size_t test_runner::_memory_fail_threshold = 0; +jmp_buf test_runner::_failure_buffer; +const char* test_runner::_failure_message; + +static size_t g_memory_total_size = 0; +static size_t g_memory_total_count = 0; + +static void* custom_allocate(size_t size) +{ + if (test_runner::_memory_fail_threshold > 0 && test_runner::_memory_fail_threshold < g_memory_total_size + size) + return 0; + else + { + void* ptr = memory_allocate(size); + + g_memory_total_size += memory_size(ptr); + g_memory_total_count++; + + return ptr; + } +} + +static void custom_deallocate(void* ptr) +{ + if (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__) +namespace std +{ + _CRTIMP2 _Prhand _Raise_handler; + _CRTIMP2 void __cdecl _Throw(const exception&) {} +} +#endif + +static bool run_test(test_runner* test) +{ +#ifndef PUGIXML_NO_EXCEPTIONS + try + { +#endif + g_memory_total_size = 0; + g_memory_total_count = 0; + test_runner::_memory_fail_threshold = 0; + +#ifdef _MSC_VER +# pragma warning(push) +# pragma warning(disable: 4611) // interaction between _setjmp and C++ object destruction is non-portable +#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 (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, (unsigned int)g_memory_total_size, (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 + +void std::exception::_Raise() const +{ + abort(); +} +#endif + +int main() +{ +#ifdef __BORLANDC__ + _control87(MCW_EM | PC_53, MCW_EM | MCW_PC); +#endif + + 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); + } + + 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; +} diff --git a/tests/test.cpp b/tests/test.cpp index 862a0ea..29d74c1 100644 --- a/tests/test.cpp +++ b/tests/test.cpp @@ -1,181 +1,181 @@ -#define _SCL_SECURE_NO_WARNINGS - -#include "test.hpp" - -#include "writer_string.hpp" - -#include -#include - -#include -#include - -#ifndef PUGIXML_NO_XPATH -static void build_document_order(std::vector& 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 : pugi::impl::strequal(lhs, rhs); -} - -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; -} - -#ifndef PUGIXML_NO_XPATH -bool test_xpath_string(const pugi::xml_node& node, const pugi::char_t* query, const pugi::char_t* expected) -{ - pugi::xpath_query q(query); - - return q.evaluate_string(node) == expected; -} - -bool test_xpath_boolean(const pugi::xml_node& node, const pugi::char_t* query, bool expected) -{ - pugi::xpath_query q(query); - - return q.evaluate_boolean(node) == expected; -} - -#include - -bool test_xpath_number(const pugi::xml_node& node, const pugi::char_t* query, double expected) -{ - pugi::xpath_query q(query); - - double value = q.evaluate_number(node); - double absolute_error = fabs(value - expected); - - const double tolerance = 1e-15f; - return absolute_error < tolerance || absolute_error < fabs(expected) * tolerance; -} - -bool test_xpath_number_nan(const pugi::xml_node& node, const pugi::char_t* query) -{ - pugi::xpath_query q(query); - - double r = q.evaluate_number(node); - -#if defined(_MSC_VER) || defined(__BORLANDC__) - return _isnan(r) != 0; -#else - return r != r; -#endif -} - -bool test_xpath_fail_compile(const pugi::char_t* query) -{ - try - { - pugi::xpath_query q(query); - return false; - } - catch (const pugi::xpath_exception&) - { - return true; - } -} - -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 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(&ui) == 1; -} - -pugi::xml_encoding get_native_encoding() -{ -#ifdef PUGIXML_WCHAR_MODE - return pugi::encoding_wchar; -#else - return pugi::encoding_utf8; -#endif -} +#define _SCL_SECURE_NO_WARNINGS + +#include "test.hpp" + +#include "writer_string.hpp" + +#include +#include + +#include +#include + +#ifndef PUGIXML_NO_XPATH +static void build_document_order(std::vector& 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 : pugi::impl::strequal(lhs, rhs); +} + +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; +} + +#ifndef PUGIXML_NO_XPATH +bool test_xpath_string(const pugi::xml_node& node, const pugi::char_t* query, const pugi::char_t* expected) +{ + pugi::xpath_query q(query); + + return q.evaluate_string(node) == expected; +} + +bool test_xpath_boolean(const pugi::xml_node& node, const pugi::char_t* query, bool expected) +{ + pugi::xpath_query q(query); + + return q.evaluate_boolean(node) == expected; +} + +#include + +bool test_xpath_number(const pugi::xml_node& node, const pugi::char_t* query, double expected) +{ + pugi::xpath_query q(query); + + double value = q.evaluate_number(node); + double absolute_error = fabs(value - expected); + + const double tolerance = 1e-15f; + return absolute_error < tolerance || absolute_error < fabs(expected) * tolerance; +} + +bool test_xpath_number_nan(const pugi::xml_node& node, const pugi::char_t* query) +{ + pugi::xpath_query q(query); + + double r = q.evaluate_number(node); + +#if defined(_MSC_VER) || defined(__BORLANDC__) + return _isnan(r) != 0; +#else + return r != r; +#endif +} + +bool test_xpath_fail_compile(const pugi::char_t* query) +{ + try + { + pugi::xpath_query q(query); + return false; + } + catch (const pugi::xpath_exception&) + { + return true; + } +} + +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 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(&ui) == 1; +} + +pugi::xml_encoding get_native_encoding() +{ +#ifdef PUGIXML_WCHAR_MODE + return pugi::encoding_wchar; +#else + return pugi::encoding_utf8; +#endif +} diff --git a/tests/test.hpp b/tests/test.hpp index d4b5879..c269fb5 100644 --- a/tests/test.hpp +++ b/tests/test.hpp @@ -1,151 +1,151 @@ -#ifndef HEADER_TEST_TEST_HPP -#define HEADER_TEST_TEST_HPP - -#include "../src/pugixml.hpp" - -#include - -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 jmp_buf _failure_buffer; - static const char* _failure_message; -}; - -bool test_string_equal(const pugi::char_t* lhs, const pugi::char_t* rhs); - -template 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); - -#ifndef PUGIXML_NO_XPATH -bool test_xpath_string(const pugi::xml_node& node, const pugi::char_t* query, const pugi::char_t* expected); -bool test_xpath_boolean(const pugi::xml_node& node, const pugi::char_t* query, bool expected); -bool test_xpath_number(const pugi::xml_node& node, const pugi::char_t* query, double expected); -bool test_xpath_number_nan(const pugi::xml_node& node, const pugi::char_t* query); -bool test_xpath_fail_compile(const pugi::char_t* query); - -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() \ - { \ - 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(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 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, " at "__FILE__ ":", __LINE__), longjmp(test_runner::_failure_buffer, 1) - -#if (defined(_MSC_VER) && _MSC_VER == 1200) || defined(__MWERKS__) -# define STRINGIZE(value) "??" // MSVC 6.0 and CodeWarrior have troubles stringizing stuff with 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_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(node, query, expected) CHECK_TEXT(test_xpath_string(node, query, expected), STRINGIZE(query) " does not evaluate to " STRINGIZE(expected) " in context " STRINGIZE(node)) -#define CHECK_XPATH_BOOLEAN(node, query, expected) CHECK_TEXT(test_xpath_boolean(node, query, expected), STRINGIZE(query) " does not evaluate to " STRINGIZE(expected) " in context " STRINGIZE(node)) -#define CHECK_XPATH_NUMBER(node, query, expected) CHECK_TEXT(test_xpath_number(node, query, expected), STRINGIZE(query) " does not evaluate to " STRINGIZE(expected) " in context " STRINGIZE(node)) -#define CHECK_XPATH_NUMBER_NAN(node, query) CHECK_TEXT(test_xpath_number_nan(node, query), STRINGIZE(query) " does not evaluate to NaN in context " STRINGIZE(node)) -#define CHECK_XPATH_FAIL(query) CHECK_TEXT(test_xpath_fail_compile(query), STRINGIZE(query) " should not compile") -#define CHECK_XPATH_NODESET(node, query) xpath_node_set_tester(node.select_nodes(query), CHECK_JOIN2(STRINGIZE(query) " does not evaluate to expected set in context " STRINGIZE(node), " at "__FILE__ ":", __LINE__)) -#endif - -#define STR(text) PUGIXML_TEXT(text) - -#ifdef __DMC__ -#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(value); // to avoid C4310 on MSVC -} - -bool is_little_endian(); -pugi::xml_encoding get_native_encoding(); - -#endif +#ifndef HEADER_TEST_TEST_HPP +#define HEADER_TEST_TEST_HPP + +#include "../src/pugixml.hpp" + +#include + +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 jmp_buf _failure_buffer; + static const char* _failure_message; +}; + +bool test_string_equal(const pugi::char_t* lhs, const pugi::char_t* rhs); + +template 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); + +#ifndef PUGIXML_NO_XPATH +bool test_xpath_string(const pugi::xml_node& node, const pugi::char_t* query, const pugi::char_t* expected); +bool test_xpath_boolean(const pugi::xml_node& node, const pugi::char_t* query, bool expected); +bool test_xpath_number(const pugi::xml_node& node, const pugi::char_t* query, double expected); +bool test_xpath_number_nan(const pugi::xml_node& node, const pugi::char_t* query); +bool test_xpath_fail_compile(const pugi::char_t* query); + +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() \ + { \ + 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(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 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, " at "__FILE__ ":", __LINE__), longjmp(test_runner::_failure_buffer, 1) + +#if (defined(_MSC_VER) && _MSC_VER == 1200) || defined(__MWERKS__) +# define STRINGIZE(value) "??" // MSVC 6.0 and CodeWarrior have troubles stringizing stuff with 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_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(node, query, expected) CHECK_TEXT(test_xpath_string(node, query, expected), STRINGIZE(query) " does not evaluate to " STRINGIZE(expected) " in context " STRINGIZE(node)) +#define CHECK_XPATH_BOOLEAN(node, query, expected) CHECK_TEXT(test_xpath_boolean(node, query, expected), STRINGIZE(query) " does not evaluate to " STRINGIZE(expected) " in context " STRINGIZE(node)) +#define CHECK_XPATH_NUMBER(node, query, expected) CHECK_TEXT(test_xpath_number(node, query, expected), STRINGIZE(query) " does not evaluate to " STRINGIZE(expected) " in context " STRINGIZE(node)) +#define CHECK_XPATH_NUMBER_NAN(node, query) CHECK_TEXT(test_xpath_number_nan(node, query), STRINGIZE(query) " does not evaluate to NaN in context " STRINGIZE(node)) +#define CHECK_XPATH_FAIL(query) CHECK_TEXT(test_xpath_fail_compile(query), STRINGIZE(query) " should not compile") +#define CHECK_XPATH_NODESET(node, query) xpath_node_set_tester(node.select_nodes(query), CHECK_JOIN2(STRINGIZE(query) " does not evaluate to expected set in context " STRINGIZE(node), " at "__FILE__ ":", __LINE__)) +#endif + +#define STR(text) PUGIXML_TEXT(text) + +#ifdef __DMC__ +#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(value); // to avoid C4310 on MSVC +} + +bool is_little_endian(); +pugi::xml_encoding get_native_encoding(); + +#endif diff --git a/tests/test_deprecated.cpp b/tests/test_deprecated.cpp index d81810e..4d97b2a 100644 --- a/tests/test_deprecated.cpp +++ b/tests/test_deprecated.cpp @@ -1,203 +1,203 @@ -// This file includes all tests for deprecated functionality; this is going away in the next release! - -#ifdef _MSC_VER -# pragma warning(disable: 4996) -#endif - -#ifdef __GNUC__ -# if __GNUC__ >= 4 && __GNUC_MINOR__ >= 2 -# pragma GCC diagnostic ignored "-Wdeprecated-declarations" -# else -# define PUGIXML_DEPRECATED -# endif -#endif - -#ifdef __INTEL_COMPILER -# pragma warning(disable: 1478) -#endif - -#include - -#include "common.hpp" - -#include "writer_string.hpp" - -#include -#include - -// format_write_bom_utf8 - it's now format_write_bom! -TEST_XML(document_save_bom_utf8, "") -{ - xml_writer_string writer; - - CHECK(test_save_narrow(doc, pugi::format_no_declaration | pugi::format_raw | pugi::format_write_bom_utf8, encoding_utf8, "\xef\xbb\xbf", 11)); -} - -// parse - it's now load_buffer_inplace -TEST(document_parse) -{ - char text[] = ""; - - pugi::xml_document doc; - - CHECK(doc.parse(text)); - CHECK_NODE(doc, STR("")); -} - -// parse with transfer_ownership_tag attribute - it's now load_buffer_inplace_own -TEST(document_parse_transfer_ownership) -{ - allocation_function alloc = get_memory_allocation_function(); - - char* text = static_cast(alloc(strlen("") + 1)); - CHECK(text); - - memcpy(text, "", strlen("") + 1); - - pugi::xml_document doc; - - CHECK(doc.parse(transfer_ownership_tag(), text)); - CHECK_NODE(doc, STR("")); -} - -#ifndef PUGIXML_NO_STL -// as_utf16 - it's now as_wide -TEST(as_utf16) -{ - CHECK(as_utf16("") == L""); - - // valid 1-byte, 2-byte and 3-byte inputs -#ifdef U_LITERALS - CHECK(as_utf16("?\xd0\x80\xe2\x80\xbd") == L"?\u0400\u203D"); -#else - CHECK(as_utf16("?\xd0\x80\xe2\x80\xbd") == L"?\x0400\x203D"); -#endif -} -#endif - -// wildcard functions -TEST_XML(dom_node_child_w, "") -{ - CHECK(doc.child_w(STR("n?de")) == doc.child(STR("node"))); - CHECK(doc.child_w(STR("n[az]de")) == xml_node()); - CHECK(doc.child_w(STR("n[aoz]de")) == doc.child(STR("node"))); - CHECK(doc.child_w(STR("*e")) == doc.child(STR("node"))); - CHECK(doc.child(STR("node")).child_w(STR("*l?[23456789]*")) == doc.child(STR("node")).child(STR("child2"))); -} - -TEST_XML(dom_node_attribute_w, "") -{ - xml_node node = doc.child(STR("node")); - - CHECK(node.attribute_w(STR("*tt?[23456789]*")) == node.attribute(STR("attr2"))); - CHECK(node.attribute_w(STR("?")) == xml_attribute()); -} - -TEST_XML(dom_node_next_previous_sibling_w, "") -{ - CHECK(xml_node().next_sibling_w(STR("n")) == xml_node()); - CHECK(xml_node().previous_sibling_w(STR("n")) == xml_node()); - - xml_node child1 = doc.child(STR("node")).child(STR("child1")); - xml_node child3 = doc.child(STR("node")).child(STR("child3")); - - CHECK(child1.next_sibling_w(STR("*[3456789]")) == child3); - CHECK(child1.next_sibling_w(STR("?")) == xml_node()); - CHECK(child3.previous_sibling_w(STR("*[3456789]")) == xml_node()); - CHECK(child3.previous_sibling_w(STR("?")) == xml_node()); - CHECK(child3.previous_sibling_w(STR("*1")) == child1); -} - -TEST_XML(dom_node_child_value_w, "value1value2value4") -{ - CHECK_STRING(xml_node().child_value_w(STR("n")), STR("")); - - xml_node node = doc.child(STR("node")); - - CHECK_STRING(node.child_value_w(STR("c*[23456789]")), STR("value2")); - CHECK_STRING(node.child_value_w(STR("*")), STR("")); // child_value(name) and child_value_w(pattern) do not continue the search if a node w/out value is found first - CHECK_STRING(node.child_value_w(STR("nothing*here")), STR("")); -} - -TEST_XML(dom_node_find_child_by_attribute_w, "") -{ - CHECK(xml_node().find_child_by_attribute_w(STR("name"), STR("attr"), STR("value")) == xml_node()); - CHECK(xml_node().find_child_by_attribute_w(STR("attr"), STR("value")) == xml_node()); - - xml_node node = doc.child(STR("node")); - - CHECK(node.find_child_by_attribute_w(STR("*"), STR("att?"), STR("val*[0123456789]")) == node.child(STR("child1"))); - CHECK(node.find_child_by_attribute_w(STR("*"), STR("attr3"), STR("val*[0123456789]")) == xml_node()); - CHECK(node.find_child_by_attribute_w(STR("att?"), STR("val*[0123456789]")) == node.child(STR("child1"))); - CHECK(node.find_child_by_attribute_w(STR("attr3"), STR("val*[0123456789]")) == xml_node()); -} - -TEST_XML(dom_node_all_elements_by_name, "") -{ - std::vector v; - - v.clear(); - xml_node().all_elements_by_name(STR("node"), std::back_inserter(v)); - CHECK(v.empty()); - - v.clear(); - doc.all_elements_by_name(STR("node"), std::back_inserter(v)); - CHECK(v.size() == 1 && v[0] == doc.child(STR("node"))); - - v.clear(); - doc.all_elements_by_name(STR("child"), std::back_inserter(v)); - CHECK(v.size() == 3); - CHECK(v[0] == doc.child(STR("node")).child(STR("child"))); - CHECK(v[1] == doc.child(STR("node")).child(STR("child")).first_child()); - CHECK(v[2] == doc.child(STR("node")).child(STR("child")).last_child()); -} - -TEST_XML(dom_node_all_elements_by_name_w, "") -{ - std::vector v; - - v.clear(); - xml_node().all_elements_by_name_w(STR("*"), std::back_inserter(v)); - CHECK(v.empty()); - - v.clear(); - doc.all_elements_by_name_w(STR("*"), std::back_inserter(v)); - CHECK(v.size() == 4); - CHECK(v[0] == doc.child(STR("node"))); - CHECK(v[1] == doc.child(STR("node")).child(STR("child"))); - CHECK(v[2] == doc.child(STR("node")).child(STR("child")).first_child()); - CHECK(v[3] == doc.child(STR("node")).child(STR("child")).last_child()); -} - -TEST_XML(dom_node_wildcard_cset, "") -{ - xml_node node = doc.child(STR("node")); - - CHECK(node.attribute_w(STR("[A-Z]")).as_int() == 0); - CHECK(node.attribute_w(STR("[a-z]")).as_int() == 1); - CHECK(node.attribute_w(STR("[A-z]")).as_int() == 1); - CHECK(node.attribute_w(STR("[z-a]")).as_int() == 0); - CHECK(node.attribute_w(STR("[a-zA-Z]")).as_int() == 1); - CHECK(node.attribute_w(STR("[!A-Z]")).as_int() == 1); - CHECK(node.attribute_w(STR("[!A-Za-z]")).as_int() == 0); -} - -TEST_XML(dom_node_wildcard_star, "") -{ - xml_node node = doc.child(STR("node")); - - CHECK(node.attribute_w(STR("*")).as_int() == 1); - CHECK(node.attribute_w(STR("?d*")).as_int() == 1); - CHECK(node.attribute_w(STR("?c*")).as_int() == 0); - CHECK(node.attribute_w(STR("*?*c*")).as_int() == 0); - CHECK(node.attribute_w(STR("*?*d*")).as_int() == 1); -} - -// document order -TEST_XML(document_order_coverage, "") -{ - doc.precompute_document_order(); - - CHECK(doc.child(STR("node")).document_order() == 0); - CHECK(doc.child(STR("node")).attribute(STR("id")).document_order() == 0); -} +// This file includes all tests for deprecated functionality; this is going away in the next release! + +#ifdef _MSC_VER +# pragma warning(disable: 4996) +#endif + +#ifdef __GNUC__ +# if __GNUC__ >= 4 && __GNUC_MINOR__ >= 2 +# pragma GCC diagnostic ignored "-Wdeprecated-declarations" +# else +# define PUGIXML_DEPRECATED +# endif +#endif + +#ifdef __INTEL_COMPILER +# pragma warning(disable: 1478) +#endif + +#include + +#include "common.hpp" + +#include "writer_string.hpp" + +#include +#include + +// format_write_bom_utf8 - it's now format_write_bom! +TEST_XML(document_save_bom_utf8, "") +{ + xml_writer_string writer; + + CHECK(test_save_narrow(doc, pugi::format_no_declaration | pugi::format_raw | pugi::format_write_bom_utf8, encoding_utf8, "\xef\xbb\xbf", 11)); +} + +// parse - it's now load_buffer_inplace +TEST(document_parse) +{ + char text[] = ""; + + pugi::xml_document doc; + + CHECK(doc.parse(text)); + CHECK_NODE(doc, STR("")); +} + +// parse with transfer_ownership_tag attribute - it's now load_buffer_inplace_own +TEST(document_parse_transfer_ownership) +{ + allocation_function alloc = get_memory_allocation_function(); + + char* text = static_cast(alloc(strlen("") + 1)); + CHECK(text); + + memcpy(text, "", strlen("") + 1); + + pugi::xml_document doc; + + CHECK(doc.parse(transfer_ownership_tag(), text)); + CHECK_NODE(doc, STR("")); +} + +#ifndef PUGIXML_NO_STL +// as_utf16 - it's now as_wide +TEST(as_utf16) +{ + CHECK(as_utf16("") == L""); + + // valid 1-byte, 2-byte and 3-byte inputs +#ifdef U_LITERALS + CHECK(as_utf16("?\xd0\x80\xe2\x80\xbd") == L"?\u0400\u203D"); +#else + CHECK(as_utf16("?\xd0\x80\xe2\x80\xbd") == L"?\x0400\x203D"); +#endif +} +#endif + +// wildcard functions +TEST_XML(dom_node_child_w, "") +{ + CHECK(doc.child_w(STR("n?de")) == doc.child(STR("node"))); + CHECK(doc.child_w(STR("n[az]de")) == xml_node()); + CHECK(doc.child_w(STR("n[aoz]de")) == doc.child(STR("node"))); + CHECK(doc.child_w(STR("*e")) == doc.child(STR("node"))); + CHECK(doc.child(STR("node")).child_w(STR("*l?[23456789]*")) == doc.child(STR("node")).child(STR("child2"))); +} + +TEST_XML(dom_node_attribute_w, "") +{ + xml_node node = doc.child(STR("node")); + + CHECK(node.attribute_w(STR("*tt?[23456789]*")) == node.attribute(STR("attr2"))); + CHECK(node.attribute_w(STR("?")) == xml_attribute()); +} + +TEST_XML(dom_node_next_previous_sibling_w, "") +{ + CHECK(xml_node().next_sibling_w(STR("n")) == xml_node()); + CHECK(xml_node().previous_sibling_w(STR("n")) == xml_node()); + + xml_node child1 = doc.child(STR("node")).child(STR("child1")); + xml_node child3 = doc.child(STR("node")).child(STR("child3")); + + CHECK(child1.next_sibling_w(STR("*[3456789]")) == child3); + CHECK(child1.next_sibling_w(STR("?")) == xml_node()); + CHECK(child3.previous_sibling_w(STR("*[3456789]")) == xml_node()); + CHECK(child3.previous_sibling_w(STR("?")) == xml_node()); + CHECK(child3.previous_sibling_w(STR("*1")) == child1); +} + +TEST_XML(dom_node_child_value_w, "value1value2value4") +{ + CHECK_STRING(xml_node().child_value_w(STR("n")), STR("")); + + xml_node node = doc.child(STR("node")); + + CHECK_STRING(node.child_value_w(STR("c*[23456789]")), STR("value2")); + CHECK_STRING(node.child_value_w(STR("*")), STR("")); // child_value(name) and child_value_w(pattern) do not continue the search if a node w/out value is found first + CHECK_STRING(node.child_value_w(STR("nothing*here")), STR("")); +} + +TEST_XML(dom_node_find_child_by_attribute_w, "") +{ + CHECK(xml_node().find_child_by_attribute_w(STR("name"), STR("attr"), STR("value")) == xml_node()); + CHECK(xml_node().find_child_by_attribute_w(STR("attr"), STR("value")) == xml_node()); + + xml_node node = doc.child(STR("node")); + + CHECK(node.find_child_by_attribute_w(STR("*"), STR("att?"), STR("val*[0123456789]")) == node.child(STR("child1"))); + CHECK(node.find_child_by_attribute_w(STR("*"), STR("attr3"), STR("val*[0123456789]")) == xml_node()); + CHECK(node.find_child_by_attribute_w(STR("att?"), STR("val*[0123456789]")) == node.child(STR("child1"))); + CHECK(node.find_child_by_attribute_w(STR("attr3"), STR("val*[0123456789]")) == xml_node()); +} + +TEST_XML(dom_node_all_elements_by_name, "") +{ + std::vector v; + + v.clear(); + xml_node().all_elements_by_name(STR("node"), std::back_inserter(v)); + CHECK(v.empty()); + + v.clear(); + doc.all_elements_by_name(STR("node"), std::back_inserter(v)); + CHECK(v.size() == 1 && v[0] == doc.child(STR("node"))); + + v.clear(); + doc.all_elements_by_name(STR("child"), std::back_inserter(v)); + CHECK(v.size() == 3); + CHECK(v[0] == doc.child(STR("node")).child(STR("child"))); + CHECK(v[1] == doc.child(STR("node")).child(STR("child")).first_child()); + CHECK(v[2] == doc.child(STR("node")).child(STR("child")).last_child()); +} + +TEST_XML(dom_node_all_elements_by_name_w, "") +{ + std::vector v; + + v.clear(); + xml_node().all_elements_by_name_w(STR("*"), std::back_inserter(v)); + CHECK(v.empty()); + + v.clear(); + doc.all_elements_by_name_w(STR("*"), std::back_inserter(v)); + CHECK(v.size() == 4); + CHECK(v[0] == doc.child(STR("node"))); + CHECK(v[1] == doc.child(STR("node")).child(STR("child"))); + CHECK(v[2] == doc.child(STR("node")).child(STR("child")).first_child()); + CHECK(v[3] == doc.child(STR("node")).child(STR("child")).last_child()); +} + +TEST_XML(dom_node_wildcard_cset, "") +{ + xml_node node = doc.child(STR("node")); + + CHECK(node.attribute_w(STR("[A-Z]")).as_int() == 0); + CHECK(node.attribute_w(STR("[a-z]")).as_int() == 1); + CHECK(node.attribute_w(STR("[A-z]")).as_int() == 1); + CHECK(node.attribute_w(STR("[z-a]")).as_int() == 0); + CHECK(node.attribute_w(STR("[a-zA-Z]")).as_int() == 1); + CHECK(node.attribute_w(STR("[!A-Z]")).as_int() == 1); + CHECK(node.attribute_w(STR("[!A-Za-z]")).as_int() == 0); +} + +TEST_XML(dom_node_wildcard_star, "") +{ + xml_node node = doc.child(STR("node")); + + CHECK(node.attribute_w(STR("*")).as_int() == 1); + CHECK(node.attribute_w(STR("?d*")).as_int() == 1); + CHECK(node.attribute_w(STR("?c*")).as_int() == 0); + CHECK(node.attribute_w(STR("*?*c*")).as_int() == 0); + CHECK(node.attribute_w(STR("*?*d*")).as_int() == 1); +} + +// document order +TEST_XML(document_order_coverage, "") +{ + doc.precompute_document_order(); + + CHECK(doc.child(STR("node")).document_order() == 0); + CHECK(doc.child(STR("node")).attribute(STR("id")).document_order() == 0); +} diff --git a/tests/test_document.cpp b/tests/test_document.cpp index 9a83a6d..1f781e2 100644 --- a/tests/test_document.cpp +++ b/tests/test_document.cpp @@ -1,710 +1,710 @@ -#define _CRT_SECURE_NO_WARNINGS -#define _CRT_NONSTDC_NO_DEPRECATE 0 - -#include // because Borland's STL is braindead, we have to include _before_ in order to get memcpy - -#include "common.hpp" - -#include "writer_string.hpp" - -#include -#include - -#include -#include - -#include - -#ifdef __MINGW32__ -# include // for unlink in C++0x mode -#endif - -#if defined(__CELLOS_LV2__) -# include // for unlink -#endif - -TEST(document_create_empty) -{ - pugi::xml_document doc; - CHECK_NODE(doc, STR("")); -} - -TEST(document_create) -{ - pugi::xml_document doc; - doc.append_child().set_name(STR("node")); - CHECK_NODE(doc, STR("")); -} - -#ifndef PUGIXML_NO_STL -TEST(document_load_stream) -{ - pugi::xml_document doc; - - std::istringstream iss(""); - CHECK(doc.load(iss)); - CHECK_NODE(doc, STR("")); -} - -TEST(document_load_stream_offset) -{ - pugi::xml_document doc; - - std::istringstream iss(" "); - - std::string s; - iss >> s; - - CHECK(doc.load(iss)); - CHECK_NODE(doc, STR("")); -} - -TEST(document_load_stream_text) -{ - pugi::xml_document doc; - - std::ifstream iss("tests/data/multiline.xml"); - CHECK(doc.load(iss)); - CHECK_NODE(doc, STR("")); -} - -TEST(document_load_stream_error) -{ - pugi::xml_document doc; - - std::ifstream fs1("filedoesnotexist"); - CHECK(doc.load(fs1).status == status_io_error); - -#ifndef __DMC__ // Digital Mars CRT does not like 'con' pseudo-file - std::ifstream fs2("con"); - CHECK(doc.load(fs2).status == status_io_error); -#endif - - test_runner::_memory_fail_threshold = 1; - std::istringstream iss(""); - CHECK(doc.load(iss).status == status_out_of_memory); -} - -TEST(document_load_stream_empty) -{ - std::istringstream iss; - - pugi::xml_document doc; - doc.load(iss); // parse result depends on STL implementation - CHECK(!doc.first_child()); -} - -TEST(document_load_stream_wide) -{ - pugi::xml_document doc; - - std::basic_istringstream iss(L""); - CHECK(doc.load(iss)); - CHECK_NODE(doc, STR("")); -} -#endif - -TEST(document_load_string) -{ - pugi::xml_document doc; - - CHECK(doc.load(STR(""))); - CHECK_NODE(doc, STR("")); -} - -TEST(document_load_file) -{ - pugi::xml_document doc; - - CHECK(doc.load_file("tests/data/small.xml")); - CHECK_NODE(doc, STR("")); -} - -TEST(document_load_file_empty) -{ - pugi::xml_document doc; - - CHECK(doc.load_file("tests/data/empty.xml")); - CHECK(!doc.first_child()); -} - -TEST(document_load_file_large) -{ - pugi::xml_document doc; - - CHECK(doc.load_file("tests/data/large.xml")); - - std::basic_string str; - str += STR(""); - for (int i = 0; i < 10000; ++i) str += STR(""); - str += STR(""); - - CHECK_NODE(doc, str.c_str()); -} - -TEST(document_load_file_error) -{ - pugi::xml_document doc; - - CHECK(doc.load_file("filedoesnotexist").status == status_file_not_found); - -#ifdef _WIN32 -#ifndef __DMC__ // Digital Mars CRT does not like 'con' pseudo-file - CHECK(doc.load_file("con").status == status_io_error); -#endif -#endif - - test_runner::_memory_fail_threshold = 1; - CHECK(doc.load_file("tests/data/small.xml").status == status_out_of_memory); -} - -TEST_XML(document_save, "") -{ - xml_writer_string writer; - - doc.save(writer, STR(""), pugi::format_no_declaration | pugi::format_raw, get_native_encoding()); - - CHECK(writer.as_string() == STR("")); -} - -#ifndef PUGIXML_NO_STL -TEST_XML(document_save_stream, "") -{ - std::ostringstream oss; - - doc.save(oss, STR(""), pugi::format_no_declaration | pugi::format_raw); - - CHECK(oss.str() == ""); -} - -TEST_XML(document_save_stream_wide, "") -{ - std::basic_ostringstream oss; - - doc.save(oss, STR(""), pugi::format_no_declaration | pugi::format_raw); - - CHECK(oss.str() == L""); -} -#endif - -TEST_XML(document_save_bom, "") -{ - unsigned int flags = format_no_declaration | format_raw | format_write_bom; - - // specific encodings - CHECK(test_save_narrow(doc, flags, encoding_utf8, "\xef\xbb\xbf", 8)); - CHECK(test_save_narrow(doc, flags, encoding_utf16_be, "\xfe\xff\x00<\x00n\x00 \x00/\x00>", 12)); - CHECK(test_save_narrow(doc, flags, encoding_utf16_le, "\xff\xfe<\x00n\x00 \x00/\x00>\x00", 12)); - CHECK(test_save_narrow(doc, flags, encoding_utf32_be, "\x00\x00\xfe\xff\x00\x00\x00<\x00\x00\x00n\x00\x00\x00 \x00\x00\x00/\x00\x00\x00>", 24)); - CHECK(test_save_narrow(doc, flags, encoding_utf32_le, "\xff\xfe\x00\x00<\x00\x00\x00n\x00\x00\x00 \x00\x00\x00/\x00\x00\x00>\x00\x00\x00", 24)); - - // encodings synonyms - CHECK(save_narrow(doc, flags, encoding_utf16) == save_narrow(doc, flags, (is_little_endian() ? encoding_utf16_le : encoding_utf16_be))); - CHECK(save_narrow(doc, flags, encoding_utf32) == save_narrow(doc, flags, (is_little_endian() ? encoding_utf32_le : encoding_utf32_be))); - - size_t wcharsize = sizeof(wchar_t); - CHECK(save_narrow(doc, flags, encoding_wchar) == save_narrow(doc, flags, (wcharsize == 2 ? encoding_utf16 : encoding_utf32))); -} - -TEST_XML(document_save_declaration, "") -{ - xml_writer_string writer; - - doc.save(writer, STR(""), pugi::format_default, get_native_encoding()); - - CHECK(writer.as_string() == STR("\n\n")); -} - -TEST_XML(document_save_declaration_present_first, "") -{ - doc.insert_child_before(node_declaration, doc.first_child()).append_attribute(STR("encoding")) = STR("utf8"); - - xml_writer_string writer; - - doc.save(writer, STR(""), pugi::format_default, get_native_encoding()); - - CHECK(writer.as_string() == STR("\n\n")); -} - -TEST_XML(document_save_declaration_present_second, "") -{ - doc.insert_child_before(node_declaration, doc.first_child()).append_attribute(STR("encoding")) = STR("utf8"); - doc.insert_child_before(node_comment, doc.first_child()).set_value(STR("text")); - - xml_writer_string writer; - - doc.save(writer, STR(""), pugi::format_default, get_native_encoding()); - - CHECK(writer.as_string() == STR("\n\n\n")); -} - -TEST_XML(document_save_declaration_present_last, "") -{ - doc.append_child(node_declaration).append_attribute(STR("encoding")) = STR("utf8"); - - xml_writer_string writer; - - doc.save(writer, STR(""), pugi::format_default, get_native_encoding()); - - // node writer only looks for declaration before the first element child - CHECK(writer.as_string() == STR("\n\n\n")); -} - -TEST_XML(document_save_file, "") -{ -#ifdef __unix - char path[] = "/tmp/pugiXXXXXX"; - - int fd = mkstemp(path); - CHECK(fd != -1); -#elif defined(__CELLOS_LV2__) - const char* path = ""; // no temporary file support -#else - const char* path = tmpnam(0); -#endif - - CHECK(doc.save_file(path)); - - CHECK(doc.load_file(path, pugi::parse_default | pugi::parse_declaration)); - CHECK_NODE(doc, STR("")); - - CHECK(unlink(path) == 0); - -#ifdef __unix - CHECK(close(fd) == 0); -#endif -} - -TEST_XML(document_save_file_error, "") -{ - CHECK(!doc.save_file("tests/data/unknown/output.xml")); -} - -TEST(document_load_buffer) -{ - const pugi::char_t text[] = STR(""); - - pugi::xml_document doc; - - CHECK(doc.load_buffer(text, sizeof(text))); - CHECK_NODE(doc, STR("")); -} - -TEST(document_load_buffer_inplace) -{ - pugi::char_t text[] = STR(""); - - pugi::xml_document doc; - - CHECK(doc.load_buffer_inplace(text, sizeof(text))); - CHECK_NODE(doc, STR("")); -} - -TEST(document_load_buffer_inplace_own) -{ - allocation_function alloc = get_memory_allocation_function(); - - size_t size = strlen("") * sizeof(pugi::char_t); - - pugi::char_t* text = static_cast(alloc(size)); - CHECK(text); - - memcpy(text, STR(""), size); - - pugi::xml_document doc; - - CHECK(doc.load_buffer_inplace_own(text, size)); - CHECK_NODE(doc, STR("")); -} - -TEST(document_parse_result_bool) -{ - xml_parse_result result; - - result.status = status_ok; - CHECK(result); - CHECK(!!result); - CHECK(result == true); - - for (int i = 1; i < 20; ++i) - { - result.status = (xml_parse_status)i; - CHECK(!result); - CHECK(result == false); - } -} - -TEST(document_parse_result_description) -{ - xml_parse_result result; - - for (int i = 0; i < 20; ++i) - { - result.status = (xml_parse_status)i; - - CHECK(result.description() != 0); - CHECK(result.description()[0] != 0); - } -} - -TEST(document_load_fail) -{ - xml_document doc; - CHECK(!doc.load(STR(""))); - CHECK(doc.child(STR("foo")).child(STR("bar"))); -} - -inline void check_utftest_document(const xml_document& doc) -{ - // ascii text - CHECK_STRING(doc.last_child().first_child().name(), STR("English")); - - // check that we have parsed some non-ascii text - CHECK((unsigned)doc.last_child().last_child().name()[0] >= 0x80); - - // check magic string - const pugi::char_t* v = doc.last_child().child(STR("Heavy")).previous_sibling().child_value(); - -#ifdef PUGIXML_WCHAR_MODE - CHECK(v[0] == 0x4e16 && v[1] == 0x754c && v[2] == 0x6709 && v[3] == 0x5f88 && v[4] == 0x591a && v[5] == 0x8bed && v[6] == 0x8a00); - - // last character is a surrogate pair - unsigned int v7 = v[7]; - size_t wcharsize = sizeof(wchar_t); - - CHECK(wcharsize == 2 ? (v[7] == 0xd852 && v[8] == 0xdf62) : (v7 == 0x24b62)); -#else - // unicode string - CHECK_STRING(v, "\xe4\xb8\x96\xe7\x95\x8c\xe6\x9c\x89\xe5\xbe\x88\xe5\xa4\x9a\xe8\xaf\xad\xe8\xa8\x80\xf0\xa4\xad\xa2"); -#endif -} - -TEST(document_load_file_convert_auto) -{ - const char* files[] = - { - "tests/data/utftest_utf16_be.xml", - "tests/data/utftest_utf16_be_bom.xml", - "tests/data/utftest_utf16_be_nodecl.xml", - "tests/data/utftest_utf16_le.xml", - "tests/data/utftest_utf16_le_bom.xml", - "tests/data/utftest_utf16_le_nodecl.xml", - "tests/data/utftest_utf32_be.xml", - "tests/data/utftest_utf32_be_bom.xml", - "tests/data/utftest_utf32_be_nodecl.xml", - "tests/data/utftest_utf32_le.xml", - "tests/data/utftest_utf32_le_bom.xml", - "tests/data/utftest_utf32_le_nodecl.xml", - "tests/data/utftest_utf8.xml", - "tests/data/utftest_utf8_bom.xml", - "tests/data/utftest_utf8_nodecl.xml" - }; - - xml_encoding encodings[] = - { - encoding_utf16_be, encoding_utf16_be, encoding_utf16_be, - encoding_utf16_le, encoding_utf16_le, encoding_utf16_le, - encoding_utf32_be, encoding_utf32_be, encoding_utf32_be, - encoding_utf32_le, encoding_utf32_le, encoding_utf32_le, - encoding_utf8, encoding_utf8, encoding_utf8 - }; - - for (unsigned int i = 0; i < sizeof(files) / sizeof(files[0]); ++i) - { - xml_document doc; - xml_parse_result res = doc.load_file(files[i]); - - CHECK(res); - CHECK(res.encoding == encodings[i]); - check_utftest_document(doc); - } -} - -TEST(document_load_file_convert_specific) -{ - const char* files[] = - { - "tests/data/utftest_utf16_be.xml", - "tests/data/utftest_utf16_be_bom.xml", - "tests/data/utftest_utf16_be_nodecl.xml", - "tests/data/utftest_utf16_le.xml", - "tests/data/utftest_utf16_le_bom.xml", - "tests/data/utftest_utf16_le_nodecl.xml", - "tests/data/utftest_utf32_be.xml", - "tests/data/utftest_utf32_be_bom.xml", - "tests/data/utftest_utf32_be_nodecl.xml", - "tests/data/utftest_utf32_le.xml", - "tests/data/utftest_utf32_le_bom.xml", - "tests/data/utftest_utf32_le_nodecl.xml", - "tests/data/utftest_utf8.xml", - "tests/data/utftest_utf8_bom.xml", - "tests/data/utftest_utf8_nodecl.xml" - }; - - xml_encoding encodings[] = - { - encoding_utf16_be, encoding_utf16_be, encoding_utf16_be, - encoding_utf16_le, encoding_utf16_le, encoding_utf16_le, - encoding_utf32_be, encoding_utf32_be, encoding_utf32_be, - encoding_utf32_le, encoding_utf32_le, encoding_utf32_le, - encoding_utf8, encoding_utf8, encoding_utf8 - }; - - for (unsigned int i = 0; i < sizeof(files) / sizeof(files[0]); ++i) - { - for (unsigned int j = 0; j < sizeof(files) / sizeof(files[0]); ++j) - { - xml_encoding encoding = encodings[j]; - - xml_document doc; - xml_parse_result res = doc.load_file(files[i], parse_default, encoding); - - if (encoding == encodings[i]) - { - CHECK(res); - CHECK(res.encoding == encoding); - check_utftest_document(doc); - } - else - { - // should not get past first tag - CHECK(!doc.first_child()); - } - } - } -} - -TEST(document_load_file_convert_native_endianness) -{ - const char* files[2][6] = - { - { - "tests/data/utftest_utf16_be.xml", - "tests/data/utftest_utf16_be_bom.xml", - "tests/data/utftest_utf16_be_nodecl.xml", - "tests/data/utftest_utf32_be.xml", - "tests/data/utftest_utf32_be_bom.xml", - "tests/data/utftest_utf32_be_nodecl.xml", - }, - { - "tests/data/utftest_utf16_le.xml", - "tests/data/utftest_utf16_le_bom.xml", - "tests/data/utftest_utf16_le_nodecl.xml", - "tests/data/utftest_utf32_le.xml", - "tests/data/utftest_utf32_le_bom.xml", - "tests/data/utftest_utf32_le_nodecl.xml", - } - }; - - xml_encoding encodings[] = - { - encoding_utf16, encoding_utf16, encoding_utf16, - encoding_utf32, encoding_utf32, encoding_utf32 - }; - - for (unsigned int i = 0; i < sizeof(files[0]) / sizeof(files[0][0]); ++i) - { - const char* right_file = files[is_little_endian()][i]; - const char* wrong_file = files[!is_little_endian()][i]; - - for (unsigned int j = 0; j < sizeof(encodings) / sizeof(encodings[0]); ++j) - { - xml_encoding encoding = encodings[j]; - - // check file with right endianness - { - xml_document doc; - xml_parse_result res = doc.load_file(right_file, parse_default, encoding); - - if (encoding == encodings[i]) - { - CHECK(res); - check_utftest_document(doc); - } - else - { - // should not get past first tag - CHECK(!doc.first_child()); - } - } - - // check file with wrong endianness - { - xml_document doc; - doc.load_file(wrong_file, parse_default, encoding); - CHECK(!doc.first_child()); - } - } - } -} - -static bool load_file_in_memory(const char* path, char*& data, size_t& size) -{ - FILE* file = fopen(path, "rb"); - if (!file) return false; - - fseek(file, 0, SEEK_END); - size = (size_t)ftell(file); - fseek(file, 0, SEEK_SET); - - data = new char[size]; - - CHECK(fread(data, 1, size, file) == size); - fclose(file); - - return true; -} - -TEST(document_contents_preserve) -{ - struct file_t - { - const char* path; - xml_encoding encoding; - - char* data; - size_t size; - }; - - file_t files[] = - { - {"tests/data/utftest_utf16_be_clean.xml", encoding_utf16_be, 0, 0}, - {"tests/data/utftest_utf16_le_clean.xml", encoding_utf16_le, 0, 0}, - {"tests/data/utftest_utf32_be_clean.xml", encoding_utf32_be, 0, 0}, - {"tests/data/utftest_utf32_le_clean.xml", encoding_utf32_le, 0, 0}, - {"tests/data/utftest_utf8_clean.xml", encoding_utf8, 0, 0} - }; - - // load files in memory - for (unsigned int i = 0; i < sizeof(files) / sizeof(files[0]); ++i) - { - CHECK(load_file_in_memory(files[i].path, files[i].data, files[i].size)); - } - - // convert each file to each format and compare bitwise - for (unsigned int src = 0; src < sizeof(files) / sizeof(files[0]); ++src) - { - for (unsigned int dst = 0; dst < sizeof(files) / sizeof(files[0]); ++dst) - { - // parse into document (preserve comments, declaration and whitespace pcdata) - xml_document doc; - CHECK(doc.load_buffer(files[src].data, files[src].size, parse_default | parse_ws_pcdata | parse_declaration | parse_comments)); - - // compare saved document with the original (raw formatting, without extra declaration, write bom if it was in original file) - CHECK(test_save_narrow(doc, format_raw | format_no_declaration | format_write_bom, files[dst].encoding, files[dst].data, files[dst].size)); - } - } - - // cleanup - for (unsigned int j = 0; j < sizeof(files) / sizeof(files[0]); ++j) - { - delete[] files[j].data; - } -} - -static bool test_parse_fail(const void* buffer, size_t size, xml_encoding encoding = encoding_utf8) -{ - // copy buffer to heap (to enable out-of-bounds checks) - void* temp = malloc(size); - memcpy(temp, buffer, size); - - // check that this parses without buffer overflows (yielding an error) - xml_document doc; - bool result = doc.load_buffer_inplace(temp, size, parse_default, encoding); - - free(temp); - - return !result; -} - -TEST(document_convert_invalid_utf8) -{ - // invalid 1-byte input - CHECK(test_parse_fail("<\xb0", 2)); - - // invalid 2-byte input - CHECK(test_parse_fail("<\xc0", 2)); - CHECK(test_parse_fail("<\xd0", 2)); - - // invalid 3-byte input - CHECK(test_parse_fail("<\xe2\x80", 3)); - CHECK(test_parse_fail("<\xe2", 2)); - - // invalid 4-byte input - CHECK(test_parse_fail("<\xf2\x97\x98", 4)); - CHECK(test_parse_fail("<\xf2\x97", 3)); - CHECK(test_parse_fail("<\xf2", 2)); - - // invalid 5-byte input - CHECK(test_parse_fail("<\xf8", 2)); -} - -TEST(document_convert_invalid_utf16) -{ - // check non-terminated degenerate handling - CHECK(test_parse_fail("\x00<\xda\x1d", 4, encoding_utf16_be)); - CHECK(test_parse_fail("<\x00\x1d\xda", 4, encoding_utf16_le)); - - // check incorrect leading code - CHECK(test_parse_fail("\x00<\xde\x24", 4, encoding_utf16_be)); - CHECK(test_parse_fail("<\x00\x24\xde", 4, encoding_utf16_le)); -} - -TEST(document_load_buffer_empty) -{ - xml_encoding encodings[] = - { - encoding_auto, - encoding_utf8, - encoding_utf16_le, - encoding_utf16_be, - encoding_utf16, - encoding_utf32_le, - encoding_utf32_be, - encoding_utf32, - encoding_wchar - }; - - char buffer[1]; - - for (unsigned int i = 0; i < sizeof(encodings) / sizeof(encodings[0]); ++i) - { - xml_encoding encoding = encodings[i]; - - xml_document doc; - CHECK(doc.load_buffer(buffer, 0, parse_default, encoding) && !doc.first_child()); - CHECK(doc.load_buffer(0, 0, parse_default, encoding) && !doc.first_child()); - - CHECK(doc.load_buffer_inplace(buffer, 0, parse_default, encoding) && !doc.first_child()); - CHECK(doc.load_buffer_inplace(0, 0, parse_default, encoding) && !doc.first_child()); - - void* own_buffer = pugi::get_memory_allocation_function()(1); - - CHECK(doc.load_buffer_inplace_own(own_buffer, 0, parse_default, encoding) && !doc.first_child()); - CHECK(doc.load_buffer_inplace_own(0, 0, parse_default, encoding) && !doc.first_child()); - } -} - -TEST(document_progressive_truncation) -{ - char* original_data; - size_t original_size; - - CHECK(load_file_in_memory("tests/data/utftest_utf8.xml", original_data, original_size)); - - for (size_t i = 1; i < original_size; ++i) - { - char* truncated_data = new char[i]; - memcpy(truncated_data, original_data, i); - - xml_document doc; - bool result = doc.load_buffer(truncated_data, i); - - // some truncate locations are parseable - those that come after declaration, declaration + doctype, declaration + doctype + comment and eof - CHECK(((i - 21) < 3 || (i - 66) < 3 || (i - 95) < 3 || i >= 3325) ? result : !result); - - delete[] truncated_data; - } - - delete[] original_data; -} +#define _CRT_SECURE_NO_WARNINGS +#define _CRT_NONSTDC_NO_DEPRECATE 0 + +#include // because Borland's STL is braindead, we have to include _before_ in order to get memcpy + +#include "common.hpp" + +#include "writer_string.hpp" + +#include +#include + +#include +#include + +#include + +#ifdef __MINGW32__ +# include // for unlink in C++0x mode +#endif + +#if defined(__CELLOS_LV2__) +# include // for unlink +#endif + +TEST(document_create_empty) +{ + pugi::xml_document doc; + CHECK_NODE(doc, STR("")); +} + +TEST(document_create) +{ + pugi::xml_document doc; + doc.append_child().set_name(STR("node")); + CHECK_NODE(doc, STR("")); +} + +#ifndef PUGIXML_NO_STL +TEST(document_load_stream) +{ + pugi::xml_document doc; + + std::istringstream iss(""); + CHECK(doc.load(iss)); + CHECK_NODE(doc, STR("")); +} + +TEST(document_load_stream_offset) +{ + pugi::xml_document doc; + + std::istringstream iss(" "); + + std::string s; + iss >> s; + + CHECK(doc.load(iss)); + CHECK_NODE(doc, STR("")); +} + +TEST(document_load_stream_text) +{ + pugi::xml_document doc; + + std::ifstream iss("tests/data/multiline.xml"); + CHECK(doc.load(iss)); + CHECK_NODE(doc, STR("")); +} + +TEST(document_load_stream_error) +{ + pugi::xml_document doc; + + std::ifstream fs1("filedoesnotexist"); + CHECK(doc.load(fs1).status == status_io_error); + +#ifndef __DMC__ // Digital Mars CRT does not like 'con' pseudo-file + std::ifstream fs2("con"); + CHECK(doc.load(fs2).status == status_io_error); +#endif + + test_runner::_memory_fail_threshold = 1; + std::istringstream iss(""); + CHECK(doc.load(iss).status == status_out_of_memory); +} + +TEST(document_load_stream_empty) +{ + std::istringstream iss; + + pugi::xml_document doc; + doc.load(iss); // parse result depends on STL implementation + CHECK(!doc.first_child()); +} + +TEST(document_load_stream_wide) +{ + pugi::xml_document doc; + + std::basic_istringstream iss(L""); + CHECK(doc.load(iss)); + CHECK_NODE(doc, STR("")); +} +#endif + +TEST(document_load_string) +{ + pugi::xml_document doc; + + CHECK(doc.load(STR(""))); + CHECK_NODE(doc, STR("")); +} + +TEST(document_load_file) +{ + pugi::xml_document doc; + + CHECK(doc.load_file("tests/data/small.xml")); + CHECK_NODE(doc, STR("")); +} + +TEST(document_load_file_empty) +{ + pugi::xml_document doc; + + CHECK(doc.load_file("tests/data/empty.xml")); + CHECK(!doc.first_child()); +} + +TEST(document_load_file_large) +{ + pugi::xml_document doc; + + CHECK(doc.load_file("tests/data/large.xml")); + + std::basic_string str; + str += STR(""); + for (int i = 0; i < 10000; ++i) str += STR(""); + str += STR(""); + + CHECK_NODE(doc, str.c_str()); +} + +TEST(document_load_file_error) +{ + pugi::xml_document doc; + + CHECK(doc.load_file("filedoesnotexist").status == status_file_not_found); + +#ifdef _WIN32 +#ifndef __DMC__ // Digital Mars CRT does not like 'con' pseudo-file + CHECK(doc.load_file("con").status == status_io_error); +#endif +#endif + + test_runner::_memory_fail_threshold = 1; + CHECK(doc.load_file("tests/data/small.xml").status == status_out_of_memory); +} + +TEST_XML(document_save, "") +{ + xml_writer_string writer; + + doc.save(writer, STR(""), pugi::format_no_declaration | pugi::format_raw, get_native_encoding()); + + CHECK(writer.as_string() == STR("")); +} + +#ifndef PUGIXML_NO_STL +TEST_XML(document_save_stream, "") +{ + std::ostringstream oss; + + doc.save(oss, STR(""), pugi::format_no_declaration | pugi::format_raw); + + CHECK(oss.str() == ""); +} + +TEST_XML(document_save_stream_wide, "") +{ + std::basic_ostringstream oss; + + doc.save(oss, STR(""), pugi::format_no_declaration | pugi::format_raw); + + CHECK(oss.str() == L""); +} +#endif + +TEST_XML(document_save_bom, "") +{ + unsigned int flags = format_no_declaration | format_raw | format_write_bom; + + // specific encodings + CHECK(test_save_narrow(doc, flags, encoding_utf8, "\xef\xbb\xbf", 8)); + CHECK(test_save_narrow(doc, flags, encoding_utf16_be, "\xfe\xff\x00<\x00n\x00 \x00/\x00>", 12)); + CHECK(test_save_narrow(doc, flags, encoding_utf16_le, "\xff\xfe<\x00n\x00 \x00/\x00>\x00", 12)); + CHECK(test_save_narrow(doc, flags, encoding_utf32_be, "\x00\x00\xfe\xff\x00\x00\x00<\x00\x00\x00n\x00\x00\x00 \x00\x00\x00/\x00\x00\x00>", 24)); + CHECK(test_save_narrow(doc, flags, encoding_utf32_le, "\xff\xfe\x00\x00<\x00\x00\x00n\x00\x00\x00 \x00\x00\x00/\x00\x00\x00>\x00\x00\x00", 24)); + + // encodings synonyms + CHECK(save_narrow(doc, flags, encoding_utf16) == save_narrow(doc, flags, (is_little_endian() ? encoding_utf16_le : encoding_utf16_be))); + CHECK(save_narrow(doc, flags, encoding_utf32) == save_narrow(doc, flags, (is_little_endian() ? encoding_utf32_le : encoding_utf32_be))); + + size_t wcharsize = sizeof(wchar_t); + CHECK(save_narrow(doc, flags, encoding_wchar) == save_narrow(doc, flags, (wcharsize == 2 ? encoding_utf16 : encoding_utf32))); +} + +TEST_XML(document_save_declaration, "") +{ + xml_writer_string writer; + + doc.save(writer, STR(""), pugi::format_default, get_native_encoding()); + + CHECK(writer.as_string() == STR("\n\n")); +} + +TEST_XML(document_save_declaration_present_first, "") +{ + doc.insert_child_before(node_declaration, doc.first_child()).append_attribute(STR("encoding")) = STR("utf8"); + + xml_writer_string writer; + + doc.save(writer, STR(""), pugi::format_default, get_native_encoding()); + + CHECK(writer.as_string() == STR("\n\n")); +} + +TEST_XML(document_save_declaration_present_second, "") +{ + doc.insert_child_before(node_declaration, doc.first_child()).append_attribute(STR("encoding")) = STR("utf8"); + doc.insert_child_before(node_comment, doc.first_child()).set_value(STR("text")); + + xml_writer_string writer; + + doc.save(writer, STR(""), pugi::format_default, get_native_encoding()); + + CHECK(writer.as_string() == STR("\n\n\n")); +} + +TEST_XML(document_save_declaration_present_last, "") +{ + doc.append_child(node_declaration).append_attribute(STR("encoding")) = STR("utf8"); + + xml_writer_string writer; + + doc.save(writer, STR(""), pugi::format_default, get_native_encoding()); + + // node writer only looks for declaration before the first element child + CHECK(writer.as_string() == STR("\n\n\n")); +} + +TEST_XML(document_save_file, "") +{ +#ifdef __unix + char path[] = "/tmp/pugiXXXXXX"; + + int fd = mkstemp(path); + CHECK(fd != -1); +#elif defined(__CELLOS_LV2__) + const char* path = ""; // no temporary file support +#else + const char* path = tmpnam(0); +#endif + + CHECK(doc.save_file(path)); + + CHECK(doc.load_file(path, pugi::parse_default | pugi::parse_declaration)); + CHECK_NODE(doc, STR("")); + + CHECK(unlink(path) == 0); + +#ifdef __unix + CHECK(close(fd) == 0); +#endif +} + +TEST_XML(document_save_file_error, "") +{ + CHECK(!doc.save_file("tests/data/unknown/output.xml")); +} + +TEST(document_load_buffer) +{ + const pugi::char_t text[] = STR(""); + + pugi::xml_document doc; + + CHECK(doc.load_buffer(text, sizeof(text))); + CHECK_NODE(doc, STR("")); +} + +TEST(document_load_buffer_inplace) +{ + pugi::char_t text[] = STR(""); + + pugi::xml_document doc; + + CHECK(doc.load_buffer_inplace(text, sizeof(text))); + CHECK_NODE(doc, STR("")); +} + +TEST(document_load_buffer_inplace_own) +{ + allocation_function alloc = get_memory_allocation_function(); + + size_t size = strlen("") * sizeof(pugi::char_t); + + pugi::char_t* text = static_cast(alloc(size)); + CHECK(text); + + memcpy(text, STR(""), size); + + pugi::xml_document doc; + + CHECK(doc.load_buffer_inplace_own(text, size)); + CHECK_NODE(doc, STR("")); +} + +TEST(document_parse_result_bool) +{ + xml_parse_result result; + + result.status = status_ok; + CHECK(result); + CHECK(!!result); + CHECK(result == true); + + for (int i = 1; i < 20; ++i) + { + result.status = (xml_parse_status)i; + CHECK(!result); + CHECK(result == false); + } +} + +TEST(document_parse_result_description) +{ + xml_parse_result result; + + for (int i = 0; i < 20; ++i) + { + result.status = (xml_parse_status)i; + + CHECK(result.description() != 0); + CHECK(result.description()[0] != 0); + } +} + +TEST(document_load_fail) +{ + xml_document doc; + CHECK(!doc.load(STR(""))); + CHECK(doc.child(STR("foo")).child(STR("bar"))); +} + +inline void check_utftest_document(const xml_document& doc) +{ + // ascii text + CHECK_STRING(doc.last_child().first_child().name(), STR("English")); + + // check that we have parsed some non-ascii text + CHECK((unsigned)doc.last_child().last_child().name()[0] >= 0x80); + + // check magic string + const pugi::char_t* v = doc.last_child().child(STR("Heavy")).previous_sibling().child_value(); + +#ifdef PUGIXML_WCHAR_MODE + CHECK(v[0] == 0x4e16 && v[1] == 0x754c && v[2] == 0x6709 && v[3] == 0x5f88 && v[4] == 0x591a && v[5] == 0x8bed && v[6] == 0x8a00); + + // last character is a surrogate pair + unsigned int v7 = v[7]; + size_t wcharsize = sizeof(wchar_t); + + CHECK(wcharsize == 2 ? (v[7] == 0xd852 && v[8] == 0xdf62) : (v7 == 0x24b62)); +#else + // unicode string + CHECK_STRING(v, "\xe4\xb8\x96\xe7\x95\x8c\xe6\x9c\x89\xe5\xbe\x88\xe5\xa4\x9a\xe8\xaf\xad\xe8\xa8\x80\xf0\xa4\xad\xa2"); +#endif +} + +TEST(document_load_file_convert_auto) +{ + const char* files[] = + { + "tests/data/utftest_utf16_be.xml", + "tests/data/utftest_utf16_be_bom.xml", + "tests/data/utftest_utf16_be_nodecl.xml", + "tests/data/utftest_utf16_le.xml", + "tests/data/utftest_utf16_le_bom.xml", + "tests/data/utftest_utf16_le_nodecl.xml", + "tests/data/utftest_utf32_be.xml", + "tests/data/utftest_utf32_be_bom.xml", + "tests/data/utftest_utf32_be_nodecl.xml", + "tests/data/utftest_utf32_le.xml", + "tests/data/utftest_utf32_le_bom.xml", + "tests/data/utftest_utf32_le_nodecl.xml", + "tests/data/utftest_utf8.xml", + "tests/data/utftest_utf8_bom.xml", + "tests/data/utftest_utf8_nodecl.xml" + }; + + xml_encoding encodings[] = + { + encoding_utf16_be, encoding_utf16_be, encoding_utf16_be, + encoding_utf16_le, encoding_utf16_le, encoding_utf16_le, + encoding_utf32_be, encoding_utf32_be, encoding_utf32_be, + encoding_utf32_le, encoding_utf32_le, encoding_utf32_le, + encoding_utf8, encoding_utf8, encoding_utf8 + }; + + for (unsigned int i = 0; i < sizeof(files) / sizeof(files[0]); ++i) + { + xml_document doc; + xml_parse_result res = doc.load_file(files[i]); + + CHECK(res); + CHECK(res.encoding == encodings[i]); + check_utftest_document(doc); + } +} + +TEST(document_load_file_convert_specific) +{ + const char* files[] = + { + "tests/data/utftest_utf16_be.xml", + "tests/data/utftest_utf16_be_bom.xml", + "tests/data/utftest_utf16_be_nodecl.xml", + "tests/data/utftest_utf16_le.xml", + "tests/data/utftest_utf16_le_bom.xml", + "tests/data/utftest_utf16_le_nodecl.xml", + "tests/data/utftest_utf32_be.xml", + "tests/data/utftest_utf32_be_bom.xml", + "tests/data/utftest_utf32_be_nodecl.xml", + "tests/data/utftest_utf32_le.xml", + "tests/data/utftest_utf32_le_bom.xml", + "tests/data/utftest_utf32_le_nodecl.xml", + "tests/data/utftest_utf8.xml", + "tests/data/utftest_utf8_bom.xml", + "tests/data/utftest_utf8_nodecl.xml" + }; + + xml_encoding encodings[] = + { + encoding_utf16_be, encoding_utf16_be, encoding_utf16_be, + encoding_utf16_le, encoding_utf16_le, encoding_utf16_le, + encoding_utf32_be, encoding_utf32_be, encoding_utf32_be, + encoding_utf32_le, encoding_utf32_le, encoding_utf32_le, + encoding_utf8, encoding_utf8, encoding_utf8 + }; + + for (unsigned int i = 0; i < sizeof(files) / sizeof(files[0]); ++i) + { + for (unsigned int j = 0; j < sizeof(files) / sizeof(files[0]); ++j) + { + xml_encoding encoding = encodings[j]; + + xml_document doc; + xml_parse_result res = doc.load_file(files[i], parse_default, encoding); + + if (encoding == encodings[i]) + { + CHECK(res); + CHECK(res.encoding == encoding); + check_utftest_document(doc); + } + else + { + // should not get past first tag + CHECK(!doc.first_child()); + } + } + } +} + +TEST(document_load_file_convert_native_endianness) +{ + const char* files[2][6] = + { + { + "tests/data/utftest_utf16_be.xml", + "tests/data/utftest_utf16_be_bom.xml", + "tests/data/utftest_utf16_be_nodecl.xml", + "tests/data/utftest_utf32_be.xml", + "tests/data/utftest_utf32_be_bom.xml", + "tests/data/utftest_utf32_be_nodecl.xml", + }, + { + "tests/data/utftest_utf16_le.xml", + "tests/data/utftest_utf16_le_bom.xml", + "tests/data/utftest_utf16_le_nodecl.xml", + "tests/data/utftest_utf32_le.xml", + "tests/data/utftest_utf32_le_bom.xml", + "tests/data/utftest_utf32_le_nodecl.xml", + } + }; + + xml_encoding encodings[] = + { + encoding_utf16, encoding_utf16, encoding_utf16, + encoding_utf32, encoding_utf32, encoding_utf32 + }; + + for (unsigned int i = 0; i < sizeof(files[0]) / sizeof(files[0][0]); ++i) + { + const char* right_file = files[is_little_endian()][i]; + const char* wrong_file = files[!is_little_endian()][i]; + + for (unsigned int j = 0; j < sizeof(encodings) / sizeof(encodings[0]); ++j) + { + xml_encoding encoding = encodings[j]; + + // check file with right endianness + { + xml_document doc; + xml_parse_result res = doc.load_file(right_file, parse_default, encoding); + + if (encoding == encodings[i]) + { + CHECK(res); + check_utftest_document(doc); + } + else + { + // should not get past first tag + CHECK(!doc.first_child()); + } + } + + // check file with wrong endianness + { + xml_document doc; + doc.load_file(wrong_file, parse_default, encoding); + CHECK(!doc.first_child()); + } + } + } +} + +static bool load_file_in_memory(const char* path, char*& data, size_t& size) +{ + FILE* file = fopen(path, "rb"); + if (!file) return false; + + fseek(file, 0, SEEK_END); + size = (size_t)ftell(file); + fseek(file, 0, SEEK_SET); + + data = new char[size]; + + CHECK(fread(data, 1, size, file) == size); + fclose(file); + + return true; +} + +TEST(document_contents_preserve) +{ + struct file_t + { + const char* path; + xml_encoding encoding; + + char* data; + size_t size; + }; + + file_t files[] = + { + {"tests/data/utftest_utf16_be_clean.xml", encoding_utf16_be, 0, 0}, + {"tests/data/utftest_utf16_le_clean.xml", encoding_utf16_le, 0, 0}, + {"tests/data/utftest_utf32_be_clean.xml", encoding_utf32_be, 0, 0}, + {"tests/data/utftest_utf32_le_clean.xml", encoding_utf32_le, 0, 0}, + {"tests/data/utftest_utf8_clean.xml", encoding_utf8, 0, 0} + }; + + // load files in memory + for (unsigned int i = 0; i < sizeof(files) / sizeof(files[0]); ++i) + { + CHECK(load_file_in_memory(files[i].path, files[i].data, files[i].size)); + } + + // convert each file to each format and compare bitwise + for (unsigned int src = 0; src < sizeof(files) / sizeof(files[0]); ++src) + { + for (unsigned int dst = 0; dst < sizeof(files) / sizeof(files[0]); ++dst) + { + // parse into document (preserve comments, declaration and whitespace pcdata) + xml_document doc; + CHECK(doc.load_buffer(files[src].data, files[src].size, parse_default | parse_ws_pcdata | parse_declaration | parse_comments)); + + // compare saved document with the original (raw formatting, without extra declaration, write bom if it was in original file) + CHECK(test_save_narrow(doc, format_raw | format_no_declaration | format_write_bom, files[dst].encoding, files[dst].data, files[dst].size)); + } + } + + // cleanup + for (unsigned int j = 0; j < sizeof(files) / sizeof(files[0]); ++j) + { + delete[] files[j].data; + } +} + +static bool test_parse_fail(const void* buffer, size_t size, xml_encoding encoding = encoding_utf8) +{ + // copy buffer to heap (to enable out-of-bounds checks) + void* temp = malloc(size); + memcpy(temp, buffer, size); + + // check that this parses without buffer overflows (yielding an error) + xml_document doc; + bool result = doc.load_buffer_inplace(temp, size, parse_default, encoding); + + free(temp); + + return !result; +} + +TEST(document_convert_invalid_utf8) +{ + // invalid 1-byte input + CHECK(test_parse_fail("<\xb0", 2)); + + // invalid 2-byte input + CHECK(test_parse_fail("<\xc0", 2)); + CHECK(test_parse_fail("<\xd0", 2)); + + // invalid 3-byte input + CHECK(test_parse_fail("<\xe2\x80", 3)); + CHECK(test_parse_fail("<\xe2", 2)); + + // invalid 4-byte input + CHECK(test_parse_fail("<\xf2\x97\x98", 4)); + CHECK(test_parse_fail("<\xf2\x97", 3)); + CHECK(test_parse_fail("<\xf2", 2)); + + // invalid 5-byte input + CHECK(test_parse_fail("<\xf8", 2)); +} + +TEST(document_convert_invalid_utf16) +{ + // check non-terminated degenerate handling + CHECK(test_parse_fail("\x00<\xda\x1d", 4, encoding_utf16_be)); + CHECK(test_parse_fail("<\x00\x1d\xda", 4, encoding_utf16_le)); + + // check incorrect leading code + CHECK(test_parse_fail("\x00<\xde\x24", 4, encoding_utf16_be)); + CHECK(test_parse_fail("<\x00\x24\xde", 4, encoding_utf16_le)); +} + +TEST(document_load_buffer_empty) +{ + xml_encoding encodings[] = + { + encoding_auto, + encoding_utf8, + encoding_utf16_le, + encoding_utf16_be, + encoding_utf16, + encoding_utf32_le, + encoding_utf32_be, + encoding_utf32, + encoding_wchar + }; + + char buffer[1]; + + for (unsigned int i = 0; i < sizeof(encodings) / sizeof(encodings[0]); ++i) + { + xml_encoding encoding = encodings[i]; + + xml_document doc; + CHECK(doc.load_buffer(buffer, 0, parse_default, encoding) && !doc.first_child()); + CHECK(doc.load_buffer(0, 0, parse_default, encoding) && !doc.first_child()); + + CHECK(doc.load_buffer_inplace(buffer, 0, parse_default, encoding) && !doc.first_child()); + CHECK(doc.load_buffer_inplace(0, 0, parse_default, encoding) && !doc.first_child()); + + void* own_buffer = pugi::get_memory_allocation_function()(1); + + CHECK(doc.load_buffer_inplace_own(own_buffer, 0, parse_default, encoding) && !doc.first_child()); + CHECK(doc.load_buffer_inplace_own(0, 0, parse_default, encoding) && !doc.first_child()); + } +} + +TEST(document_progressive_truncation) +{ + char* original_data; + size_t original_size; + + CHECK(load_file_in_memory("tests/data/utftest_utf8.xml", original_data, original_size)); + + for (size_t i = 1; i < original_size; ++i) + { + char* truncated_data = new char[i]; + memcpy(truncated_data, original_data, i); + + xml_document doc; + bool result = doc.load_buffer(truncated_data, i); + + // some truncate locations are parseable - those that come after declaration, declaration + doctype, declaration + doctype + comment and eof + CHECK(((i - 21) < 3 || (i - 66) < 3 || (i - 95) < 3 || i >= 3325) ? result : !result); + + delete[] truncated_data; + } + + delete[] original_data; +} diff --git a/tests/test_dom_modify.cpp b/tests/test_dom_modify.cpp index 1e38d95..38cc89e 100644 --- a/tests/test_dom_modify.cpp +++ b/tests/test_dom_modify.cpp @@ -1,659 +1,659 @@ -#include "common.hpp" - -#include - -TEST_XML(dom_attr_assign, "") -{ - xml_node node = doc.child(STR("node")); - - node.append_attribute(STR("attr1")) = STR("v1"); - xml_attribute() = STR("v1"); - - node.append_attribute(STR("attr2")) = -2147483647; - node.append_attribute(STR("attr3")) = -2147483647 - 1; - xml_attribute() = -2147483647 - 1; - - node.append_attribute(STR("attr4")) = 4294967295u; - node.append_attribute(STR("attr5")) = 4294967294u; - xml_attribute() = 2147483647; - - node.append_attribute(STR("attr6")) = 0.5; - xml_attribute() = 0.5; - - node.append_attribute(STR("attr7")) = true; - xml_attribute() = true; - - CHECK_NODE(node, STR("")); -} - -TEST_XML(dom_attr_set_value, "") -{ - xml_node node = doc.child(STR("node")); - - CHECK(node.append_attribute(STR("attr1")).set_value(STR("v1"))); - CHECK(!xml_attribute().set_value(STR("v1"))); - - CHECK(node.append_attribute(STR("attr2")).set_value(-2147483647)); - CHECK(node.append_attribute(STR("attr3")).set_value(-2147483647 - 1)); - CHECK(!xml_attribute().set_value(-2147483647)); - - CHECK(node.append_attribute(STR("attr4")).set_value(4294967295u)); - CHECK(node.append_attribute(STR("attr5")).set_value(4294967294u)); - CHECK(!xml_attribute().set_value(4294967295u)); - - CHECK(node.append_attribute(STR("attr6")).set_value(0.5)); - CHECK(!xml_attribute().set_value(0.5)); - - CHECK(node.append_attribute(STR("attr7")).set_value(true)); - CHECK(!xml_attribute().set_value(true)); - - CHECK_NODE(node, STR("")); -} - -TEST_XML(dom_node_set_name, "text") -{ - CHECK(doc.child(STR("node")).set_name(STR("n"))); - CHECK(!doc.child(STR("node")).first_child().set_name(STR("n"))); - CHECK(!xml_node().set_name(STR("n"))); - - CHECK_NODE(doc, STR("text")); -} - -TEST_XML(dom_node_set_value, "text") -{ - CHECK(doc.child(STR("node")).first_child().set_value(STR("no text"))); - CHECK(!doc.child(STR("node")).set_value(STR("no text"))); - CHECK(!xml_node().set_value(STR("no text"))); - - CHECK_NODE(doc, STR("no text")); -} - -TEST_XML(dom_node_set_value_allocated, "text") -{ - CHECK(doc.child(STR("node")).first_child().set_value(STR("no text"))); - CHECK(!doc.child(STR("node")).set_value(STR("no text"))); - CHECK(!xml_node().set_value(STR("no text"))); - CHECK(doc.child(STR("node")).first_child().set_value(STR("no text at all"))); - - CHECK_NODE(doc, STR("no text at all")); -} - -TEST_XML(dom_node_append_attribute, "") -{ - CHECK(xml_node().append_attribute(STR("a")) == xml_attribute()); - CHECK(doc.append_attribute(STR("a")) == xml_attribute()); - - xml_attribute a1 = doc.child(STR("node")).append_attribute(STR("a1")); - CHECK(a1); - a1 = STR("v1"); - - xml_attribute a2 = doc.child(STR("node")).append_attribute(STR("a2")); - CHECK(a2 && a1 != a2); - a2 = STR("v2"); - - xml_attribute a3 = doc.child(STR("node")).child(STR("child")).append_attribute(STR("a3")); - CHECK(a3 && a1 != a3 && a2 != a3); - a3 = STR("v3"); - - CHECK_NODE(doc, STR("")); -} - -TEST_XML(dom_node_insert_attribute_after, "") -{ - CHECK(xml_node().insert_attribute_after(STR("a"), xml_attribute()) == xml_attribute()); - - xml_node node = doc.child(STR("node")); - xml_node child = node.child(STR("child")); - - xml_attribute a1 = node.attribute(STR("a1")); - xml_attribute a2 = child.attribute(STR("a2")); - - CHECK(node.insert_attribute_after(STR("a"), xml_attribute()) == xml_attribute()); - CHECK(node.insert_attribute_after(STR("a"), a2) == xml_attribute()); - - xml_attribute a3 = node.insert_attribute_after(STR("a3"), a1); - CHECK(a3 && a3 != a2 && a3 != a1); - a3 = STR("v3"); - - xml_attribute a4 = node.insert_attribute_after(STR("a4"), a1); - CHECK(a4 && a4 != a3 && a4 != a2 && a4 != a1); - a4 = STR("v4"); - - xml_attribute a5 = node.insert_attribute_after(STR("a5"), a3); - CHECK(a5 && a5 != a4 && a5 != a3 && a5 != a2 && a5 != a1); - a5 = STR("v5"); - - CHECK(child.insert_attribute_after(STR("a"), a4) == xml_attribute()); - - CHECK_NODE(doc, STR("")); -} - -TEST_XML(dom_node_insert_attribute_before, "") -{ - CHECK(xml_node().insert_attribute_before(STR("a"), xml_attribute()) == xml_attribute()); - - xml_node node = doc.child(STR("node")); - xml_node child = node.child(STR("child")); - - xml_attribute a1 = node.attribute(STR("a1")); - xml_attribute a2 = child.attribute(STR("a2")); - - CHECK(node.insert_attribute_before(STR("a"), xml_attribute()) == xml_attribute()); - CHECK(node.insert_attribute_before(STR("a"), a2) == xml_attribute()); - - xml_attribute a3 = node.insert_attribute_before(STR("a3"), a1); - CHECK(a3 && a3 != a2 && a3 != a1); - a3 = STR("v3"); - - xml_attribute a4 = node.insert_attribute_before(STR("a4"), a1); - CHECK(a4 && a4 != a3 && a4 != a2 && a4 != a1); - a4 = STR("v4"); - - xml_attribute a5 = node.insert_attribute_before(STR("a5"), a3); - CHECK(a5 && a5 != a4 && a5 != a3 && a5 != a2 && a5 != a1); - a5 = STR("v5"); - - CHECK(child.insert_attribute_before(STR("a"), a4) == xml_attribute()); - - CHECK_NODE(doc, STR("")); -} - -TEST_XML(dom_node_append_copy_attribute, "") -{ - CHECK(xml_node().append_copy(xml_attribute()) == xml_attribute()); - CHECK(xml_node().append_copy(doc.child(STR("node")).attribute(STR("a1"))) == xml_attribute()); - CHECK(doc.append_copy(doc.child(STR("node")).attribute(STR("a1"))) == xml_attribute()); - - xml_node node = doc.child(STR("node")); - xml_node child = node.child(STR("child")); - - xml_attribute a1 = node.attribute(STR("a1")); - xml_attribute a2 = child.attribute(STR("a2")); - - xml_attribute a3 = node.append_copy(a1); - CHECK(a3 && a3 != a2 && a3 != a1); - - xml_attribute a4 = node.append_copy(a2); - CHECK(a4 && a4 != a3 && a4 != a2 && a4 != a1); - - xml_attribute a5 = node.last_child().append_copy(a1); - CHECK(a5 && a5 != a4 && a5 != a3 && a5 != a2 && a5 != a1); - - CHECK_NODE(doc, STR("")); - - a3.set_name(STR("a3")); - a3 = STR("v3"); - - a4.set_name(STR("a4")); - a4 = STR("v4"); - - a5.set_name(STR("a5")); - a5 = STR("v5"); - - CHECK_NODE(doc, STR("")); -} - -TEST_XML(dom_node_insert_copy_after_attribute, "") -{ - CHECK(xml_node().insert_copy_after(xml_attribute(), xml_attribute()) == xml_attribute()); - - xml_node node = doc.child(STR("node")); - xml_node child = node.child(STR("child")); - - xml_attribute a1 = node.attribute(STR("a1")); - xml_attribute a2 = child.attribute(STR("a2")); - - CHECK(node.insert_copy_after(a1, xml_attribute()) == xml_attribute()); - CHECK(node.insert_copy_after(xml_attribute(), a1) == xml_attribute()); - CHECK(node.insert_copy_after(a2, a2) == xml_attribute()); - - xml_attribute a3 = node.insert_copy_after(a1, a1); - CHECK(a3 && a3 != a2 && a3 != a1); - - xml_attribute a4 = node.insert_copy_after(a2, a1); - CHECK(a4 && a4 != a3 && a4 != a2 && a4 != a1); - - xml_attribute a5 = node.insert_copy_after(a4, a1); - CHECK(a5 && a5 != a4 && a5 != a3 && a5 != a2 && a5 != a1); - - CHECK(child.insert_copy_after(a4, a4) == xml_attribute()); - - CHECK_NODE(doc, STR("")); - - a3.set_name(STR("a3")); - a3 = STR("v3"); - - a4.set_name(STR("a4")); - a4 = STR("v4"); - - a5.set_name(STR("a5")); - a5 = STR("v5"); - - CHECK_NODE(doc, STR("")); -} - -TEST_XML(dom_node_insert_copy_before_attribute, "") -{ - CHECK(xml_node().insert_copy_before(xml_attribute(), xml_attribute()) == xml_attribute()); - - xml_node node = doc.child(STR("node")); - xml_node child = node.child(STR("child")); - - xml_attribute a1 = node.attribute(STR("a1")); - xml_attribute a2 = child.attribute(STR("a2")); - - CHECK(node.insert_copy_before(a1, xml_attribute()) == xml_attribute()); - CHECK(node.insert_copy_before(xml_attribute(), a1) == xml_attribute()); - CHECK(node.insert_copy_before(a2, a2) == xml_attribute()); - - xml_attribute a3 = node.insert_copy_before(a1, a1); - CHECK(a3 && a3 != a2 && a3 != a1); - - xml_attribute a4 = node.insert_copy_before(a2, a1); - CHECK(a4 && a4 != a3 && a4 != a2 && a4 != a1); - - xml_attribute a5 = node.insert_copy_before(a4, a1); - CHECK(a5 && a5 != a4 && a5 != a3 && a5 != a2 && a5 != a1); - - CHECK(child.insert_copy_before(a4, a4) == xml_attribute()); - - CHECK_NODE(doc, STR("")); - - a3.set_name(STR("a3")); - a3 = STR("v3"); - - a4.set_name(STR("a4")); - a4 = STR("v4"); - - a5.set_name(STR("a5")); - a5 = STR("v5"); - - CHECK_NODE(doc, STR("")); -} - -TEST_XML(dom_node_remove_attribute, "") -{ - CHECK(!xml_node().remove_attribute(STR("a"))); - CHECK(!xml_node().remove_attribute(xml_attribute())); - - xml_node node = doc.child(STR("node")); - xml_node child = node.child(STR("child")); - - CHECK(!node.remove_attribute(STR("a"))); - CHECK(!node.remove_attribute(xml_attribute())); - CHECK(!node.remove_attribute(child.attribute(STR("a4")))); - - CHECK_NODE(doc, STR("")); - - CHECK(node.remove_attribute(STR("a1"))); - CHECK(node.remove_attribute(node.attribute(STR("a3")))); - CHECK(child.remove_attribute(STR("a4"))); - - CHECK_NODE(doc, STR("")); -} - -TEST_XML(dom_node_append_child, "foo") -{ - CHECK(xml_node().append_child() == xml_node()); - CHECK(doc.child(STR("node")).first_child().append_child() == xml_node()); - CHECK(doc.append_child(node_document) == xml_node()); - CHECK(doc.append_child(node_null) == xml_node()); - - xml_node n1 = doc.child(STR("node")).append_child(); - CHECK(n1); - CHECK(n1.set_name(STR("n1"))); - - xml_node n2 = doc.child(STR("node")).append_child(); - CHECK(n2 && n1 != n2); - CHECK(n2.set_name(STR("n2"))); - - xml_node n3 = doc.child(STR("node")).child(STR("child")).append_child(node_pcdata); - CHECK(n3 && n1 != n3 && n2 != n3); - CHECK(n3.set_value(STR("n3"))); - - xml_node n4 = doc.append_child(node_comment); - CHECK(n4 && n1 != n4 && n2 != n4 && n3 != n4); - CHECK(n4.set_value(STR("n4"))); - - CHECK_NODE(doc, STR("foon3")); -} - -TEST_XML(dom_node_insert_child_after, "foo") -{ - CHECK(xml_node().insert_child_after(node_element, xml_node()) == xml_node()); - CHECK(doc.child(STR("node")).first_child().insert_child_after(node_element, xml_node()) == xml_node()); - CHECK(doc.insert_child_after(node_document, xml_node()) == xml_node()); - CHECK(doc.insert_child_after(node_null, xml_node()) == xml_node()); - - xml_node node = doc.child(STR("node")); - xml_node child = node.child(STR("child")); - - CHECK(node.insert_child_after(node_element, node) == xml_node()); - CHECK(child.insert_child_after(node_element, node) == xml_node()); - - xml_node n1 = node.insert_child_after(node_element, child); - CHECK(n1 && n1 != node && n1 != child); - CHECK(n1.set_name(STR("n1"))); - - xml_node n2 = node.insert_child_after(node_element, child); - CHECK(n2 && n2 != node && n2 != child && n2 != n1); - CHECK(n2.set_name(STR("n2"))); - - xml_node n3 = node.insert_child_after(node_pcdata, n2); - CHECK(n3 && n3 != node && n3 != child && n3 != n1 && n3 != n2); - CHECK(n3.set_value(STR("n3"))); - - xml_node n4 = node.insert_child_after(node_pi, node.first_child()); - CHECK(n4 && n4 != node && n4 != child && n4 != n1 && n4 != n2 && n4 != n3); - CHECK(n4.set_name(STR("n4"))); - - CHECK(child.insert_child_after(node_element, n3) == xml_node()); - - CHECK_NODE(doc, STR("foon3")); -} - -TEST_XML(dom_node_insert_child_before, "foo") -{ - CHECK(xml_node().insert_child_before(node_element, xml_node()) == xml_node()); - CHECK(doc.child(STR("node")).first_child().insert_child_before(node_element, xml_node()) == xml_node()); - CHECK(doc.insert_child_before(node_document, xml_node()) == xml_node()); - CHECK(doc.insert_child_before(node_null, xml_node()) == xml_node()); - - xml_node node = doc.child(STR("node")); - xml_node child = node.child(STR("child")); - - CHECK(node.insert_child_before(node_element, node) == xml_node()); - CHECK(child.insert_child_before(node_element, node) == xml_node()); - - xml_node n1 = node.insert_child_before(node_element, child); - CHECK(n1 && n1 != node && n1 != child); - CHECK(n1.set_name(STR("n1"))); - - xml_node n2 = node.insert_child_before(node_element, child); - CHECK(n2 && n2 != node && n2 != child && n2 != n1); - CHECK(n2.set_name(STR("n2"))); - - xml_node n3 = node.insert_child_before(node_pcdata, n2); - CHECK(n3 && n3 != node && n3 != child && n3 != n1 && n3 != n2); - CHECK(n3.set_value(STR("n3"))); - - xml_node n4 = node.insert_child_before(node_pi, node.first_child()); - CHECK(n4 && n4 != node && n4 != child && n4 != n1 && n4 != n2 && n4 != n3); - CHECK(n4.set_name(STR("n4"))); - - CHECK(child.insert_child_before(node_element, n3) == xml_node()); - - CHECK_NODE(doc, STR("foon3")); -} - -TEST_XML(dom_node_remove_child, "") -{ - CHECK(!xml_node().remove_child(STR("a"))); - CHECK(!xml_node().remove_child(xml_node())); - - xml_node node = doc.child(STR("node")); - xml_node child = node.child(STR("child")); - - CHECK(!node.remove_child(STR("a"))); - CHECK(!node.remove_child(xml_node())); - CHECK(!node.remove_child(child.child(STR("n4")))); - - CHECK_NODE(doc, STR("")); - - CHECK(node.remove_child(STR("n1"))); - CHECK(node.remove_child(node.child(STR("n3")))); - CHECK(child.remove_child(STR("n4"))); - - CHECK_NODE(doc, STR("")); -} - -TEST_XML(dom_node_remove_child_complex, "") -{ - doc.child(STR("node")).remove_child(STR("n1")); - - CHECK_NODE(doc, STR("")); - - CHECK(doc.remove_child(STR("node"))); - - CHECK_NODE(doc, STR("")); -} - -TEST_XML(dom_node_remove_child_complex_allocated, "") -{ - doc.append_copy(doc.child(STR("node"))); - - CHECK(doc.remove_child(STR("node"))); - CHECK(doc.remove_child(STR("node"))); - - CHECK_NODE(doc, STR("")); -} - -TEST_XML(dom_node_append_copy, "foo") -{ - CHECK(xml_node().append_copy(xml_node()) == xml_node()); - CHECK(doc.child(STR("node")).first_child().append_copy(doc.child(STR("node"))) == xml_node()); - CHECK(doc.append_copy(doc) == xml_node()); - CHECK(doc.append_copy(xml_node()) == xml_node()); - - xml_node n1 = doc.child(STR("node")).append_copy(doc.child(STR("node")).first_child()); - CHECK(n1); - CHECK_STRING(n1.value(), STR("foo")); - CHECK_NODE(doc, STR("foofoo")); - - xml_node n2 = doc.child(STR("node")).append_copy(doc.child(STR("node")).child(STR("child"))); - CHECK(n2 && n2 != n1); - CHECK_STRING(n2.name(), STR("child")); - CHECK_NODE(doc, STR("foofoo")); - - xml_node n3 = doc.child(STR("node")).child(STR("child")).append_copy(doc.child(STR("node")).first_child()); - CHECK(n3 && n3 != n1 && n3 != n2); - CHECK_STRING(n3.value(), STR("foo")); - CHECK_NODE(doc, STR("foofoofoo")); -} - -TEST_XML(dom_node_insert_copy_after, "foo") -{ - CHECK(xml_node().insert_copy_after(xml_node(), xml_node()) == xml_node()); - CHECK(doc.child(STR("node")).first_child().insert_copy_after(doc.child(STR("node")), doc.child(STR("node"))) == xml_node()); - CHECK(doc.insert_copy_after(doc, doc) == xml_node()); - CHECK(doc.insert_copy_after(xml_node(), doc.child(STR("node"))) == xml_node()); - CHECK(doc.insert_copy_after(doc.child(STR("node")), xml_node()) == xml_node()); - - xml_node n1 = doc.child(STR("node")).insert_copy_after(doc.child(STR("node")).child(STR("child")), doc.child(STR("node")).first_child()); - CHECK(n1); - CHECK_STRING(n1.name(), STR("child")); - CHECK_NODE(doc, STR("foo")); - - xml_node n2 = doc.child(STR("node")).insert_copy_after(doc.child(STR("node")).first_child(), doc.child(STR("node")).last_child()); - CHECK(n2 && n2 != n1); - CHECK_STRING(n2.value(), STR("foo")); - CHECK_NODE(doc, STR("foofoo")); - - xml_node n3 = doc.child(STR("node")).insert_copy_after(doc.child(STR("node")).first_child(), doc.child(STR("node")).first_child()); - CHECK(n3 && n3 != n1 && n3 != n2); - CHECK_STRING(n3.value(), STR("foo")); - CHECK_NODE(doc, STR("foofoofoo")); -} - -TEST_XML(dom_node_insert_copy_before, "foo") -{ - CHECK(xml_node().insert_copy_before(xml_node(), xml_node()) == xml_node()); - CHECK(doc.child(STR("node")).first_child().insert_copy_before(doc.child(STR("node")), doc.child(STR("node"))) == xml_node()); - CHECK(doc.insert_copy_before(doc, doc) == xml_node()); - CHECK(doc.insert_copy_before(xml_node(), doc.child(STR("node"))) == xml_node()); - CHECK(doc.insert_copy_before(doc.child(STR("node")), xml_node()) == xml_node()); - - xml_node n1 = doc.child(STR("node")).insert_copy_before(doc.child(STR("node")).child(STR("child")), doc.child(STR("node")).first_child()); - CHECK(n1); - CHECK_STRING(n1.name(), STR("child")); - CHECK_NODE(doc, STR("foo")); - - xml_node n2 = doc.child(STR("node")).insert_copy_before(doc.child(STR("node")).first_child(), doc.child(STR("node")).last_child()); - CHECK(n2 && n2 != n1); - CHECK_STRING(n2.name(), STR("child")); - CHECK_NODE(doc, STR("foo")); - - xml_node n3 = doc.child(STR("node")).insert_copy_before(doc.child(STR("node")).first_child().next_sibling(), doc.child(STR("node")).first_child()); - CHECK(n3 && n3 != n1 && n3 != n2); - CHECK_STRING(n3.value(), STR("foo")); - CHECK_NODE(doc, STR("foofoo")); -} - -TEST_XML(dom_node_copy_recursive, "foo") -{ - doc.child(STR("node")).append_copy(doc.child(STR("node"))); - CHECK_NODE(doc, STR("foofoo")); -} - -TEST_XML(dom_node_copy_crossdoc, "") -{ - xml_document newdoc; - newdoc.append_copy(doc.child(STR("node"))); - CHECK_NODE(doc, STR("")); - CHECK_NODE(newdoc, STR("")); -} - -TEST_XML_FLAGS(dom_node_copy_types, "pcdata", parse_default | parse_pi | parse_comments | parse_declaration) -{ - doc.append_copy(doc.child(STR("root"))); - CHECK_NODE(doc, STR("pcdatapcdata")); - - doc.insert_copy_before(doc.first_child(), doc.first_child()); - CHECK_NODE(doc, STR("pcdatapcdata")); -} - -TEST_XML(dom_attr_assign_large_number, "") -{ - xml_node node = doc.child(STR("node")); - - node.attribute(STR("attr1")) = FLT_MAX; - node.attribute(STR("attr2")) = DBL_MAX; - - CHECK(test_node(node, STR(""), STR(""), pugi::format_raw) || - test_node(node, STR(""), STR(""), pugi::format_raw)); -} - -TEST(dom_node_declaration_name) -{ - xml_document doc; - doc.append_child(node_declaration); - - // name 'xml' is auto-assigned - CHECK(doc.first_child().type() == node_declaration); - CHECK_STRING(doc.first_child().name(), STR("xml")); - - doc.insert_child_after(node_declaration, doc.first_child()); - doc.insert_child_before(node_declaration, doc.first_child()); - - CHECK_NODE(doc, STR("")); -} - -TEST(dom_node_declaration_top_level) -{ - xml_document doc; - doc.append_child().set_name(STR("node")); - - xml_node node = doc.first_child(); - node.append_child(node_pcdata).set_value(STR("text")); - - CHECK(node.insert_child_before(node_declaration, node.first_child()) == xml_node()); - CHECK(node.insert_child_after(node_declaration, node.first_child()) == xml_node()); - CHECK(node.append_child(node_declaration) == xml_node()); - - CHECK_NODE(doc, STR("text")); - - CHECK(doc.insert_child_before(node_declaration, node)); - CHECK(doc.insert_child_after(node_declaration, node)); - CHECK(doc.append_child(node_declaration)); - - CHECK_NODE(doc, STR("text")); -} - -TEST(dom_node_declaration_copy) -{ - xml_document doc; - doc.append_child(node_declaration); - - doc.append_child().set_name(STR("node")); - - doc.last_child().append_copy(doc.first_child()); - - CHECK_NODE(doc, STR("")); -} - -TEST(dom_string_out_of_memory) -{ - unsigned int length = 65536; - - char_t* string = new char_t[length + 1]; - for (unsigned int i = 0; i < length; ++i) string[i] = 'a'; - string[length] = 0; - - xml_document doc; - xml_node node = doc.append_child(); - xml_attribute attr = node.append_attribute(STR("a")); - xml_node text = node.append_child(node_pcdata); - - // no value => long value - test_runner::_memory_fail_threshold = 32; - - CHECK(!node.set_name(string)); - CHECK(!text.set_value(string)); - CHECK(!attr.set_name(string)); - CHECK(!attr.set_value(string)); - - // set some names/values - test_runner::_memory_fail_threshold = 0; - - node.set_name(STR("n")); - attr.set_value(STR("v")); - text.set_value(STR("t")); - - // some value => long value - test_runner::_memory_fail_threshold = 32; - - CHECK(!node.set_name(string)); - CHECK(!text.set_value(string)); - CHECK(!attr.set_name(string)); - CHECK(!attr.set_value(string)); - - // check that original state was preserved - test_runner::_memory_fail_threshold = 0; - - CHECK_NODE(doc, STR("t")); -} - -TEST(dom_node_out_of_memory) -{ - test_runner::_memory_fail_threshold = 65536; - - // exhaust memory limit - xml_document doc; - - xml_node n = doc.append_child(); - CHECK(n.set_name(STR("n"))); - - xml_attribute a = n.append_attribute(STR("a")); - CHECK(a); - - while (n.append_child(node_comment) || n.append_attribute(STR("b"))) - { - // nop - } - - // verify all node modification operations - CHECK(!n.append_child()); - CHECK(!n.insert_child_after(node_element, n.first_child())); - CHECK(!n.insert_child_before(node_element, n.first_child())); - CHECK(!n.append_attribute(STR(""))); - CHECK(!n.insert_attribute_after(STR(""), a)); - CHECK(!n.insert_attribute_before(STR(""), a)); - - // verify node copy operations - CHECK(!n.append_copy(n.first_child())); - CHECK(!n.insert_copy_after(n.first_child(), n.first_child())); - CHECK(!n.insert_copy_before(n.first_child(), n.first_child())); - CHECK(!n.append_copy(a)); - CHECK(!n.insert_copy_after(a, a)); - CHECK(!n.insert_copy_before(a, a)); -} +#include "common.hpp" + +#include + +TEST_XML(dom_attr_assign, "") +{ + xml_node node = doc.child(STR("node")); + + node.append_attribute(STR("attr1")) = STR("v1"); + xml_attribute() = STR("v1"); + + node.append_attribute(STR("attr2")) = -2147483647; + node.append_attribute(STR("attr3")) = -2147483647 - 1; + xml_attribute() = -2147483647 - 1; + + node.append_attribute(STR("attr4")) = 4294967295u; + node.append_attribute(STR("attr5")) = 4294967294u; + xml_attribute() = 2147483647; + + node.append_attribute(STR("attr6")) = 0.5; + xml_attribute() = 0.5; + + node.append_attribute(STR("attr7")) = true; + xml_attribute() = true; + + CHECK_NODE(node, STR("")); +} + +TEST_XML(dom_attr_set_value, "") +{ + xml_node node = doc.child(STR("node")); + + CHECK(node.append_attribute(STR("attr1")).set_value(STR("v1"))); + CHECK(!xml_attribute().set_value(STR("v1"))); + + CHECK(node.append_attribute(STR("attr2")).set_value(-2147483647)); + CHECK(node.append_attribute(STR("attr3")).set_value(-2147483647 - 1)); + CHECK(!xml_attribute().set_value(-2147483647)); + + CHECK(node.append_attribute(STR("attr4")).set_value(4294967295u)); + CHECK(node.append_attribute(STR("attr5")).set_value(4294967294u)); + CHECK(!xml_attribute().set_value(4294967295u)); + + CHECK(node.append_attribute(STR("attr6")).set_value(0.5)); + CHECK(!xml_attribute().set_value(0.5)); + + CHECK(node.append_attribute(STR("attr7")).set_value(true)); + CHECK(!xml_attribute().set_value(true)); + + CHECK_NODE(node, STR("")); +} + +TEST_XML(dom_node_set_name, "text") +{ + CHECK(doc.child(STR("node")).set_name(STR("n"))); + CHECK(!doc.child(STR("node")).first_child().set_name(STR("n"))); + CHECK(!xml_node().set_name(STR("n"))); + + CHECK_NODE(doc, STR("text")); +} + +TEST_XML(dom_node_set_value, "text") +{ + CHECK(doc.child(STR("node")).first_child().set_value(STR("no text"))); + CHECK(!doc.child(STR("node")).set_value(STR("no text"))); + CHECK(!xml_node().set_value(STR("no text"))); + + CHECK_NODE(doc, STR("no text")); +} + +TEST_XML(dom_node_set_value_allocated, "text") +{ + CHECK(doc.child(STR("node")).first_child().set_value(STR("no text"))); + CHECK(!doc.child(STR("node")).set_value(STR("no text"))); + CHECK(!xml_node().set_value(STR("no text"))); + CHECK(doc.child(STR("node")).first_child().set_value(STR("no text at all"))); + + CHECK_NODE(doc, STR("no text at all")); +} + +TEST_XML(dom_node_append_attribute, "") +{ + CHECK(xml_node().append_attribute(STR("a")) == xml_attribute()); + CHECK(doc.append_attribute(STR("a")) == xml_attribute()); + + xml_attribute a1 = doc.child(STR("node")).append_attribute(STR("a1")); + CHECK(a1); + a1 = STR("v1"); + + xml_attribute a2 = doc.child(STR("node")).append_attribute(STR("a2")); + CHECK(a2 && a1 != a2); + a2 = STR("v2"); + + xml_attribute a3 = doc.child(STR("node")).child(STR("child")).append_attribute(STR("a3")); + CHECK(a3 && a1 != a3 && a2 != a3); + a3 = STR("v3"); + + CHECK_NODE(doc, STR("")); +} + +TEST_XML(dom_node_insert_attribute_after, "") +{ + CHECK(xml_node().insert_attribute_after(STR("a"), xml_attribute()) == xml_attribute()); + + xml_node node = doc.child(STR("node")); + xml_node child = node.child(STR("child")); + + xml_attribute a1 = node.attribute(STR("a1")); + xml_attribute a2 = child.attribute(STR("a2")); + + CHECK(node.insert_attribute_after(STR("a"), xml_attribute()) == xml_attribute()); + CHECK(node.insert_attribute_after(STR("a"), a2) == xml_attribute()); + + xml_attribute a3 = node.insert_attribute_after(STR("a3"), a1); + CHECK(a3 && a3 != a2 && a3 != a1); + a3 = STR("v3"); + + xml_attribute a4 = node.insert_attribute_after(STR("a4"), a1); + CHECK(a4 && a4 != a3 && a4 != a2 && a4 != a1); + a4 = STR("v4"); + + xml_attribute a5 = node.insert_attribute_after(STR("a5"), a3); + CHECK(a5 && a5 != a4 && a5 != a3 && a5 != a2 && a5 != a1); + a5 = STR("v5"); + + CHECK(child.insert_attribute_after(STR("a"), a4) == xml_attribute()); + + CHECK_NODE(doc, STR("")); +} + +TEST_XML(dom_node_insert_attribute_before, "") +{ + CHECK(xml_node().insert_attribute_before(STR("a"), xml_attribute()) == xml_attribute()); + + xml_node node = doc.child(STR("node")); + xml_node child = node.child(STR("child")); + + xml_attribute a1 = node.attribute(STR("a1")); + xml_attribute a2 = child.attribute(STR("a2")); + + CHECK(node.insert_attribute_before(STR("a"), xml_attribute()) == xml_attribute()); + CHECK(node.insert_attribute_before(STR("a"), a2) == xml_attribute()); + + xml_attribute a3 = node.insert_attribute_before(STR("a3"), a1); + CHECK(a3 && a3 != a2 && a3 != a1); + a3 = STR("v3"); + + xml_attribute a4 = node.insert_attribute_before(STR("a4"), a1); + CHECK(a4 && a4 != a3 && a4 != a2 && a4 != a1); + a4 = STR("v4"); + + xml_attribute a5 = node.insert_attribute_before(STR("a5"), a3); + CHECK(a5 && a5 != a4 && a5 != a3 && a5 != a2 && a5 != a1); + a5 = STR("v5"); + + CHECK(child.insert_attribute_before(STR("a"), a4) == xml_attribute()); + + CHECK_NODE(doc, STR("")); +} + +TEST_XML(dom_node_append_copy_attribute, "") +{ + CHECK(xml_node().append_copy(xml_attribute()) == xml_attribute()); + CHECK(xml_node().append_copy(doc.child(STR("node")).attribute(STR("a1"))) == xml_attribute()); + CHECK(doc.append_copy(doc.child(STR("node")).attribute(STR("a1"))) == xml_attribute()); + + xml_node node = doc.child(STR("node")); + xml_node child = node.child(STR("child")); + + xml_attribute a1 = node.attribute(STR("a1")); + xml_attribute a2 = child.attribute(STR("a2")); + + xml_attribute a3 = node.append_copy(a1); + CHECK(a3 && a3 != a2 && a3 != a1); + + xml_attribute a4 = node.append_copy(a2); + CHECK(a4 && a4 != a3 && a4 != a2 && a4 != a1); + + xml_attribute a5 = node.last_child().append_copy(a1); + CHECK(a5 && a5 != a4 && a5 != a3 && a5 != a2 && a5 != a1); + + CHECK_NODE(doc, STR("")); + + a3.set_name(STR("a3")); + a3 = STR("v3"); + + a4.set_name(STR("a4")); + a4 = STR("v4"); + + a5.set_name(STR("a5")); + a5 = STR("v5"); + + CHECK_NODE(doc, STR("")); +} + +TEST_XML(dom_node_insert_copy_after_attribute, "") +{ + CHECK(xml_node().insert_copy_after(xml_attribute(), xml_attribute()) == xml_attribute()); + + xml_node node = doc.child(STR("node")); + xml_node child = node.child(STR("child")); + + xml_attribute a1 = node.attribute(STR("a1")); + xml_attribute a2 = child.attribute(STR("a2")); + + CHECK(node.insert_copy_after(a1, xml_attribute()) == xml_attribute()); + CHECK(node.insert_copy_after(xml_attribute(), a1) == xml_attribute()); + CHECK(node.insert_copy_after(a2, a2) == xml_attribute()); + + xml_attribute a3 = node.insert_copy_after(a1, a1); + CHECK(a3 && a3 != a2 && a3 != a1); + + xml_attribute a4 = node.insert_copy_after(a2, a1); + CHECK(a4 && a4 != a3 && a4 != a2 && a4 != a1); + + xml_attribute a5 = node.insert_copy_after(a4, a1); + CHECK(a5 && a5 != a4 && a5 != a3 && a5 != a2 && a5 != a1); + + CHECK(child.insert_copy_after(a4, a4) == xml_attribute()); + + CHECK_NODE(doc, STR("")); + + a3.set_name(STR("a3")); + a3 = STR("v3"); + + a4.set_name(STR("a4")); + a4 = STR("v4"); + + a5.set_name(STR("a5")); + a5 = STR("v5"); + + CHECK_NODE(doc, STR("")); +} + +TEST_XML(dom_node_insert_copy_before_attribute, "") +{ + CHECK(xml_node().insert_copy_before(xml_attribute(), xml_attribute()) == xml_attribute()); + + xml_node node = doc.child(STR("node")); + xml_node child = node.child(STR("child")); + + xml_attribute a1 = node.attribute(STR("a1")); + xml_attribute a2 = child.attribute(STR("a2")); + + CHECK(node.insert_copy_before(a1, xml_attribute()) == xml_attribute()); + CHECK(node.insert_copy_before(xml_attribute(), a1) == xml_attribute()); + CHECK(node.insert_copy_before(a2, a2) == xml_attribute()); + + xml_attribute a3 = node.insert_copy_before(a1, a1); + CHECK(a3 && a3 != a2 && a3 != a1); + + xml_attribute a4 = node.insert_copy_before(a2, a1); + CHECK(a4 && a4 != a3 && a4 != a2 && a4 != a1); + + xml_attribute a5 = node.insert_copy_before(a4, a1); + CHECK(a5 && a5 != a4 && a5 != a3 && a5 != a2 && a5 != a1); + + CHECK(child.insert_copy_before(a4, a4) == xml_attribute()); + + CHECK_NODE(doc, STR("")); + + a3.set_name(STR("a3")); + a3 = STR("v3"); + + a4.set_name(STR("a4")); + a4 = STR("v4"); + + a5.set_name(STR("a5")); + a5 = STR("v5"); + + CHECK_NODE(doc, STR("")); +} + +TEST_XML(dom_node_remove_attribute, "") +{ + CHECK(!xml_node().remove_attribute(STR("a"))); + CHECK(!xml_node().remove_attribute(xml_attribute())); + + xml_node node = doc.child(STR("node")); + xml_node child = node.child(STR("child")); + + CHECK(!node.remove_attribute(STR("a"))); + CHECK(!node.remove_attribute(xml_attribute())); + CHECK(!node.remove_attribute(child.attribute(STR("a4")))); + + CHECK_NODE(doc, STR("")); + + CHECK(node.remove_attribute(STR("a1"))); + CHECK(node.remove_attribute(node.attribute(STR("a3")))); + CHECK(child.remove_attribute(STR("a4"))); + + CHECK_NODE(doc, STR("")); +} + +TEST_XML(dom_node_append_child, "foo") +{ + CHECK(xml_node().append_child() == xml_node()); + CHECK(doc.child(STR("node")).first_child().append_child() == xml_node()); + CHECK(doc.append_child(node_document) == xml_node()); + CHECK(doc.append_child(node_null) == xml_node()); + + xml_node n1 = doc.child(STR("node")).append_child(); + CHECK(n1); + CHECK(n1.set_name(STR("n1"))); + + xml_node n2 = doc.child(STR("node")).append_child(); + CHECK(n2 && n1 != n2); + CHECK(n2.set_name(STR("n2"))); + + xml_node n3 = doc.child(STR("node")).child(STR("child")).append_child(node_pcdata); + CHECK(n3 && n1 != n3 && n2 != n3); + CHECK(n3.set_value(STR("n3"))); + + xml_node n4 = doc.append_child(node_comment); + CHECK(n4 && n1 != n4 && n2 != n4 && n3 != n4); + CHECK(n4.set_value(STR("n4"))); + + CHECK_NODE(doc, STR("foon3")); +} + +TEST_XML(dom_node_insert_child_after, "foo") +{ + CHECK(xml_node().insert_child_after(node_element, xml_node()) == xml_node()); + CHECK(doc.child(STR("node")).first_child().insert_child_after(node_element, xml_node()) == xml_node()); + CHECK(doc.insert_child_after(node_document, xml_node()) == xml_node()); + CHECK(doc.insert_child_after(node_null, xml_node()) == xml_node()); + + xml_node node = doc.child(STR("node")); + xml_node child = node.child(STR("child")); + + CHECK(node.insert_child_after(node_element, node) == xml_node()); + CHECK(child.insert_child_after(node_element, node) == xml_node()); + + xml_node n1 = node.insert_child_after(node_element, child); + CHECK(n1 && n1 != node && n1 != child); + CHECK(n1.set_name(STR("n1"))); + + xml_node n2 = node.insert_child_after(node_element, child); + CHECK(n2 && n2 != node && n2 != child && n2 != n1); + CHECK(n2.set_name(STR("n2"))); + + xml_node n3 = node.insert_child_after(node_pcdata, n2); + CHECK(n3 && n3 != node && n3 != child && n3 != n1 && n3 != n2); + CHECK(n3.set_value(STR("n3"))); + + xml_node n4 = node.insert_child_after(node_pi, node.first_child()); + CHECK(n4 && n4 != node && n4 != child && n4 != n1 && n4 != n2 && n4 != n3); + CHECK(n4.set_name(STR("n4"))); + + CHECK(child.insert_child_after(node_element, n3) == xml_node()); + + CHECK_NODE(doc, STR("foon3")); +} + +TEST_XML(dom_node_insert_child_before, "foo") +{ + CHECK(xml_node().insert_child_before(node_element, xml_node()) == xml_node()); + CHECK(doc.child(STR("node")).first_child().insert_child_before(node_element, xml_node()) == xml_node()); + CHECK(doc.insert_child_before(node_document, xml_node()) == xml_node()); + CHECK(doc.insert_child_before(node_null, xml_node()) == xml_node()); + + xml_node node = doc.child(STR("node")); + xml_node child = node.child(STR("child")); + + CHECK(node.insert_child_before(node_element, node) == xml_node()); + CHECK(child.insert_child_before(node_element, node) == xml_node()); + + xml_node n1 = node.insert_child_before(node_element, child); + CHECK(n1 && n1 != node && n1 != child); + CHECK(n1.set_name(STR("n1"))); + + xml_node n2 = node.insert_child_before(node_element, child); + CHECK(n2 && n2 != node && n2 != child && n2 != n1); + CHECK(n2.set_name(STR("n2"))); + + xml_node n3 = node.insert_child_before(node_pcdata, n2); + CHECK(n3 && n3 != node && n3 != child && n3 != n1 && n3 != n2); + CHECK(n3.set_value(STR("n3"))); + + xml_node n4 = node.insert_child_before(node_pi, node.first_child()); + CHECK(n4 && n4 != node && n4 != child && n4 != n1 && n4 != n2 && n4 != n3); + CHECK(n4.set_name(STR("n4"))); + + CHECK(child.insert_child_before(node_element, n3) == xml_node()); + + CHECK_NODE(doc, STR("foon3")); +} + +TEST_XML(dom_node_remove_child, "") +{ + CHECK(!xml_node().remove_child(STR("a"))); + CHECK(!xml_node().remove_child(xml_node())); + + xml_node node = doc.child(STR("node")); + xml_node child = node.child(STR("child")); + + CHECK(!node.remove_child(STR("a"))); + CHECK(!node.remove_child(xml_node())); + CHECK(!node.remove_child(child.child(STR("n4")))); + + CHECK_NODE(doc, STR("")); + + CHECK(node.remove_child(STR("n1"))); + CHECK(node.remove_child(node.child(STR("n3")))); + CHECK(child.remove_child(STR("n4"))); + + CHECK_NODE(doc, STR("")); +} + +TEST_XML(dom_node_remove_child_complex, "") +{ + doc.child(STR("node")).remove_child(STR("n1")); + + CHECK_NODE(doc, STR("")); + + CHECK(doc.remove_child(STR("node"))); + + CHECK_NODE(doc, STR("")); +} + +TEST_XML(dom_node_remove_child_complex_allocated, "") +{ + doc.append_copy(doc.child(STR("node"))); + + CHECK(doc.remove_child(STR("node"))); + CHECK(doc.remove_child(STR("node"))); + + CHECK_NODE(doc, STR("")); +} + +TEST_XML(dom_node_append_copy, "foo") +{ + CHECK(xml_node().append_copy(xml_node()) == xml_node()); + CHECK(doc.child(STR("node")).first_child().append_copy(doc.child(STR("node"))) == xml_node()); + CHECK(doc.append_copy(doc) == xml_node()); + CHECK(doc.append_copy(xml_node()) == xml_node()); + + xml_node n1 = doc.child(STR("node")).append_copy(doc.child(STR("node")).first_child()); + CHECK(n1); + CHECK_STRING(n1.value(), STR("foo")); + CHECK_NODE(doc, STR("foofoo")); + + xml_node n2 = doc.child(STR("node")).append_copy(doc.child(STR("node")).child(STR("child"))); + CHECK(n2 && n2 != n1); + CHECK_STRING(n2.name(), STR("child")); + CHECK_NODE(doc, STR("foofoo")); + + xml_node n3 = doc.child(STR("node")).child(STR("child")).append_copy(doc.child(STR("node")).first_child()); + CHECK(n3 && n3 != n1 && n3 != n2); + CHECK_STRING(n3.value(), STR("foo")); + CHECK_NODE(doc, STR("foofoofoo")); +} + +TEST_XML(dom_node_insert_copy_after, "foo") +{ + CHECK(xml_node().insert_copy_after(xml_node(), xml_node()) == xml_node()); + CHECK(doc.child(STR("node")).first_child().insert_copy_after(doc.child(STR("node")), doc.child(STR("node"))) == xml_node()); + CHECK(doc.insert_copy_after(doc, doc) == xml_node()); + CHECK(doc.insert_copy_after(xml_node(), doc.child(STR("node"))) == xml_node()); + CHECK(doc.insert_copy_after(doc.child(STR("node")), xml_node()) == xml_node()); + + xml_node n1 = doc.child(STR("node")).insert_copy_after(doc.child(STR("node")).child(STR("child")), doc.child(STR("node")).first_child()); + CHECK(n1); + CHECK_STRING(n1.name(), STR("child")); + CHECK_NODE(doc, STR("foo")); + + xml_node n2 = doc.child(STR("node")).insert_copy_after(doc.child(STR("node")).first_child(), doc.child(STR("node")).last_child()); + CHECK(n2 && n2 != n1); + CHECK_STRING(n2.value(), STR("foo")); + CHECK_NODE(doc, STR("foofoo")); + + xml_node n3 = doc.child(STR("node")).insert_copy_after(doc.child(STR("node")).first_child(), doc.child(STR("node")).first_child()); + CHECK(n3 && n3 != n1 && n3 != n2); + CHECK_STRING(n3.value(), STR("foo")); + CHECK_NODE(doc, STR("foofoofoo")); +} + +TEST_XML(dom_node_insert_copy_before, "foo") +{ + CHECK(xml_node().insert_copy_before(xml_node(), xml_node()) == xml_node()); + CHECK(doc.child(STR("node")).first_child().insert_copy_before(doc.child(STR("node")), doc.child(STR("node"))) == xml_node()); + CHECK(doc.insert_copy_before(doc, doc) == xml_node()); + CHECK(doc.insert_copy_before(xml_node(), doc.child(STR("node"))) == xml_node()); + CHECK(doc.insert_copy_before(doc.child(STR("node")), xml_node()) == xml_node()); + + xml_node n1 = doc.child(STR("node")).insert_copy_before(doc.child(STR("node")).child(STR("child")), doc.child(STR("node")).first_child()); + CHECK(n1); + CHECK_STRING(n1.name(), STR("child")); + CHECK_NODE(doc, STR("foo")); + + xml_node n2 = doc.child(STR("node")).insert_copy_before(doc.child(STR("node")).first_child(), doc.child(STR("node")).last_child()); + CHECK(n2 && n2 != n1); + CHECK_STRING(n2.name(), STR("child")); + CHECK_NODE(doc, STR("foo")); + + xml_node n3 = doc.child(STR("node")).insert_copy_before(doc.child(STR("node")).first_child().next_sibling(), doc.child(STR("node")).first_child()); + CHECK(n3 && n3 != n1 && n3 != n2); + CHECK_STRING(n3.value(), STR("foo")); + CHECK_NODE(doc, STR("foofoo")); +} + +TEST_XML(dom_node_copy_recursive, "foo") +{ + doc.child(STR("node")).append_copy(doc.child(STR("node"))); + CHECK_NODE(doc, STR("foofoo")); +} + +TEST_XML(dom_node_copy_crossdoc, "") +{ + xml_document newdoc; + newdoc.append_copy(doc.child(STR("node"))); + CHECK_NODE(doc, STR("")); + CHECK_NODE(newdoc, STR("")); +} + +TEST_XML_FLAGS(dom_node_copy_types, "pcdata", parse_default | parse_pi | parse_comments | parse_declaration) +{ + doc.append_copy(doc.child(STR("root"))); + CHECK_NODE(doc, STR("pcdatapcdata")); + + doc.insert_copy_before(doc.first_child(), doc.first_child()); + CHECK_NODE(doc, STR("pcdatapcdata")); +} + +TEST_XML(dom_attr_assign_large_number, "") +{ + xml_node node = doc.child(STR("node")); + + node.attribute(STR("attr1")) = FLT_MAX; + node.attribute(STR("attr2")) = DBL_MAX; + + CHECK(test_node(node, STR(""), STR(""), pugi::format_raw) || + test_node(node, STR(""), STR(""), pugi::format_raw)); +} + +TEST(dom_node_declaration_name) +{ + xml_document doc; + doc.append_child(node_declaration); + + // name 'xml' is auto-assigned + CHECK(doc.first_child().type() == node_declaration); + CHECK_STRING(doc.first_child().name(), STR("xml")); + + doc.insert_child_after(node_declaration, doc.first_child()); + doc.insert_child_before(node_declaration, doc.first_child()); + + CHECK_NODE(doc, STR("")); +} + +TEST(dom_node_declaration_top_level) +{ + xml_document doc; + doc.append_child().set_name(STR("node")); + + xml_node node = doc.first_child(); + node.append_child(node_pcdata).set_value(STR("text")); + + CHECK(node.insert_child_before(node_declaration, node.first_child()) == xml_node()); + CHECK(node.insert_child_after(node_declaration, node.first_child()) == xml_node()); + CHECK(node.append_child(node_declaration) == xml_node()); + + CHECK_NODE(doc, STR("text")); + + CHECK(doc.insert_child_before(node_declaration, node)); + CHECK(doc.insert_child_after(node_declaration, node)); + CHECK(doc.append_child(node_declaration)); + + CHECK_NODE(doc, STR("text")); +} + +TEST(dom_node_declaration_copy) +{ + xml_document doc; + doc.append_child(node_declaration); + + doc.append_child().set_name(STR("node")); + + doc.last_child().append_copy(doc.first_child()); + + CHECK_NODE(doc, STR("")); +} + +TEST(dom_string_out_of_memory) +{ + unsigned int length = 65536; + + char_t* string = new char_t[length + 1]; + for (unsigned int i = 0; i < length; ++i) string[i] = 'a'; + string[length] = 0; + + xml_document doc; + xml_node node = doc.append_child(); + xml_attribute attr = node.append_attribute(STR("a")); + xml_node text = node.append_child(node_pcdata); + + // no value => long value + test_runner::_memory_fail_threshold = 32; + + CHECK(!node.set_name(string)); + CHECK(!text.set_value(string)); + CHECK(!attr.set_name(string)); + CHECK(!attr.set_value(string)); + + // set some names/values + test_runner::_memory_fail_threshold = 0; + + node.set_name(STR("n")); + attr.set_value(STR("v")); + text.set_value(STR("t")); + + // some value => long value + test_runner::_memory_fail_threshold = 32; + + CHECK(!node.set_name(string)); + CHECK(!text.set_value(string)); + CHECK(!attr.set_name(string)); + CHECK(!attr.set_value(string)); + + // check that original state was preserved + test_runner::_memory_fail_threshold = 0; + + CHECK_NODE(doc, STR("t")); +} + +TEST(dom_node_out_of_memory) +{ + test_runner::_memory_fail_threshold = 65536; + + // exhaust memory limit + xml_document doc; + + xml_node n = doc.append_child(); + CHECK(n.set_name(STR("n"))); + + xml_attribute a = n.append_attribute(STR("a")); + CHECK(a); + + while (n.append_child(node_comment) || n.append_attribute(STR("b"))) + { + // nop + } + + // verify all node modification operations + CHECK(!n.append_child()); + CHECK(!n.insert_child_after(node_element, n.first_child())); + CHECK(!n.insert_child_before(node_element, n.first_child())); + CHECK(!n.append_attribute(STR(""))); + CHECK(!n.insert_attribute_after(STR(""), a)); + CHECK(!n.insert_attribute_before(STR(""), a)); + + // verify node copy operations + CHECK(!n.append_copy(n.first_child())); + CHECK(!n.insert_copy_after(n.first_child(), n.first_child())); + CHECK(!n.insert_copy_before(n.first_child(), n.first_child())); + CHECK(!n.append_copy(a)); + CHECK(!n.insert_copy_after(a, a)); + CHECK(!n.insert_copy_before(a, a)); +} diff --git a/tests/test_dom_traverse.cpp b/tests/test_dom_traverse.cpp index 896bf6f..8075dc3 100644 --- a/tests/test_dom_traverse.cpp +++ b/tests/test_dom_traverse.cpp @@ -1,756 +1,756 @@ -#define _CRT_SECURE_NO_WARNINGS -#define _SCL_SECURE_NO_WARNINGS - -#include "common.hpp" - -#include - -#include -#include - -#include -#include -#include -#include - -#include "helpers.hpp" - -#ifdef PUGIXML_NO_STL -template static I move_iter(I base, int n) -{ - if (n > 0) while (n--) ++base; - else while (n++) --base; - return base; -} -#else -template static I move_iter(I base, int n) -{ - std::advance(base, n); - return base; -} -#endif - -template static void generic_empty_test(const T& obj) -{ - T null; - - CHECK(null.empty()); - CHECK(!obj.empty()); -} - -TEST_XML(dom_attr_bool_ops, "") -{ - generic_bool_ops_test(doc.child(STR("node")).attribute(STR("attr"))); -} - -TEST_XML(dom_attr_eq_ops, "") -{ - generic_eq_ops_test(doc.child(STR("node")).attribute(STR("attr1")), doc.child(STR("node")).attribute(STR("attr2"))); -} - -TEST_XML(dom_attr_rel_ops, "") -{ - generic_rel_ops_test(doc.child(STR("node")).attribute(STR("attr1")), doc.child(STR("node")).attribute(STR("attr2"))); -} - -TEST_XML(dom_attr_empty, "") -{ - generic_empty_test(doc.child(STR("node")).attribute(STR("attr"))); -} - -TEST_XML(dom_attr_next_previous_attribute, "") -{ - xml_attribute attr1 = doc.child(STR("node")).attribute(STR("attr1")); - xml_attribute attr2 = doc.child(STR("node")).attribute(STR("attr2")); - - CHECK(attr1.next_attribute() == attr2); - CHECK(attr2.next_attribute() == xml_attribute()); - - CHECK(attr1.previous_attribute() == xml_attribute()); - CHECK(attr2.previous_attribute() == attr1); - - CHECK(xml_attribute().next_attribute() == xml_attribute()); - CHECK(xml_attribute().previous_attribute() == xml_attribute()); -} - -TEST_XML(dom_attr_name_value, "") -{ - xml_attribute attr = doc.child(STR("node")).attribute(STR("attr")); - - CHECK_NAME_VALUE(attr, STR("attr"), STR("1")); - CHECK_NAME_VALUE(xml_attribute(), STR(""), STR("")); -} - -TEST_XML(dom_attr_as_int, "") -{ - xml_node node = doc.child(STR("node")); - - CHECK(xml_attribute().as_int() == 0); - CHECK(node.attribute(STR("attr1")).as_int() == 1); - CHECK(node.attribute(STR("attr2")).as_int() == -1); - CHECK(node.attribute(STR("attr3")).as_int() == -2147483647 - 1); - CHECK(node.attribute(STR("attr4")).as_int() == 2147483647); -} - -TEST_XML(dom_attr_as_uint, "") -{ - xml_node node = doc.child(STR("node")); - - CHECK(xml_attribute().as_uint() == 0); - CHECK(node.attribute(STR("attr1")).as_uint() == 0); - CHECK(node.attribute(STR("attr2")).as_uint() == 1); - CHECK(node.attribute(STR("attr3")).as_uint() == 2147483647); - CHECK(node.attribute(STR("attr4")).as_uint() == 4294967295u); -} - -TEST_XML(dom_attr_as_float, "") -{ - xml_node node = doc.child(STR("node")); - - CHECK(xml_attribute().as_float() == 0); - CHECK_DOUBLE(node.attribute(STR("attr1")).as_float(), 0); - CHECK_DOUBLE(node.attribute(STR("attr2")).as_float(), 1); - CHECK_DOUBLE(node.attribute(STR("attr3")).as_float(), 0.12); - CHECK_DOUBLE(node.attribute(STR("attr4")).as_float(), -5.1); - CHECK_DOUBLE(node.attribute(STR("attr5")).as_float(), 3e-4); - CHECK_DOUBLE(node.attribute(STR("attr6")).as_float(), 3.14159265358979323846); -} - -TEST_XML(dom_attr_as_double, "") -{ - xml_node node = doc.child(STR("node")); - - CHECK(xml_attribute().as_double() == 0); - CHECK_DOUBLE(node.attribute(STR("attr1")).as_double(), 0); - CHECK_DOUBLE(node.attribute(STR("attr2")).as_double(), 1); - CHECK_DOUBLE(node.attribute(STR("attr3")).as_double(), 0.12); - CHECK_DOUBLE(node.attribute(STR("attr4")).as_double(), -5.1); - CHECK_DOUBLE(node.attribute(STR("attr5")).as_double(), 3e-4); - CHECK_DOUBLE(node.attribute(STR("attr6")).as_double(), 3.14159265358979323846); -} - -TEST_XML(dom_attr_as_bool, "") -{ - xml_node node = doc.child(STR("node")); - - CHECK(!xml_attribute().as_bool()); - CHECK(!node.attribute(STR("attr1")).as_bool()); - CHECK(node.attribute(STR("attr2")).as_bool()); - CHECK(node.attribute(STR("attr3")).as_bool()); - CHECK(node.attribute(STR("attr4")).as_bool()); - CHECK(node.attribute(STR("attr5")).as_bool()); - CHECK(node.attribute(STR("attr6")).as_bool()); - CHECK(!node.attribute(STR("attr7")).as_bool()); -} - -TEST_XML(dom_attr_iterator, "") -{ - xml_node node1 = doc.child(STR("node")).child(STR("node1")); - xml_node node2 = doc.child(STR("node")).child(STR("node2")); - xml_node node3 = doc.child(STR("node")).child(STR("node3")); - - CHECK(xml_node().attributes_begin() == xml_attribute_iterator()); - CHECK(xml_node().attributes_end() == xml_attribute_iterator()); - - CHECK(node1.attributes_begin() == xml_attribute_iterator(node1.attribute(STR("attr1")), node1)); - CHECK(move_iter(node1.attributes_begin(), 1) == node1.attributes_end()); - CHECK(move_iter(node1.attributes_end(), -1) == node1.attributes_begin()); - CHECK(*node1.attributes_begin() == node1.attribute(STR("attr1"))); - CHECK_STRING(node1.attributes_begin()->name(), STR("attr1")); - - CHECK(move_iter(node2.attributes_begin(), 2) == node2.attributes_end()); - CHECK(move_iter(node2.attributes_end(), -2) == node2.attributes_begin()); - - CHECK(node3.attributes_begin() != xml_attribute_iterator()); - CHECK(node3.attributes_begin() == node3.attributes_end()); - - xml_attribute_iterator it = xml_attribute_iterator(node2.attribute(STR("attr2")), node2); - xml_attribute_iterator itt = it; - - CHECK(itt++ == it); - CHECK(itt == node2.attributes_end()); - - CHECK(itt-- == node2.attributes_end()); - CHECK(itt == it); - - CHECK(++itt == node2.attributes_end()); - CHECK(itt == node2.attributes_end()); - - CHECK(--itt == it); - CHECK(itt == it); - - CHECK(++itt != it); -} - -TEST_XML(dom_attr_iterator_end, "") -{ - xml_node node1 = doc.child(STR("node")).child(STR("node1")); - xml_node node2 = doc.child(STR("node")).child(STR("node2")); - xml_node node3 = doc.child(STR("node")).child(STR("node3")); - - CHECK(node1.attributes_end() != node2.attributes_end() && node1.attributes_end() != node3.attributes_end() && node2.attributes_end() != node3.attributes_end()); - CHECK(node1.attributes_end() != xml_attribute_iterator() && node2.attributes_end() != xml_attribute_iterator() && node3.attributes_end() != xml_attribute_iterator()); -} - -TEST_XML(dom_attr_iterator_invalidate, "") -{ - xml_node node2 = doc.child(STR("node")).child(STR("node2")); - - xml_attribute_iterator it1 = node2.attributes_begin(); - xml_attribute_iterator it2 = move_iter(it1, 1); - xml_attribute_iterator it3 = move_iter(it2, 1); - - CHECK(it3 == node2.attributes_end()); - - // removing attr2, it2 is invalid now, it3 is still past-the-end - node2.remove_attribute(*it2); - - CHECK(node2.attributes_end() == it3); - CHECK(move_iter(it1, 1) == it3); - CHECK(move_iter(it3, -1) == it1); - CHECK_STRING(it1->name(), STR("attr1")); - - // adding attr2 back, it3 is still past-the-end! - xml_attribute_iterator it2new = xml_attribute_iterator(node2.append_attribute(STR("attr2-new")), node2); - - CHECK(node2.attributes_end() == it3); - CHECK(move_iter(it1, 1) == it2new); - CHECK(move_iter(it2new, 1) == it3); - CHECK(move_iter(it3, -1) == it2new); - CHECK_STRING(it2new->name(), STR("attr2-new")); - - // removing both attributes, it3 is now equal to the begin - node2.remove_attribute(*it1); - node2.remove_attribute(*it2new); - CHECK(!node2.first_attribute()); - - CHECK(node2.attributes_begin() == it3); - CHECK(node2.attributes_end() == it3); -} - -TEST_XML(dom_node_bool_ops, "") -{ - generic_bool_ops_test(doc.child(STR("node"))); -} - -TEST_XML(dom_node_eq_ops, "") -{ - generic_eq_ops_test(doc.child(STR("node")).child(STR("node1")), doc.child(STR("node")).child(STR("node2"))); -} - -TEST_XML(dom_node_rel_ops, "") -{ - generic_rel_ops_test(doc.child(STR("node")).child(STR("node1")), doc.child(STR("node")).child(STR("node2"))); -} - -TEST_XML(dom_node_empty, "") -{ - generic_empty_test(doc.child(STR("node"))); -} - -TEST_XML(dom_node_iterator, "") -{ - xml_node node1 = doc.child(STR("node")).child(STR("node1")); - xml_node node2 = doc.child(STR("node")).child(STR("node2")); - xml_node node3 = doc.child(STR("node")).child(STR("node3")); - - CHECK(xml_node().begin() == xml_node_iterator()); - CHECK(xml_node().end() == xml_node_iterator()); - - CHECK(node1.begin() == xml_node_iterator(node1.child(STR("child1")))); - CHECK(move_iter(node1.begin(), 1) == node1.end()); - CHECK(move_iter(node1.end(), -1) == node1.begin()); - CHECK(*node1.begin() == node1.child(STR("child1"))); - CHECK_STRING(node1.begin()->name(), STR("child1")); - - CHECK(move_iter(node2.begin(), 2) == node2.end()); - CHECK(move_iter(node2.end(), -2) == node2.begin()); - - CHECK(node3.begin() != xml_node_iterator()); - CHECK(node3.begin() == node3.end()); - - xml_node_iterator it = node2.child(STR("child2")); - xml_node_iterator itt = it; - - CHECK(itt++ == it); - CHECK(itt == node2.end()); - - CHECK(itt-- == node2.end()); - CHECK(itt == it); - - CHECK(++itt == node2.end()); - CHECK(itt == node2.end()); - - CHECK(--itt == it); - CHECK(itt == it); - - CHECK(++itt != it); -} - -TEST_XML(dom_node_iterator_end, "") -{ - xml_node node1 = doc.child(STR("node")).child(STR("node1")); - xml_node node2 = doc.child(STR("node")).child(STR("node2")); - xml_node node3 = doc.child(STR("node")).child(STR("node3")); - - CHECK(node1.end() != node2.end() && node1.end() != node3.end() && node2.end() != node3.end()); - CHECK(node1.end() != xml_node_iterator() && node2.end() != xml_node_iterator() && node3.end() != xml_node_iterator()); -} - -TEST_XML(dom_node_iterator_invalidate, "") -{ - xml_node node2 = doc.child(STR("node")).child(STR("node2")); - - xml_node_iterator it1 = node2.begin(); - xml_node_iterator it2 = move_iter(it1, 1); - xml_node_iterator it3 = move_iter(it2, 1); - - CHECK(it3 == node2.end()); - - // removing child2, it2 is invalid now, it3 is still past-the-end - node2.remove_child(*it2); - - CHECK(node2.end() == it3); - CHECK(move_iter(it1, 1) == it3); - CHECK(move_iter(it3, -1) == it1); - CHECK_STRING(it1->name(), STR("child1")); - - // adding attr2 back, it3 is still past-the-end! - xml_node_iterator it2new = node2.append_child(); - it2new->set_name(STR("child2-new")); - - CHECK(node2.end() == it3); - CHECK(move_iter(it1, 1) == it2new); - CHECK(move_iter(it2new, 1) == it3); - CHECK(move_iter(it3, -1) == it2new); - CHECK_STRING(it2new->name(), STR("child2-new")); - - // removing both nodes, it3 is now equal to the begin - node2.remove_child(*it1); - node2.remove_child(*it2new); - CHECK(!node2.first_child()); - - CHECK(node2.begin() == it3); - CHECK(node2.end() == it3); -} - -TEST_XML(dom_node_parent, "") -{ - CHECK(xml_node().parent() == xml_node()); - CHECK(doc.child(STR("node")).child(STR("child")).parent() == doc.child(STR("node"))); - CHECK(doc.child(STR("node")).parent() == doc); -} - -TEST_XML(dom_node_root, "") -{ - CHECK(xml_node().root() == xml_node()); - CHECK(doc.child(STR("node")).child(STR("child")).root() == doc); - CHECK(doc.child(STR("node")).root() == doc); -} - -TEST_XML_FLAGS(dom_node_type, "pcdata", parse_default | parse_pi | parse_comments | parse_declaration) -{ - CHECK(xml_node().type() == node_null); - CHECK(doc.type() == node_document); - - xml_node_iterator it = doc.begin(); - - CHECK((it++)->type() == node_declaration); - CHECK((it++)->type() == node_pi); - CHECK((it++)->type() == node_comment); - CHECK((it++)->type() == node_element); - - xml_node_iterator cit = doc.child(STR("node")).begin(); - - CHECK((cit++)->type() == node_pcdata); - CHECK((cit++)->type() == node_cdata); -} - -TEST_XML_FLAGS(dom_node_name_value, "pcdata", parse_default | parse_pi | parse_comments | parse_declaration) -{ - CHECK_NAME_VALUE(xml_node(), STR(""), STR("")); - CHECK_NAME_VALUE(doc, STR(""), STR("")); - - xml_node_iterator it = doc.begin(); - - CHECK_NAME_VALUE(*it++, STR("xml"), STR("")); - CHECK_NAME_VALUE(*it++, STR("pi"), STR("")); - CHECK_NAME_VALUE(*it++, STR(""), STR("comment")); - CHECK_NAME_VALUE(*it++, STR("node"), STR("")); - - xml_node_iterator cit = doc.child(STR("node")).begin(); - - CHECK_NAME_VALUE(*cit++, STR(""), STR("pcdata")); - CHECK_NAME_VALUE(*cit++, STR(""), STR("cdata")); -} - -TEST_XML(dom_node_child, "") -{ - CHECK(xml_node().child(STR("n")) == xml_node()); - - CHECK(doc.child(STR("n")) == xml_node()); - CHECK_NAME_VALUE(doc.child(STR("node")), STR("node"), STR("")); - CHECK(doc.child(STR("node")).child(STR("child2")) == doc.child(STR("node")).last_child()); -} - -TEST_XML(dom_node_attribute, "") -{ - CHECK(xml_node().attribute(STR("a")) == xml_attribute()); - - xml_node node = doc.child(STR("node")); - - CHECK(node.attribute(STR("n")) == xml_attribute()); - CHECK_NAME_VALUE(node.attribute(STR("attr1")), STR("attr1"), STR("0")); - CHECK(node.attribute(STR("attr2")) == node.last_attribute()); -} - -TEST_XML(dom_node_next_previous_sibling, "") -{ - CHECK(xml_node().next_sibling() == xml_node()); - CHECK(xml_node().next_sibling(STR("n")) == xml_node()); - - CHECK(xml_node().previous_sibling() == xml_node()); - CHECK(xml_node().previous_sibling(STR("n")) == xml_node()); - - xml_node child1 = doc.child(STR("node")).child(STR("child1")); - xml_node child2 = doc.child(STR("node")).child(STR("child2")); - xml_node child3 = doc.child(STR("node")).child(STR("child3")); - - CHECK(child1.next_sibling() == child2); - CHECK(child3.next_sibling() == xml_node()); - - CHECK(child1.previous_sibling() == xml_node()); - CHECK(child3.previous_sibling() == child2); - - CHECK(child1.next_sibling(STR("child3")) == child3); - CHECK(child1.next_sibling(STR("child")) == xml_node()); - - CHECK(child3.previous_sibling(STR("child1")) == child1); - CHECK(child3.previous_sibling(STR("child")) == xml_node()); -} - -TEST_XML(dom_node_child_value, "value1value2value4") -{ - CHECK_STRING(xml_node().child_value(), STR("")); - CHECK_STRING(xml_node().child_value(STR("n")), STR("")); - - xml_node node = doc.child(STR("node")); - - CHECK_STRING(node.child_value(), STR("value4")); - CHECK_STRING(node.child(STR("child1")).child_value(), STR("value1")); - CHECK_STRING(node.child(STR("child2")).child_value(), STR("value2")); - CHECK_STRING(node.child(STR("child3")).child_value(), STR("value3")); - CHECK_STRING(node.child_value(STR("child3")), STR("value3")); -} - -TEST_XML(dom_node_first_last_attribute, "") -{ - xml_node node = doc.child(STR("node")); - - CHECK(node.first_attribute() == node.attribute(STR("attr1"))); - CHECK(node.last_attribute() == node.attribute(STR("attr2"))); - - CHECK(xml_node().first_attribute() == xml_attribute()); - CHECK(xml_node().last_attribute() == xml_attribute()); - - CHECK(doc.first_attribute() == xml_attribute()); - CHECK(doc.last_attribute() == xml_attribute()); -} - -TEST_XML(dom_node_first_last_child, "") -{ - xml_node node = doc.child(STR("node")); - - CHECK(node.first_child() == node.child(STR("child1"))); - CHECK(node.last_child() == node.child(STR("child2"))); - - CHECK(xml_node().first_child() == xml_node()); - CHECK(xml_node().last_child() == xml_node()); - - CHECK(doc.first_child() == node); - CHECK(doc.last_child() == node); -} - -TEST_XML(dom_node_find_child_by_attribute, "") -{ - CHECK(xml_node().find_child_by_attribute(STR("name"), STR("attr"), STR("value")) == xml_node()); - CHECK(xml_node().find_child_by_attribute(STR("attr"), STR("value")) == xml_node()); - - xml_node node = doc.child(STR("node")); - - CHECK(node.find_child_by_attribute(STR("child2"), STR("attr"), STR("value3")) == node.last_child()); - CHECK(node.find_child_by_attribute(STR("child2"), STR("attr3"), STR("value3")) == xml_node()); - CHECK(node.find_child_by_attribute(STR("attr"), STR("value2")) == node.child(STR("child2"))); - CHECK(node.find_child_by_attribute(STR("attr3"), STR("value")) == xml_node()); -} - -struct find_predicate_const -{ - bool result; - - find_predicate_const(bool result): result(result) - { - } - - template bool operator()(const T&) const - { - return result; - } -}; - -struct find_predicate_prefix -{ - const pugi::char_t* prefix; - - find_predicate_prefix(const pugi::char_t* prefix): prefix(prefix) - { - } - - template bool operator()(const T& obj) const - { - #ifdef PUGIXML_WCHAR_MODE - // can't use wcsncmp here because of a bug in DMC - return std::basic_string(obj.name()).compare(0, wcslen(prefix), prefix) == 0; - #else - return strncmp(obj.name(), prefix, strlen(prefix)) == 0; - #endif - } -}; - -TEST_XML(dom_node_find_attribute, "") -{ - CHECK(xml_node().find_attribute(find_predicate_const(true)) == xml_attribute()); - - xml_node node = doc.child(STR("node")); - - CHECK(doc.find_attribute(find_predicate_const(true)) == xml_attribute()); - CHECK(node.find_attribute(find_predicate_const(true)) == node.first_attribute()); - CHECK(node.find_attribute(find_predicate_const(false)) == xml_attribute()); - CHECK(node.find_attribute(find_predicate_prefix(STR("attr2"))) == node.last_attribute()); - CHECK(node.find_attribute(find_predicate_prefix(STR("attr"))) == node.first_attribute()); -} - -TEST_XML(dom_node_find_child, "") -{ - CHECK(xml_node().find_child(find_predicate_const(true)) == xml_node()); - - xml_node node = doc.child(STR("node")); - - CHECK(node.child(STR("node")).child(STR("child1")).find_child(find_predicate_const(true)) == xml_node()); - CHECK(node.find_child(find_predicate_const(true)) == node.first_child()); - CHECK(node.find_child(find_predicate_const(false)) == xml_node()); - CHECK(node.find_child(find_predicate_prefix(STR("child2"))) == node.last_child()); - CHECK(node.find_child(find_predicate_prefix(STR("child"))) == node.first_child()); -} - -TEST_XML(dom_node_find_node, "") -{ - CHECK(xml_node().find_node(find_predicate_const(true)) == xml_node()); - - xml_node node = doc.child(STR("node")); - - CHECK(node.child(STR("node")).child(STR("child1")).find_node(find_predicate_const(true)) == xml_node()); - CHECK(node.find_node(find_predicate_const(true)) == node.first_child()); - CHECK(node.find_node(find_predicate_const(false)) == xml_node()); - CHECK(node.find_node(find_predicate_prefix(STR("child2"))) == node.last_child()); - CHECK(node.find_node(find_predicate_prefix(STR("child"))) == node.first_child()); - CHECK(doc.find_node(find_predicate_prefix(STR("child"))) == node.first_child()); - CHECK(doc.find_node(find_predicate_prefix(STR("child2"))) == node.last_child()); - CHECK(doc.find_node(find_predicate_prefix(STR("child3"))) == xml_node()); -} - -#ifndef PUGIXML_NO_STL -TEST_XML(dom_node_path, "text") -{ - CHECK(xml_node().path() == STR("")); - - CHECK(doc.path() == STR("")); - CHECK(doc.child(STR("node")).path() == STR("/node")); - CHECK(doc.child(STR("node")).child(STR("child1")).path() == STR("/node/child1")); - CHECK(doc.child(STR("node")).child(STR("child1")).child(STR("child2")).path() == STR("/node/child1/child2")); - CHECK(doc.child(STR("node")).child(STR("child1")).first_child().path() == STR("/node/child1/")); - - CHECK(doc.child(STR("node")).child(STR("child1")).path('\\') == STR("\\node\\child1")); -} -#endif - -TEST_XML(dom_node_first_element_by_path, "text") -{ - CHECK(xml_node().first_element_by_path(STR("/")) == xml_node()); - - CHECK(doc.first_element_by_path(STR("")) == doc); - CHECK(doc.first_element_by_path(STR("/")) == doc); - - CHECK(doc.first_element_by_path(STR("/node/")) == doc.child(STR("node"))); - CHECK(doc.first_element_by_path(STR("node/")) == doc.child(STR("node"))); - CHECK(doc.first_element_by_path(STR("node")) == doc.child(STR("node"))); - CHECK(doc.first_element_by_path(STR("/node")) == doc.child(STR("node"))); - -#ifndef PUGIXML_NO_STL - CHECK(doc.first_element_by_path(STR("/node/child1/child2")).path() == STR("/node/child1/child2")); -#endif - - CHECK(doc.first_element_by_path(STR("/node/child2")) == xml_node()); - - CHECK(doc.first_element_by_path(STR("\\node\\child1"), '\\') == doc.child(STR("node")).child(STR("child1"))); - - CHECK(doc.child(STR("node")).first_element_by_path(STR("..")) == doc); - CHECK(doc.child(STR("node")).first_element_by_path(STR(".")) == doc.child(STR("node"))); - - CHECK(doc.child(STR("node")).first_element_by_path(STR("../node/./child1/../.")) == doc.child(STR("node"))); - - CHECK(doc.child(STR("node")).first_element_by_path(STR("child1")) == doc.child(STR("node")).child(STR("child1"))); - CHECK(doc.child(STR("node")).first_element_by_path(STR("child1/")) == doc.child(STR("node")).child(STR("child1"))); - CHECK(doc.child(STR("node")).first_element_by_path(STR("child")) == xml_node()); - CHECK(doc.child(STR("node")).first_element_by_path(STR("child11")) == xml_node()); -} - -struct test_walker: xml_tree_walker -{ - std::basic_string log; - unsigned int call_count; - unsigned int stop_count; - - test_walker(unsigned int stop_count = 0): call_count(0), stop_count(stop_count) - { - } - - std::basic_string depthstr() const - { - char buf[32]; - sprintf(buf, "%d", depth()); - - #ifdef PUGIXML_WCHAR_MODE - wchar_t wbuf[32]; - std::copy(buf, buf + strlen(buf) + 1, &wbuf[0]); - - return std::basic_string(wbuf); - #else - return std::basic_string(buf); - #endif - } - - virtual bool begin(xml_node& node) - { - log += STR("|"); - log += depthstr(); - log += STR(" <"); - log += node.name(); - log += STR("="); - log += node.value(); - - return ++call_count != stop_count && xml_tree_walker::begin(node); - } - - virtual bool for_each(xml_node& node) - { - log += STR("|"); - log += depthstr(); - log += STR(" !"); - log += node.name(); - log += STR("="); - log += node.value(); - - return ++call_count != stop_count && xml_tree_walker::end(node); - } - - virtual bool end(xml_node& node) - { - log += STR("|"); - log += depthstr(); - log += STR(" >"); - log += node.name(); - log += STR("="); - log += node.value(); - - return ++call_count != stop_count; - } -}; - -TEST_XML(dom_node_traverse, "text") -{ - test_walker walker; - - CHECK(doc.traverse(walker)); - - CHECK(walker.call_count == 5); - CHECK(walker.log == STR("|-1 <=|0 !node=|1 !child=|2 !=text|-1 >=")); -} - -TEST_XML(dom_node_traverse_siblings, "text") -{ - test_walker walker; - - CHECK(doc.traverse(walker)); - - CHECK(walker.call_count == 7); - CHECK(walker.log == STR("|-1 <=|0 !node=|1 !child=|1 !child=|2 !=text|1 !child=|-1 >=")); -} - -TEST(dom_node_traverse_empty) -{ - test_walker walker; - - CHECK(xml_node().traverse(walker)); - - CHECK(walker.call_count == 2); - CHECK(walker.log == STR("|-1 <=|-1 >=")); -} - -TEST_XML(dom_node_traverse_child, "text") -{ - test_walker walker; - - CHECK(doc.child(STR("node")).traverse(walker)); - - CHECK(walker.call_count == 4); - CHECK(walker.log == STR("|-1 node=")); -} - -TEST_XML(dom_node_traverse_stop_begin, "text") -{ - test_walker walker(1); - - CHECK(!doc.traverse(walker)); - - CHECK(walker.call_count == 1); - CHECK(walker.log == STR("|-1 <=")); -} - -TEST_XML(dom_node_traverse_stop_for_each, "text") -{ - test_walker walker(3); - - CHECK(!doc.traverse(walker)); - - CHECK(walker.call_count == 3); - CHECK(walker.log == STR("|-1 <=|0 !node=|1 !child=")); -} - -TEST_XML(dom_node_traverse_stop_end, "text") -{ - test_walker walker(5); - - CHECK(!doc.traverse(walker)); - - CHECK(walker.call_count == 5); - CHECK(walker.log == STR("|-1 <=|0 !node=|1 !child=|2 !=text|-1 >=")); -} - -TEST_XML_FLAGS(dom_offset_debug, "pcdata", parse_default | parse_pi | parse_comments | parse_declaration) -{ - CHECK(xml_node().offset_debug() == -1); - CHECK(doc.offset_debug() == 0); - - xml_node_iterator it = doc.begin(); - - CHECK((it++)->offset_debug() == 2); - CHECK((it++)->offset_debug() == 9); - CHECK((it++)->offset_debug() == 17); - CHECK((it++)->offset_debug() == 28); - - xml_node_iterator cit = doc.child(STR("node")).begin(); - - CHECK((cit++)->offset_debug() == 33); - CHECK((cit++)->offset_debug() == 48); -} +#define _CRT_SECURE_NO_WARNINGS +#define _SCL_SECURE_NO_WARNINGS + +#include "common.hpp" + +#include + +#include +#include + +#include +#include +#include +#include + +#include "helpers.hpp" + +#ifdef PUGIXML_NO_STL +template static I move_iter(I base, int n) +{ + if (n > 0) while (n--) ++base; + else while (n++) --base; + return base; +} +#else +template static I move_iter(I base, int n) +{ + std::advance(base, n); + return base; +} +#endif + +template static void generic_empty_test(const T& obj) +{ + T null; + + CHECK(null.empty()); + CHECK(!obj.empty()); +} + +TEST_XML(dom_attr_bool_ops, "") +{ + generic_bool_ops_test(doc.child(STR("node")).attribute(STR("attr"))); +} + +TEST_XML(dom_attr_eq_ops, "") +{ + generic_eq_ops_test(doc.child(STR("node")).attribute(STR("attr1")), doc.child(STR("node")).attribute(STR("attr2"))); +} + +TEST_XML(dom_attr_rel_ops, "") +{ + generic_rel_ops_test(doc.child(STR("node")).attribute(STR("attr1")), doc.child(STR("node")).attribute(STR("attr2"))); +} + +TEST_XML(dom_attr_empty, "") +{ + generic_empty_test(doc.child(STR("node")).attribute(STR("attr"))); +} + +TEST_XML(dom_attr_next_previous_attribute, "") +{ + xml_attribute attr1 = doc.child(STR("node")).attribute(STR("attr1")); + xml_attribute attr2 = doc.child(STR("node")).attribute(STR("attr2")); + + CHECK(attr1.next_attribute() == attr2); + CHECK(attr2.next_attribute() == xml_attribute()); + + CHECK(attr1.previous_attribute() == xml_attribute()); + CHECK(attr2.previous_attribute() == attr1); + + CHECK(xml_attribute().next_attribute() == xml_attribute()); + CHECK(xml_attribute().previous_attribute() == xml_attribute()); +} + +TEST_XML(dom_attr_name_value, "") +{ + xml_attribute attr = doc.child(STR("node")).attribute(STR("attr")); + + CHECK_NAME_VALUE(attr, STR("attr"), STR("1")); + CHECK_NAME_VALUE(xml_attribute(), STR(""), STR("")); +} + +TEST_XML(dom_attr_as_int, "") +{ + xml_node node = doc.child(STR("node")); + + CHECK(xml_attribute().as_int() == 0); + CHECK(node.attribute(STR("attr1")).as_int() == 1); + CHECK(node.attribute(STR("attr2")).as_int() == -1); + CHECK(node.attribute(STR("attr3")).as_int() == -2147483647 - 1); + CHECK(node.attribute(STR("attr4")).as_int() == 2147483647); +} + +TEST_XML(dom_attr_as_uint, "") +{ + xml_node node = doc.child(STR("node")); + + CHECK(xml_attribute().as_uint() == 0); + CHECK(node.attribute(STR("attr1")).as_uint() == 0); + CHECK(node.attribute(STR("attr2")).as_uint() == 1); + CHECK(node.attribute(STR("attr3")).as_uint() == 2147483647); + CHECK(node.attribute(STR("attr4")).as_uint() == 4294967295u); +} + +TEST_XML(dom_attr_as_float, "") +{ + xml_node node = doc.child(STR("node")); + + CHECK(xml_attribute().as_float() == 0); + CHECK_DOUBLE(node.attribute(STR("attr1")).as_float(), 0); + CHECK_DOUBLE(node.attribute(STR("attr2")).as_float(), 1); + CHECK_DOUBLE(node.attribute(STR("attr3")).as_float(), 0.12); + CHECK_DOUBLE(node.attribute(STR("attr4")).as_float(), -5.1); + CHECK_DOUBLE(node.attribute(STR("attr5")).as_float(), 3e-4); + CHECK_DOUBLE(node.attribute(STR("attr6")).as_float(), 3.14159265358979323846); +} + +TEST_XML(dom_attr_as_double, "") +{ + xml_node node = doc.child(STR("node")); + + CHECK(xml_attribute().as_double() == 0); + CHECK_DOUBLE(node.attribute(STR("attr1")).as_double(), 0); + CHECK_DOUBLE(node.attribute(STR("attr2")).as_double(), 1); + CHECK_DOUBLE(node.attribute(STR("attr3")).as_double(), 0.12); + CHECK_DOUBLE(node.attribute(STR("attr4")).as_double(), -5.1); + CHECK_DOUBLE(node.attribute(STR("attr5")).as_double(), 3e-4); + CHECK_DOUBLE(node.attribute(STR("attr6")).as_double(), 3.14159265358979323846); +} + +TEST_XML(dom_attr_as_bool, "") +{ + xml_node node = doc.child(STR("node")); + + CHECK(!xml_attribute().as_bool()); + CHECK(!node.attribute(STR("attr1")).as_bool()); + CHECK(node.attribute(STR("attr2")).as_bool()); + CHECK(node.attribute(STR("attr3")).as_bool()); + CHECK(node.attribute(STR("attr4")).as_bool()); + CHECK(node.attribute(STR("attr5")).as_bool()); + CHECK(node.attribute(STR("attr6")).as_bool()); + CHECK(!node.attribute(STR("attr7")).as_bool()); +} + +TEST_XML(dom_attr_iterator, "") +{ + xml_node node1 = doc.child(STR("node")).child(STR("node1")); + xml_node node2 = doc.child(STR("node")).child(STR("node2")); + xml_node node3 = doc.child(STR("node")).child(STR("node3")); + + CHECK(xml_node().attributes_begin() == xml_attribute_iterator()); + CHECK(xml_node().attributes_end() == xml_attribute_iterator()); + + CHECK(node1.attributes_begin() == xml_attribute_iterator(node1.attribute(STR("attr1")), node1)); + CHECK(move_iter(node1.attributes_begin(), 1) == node1.attributes_end()); + CHECK(move_iter(node1.attributes_end(), -1) == node1.attributes_begin()); + CHECK(*node1.attributes_begin() == node1.attribute(STR("attr1"))); + CHECK_STRING(node1.attributes_begin()->name(), STR("attr1")); + + CHECK(move_iter(node2.attributes_begin(), 2) == node2.attributes_end()); + CHECK(move_iter(node2.attributes_end(), -2) == node2.attributes_begin()); + + CHECK(node3.attributes_begin() != xml_attribute_iterator()); + CHECK(node3.attributes_begin() == node3.attributes_end()); + + xml_attribute_iterator it = xml_attribute_iterator(node2.attribute(STR("attr2")), node2); + xml_attribute_iterator itt = it; + + CHECK(itt++ == it); + CHECK(itt == node2.attributes_end()); + + CHECK(itt-- == node2.attributes_end()); + CHECK(itt == it); + + CHECK(++itt == node2.attributes_end()); + CHECK(itt == node2.attributes_end()); + + CHECK(--itt == it); + CHECK(itt == it); + + CHECK(++itt != it); +} + +TEST_XML(dom_attr_iterator_end, "") +{ + xml_node node1 = doc.child(STR("node")).child(STR("node1")); + xml_node node2 = doc.child(STR("node")).child(STR("node2")); + xml_node node3 = doc.child(STR("node")).child(STR("node3")); + + CHECK(node1.attributes_end() != node2.attributes_end() && node1.attributes_end() != node3.attributes_end() && node2.attributes_end() != node3.attributes_end()); + CHECK(node1.attributes_end() != xml_attribute_iterator() && node2.attributes_end() != xml_attribute_iterator() && node3.attributes_end() != xml_attribute_iterator()); +} + +TEST_XML(dom_attr_iterator_invalidate, "") +{ + xml_node node2 = doc.child(STR("node")).child(STR("node2")); + + xml_attribute_iterator it1 = node2.attributes_begin(); + xml_attribute_iterator it2 = move_iter(it1, 1); + xml_attribute_iterator it3 = move_iter(it2, 1); + + CHECK(it3 == node2.attributes_end()); + + // removing attr2, it2 is invalid now, it3 is still past-the-end + node2.remove_attribute(*it2); + + CHECK(node2.attributes_end() == it3); + CHECK(move_iter(it1, 1) == it3); + CHECK(move_iter(it3, -1) == it1); + CHECK_STRING(it1->name(), STR("attr1")); + + // adding attr2 back, it3 is still past-the-end! + xml_attribute_iterator it2new = xml_attribute_iterator(node2.append_attribute(STR("attr2-new")), node2); + + CHECK(node2.attributes_end() == it3); + CHECK(move_iter(it1, 1) == it2new); + CHECK(move_iter(it2new, 1) == it3); + CHECK(move_iter(it3, -1) == it2new); + CHECK_STRING(it2new->name(), STR("attr2-new")); + + // removing both attributes, it3 is now equal to the begin + node2.remove_attribute(*it1); + node2.remove_attribute(*it2new); + CHECK(!node2.first_attribute()); + + CHECK(node2.attributes_begin() == it3); + CHECK(node2.attributes_end() == it3); +} + +TEST_XML(dom_node_bool_ops, "") +{ + generic_bool_ops_test(doc.child(STR("node"))); +} + +TEST_XML(dom_node_eq_ops, "") +{ + generic_eq_ops_test(doc.child(STR("node")).child(STR("node1")), doc.child(STR("node")).child(STR("node2"))); +} + +TEST_XML(dom_node_rel_ops, "") +{ + generic_rel_ops_test(doc.child(STR("node")).child(STR("node1")), doc.child(STR("node")).child(STR("node2"))); +} + +TEST_XML(dom_node_empty, "") +{ + generic_empty_test(doc.child(STR("node"))); +} + +TEST_XML(dom_node_iterator, "") +{ + xml_node node1 = doc.child(STR("node")).child(STR("node1")); + xml_node node2 = doc.child(STR("node")).child(STR("node2")); + xml_node node3 = doc.child(STR("node")).child(STR("node3")); + + CHECK(xml_node().begin() == xml_node_iterator()); + CHECK(xml_node().end() == xml_node_iterator()); + + CHECK(node1.begin() == xml_node_iterator(node1.child(STR("child1")))); + CHECK(move_iter(node1.begin(), 1) == node1.end()); + CHECK(move_iter(node1.end(), -1) == node1.begin()); + CHECK(*node1.begin() == node1.child(STR("child1"))); + CHECK_STRING(node1.begin()->name(), STR("child1")); + + CHECK(move_iter(node2.begin(), 2) == node2.end()); + CHECK(move_iter(node2.end(), -2) == node2.begin()); + + CHECK(node3.begin() != xml_node_iterator()); + CHECK(node3.begin() == node3.end()); + + xml_node_iterator it = node2.child(STR("child2")); + xml_node_iterator itt = it; + + CHECK(itt++ == it); + CHECK(itt == node2.end()); + + CHECK(itt-- == node2.end()); + CHECK(itt == it); + + CHECK(++itt == node2.end()); + CHECK(itt == node2.end()); + + CHECK(--itt == it); + CHECK(itt == it); + + CHECK(++itt != it); +} + +TEST_XML(dom_node_iterator_end, "") +{ + xml_node node1 = doc.child(STR("node")).child(STR("node1")); + xml_node node2 = doc.child(STR("node")).child(STR("node2")); + xml_node node3 = doc.child(STR("node")).child(STR("node3")); + + CHECK(node1.end() != node2.end() && node1.end() != node3.end() && node2.end() != node3.end()); + CHECK(node1.end() != xml_node_iterator() && node2.end() != xml_node_iterator() && node3.end() != xml_node_iterator()); +} + +TEST_XML(dom_node_iterator_invalidate, "") +{ + xml_node node2 = doc.child(STR("node")).child(STR("node2")); + + xml_node_iterator it1 = node2.begin(); + xml_node_iterator it2 = move_iter(it1, 1); + xml_node_iterator it3 = move_iter(it2, 1); + + CHECK(it3 == node2.end()); + + // removing child2, it2 is invalid now, it3 is still past-the-end + node2.remove_child(*it2); + + CHECK(node2.end() == it3); + CHECK(move_iter(it1, 1) == it3); + CHECK(move_iter(it3, -1) == it1); + CHECK_STRING(it1->name(), STR("child1")); + + // adding attr2 back, it3 is still past-the-end! + xml_node_iterator it2new = node2.append_child(); + it2new->set_name(STR("child2-new")); + + CHECK(node2.end() == it3); + CHECK(move_iter(it1, 1) == it2new); + CHECK(move_iter(it2new, 1) == it3); + CHECK(move_iter(it3, -1) == it2new); + CHECK_STRING(it2new->name(), STR("child2-new")); + + // removing both nodes, it3 is now equal to the begin + node2.remove_child(*it1); + node2.remove_child(*it2new); + CHECK(!node2.first_child()); + + CHECK(node2.begin() == it3); + CHECK(node2.end() == it3); +} + +TEST_XML(dom_node_parent, "") +{ + CHECK(xml_node().parent() == xml_node()); + CHECK(doc.child(STR("node")).child(STR("child")).parent() == doc.child(STR("node"))); + CHECK(doc.child(STR("node")).parent() == doc); +} + +TEST_XML(dom_node_root, "") +{ + CHECK(xml_node().root() == xml_node()); + CHECK(doc.child(STR("node")).child(STR("child")).root() == doc); + CHECK(doc.child(STR("node")).root() == doc); +} + +TEST_XML_FLAGS(dom_node_type, "pcdata", parse_default | parse_pi | parse_comments | parse_declaration) +{ + CHECK(xml_node().type() == node_null); + CHECK(doc.type() == node_document); + + xml_node_iterator it = doc.begin(); + + CHECK((it++)->type() == node_declaration); + CHECK((it++)->type() == node_pi); + CHECK((it++)->type() == node_comment); + CHECK((it++)->type() == node_element); + + xml_node_iterator cit = doc.child(STR("node")).begin(); + + CHECK((cit++)->type() == node_pcdata); + CHECK((cit++)->type() == node_cdata); +} + +TEST_XML_FLAGS(dom_node_name_value, "pcdata", parse_default | parse_pi | parse_comments | parse_declaration) +{ + CHECK_NAME_VALUE(xml_node(), STR(""), STR("")); + CHECK_NAME_VALUE(doc, STR(""), STR("")); + + xml_node_iterator it = doc.begin(); + + CHECK_NAME_VALUE(*it++, STR("xml"), STR("")); + CHECK_NAME_VALUE(*it++, STR("pi"), STR("")); + CHECK_NAME_VALUE(*it++, STR(""), STR("comment")); + CHECK_NAME_VALUE(*it++, STR("node"), STR("")); + + xml_node_iterator cit = doc.child(STR("node")).begin(); + + CHECK_NAME_VALUE(*cit++, STR(""), STR("pcdata")); + CHECK_NAME_VALUE(*cit++, STR(""), STR("cdata")); +} + +TEST_XML(dom_node_child, "") +{ + CHECK(xml_node().child(STR("n")) == xml_node()); + + CHECK(doc.child(STR("n")) == xml_node()); + CHECK_NAME_VALUE(doc.child(STR("node")), STR("node"), STR("")); + CHECK(doc.child(STR("node")).child(STR("child2")) == doc.child(STR("node")).last_child()); +} + +TEST_XML(dom_node_attribute, "") +{ + CHECK(xml_node().attribute(STR("a")) == xml_attribute()); + + xml_node node = doc.child(STR("node")); + + CHECK(node.attribute(STR("n")) == xml_attribute()); + CHECK_NAME_VALUE(node.attribute(STR("attr1")), STR("attr1"), STR("0")); + CHECK(node.attribute(STR("attr2")) == node.last_attribute()); +} + +TEST_XML(dom_node_next_previous_sibling, "") +{ + CHECK(xml_node().next_sibling() == xml_node()); + CHECK(xml_node().next_sibling(STR("n")) == xml_node()); + + CHECK(xml_node().previous_sibling() == xml_node()); + CHECK(xml_node().previous_sibling(STR("n")) == xml_node()); + + xml_node child1 = doc.child(STR("node")).child(STR("child1")); + xml_node child2 = doc.child(STR("node")).child(STR("child2")); + xml_node child3 = doc.child(STR("node")).child(STR("child3")); + + CHECK(child1.next_sibling() == child2); + CHECK(child3.next_sibling() == xml_node()); + + CHECK(child1.previous_sibling() == xml_node()); + CHECK(child3.previous_sibling() == child2); + + CHECK(child1.next_sibling(STR("child3")) == child3); + CHECK(child1.next_sibling(STR("child")) == xml_node()); + + CHECK(child3.previous_sibling(STR("child1")) == child1); + CHECK(child3.previous_sibling(STR("child")) == xml_node()); +} + +TEST_XML(dom_node_child_value, "value1value2value4") +{ + CHECK_STRING(xml_node().child_value(), STR("")); + CHECK_STRING(xml_node().child_value(STR("n")), STR("")); + + xml_node node = doc.child(STR("node")); + + CHECK_STRING(node.child_value(), STR("value4")); + CHECK_STRING(node.child(STR("child1")).child_value(), STR("value1")); + CHECK_STRING(node.child(STR("child2")).child_value(), STR("value2")); + CHECK_STRING(node.child(STR("child3")).child_value(), STR("value3")); + CHECK_STRING(node.child_value(STR("child3")), STR("value3")); +} + +TEST_XML(dom_node_first_last_attribute, "") +{ + xml_node node = doc.child(STR("node")); + + CHECK(node.first_attribute() == node.attribute(STR("attr1"))); + CHECK(node.last_attribute() == node.attribute(STR("attr2"))); + + CHECK(xml_node().first_attribute() == xml_attribute()); + CHECK(xml_node().last_attribute() == xml_attribute()); + + CHECK(doc.first_attribute() == xml_attribute()); + CHECK(doc.last_attribute() == xml_attribute()); +} + +TEST_XML(dom_node_first_last_child, "") +{ + xml_node node = doc.child(STR("node")); + + CHECK(node.first_child() == node.child(STR("child1"))); + CHECK(node.last_child() == node.child(STR("child2"))); + + CHECK(xml_node().first_child() == xml_node()); + CHECK(xml_node().last_child() == xml_node()); + + CHECK(doc.first_child() == node); + CHECK(doc.last_child() == node); +} + +TEST_XML(dom_node_find_child_by_attribute, "") +{ + CHECK(xml_node().find_child_by_attribute(STR("name"), STR("attr"), STR("value")) == xml_node()); + CHECK(xml_node().find_child_by_attribute(STR("attr"), STR("value")) == xml_node()); + + xml_node node = doc.child(STR("node")); + + CHECK(node.find_child_by_attribute(STR("child2"), STR("attr"), STR("value3")) == node.last_child()); + CHECK(node.find_child_by_attribute(STR("child2"), STR("attr3"), STR("value3")) == xml_node()); + CHECK(node.find_child_by_attribute(STR("attr"), STR("value2")) == node.child(STR("child2"))); + CHECK(node.find_child_by_attribute(STR("attr3"), STR("value")) == xml_node()); +} + +struct find_predicate_const +{ + bool result; + + find_predicate_const(bool result): result(result) + { + } + + template bool operator()(const T&) const + { + return result; + } +}; + +struct find_predicate_prefix +{ + const pugi::char_t* prefix; + + find_predicate_prefix(const pugi::char_t* prefix): prefix(prefix) + { + } + + template bool operator()(const T& obj) const + { + #ifdef PUGIXML_WCHAR_MODE + // can't use wcsncmp here because of a bug in DMC + return std::basic_string(obj.name()).compare(0, wcslen(prefix), prefix) == 0; + #else + return strncmp(obj.name(), prefix, strlen(prefix)) == 0; + #endif + } +}; + +TEST_XML(dom_node_find_attribute, "") +{ + CHECK(xml_node().find_attribute(find_predicate_const(true)) == xml_attribute()); + + xml_node node = doc.child(STR("node")); + + CHECK(doc.find_attribute(find_predicate_const(true)) == xml_attribute()); + CHECK(node.find_attribute(find_predicate_const(true)) == node.first_attribute()); + CHECK(node.find_attribute(find_predicate_const(false)) == xml_attribute()); + CHECK(node.find_attribute(find_predicate_prefix(STR("attr2"))) == node.last_attribute()); + CHECK(node.find_attribute(find_predicate_prefix(STR("attr"))) == node.first_attribute()); +} + +TEST_XML(dom_node_find_child, "") +{ + CHECK(xml_node().find_child(find_predicate_const(true)) == xml_node()); + + xml_node node = doc.child(STR("node")); + + CHECK(node.child(STR("node")).child(STR("child1")).find_child(find_predicate_const(true)) == xml_node()); + CHECK(node.find_child(find_predicate_const(true)) == node.first_child()); + CHECK(node.find_child(find_predicate_const(false)) == xml_node()); + CHECK(node.find_child(find_predicate_prefix(STR("child2"))) == node.last_child()); + CHECK(node.find_child(find_predicate_prefix(STR("child"))) == node.first_child()); +} + +TEST_XML(dom_node_find_node, "") +{ + CHECK(xml_node().find_node(find_predicate_const(true)) == xml_node()); + + xml_node node = doc.child(STR("node")); + + CHECK(node.child(STR("node")).child(STR("child1")).find_node(find_predicate_const(true)) == xml_node()); + CHECK(node.find_node(find_predicate_const(true)) == node.first_child()); + CHECK(node.find_node(find_predicate_const(false)) == xml_node()); + CHECK(node.find_node(find_predicate_prefix(STR("child2"))) == node.last_child()); + CHECK(node.find_node(find_predicate_prefix(STR("child"))) == node.first_child()); + CHECK(doc.find_node(find_predicate_prefix(STR("child"))) == node.first_child()); + CHECK(doc.find_node(find_predicate_prefix(STR("child2"))) == node.last_child()); + CHECK(doc.find_node(find_predicate_prefix(STR("child3"))) == xml_node()); +} + +#ifndef PUGIXML_NO_STL +TEST_XML(dom_node_path, "text") +{ + CHECK(xml_node().path() == STR("")); + + CHECK(doc.path() == STR("")); + CHECK(doc.child(STR("node")).path() == STR("/node")); + CHECK(doc.child(STR("node")).child(STR("child1")).path() == STR("/node/child1")); + CHECK(doc.child(STR("node")).child(STR("child1")).child(STR("child2")).path() == STR("/node/child1/child2")); + CHECK(doc.child(STR("node")).child(STR("child1")).first_child().path() == STR("/node/child1/")); + + CHECK(doc.child(STR("node")).child(STR("child1")).path('\\') == STR("\\node\\child1")); +} +#endif + +TEST_XML(dom_node_first_element_by_path, "text") +{ + CHECK(xml_node().first_element_by_path(STR("/")) == xml_node()); + + CHECK(doc.first_element_by_path(STR("")) == doc); + CHECK(doc.first_element_by_path(STR("/")) == doc); + + CHECK(doc.first_element_by_path(STR("/node/")) == doc.child(STR("node"))); + CHECK(doc.first_element_by_path(STR("node/")) == doc.child(STR("node"))); + CHECK(doc.first_element_by_path(STR("node")) == doc.child(STR("node"))); + CHECK(doc.first_element_by_path(STR("/node")) == doc.child(STR("node"))); + +#ifndef PUGIXML_NO_STL + CHECK(doc.first_element_by_path(STR("/node/child1/child2")).path() == STR("/node/child1/child2")); +#endif + + CHECK(doc.first_element_by_path(STR("/node/child2")) == xml_node()); + + CHECK(doc.first_element_by_path(STR("\\node\\child1"), '\\') == doc.child(STR("node")).child(STR("child1"))); + + CHECK(doc.child(STR("node")).first_element_by_path(STR("..")) == doc); + CHECK(doc.child(STR("node")).first_element_by_path(STR(".")) == doc.child(STR("node"))); + + CHECK(doc.child(STR("node")).first_element_by_path(STR("../node/./child1/../.")) == doc.child(STR("node"))); + + CHECK(doc.child(STR("node")).first_element_by_path(STR("child1")) == doc.child(STR("node")).child(STR("child1"))); + CHECK(doc.child(STR("node")).first_element_by_path(STR("child1/")) == doc.child(STR("node")).child(STR("child1"))); + CHECK(doc.child(STR("node")).first_element_by_path(STR("child")) == xml_node()); + CHECK(doc.child(STR("node")).first_element_by_path(STR("child11")) == xml_node()); +} + +struct test_walker: xml_tree_walker +{ + std::basic_string log; + unsigned int call_count; + unsigned int stop_count; + + test_walker(unsigned int stop_count = 0): call_count(0), stop_count(stop_count) + { + } + + std::basic_string depthstr() const + { + char buf[32]; + sprintf(buf, "%d", depth()); + + #ifdef PUGIXML_WCHAR_MODE + wchar_t wbuf[32]; + std::copy(buf, buf + strlen(buf) + 1, &wbuf[0]); + + return std::basic_string(wbuf); + #else + return std::basic_string(buf); + #endif + } + + virtual bool begin(xml_node& node) + { + log += STR("|"); + log += depthstr(); + log += STR(" <"); + log += node.name(); + log += STR("="); + log += node.value(); + + return ++call_count != stop_count && xml_tree_walker::begin(node); + } + + virtual bool for_each(xml_node& node) + { + log += STR("|"); + log += depthstr(); + log += STR(" !"); + log += node.name(); + log += STR("="); + log += node.value(); + + return ++call_count != stop_count && xml_tree_walker::end(node); + } + + virtual bool end(xml_node& node) + { + log += STR("|"); + log += depthstr(); + log += STR(" >"); + log += node.name(); + log += STR("="); + log += node.value(); + + return ++call_count != stop_count; + } +}; + +TEST_XML(dom_node_traverse, "text") +{ + test_walker walker; + + CHECK(doc.traverse(walker)); + + CHECK(walker.call_count == 5); + CHECK(walker.log == STR("|-1 <=|0 !node=|1 !child=|2 !=text|-1 >=")); +} + +TEST_XML(dom_node_traverse_siblings, "text") +{ + test_walker walker; + + CHECK(doc.traverse(walker)); + + CHECK(walker.call_count == 7); + CHECK(walker.log == STR("|-1 <=|0 !node=|1 !child=|1 !child=|2 !=text|1 !child=|-1 >=")); +} + +TEST(dom_node_traverse_empty) +{ + test_walker walker; + + CHECK(xml_node().traverse(walker)); + + CHECK(walker.call_count == 2); + CHECK(walker.log == STR("|-1 <=|-1 >=")); +} + +TEST_XML(dom_node_traverse_child, "text") +{ + test_walker walker; + + CHECK(doc.child(STR("node")).traverse(walker)); + + CHECK(walker.call_count == 4); + CHECK(walker.log == STR("|-1 node=")); +} + +TEST_XML(dom_node_traverse_stop_begin, "text") +{ + test_walker walker(1); + + CHECK(!doc.traverse(walker)); + + CHECK(walker.call_count == 1); + CHECK(walker.log == STR("|-1 <=")); +} + +TEST_XML(dom_node_traverse_stop_for_each, "text") +{ + test_walker walker(3); + + CHECK(!doc.traverse(walker)); + + CHECK(walker.call_count == 3); + CHECK(walker.log == STR("|-1 <=|0 !node=|1 !child=")); +} + +TEST_XML(dom_node_traverse_stop_end, "text") +{ + test_walker walker(5); + + CHECK(!doc.traverse(walker)); + + CHECK(walker.call_count == 5); + CHECK(walker.log == STR("|-1 <=|0 !node=|1 !child=|2 !=text|-1 >=")); +} + +TEST_XML_FLAGS(dom_offset_debug, "pcdata", parse_default | parse_pi | parse_comments | parse_declaration) +{ + CHECK(xml_node().offset_debug() == -1); + CHECK(doc.offset_debug() == 0); + + xml_node_iterator it = doc.begin(); + + CHECK((it++)->offset_debug() == 2); + CHECK((it++)->offset_debug() == 9); + CHECK((it++)->offset_debug() == 17); + CHECK((it++)->offset_debug() == 28); + + xml_node_iterator cit = doc.child(STR("node")).begin(); + + CHECK((cit++)->offset_debug() == 33); + CHECK((cit++)->offset_debug() == 48); +} diff --git a/tests/test_header_guard.cpp b/tests/test_header_guard.cpp index 3706cc9..2f65928 100644 --- a/tests/test_header_guard.cpp +++ b/tests/test_header_guard.cpp @@ -1,3 +1,3 @@ -// Tests header guards -#include "../src/pugixml.hpp" -#include "../src/pugixml.hpp" +// Tests header guards +#include "../src/pugixml.hpp" +#include "../src/pugixml.hpp" diff --git a/tests/test_header_iosfwd_1.cpp b/tests/test_header_iosfwd_1.cpp index 73e8527..0ed528a 100644 --- a/tests/test_header_iosfwd_1.cpp +++ b/tests/test_header_iosfwd_1.cpp @@ -1,3 +1,3 @@ -// Tests compatibility with iosfwd -#include "../src/pugixml.hpp" -#include +// Tests compatibility with iosfwd +#include "../src/pugixml.hpp" +#include diff --git a/tests/test_header_iosfwd_2.cpp b/tests/test_header_iosfwd_2.cpp index e472b9c..865d0d8 100644 --- a/tests/test_header_iosfwd_2.cpp +++ b/tests/test_header_iosfwd_2.cpp @@ -1,3 +1,3 @@ -// Tests compatibility with iosfwd -#include -#include "../src/pugixml.hpp" +// Tests compatibility with iosfwd +#include +#include "../src/pugixml.hpp" diff --git a/tests/test_header_iostream_1.cpp b/tests/test_header_iostream_1.cpp index 2b359f9..a836d4f 100644 --- a/tests/test_header_iostream_1.cpp +++ b/tests/test_header_iostream_1.cpp @@ -1,3 +1,3 @@ -// Tests compatibility with iostream -#include "../src/pugixml.hpp" -#include +// Tests compatibility with iostream +#include "../src/pugixml.hpp" +#include diff --git a/tests/test_header_iostream_2.cpp b/tests/test_header_iostream_2.cpp index 0b1b6b8..c0be50b 100644 --- a/tests/test_header_iostream_2.cpp +++ b/tests/test_header_iostream_2.cpp @@ -1,3 +1,3 @@ -// Tests compatibility with iostream -#include -#include "../src/pugixml.hpp" +// Tests compatibility with iostream +#include +#include "../src/pugixml.hpp" diff --git a/tests/test_header_string_1.cpp b/tests/test_header_string_1.cpp index 9e9d33f..07d1263 100644 --- a/tests/test_header_string_1.cpp +++ b/tests/test_header_string_1.cpp @@ -1,3 +1,3 @@ -// Tests compatibility with string -#include "../src/pugixml.hpp" -#include +// Tests compatibility with string +#include "../src/pugixml.hpp" +#include diff --git a/tests/test_header_string_2.cpp b/tests/test_header_string_2.cpp index 01d72ac..2813fc9 100644 --- a/tests/test_header_string_2.cpp +++ b/tests/test_header_string_2.cpp @@ -1,3 +1,3 @@ -// Tests compatibility with string -#include -#include "../src/pugixml.hpp" +// Tests compatibility with string +#include +#include "../src/pugixml.hpp" diff --git a/tests/test_memory.cpp b/tests/test_memory.cpp index 80e36c2..8b4b6bc 100644 --- a/tests/test_memory.cpp +++ b/tests/test_memory.cpp @@ -1,129 +1,129 @@ -#include "common.hpp" - -#include - -namespace -{ - int allocate_count = 0; - int deallocate_count = 0; - - void* allocate(size_t size) - { - ++allocate_count; - return new char[size]; - } - - void deallocate(void* ptr) - { - ++deallocate_count; - delete[] reinterpret_cast(ptr); - } -} - -TEST(custom_memory_management) -{ - allocate_count = deallocate_count = 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(allocate_count == 0 && deallocate_count == 0); - - CHECK(doc.load(STR(""))); - - CHECK(allocate_count == 2 && deallocate_count == 0); - - // modify document (no new page) - CHECK(doc.first_child().set_name(STR("foobars"))); - CHECK(allocate_count == 2 && deallocate_count == 0); - - // modify document (new page) - std::basic_string s(65536, 'x'); - - CHECK(doc.first_child().set_name(s.c_str())); - CHECK(allocate_count == 3 && deallocate_count == 0); - - // modify document (new page, old one should die) - s += s; - - CHECK(doc.first_child().set_name(s.c_str())); - CHECK(allocate_count == 4 && deallocate_count == 1); - } - - CHECK(allocate_count == 4 && deallocate_count == 4); - - // restore old functions - set_memory_management_functions(old_allocate, old_deallocate); -} - -TEST(large_allocations) -{ - allocate_count = deallocate_count = 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(allocate_count == 0 && deallocate_count == 0); - - // initial fill - for (size_t i = 0; i < 128; ++i) - { - std::basic_string s(i * 128, 'x'); - - CHECK(doc.append_child(node_pcdata).set_value(s.c_str())); - } - - CHECK(allocate_count > 0 && deallocate_count == 0); - - // grow-prune loop - while (doc.first_child()) - { - pugi::xml_node node; - - // grow - for (node = doc.first_child(); node; node = node.next_sibling()) - { - std::basic_string s = node.value(); - - CHECK(node.set_value((s + s).c_str())); - } - - // prune - for (node = doc.first_child(); node; ) - { - pugi::xml_node next = node.next_sibling().next_sibling(); - - node.parent().remove_child(node); - - node = next; - } - } - - CHECK(allocate_count == deallocate_count + 1); // only one live page left (it waits for new allocations) - - char buffer; - CHECK(doc.load_buffer_inplace(&buffer, 0, parse_default, get_native_encoding())); - - CHECK(allocate_count == deallocate_count); // no live pages left - } - - CHECK(allocate_count == deallocate_count); // everything is freed - - // restore old functions - set_memory_management_functions(old_allocate, old_deallocate); -} +#include "common.hpp" + +#include + +namespace +{ + int allocate_count = 0; + int deallocate_count = 0; + + void* allocate(size_t size) + { + ++allocate_count; + return new char[size]; + } + + void deallocate(void* ptr) + { + ++deallocate_count; + delete[] reinterpret_cast(ptr); + } +} + +TEST(custom_memory_management) +{ + allocate_count = deallocate_count = 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(allocate_count == 0 && deallocate_count == 0); + + CHECK(doc.load(STR(""))); + + CHECK(allocate_count == 2 && deallocate_count == 0); + + // modify document (no new page) + CHECK(doc.first_child().set_name(STR("foobars"))); + CHECK(allocate_count == 2 && deallocate_count == 0); + + // modify document (new page) + std::basic_string s(65536, 'x'); + + CHECK(doc.first_child().set_name(s.c_str())); + CHECK(allocate_count == 3 && deallocate_count == 0); + + // modify document (new page, old one should die) + s += s; + + CHECK(doc.first_child().set_name(s.c_str())); + CHECK(allocate_count == 4 && deallocate_count == 1); + } + + CHECK(allocate_count == 4 && deallocate_count == 4); + + // restore old functions + set_memory_management_functions(old_allocate, old_deallocate); +} + +TEST(large_allocations) +{ + allocate_count = deallocate_count = 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(allocate_count == 0 && deallocate_count == 0); + + // initial fill + for (size_t i = 0; i < 128; ++i) + { + std::basic_string s(i * 128, 'x'); + + CHECK(doc.append_child(node_pcdata).set_value(s.c_str())); + } + + CHECK(allocate_count > 0 && deallocate_count == 0); + + // grow-prune loop + while (doc.first_child()) + { + pugi::xml_node node; + + // grow + for (node = doc.first_child(); node; node = node.next_sibling()) + { + std::basic_string s = node.value(); + + CHECK(node.set_value((s + s).c_str())); + } + + // prune + for (node = doc.first_child(); node; ) + { + pugi::xml_node next = node.next_sibling().next_sibling(); + + node.parent().remove_child(node); + + node = next; + } + } + + CHECK(allocate_count == deallocate_count + 1); // only one live page left (it waits for new allocations) + + char buffer; + CHECK(doc.load_buffer_inplace(&buffer, 0, parse_default, get_native_encoding())); + + CHECK(allocate_count == deallocate_count); // no live pages left + } + + CHECK(allocate_count == deallocate_count); // everything is freed + + // restore old functions + set_memory_management_functions(old_allocate, old_deallocate); +} diff --git a/tests/test_parse.cpp b/tests/test_parse.cpp index 7f52d09..a997692 100644 --- a/tests/test_parse.cpp +++ b/tests/test_parse.cpp @@ -1,683 +1,683 @@ -#include "common.hpp" - -TEST(parse_pi_skip) -{ - xml_document doc; - - unsigned int flag_sets[] = {parse_minimal, parse_minimal | parse_declaration}; - - for (unsigned int i = 0; i < sizeof(flag_sets) / sizeof(flag_sets[0]); ++i) - { - unsigned int flags = flag_sets[i]; - - CHECK(doc.load(STR(""), flags)); - CHECK(!doc.first_child()); - - CHECK(doc.load(STR(" value?>"), flags)); - CHECK(!doc.first_child()); - } -} - -TEST(parse_pi_parse) -{ - xml_document doc; - CHECK(doc.load(STR(""), parse_minimal | parse_pi)); - - xml_node pi1 = doc.first_child(); - xml_node pi2 = doc.last_child(); - - CHECK(pi1 != pi2); - CHECK(pi1.type() == node_pi); - CHECK_STRING(pi1.name(), STR("pi1")); - CHECK_STRING(pi1.value(), STR("")); - CHECK(pi2.type() == node_pi); - CHECK_STRING(pi2.name(), STR("pi2")); - CHECK_STRING(pi2.value(), STR("value")); -} - -TEST(parse_pi_error) -{ - xml_document doc; - - unsigned int flag_sets[] = {parse_minimal, parse_minimal | parse_pi}; - - for (unsigned int i = 0; i < sizeof(flag_sets) / sizeof(flag_sets[0]); ++i) - { - unsigned int flags = flag_sets[i]; - - CHECK(doc.load(STR(""), flags).status == status_bad_pi); - CHECK(doc.load(STR(""), flags).status == status_bad_pi); - CHECK(doc.load(STR(""), flags).status == status_bad_pi); - CHECK(doc.load(STR(""), flags).status == status_bad_pi); - CHECK(doc.load(STR(" "), flags).status == status_bad_pi); - CHECK(doc.load(STR(""), parse_minimal | parse_pi).status == status_bad_pi); - CHECK(doc.load(STR(""), parse_minimal | parse_pi).status == status_bad_pi); - CHECK(doc.load(STR(""), parse_minimal | parse_pi).status == status_bad_pi); -} - -TEST(parse_comments_skip) -{ - xml_document doc; - CHECK(doc.load(STR(""), parse_minimal)); - CHECK(!doc.first_child()); -} - -TEST(parse_comments_parse) -{ - xml_document doc; - CHECK(doc.load(STR(""), parse_minimal | parse_comments)); - - xml_node c1 = doc.first_child(); - xml_node c2 = doc.last_child(); - - CHECK(c1 != c2); - CHECK(c1.type() == node_comment); - CHECK_STRING(c1.name(), STR("")); - CHECK_STRING(c1.value(), STR("")); - CHECK(c2.type() == node_comment); - CHECK_STRING(c2.name(), STR("")); - CHECK_STRING(c2.value(), STR("value")); -} - -TEST(parse_comments_parse_no_eol) -{ - xml_document doc; - CHECK(doc.load(STR(""), parse_minimal | parse_comments)); - - xml_node c = doc.first_child(); - CHECK(c.type() == node_comment); - CHECK_STRING(c.value(), STR("\r\rval1\rval2\r\nval3\nval4\r\r")); -} - -TEST(parse_comments_parse_eol) -{ - xml_document doc; - CHECK(doc.load(STR(""), parse_minimal | parse_comments | parse_eol)); - - xml_node c = doc.first_child(); - CHECK(c.type() == node_comment); - CHECK_STRING(c.value(), STR("\n\nval1\nval2\nval3\nval4\n\n")); -} - -TEST(parse_comments_error) -{ - xml_document doc; - - unsigned int flag_sets[] = {parse_minimal, parse_minimal | parse_comments, parse_minimal | parse_comments | parse_eol}; - - for (unsigned int i = 0; i < sizeof(flag_sets) / sizeof(flag_sets[0]); ++i) - { - unsigned int flags = flag_sets[i]; - - CHECK(doc.load(STR(""), flags).status == status_bad_comment); - CHECK(doc.load(STR(""), flags).status == status_bad_comment); - CHECK(doc.load(STR(""), flags).status == status_bad_comment); - } -} - -TEST(parse_cdata_skip) -{ - xml_document doc; - CHECK(doc.load(STR(""), parse_minimal)); - CHECK(!doc.first_child()); -} - -TEST(parse_cdata_parse) -{ - xml_document doc; - CHECK(doc.load(STR(""), parse_minimal | parse_cdata)); - - xml_node c1 = doc.first_child(); - xml_node c2 = doc.last_child(); - - CHECK(c1 != c2); - CHECK(c1.type() == node_cdata); - CHECK_STRING(c1.name(), STR("")); - CHECK_STRING(c1.value(), STR("")); - CHECK(c2.type() == node_cdata); - CHECK_STRING(c2.name(), STR("")); - CHECK_STRING(c2.value(), STR("value")); -} - -TEST(parse_cdata_parse_no_eol) -{ - xml_document doc; - CHECK(doc.load(STR(""), parse_minimal | parse_cdata)); - - xml_node c = doc.first_child(); - CHECK(c.type() == node_cdata); - CHECK_STRING(c.value(), STR("\r\rval1\rval2\r\nval3\nval4\r\r")); -} - -TEST(parse_cdata_parse_eol) -{ - xml_document doc; - CHECK(doc.load(STR(""), parse_minimal | parse_cdata | parse_eol)); - - xml_node c = doc.first_child(); - CHECK(c.type() == node_cdata); - CHECK_STRING(c.value(), STR("\n\nval1\nval2\nval3\nval4\n\n")); -} - -TEST(parse_cdata_error) -{ - xml_document doc; - - unsigned int flag_sets[] = {parse_minimal, parse_minimal | parse_cdata, parse_minimal | parse_cdata | parse_eol}; - - for (unsigned int i = 0; i < sizeof(flag_sets) / sizeof(flag_sets[0]); ++i) - { - unsigned int flags = flag_sets[i]; - - CHECK(doc.load(STR(""), flags).status == status_bad_cdata); - CHECK(doc.load(STR(""), flags).status == status_bad_cdata); - } -} - -TEST(parse_ws_pcdata_skip) -{ - xml_document doc; - CHECK(doc.load(STR(" "), parse_minimal)); - CHECK(!doc.first_child()); - - CHECK(doc.load(STR(" "), parse_minimal)); - - xml_node root = doc.child(STR("root")); - - CHECK(root.first_child() == root.last_child()); - CHECK(!root.first_child().first_child()); -} - -TEST(parse_ws_pcdata_parse) -{ - xml_document doc; - CHECK(doc.load(STR(" "), parse_minimal | parse_ws_pcdata)); - - xml_node root = doc.child(STR("root")); - - xml_node c1 = root.first_child(); - xml_node c2 = c1.next_sibling(); - xml_node c3 = c2.next_sibling(); - - CHECK(c3 == root.last_child()); - - CHECK(c1.type() == node_pcdata); - CHECK_STRING(c1.value(), STR(" ")); - CHECK(c3.type() == node_pcdata); - CHECK_STRING(c3.value(), STR(" ")); - - CHECK(c2.first_child() == c2.last_child()); - CHECK(c2.first_child().type() == node_pcdata); - CHECK_STRING(c2.first_child().value(), STR(" ")); -} - -TEST(parse_pcdata_no_eol) -{ - xml_document doc; - CHECK(doc.load(STR("\r\rval1\rval2\r\nval3\nval4\r\r"), parse_minimal)); - - CHECK_STRING(doc.child_value(STR("root")), STR("\r\rval1\rval2\r\nval3\nval4\r\r")); -} - -TEST(parse_pcdata_eol) -{ - xml_document doc; - CHECK(doc.load(STR("\r\rval1\rval2\r\nval3\nval4\r\r"), parse_minimal | parse_eol)); - - CHECK_STRING(doc.child_value(STR("root")), STR("\n\nval1\nval2\nval3\nval4\n\n")); -} - -TEST(parse_pcdata_skip_ext) -{ - xml_document doc; - CHECK(doc.load(STR("prepost"), parse_minimal)); - CHECK(doc.first_child() == doc.last_child()); - CHECK(doc.first_child().type() == node_element); -} - -TEST(parse_pcdata_error) -{ - xml_document doc; - CHECK(doc.load(STR("pcdata"), parse_minimal).status == status_end_element_mismatch); -} - -TEST(parse_escapes_skip) -{ - xml_document doc; - CHECK(doc.load(STR("<>&'""), parse_minimal)); - CHECK_STRING(doc.child(STR("node")).attribute(STR("id")).value(), STR("<>&'"")); -} - -TEST(parse_escapes_parse) -{ - xml_document doc; - CHECK(doc.load(STR("<>&'""), parse_minimal | parse_escapes)); - CHECK_STRING(doc.child_value(STR("node")), STR("<>&'\"")); - CHECK_STRING(doc.child(STR("node")).attribute(STR("id")).value(), STR("<>&'\"")); -} - -TEST(parse_escapes_code) -{ - xml_document doc; - CHECK(doc.load(STR(" "), parse_minimal | parse_escapes)); - CHECK_STRING(doc.child_value(STR("node")), STR("\01 ")); -} - -TEST(parse_escapes_code_exhaustive_dec) -{ - xml_document doc; - CHECK(doc.load(STR("&#/; &#:;&#a;&#A; "), parse_minimal | parse_escapes)); - CHECK_STRING(doc.child_value(STR("node")), STR("&#/;\x1\x2\x3\x4\x5\x6\x7\x8\x9&#:;&#a;&#A; ")); -} - -TEST(parse_escapes_code_exhaustive_hex) -{ - xml_document doc; - CHECK(doc.load(STR("&#x/; &#x:;&#x@; &#xG;&#x`; &#xg;"), parse_minimal | parse_escapes)); - CHECK_STRING(doc.child_value(STR("node")), STR("&#x/;\x1\x2\x3\x4\x5\x6\x7\x8\x9&#x:;&#x@;\xa\xb\xc\xd\xe\xf&#xG;&#x`;\xa\xb\xc\xd\xe\xf&#xg;")); -} - -TEST(parse_escapes_code_restore) -{ - xml_document doc; - CHECK(doc.load(STR("  - - "), parse_minimal | parse_escapes)); - CHECK_STRING(doc.child_value(STR("node")), STR("  - - ")); -} - -TEST(parse_escapes_char_restore) -{ - xml_document doc; - - CHECK(doc.load(STR("&q &qu &quo " "), parse_minimal | parse_escapes)); - CHECK_STRING(doc.child_value(STR("node")), STR("&q &qu &quo " ")); - - CHECK(doc.load(STR("&a &ap &apo &apos "), parse_minimal | parse_escapes)); - CHECK_STRING(doc.child_value(STR("node")), STR("&a &ap &apo &apos ")); - - CHECK(doc.load(STR("&a &am & "), parse_minimal | parse_escapes)); - CHECK_STRING(doc.child_value(STR("node")), STR("&a &am & ")); - - CHECK(doc.load(STR("&l < "), parse_minimal | parse_escapes)); - CHECK_STRING(doc.child_value(STR("node")), STR("&l < ")); - - CHECK(doc.load(STR("&g > "), parse_minimal | parse_escapes)); - CHECK_STRING(doc.child_value(STR("node")), STR("&g > ")); -} - -TEST(parse_escapes_unicode) -{ - xml_document doc; - CHECK(doc.load(STR("γγ𤭢"), parse_minimal | parse_escapes)); - -#ifdef PUGIXML_WCHAR_MODE - const pugi::char_t* v = doc.child_value(STR("node")); - - unsigned int v2 = v[2]; - size_t wcharsize = sizeof(wchar_t); - - CHECK(v[0] == 0x3b3 && v[1] == 0x3b3 && (wcharsize == 2 ? v[2] == 0xd852 && v[3] == 0xdf62 : v2 == 0x24b62)); -#else - CHECK_STRING(doc.child_value(STR("node")), "\xce\xb3\xce\xb3\xf0\xa4\xad\xa2"); -#endif -} - -TEST(parse_escapes_error) -{ - xml_document doc; - CHECK(doc.load(STR("g;&#ab;""), parse_minimal | parse_escapes)); - CHECK_STRING(doc.child_value(STR("node")), STR("g;&#ab;"")); - - CHECK(!doc.load(STR("&#;&#x;&;&#x-;&#-;"), parse_minimal | parse_escapes)); - CHECK_STRING(doc.child_value(STR("node")), STR("&#;&#x;&;&#x-;&#-;")); -} - -TEST(parse_attribute_spaces) -{ - xml_document doc; - CHECK(doc.load(STR(""), parse_minimal)); - CHECK_STRING(doc.child(STR("node")).attribute(STR("id1")).value(), STR("v1")); - CHECK_STRING(doc.child(STR("node")).attribute(STR("id2")).value(), STR("v2")); - CHECK_STRING(doc.child(STR("node")).attribute(STR("id3")).value(), STR("v3")); - CHECK_STRING(doc.child(STR("node")).attribute(STR("id4")).value(), STR("v4")); - CHECK_STRING(doc.child(STR("node")).attribute(STR("id5")).value(), STR("v5")); -} - -TEST(parse_attribute_quot) -{ - xml_document doc; - CHECK(doc.load(STR(""), parse_minimal)); - CHECK_STRING(doc.child(STR("node")).attribute(STR("id1")).value(), STR("v1")); - CHECK_STRING(doc.child(STR("node")).attribute(STR("id2")).value(), STR("v2")); -} - -TEST(parse_attribute_no_eol_no_wconv) -{ - xml_document doc; - CHECK(doc.load(STR(""), parse_minimal)); - CHECK_STRING(doc.child(STR("node")).attribute(STR("id")).value(), STR(" \t\r\rval1 \rval2\r\nval3\nval4\r\r")); -} - -TEST(parse_attribute_eol_no_wconv) -{ - xml_document doc; - CHECK(doc.load(STR(""), parse_minimal | parse_eol)); - CHECK_STRING(doc.child(STR("node")).attribute(STR("id")).value(), STR(" \t\n\nval1 \nval2\nval3\nval4\n\n")); -} - -TEST(parse_attribute_no_eol_wconv) -{ - xml_document doc; - CHECK(doc.load(STR(""), parse_minimal | parse_wconv_attribute)); - CHECK_STRING(doc.child(STR("node")).attribute(STR("id")).value(), STR(" val1 val2 val3 val4 ")); -} - -TEST(parse_attribute_eol_wconv) -{ - xml_document doc; - CHECK(doc.load(STR(""), parse_minimal | parse_eol | parse_wconv_attribute)); - CHECK_STRING(doc.child(STR("node")).attribute(STR("id")).value(), STR(" val1 val2 val3 val4 ")); -} - -TEST(parse_attribute_wnorm) -{ - xml_document doc; - - for (int eol = 0; eol < 2; ++eol) - for (int wconv = 0; wconv < 2; ++wconv) - { - unsigned int flags = parse_minimal | parse_wnorm_attribute | (eol ? parse_eol : 0) | (wconv ? parse_wconv_attribute : 0); - CHECK(doc.load(STR(""), flags)); - CHECK_STRING(doc.child(STR("node")).attribute(STR("id")).value(), STR("val1 val2 val3 val4")); - } -} - -TEST(parse_attribute_variations) -{ - xml_document doc; - - for (int wnorm = 0; wnorm < 2; ++wnorm) - for (int eol = 0; eol < 2; ++eol) - for (int wconv = 0; wconv < 2; ++wconv) - for (int escapes = 0; escapes < 2; ++escapes) - { - unsigned int flags = parse_minimal; - - flags |= (wnorm ? parse_wnorm_attribute : 0); - flags |= (eol ? parse_eol : 0); - flags |= (wconv ? parse_wconv_attribute : 0); - flags |= (escapes ? parse_escapes : 0); - - CHECK(doc.load(STR(""), flags)); - CHECK_STRING(doc.child(STR("node")).attribute(STR("id")).value(), STR("1")); - } -} - - -TEST(parse_attribute_error) -{ - xml_document doc; - CHECK(doc.load(STR(""), parse_minimal).status == status_bad_attribute); - CHECK(doc.load(STR(""), parse_minimal).status == status_bad_attribute); - CHECK(doc.load(STR(""), parse_minimal).status == status_bad_attribute); - CHECK(doc.load(STR(""), parse_minimal).status == status_bad_attribute); - CHECK(doc.load(STR(""), parse_minimal).status == status_bad_attribute); - CHECK(doc.load(STR(""), parse_minimal).status == status_bad_start_element); - CHECK(doc.load(STR(""), parse_minimal).status == status_bad_start_element); - CHECK(doc.load(STR(""), parse_minimal).status == status_bad_attribute); - CHECK(doc.load(STR(""), parse_minimal).status == status_bad_attribute); - CHECK(doc.load(STR(""), parse_minimal).status == status_bad_start_element); -} - -TEST(parse_tag_single) -{ - xml_document doc; - CHECK(doc.load(STR(""), parse_minimal)); - CHECK_NODE(doc, STR("")); -} - -TEST(parse_tag_hierarchy) -{ - xml_document doc; - CHECK(doc.load(STR(""), parse_minimal)); - CHECK_NODE(doc, STR("")); -} - -TEST(parse_tag_error) -{ - xml_document doc; - CHECK(doc.load(STR("<"), parse_minimal).status == status_unrecognized_tag); - CHECK(doc.load(STR(""), parse_minimal).status == status_bad_start_element); - CHECK(doc.load(STR(""), parse_minimal).status == status_bad_start_element); - CHECK(doc.load(STR(""), parse_minimal).status == status_end_element_mismatch); - CHECK(doc.load(STR(""), parse_minimal).status == status_end_element_mismatch); - CHECK(doc.load(STR(""), parse_minimal).status == status_end_element_mismatch); - CHECK(doc.load(STR(""), parse_minimal).status == status_end_element_mismatch); - CHECK(doc.load(STR("<"), parse_minimal).status == status_unrecognized_tag); - CHECK(doc.load(STR(""), parse_minimal).status == status_end_element_mismatch); - CHECK(doc.load(STR(""), parse_minimal).status == status_end_element_mismatch); - CHECK(doc.load(STR(""), parse_minimal).status == status_end_element_mismatch); - CHECK(doc.load(STR(""), parse_minimal).status == status_end_element_mismatch); - CHECK(doc.load(STR(""), parse_minimal).status == status_bad_end_element); - CHECK(doc.load(STR(""), parse_minimal).status == status_bad_start_element); - CHECK(doc.load(STR(""), parse_minimal).status == status_bad_start_element); -} - -TEST(parse_declaration_cases) -{ - xml_document doc; - CHECK(doc.load(STR(""), parse_minimal | parse_pi)); - CHECK(!doc.first_child()); -} - -TEST(parse_declaration_attr_cases) -{ - xml_document doc; - CHECK(doc.load(STR(""), parse_minimal | parse_pi)); - CHECK(!doc.first_child()); -} - -TEST(parse_declaration_skip) -{ - xml_document doc; - - unsigned int flag_sets[] = {parse_minimal, parse_minimal | parse_pi}; - - for (unsigned int i = 0; i < sizeof(flag_sets) / sizeof(flag_sets[0]); ++i) - { - unsigned int flags = flag_sets[i]; - - CHECK(doc.load(STR(""), flags)); - CHECK(!doc.first_child()); - - CHECK(doc.load(STR(" ?>"), flags)); - CHECK(!doc.first_child()); - } -} - -TEST(parse_declaration_parse) -{ - xml_document doc; - CHECK(doc.load(STR(""), parse_minimal | parse_declaration)); - - xml_node d1 = doc.first_child(); - xml_node d2 = doc.last_child(); - - CHECK(d1 != d2); - CHECK(d1.type() == node_declaration); - CHECK_STRING(d1.name(), STR("xml")); - CHECK(d2.type() == node_declaration); - CHECK_STRING(d2.name(), STR("xml")); - CHECK_STRING(d2.attribute(STR("version")).value(), STR("1.0")); -} - -TEST(parse_declaration_error) -{ - xml_document doc; - - unsigned int flag_sets[] = {parse_minimal, parse_minimal | parse_declaration}; - - for (unsigned int i = 0; i < sizeof(flag_sets) / sizeof(flag_sets[0]); ++i) - { - unsigned int flags = flag_sets[i]; - - CHECK(doc.load(STR(""), flags).status == status_bad_pi); - CHECK(doc.load(STR(""), flags).status == status_bad_pi); - } - - CHECK(doc.load(STR(""), parse_minimal | parse_declaration).status == status_bad_attribute); - CHECK(doc.load(STR(""), parse_minimal | parse_declaration).status == status_bad_pi); -} - -TEST(parse_empty) -{ - xml_document doc; - CHECK(doc.load(STR("")) && !doc.first_child()); -} - -TEST(parse_out_of_memory) -{ - test_runner::_memory_fail_threshold = 256; - - xml_document doc; - CHECK(doc.load(STR("")).status == status_out_of_memory); - CHECK(!doc.first_child()); -} - -TEST(parse_out_of_memory_halfway) -{ - unsigned int count = 10000; - char_t* text = new char_t[count * 4]; - - for (unsigned int i = 0; i < count; ++i) - { - text[4*i + 0] = '<'; - text[4*i + 1] = 'n'; - text[4*i + 2] = '/'; - text[4*i + 3] = '>'; - } - - test_runner::_memory_fail_threshold = 65536; - - xml_document doc; - CHECK(doc.load_buffer_inplace(text, count * 4).status == status_out_of_memory); - CHECK_NODE(doc.first_child(), STR("")); - - delete[] text; -} - -static bool test_offset(const char_t* contents, unsigned int options, pugi::xml_parse_status status, ptrdiff_t offset) -{ - xml_document doc; - xml_parse_result res = doc.load(contents, options); - - return res.status == status && res.offset == offset; -} - -#define CHECK_OFFSET(contents, options, status, offset) CHECK(test_offset(STR(contents), options, status, offset)) - -TEST(parse_error_offset) -{ - CHECK_OFFSET("", parse_default, status_ok, 0); - - test_runner::_memory_fail_threshold = 1; - CHECK_OFFSET("", parse_default, status_out_of_memory, 0); - test_runner::_memory_fail_threshold = 0; - - CHECK_OFFSET("<3d/>", parse_default, status_unrecognized_tag, 1); - CHECK_OFFSET(" <3d/>", parse_default, status_unrecognized_tag, 2); - CHECK_OFFSET(" <", parse_default, status_unrecognized_tag, 2); - - CHECK_OFFSET("", parse_default, status_bad_start_element, 5); - - CHECK_OFFSET("", parse_default, status_bad_attribute, 8); - CHECK_OFFSET("<>&'""), parse_minimal)); + CHECK_STRING(doc.child(STR("node")).attribute(STR("id")).value(), STR("<>&'"")); +} + +TEST(parse_escapes_parse) +{ + xml_document doc; + CHECK(doc.load(STR("<>&'""), parse_minimal | parse_escapes)); + CHECK_STRING(doc.child_value(STR("node")), STR("<>&'\"")); + CHECK_STRING(doc.child(STR("node")).attribute(STR("id")).value(), STR("<>&'\"")); +} + +TEST(parse_escapes_code) +{ + xml_document doc; + CHECK(doc.load(STR(" "), parse_minimal | parse_escapes)); + CHECK_STRING(doc.child_value(STR("node")), STR("\01 ")); +} + +TEST(parse_escapes_code_exhaustive_dec) +{ + xml_document doc; + CHECK(doc.load(STR("&#/; &#:;&#a;&#A; "), parse_minimal | parse_escapes)); + CHECK_STRING(doc.child_value(STR("node")), STR("&#/;\x1\x2\x3\x4\x5\x6\x7\x8\x9&#:;&#a;&#A; ")); +} + +TEST(parse_escapes_code_exhaustive_hex) +{ + xml_document doc; + CHECK(doc.load(STR("&#x/; &#x:;&#x@; &#xG;&#x`; &#xg;"), parse_minimal | parse_escapes)); + CHECK_STRING(doc.child_value(STR("node")), STR("&#x/;\x1\x2\x3\x4\x5\x6\x7\x8\x9&#x:;&#x@;\xa\xb\xc\xd\xe\xf&#xG;&#x`;\xa\xb\xc\xd\xe\xf&#xg;")); +} + +TEST(parse_escapes_code_restore) +{ + xml_document doc; + CHECK(doc.load(STR("  - - "), parse_minimal | parse_escapes)); + CHECK_STRING(doc.child_value(STR("node")), STR("  - - ")); +} + +TEST(parse_escapes_char_restore) +{ + xml_document doc; + + CHECK(doc.load(STR("&q &qu &quo " "), parse_minimal | parse_escapes)); + CHECK_STRING(doc.child_value(STR("node")), STR("&q &qu &quo " ")); + + CHECK(doc.load(STR("&a &ap &apo &apos "), parse_minimal | parse_escapes)); + CHECK_STRING(doc.child_value(STR("node")), STR("&a &ap &apo &apos ")); + + CHECK(doc.load(STR("&a &am & "), parse_minimal | parse_escapes)); + CHECK_STRING(doc.child_value(STR("node")), STR("&a &am & ")); + + CHECK(doc.load(STR("&l < "), parse_minimal | parse_escapes)); + CHECK_STRING(doc.child_value(STR("node")), STR("&l < ")); + + CHECK(doc.load(STR("&g > "), parse_minimal | parse_escapes)); + CHECK_STRING(doc.child_value(STR("node")), STR("&g > ")); +} + +TEST(parse_escapes_unicode) +{ + xml_document doc; + CHECK(doc.load(STR("γγ𤭢"), parse_minimal | parse_escapes)); + +#ifdef PUGIXML_WCHAR_MODE + const pugi::char_t* v = doc.child_value(STR("node")); + + unsigned int v2 = v[2]; + size_t wcharsize = sizeof(wchar_t); + + CHECK(v[0] == 0x3b3 && v[1] == 0x3b3 && (wcharsize == 2 ? v[2] == 0xd852 && v[3] == 0xdf62 : v2 == 0x24b62)); +#else + CHECK_STRING(doc.child_value(STR("node")), "\xce\xb3\xce\xb3\xf0\xa4\xad\xa2"); +#endif +} + +TEST(parse_escapes_error) +{ + xml_document doc; + CHECK(doc.load(STR("g;&#ab;""), parse_minimal | parse_escapes)); + CHECK_STRING(doc.child_value(STR("node")), STR("g;&#ab;"")); + + CHECK(!doc.load(STR("&#;&#x;&;&#x-;&#-;"), parse_minimal | parse_escapes)); + CHECK_STRING(doc.child_value(STR("node")), STR("&#;&#x;&;&#x-;&#-;")); +} + +TEST(parse_attribute_spaces) +{ + xml_document doc; + CHECK(doc.load(STR(""), parse_minimal)); + CHECK_STRING(doc.child(STR("node")).attribute(STR("id1")).value(), STR("v1")); + CHECK_STRING(doc.child(STR("node")).attribute(STR("id2")).value(), STR("v2")); + CHECK_STRING(doc.child(STR("node")).attribute(STR("id3")).value(), STR("v3")); + CHECK_STRING(doc.child(STR("node")).attribute(STR("id4")).value(), STR("v4")); + CHECK_STRING(doc.child(STR("node")).attribute(STR("id5")).value(), STR("v5")); +} + +TEST(parse_attribute_quot) +{ + xml_document doc; + CHECK(doc.load(STR(""), parse_minimal)); + CHECK_STRING(doc.child(STR("node")).attribute(STR("id1")).value(), STR("v1")); + CHECK_STRING(doc.child(STR("node")).attribute(STR("id2")).value(), STR("v2")); +} + +TEST(parse_attribute_no_eol_no_wconv) +{ + xml_document doc; + CHECK(doc.load(STR(""), parse_minimal)); + CHECK_STRING(doc.child(STR("node")).attribute(STR("id")).value(), STR(" \t\r\rval1 \rval2\r\nval3\nval4\r\r")); +} + +TEST(parse_attribute_eol_no_wconv) +{ + xml_document doc; + CHECK(doc.load(STR(""), parse_minimal | parse_eol)); + CHECK_STRING(doc.child(STR("node")).attribute(STR("id")).value(), STR(" \t\n\nval1 \nval2\nval3\nval4\n\n")); +} + +TEST(parse_attribute_no_eol_wconv) +{ + xml_document doc; + CHECK(doc.load(STR(""), parse_minimal | parse_wconv_attribute)); + CHECK_STRING(doc.child(STR("node")).attribute(STR("id")).value(), STR(" val1 val2 val3 val4 ")); +} + +TEST(parse_attribute_eol_wconv) +{ + xml_document doc; + CHECK(doc.load(STR(""), parse_minimal | parse_eol | parse_wconv_attribute)); + CHECK_STRING(doc.child(STR("node")).attribute(STR("id")).value(), STR(" val1 val2 val3 val4 ")); +} + +TEST(parse_attribute_wnorm) +{ + xml_document doc; + + for (int eol = 0; eol < 2; ++eol) + for (int wconv = 0; wconv < 2; ++wconv) + { + unsigned int flags = parse_minimal | parse_wnorm_attribute | (eol ? parse_eol : 0) | (wconv ? parse_wconv_attribute : 0); + CHECK(doc.load(STR(""), flags)); + CHECK_STRING(doc.child(STR("node")).attribute(STR("id")).value(), STR("val1 val2 val3 val4")); + } +} + +TEST(parse_attribute_variations) +{ + xml_document doc; + + for (int wnorm = 0; wnorm < 2; ++wnorm) + for (int eol = 0; eol < 2; ++eol) + for (int wconv = 0; wconv < 2; ++wconv) + for (int escapes = 0; escapes < 2; ++escapes) + { + unsigned int flags = parse_minimal; + + flags |= (wnorm ? parse_wnorm_attribute : 0); + flags |= (eol ? parse_eol : 0); + flags |= (wconv ? parse_wconv_attribute : 0); + flags |= (escapes ? parse_escapes : 0); + + CHECK(doc.load(STR(""), flags)); + CHECK_STRING(doc.child(STR("node")).attribute(STR("id")).value(), STR("1")); + } +} + + +TEST(parse_attribute_error) +{ + xml_document doc; + CHECK(doc.load(STR(""), parse_minimal).status == status_bad_attribute); + CHECK(doc.load(STR(""), parse_minimal).status == status_bad_attribute); + CHECK(doc.load(STR(""), parse_minimal).status == status_bad_attribute); + CHECK(doc.load(STR(""), parse_minimal).status == status_bad_attribute); + CHECK(doc.load(STR(""), parse_minimal).status == status_bad_attribute); + CHECK(doc.load(STR(""), parse_minimal).status == status_bad_start_element); + CHECK(doc.load(STR(""), parse_minimal).status == status_bad_start_element); + CHECK(doc.load(STR(""), parse_minimal).status == status_bad_attribute); + CHECK(doc.load(STR(""), parse_minimal).status == status_bad_attribute); + CHECK(doc.load(STR(""), parse_minimal).status == status_bad_start_element); +} + +TEST(parse_tag_single) +{ + xml_document doc; + CHECK(doc.load(STR(""), parse_minimal)); + CHECK_NODE(doc, STR("")); +} + +TEST(parse_tag_hierarchy) +{ + xml_document doc; + CHECK(doc.load(STR(""), parse_minimal)); + CHECK_NODE(doc, STR("")); +} + +TEST(parse_tag_error) +{ + xml_document doc; + CHECK(doc.load(STR("<"), parse_minimal).status == status_unrecognized_tag); + CHECK(doc.load(STR(""), parse_minimal).status == status_bad_start_element); + CHECK(doc.load(STR(""), parse_minimal).status == status_bad_start_element); + CHECK(doc.load(STR(""), parse_minimal).status == status_end_element_mismatch); + CHECK(doc.load(STR(""), parse_minimal).status == status_end_element_mismatch); + CHECK(doc.load(STR(""), parse_minimal).status == status_end_element_mismatch); + CHECK(doc.load(STR(""), parse_minimal).status == status_end_element_mismatch); + CHECK(doc.load(STR("<"), parse_minimal).status == status_unrecognized_tag); + CHECK(doc.load(STR(""), parse_minimal).status == status_end_element_mismatch); + CHECK(doc.load(STR(""), parse_minimal).status == status_end_element_mismatch); + CHECK(doc.load(STR(""), parse_minimal).status == status_end_element_mismatch); + CHECK(doc.load(STR(""), parse_minimal).status == status_end_element_mismatch); + CHECK(doc.load(STR(""), parse_minimal).status == status_bad_end_element); + CHECK(doc.load(STR(""), parse_minimal).status == status_bad_start_element); + CHECK(doc.load(STR(""), parse_minimal).status == status_bad_start_element); +} + +TEST(parse_declaration_cases) +{ + xml_document doc; + CHECK(doc.load(STR(""), parse_minimal | parse_pi)); + CHECK(!doc.first_child()); +} + +TEST(parse_declaration_attr_cases) +{ + xml_document doc; + CHECK(doc.load(STR(""), parse_minimal | parse_pi)); + CHECK(!doc.first_child()); +} + +TEST(parse_declaration_skip) +{ + xml_document doc; + + unsigned int flag_sets[] = {parse_minimal, parse_minimal | parse_pi}; + + for (unsigned int i = 0; i < sizeof(flag_sets) / sizeof(flag_sets[0]); ++i) + { + unsigned int flags = flag_sets[i]; + + CHECK(doc.load(STR(""), flags)); + CHECK(!doc.first_child()); + + CHECK(doc.load(STR(" ?>"), flags)); + CHECK(!doc.first_child()); + } +} + +TEST(parse_declaration_parse) +{ + xml_document doc; + CHECK(doc.load(STR(""), parse_minimal | parse_declaration)); + + xml_node d1 = doc.first_child(); + xml_node d2 = doc.last_child(); + + CHECK(d1 != d2); + CHECK(d1.type() == node_declaration); + CHECK_STRING(d1.name(), STR("xml")); + CHECK(d2.type() == node_declaration); + CHECK_STRING(d2.name(), STR("xml")); + CHECK_STRING(d2.attribute(STR("version")).value(), STR("1.0")); +} + +TEST(parse_declaration_error) +{ + xml_document doc; + + unsigned int flag_sets[] = {parse_minimal, parse_minimal | parse_declaration}; + + for (unsigned int i = 0; i < sizeof(flag_sets) / sizeof(flag_sets[0]); ++i) + { + unsigned int flags = flag_sets[i]; + + CHECK(doc.load(STR(""), flags).status == status_bad_pi); + CHECK(doc.load(STR(""), flags).status == status_bad_pi); + } + + CHECK(doc.load(STR(""), parse_minimal | parse_declaration).status == status_bad_attribute); + CHECK(doc.load(STR(""), parse_minimal | parse_declaration).status == status_bad_pi); +} + +TEST(parse_empty) +{ + xml_document doc; + CHECK(doc.load(STR("")) && !doc.first_child()); +} + +TEST(parse_out_of_memory) +{ + test_runner::_memory_fail_threshold = 256; + + xml_document doc; + CHECK(doc.load(STR("")).status == status_out_of_memory); + CHECK(!doc.first_child()); +} + +TEST(parse_out_of_memory_halfway) +{ + unsigned int count = 10000; + char_t* text = new char_t[count * 4]; + + for (unsigned int i = 0; i < count; ++i) + { + text[4*i + 0] = '<'; + text[4*i + 1] = 'n'; + text[4*i + 2] = '/'; + text[4*i + 3] = '>'; + } + + test_runner::_memory_fail_threshold = 65536; + + xml_document doc; + CHECK(doc.load_buffer_inplace(text, count * 4).status == status_out_of_memory); + CHECK_NODE(doc.first_child(), STR("")); + + delete[] text; +} + +static bool test_offset(const char_t* contents, unsigned int options, pugi::xml_parse_status status, ptrdiff_t offset) +{ + xml_document doc; + xml_parse_result res = doc.load(contents, options); + + return res.status == status && res.offset == offset; +} + +#define CHECK_OFFSET(contents, options, status, offset) CHECK(test_offset(STR(contents), options, status, offset)) + +TEST(parse_error_offset) +{ + CHECK_OFFSET("", parse_default, status_ok, 0); + + test_runner::_memory_fail_threshold = 1; + CHECK_OFFSET("", parse_default, status_out_of_memory, 0); + test_runner::_memory_fail_threshold = 0; + + CHECK_OFFSET("<3d/>", parse_default, status_unrecognized_tag, 1); + CHECK_OFFSET(" <3d/>", parse_default, status_unrecognized_tag, 2); + CHECK_OFFSET(" <", parse_default, status_unrecognized_tag, 2); + + CHECK_OFFSET("", parse_default, status_bad_start_element, 5); + + CHECK_OFFSET("", parse_default, status_bad_attribute, 8); + CHECK_OFFSET(""); - TEST_DOCTYPE_WF(""); - TEST_DOCTYPE_WF(""); - TEST_DOCTYPE_WF(""); - TEST_DOCTYPE_WF("]>"); -} - -TEST(parse_doctype_error) -{ - TEST_DOCTYPE_NWF(""); - TEST_DOCTYPE_NWF("]"); - TEST_DOCTYPE_NWF("] "); -} - -// Examples from W3C recommendations -TEST(parse_doctype_w3c_wf) -{ - TEST_DOCTYPE_WF(""); - TEST_DOCTYPE_WF(" ]>"); - TEST_DOCTYPE_WF(" ]>"); - TEST_DOCTYPE_WF(" ]]> ]]>]>"); - TEST_DOCTYPE_WF(" ]>"); - TEST_DOCTYPE_WF(" ]>"); -} - -TEST(parse_doctype_w3c_nwf) -{ - TEST_DOCTYPE_NWF(""); - TEST_DOCTYPE_NWF(" ]"); - TEST_DOCTYPE_NWF(""); - TEST_DOCTYPE_NWF(" ]"); - TEST_DOCTYPE_NWF(""); - TEST_DOCTYPE_NWF(" ]>"); - TEST_DOCTYPE_WF(" ]>"); - TEST_DOCTYPE_WF(" %e; ]>"); - TEST_DOCTYPE_WF(" ]>"); - TEST_DOCTYPE_WF(" ]>"); - TEST_DOCTYPE_WF(" ]>"); - TEST_DOCTYPE_WF(" ]>"); - TEST_DOCTYPE_WF(" ]>"); - TEST_DOCTYPE_WF(""); - TEST_DOCTYPE_WF(" ]>"); - TEST_DOCTYPE_WF(" ]>"); - TEST_DOCTYPE_WF(" ]>"); - TEST_DOCTYPE_WF(" ]>"); - TEST_DOCTYPE_WF(" \"> ]>"); - TEST_DOCTYPE_WF(" ]>"); - TEST_DOCTYPE_WF(" ]>"); - TEST_DOCTYPE_WF(" %pe; %intpe; ]>"); - TEST_DOCTYPE_WF(" ]>"); - TEST_DOCTYPE_WF(" ]>"); - TEST_DOCTYPE_WF(" ]>"); - TEST_DOCTYPE_WF(" ]>"); - TEST_DOCTYPE_WF(" ]>"); - TEST_DOCTYPE_WF(" ]>"); - TEST_DOCTYPE_WF(" ]>"); - TEST_DOCTYPE_WF("]]> ]>"); - TEST_DOCTYPE_WF(" ]>"); - TEST_DOCTYPE_NWF(" \"> \"> "); - TEST_DOCTYPE_WF(" ]>"); -} - -TEST(parse_doctype_xmlconf_eduni_2) -{ - TEST_DOCTYPE_WF("\"> %pe; ]>"); - TEST_DOCTYPE_WF(" ]>"); - TEST_DOCTYPE_WF(" ]>"); - TEST_DOCTYPE_WF(" ]>"); - TEST_DOCTYPE_WF(" ]>"); - TEST_DOCTYPE_WF(" ]>"); -} - -TEST(parse_doctype_xmlconf_eduni_3) -{ - TEST_DOCTYPE_WF(" ]>"); - TEST_DOCTYPE_WF(" ]>"); - TEST_DOCTYPE_WF("\"> ]>"); -} - -TEST(parse_doctype_xmlconf_eduni_4) -{ - TEST_DOCTYPE_WF(" ]>"); - TEST_DOCTYPE_WF(" ]>"); - TEST_DOCTYPE_WF(" ]>"); - TEST_DOCTYPE_WF(" ]>"); -} - -TEST(parse_doctype_xmlconf_eduni_5) -{ - TEST_DOCTYPE_WF(" ]>"); - TEST_DOCTYPE_WF(" ]>"); - TEST_DOCTYPE_WF(" ]>"); -} - -TEST(parse_doctype_xmlconf_ibm_1) -{ - TEST_DOCTYPE_WF(" ]>"); - TEST_DOCTYPE_WF(" ]>"); - TEST_DOCTYPE_WF(" ]>"); - TEST_DOCTYPE_WF(" ]>"); - TEST_DOCTYPE_WF(" ]>"); - TEST_DOCTYPE_WF(" ]>"); - TEST_DOCTYPE_WF(" ]>"); - TEST_DOCTYPE_WF(" ]>"); - TEST_DOCTYPE_WF(" %pe1; ]>"); - TEST_DOCTYPE_WF(" ]>"); - TEST_DOCTYPE_WF(" \"> %pe3; ]>"); - TEST_DOCTYPE_WF(" '> %pe1; ]>"); -} - -TEST(parse_doctype_xmlconf_ibm_2) -{ - TEST_DOCTYPE_WF(" \"> ]>"); - TEST_DOCTYPE_WF(" ]>"); - TEST_DOCTYPE_WF(" ]>"); - TEST_DOCTYPE_WF(" ]>"); - TEST_DOCTYPE_WF(" ]>"); - TEST_DOCTYPE_NWF(" ]>"); - TEST_DOCTYPE_WF(" ]>"); - TEST_DOCTYPE_NWF(" ]>"); - TEST_DOCTYPE_NWF(" ]>"); - TEST_DOCTYPE_NWF(" ]>"); - TEST_DOCTYPE_NWF(" ]>"); - TEST_DOCTYPE_WF(" ]>"); - TEST_DOCTYPE_WF(" &generalE; \"> %parameterE; ] animal>"); - TEST_DOCTYPE_WF(" ]>"); - TEST_DOCTYPE_WF(" ]>"); - TEST_DOCTYPE_NWF(" \"> ]>"); - TEST_DOCTYPE_WF(" ]>"); - TEST_DOCTYPE_WF(" ]>"); - TEST_DOCTYPE_WF(" ]>"); - TEST_DOCTYPE_WF(" ]]> ]>"); - TEST_DOCTYPE_WF(" ]]> ]>"); - TEST_DOCTYPE_NWF(" ]]> ]>"); - TEST_DOCTYPE_WF(" ]]> ]>"); - TEST_DOCTYPE_WF(" ]]> ]>"); - TEST_DOCTYPE_WF(" [INCLUDE ]]> ]>"); - TEST_DOCTYPE_NWF(" ]>"); - TEST_DOCTYPE_NWF(" ]>"); - TEST_DOCTYPE_WF(" %paaa; \"> ]>"); - TEST_DOCTYPE_WF(" \"> %paaa; ]>"); - TEST_DOCTYPE_NWF(" \" %paaa; ]>"); - TEST_DOCTYPE_WF(" ]>"); -} - -TEST(parse_doctype_xmlconf_ibm_3) -{ - TEST_DOCTYPE_WF(" ]>"); - TEST_DOCTYPE_WF(" ]>"); - TEST_DOCTYPE_WF(" ]>"); - TEST_DOCTYPE_WF(""); - TEST_DOCTYPE_WF(" ]>"); - TEST_DOCTYPE_WF(""); - TEST_DOCTYPE_WF(""); - TEST_DOCTYPE_WF(""); - TEST_DOCTYPE_WF(""); - TEST_DOCTYPE_WF(""); - TEST_DOCTYPE_WF(" ]>"); - TEST_DOCTYPE_NWF(" ]>"); - TEST_DOCTYPE_WF(" ]>"); - TEST_DOCTYPE_NWF(" ]>"); - TEST_DOCTYPE_WF(" IN PI ?> ]>"); - TEST_DOCTYPE_WF(" \"> \"> \"> %make_leopard_element; %make_small; \"> %make_big; %make_attlist; ]>"); - TEST_DOCTYPE_WF("\"> ]]> %rootElement; \"> %make_tiger_element; ]]> ]>"); - TEST_DOCTYPE_WF(" General entity reference in element content\"> ]>"); - TEST_DOCTYPE_WF(" ]>"); - TEST_DOCTYPE_WF("'. These must be balanced ]>"); - TEST_DOCTYPE_WF("'. These must be balanced ]]> ]]> ]>"); - TEST_DOCTYPE_WF("'. These must be balanced ]]> nesting ]]> nesting again ]]> end ]]> ]>"); - TEST_DOCTYPE_WF(" \"> %pe1; ]> ]>"); -} - -TEST(parse_doctype_xmlconf_oasis_1) -{ - TEST_DOCTYPE_WF(" ]>"); - TEST_DOCTYPE_WF("\"> ]]> %rootel; ]]> ]>"); - TEST_DOCTYPE_WF(" ]]>]]> ]>"); - TEST_DOCTYPE_WF(" ]]>]]> ]>"); - TEST_DOCTYPE_NWF(" ]>"); - TEST_DOCTYPE_WF(" ]]> ]>"); - TEST_DOCTYPE_NWF(" ]>"); - TEST_DOCTYPE_WF(" '. These must be balanced, but it is no section keyword is required: ] ]> ]] > ]]> ]]> ]>"); - TEST_DOCTYPE_WF(" ?>/\''\"> ]>"); - TEST_DOCTYPE_WF(" ]>"); - TEST_DOCTYPE_WF(" ]>"); - TEST_DOCTYPE_WF(" "); // not actually a doctype :) - TEST_DOCTYPE_WF(" &a%b&#c?>"); // not actually a doctype :) - TEST_DOCTYPE_WF("]>"); -} - -TEST(parse_doctype_xmlconf_xmltest_1) -{ - TEST_DOCTYPE_NWF(" ]> ]>"); - TEST_DOCTYPE_NWF(" "); - TEST_DOCTYPE_NWF(" "); - TEST_DOCTYPE_WF(" %e; -->"); - TEST_DOCTYPE_WF(" ]>"); - TEST_DOCTYPE_WF(" ]>"); - TEST_DOCTYPE_WF("\"> ]>"); - TEST_DOCTYPE_WF(" \"> ]>"); -} +#include "common.hpp" + +#include + +static bool test_doctype_wf(const std::basic_string& decl) +{ + xml_document doc; + + // standalone + if (!doc.load(decl.c_str()) || (bool)doc.first_child()) return false; + + // pcdata pre/postfix + if (!doc.load((STR("a") + decl).c_str()) || (bool)doc.first_child()) return false; + if (!doc.load((decl + STR("b")).c_str()) || (bool)doc.first_child()) return false; + if (!doc.load((STR("a") + decl + STR("b")).c_str()) || (bool)doc.first_child()) return false; + + // node pre/postfix + if (!doc.load((STR("") + decl).c_str()) || !test_node(doc, STR(""), STR(""), format_raw)) return false; + if (!doc.load((decl + STR("")).c_str()) || !test_node(doc, STR(""), STR(""), format_raw)) return false; + if (!doc.load((STR("") + decl + STR("")).c_str()) || !test_node(doc, STR(""), STR(""), format_raw)) return false; + + // wrap in node to check that doctype is parsed fully (does not leave any "pcdata") + if (!doc.load((STR("") + decl + STR("")).c_str()) || !test_node(doc, STR(""), STR(""), format_raw)) return false; + + return true; +} + +static bool test_doctype_nwf(const std::basic_string& decl) +{ + xml_document doc; + + // standalone + if (doc.load(decl.c_str()).status != status_bad_doctype) return false; + + // pcdata postfix + if (doc.load((decl + STR("b")).c_str()).status != status_bad_doctype) return false; + + // node postfix + if (doc.load((decl + STR("")).c_str()).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(""); + TEST_DOCTYPE_WF(""); + TEST_DOCTYPE_WF(""); + TEST_DOCTYPE_WF(""); + TEST_DOCTYPE_WF(""); + TEST_DOCTYPE_WF("]>"); +} + +TEST(parse_doctype_error) +{ + TEST_DOCTYPE_NWF(""); + TEST_DOCTYPE_NWF("]"); + TEST_DOCTYPE_NWF("] "); +} + +// Examples from W3C recommendations +TEST(parse_doctype_w3c_wf) +{ + TEST_DOCTYPE_WF(""); + TEST_DOCTYPE_WF(" ]>"); + TEST_DOCTYPE_WF(" ]>"); + TEST_DOCTYPE_WF(" ]]> ]]>]>"); + TEST_DOCTYPE_WF(" ]>"); + TEST_DOCTYPE_WF(" ]>"); +} + +TEST(parse_doctype_w3c_nwf) +{ + TEST_DOCTYPE_NWF(""); + TEST_DOCTYPE_NWF(" ]"); + TEST_DOCTYPE_NWF(""); + TEST_DOCTYPE_NWF(" ]"); + TEST_DOCTYPE_NWF(""); + TEST_DOCTYPE_NWF(" ]>"); + TEST_DOCTYPE_WF(" ]>"); + TEST_DOCTYPE_WF(" %e; ]>"); + TEST_DOCTYPE_WF(" ]>"); + TEST_DOCTYPE_WF(" ]>"); + TEST_DOCTYPE_WF(" ]>"); + TEST_DOCTYPE_WF(" ]>"); + TEST_DOCTYPE_WF(" ]>"); + TEST_DOCTYPE_WF(""); + TEST_DOCTYPE_WF(" ]>"); + TEST_DOCTYPE_WF(" ]>"); + TEST_DOCTYPE_WF(" ]>"); + TEST_DOCTYPE_WF(" ]>"); + TEST_DOCTYPE_WF(" \"> ]>"); + TEST_DOCTYPE_WF(" ]>"); + TEST_DOCTYPE_WF(" ]>"); + TEST_DOCTYPE_WF(" %pe; %intpe; ]>"); + TEST_DOCTYPE_WF(" ]>"); + TEST_DOCTYPE_WF(" ]>"); + TEST_DOCTYPE_WF(" ]>"); + TEST_DOCTYPE_WF(" ]>"); + TEST_DOCTYPE_WF(" ]>"); + TEST_DOCTYPE_WF(" ]>"); + TEST_DOCTYPE_WF(" ]>"); + TEST_DOCTYPE_WF("]]> ]>"); + TEST_DOCTYPE_WF(" ]>"); + TEST_DOCTYPE_NWF(" \"> \"> "); + TEST_DOCTYPE_WF(" ]>"); +} + +TEST(parse_doctype_xmlconf_eduni_2) +{ + TEST_DOCTYPE_WF("\"> %pe; ]>"); + TEST_DOCTYPE_WF(" ]>"); + TEST_DOCTYPE_WF(" ]>"); + TEST_DOCTYPE_WF(" ]>"); + TEST_DOCTYPE_WF(" ]>"); + TEST_DOCTYPE_WF(" ]>"); +} + +TEST(parse_doctype_xmlconf_eduni_3) +{ + TEST_DOCTYPE_WF(" ]>"); + TEST_DOCTYPE_WF(" ]>"); + TEST_DOCTYPE_WF("\"> ]>"); +} + +TEST(parse_doctype_xmlconf_eduni_4) +{ + TEST_DOCTYPE_WF(" ]>"); + TEST_DOCTYPE_WF(" ]>"); + TEST_DOCTYPE_WF(" ]>"); + TEST_DOCTYPE_WF(" ]>"); +} + +TEST(parse_doctype_xmlconf_eduni_5) +{ + TEST_DOCTYPE_WF(" ]>"); + TEST_DOCTYPE_WF(" ]>"); + TEST_DOCTYPE_WF(" ]>"); +} + +TEST(parse_doctype_xmlconf_ibm_1) +{ + TEST_DOCTYPE_WF(" ]>"); + TEST_DOCTYPE_WF(" ]>"); + TEST_DOCTYPE_WF(" ]>"); + TEST_DOCTYPE_WF(" ]>"); + TEST_DOCTYPE_WF(" ]>"); + TEST_DOCTYPE_WF(" ]>"); + TEST_DOCTYPE_WF(" ]>"); + TEST_DOCTYPE_WF(" ]>"); + TEST_DOCTYPE_WF(" %pe1; ]>"); + TEST_DOCTYPE_WF(" ]>"); + TEST_DOCTYPE_WF(" \"> %pe3; ]>"); + TEST_DOCTYPE_WF(" '> %pe1; ]>"); +} + +TEST(parse_doctype_xmlconf_ibm_2) +{ + TEST_DOCTYPE_WF(" \"> ]>"); + TEST_DOCTYPE_WF(" ]>"); + TEST_DOCTYPE_WF(" ]>"); + TEST_DOCTYPE_WF(" ]>"); + TEST_DOCTYPE_WF(" ]>"); + TEST_DOCTYPE_NWF(" ]>"); + TEST_DOCTYPE_WF(" ]>"); + TEST_DOCTYPE_NWF(" ]>"); + TEST_DOCTYPE_NWF(" ]>"); + TEST_DOCTYPE_NWF(" ]>"); + TEST_DOCTYPE_NWF(" ]>"); + TEST_DOCTYPE_WF(" ]>"); + TEST_DOCTYPE_WF(" &generalE; \"> %parameterE; ] animal>"); + TEST_DOCTYPE_WF(" ]>"); + TEST_DOCTYPE_WF(" ]>"); + TEST_DOCTYPE_NWF(" \"> ]>"); + TEST_DOCTYPE_WF(" ]>"); + TEST_DOCTYPE_WF(" ]>"); + TEST_DOCTYPE_WF(" ]>"); + TEST_DOCTYPE_WF(" ]]> ]>"); + TEST_DOCTYPE_WF(" ]]> ]>"); + TEST_DOCTYPE_NWF(" ]]> ]>"); + TEST_DOCTYPE_WF(" ]]> ]>"); + TEST_DOCTYPE_WF(" ]]> ]>"); + TEST_DOCTYPE_WF(" [INCLUDE ]]> ]>"); + TEST_DOCTYPE_NWF(" ]>"); + TEST_DOCTYPE_NWF(" ]>"); + TEST_DOCTYPE_WF(" %paaa; \"> ]>"); + TEST_DOCTYPE_WF(" \"> %paaa; ]>"); + TEST_DOCTYPE_NWF(" \" %paaa; ]>"); + TEST_DOCTYPE_WF(" ]>"); +} + +TEST(parse_doctype_xmlconf_ibm_3) +{ + TEST_DOCTYPE_WF(" ]>"); + TEST_DOCTYPE_WF(" ]>"); + TEST_DOCTYPE_WF(" ]>"); + TEST_DOCTYPE_WF(""); + TEST_DOCTYPE_WF(" ]>"); + TEST_DOCTYPE_WF(""); + TEST_DOCTYPE_WF(""); + TEST_DOCTYPE_WF(""); + TEST_DOCTYPE_WF(""); + TEST_DOCTYPE_WF(""); + TEST_DOCTYPE_WF(" ]>"); + TEST_DOCTYPE_NWF(" ]>"); + TEST_DOCTYPE_WF(" ]>"); + TEST_DOCTYPE_NWF(" ]>"); + TEST_DOCTYPE_WF(" IN PI ?> ]>"); + TEST_DOCTYPE_WF(" \"> \"> \"> %make_leopard_element; %make_small; \"> %make_big; %make_attlist; ]>"); + TEST_DOCTYPE_WF("\"> ]]> %rootElement; \"> %make_tiger_element; ]]> ]>"); + TEST_DOCTYPE_WF(" General entity reference in element content\"> ]>"); + TEST_DOCTYPE_WF(" ]>"); + TEST_DOCTYPE_WF("'. These must be balanced ]>"); + TEST_DOCTYPE_WF("'. These must be balanced ]]> ]]> ]>"); + TEST_DOCTYPE_WF("'. These must be balanced ]]> nesting ]]> nesting again ]]> end ]]> ]>"); + TEST_DOCTYPE_WF(" \"> %pe1; ]> ]>"); +} + +TEST(parse_doctype_xmlconf_oasis_1) +{ + TEST_DOCTYPE_WF(" ]>"); + TEST_DOCTYPE_WF("\"> ]]> %rootel; ]]> ]>"); + TEST_DOCTYPE_WF(" ]]>]]> ]>"); + TEST_DOCTYPE_WF(" ]]>]]> ]>"); + TEST_DOCTYPE_NWF(" ]>"); + TEST_DOCTYPE_WF(" ]]> ]>"); + TEST_DOCTYPE_NWF(" ]>"); + TEST_DOCTYPE_WF(" '. These must be balanced, but it is no section keyword is required: ] ]> ]] > ]]> ]]> ]>"); + TEST_DOCTYPE_WF(" ?>/\''\"> ]>"); + TEST_DOCTYPE_WF(" ]>"); + TEST_DOCTYPE_WF(" ]>"); + TEST_DOCTYPE_WF(" "); // not actually a doctype :) + TEST_DOCTYPE_WF(" &a%b&#c?>"); // not actually a doctype :) + TEST_DOCTYPE_WF("]>"); +} + +TEST(parse_doctype_xmlconf_xmltest_1) +{ + TEST_DOCTYPE_NWF(" ]> ]>"); + TEST_DOCTYPE_NWF(" "); + TEST_DOCTYPE_NWF(" "); + TEST_DOCTYPE_WF(" %e; -->"); + TEST_DOCTYPE_WF(" ]>"); + TEST_DOCTYPE_WF(" ]>"); + TEST_DOCTYPE_WF("\"> ]>"); + TEST_DOCTYPE_WF(" \"> ]>"); +} diff --git a/tests/test_unicode.cpp b/tests/test_unicode.cpp index ea2494b..0b656a3 100644 --- a/tests/test_unicode.cpp +++ b/tests/test_unicode.cpp @@ -1,137 +1,137 @@ -#ifndef PUGIXML_NO_STL - -#include "common.hpp" - -#include - -// 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::wstring 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] == 0xda1d && b4[1] == 0xde24 && b4[2] == L' ' && b4[3] == 0xdbc0 && b4[4] == 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::wstring b5 = as_wide("\xf8\nbcd"); - CHECK(b5 == L"\nbcd"); -} - -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::wstring 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 - } -} -#endif +#ifndef PUGIXML_NO_STL + +#include "common.hpp" + +#include + +// 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::wstring 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] == 0xda1d && b4[1] == 0xde24 && b4[2] == L' ' && b4[3] == 0xdbc0 && b4[4] == 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::wstring b5 = as_wide("\xf8\nbcd"); + CHECK(b5 == L"\nbcd"); +} + +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::wstring 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 + } +} +#endif diff --git a/tests/test_write.cpp b/tests/test_write.cpp index cb75c74..b7d8412 100644 --- a/tests/test_write.cpp +++ b/tests/test_write.cpp @@ -1,354 +1,354 @@ -#include "common.hpp" - -#include "writer_string.hpp" - -#include -#include - -TEST_XML(write_simple, "text") -{ - CHECK_NODE_EX(doc, STR("\ntext\n\n"), STR(""), 0); -} - -TEST_XML(write_raw, "text") -{ - CHECK_NODE_EX(doc, STR("text"), STR(""), format_raw); -} - -TEST_XML(write_indent, "text") -{ - CHECK_NODE_EX(doc, STR("\n\t\n\t\ttext\n\t\n\n"), STR("\t"), format_indent); -} - -TEST_XML(write_pcdata, "text") -{ - CHECK_NODE_EX(doc, STR("\n\t\n\t\t\n\t\ttext\n\t\n\n"), STR("\t"), format_indent); -} - -TEST_XML(write_cdata, "") -{ - CHECK_NODE(doc, STR("")); - CHECK_NODE_EX(doc, STR("\n"), STR(""), 0); -} - -TEST_XML_FLAGS(write_comment, "", parse_default | parse_comments) -{ - CHECK_NODE(doc, STR("")); - CHECK_NODE_EX(doc, STR("\n"), STR(""), 0); -} - -TEST_XML_FLAGS(write_pi, "", parse_default | parse_pi) -{ - CHECK_NODE(doc, STR("")); - CHECK_NODE_EX(doc, STR("\n"), STR(""), 0); -} - -TEST_XML_FLAGS(write_declaration, "", parse_default | parse_declaration) -{ - CHECK_NODE(doc, STR("")); - CHECK_NODE_EX(doc, STR("\n"), STR(""), 0); -} - -TEST_XML(write_escape, "text") -{ - 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("<>'\"&\r\n\t")); -} - -TEST_XML(write_escape_unicode, "") -{ -#ifdef PUGIXML_WCHAR_MODE - #ifdef U_LITERALS - CHECK_NODE(doc, STR("")); - #else - CHECK_NODE(doc, STR("")); - #endif -#else - CHECK_NODE(doc, STR("")); -#endif -} - -struct test_writer: xml_writer -{ - std::basic_string contents; - - virtual void write(const void* data, size_t size) - { - CHECK(size % sizeof(pugi::char_t) == 0); - contents += std::basic_string(static_cast(data), static_cast(data) + size / sizeof(pugi::char_t)); - } -}; - -TEST_XML(write_print_writer, "") -{ - test_writer writer; - doc.print(writer, STR(""), format_default, get_native_encoding()); - - CHECK(writer.contents == STR("\n")); -} - -#ifndef PUGIXML_NO_STL -TEST_XML(write_print_stream, "") -{ - std::ostringstream oss; - doc.print(oss, STR(""), format_default, encoding_utf8); - - CHECK(oss.str() == "\n"); -} - -TEST_XML(write_print_stream_encode, "") -{ - 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, "") -{ - std::basic_ostringstream oss; - doc.print(oss, STR(""), format_default, encoding_utf8); - - CHECK(oss.str() == L"\n"); -} -#endif - -TEST_XML(write_huge_chunk, "") -{ - std::basic_string 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::wstring 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] == 0xd852 && v[5] == 0xdf62 && v[6] == ' ' && v[7] == '/' && v[8] == '>' && v[9] == '\n'); - } -} - -#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 s_utf16; - - for (unsigned int i = 0; i < N; ++i) s_utf16 += static_cast(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<"; - - 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<\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")); - CHECK_NODE_EX(doc, STR("<:anonymous>\n\t<:anonymous />\n\t<:anonymous>text\n\n"), STR("\t"), format_default); -} - -TEST(write_no_name_pi) -{ - xml_document doc; - doc.append_child(node_pi); - - CHECK_NODE(doc, STR("")); -} - -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("")); -} +#include "common.hpp" + +#include "writer_string.hpp" + +#include +#include + +TEST_XML(write_simple, "text") +{ + CHECK_NODE_EX(doc, STR("\ntext\n\n"), STR(""), 0); +} + +TEST_XML(write_raw, "text") +{ + CHECK_NODE_EX(doc, STR("text"), STR(""), format_raw); +} + +TEST_XML(write_indent, "text") +{ + CHECK_NODE_EX(doc, STR("\n\t\n\t\ttext\n\t\n\n"), STR("\t"), format_indent); +} + +TEST_XML(write_pcdata, "text") +{ + CHECK_NODE_EX(doc, STR("\n\t\n\t\t\n\t\ttext\n\t\n\n"), STR("\t"), format_indent); +} + +TEST_XML(write_cdata, "") +{ + CHECK_NODE(doc, STR("")); + CHECK_NODE_EX(doc, STR("\n"), STR(""), 0); +} + +TEST_XML_FLAGS(write_comment, "", parse_default | parse_comments) +{ + CHECK_NODE(doc, STR("")); + CHECK_NODE_EX(doc, STR("\n"), STR(""), 0); +} + +TEST_XML_FLAGS(write_pi, "", parse_default | parse_pi) +{ + CHECK_NODE(doc, STR("")); + CHECK_NODE_EX(doc, STR("\n"), STR(""), 0); +} + +TEST_XML_FLAGS(write_declaration, "", parse_default | parse_declaration) +{ + CHECK_NODE(doc, STR("")); + CHECK_NODE_EX(doc, STR("\n"), STR(""), 0); +} + +TEST_XML(write_escape, "text") +{ + 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("<>'\"&\r\n\t")); +} + +TEST_XML(write_escape_unicode, "") +{ +#ifdef PUGIXML_WCHAR_MODE + #ifdef U_LITERALS + CHECK_NODE(doc, STR("")); + #else + CHECK_NODE(doc, STR("")); + #endif +#else + CHECK_NODE(doc, STR("")); +#endif +} + +struct test_writer: xml_writer +{ + std::basic_string contents; + + virtual void write(const void* data, size_t size) + { + CHECK(size % sizeof(pugi::char_t) == 0); + contents += std::basic_string(static_cast(data), static_cast(data) + size / sizeof(pugi::char_t)); + } +}; + +TEST_XML(write_print_writer, "") +{ + test_writer writer; + doc.print(writer, STR(""), format_default, get_native_encoding()); + + CHECK(writer.contents == STR("\n")); +} + +#ifndef PUGIXML_NO_STL +TEST_XML(write_print_stream, "") +{ + std::ostringstream oss; + doc.print(oss, STR(""), format_default, encoding_utf8); + + CHECK(oss.str() == "\n"); +} + +TEST_XML(write_print_stream_encode, "") +{ + 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, "") +{ + std::basic_ostringstream oss; + doc.print(oss, STR(""), format_default, encoding_utf8); + + CHECK(oss.str() == L"\n"); +} +#endif + +TEST_XML(write_huge_chunk, "") +{ + std::basic_string 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::wstring 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] == 0xd852 && v[5] == 0xdf62 && v[6] == ' ' && v[7] == '/' && v[8] == '>' && v[9] == '\n'); + } +} + +#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 s_utf16; + + for (unsigned int i = 0; i < N; ++i) s_utf16 += static_cast(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<"; + + 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<\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")); + CHECK_NODE_EX(doc, STR("<:anonymous>\n\t<:anonymous />\n\t<:anonymous>text\n\n"), STR("\t"), format_default); +} + +TEST(write_no_name_pi) +{ + xml_document doc; + doc.append_child(node_pi); + + CHECK_NODE(doc, STR("")); +} + +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("")); +} diff --git a/tests/test_xpath.cpp b/tests/test_xpath.cpp index 7b52437..608859f 100644 --- a/tests/test_xpath.cpp +++ b/tests/test_xpath.cpp @@ -1,227 +1,227 @@ -#ifndef PUGIXML_NO_XPATH - -#include "common.hpp" - -#include -#include -#include - -#include - -TEST(xpath_allocator_many_pages) -{ - pugi::string_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) -{ - pugi::string_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, "test") -{ - // 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, "") -{ - 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, "") -{ - 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(xpath_long_numbers_parse) -{ - const pugi::char_t* str_flt_max = STR("340282346638528860000000000000000000000"); - const pugi::char_t* str_flt_max_dec = STR("340282346638528860000000000000000000000.000000"); - - const pugi::char_t* str_dbl_max = STR("179769313486231570000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"); - const pugi::char_t* str_dbl_max_dec = STR("179769313486231570000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.000000"); - - xml_node c; - - // check parsing - CHECK_XPATH_NUMBER(c, str_flt_max, FLT_MAX); - CHECK_XPATH_NUMBER(c, str_flt_max_dec, FLT_MAX); - CHECK_XPATH_NUMBER(c, str_dbl_max, DBL_MAX); - CHECK_XPATH_NUMBER(c, str_dbl_max_dec, DBL_MAX); -} - -static bool test_xpath_string_prefix(const pugi::xml_node& node, const pugi::char_t* query, const pugi::char_t* expected, size_t match_length) -{ -#ifdef PUGIXML_WCHAR_MODE - size_t expected_length = wcslen(expected); -#else - size_t expected_length = strlen(expected); -#endif - - pugi::xpath_query q(query); - pugi::string_t value = q.evaluate_string(node); - - return value.length() == expected_length && value.compare(0, match_length, expected, match_length) == 0; -} - -TEST(xpath_long_numbers_stringize) -{ - const pugi::char_t* str_flt_max = STR("340282346638528860000000000000000000000"); - const pugi::char_t* str_flt_max_dec = STR("340282346638528860000000000000000000000.000000"); - - const pugi::char_t* str_dbl_max = STR("179769313486231570000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"); - const pugi::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)); -} - -#include - -TEST(xpath_denorm_numbers) -{ - pugi::string_t query; - - // 10^-318 - double denormal - for (int i = 0; i < 106; ++i) - { - if (i != 0) query += STR(" * "); - query += STR("0.001"); - } - - CHECK_XPATH_STRING(xml_node(), query.c_str(), STR("0.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000009999987484955998")); -} - -TEST_XML(xpath_rexml_1, "") -{ - 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, "zzz") -{ - CHECK_XPATH_NODESET(doc, STR("a:x/a:y[@p='p' and @q='q']/a:z/text()")) % 8; -} - -TEST_XML(xpath_rexml_3, "
free flowing text.
free flowing text.
free flowing text.
") -{ - 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, "TEXT1TEXT2", 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, "") -{ - 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, "
ab
") -{ - 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, "whatevertextselectsomething") -{ - // 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, "
") -{ - 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, "0.5
") -{ - 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")); -} - -#endif +#ifndef PUGIXML_NO_XPATH + +#include "common.hpp" + +#include +#include +#include + +#include + +TEST(xpath_allocator_many_pages) +{ + pugi::string_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) +{ + pugi::string_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, "test") +{ + // 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, "") +{ + 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, "") +{ + 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(xpath_long_numbers_parse) +{ + const pugi::char_t* str_flt_max = STR("340282346638528860000000000000000000000"); + const pugi::char_t* str_flt_max_dec = STR("340282346638528860000000000000000000000.000000"); + + const pugi::char_t* str_dbl_max = STR("179769313486231570000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"); + const pugi::char_t* str_dbl_max_dec = STR("179769313486231570000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.000000"); + + xml_node c; + + // check parsing + CHECK_XPATH_NUMBER(c, str_flt_max, FLT_MAX); + CHECK_XPATH_NUMBER(c, str_flt_max_dec, FLT_MAX); + CHECK_XPATH_NUMBER(c, str_dbl_max, DBL_MAX); + CHECK_XPATH_NUMBER(c, str_dbl_max_dec, DBL_MAX); +} + +static bool test_xpath_string_prefix(const pugi::xml_node& node, const pugi::char_t* query, const pugi::char_t* expected, size_t match_length) +{ +#ifdef PUGIXML_WCHAR_MODE + size_t expected_length = wcslen(expected); +#else + size_t expected_length = strlen(expected); +#endif + + pugi::xpath_query q(query); + pugi::string_t value = q.evaluate_string(node); + + return value.length() == expected_length && value.compare(0, match_length, expected, match_length) == 0; +} + +TEST(xpath_long_numbers_stringize) +{ + const pugi::char_t* str_flt_max = STR("340282346638528860000000000000000000000"); + const pugi::char_t* str_flt_max_dec = STR("340282346638528860000000000000000000000.000000"); + + const pugi::char_t* str_dbl_max = STR("179769313486231570000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"); + const pugi::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)); +} + +#include + +TEST(xpath_denorm_numbers) +{ + pugi::string_t query; + + // 10^-318 - double denormal + for (int i = 0; i < 106; ++i) + { + if (i != 0) query += STR(" * "); + query += STR("0.001"); + } + + CHECK_XPATH_STRING(xml_node(), query.c_str(), STR("0.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000009999987484955998")); +} + +TEST_XML(xpath_rexml_1, "") +{ + 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, "zzz") +{ + CHECK_XPATH_NODESET(doc, STR("a:x/a:y[@p='p' and @q='q']/a:z/text()")) % 8; +} + +TEST_XML(xpath_rexml_3, "
free flowing text.
free flowing text.
free flowing text.
") +{ + 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, "TEXT1TEXT2", 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, "") +{ + 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, "
ab
") +{ + 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, "whatevertextselectsomething") +{ + // 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, "
") +{ + 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, "0.5
") +{ + 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")); +} + +#endif diff --git a/tests/test_xpath_api.cpp b/tests/test_xpath_api.cpp index 56e8ff6..f7fc868 100644 --- a/tests/test_xpath_api.cpp +++ b/tests/test_xpath_api.cpp @@ -1,150 +1,150 @@ -#ifndef PUGIXML_NO_XPATH - -#include "common.hpp" - -#include "helpers.hpp" - -#include - -TEST_XML(xpath_api_select_nodes, "") -{ - 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_single_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); - - xpath_node n3 = doc.select_single_node(STR("node/bar")); - - CHECK(!n3); - - xpath_node n4 = doc.select_single_node(STR("node/head/following-sibling::foo")); - xpath_node n5 = doc.select_single_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(xpath_api_exception_what) -{ - try - { - xpath_query q(STR("")); - } - catch (const xpath_exception& e) - { - CHECK(e.what()[0] != 0); - } -} - -TEST_XML(xpath_api_node_bool_ops, "") -{ - generic_bool_ops_test(doc.select_single_node(STR("node"))); - generic_bool_ops_test(doc.select_single_node(STR("node/@attr"))); -} - -TEST_XML(xpath_api_node_eq_ops, "") -{ - generic_eq_ops_test(doc.select_single_node(STR("node")), doc.select_single_node(STR("node/@attr"))); -} - -TEST_XML(xpath_api_node_accessors, "") -{ - xpath_node null; - xpath_node node = doc.select_single_node(STR("node")); - xpath_node attr = doc.select_single_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, "") -{ - 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_evaluate, "") -{ - xpath_query q(STR("node/@attr")); - - CHECK(q.evaluate_boolean(doc)); - CHECK(q.evaluate_number(doc) == 3); - CHECK(q.evaluate_string(doc) == STR("3")); - - xpath_node_set ns = q.evaluate_node_set(doc); - CHECK(ns.size() == 1 && ns[0].attribute() == doc.child(STR("node")).attribute(STR("attr"))); -} - -TEST(xpath_api_evaluate_node_set) -{ - try - { - xpath_query q(STR("1")); - - q.evaluate_node_set(xml_node()); - } - catch (const xpath_exception&) - { - } -} - -TEST(xpath_api_return_type) -{ - 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); -} - -#endif +#ifndef PUGIXML_NO_XPATH + +#include "common.hpp" + +#include "helpers.hpp" + +#include + +TEST_XML(xpath_api_select_nodes, "") +{ + 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_single_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); + + xpath_node n3 = doc.select_single_node(STR("node/bar")); + + CHECK(!n3); + + xpath_node n4 = doc.select_single_node(STR("node/head/following-sibling::foo")); + xpath_node n5 = doc.select_single_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(xpath_api_exception_what) +{ + try + { + xpath_query q(STR("")); + } + catch (const xpath_exception& e) + { + CHECK(e.what()[0] != 0); + } +} + +TEST_XML(xpath_api_node_bool_ops, "") +{ + generic_bool_ops_test(doc.select_single_node(STR("node"))); + generic_bool_ops_test(doc.select_single_node(STR("node/@attr"))); +} + +TEST_XML(xpath_api_node_eq_ops, "") +{ + generic_eq_ops_test(doc.select_single_node(STR("node")), doc.select_single_node(STR("node/@attr"))); +} + +TEST_XML(xpath_api_node_accessors, "") +{ + xpath_node null; + xpath_node node = doc.select_single_node(STR("node")); + xpath_node attr = doc.select_single_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, "") +{ + 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_evaluate, "") +{ + xpath_query q(STR("node/@attr")); + + CHECK(q.evaluate_boolean(doc)); + CHECK(q.evaluate_number(doc) == 3); + CHECK(q.evaluate_string(doc) == STR("3")); + + xpath_node_set ns = q.evaluate_node_set(doc); + CHECK(ns.size() == 1 && ns[0].attribute() == doc.child(STR("node")).attribute(STR("attr"))); +} + +TEST(xpath_api_evaluate_node_set) +{ + try + { + xpath_query q(STR("1")); + + q.evaluate_node_set(xml_node()); + } + catch (const xpath_exception&) + { + } +} + +TEST(xpath_api_return_type) +{ + 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); +} + +#endif diff --git a/tests/test_xpath_functions.cpp b/tests/test_xpath_functions.cpp index 7b44294..3eb69c6 100644 --- a/tests/test_xpath_functions.cpp +++ b/tests/test_xpath_functions.cpp @@ -1,747 +1,747 @@ -#ifndef PUGIXML_NO_XPATH - -#include "common.hpp" - -TEST_XML(xpath_number_number, "123") -{ - 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, "123789") -{ - 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__)) // MacOS X gcc 4.0.1 implements 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__)) // MacOS X gcc 4.0.1 implements 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, "") -{ - 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, "") -{ - 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('ru-uk')"), true); - CHECK_XPATH_BOOLEAN(doc.child(STR("node")).child(STR("child")), STR("lang('ru')"), true); - CHECK_XPATH_BOOLEAN(doc.child(STR("node")).child(STR("child")).child(STR("subchild")), STR("lang('ru')"), true); - CHECK_XPATH_BOOLEAN(doc.child(STR("node")).child(STR("child")).child(STR("subchild")), STR("lang('RU')"), 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('ru-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 2 arguments - CHECK_XPATH_FAIL(STR("lang(1, 2)")); -} - -TEST_XML(xpath_string_string, "123789100") -{ - 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('', '')"), 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('', '')"), 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(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("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_string_length, "123") -{ - 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, " \t\r\rval1 \rval2\r\nval3\nval4\r\r", 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_XML(xpath_nodeset_last, "") -{ - 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, "") -{ - 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, "") -{ - 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, "") -{ - 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, "text", 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, "text", 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("")); - - // namespace-uri with 2 arguments - CHECK_XPATH_FAIL(STR("namespace-uri(c1, c2)")); -} - -TEST_XML_FLAGS(xpath_nodeset_name, "text", 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, "pcdata", 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_XML(xpath_string_concat_translate, "foobar") -{ - CHECK_XPATH_STRING(doc, STR("concat('a', 'b', 'c', translate(node, 'o', 'a'), 'd')"), STR("abcfaabard")); -} - -#endif +#ifndef PUGIXML_NO_XPATH + +#include "common.hpp" + +TEST_XML(xpath_number_number, "123") +{ + 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, "123789") +{ + 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__)) // MacOS X gcc 4.0.1 implements 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__)) // MacOS X gcc 4.0.1 implements 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, "") +{ + 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, "") +{ + 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('ru-uk')"), true); + CHECK_XPATH_BOOLEAN(doc.child(STR("node")).child(STR("child")), STR("lang('ru')"), true); + CHECK_XPATH_BOOLEAN(doc.child(STR("node")).child(STR("child")).child(STR("subchild")), STR("lang('ru')"), true); + CHECK_XPATH_BOOLEAN(doc.child(STR("node")).child(STR("child")).child(STR("subchild")), STR("lang('RU')"), 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('ru-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 2 arguments + CHECK_XPATH_FAIL(STR("lang(1, 2)")); +} + +TEST_XML(xpath_string_string, "123789100") +{ + 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('', '')"), 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('', '')"), 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(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("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_string_length, "123") +{ + 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, " \t\r\rval1 \rval2\r\nval3\nval4\r\r", 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_XML(xpath_nodeset_last, "") +{ + 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, "") +{ + 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, "") +{ + 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, "") +{ + 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, "text", 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, "text", 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("")); + + // namespace-uri with 2 arguments + CHECK_XPATH_FAIL(STR("namespace-uri(c1, c2)")); +} + +TEST_XML_FLAGS(xpath_nodeset_name, "text", 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, "pcdata", 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_XML(xpath_string_concat_translate, "foobar") +{ + CHECK_XPATH_STRING(doc, STR("concat('a', 'b', 'c', translate(node, 'o', 'a'), 'd')"), STR("abcfaabard")); +} + +#endif diff --git a/tests/test_xpath_operators.cpp b/tests/test_xpath_operators.cpp index b834b95..c7fe165 100644 --- a/tests/test_xpath_operators.cpp +++ b/tests/test_xpath_operators.cpp @@ -1,473 +1,473 @@ -#ifndef PUGIXML_NO_XPATH - -#include "common.hpp" - -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, "1023") -{ - 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, "abacbdabb") -{ - 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 intutive) - 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, "1-11001nan") -{ - 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, "1-1-1001nan1-4") -{ - 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); - -#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); -#endif -} - -TEST_XML(xpath_operators_inequality_node_set_primitive, "1-1-1001nan") -{ - 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, "") -{ - 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(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(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); -} - -#endif +#ifndef PUGIXML_NO_XPATH + +#include "common.hpp" + +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, "1023") +{ + 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, "abacbdabb") +{ + 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 intutive) + 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, "1-11001nan") +{ + 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, "1-1-1001nan1-4") +{ + 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); + +#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); +#endif +} + +TEST_XML(xpath_operators_inequality_node_set_primitive, "1-1-1001nan") +{ + 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, "") +{ + 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(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(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); +} + +#endif diff --git a/tests/test_xpath_parse.cpp b/tests/test_xpath_parse.cpp index ceede22..8c08ef9 100644 --- a/tests/test_xpath_parse.cpp +++ b/tests/test_xpath_parse.cpp @@ -1,272 +1,272 @@ -#ifndef PUGIXML_NO_XPATH - -#include "common.hpp" - -#include - -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")); // not implemented - CHECK_XPATH_FAIL(STR("$1")); -} - -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]); - } -} - -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 path_utf8 = pugi::as_utf8(paths[i]); - xpath_query q(path_utf8.c_str()); - #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, "
") -{ - 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; -} - -#endif +#ifndef PUGIXML_NO_XPATH + +#include "common.hpp" + +#include + +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")); // not implemented + CHECK_XPATH_FAIL(STR("$1")); +} + +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]); + } +} + +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 path_utf8 = pugi::as_utf8(paths[i]); + xpath_query q(path_utf8.c_str()); + #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, "
") +{ + 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; +} + +#endif diff --git a/tests/test_xpath_paths.cpp b/tests/test_xpath_paths.cpp index b726a5a..2799f40 100644 --- a/tests/test_xpath_paths.cpp +++ b/tests/test_xpath_paths.cpp @@ -1,472 +1,472 @@ -#ifndef PUGIXML_NO_XPATH - -#include "common.hpp" - -TEST_XML(xpath_paths_axes_child, "") -{ - xml_node c; - xml_node n = doc.child(STR("node")); - - 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()")); -} - -TEST_XML(xpath_paths_axes_descendant, "") -{ - xml_node c; - xml_node n = doc.child(STR("node")); - - CHECK_XPATH_NODESET(c, STR("descendant:: node()")); - - CHECK_XPATH_NODESET(n, STR("descendant:: node()")) % 4 % 6 % 7 % 8 % 9; // child, subchild, another, subchild, last - CHECK_XPATH_NODESET(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()")); -} - -TEST_XML(xpath_paths_axes_parent, "") -{ - xml_node c; - xml_node n = doc.child(STR("node")); - - 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()")); -} - -TEST_XML(xpath_paths_axes_ancestor, "") -{ - xml_node c; - xml_node n = doc.child(STR("node")); - - CHECK_XPATH_NODESET(c, STR("ancestor:: node()")); - - CHECK_XPATH_NODESET(n.child(STR("child")), STR("ancestor:: node()")) % 2 % 1; // node, root - CHECK_XPATH_NODESET(n, 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()")); -} - -TEST_XML(xpath_paths_axes_following_sibling, "") -{ - xml_node c; - xml_node n = doc.child(STR("node")); - - 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 -} - -TEST_XML(xpath_paths_axes_preceding_sibling, "") -{ - xml_node c; - xml_node n = doc.child(STR("node")); - - 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 -} - -TEST_XML(xpath_paths_axes_following, "") -{ - xml_node c; - xml_node n = doc.child(STR("node")); - - 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 -} - -TEST_XML(xpath_paths_axes_preceding, "") -{ - xml_node c; - xml_node n = doc.child(STR("node")); - - CHECK_XPATH_NODESET(c, STR("preceding:: node()")); - - CHECK_XPATH_NODESET(n.child(STR("child")), STR("preceding:: node()")); // no ancestors - CHECK_XPATH_NODESET(n.child(STR("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 -} - -TEST_XML(xpath_paths_axes_attribute, "") -{ - xml_node c; - xml_node n = doc.child(STR("node")); - - 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()")); -} - -TEST_XML(xpath_paths_axes_namespace, "") -{ - xml_node n = doc.child(STR("node")); - - CHECK_XPATH_NODESET(n, STR("namespace:: node()")); // namespace nodes are not supported - CHECK_XPATH_NODESET(n, STR("@attr/attribute::node()")); -} - -TEST_XML(xpath_paths_axes_self, "") -{ - xml_node c; - xml_node n = doc.child(STR("node")); - - 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 -} - -TEST_XML(xpath_paths_axes_descendant_or_self, "") -{ - xml_node c; - xml_node n = doc.child(STR("node")); - - CHECK_XPATH_NODESET(c, STR("descendant-or-self:: node()")); - - CHECK_XPATH_NODESET(n, STR("descendant-or-self:: node()")) % 2 % 4 % 6 % 7 % 8 % 9; // node, child, subchild, another, subchild, last - CHECK_XPATH_NODESET(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 -} - -TEST_XML(xpath_paths_axes_ancestor_or_self, "") -{ - xml_node c; - xml_node n = doc.child(STR("node")); - - CHECK_XPATH_NODESET(c, STR("ancestor-or-self:: node()")); - - CHECK_XPATH_NODESET(n.child(STR("child")), STR("ancestor-or-self:: node()")) % 4 % 2 % 1; // child, node, root - CHECK_XPATH_NODESET(n, 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 -} - -TEST_XML(xpath_paths_axes_abbrev, "") -{ - 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, "") -{ - 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, "", 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, "") -{ - 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, "pcdata", 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, "pcdata", 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_absolute, "") -{ - xml_node c; - xml_node n = doc.child(STR("node")); - - CHECK_XPATH_NODESET(c, STR("/foo")); - CHECK_XPATH_NODESET(n, STR("/foo")); - CHECK_XPATH_NODESET(n, STR("/node/foo")) % 3; - CHECK_XPATH_NODESET(n.child(STR("foo")), STR("/node/foo")) % 3; - - CHECK_XPATH_NODESET(c, STR("/")); - CHECK_XPATH_NODESET(n, STR("/")) % 1; - CHECK_XPATH_NODESET(n.child(STR("foo")), STR("/")) % 1; -} - -TEST_XML(xpath_paths_step_abbrev, "") -{ - 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, "") -{ - 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, "") -{ - 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, "") -{ - 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, "") -{ - 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_several, "") -{ - 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, "") -{ - 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, "") -{ - 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, "") -{ - 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, "") -{ - 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, "") -{ - 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, "") -{ - CHECK_XPATH_NODESET(doc, STR("(node/child/subchild)[2]")) % 7; -} - -#endif +#ifndef PUGIXML_NO_XPATH + +#include "common.hpp" + +TEST_XML(xpath_paths_axes_child, "") +{ + xml_node c; + xml_node n = doc.child(STR("node")); + + 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()")); +} + +TEST_XML(xpath_paths_axes_descendant, "") +{ + xml_node c; + xml_node n = doc.child(STR("node")); + + CHECK_XPATH_NODESET(c, STR("descendant:: node()")); + + CHECK_XPATH_NODESET(n, STR("descendant:: node()")) % 4 % 6 % 7 % 8 % 9; // child, subchild, another, subchild, last + CHECK_XPATH_NODESET(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()")); +} + +TEST_XML(xpath_paths_axes_parent, "") +{ + xml_node c; + xml_node n = doc.child(STR("node")); + + 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()")); +} + +TEST_XML(xpath_paths_axes_ancestor, "") +{ + xml_node c; + xml_node n = doc.child(STR("node")); + + CHECK_XPATH_NODESET(c, STR("ancestor:: node()")); + + CHECK_XPATH_NODESET(n.child(STR("child")), STR("ancestor:: node()")) % 2 % 1; // node, root + CHECK_XPATH_NODESET(n, 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()")); +} + +TEST_XML(xpath_paths_axes_following_sibling, "") +{ + xml_node c; + xml_node n = doc.child(STR("node")); + + 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 +} + +TEST_XML(xpath_paths_axes_preceding_sibling, "") +{ + xml_node c; + xml_node n = doc.child(STR("node")); + + 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 +} + +TEST_XML(xpath_paths_axes_following, "") +{ + xml_node c; + xml_node n = doc.child(STR("node")); + + 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 +} + +TEST_XML(xpath_paths_axes_preceding, "") +{ + xml_node c; + xml_node n = doc.child(STR("node")); + + CHECK_XPATH_NODESET(c, STR("preceding:: node()")); + + CHECK_XPATH_NODESET(n.child(STR("child")), STR("preceding:: node()")); // no ancestors + CHECK_XPATH_NODESET(n.child(STR("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 +} + +TEST_XML(xpath_paths_axes_attribute, "") +{ + xml_node c; + xml_node n = doc.child(STR("node")); + + 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()")); +} + +TEST_XML(xpath_paths_axes_namespace, "") +{ + xml_node n = doc.child(STR("node")); + + CHECK_XPATH_NODESET(n, STR("namespace:: node()")); // namespace nodes are not supported + CHECK_XPATH_NODESET(n, STR("@attr/attribute::node()")); +} + +TEST_XML(xpath_paths_axes_self, "") +{ + xml_node c; + xml_node n = doc.child(STR("node")); + + 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 +} + +TEST_XML(xpath_paths_axes_descendant_or_self, "") +{ + xml_node c; + xml_node n = doc.child(STR("node")); + + CHECK_XPATH_NODESET(c, STR("descendant-or-self:: node()")); + + CHECK_XPATH_NODESET(n, STR("descendant-or-self:: node()")) % 2 % 4 % 6 % 7 % 8 % 9; // node, child, subchild, another, subchild, last + CHECK_XPATH_NODESET(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 +} + +TEST_XML(xpath_paths_axes_ancestor_or_self, "") +{ + xml_node c; + xml_node n = doc.child(STR("node")); + + CHECK_XPATH_NODESET(c, STR("ancestor-or-self:: node()")); + + CHECK_XPATH_NODESET(n.child(STR("child")), STR("ancestor-or-self:: node()")) % 4 % 2 % 1; // child, node, root + CHECK_XPATH_NODESET(n, 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 +} + +TEST_XML(xpath_paths_axes_abbrev, "") +{ + 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, "") +{ + 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, "", 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, "") +{ + 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, "pcdata", 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, "pcdata", 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_absolute, "") +{ + xml_node c; + xml_node n = doc.child(STR("node")); + + CHECK_XPATH_NODESET(c, STR("/foo")); + CHECK_XPATH_NODESET(n, STR("/foo")); + CHECK_XPATH_NODESET(n, STR("/node/foo")) % 3; + CHECK_XPATH_NODESET(n.child(STR("foo")), STR("/node/foo")) % 3; + + CHECK_XPATH_NODESET(c, STR("/")); + CHECK_XPATH_NODESET(n, STR("/")) % 1; + CHECK_XPATH_NODESET(n.child(STR("foo")), STR("/")) % 1; +} + +TEST_XML(xpath_paths_step_abbrev, "") +{ + 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, "") +{ + 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, "") +{ + 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, "") +{ + 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, "") +{ + 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_several, "") +{ + 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, "") +{ + 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, "") +{ + 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, "") +{ + 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, "") +{ + 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, "") +{ + 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, "") +{ + CHECK_XPATH_NODESET(doc, STR("(node/child/subchild)[2]")) % 7; +} + +#endif diff --git a/tests/test_xpath_paths_abbrev_w3c.cpp b/tests/test_xpath_paths_abbrev_w3c.cpp index ebd13aa..af65752 100644 --- a/tests/test_xpath_paths_abbrev_w3c.cpp +++ b/tests/test_xpath_paths_abbrev_w3c.cpp @@ -1,217 +1,217 @@ -#ifndef PUGIXML_NO_XPATH - -#include "common.hpp" - -TEST_XML(xpath_paths_abbrev_w3c_1, "") -{ - 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, "") -{ - 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, "pcdata") -{ - 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, "") -{ - 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, "") -{ - 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, "") -{ - 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, "") -{ - 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, "") -{ - xml_node c; - - CHECK_XPATH_NODESET(c, STR("*/para")); - CHECK_XPATH_NODESET(doc, STR("*/para")) % 3 % 9; -} - -TEST_XML(xpath_paths_abbrev_w3c_9, "
") -{ - 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, "") -{ - 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, "") -{ - 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, "") -{ - 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, "") -{ - 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, "") -{ - 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, "") -{ - 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, "") -{ - 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, "") -{ - 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, "") -{ - 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, "") -{ - 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, "") -{ - 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, "fooIntroductionintroductionIntroductionfoo") -{ - 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, "fooIntroductionintroductionIntroductionfoo") -{ - 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, "") -{ - xml_node c; - xml_node n = doc.child(STR("node")); - - CHECK_XPATH_NODESET(c, STR("employee[@secretary and @assistant]")); - CHECK_XPATH_NODESET(n, STR("employee[@secretary and @assistant]")) % 8 % 11; -} - -#endif +#ifndef PUGIXML_NO_XPATH + +#include "common.hpp" + +TEST_XML(xpath_paths_abbrev_w3c_1, "") +{ + 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, "") +{ + 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, "pcdata") +{ + 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, "") +{ + 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, "") +{ + 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, "") +{ + 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, "") +{ + 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, "") +{ + xml_node c; + + CHECK_XPATH_NODESET(c, STR("*/para")); + CHECK_XPATH_NODESET(doc, STR("*/para")) % 3 % 9; +} + +TEST_XML(xpath_paths_abbrev_w3c_9, "
") +{ + 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, "") +{ + 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, "") +{ + 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, "") +{ + 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, "") +{ + 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, "") +{ + 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, "") +{ + 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, "") +{ + 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, "") +{ + 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, "") +{ + 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, "") +{ + 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, "") +{ + 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, "fooIntroductionintroductionIntroductionfoo") +{ + 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, "fooIntroductionintroductionIntroductionfoo") +{ + 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, "") +{ + 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 diff --git a/tests/test_xpath_paths_w3c.cpp b/tests/test_xpath_paths_w3c.cpp index d3f1554..2005bc5 100644 --- a/tests/test_xpath_paths_w3c.cpp +++ b/tests/test_xpath_paths_w3c.cpp @@ -1,310 +1,310 @@ -#ifndef PUGIXML_NO_XPATH - -#include "common.hpp" - -TEST_XML(xpath_paths_w3c_1, "") -{ - 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, "") -{ - 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, "pcdata") -{ - 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, "pcdata") -{ - 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, "") -{ - 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, "") -{ - 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, "") -{ - 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, "
") -{ - 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, "
") -{ - 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, "") -{ - 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, "") -{ - 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, "") -{ - 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, "") -{ - 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, "") -{ - 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, "") -{ - 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, "") -{ - 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, "") -{ - 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, "") -{ - 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, "") -{ - 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, "") -{ - 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, "") -{ - 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, "") -{ - 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, "
") -{ - 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, "
") -{ - 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, "") -{ - 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, "") -{ - 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, "") -{ - 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, "") -{ - 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, "fooIntroductionintroductionIntroductionfoo") -{ - 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, "fooIntroductionintroductionIntroductionfoo") -{ - 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, "") -{ - 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, "") -{ - 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, "") -{ - xml_node c; - xml_node n = doc.child(STR("node")); - - CHECK_XPATH_NODESET(c, STR("child::*[self::chapter or self::appendix][position()=last()]")); - CHECK_XPATH_NODESET(n, STR("child::*[self::chapter or self::appendix][position()=last()]")) % 8; -} - -#endif +#ifndef PUGIXML_NO_XPATH + +#include "common.hpp" + +TEST_XML(xpath_paths_w3c_1, "") +{ + 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, "") +{ + 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, "pcdata") +{ + 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, "pcdata") +{ + 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, "") +{ + 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, "") +{ + 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, "") +{ + 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, "
") +{ + 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, "
") +{ + 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, "") +{ + 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, "") +{ + 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, "") +{ + 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, "") +{ + 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, "") +{ + 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, "") +{ + 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, "") +{ + 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, "") +{ + 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, "") +{ + 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, "") +{ + 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, "") +{ + 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, "") +{ + 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, "") +{ + 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, "
") +{ + 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, "
") +{ + 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, "") +{ + 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, "") +{ + 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, "") +{ + 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, "") +{ + 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, "fooIntroductionintroductionIntroductionfoo") +{ + 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, "fooIntroductionintroductionIntroductionfoo") +{ + 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, "") +{ + 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, "") +{ + 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, "") +{ + 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 diff --git a/tests/test_xpath_xalan_1.cpp b/tests/test_xpath_xalan_1.cpp index 7be711f..b862b1e 100644 --- a/tests/test_xpath_xalan_1.cpp +++ b/tests/test_xpath_xalan_1.cpp @@ -1,407 +1,407 @@ -#ifndef PUGIXML_NO_XPATH - -#include "common.hpp" - -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, "") -{ - 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, "foobarfoobarfoo") -{ - 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, "firstsecondthirdfourth") -{ - 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, "12345678") -{ - 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, "truefalse?10") -{ - 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, "b") -{ - 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, "3") -{ - 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, "3") -{ - 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, "24517-58-37") -{ - 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, "231237212
5
2
") -{ - 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, "37x") -{ - 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, "37x") -{ - 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, "0.0004") -{ - 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); - CHECK_XPATH_BOOLEAN(doc, STR("(number(k) = (4 div 10000))"), true); - CHECK_XPATH_NUMBER(doc, STR("number(0.0001 * 4)"), 0.0004); - CHECK_XPATH_BOOLEAN(doc, STR("(number(k) = (0.0001 * 4))"), true); -} - -TEST(xpath_xalan_math_9) -{ - xml_node c; - - CHECK_XPATH_STRING(c, STR("string(number('0.0'))"), STR("0")); - CHECK_XPATH_STRING(c, STR("string(-1 * number('0.0'))"), STR("0")); - - CHECK_XPATH_STRING(c, STR("string(number('0.4'))"), STR("0.4")); - CHECK_XPATH_STRING(c, STR("string(-1 * number('0.4'))"), STR("-0.4")); - - CHECK_XPATH_STRING(c, STR("string(number('4.0'))"), STR("4")); - CHECK_XPATH_STRING(c, STR("string(-1 * number('4.0'))"), STR("-4")); - - CHECK_XPATH_STRING(c, STR("string(number('0.04'))"), STR("0.04")); - CHECK_XPATH_STRING(c, STR("string(-1 * number('0.04'))"), STR("-0.04")); - - CHECK_XPATH_STRING(c, STR("string(number('0.004'))"), STR("0.004")); - CHECK_XPATH_STRING(c, STR("string(-1 * number('0.004'))"), STR("-0.004")); - - CHECK_XPATH_STRING(c, STR("string(number('0.0004'))"), STR("0.0004")); - CHECK_XPATH_STRING(c, STR("string(-1 * number('0.0004'))"), STR("-0.0004")); - - CHECK_XPATH_STRING(c, STR("string(number('0.0000000000001'))"), STR("0.0000000000001")); - CHECK_XPATH_STRING(c, STR("string(-1 * number('0.0000000000001'))"), STR("-0.0000000000001")); - - CHECK_XPATH_STRING(c, STR("string(number('0.0000000000000000000000000001'))"), STR("0.0000000000000000000000000001")); - CHECK_XPATH_STRING(c, STR("string(-1 * number('0.0000000000000000000000000001'))"), STR("-0.0000000000000000000000000001")); - - CHECK_XPATH_STRING(c, STR("string(number('0.0000000000001000000000000001'))"), STR("0.0000000000001000000000000001")); - CHECK_XPATH_STRING(c, STR("string(-1 * number('0.0000000000001000000000000001'))"), STR("-0.0000000000001000000000000001")); - - CHECK_XPATH_STRING(c, STR("string(number('0.0012'))"), STR("0.0012")); - CHECK_XPATH_STRING(c, STR("string(-1 * number('0.0012'))"), STR("-0.0012")); - - CHECK_XPATH_STRING(c, STR("string(number('0.012'))"), STR("0.012")); - CHECK_XPATH_STRING(c, STR("string(-1 * number('0.012'))"), STR("-0.012")); -} - -#endif +#ifndef PUGIXML_NO_XPATH + +#include "common.hpp" + +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, "") +{ + 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, "foobarfoobarfoo") +{ + 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, "firstsecondthirdfourth") +{ + 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, "12345678") +{ + 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, "truefalse?10") +{ + 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, "b") +{ + 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, "3") +{ + 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, "3") +{ + 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, "24517-58-37") +{ + 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, "231237212
5
2
") +{ + 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, "37x") +{ + 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, "37x") +{ + 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, "0.0004") +{ + 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); + CHECK_XPATH_BOOLEAN(doc, STR("(number(k) = (4 div 10000))"), 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 diff --git a/tests/test_xpath_xalan_2.cpp b/tests/test_xpath_xalan_2.cpp index abc6a1c..aa8ae17 100644 --- a/tests/test_xpath_xalan_2.cpp +++ b/tests/test_xpath_xalan_2.cpp @@ -1,399 +1,399 @@ -#ifndef PUGIXML_NO_XPATH - -#define _CRT_SECURE_NO_WARNINGS - -#include "common.hpp" - -#include - -TEST_XML(xpath_xalan_string_1, "ENCYCLOPEDIA") -{ - 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, "\n \n \n b\n c\n d\n e\n \n \n w\n x\n y\n z\n \n \n", 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, "ENCYCLOPEDIA") -{ - 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, "abcdefwhat's up") -{ - 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 std::basic_string number_to_string(int number) -{ - std::basic_string result; - - while (number) - { - result = static_cast('0' + number % 10) + result; - number /= 10; - } - - return result; -} - -TEST(xpath_xalan_string_5) -{ - std::basic_string query = STR("concat("); - - for (int i = 1; i < 1000; ++i) - { - query += STR("concat('t',"); - query += number_to_string(i); - query += STR("), "); - } - - query += STR("'')"); - - std::basic_string expected; - - for (int j = 1; j < 1000; ++j) - { - expected += STR("t"); - expected += number_to_string(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 +#ifndef PUGIXML_NO_XPATH + +#define _CRT_SECURE_NO_WARNINGS + +#include "common.hpp" + +#include + +TEST_XML(xpath_xalan_string_1, "ENCYCLOPEDIA") +{ + 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, "\n \n \n b\n c\n d\n e\n \n \n w\n x\n y\n z\n \n \n", 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, "ENCYCLOPEDIA") +{ + 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, "abcdefwhat's up") +{ + 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 std::basic_string number_to_string(int number) +{ + std::basic_string result; + + while (number) + { + result = static_cast('0' + number % 10) + result; + number /= 10; + } + + return result; +} + +TEST(xpath_xalan_string_5) +{ + std::basic_string query = STR("concat("); + + for (int i = 1; i < 1000; ++i) + { + query += STR("concat('t',"); + query += number_to_string(i); + query += STR("), "); + } + + query += STR("'')"); + + std::basic_string expected; + + for (int j = 1; j < 1000; ++j) + { + expected += STR("t"); + expected += number_to_string(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 diff --git a/tests/test_xpath_xalan_3.cpp b/tests/test_xpath_xalan_3.cpp index ee9253d..54b8a62 100644 --- a/tests/test_xpath_xalan_3.cpp +++ b/tests/test_xpath_xalan_3.cpp @@ -1,319 +1,319 @@ -#ifndef PUGIXML_NO_XPATH - -#include "common.hpp" - -TEST_XML(xpath_xalan_axes_1, "
") -{ - xml_node center = doc.select_single_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, " Level-1 Level-2 Level-3 Level-4
Level-5 Level-6
", parse_default | parse_comments | parse_pi) -{ - xml_node center = doc.select_single_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, "
") -{ - xml_node center = doc.select_single_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, "
") -{ - xml_node north = doc.select_single_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", 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, "Test for source tree depthABCDEFGHIJKLMNO") -{ - 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, "
") -{ - xml_node center = doc.select_single_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, "
") -{ - xml_node near_north = doc.select_single_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, "") -{ - xml_node baz = doc.select_single_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, "") -{ - 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, "
helloahoy
goodbyesayonaraadios
alohaA3b-1A3b-2shalom
") -{ - 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, "north-text1
center-text1south-textcenter-text2
north-text2
", 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, "") -{ - xml_node d = doc.child(STR("doc")); - xml_node baz = doc.select_single_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, "text
text", 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, "is newxyzis new but has textis not new") -{ - 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, "") -{ - 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, "here") -{ - CHECK_XPATH_NODESET(doc, STR("//xx/descendant::*")) % 10 % 20 % 24 % 26 % 27; -} - -TEST_XML(xpath_xalan_axes_18, "
") -{ - xml_node center = doc.child(STR("north")).child(STR("center")); - - CHECK_XPATH_NODESET(center, STR("@*/self::node()")) % 4; - CHECK_XPATH_NODESET(center, STR("@*/self::*")); // * tests for principal node type - CHECK_XPATH_NODESET(center, STR("@*/self::text()")); - CHECK_XPATH_NODESET(center, STR("@*/self::center-attr")); // * tests for principal node type -} - -#endif +#ifndef PUGIXML_NO_XPATH + +#include "common.hpp" + +TEST_XML(xpath_xalan_axes_1, "
") +{ + xml_node center = doc.select_single_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, " Level-1 Level-2 Level-3 Level-4
Level-5 Level-6
", parse_default | parse_comments | parse_pi) +{ + xml_node center = doc.select_single_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, "
") +{ + xml_node center = doc.select_single_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, "
") +{ + xml_node north = doc.select_single_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", 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, "Test for source tree depthABCDEFGHIJKLMNO") +{ + 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, "
") +{ + xml_node center = doc.select_single_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, "
") +{ + xml_node near_north = doc.select_single_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, "") +{ + xml_node baz = doc.select_single_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, "") +{ + 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, "
helloahoy
goodbyesayonaraadios
alohaA3b-1A3b-2shalom
") +{ + 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, "north-text1
center-text1south-textcenter-text2
north-text2
", 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, "") +{ + xml_node d = doc.child(STR("doc")); + xml_node baz = doc.select_single_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, "text
text", 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, "is newxyzis new but has textis not new") +{ + 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, "") +{ + 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, "here") +{ + CHECK_XPATH_NODESET(doc, STR("//xx/descendant::*")) % 10 % 20 % 24 % 26 % 27; +} + +TEST_XML(xpath_xalan_axes_18, "
") +{ + 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 diff --git a/tests/test_xpath_xalan_4.cpp b/tests/test_xpath_xalan_4.cpp index 10784da..c71eaf7 100644 --- a/tests/test_xpath_xalan_4.cpp +++ b/tests/test_xpath_xalan_4.cpp @@ -1,298 +1,298 @@ -#ifndef PUGIXML_NO_XPATH - -#include "common.hpp" - -TEST_XML(xpath_xalan_position_1, "1234") -{ - 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, "111912632827256345", 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, "
AAA
BBBAbout this article
CCCThis is the section titled 'ZZZ'.DDDDon't worry.
EEEThis is the deep subsection.
") -{ - 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, "
hello
goodbyesayonara
aloha
") -{ - CHECK_XPATH_NODESET(doc, STR("chapter//footnote[1]")) % 4 % 7 % 12; -} - -TEST_XML(xpath_xalan_position_5, "
helloahoy
goodbyesayonaraadios
alohashalomyociao
") -{ - 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, "pcdata", 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, "
helloahoy
goodbyesayonaraadios
alohaA3b-1A3b-2shalom
") -{ - 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, "") -{ - 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-v2doc-l1-x2doc-l1-l2-v3doc-l1-l2-w3doc-l1-l2-x3doc-l1-l2-y3doc-l1-l2-l3-v4doc-l1-l2-l3-x4") -{ - 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, "John DoeJane Doe") -{ - 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, "en
en
ENen-us
") -{ - 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, "1234") -{ - 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, "") -{ - 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, "12345") -{ - 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, "
configuration".(split /\s+/)[0]."
$define" . ($present ? "+" : " ") . "
$platform$toolset pass"; + + if ($coverage_pugixml > 0 || $coverage_pugixpath > 0) + { + print "
" . ($coverage_pugixml + 0) . "%
" . ($coverage_pugixpath + 0) . "%
"; + } + + print "
fail
text1text2text3text4
text1text2text3text4
1.11.2
2.12.22.3
3.13.23.2.1
44.14.1.1
5.15.25.35.4
6.16.2
7.17.27.3
8.18.28.38.4
") -{ - 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, "Wrong node selected!!Test executed successfullyWrong node selected!!") -{ - 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, "12target34") -{ - 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, "12target34missed") -{ - 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, "this23thisthisthathellogoodbyethisthatthishellogoodbyeother") -{ - 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, "f-insidef-insidef-insidef-insidef-inside") -{ - 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, "Text from first elementText from child1 of first elementText from child2 of first elementText from second elementText from child1 of second elementText from child2 of second element (correct execution)") -{ - 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, "123456") -{ - 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, "12target3target") -{ - CHECK_XPATH_STRING(doc, STR("doc/a[following-sibling::*=descendant::*]"), STR("2target")); -} - -TEST_XML(xpath_xalan_predicate_13, "12target3") -{ - 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, "12child234child4") -{ - CHECK_XPATH_NODESET(doc, STR("doc/a[not(@*)]")) % 6 % 11; -} - -TEST_XML(xpath_xalan_predicate_15, "xinside") -{ - CHECK_XPATH_NODESET(doc, STR("doc/descendant::*[string-length(name(.))=1]")) % 3 % 6 % 9 % 11 % 13; -} - -#endif +#ifndef PUGIXML_NO_XPATH + +#include "common.hpp" + +TEST_XML(xpath_xalan_position_1, "1234") +{ + 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, "111912632827256345", 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, "
AAA
BBBAbout this article
CCCThis is the section titled 'ZZZ'.DDDDon't worry.
EEEThis is the deep subsection.
") +{ + 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, "
hello
goodbyesayonara
aloha
") +{ + CHECK_XPATH_NODESET(doc, STR("chapter//footnote[1]")) % 4 % 7 % 12; +} + +TEST_XML(xpath_xalan_position_5, "
helloahoy
goodbyesayonaraadios
alohashalomyociao
") +{ + 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, "pcdata", 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, "
helloahoy
goodbyesayonaraadios
alohaA3b-1A3b-2shalom
") +{ + 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, "") +{ + 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-v2doc-l1-x2doc-l1-l2-v3doc-l1-l2-w3doc-l1-l2-x3doc-l1-l2-y3doc-l1-l2-l3-v4doc-l1-l2-l3-x4") +{ + 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, "John DoeJane Doe") +{ + 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, "en
en
ENen-us
") +{ + 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, "1234") +{ + 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, "") +{ + 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, "12345") +{ + 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, "
1.11.2
2.12.22.3
3.13.23.2.1
44.14.1.1
5.15.25.35.4
6.16.2
7.17.27.3
8.18.28.38.4
") +{ + 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, "Wrong node selected!!Test executed successfullyWrong node selected!!") +{ + 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, "12target34") +{ + 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, "12target34missed") +{ + 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, "this23thisthisthathellogoodbyethisthatthishellogoodbyeother") +{ + 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, "f-insidef-insidef-insidef-insidef-inside") +{ + 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, "Text from first elementText from child1 of first elementText from child2 of first elementText from second elementText from child1 of second elementText from child2 of second element (correct execution)") +{ + 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, "123456") +{ + 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, "12target3target") +{ + CHECK_XPATH_STRING(doc, STR("doc/a[following-sibling::*=descendant::*]"), STR("2target")); +} + +TEST_XML(xpath_xalan_predicate_13, "12target3") +{ + 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, "12child234child4") +{ + CHECK_XPATH_NODESET(doc, STR("doc/a[not(@*)]")) % 6 % 11; +} + +TEST_XML(xpath_xalan_predicate_15, "xinside") +{ + CHECK_XPATH_NODESET(doc, STR("doc/descendant::*[string-length(name(.))=1]")) % 3 % 6 % 9 % 11 % 13; +} + +#endif diff --git a/tests/test_xpath_xalan_5.cpp b/tests/test_xpath_xalan_5.cpp index 3a71bc2..e6a4fb9 100644 --- a/tests/test_xpath_xalan_5.cpp +++ b/tests/test_xpath_xalan_5.cpp @@ -1,293 +1,293 @@ -#ifndef PUGIXML_NO_XPATH - -#include "common.hpp" - -TEST_XML(xpath_xalan_select_1, "") -{ - CHECK_XPATH_STRING(doc, STR("/doc/a/b/@attr"), STR("test")); -} - -TEST_XML(xpath_xalan_select_2, "doremifasolatidoG#AAbBbCC#D") -{ - 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, "preceding sibling number 1current nodefollowing sibling number 3cousin 1cousin 2cousin 3") -{ - 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, "bad1bad2bad3bad4OKbad5") -{ - 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, "bad0bad1bad2", 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, "
9
") -{ - 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, "
9
8
") -{ - 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, "x
7
y
9
z
5
") -{ - CHECK_XPATH_NODESET(doc, STR("doc/a[div=9]")) % 7; -} - -TEST_XML(xpath_xalan_select_9, "7379929920") -{ - CHECK_XPATH_NODESET(doc, STR("doc/a[*=9]")) % 9 % 15 % 21; -} - -TEST_XML(xpath_xalan_select_10, "child1child2") -{ - 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, "descendant number 1descendant number 2") -{ - CHECK_XPATH_NODESET(doc, STR("//child1/ancestor::sub1|//child1/ancestor::sub2")) % 3 % 7; -} - -TEST_XML(xpath_xalan_select_12, "child number 1grandchild number 1child number 2grandchild number 2child number 3grandchild number 3child number 4grandchild number 4") -{ - 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, "Carmelo MontanezNineDavid MarstonSevenMary BradyTenLynne RosenthalFive") -{ - 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, "child number 1child number 2") -{ - 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, "Selection of this child is an error.Selection of this child is an error.Selection of this child is an error.Selection of this child is an error.EFGSelection of this child is an error.Selection of this child is an error.JKSelection of this child is an error.Selection of this child is an error.NOP") -{ - 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, "1234") -{ - 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, "") -{ - 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, "HelloThereWorld") -{ - 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, "1in-a2345678in-c9", 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, "15152252") -{ - CHECK_XPATH_NODESET(doc, STR("/report/colData[@colId='F' and not(.=preceding::colData)]")) % 3; -} - -TEST(xpath_xalan_error_boolean) -{ - CHECK_XPATH_FAIL(STR("nt(true())")); - CHECK_XPATH_FAIL(STR("not(troo())")); - CHECK_XPATH_FAIL(STR("troo() and (2 = 2)")); - CHECK_XPATH_FAIL(STR("troo() or (2 = 2)")); - CHECK_XPATH_FAIL(STR("2 = troo()")); - CHECK_XPATH_FAIL(STR("boolean(troo())")); - CHECK_XPATH_FAIL(STR("true(doc)")); - CHECK_XPATH_FAIL(STR("false(doc)")); - CHECK_XPATH_FAIL(STR("not()")); - CHECK_XPATH_FAIL(STR("not(false(), doc)")); - CHECK_XPATH_FAIL(STR("boolean()")); - CHECK_XPATH_FAIL(STR("boolean(false(), doc)")); - CHECK_XPATH_FAIL(STR("lang()")); - CHECK_XPATH_FAIL(STR("lang('en','us')")); -} - -TEST(xpath_xalan_error_conditional) -{ - CHECK_XPATH_FAIL(STR("")); - CHECK_XPATH_FAIL(STR("@name='John' | @name='Joe'")); - CHECK_XPATH_FAIL(STR("\x95not(name(.)='')")); -} - -TEST(xpath_xalan_error_match) -{ - CHECK_XPATH_FAIL(STR("//")); - CHECK_XPATH_FAIL(STR("section1|")); - CHECK_XPATH_FAIL(STR("|section1")); -} - -TEST(xpath_xalan_error_math) -{ - CHECK_XPATH_FAIL(STR("6 quo 4")); - CHECK_XPATH_FAIL(STR("-troo()")); - CHECK_XPATH_FAIL(STR("number(troo())")); - CHECK_XPATH_FAIL(STR("5 * troo()")); - CHECK_XPATH_FAIL(STR("12 div troo()")); - CHECK_XPATH_FAIL(STR("number(8,doc)")); - CHECK_XPATH_FAIL(STR("sum(doc, 8)")); - CHECK_XPATH_FAIL(STR("sum()")); - CHECK_XPATH_FAIL(STR("floor(8,7)")); - CHECK_XPATH_FAIL(STR("floor()")); - CHECK_XPATH_FAIL(STR("ceiling(8,7)")); - CHECK_XPATH_FAIL(STR("ceiling()")); - CHECK_XPATH_FAIL(STR("round(8,7)")); - CHECK_XPATH_FAIL(STR("round()")); -} - -TEST(xpath_xalan_error_namespace) -{ - CHECK_XPATH_FAIL(STR("local-name(baz2:b,..)")); - CHECK_XPATH_FAIL(STR("namespace-uri(baz2:b,..)")); - CHECK_XPATH_FAIL(STR("name(a,b)")); - CHECK_XPATH_FAIL(STR(":foo")); - CHECK_XPATH_FAIL(STR("*:foo")); -} - -TEST(xpath_xalan_error_position) -{ - CHECK_XPATH_FAIL(STR("*[last(*,2)]")); - CHECK_XPATH_FAIL(STR("position(b)=1")); - CHECK_XPATH_FAIL(STR("count()")); - CHECK_XPATH_FAIL(STR("count(*,4)")); - CHECK_XPATH_FAIL(STR("position()=last(a)")); -} - -TEST(xpath_xalan_error_select) -{ - CHECK_XPATH_FAIL(STR("")); - CHECK_XPATH_FAIL(STR("count(troo())")); - CHECK_XPATH_FAIL(STR("c::sub")); - CHECK_XPATH_FAIL(STR("c()")); - CHECK_XPATH_FAIL(STR("(* - 4) foo 2")); - CHECK_XPATH_FAIL(STR("5 . + *")); - CHECK_XPATH_FAIL(STR("4/.")); - CHECK_XPATH_FAIL(STR("true()/.")); - CHECK_XPATH_FAIL(STR("item//[@type='x']")); - CHECK_XPATH_FAIL(STR("//")); - CHECK_XPATH_FAIL(STR("item//")); - CHECK_XPATH_FAIL(STR("count(//)")); - CHECK_XPATH_FAIL(STR("substring-after(//,'0')")); - CHECK_XPATH_FAIL(STR("//+17")); - CHECK_XPATH_FAIL(STR("//|subitem")); - CHECK_XPATH_FAIL(STR("..[near-north]")); -} - -TEST(xpath_xalan_error_string) -{ - CHECK_XPATH_FAIL(STR("string(troo())")); - CHECK_XPATH_FAIL(STR("string-length(troo())")); - CHECK_XPATH_FAIL(STR("normalize-space(a,'\t\r\n ab cd ')")); - CHECK_XPATH_FAIL(STR("contains('ENCYCLOPEDIA')")); - CHECK_XPATH_FAIL(STR("contains('ENCYCLOPEDIA','LOPE',doc)")); - CHECK_XPATH_FAIL(STR("starts-with('ENCYCLOPEDIA')")); - CHECK_XPATH_FAIL(STR("starts-with('ENCYCLOPEDIA','LOPE',doc)")); - CHECK_XPATH_FAIL(STR("substring-before('ENCYCLOPEDIA')")); - CHECK_XPATH_FAIL(STR("substring-before('ENCYCLOPEDIA','LOPE',doc)")); - CHECK_XPATH_FAIL(STR("substring-after('ENCYCLOPEDIA')")); - CHECK_XPATH_FAIL(STR("substring-after('ENCYCLOPEDIA','LOPE',doc)")); - CHECK_XPATH_FAIL(STR("substring('ENCYCLOPEDIA')")); - CHECK_XPATH_FAIL(STR("substring('ENCYCLOPEDIA',4,5,2)")); - CHECK_XPATH_FAIL(STR("concat('x')")); - CHECK_XPATH_FAIL(STR("string-length('ENCYCLOPEDIA','PEDI')")); - CHECK_XPATH_FAIL(STR("translate('bar','abc')")); - CHECK_XPATH_FAIL(STR("translate('bar','abc','ABC','output')")); - CHECK_XPATH_FAIL(STR("string(22,44)")); - CHECK_XPATH_FAIL(STR("concat(/*)")); -} - -#endif +#ifndef PUGIXML_NO_XPATH + +#include "common.hpp" + +TEST_XML(xpath_xalan_select_1, "") +{ + CHECK_XPATH_STRING(doc, STR("/doc/a/b/@attr"), STR("test")); +} + +TEST_XML(xpath_xalan_select_2, "doremifasolatidoG#AAbBbCC#D") +{ + 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, "preceding sibling number 1current nodefollowing sibling number 3cousin 1cousin 2cousin 3") +{ + 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, "bad1bad2bad3bad4OKbad5") +{ + 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, "bad0bad1bad2", 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, "
9
") +{ + 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, "
9
8
") +{ + 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, "x
7
y
9
z
5
") +{ + CHECK_XPATH_NODESET(doc, STR("doc/a[div=9]")) % 7; +} + +TEST_XML(xpath_xalan_select_9, "7379929920") +{ + CHECK_XPATH_NODESET(doc, STR("doc/a[*=9]")) % 9 % 15 % 21; +} + +TEST_XML(xpath_xalan_select_10, "child1child2") +{ + 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, "descendant number 1descendant number 2") +{ + CHECK_XPATH_NODESET(doc, STR("//child1/ancestor::sub1|//child1/ancestor::sub2")) % 3 % 7; +} + +TEST_XML(xpath_xalan_select_12, "child number 1grandchild number 1child number 2grandchild number 2child number 3grandchild number 3child number 4grandchild number 4") +{ + 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, "Carmelo MontanezNineDavid MarstonSevenMary BradyTenLynne RosenthalFive") +{ + 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, "child number 1child number 2") +{ + 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, "Selection of this child is an error.Selection of this child is an error.Selection of this child is an error.Selection of this child is an error.EFGSelection of this child is an error.Selection of this child is an error.JKSelection of this child is an error.Selection of this child is an error.NOP") +{ + 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, "1234") +{ + 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, "") +{ + 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, "HelloThereWorld") +{ + 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, "1in-a2345678in-c9", 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, "15152252") +{ + 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 diff --git a/tests/writer_string.cpp b/tests/writer_string.cpp index 878a103..f35b461 100644 --- a/tests/writer_string.cpp +++ b/tests/writer_string.cpp @@ -1,77 +1,77 @@ -#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 += std::string(static_cast(data), size); -} - -std::string xml_writer_string::as_narrow() const -{ - return contents; -} - -std::wstring xml_writer_string::as_wide() const -{ - CHECK(contents.size() % sizeof(wchar_t) == 0); - - return std::wstring(reinterpret_cast(contents.data()), contents.size() / sizeof(wchar_t)); -} - -std::basic_string 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 - - return std::basic_string(reinterpret_cast(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(""), 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(""), 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::wstring write_wide(pugi::xml_node node, unsigned int flags, pugi::xml_encoding encoding) -{ - xml_writer_string writer; - - node.print(writer, STR(""), flags, encoding); - - return writer.as_wide(); -} +#include "writer_string.hpp" + +#include "test.hpp" + +static bool test_narrow(const std::string& result, const char* expected, size_t length) +{ + // check result + if (result != std::string(expected, expected + length)) return false; + + // check comparison operator (incorrect implementation can theoretically early-out on zero terminators...) + if (length > 0 && result == std::string(expected, expected + length - 1) + "?") return false; + + return true; +} + +void xml_writer_string::write(const void* data, size_t size) +{ + contents += std::string(static_cast(data), size); +} + +std::string xml_writer_string::as_narrow() const +{ + return contents; +} + +std::wstring xml_writer_string::as_wide() const +{ + CHECK(contents.size() % sizeof(wchar_t) == 0); + + return std::wstring(reinterpret_cast(contents.data()), contents.size() / sizeof(wchar_t)); +} + +std::basic_string 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 + + return std::basic_string(reinterpret_cast(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(""), 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(""), 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::wstring write_wide(pugi::xml_node node, unsigned int flags, pugi::xml_encoding encoding) +{ + xml_writer_string writer; + + node.print(writer, STR(""), flags, encoding); + + return writer.as_wide(); +} diff --git a/tests/writer_string.hpp b/tests/writer_string.hpp index acf6318..390f93b 100644 --- a/tests/writer_string.hpp +++ b/tests/writer_string.hpp @@ -1,27 +1,27 @@ -#ifndef HEADER_TEST_WRITER_STRING_HPP -#define HEADER_TEST_WRITER_STRING_HPP - -#include "../src/pugixml.hpp" - -#include - -struct xml_writer_string: public pugi::xml_writer -{ - std::string contents; - - virtual void write(const void* data, size_t size); - - std::string as_narrow() const; - std::wstring as_wide() const; - std::basic_string 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::wstring write_wide(pugi::xml_node node, unsigned int flags, pugi::xml_encoding encoding); - -#endif +#ifndef HEADER_TEST_WRITER_STRING_HPP +#define HEADER_TEST_WRITER_STRING_HPP + +#include "../src/pugixml.hpp" + +#include + +struct xml_writer_string: public pugi::xml_writer +{ + std::string contents; + + virtual void write(const void* data, size_t size); + + std::string as_narrow() const; + std::wstring as_wide() const; + std::basic_string 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::wstring write_wide(pugi::xml_node node, unsigned int flags, pugi::xml_encoding encoding); + +#endif -- cgit v1.2.3