mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-04-27 12:13:48 +02:00
1022 lines
39 KiB
ObjectPascal
1022 lines
39 KiB
ObjectPascal
{**********************************************************************
|
|
|
|
This file is part of the Free Component Library (FCL)
|
|
|
|
Test suite for the xpath.pp unit.
|
|
Largely based on expressions from libxml2 source tree.
|
|
Copyright (c) 2009 by Sergei Gorelkin, sergei_gorelkin@mail.ru
|
|
|
|
See the file COPYING.FPC, included in this distribution,
|
|
for details about the copyright.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
|
|
**********************************************************************}
|
|
program xpathts;
|
|
{$mode delphi}{$h+}
|
|
|
|
uses
|
|
Classes, SysUtils, Math,
|
|
dom, xmlread, xmlwrite, xpath;
|
|
|
|
type
|
|
TResultType = (rtString, rtNumber, rtBool, rtNodeStr, rtOther);
|
|
|
|
TTestRec = record
|
|
data: string; // UTF-8 encoded
|
|
expr: DOMString;
|
|
case rt: TResultType of
|
|
rtString, rtNodeStr: (s: DOMPChar); // cannot use DOMString here
|
|
rtNumber: (n: Extended);
|
|
rtBool: (b: Boolean);
|
|
end;
|
|
|
|
TTestRec3 = record
|
|
data: string; // UTF-8 encoded
|
|
re: string;
|
|
expr: DOMString;
|
|
case rt: TResultType of
|
|
rtString, rtNodeStr: (s: DOMPChar); // cannot use DOMString here
|
|
rtNumber: (n: Extended);
|
|
rtBool: (b: Boolean);
|
|
end;
|
|
|
|
{$warnings off}
|
|
const
|
|
BaseTests: array[0..4] of TTestRec = (
|
|
(expr: '1'; rt: rtNumber; n: 1),
|
|
(expr: '1+2'; rt: rtNumber; n: 3),
|
|
(expr: '2*3'; rt: rtNumber; n: 6),
|
|
(expr: '1+2*3+4'; rt: rtNumber; n: 11),
|
|
(expr: '(1+2)*(3+4)'; rt: rtNumber; n: 21)
|
|
);
|
|
|
|
CompareTests: array[0..46] of TTestRec = (
|
|
(expr: '0<0'; rt: rtBool; b: False),
|
|
(expr: '0<=0'; rt: rtBool; b: True),
|
|
(expr: '0>0'; rt: rtBool; b: False),
|
|
(expr: '0>=0'; rt: rtBool; b: True),
|
|
(expr: '0<1'; rt: rtBool; b: True),
|
|
(expr: '0<=1'; rt: rtBool; b: True),
|
|
(expr: '0>1'; rt: rtBool; b: False),
|
|
(expr: '0>=1'; rt: rtBool; b: False),
|
|
(expr: '1<0'; rt: rtBool; b: False),
|
|
(expr: '1<=0'; rt: rtBool; b: False),
|
|
(expr: '1>0'; rt: rtBool; b: True),
|
|
(expr: '1>=0'; rt: rtBool; b: True),
|
|
(expr: '1<1'; rt: rtBool; b: False),
|
|
(expr: '1<=1'; rt: rtBool; b: True),
|
|
(expr: '1>1'; rt: rtBool; b: False),
|
|
(expr: '1>=1'; rt: rtBool; b: True),
|
|
(expr: '0>-0'; rt: rtBool; b: False),
|
|
(expr: '"0"<1'; rt: rtBool; b: True),
|
|
(expr: '"0"<=1'; rt: rtBool; b: True),
|
|
(expr: '"0">1'; rt: rtBool; b: False),
|
|
(expr: '"0">=1'; rt: rtBool; b: False),
|
|
(expr: '0<"1.2"'; rt: rtBool; b: True),
|
|
(expr: '0<="1.2"'; rt: rtBool; b: True),
|
|
(expr: '0>"1.2"'; rt: rtBool; b: False),
|
|
(expr: '0>="1.2"'; rt: rtBool; b: False),
|
|
(expr: '0<"-0.2"'; rt: rtBool; b: False),
|
|
(expr: '0<="-0.2"'; rt: rtBool; b: False),
|
|
(expr: '0>"-0.2"'; rt: rtBool; b: True),
|
|
(expr: '0>="-0.2"'; rt: rtBool; b: True),
|
|
(expr: 'false()<1'; rt: rtBool; b: True),
|
|
(expr: 'false()<=1'; rt: rtBool; b: True),
|
|
(expr: '0>true()'; rt: rtBool; b: False),
|
|
(expr: '0>=true()'; rt: rtBool; b: False),
|
|
(expr: '"a" > "a"'; rt: rtBool; b: False),
|
|
(expr: '"a" > "b"'; rt: rtBool; b: False),
|
|
(expr: '"b" > "a"'; rt: rtBool; b: False),
|
|
(expr: '"a" < "a"'; rt: rtBool; b: False),
|
|
(expr: '"a" < "b"'; rt: rtBool; b: False),
|
|
(expr: '"b" < "a"'; rt: rtBool; b: False),
|
|
(expr: '"a" >= "a"'; rt: rtBool; b: False),
|
|
(expr: '"a" >= "b"'; rt: rtBool; b: False),
|
|
(expr: '"b" >= "a"'; rt: rtBool; b: False),
|
|
(expr: '"a" <= "a"'; rt: rtBool; b: False),
|
|
(expr: '"a" <= "b"'; rt: rtBool; b: False),
|
|
(expr: '"b" <= "a"'; rt: rtBool; b: False),
|
|
(expr: '"a" > "0.0"'; rt: rtBool; b: False),
|
|
(expr: '"a" < "0.0"'; rt: rtBool; b: False)
|
|
);
|
|
|
|
nscmp = '<doc>'#10+
|
|
'<j l="12" w="33">first</j>'#10+
|
|
'<j l="17" w="45">second</j>'#10+
|
|
'<j l="16" w="78">third</j>'#10+
|
|
'<j l="12" w="33">fourth</j>'#10+
|
|
'</doc>';
|
|
|
|
nscmp2 = '<doc>'#10+
|
|
'<j l="12" w="45">first</j>'#10+
|
|
'<j l="17" w="45">second</j>'#10+
|
|
'<j l="16" w="78">third</j>'#10+
|
|
'<j l="12" w="33">fourth</j>'#10+
|
|
'</doc>';
|
|
|
|
simple = '<doc>test</doc>';
|
|
|
|
bool58 = '<doc>'#10+
|
|
'<av>'#10+
|
|
' <a>'#10+
|
|
' <b>b</b>'#10+
|
|
' <c>c</c>'#10+
|
|
' <d>d</d>'#10+
|
|
' <e>e</e>'#10+
|
|
' </a>'#10+
|
|
' <v>'#10+
|
|
' <w>w</w>'#10+
|
|
' <x>x</x>'#10+
|
|
' <y>y</y>'#10+
|
|
' <z>z</z>'#10+
|
|
' </v>'#10+
|
|
' <a>'#10+
|
|
' <b>fe</b>'#10+
|
|
' <c>fi</c>'#10+
|
|
' <d>fo</d>'#10+
|
|
' <e>fu</e>'#10+
|
|
' </a>'#10+
|
|
' <v>'#10+
|
|
' <w>fee</w>'#10+
|
|
' <x>fii</x>'#10+
|
|
' <y>foo</y>'#10+
|
|
' <z>fom</z>'#10+
|
|
' </v>'#10+
|
|
' <j>foo</j>'#10+
|
|
' <j>foo</j>'#10+
|
|
' <j>foo</j>'#10+
|
|
' <j>foo</j>'#10+
|
|
'</av>'#10+
|
|
'</doc>';
|
|
|
|
bool84='<doc>'#10+
|
|
'<avj>'#10+
|
|
' <good>'#10+
|
|
' <b>12</b>'#10+
|
|
' <c>34</c>'#10+
|
|
' <d>56</d>'#10+
|
|
' <e>78</e>'#10+
|
|
' </good>'#10+
|
|
'</avj>'#10+
|
|
'</doc>';
|
|
|
|
bool85='<doc>'#10+
|
|
'<avj>'#10+
|
|
' <bool>'#10+
|
|
' <b>true</b>'#10+
|
|
' <c></c>'#10+
|
|
' <d>false?</d>'#10+
|
|
' <e>1</e>'#10+
|
|
' <f>0</f>'#10+
|
|
' </bool>'#10+
|
|
'</avj>'#10+
|
|
'</doc>';
|
|
|
|
str04='<doc>'#10+
|
|
'<a>Testing this</a>'#10+
|
|
'<b>and this too</b>'#10+
|
|
'</doc>';
|
|
|
|
NodesetCompareTests: array[0..38] of TTestRec = (
|
|
{ same nodeset }
|
|
(data: nscmp; expr: 'j[@l="12"] = j[@w="33"]'; rt: rtBool; b: True), // #70
|
|
{ disjoint nodesets }
|
|
(data: nscmp; expr: 'j[@l="12"] = j[@l="17"]'; rt: rtBool; b: False), // #71
|
|
{ both have one common node }
|
|
(data: nscmp2; expr: 'j[@l="12"] = j[@w="45"]'; rt: rtBool; b: True), // #72
|
|
{ same nodeset - unequal }
|
|
(data: nscmp; expr: 'j[@l="12"] != j[@w="33"]'; rt: rtBool; b: True), // #73
|
|
{ disjoint - unequal }
|
|
(data: nscmp; expr: 'j[@l="12"] != j[@l="17"]'; rt: rtBool; b: True), // #74
|
|
{ one common node - unequal }
|
|
(data: nscmp2; expr: 'j[@l="12"] != j[@w="45"]'; rt: rtBool; b: True), // #75
|
|
{ single common node - unequal }
|
|
(data: nscmp2; expr: 'j[@l="16"] != j[@w="78"]'; rt: rtBool; b: False),// #76
|
|
{ nodeset vs. string }
|
|
(data: bool58; expr: '/doc/av//*="foo"'; rt: rtBool; b: True), // #58.1
|
|
(data: bool58; expr: 'not(/doc/av//*!="foo")'; rt: rtBool; b: False), // #58.2
|
|
(data: bool58; expr: '/doc/av//j="foo"'; rt: rtBool; b: True), // #58.3
|
|
(data: bool58; expr: 'not(/doc/av//j!="foo")'; rt: rtBool; b: True), // #58.4
|
|
{ empty nodeset vs. string. Data differs, but that doesn't matter }
|
|
(data: bool58; expr: '/doc/avj//k="foo"'; rt: rtBool; b: False), // #59.1
|
|
(data: bool58; expr: 'not(/doc/avj//k="foo")'; rt: rtBool; b: True), // #59.2
|
|
(data: bool58; expr: '/doc/avj//k!="foo"'; rt: rtBool; b: False), // #59.3
|
|
(data: bool58; expr: 'not(/doc/avj//k!="foo")'; rt: rtBool; b: True), // #59.4
|
|
{ nodeset vs. number }
|
|
(data: bool84; expr: '/doc/avj/good/*=34'; rt: rtBool; b: True), // #84.1
|
|
(data: bool84; expr: 'not(/doc/avj/good/*=34)'; rt: rtBool; b: False), // #84.2
|
|
(data: bool84; expr: '/doc/avj/good/*!=34'; rt: rtBool; b: True), // #84.3
|
|
(data: bool84; expr: 'not(/doc/avj/good/*!=34)'; rt: rtBool; b: False),// #84.4
|
|
{ same with reversed order of operands }
|
|
(data: bool84; expr: '34=/doc/avj/good/*'; rt: rtBool; b: True), // #84.5
|
|
(data: bool84; expr: 'not(34=/doc/avj/good/*)'; rt: rtBool; b: False), // #84.6
|
|
(data: bool84; expr: '34!=/doc/avj/good/*'; rt: rtBool; b: True), // #84.7
|
|
(data: bool84; expr: 'not(34!=/doc/avj/good/*)'; rt: rtBool; b: False),// #84.8
|
|
{ nodeset vs. boolean }
|
|
(data: bool85; expr: '/doc/avj/bool/*=true()'; rt: rtBool; b: True), // #85.1
|
|
(data: bool85; expr: 'not(/doc/avj/bool/*=true())'; rt: rtBool; b: False), // #85.2
|
|
(data: bool85; expr: '/doc/avj/bool/*!=true()'; rt: rtBool; b: False), // #85.3
|
|
(data: bool85; expr: 'not(/doc/avj/bool/*!=true())'; rt: rtBool; b: True), // #85.4
|
|
{ same with reversed order of operands }
|
|
(data: bool85; expr: 'true()=/doc/avj/bool/*'; rt: rtBool; b: True), // #85.5
|
|
(data: bool85; expr: 'not(true()=/doc/avj/bool/*)'; rt: rtBool; b: False), // #85.6
|
|
(data: bool85; expr: 'true()!=/doc/avj/bool/*'; rt: rtBool; b: False), // #85.7
|
|
(data: bool85; expr: 'not(true()!=/doc/avj/bool/*)'; rt: rtBool; b: True), // #85.8
|
|
{ empty nodeset vs. boolean }
|
|
(data: bool85; expr: '/doc/avj/none/*=true()'; rt: rtBool; b: False), // #86.1
|
|
(data: bool85; expr: 'not(/doc/avj/none/*=true())'; rt: rtBool; b: True), // #86.2
|
|
(data: bool85; expr: '/doc/avj/none/*!=true()'; rt: rtBool; b: True), // #86.3
|
|
(data: bool85; expr: 'not(/doc/avj/none/*!=true())'; rt: rtBool; b: False),// #86.4
|
|
{ same with reversed order of operands }
|
|
(data: bool85; expr: 'true()=/doc/avj/none/*'; rt: rtBool; b: False), // #86.5
|
|
(data: bool85; expr: 'not(true()=/doc/avj/none/*)'; rt: rtBool; b: True), // #86.6
|
|
(data: bool85; expr: 'true()!=/doc/avj/none/*'; rt: rtBool; b: True), // #86.7
|
|
(data: bool85; expr: 'not(true()!=/doc/avj/none/*)'; rt: rtBool; b: False) // #86.8
|
|
|
|
);
|
|
|
|
EqualityTests: array[0..25] of TTestRec = (
|
|
(expr: '1=1'; rt: rtBool; b: True),
|
|
(expr: '1!=1'; rt: rtBool; b: False),
|
|
(expr: '1=0'; rt: rtBool; b: False),
|
|
(expr: '1!=0'; rt: rtBool; b: True),
|
|
|
|
(expr: 'true()=true()'; rt: rtBool; b: True),
|
|
(expr: 'true()!=true()'; rt: rtBool; b: False),
|
|
(expr: 'true()=false()'; rt: rtBool; b: False),
|
|
(expr: 'false()!=true()'; rt: rtBool; b: True),
|
|
|
|
(expr: '"test"="test"'; rt: rtBool; b: True),
|
|
(expr: '"test"!="test"'; rt: rtBool; b: False),
|
|
(expr: '"test2"="test"'; rt: rtBool; b: False),
|
|
(expr: '"test2"!="test"'; rt: rtBool; b: True),
|
|
|
|
(expr: 'false()=0'; rt: rtBool; b: True),
|
|
(expr: 'false()!=0'; rt: rtBool; b: False),
|
|
(expr: 'false()=1'; rt: rtBool; b: False),
|
|
|
|
(expr: 'false()!=1'; rt: rtBool; b: True),
|
|
(expr: '0=true()'; rt: rtBool; b: False),
|
|
(expr: '0!=true()'; rt: rtBool; b: True),
|
|
(expr: '1=true()'; rt: rtBool; b: True),
|
|
(expr: '1!=true()'; rt: rtBool; b: False),
|
|
|
|
(expr: 'true()="test"'; rt: rtBool; b: True),
|
|
(expr: 'false()="test"'; rt: rtBool; b: False),
|
|
(expr: '"test"!=true()'; rt: rtBool; b: False),
|
|
(expr: '"test"!=false()'; rt: rtBool; b: True),
|
|
|
|
(expr: '"a"=0.0'; rt: rtBool; b: False),
|
|
(expr: '"a"!=0.0'; rt: rtBool; b: True)
|
|
);
|
|
|
|
math88='<doc>'+
|
|
'<n0>0</n0>'+
|
|
'<n1>1</n1>'+
|
|
'<n2>2</n2>'+
|
|
'<n3>3</n3>'+
|
|
'<n4>4</n4>'+
|
|
'<n5>5</n5>'+
|
|
'<n6>6</n6>'+
|
|
'<n7>2</n7>'+
|
|
'<n8>6</n8>'+
|
|
'<n9>10</n9>'+
|
|
'<n10>3</n10>'+
|
|
'</doc>';
|
|
|
|
math85='<doc>'+
|
|
'<n0>0</n0>'+
|
|
'<n1>1</n1>'+
|
|
'<n2>2</n2>'+
|
|
'<n3>3</n3>'+
|
|
'<n4>4</n4>'+
|
|
'<e>five</e>'+
|
|
'</doc>';
|
|
|
|
math80='<doc>'+
|
|
'<n1 attrib="10">5</n1>'+
|
|
'<n2 attrib="4">2</n2>'+
|
|
'<div attrib="-5">-5</div>'+
|
|
'<mod attrib="-2">2</mod>'+
|
|
'</doc>';
|
|
|
|
math69='<doc>'+
|
|
'<n-1 attrib="9">3</n-1>'+
|
|
'<n-2 attrib="1">7</n-2>'+
|
|
'</doc>';
|
|
|
|
FloatTests: array[0..70] of TTestRec = (
|
|
(expr: '1'; rt: rtNumber; n: 1),
|
|
(expr: '123'; rt: rtNumber; n: 123),
|
|
(expr: '1.23'; rt: rtNumber; n: 1.23),
|
|
(expr: '0.123'; rt: rtNumber; n: 0.123),
|
|
(expr: '4.'; rt: rtNumber; n: 4),
|
|
(expr: '.4'; rt: rtNumber; n: 0.4),
|
|
//(expr: '1.23e3'; rt: rtNumber; n: 1230),
|
|
//(expr: '1.23e-3'; rt: rtNumber; n: 0.00123),
|
|
(expr: '1 div 0'; rt: rtNumber; n: Infinity),
|
|
(expr: '-1 div 0'; rt: rtNumber; n: -Infinity),
|
|
(expr: '0 div 0'; rt: rtNumber; n: NaN),
|
|
(expr: '1 div -0'; rt: rtNumber; n: -Infinity),
|
|
|
|
(expr: '(1 div 0) > 0'; rt: rtBool; b: True),
|
|
(expr: '(1 div 0) < 0'; rt: rtBool; b: False),
|
|
(expr: '(-1 div 0) > 0'; rt: rtBool; b: False),
|
|
(expr: '(-1 div 0) < 0'; rt: rtBool; b: True),
|
|
(expr: '(0 div 0) > 0'; rt: rtBool; b: False),
|
|
(expr: '(0 div 0) < 0'; rt: rtBool; b: False),
|
|
(expr: '(1 div -0) > 0'; rt: rtBool; b: False),
|
|
(expr: '(1 div -0) < 0'; rt: rtBool; b: True),
|
|
(expr: '0 div 0 = 0 div 0'; rt: rtBool; b: False),
|
|
(expr: '0 div 0 != 0 div 0'; rt: rtBool; b: True),
|
|
(expr: '0 div 0 > 0 div 0'; rt: rtBool; b: False),
|
|
(expr: '0 div 0 < 0 div 0'; rt: rtBool; b: False),
|
|
(expr: '0 div 0 >= 0 div 0'; rt: rtBool; b: False),
|
|
(expr: '0 div 0 <= 0 div 0'; rt: rtBool; b: False),
|
|
(expr: '1 div 0 = -1 div 0'; rt: rtBool; b: False),
|
|
(expr: '1 div 0 != -1 div 0'; rt: rtBool; b: True),
|
|
(expr: '1 div 0 > -1 div 0'; rt: rtBool; b: True),
|
|
(expr: '1 div 0 < -1 div 0'; rt: rtBool; b: False),
|
|
(expr: '1 div 0 >= -1 div 0'; rt: rtBool; b: True),
|
|
(expr: '1 div 0 <= -1 div 0'; rt: rtBool; b: False),
|
|
(expr: '1 div 0 = 1 div 0'; rt: rtBool; b: True),
|
|
(expr: '1 div 0 != 1 div 0'; rt: rtBool; b: False),
|
|
(expr: '1 div 0 > 1 div 0'; rt: rtBool; b: False),
|
|
(expr: '1 div 0 < 1 div 0'; rt: rtBool; b: False),
|
|
(expr: '1 div 0 >= -1 div 0'; rt: rtBool; b: True),
|
|
(expr: '1 div 0 <= -1 div 0'; rt: rtBool; b: False),
|
|
(expr: '-2 div 0 = -1 div 0'; rt: rtBool; b: True),
|
|
|
|
(expr: '1 div floor(0.1)'; rt: rtNumber; n: Infinity),
|
|
(expr: '1 div floor(-0.1)'; rt: rtNumber; n: -1),
|
|
(expr: '1 div floor(-0)'; rt: rtNumber; n: -Infinity),
|
|
(expr: '1 div floor(0)'; rt: rtNumber; n: Infinity),
|
|
(expr: '1 div ceiling(0.1)'; rt: rtNumber; n: 1),
|
|
(expr: '1 div ceiling(-0.1)'; rt: rtNumber; n: -Infinity),
|
|
(expr: '1 div ceiling(-0)'; rt: rtNumber; n: -Infinity),
|
|
(expr: '1 div ceiling(0)'; rt: rtNumber; n: Infinity),
|
|
(expr: '1 div round(0.1)'; rt: rtNumber; n: Infinity),
|
|
(expr: '1 div round(-0.1)'; rt: rtNumber; n: -Infinity),
|
|
(expr: '1 div round(-0)'; rt: rtNumber; n: -Infinity),
|
|
(expr: '1 div round(0)'; rt: rtNumber; n: Infinity),
|
|
(expr: '1 div number("f")'; rt: rtNumber; n: NaN),
|
|
(expr: 'number("f") div 1'; rt: rtNumber; n: NaN),
|
|
(expr: '1 div (1 div 0)'; rt: rtNumber; n: 0),
|
|
(expr: '(1 div 0) div 1'; rt: rtNumber; n: Infinity),
|
|
(expr: '-(1 div 0) div 1'; rt: rtNumber; n: -Infinity),
|
|
|
|
(expr: '5 mod 2'; rt: rtNumber; n: 1),
|
|
(expr: '5 mod -2'; rt: rtNumber; n: 1),
|
|
(expr: '-5 mod 2'; rt: rtNumber; n: -1),
|
|
(expr: '-5 mod -2'; rt: rtNumber; n: -1),
|
|
(expr: '2 mod number("xxx")'; rt: rtNumber; n: NaN),
|
|
(expr: 'number("xxx") mod 3'; rt: rtNumber; n: NaN),
|
|
(expr: '8 mod 3 = 2'; rt: rtBool; b: True),
|
|
(data: math88; expr: '(n1*n2*n3*n4*n5*n6)div n7 div n8 div n9 div n10'; rt: rtNumber; n: 2),
|
|
(data: math85; expr: '((((((n3+5)*(3)+(((n2)+2)*(n1 - 6)))-(n4 - n2))+(-(4-6)))))'; rt: rtNumber; n: 4),
|
|
(data: math80; expr: 'div mod mod'; rt: rtNumber; n: -1),
|
|
(data: math69; expr: '-(n-2/@attrib) - -(n-1/@attrib)'; rt: rtNumber; n: 8),
|
|
(data: math69; expr: '-n-2/@attrib --n-1/@attrib'; rt: rtNumber; n: 8),
|
|
(data: math69; expr: '-n-2 --n-1'; rt: rtNumber; n: -4),
|
|
|
|
// test boolean operator short-circuting; "count(5)" acts as an error
|
|
(expr: '10+30*20 or count(5)'; rt: rtBool; b: True),
|
|
(expr: '75-50-25 and count(5)'; rt: rtBool; b: False),
|
|
(expr: '"1" and "0"'; rt: rtBool; b: True),
|
|
(expr: '0 or ""'; rt: rtBool; b: False)
|
|
);
|
|
|
|
math95='<doc>'+
|
|
'<e>1</e>'+
|
|
'<e>2</e>'+
|
|
'<e>3</e>'+
|
|
'<e>4</e>'+
|
|
'<e>five</e>'+
|
|
'</doc>';
|
|
|
|
math96='<doc>'+
|
|
'<e>17</e>'+
|
|
'<e>-5</e>'+
|
|
'<e>8</e>'+
|
|
'<e>-37</e>'+
|
|
'</doc>';
|
|
|
|
expr01='<doc>'+
|
|
'<para id="1" xml:lang="en">en</para>'+
|
|
'<div xml:lang="en">'+
|
|
' <para>en</para>'+
|
|
'</div>'+
|
|
'<para id="3" xml:lang="EN">EN</para>'+
|
|
'<para id="4" xml:lang="en-us">en-us</para>'+
|
|
'</doc>';
|
|
|
|
id04='<!DOCTYPE t04 ['+
|
|
'<!ELEMENT t04 (a*)>'+
|
|
'<!ELEMENT a EMPTY>'+
|
|
'<!ATTLIST a id ID #REQUIRED>'+
|
|
']>'+
|
|
'<t04>'+
|
|
'<a id="a"/>'+
|
|
'<a id="b"/>'+
|
|
'<a id="c"/>'+
|
|
'<a id="d"/>'+
|
|
'</t04>';
|
|
|
|
pos04='<doc>'+
|
|
'<a test="true"><num>1</num></a>'+
|
|
'<a><num>1191</num></a>'+
|
|
'<a><num>263</num></a>'+
|
|
'<a test="true"><num>2</num></a>'+
|
|
'<a><num>827</num></a>'+
|
|
'<a><num>256</num></a>'+
|
|
'<a test="true"><num>3</num></a>'+
|
|
'<a test="true"><num>4</num></a>'+
|
|
'</doc>';
|
|
|
|
FunctionTests: array[0..51] of TTestRec = (
|
|
// last()
|
|
// local-name()
|
|
// namespace-uri()
|
|
// name()
|
|
|
|
(expr: 'boolean(0)'; rt: rtBool; b: False),
|
|
(expr: 'boolean(-0)'; rt: rtBool; b: False),
|
|
(expr: 'boolean(1 div 0)'; rt: rtBool; b: True),
|
|
(expr: 'boolean(-1 div 0)'; rt: rtBool; b: True),
|
|
(expr: 'boolean(0 div 0)'; rt: rtBool; b: False),
|
|
(expr: 'boolean("")'; rt: rtBool; b: False),
|
|
(expr: 'boolean("abc")'; rt: rtBool; b: True),
|
|
|
|
(data: simple; expr: 'boolean(/doc)'; rt: rtBool; b: True), // #40
|
|
(data: simple; expr: 'boolean(foo)'; rt: rtBool; b: False), // #41
|
|
|
|
(expr: 'true()'; rt: rtBool; b: True),
|
|
(expr: 'false()'; rt: rtBool; b: False),
|
|
(expr: 'not(true())'; rt: rtBool; b: False),
|
|
(expr: 'not(false())'; rt: rtBool; b: True),
|
|
(expr: 'not("")'; rt: rtBool; b: True),
|
|
|
|
// lang() tests. These ones, however, test much more than lang().
|
|
(data: expr01; expr: 'para[@id="1" and lang("en")]'; rt: rtNodeStr; s: 'en'), // expression01
|
|
(data: expr01; expr: 'para[@id="4" and lang("en")]'; rt: rtNodeStr; s: 'en-us'), // expression03
|
|
(data: expr01; expr: 'div/para[lang("en")]'; rt: rtNodeStr; s: 'en'), // expression04
|
|
(data: expr01; expr: 'para[@id="3" and lang("en")]'; rt: rtNodeStr; s: 'EN'), // expression05
|
|
|
|
(data: id04; expr: 'id("c")/@id'; rt: rtNodeStr; s: 'c'), // idkey04
|
|
|
|
// position() tests
|
|
(data: pos04; expr: '*[@test][position()=4]/num'; rt: rtNodeStr; s: '4'),
|
|
|
|
(expr: 'number("1.5")'; rt: rtNumber; n: 1.5),
|
|
(expr: 'number("abc")'; rt: rtNumber; n: NaN),
|
|
(expr: '-number("abc")'; rt: rtNumber; n: NaN),
|
|
(expr: 'number(true())'; rt: rtNumber; n: 1.0),
|
|
(expr: 'number(false())'; rt: rtNumber; n: 0),
|
|
|
|
(data: math95; expr: 'sum(e)'; rt: rtNumber; n: NaN),
|
|
(data: math96; expr: 'sum(e)'; rt: rtNumber; n: -17),
|
|
|
|
(expr: 'floor(0.1)'; rt: rtNumber; n: 0),
|
|
(expr: 'floor(-0.1)'; rt: rtNumber; n: -1),
|
|
(expr: 'floor(-0)'; rt: rtNumber; n: 0),
|
|
(expr: 'floor(0)'; rt: rtNumber; n: 0),
|
|
(expr: 'floor(5.2)'; rt: rtNumber; n: 5),
|
|
(expr: 'floor(-5.2)'; rt: rtNumber; n: -6),
|
|
(expr: 'floor("NaN")'; rt: rtNumber; n: NaN),
|
|
|
|
(expr: 'ceiling(0.1)'; rt: rtNumber; n: 1),
|
|
(expr: 'ceiling(-0.1)'; rt: rtNumber; n: 0),
|
|
(expr: 'ceiling(-0)'; rt: rtNumber; n: 0),
|
|
(expr: 'ceiling(0)'; rt: rtNumber; n: 0),
|
|
(expr: 'ceiling(5.2)'; rt: rtNumber; n: 6),
|
|
(expr: 'ceiling(-5.2)'; rt: rtNumber; n: -5),
|
|
(expr: 'ceiling("NaN")'; rt: rtNumber; n: NaN),
|
|
|
|
(expr: 'round(0.1)'; rt: rtNumber; n: 0),
|
|
(expr: 'round(5.2)'; rt: rtNumber; n: 5),
|
|
(expr: 'round(5.5)'; rt: rtNumber; n: 6),
|
|
(expr: 'round(5.6)'; rt: rtNumber; n: 6),
|
|
(expr: 'round(-0.1)'; rt: rtNumber; n: 0),
|
|
(expr: 'round(-5.2)'; rt: rtNumber; n: -5),
|
|
(expr: 'round(-5.5)'; rt: rtNumber; n: -5),
|
|
(expr: 'round(-5.6)'; rt: rtNumber; n: -6),
|
|
(expr: 'round("NaN")'; rt: rtNumber; n: NaN),
|
|
(expr: 'round(1 div 0)'; rt: rtNumber; n: Infinity),
|
|
(expr: 'round(-1 div 0)'; rt: rtNumber; n: -Infinity)
|
|
);
|
|
|
|
str14 ='<doc>'#10+
|
|
' <av>'#10+
|
|
' <a>'#10+
|
|
' <b>b</b>'#10+
|
|
' <c>c</c>'#10+
|
|
' <d>d</d>'#10+
|
|
' <e>e</e>'#10+
|
|
' </a>'#10+
|
|
' <v>'#10+
|
|
' <w>w</w>'#10+
|
|
' <x>x</x>'#10+
|
|
' <y>y</y>'#10+
|
|
' <z>z</z>'#10+
|
|
' </v>'#10+
|
|
' </av>'#10+
|
|
'</doc>';
|
|
|
|
out14 =#10+
|
|
' b'#10+
|
|
' c'#10+
|
|
' d'#10+
|
|
' e'#10+
|
|
' ';
|
|
|
|
node08='<docs xmlns:ped="http://www.ped.com"><?MyPI DoesNothing ?><!-- This is a big tree containing all letters of the alphabet -->'#10+
|
|
'<a attr1="This should not be seen">A</a>'#10+
|
|
'<b><c attr1="tsnbs" attr2="tsnbs">B-C</c>'#10+
|
|
'<d><e><f>TextNode_between_F_and_G'#10+
|
|
'<g><h><i><j><k><l><m><n><o><p><q><r><s><t><u><v><w><x><y><z><Yahoo>Yahoo</Yahoo>'#10+
|
|
'</z></y></x></w></v></u></t></s></r></q></p></o></n></m></l></k></j></i></h>SecondNode_after_H</g></f></e></d></b>'#10+
|
|
'</docs>';
|
|
|
|
out08=#10+
|
|
'A'#10+
|
|
'B-C'#10+
|
|
'TextNode_between_F_and_G'#10+
|
|
'Yahoo'#10+
|
|
'SecondNode_after_H'#10;
|
|
|
|
str30='<doc xmlns="http://xsl.lotus.com/ns2" xmlns:ns1="http://xsl.lotus.com/ns1">'#10+
|
|
'<ns1:a attrib1="test" xmlns="http://xsl.lotus.com/ns2" xmlns:ns1="http://xsl.lotus.com/ns1"/>'#10+
|
|
'<b ns1:attrib2="test"/>'#10+
|
|
'</doc>';
|
|
|
|
ns11='<doc-one xmlns="http://xsl.lotus.com/ns2" xmlns:ns1="http://xsl.lotus.com/ns1">'+
|
|
' <ns1:a-two attrib1="Goodbye" xmlns="http://xsl.lotus.com/ns2" xmlns:ns1="http://xsl.lotus.com/ns1">Hello</ns1:a-two>'+
|
|
' <b-three ns1:attrib2="Ciao">'+
|
|
' <c-four/>'+
|
|
' </b-three>'+
|
|
'</doc-one>';
|
|
|
|
pidata='<?a-pi data="foo"?><?b-pi data="bar"?><doc/>';
|
|
|
|
StringTests: array[0..87] of TTestRec = ( // numbers refer to xalan/string/stringXX
|
|
(expr: 'string(0)'; rt: rtString; s: '0'),
|
|
(expr: 'string(5)'; rt: rtString; s: '5'), // #38/39
|
|
(expr: 'string(0.5)'; rt: rtString; s: '0.5'),
|
|
(expr: 'string(-0.5)'; rt: rtString; s: '-0.5'),
|
|
(expr: 'string("test")'; rt: rtString; s: 'test'), // #40
|
|
(expr: 'string("")'; rt: rtString; s: ''), // #41
|
|
(expr: 'string(true())'; rt: rtString; s: 'true'),
|
|
(expr: 'string(false())'; rt: rtString; s: 'false'),
|
|
(expr: 'string(0 div 0)'; rt: rtString; s: 'NaN'),
|
|
(expr: 'string(1 div 0)'; rt: rtString; s: 'Infinity'),
|
|
(expr: 'string(-1 div 0)'; rt: rtString; s: '-Infinity'),
|
|
// maybe other checks for correct numeric formats
|
|
(data: str14; expr: 'string(av//*)'; rt: rtString; s: out14),
|
|
(data: node08; expr: '/'; rt: rtNodeStr; s: out08),
|
|
|
|
(expr: 'concat("titi","toto")'; rt: rtString; s: 'tititoto'),
|
|
(expr: 'concat("titi","toto","tata")'; rt: rtString; s: 'tititototata'),
|
|
(expr: 'concat("titi",''toto'')'; rt: rtString; s: 'tititoto'),
|
|
(expr: 'concat("titi",''toto'',"tata","last")'; rt: rtString; s: 'tititototatalast'),
|
|
(expr: 'concat("cd", 34)'; rt: rtString; s: 'cd34'), // #101
|
|
(expr: 'concat(false(), "ly")'; rt: rtString; s: 'falsely'), // #104
|
|
|
|
(expr: 'starts-with("tititoto","titi")'; rt: rtBool; b: True),
|
|
(expr: 'starts-with("tititoto","to")'; rt: rtBool; b: False),
|
|
(expr: 'starts-with("ab", "abc")'; rt: rtBool; b: False), // #46
|
|
(expr: 'starts-with("abc", "bc")'; rt: rtBool; b: False), // #47
|
|
(expr: 'starts-with("abc", "")'; rt: rtBool; b: True), // #48
|
|
(expr: 'starts-with("", "")'; rt: rtBool; b: True), // #49
|
|
(expr: 'starts-with(true(), "tr")'; rt: rtBool; b: True), // #50
|
|
|
|
(expr: 'contains("tititototata","titi")'; rt: rtBool; b: True),
|
|
(expr: 'contains("tititototata","toto")'; rt: rtBool; b: True),
|
|
(expr: 'contains("tititototata","tata")'; rt: rtBool; b: True),
|
|
(expr: 'contains("tititototata","tita")'; rt: rtBool; b: False),
|
|
// 'contains(concat(.,'BC'),concat('A','B','C'))' == true // #57
|
|
(expr: 'contains("ab", "abc")'; rt: rtBool; b: False), // #58
|
|
(expr: 'contains("abc", "bcd")'; rt: rtBool; b: False), // #60
|
|
(expr: 'contains("abc", "")'; rt: rtBool; b: True), // #61
|
|
(expr: 'contains("", "")'; rt: rtBool; b: True), // #62
|
|
(expr: 'contains(true(), "e")'; rt: rtBool; b: True), // #63
|
|
|
|
(expr: 'substring("12345",2,3)'; rt: rtString; s: '234'),
|
|
(expr: 'substring("12345",2)'; rt: rtString; s: '2345'),
|
|
(expr: 'substring("12345",-4)'; rt: rtString; s: '12345'),
|
|
(expr: 'substring("12345",3.4)'; rt: rtString; s: '345'),
|
|
(expr: 'substring("12345",3.6)'; rt: rtString; s: '45'),
|
|
|
|
(expr: 'substring("12345",1.5,2.6)'; rt: rtString; s: '234'), // #16
|
|
(expr: 'substring("12345",2.2,2.2)'; rt: rtString; s: '23'),
|
|
(expr: 'substring("12345",0,3)'; rt: rtString; s: '12'), // #17
|
|
(expr: 'substring("12345",-8,10)'; rt: rtString; s: '1'),
|
|
(expr: 'substring("12345",4,-10)'; rt: rtString; s: ''),
|
|
|
|
(expr: 'substring("12345",0 div 0, 3)'; rt: rtString; s: ''), // #18
|
|
(expr: 'substring("12345",1, 0 div 0)'; rt: rtString; s: ''), // #19
|
|
(expr: 'substring("12345",1 div 0, 3)'; rt: rtString; s: ''),
|
|
(expr: 'substring("12345",3,-1 div 0)'; rt: rtString; s: ''),
|
|
(expr: 'substring("12345",-42, 1 div 0)'; rt: rtString; s: '12345'), // #20
|
|
|
|
(expr: 'substring("12345",-1 div 0, 1 div 0)'; rt: rtString; s: ''), // #21
|
|
(expr: 'substring("12345",-1 div 0,5)'; rt: rtString; s: ''),
|
|
|
|
(expr: 'substring-before("1999/04/01","/")'; rt: rtString; s: '1999'), // #08
|
|
(expr: 'substring-before("1999/04/01","a")'; rt: rtString; s: ''), // #68 modified
|
|
(expr: 'substring-after("1999/04/01","/")'; rt: rtString; s: '04/01'), // #09
|
|
(expr: 'substring-after("1999/04/01","19")'; rt: rtString; s: '99/04/01'),
|
|
(expr: 'substring-after("1999/04/01","a")'; rt: rtString; s: ''),
|
|
|
|
(expr: 'string-length("")'; rt: rtNumber; n: 0),
|
|
(expr: 'string-length("titi")'; rt: rtNumber; n: 4),
|
|
(data: simple; expr: 'string-length(.)'; rt: rtNumber; n: 4), // #02 modified
|
|
(data: str04; expr: 'string-length(/)'; rt: rtNumber; n:27), // #04.1 modified
|
|
(data: str04; expr: 'string-length(/doc/a)'; rt: rtNumber; n: 12), // #04.2
|
|
(data: str04; expr: 'string-length()'; rt: rtNumber; n: 27),
|
|
(expr: 'normalize-space("'#9#10#13' ab cd'#10#13#9'ef'#9#10#13' ")'; rt: rtString; s: 'ab cd ef'), // #10
|
|
|
|
(expr: 'translate("bar", "abc", "ABC")'; rt: rtString; s: 'BAr'), // #11
|
|
(expr: 'translate("--aaa--","abc-","ABC")'; rt: rtString; s: 'AAA'),
|
|
(expr: 'translate("ddaaadddd","abcd","ABCxy")'; rt: rtString; s: 'xxAAAxxxx'), // #96
|
|
|
|
(data: node08; expr: 'name(a/@attr1)'; rt: rtString; s: 'attr1'), // namespace08 modified
|
|
(data: node08; expr: 'namespace-uri(a/@attr1)'; rt: rtString; s: ''),
|
|
(data: node08; expr: 'local-name(a/@attr1)'; rt: rtString; s: 'attr1'),
|
|
|
|
(data: pidata; expr: 'name(/processing-instruction())'; rt: rtString; s: 'a-pi'), // namespace29 modified
|
|
(data: pidata; expr: 'name(/processing-instruction("b-pi"))'; rt: rtString; s: 'b-pi'),
|
|
(data: pidata; expr: 'local-name(/processing-instruction())'; rt: rtString; s: 'a-pi'),
|
|
(data: pidata; expr: 'namespace-uri(/processing-instruction())'; rt: rtString; s: ''),
|
|
|
|
(data: node08; expr: 'name(//comment())'; rt: rtString; s: ''), // namespace30 modified
|
|
(data: node08; expr: 'local-name(//comment())'; rt: rtString; s: ''),
|
|
(data: node08; expr: 'namespace-uri(//comment())'; rt: rtString; s: ''),
|
|
|
|
(data: node08; expr: 'name(//text())'; rt: rtString; s: ''), // namespace31 modified
|
|
(data: node08; expr: 'local-name(//text())'; rt: rtString; s: ''),
|
|
(data: node08; expr: 'namespace-uri(//text())'; rt: rtString; s: ''),
|
|
|
|
// tests for number->string conversions at boundary conditions
|
|
(expr: 'string(123456789012345678)'; rt: rtString; s: '123456789012345680'), // #132.1
|
|
(expr: 'string(-123456789012345678)'; rt: rtString; s: '-123456789012345680'), // #132.2
|
|
(expr: 'string(.10123456789234567893)'; rt: rtString; s: '0.10123456789234568'), // #133.1
|
|
(expr: 'string(-.10123456789234567893)'; rt: rtString; s: '-0.10123456789234568'), // #133.2
|
|
|
|
(expr: 'string(9.87654321012345)'; rt: rtString; s: '9.87654321012345'), // #134.1
|
|
(expr: 'string(98765432101234.5)'; rt: rtString; s: '98765432101234.5'), // #134.2
|
|
(expr: 'string(.0000000000000000000000000000000000000000123456789)'; rt: rtString; // #135.1
|
|
s: '0.0000000000000000000000000000000000000000123456789'),
|
|
(expr: 'string(-.0000000000000000000000000000000000000000123456789)'; rt: rtString; // #135.2
|
|
s: '-0.0000000000000000000000000000000000000000123456789')
|
|
);
|
|
|
|
res1 = '<foo xmlns:baz1="http://xsl.lotus.com/ns1" xmlns:baz2="http://xsl.lotus.com/ns2"/>';
|
|
|
|
nameTests: array[0..17] of TTestRec3 = (
|
|
(data: str30; re: res1; expr: 'namespace-uri(baz1:a/@baz2:attrib1)'; rt: rtString; s: ''), // #30
|
|
(data: str30; re: res1; expr: 'namespace-uri(baz2:b/@baz1:attrib2)'; rt: rtString; s: 'http://xsl.lotus.com/ns1'), // #31
|
|
(data: str30; re: res1; expr: 'name(*)'; rt: rtString; s: 'ns1:a'), // #32
|
|
(data: str30; re: res1; expr: 'name(baz1:a)'; rt: rtString; s: 'ns1:a'), // #33
|
|
(data: str30; re: res1; expr: 'name(baz2:b)'; rt: rtString; s: 'b'), // #34
|
|
(data: str30; re: res1; expr: 'name(baz1:a/@baz2:attrib1)'; rt: rtString; s: ''), // #35
|
|
(data: str30; re: res1; expr: 'name(baz2:b/@baz1:attrib2)'; rt: rtString; s: 'ns1:attrib2'), // #36
|
|
|
|
(data: str30; re: res1; expr: 'local-name(baz2:b)'; rt: rtString; s: 'b'), // namespace07
|
|
(data: str30; re: res1; expr: 'local-name(baz2:b/@baz1:attrib2)'; rt: rtString; s: 'attrib2'), // namespace09
|
|
(data: str30; re: res1; expr: 'local-name()'; rt: rtString; s: 'doc'), // namespace26
|
|
(data: str30; re: res1; expr: 'namespace-uri()'; rt: rtString; s: 'http://xsl.lotus.com/ns2'), // namespace27
|
|
|
|
(data: ns11; re: res1; expr: 'namespace-uri(baz1:a-two)'; rt: rtString; s: 'http://xsl.lotus.com/ns1'), // namespace11
|
|
(data: ns11; re: res1; expr: 'namespace-uri(baz1:a-two/@attrib1)'; rt: rtString; s: ''),
|
|
(data: ns11; re: res1; expr: 'namespace-uri(baz2:b-three)'; rt: rtString; s: 'http://xsl.lotus.com/ns2'),
|
|
(data: ns11; re: res1; expr: 'namespace-uri(baz2:b-three/@baz1:attrib2)'; rt: rtString; s: 'http://xsl.lotus.com/ns1'),
|
|
{*} (data: ns11; re: res1; expr: 'namespace-uri(baz2:b-three/c-four)'; rt: rtString; s: ''),
|
|
(data: ns11; re: res1; expr: 'namespace-uri(bogus)'; rt: rtString; s: ''),
|
|
|
|
(data: str30; re: res1; expr: 'name(baz1:*)'; rt: rtString; s: 'ns1:a')
|
|
);
|
|
|
|
ax114='<doc>'+
|
|
'<foo att1="c">'+
|
|
' <foo att1="b">'+
|
|
' <foo att1="a"/>'+
|
|
' </foo>'+
|
|
'</foo>'+
|
|
'<baz/>'+
|
|
'</doc>';
|
|
|
|
ax115='<doc>'+
|
|
'<foo att1="c"/>'+
|
|
'<foo att1="b"/>'+
|
|
'<foo att1="a"/>'+
|
|
'<baz/>'+
|
|
'</doc>';
|
|
|
|
|
|
ax117='<chapter title="A" x="0">'+
|
|
'<section title="A1" x="1">'+
|
|
' <subsection title="A1a" x="2">hello</subsection>'+
|
|
' <subsection title="A1b">ahoy</subsection>'+
|
|
'</section>'+
|
|
'<section title="A2">'+
|
|
' <subsection title="A2a">goodbye</subsection>'+
|
|
' <subsection title="A2b">sayonara</subsection>'+
|
|
' <subsection title="A2c">adios</subsection>'+
|
|
'</section>'+
|
|
'<section title="A3">'+
|
|
' <subsection title="A3a">aloha</subsection>'+
|
|
' <subsection title="A3b">'+
|
|
' <footnote x="3">A3b-1</footnote>'+
|
|
' <footnote>A3b-2</footnote>'+
|
|
' </subsection>'+
|
|
' <subsection title="A3c">shalom</subsection>'+
|
|
'</section>'+
|
|
'</chapter>';
|
|
|
|
AxesTests: array[0..15] of TTestRec = (
|
|
(data: ax117; expr: 'count(//@*)'; rt: rtNumber; n: 16),
|
|
(data: ax117; expr: 'count(//@title)'; rt: rtNumber; n: 12),
|
|
(data: ax117; expr: 'count(//section//@*)'; rt: rtNumber; n: 14),
|
|
(data: ax117; expr: 'count(//section//@title)'; rt: rtNumber; n: 11),
|
|
(data: ax117; expr: 'count(/chapter/.//@*)'; rt: rtNumber; n: 16),
|
|
(data: ax117; expr: 'count(/chapter/.//@title)'; rt: rtNumber; n: 12),
|
|
(data: ax117; expr: 'count(/chapter/section[1]//@*)'; rt: rtNumber; n: 5),
|
|
(data: ax117; expr: 'count(/chapter/section[1]//@title)'; rt: rtNumber; n: 3),
|
|
(data: ax117; expr: 'count(/chapter/section[2]//@*)'; rt: rtNumber; n: 4),
|
|
(data: ax117; expr: 'count(/chapter/section[2]//@title)'; rt: rtNumber; n: 4),
|
|
(data: ax117; expr: 'count(/chapter/section[3]//@*)'; rt: rtNumber; n: 5),
|
|
(data: ax117; expr: 'count(/chapter/section[3]//@title)'; rt: rtNumber; n: 4),
|
|
|
|
(data: simple; expr: 'local-name(namespace::*[1])'; rt: rtString; s: 'xml'), // namespace28a
|
|
(data: simple; expr: 'name(namespace::*[1])'; rt: rtString; s: 'xml'), // namespace28b
|
|
(data: ax117; expr: 'name(//subsection[@title="A3b"]/@title/parent::*)'; rt: rtString; s: 'subsection'), // axes96 modified
|
|
(data: ax117; expr: 'name(//subsection[@title="A3b"]/@title/ancestor::*[1])'; rt: rtString; s: 'subsection') // axes97 modified
|
|
);
|
|
|
|
AxesTests2: array[0..3] of TTestRec3 = (
|
|
(data: ax114; re: '//baz'; expr: 'preceding::foo[1]/@att1'; rt: rtNodeStr; s: 'a'),
|
|
(data: ax114; re: '//baz'; expr: '(preceding::foo)[1]/@att1'; rt: rtNodeStr; s: 'c'), // won't parse
|
|
(data: ax115; re: '//baz'; expr: 'preceding-sibling::foo[1]/@att1'; rt: rtNodeStr; s: 'a'),
|
|
(data: ax115; re: '//baz'; expr: '(preceding-sibling::foo)[1]/@att1'; rt: rtNodeStr; s: 'c') // won't parse
|
|
);
|
|
|
|
pred44 = '<doc>'+
|
|
'<element1>'+
|
|
'<child1>Success</child1>'+
|
|
'<child2>child2</child2>'+
|
|
'</element1>'+
|
|
'<element2>'+
|
|
'<child1>Wrong node selected!!</child1>'+
|
|
'</element2>'+
|
|
'<element3>'+
|
|
'<child1>Wrong node selected!!</child1>'+
|
|
'</element3>'+
|
|
'</doc>';
|
|
|
|
pred11 = '<doc>'+
|
|
'<a>1</a>'+
|
|
'<a>2'+
|
|
'<achild>target</achild>'+
|
|
'</a>'+
|
|
'<a>3</a>'+
|
|
'<a>target</a>'+
|
|
'</doc>';
|
|
|
|
PredicateTests: array [0..4] of TTestRec = (
|
|
(data: pred44; expr: '//child1[parent::element1]'; rt: rtNodeStr; s: 'Success'), // predicate44
|
|
{should select all but last elements named 'e' }
|
|
(data: math96; expr: 'sum(e[true()=following-sibling::*])'; rt: rtNumber; n: 20), // predicate03
|
|
{should select two first elements}
|
|
(data: math96; expr: 'sum(e[8=following-sibling::*])'; rt: rtNumber; n: 12), // predicate05
|
|
(data: pred11; expr: 'a["target"=descendant::*]'; rt: rtNodeStr; s: '2target'), // predicate06
|
|
(data: pred11; expr: 'a[following-sibling::*=descendant::*]'; rt: rtNodeStr; s: '2target') // predicate11
|
|
|
|
|
|
|
|
|
|
);
|
|
{$warnings on}
|
|
|
|
var
|
|
FailCount: Integer = 0;
|
|
|
|
procedure CheckResult(const t: TTestRec; r: TXPathVariable); overload;
|
|
begin
|
|
case t.rt of
|
|
rtBool:
|
|
begin
|
|
if (r is TXPathBooleanVariable) and (r.AsBoolean = t.b) then
|
|
Exit;
|
|
writeln;
|
|
writeln('Failed: ', t.expr);
|
|
writeln('Expected: ', t.b, ' got: ', r.AsBoolean);
|
|
end;
|
|
|
|
rtNumber:
|
|
begin
|
|
if (r is TXPathNumberVariable) then
|
|
begin
|
|
if IsNan(t.n) then
|
|
begin
|
|
if IsNan(r.AsNumber) then
|
|
Exit;
|
|
end
|
|
else
|
|
begin
|
|
if IsInfinite(t.n) and (t.n = r.AsNumber) then
|
|
Exit;
|
|
if not IsNan(TXPathNumberVariable(r).Value) and SameValue(TXPathNumberVariable(r).Value, t.n) then
|
|
Exit;
|
|
end;
|
|
end;
|
|
writeln;
|
|
writeln('Failed: ', t.expr);
|
|
writeln('Expected: ', t.n, ' got: ', r.AsNumber);
|
|
end;
|
|
|
|
rtString:
|
|
begin
|
|
if (r is TXPathStringVariable) and (r.AsText = DOMString(t.s)) then
|
|
Exit;
|
|
writeln;
|
|
writeln('Failed: ', t.expr);
|
|
writeln('Expected: ', DOMString(t.s), ' got: ', r.AsText);
|
|
end;
|
|
rtNodeStr:
|
|
begin
|
|
if (r is TXPathNodeSetVariable) and (r.AsNodeSet.Count = 1) and (r.AsText = DOMString(t.s)) then
|
|
Exit;
|
|
writeln;
|
|
writeln('Failed: ', t.expr);
|
|
if r.AsNodeSet.Count > 1 then
|
|
writeln('Result is not a single node');
|
|
writeln('Expected: ', DOMString(t.s), ' got: ', r.AsText);
|
|
end;
|
|
end;
|
|
Inc(FailCount);
|
|
end;
|
|
|
|
procedure CheckResult(const t: TTestRec3; r: TXPathVariable); overload;
|
|
var
|
|
temp: TTestRec;
|
|
begin
|
|
temp.data := t.data;
|
|
temp.expr := t.expr;
|
|
temp.rt := t.rt;
|
|
temp.n := t.n;
|
|
CheckResult(temp, r);
|
|
end;
|
|
|
|
|
|
function ParseString(const data: string): TXMLDocument;
|
|
var
|
|
parser: TDOMParser;
|
|
src: TXMLInputSource;
|
|
begin
|
|
parser := TDOMParser.Create;
|
|
try
|
|
parser.Options.PreserveWhitespace := True;
|
|
parser.Options.Namespaces := True;
|
|
src := TXMLInputSource.Create(data);
|
|
try
|
|
parser.Parse(src, Result);
|
|
finally
|
|
src.Free;
|
|
end;
|
|
finally
|
|
parser.Free;
|
|
end;
|
|
end;
|
|
|
|
procedure DoSuite(const tests: array of TTestRec);
|
|
var
|
|
i: Integer;
|
|
doc: TXMLDocument;
|
|
rslt: TXPathVariable;
|
|
begin
|
|
for i := 0 to High(tests) do
|
|
begin
|
|
if tests[i].data <> '' then
|
|
doc := ParseString(tests[i].data)
|
|
else
|
|
doc := TXMLDocument.Create;
|
|
try
|
|
try
|
|
rslt := EvaluateXPathExpression(tests[i].expr, doc.DocumentElement);
|
|
try
|
|
CheckResult(tests[i], rslt);
|
|
finally
|
|
rslt.Free;
|
|
end;
|
|
except
|
|
writeln;
|
|
writeln('Failed: ', tests[i].expr);
|
|
SysUtils.ShowException(ExceptObject, ExceptAddr);
|
|
Inc(FailCount);
|
|
end;
|
|
finally
|
|
doc.Free;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure DoSuite_WithResolver(const tests: array of TTestRec3);
|
|
var
|
|
i: Integer;
|
|
doc: TXMLDocument;
|
|
rslt: TXPathVariable;
|
|
nsdoc: TXMLDocument;
|
|
resolver: TXPathNSResolver;
|
|
begin
|
|
for i := 0 to High(tests) do
|
|
begin
|
|
doc := ParseString(tests[i].data);
|
|
try
|
|
nsdoc := ParseString(tests[i].re);
|
|
try
|
|
try
|
|
resolver := TXPathNSResolver.Create(nsdoc.DocumentElement);
|
|
try
|
|
rslt := EvaluateXPathExpression(tests[i].expr, doc.DocumentElement, resolver);
|
|
try
|
|
CheckResult(tests[i], rslt);
|
|
finally
|
|
rslt.Free;
|
|
end;
|
|
finally
|
|
resolver.Free;
|
|
end;
|
|
except
|
|
writeln;
|
|
writeln('Failed: ', tests[i].expr);
|
|
SysUtils.ShowException(ExceptObject, ExceptAddr);
|
|
Inc(FailCount);
|
|
end;
|
|
finally
|
|
nsdoc.Free;
|
|
end;
|
|
finally
|
|
doc.Free;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure DoSuite_WithContext(const tests: array of TTestRec3);
|
|
var
|
|
i: Integer;
|
|
doc: TXMLDocument;
|
|
rslt: TXPathVariable;
|
|
context: TXPathVariable;
|
|
ctxNs: TNodeSet;
|
|
begin
|
|
for i := 0 to High(tests) do
|
|
begin
|
|
doc := ParseString(tests[i].data);
|
|
try
|
|
context := EvaluateXPathExpression(tests[i].re, doc.DocumentElement);
|
|
try
|
|
try
|
|
ctxNs := context.AsNodeSet;
|
|
if ctxNs.Count <> 1 then
|
|
raise Exception.CreateFmt('Context expression "%s" does not evaluate to a single node', [tests[i].re]);
|
|
rslt := EvaluateXPathExpression(tests[i].expr, TDOMNode(ctxNs[0]));
|
|
try
|
|
CheckResult(tests[i], rslt);
|
|
finally
|
|
rslt.Free;
|
|
end;
|
|
except
|
|
writeln;
|
|
writeln('Failed: ', tests[i].expr);
|
|
SysUtils.ShowException(ExceptObject, ExceptAddr);
|
|
Inc(FailCount);
|
|
end;
|
|
finally
|
|
context.Free;
|
|
end;
|
|
finally
|
|
doc.Free;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
begin
|
|
DoSuite(BaseTests);
|
|
DoSuite(CompareTests);
|
|
DoSuite(NodesetCompareTests);
|
|
DoSuite(EqualityTests);
|
|
DoSuite(FloatTests);
|
|
DoSuite(FunctionTests);
|
|
DoSuite(StringTests);
|
|
DoSuite(AxesTests);
|
|
DoSuite_WithContext(AxesTests2);
|
|
DoSuite_WithResolver(nameTests);
|
|
DoSuite(PredicateTests);
|
|
|
|
writeln;
|
|
writeln('Total failed tests: ', FailCount);
|
|
end.
|