xpathts.pp 39 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021
  1. {**********************************************************************
  2. This file is part of the Free Component Library (FCL)
  3. Test suite for the xpath.pp unit.
  4. Largely based on expressions from libxml2 source tree.
  5. Copyright (c) 2009 by Sergei Gorelkin, [email protected]
  6. See the file COPYING.FPC, included in this distribution,
  7. for details about the copyright.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  11. **********************************************************************}
  12. program xpathts;
  13. {$mode delphi}{$h+}
  14. uses
  15. Classes, SysUtils, Math,
  16. dom, xmlread, xmlwrite, xpath;
  17. type
  18. TResultType = (rtString, rtNumber, rtBool, rtNodeStr, rtOther);
  19. TTestRec = record
  20. data: string; // UTF-8 encoded
  21. expr: DOMString;
  22. case rt: TResultType of
  23. rtString, rtNodeStr: (s: DOMPChar); // cannot use DOMString here
  24. rtNumber: (n: Extended);
  25. rtBool: (b: Boolean);
  26. end;
  27. TTestRec3 = record
  28. data: string; // UTF-8 encoded
  29. re: string;
  30. expr: DOMString;
  31. case rt: TResultType of
  32. rtString, rtNodeStr: (s: DOMPChar); // cannot use DOMString here
  33. rtNumber: (n: Extended);
  34. rtBool: (b: Boolean);
  35. end;
  36. {$warnings off}
  37. const
  38. BaseTests: array[0..4] of TTestRec = (
  39. (expr: '1'; rt: rtNumber; n: 1),
  40. (expr: '1+2'; rt: rtNumber; n: 3),
  41. (expr: '2*3'; rt: rtNumber; n: 6),
  42. (expr: '1+2*3+4'; rt: rtNumber; n: 11),
  43. (expr: '(1+2)*(3+4)'; rt: rtNumber; n: 21)
  44. );
  45. CompareTests: array[0..46] of TTestRec = (
  46. (expr: '0<0'; rt: rtBool; b: False),
  47. (expr: '0<=0'; rt: rtBool; b: True),
  48. (expr: '0>0'; rt: rtBool; b: False),
  49. (expr: '0>=0'; rt: rtBool; b: True),
  50. (expr: '0<1'; rt: rtBool; b: True),
  51. (expr: '0<=1'; rt: rtBool; b: True),
  52. (expr: '0>1'; rt: rtBool; b: False),
  53. (expr: '0>=1'; rt: rtBool; b: False),
  54. (expr: '1<0'; rt: rtBool; b: False),
  55. (expr: '1<=0'; rt: rtBool; b: False),
  56. (expr: '1>0'; rt: rtBool; b: True),
  57. (expr: '1>=0'; rt: rtBool; b: True),
  58. (expr: '1<1'; rt: rtBool; b: False),
  59. (expr: '1<=1'; rt: rtBool; b: True),
  60. (expr: '1>1'; rt: rtBool; b: False),
  61. (expr: '1>=1'; rt: rtBool; b: True),
  62. (expr: '0>-0'; rt: rtBool; b: False),
  63. (expr: '"0"<1'; rt: rtBool; b: True),
  64. (expr: '"0"<=1'; rt: rtBool; b: True),
  65. (expr: '"0">1'; rt: rtBool; b: False),
  66. (expr: '"0">=1'; rt: rtBool; b: False),
  67. (expr: '0<"1.2"'; rt: rtBool; b: True),
  68. (expr: '0<="1.2"'; rt: rtBool; b: True),
  69. (expr: '0>"1.2"'; rt: rtBool; b: False),
  70. (expr: '0>="1.2"'; rt: rtBool; b: False),
  71. (expr: '0<"-0.2"'; rt: rtBool; b: False),
  72. (expr: '0<="-0.2"'; rt: rtBool; b: False),
  73. (expr: '0>"-0.2"'; rt: rtBool; b: True),
  74. (expr: '0>="-0.2"'; rt: rtBool; b: True),
  75. (expr: 'false()<1'; rt: rtBool; b: True),
  76. (expr: 'false()<=1'; rt: rtBool; b: True),
  77. (expr: '0>true()'; rt: rtBool; b: False),
  78. (expr: '0>=true()'; rt: rtBool; b: False),
  79. (expr: '"a" > "a"'; rt: rtBool; b: False),
  80. (expr: '"a" > "b"'; rt: rtBool; b: False),
  81. (expr: '"b" > "a"'; rt: rtBool; b: False),
  82. (expr: '"a" < "a"'; rt: rtBool; b: False),
  83. (expr: '"a" < "b"'; rt: rtBool; b: False),
  84. (expr: '"b" < "a"'; rt: rtBool; b: False),
  85. (expr: '"a" >= "a"'; rt: rtBool; b: False),
  86. (expr: '"a" >= "b"'; rt: rtBool; b: False),
  87. (expr: '"b" >= "a"'; rt: rtBool; b: False),
  88. (expr: '"a" <= "a"'; rt: rtBool; b: False),
  89. (expr: '"a" <= "b"'; rt: rtBool; b: False),
  90. (expr: '"b" <= "a"'; rt: rtBool; b: False),
  91. (expr: '"a" > "0.0"'; rt: rtBool; b: False),
  92. (expr: '"a" < "0.0"'; rt: rtBool; b: False)
  93. );
  94. nscmp = '<doc>'#10+
  95. '<j l="12" w="33">first</j>'#10+
  96. '<j l="17" w="45">second</j>'#10+
  97. '<j l="16" w="78">third</j>'#10+
  98. '<j l="12" w="33">fourth</j>'#10+
  99. '</doc>';
  100. nscmp2 = '<doc>'#10+
  101. '<j l="12" w="45">first</j>'#10+
  102. '<j l="17" w="45">second</j>'#10+
  103. '<j l="16" w="78">third</j>'#10+
  104. '<j l="12" w="33">fourth</j>'#10+
  105. '</doc>';
  106. simple = '<doc>test</doc>';
  107. bool58 = '<doc>'#10+
  108. '<av>'#10+
  109. ' <a>'#10+
  110. ' <b>b</b>'#10+
  111. ' <c>c</c>'#10+
  112. ' <d>d</d>'#10+
  113. ' <e>e</e>'#10+
  114. ' </a>'#10+
  115. ' <v>'#10+
  116. ' <w>w</w>'#10+
  117. ' <x>x</x>'#10+
  118. ' <y>y</y>'#10+
  119. ' <z>z</z>'#10+
  120. ' </v>'#10+
  121. ' <a>'#10+
  122. ' <b>fe</b>'#10+
  123. ' <c>fi</c>'#10+
  124. ' <d>fo</d>'#10+
  125. ' <e>fu</e>'#10+
  126. ' </a>'#10+
  127. ' <v>'#10+
  128. ' <w>fee</w>'#10+
  129. ' <x>fii</x>'#10+
  130. ' <y>foo</y>'#10+
  131. ' <z>fom</z>'#10+
  132. ' </v>'#10+
  133. ' <j>foo</j>'#10+
  134. ' <j>foo</j>'#10+
  135. ' <j>foo</j>'#10+
  136. ' <j>foo</j>'#10+
  137. '</av>'#10+
  138. '</doc>';
  139. bool84='<doc>'#10+
  140. '<avj>'#10+
  141. ' <good>'#10+
  142. ' <b>12</b>'#10+
  143. ' <c>34</c>'#10+
  144. ' <d>56</d>'#10+
  145. ' <e>78</e>'#10+
  146. ' </good>'#10+
  147. '</avj>'#10+
  148. '</doc>';
  149. bool85='<doc>'#10+
  150. '<avj>'#10+
  151. ' <bool>'#10+
  152. ' <b>true</b>'#10+
  153. ' <c></c>'#10+
  154. ' <d>false?</d>'#10+
  155. ' <e>1</e>'#10+
  156. ' <f>0</f>'#10+
  157. ' </bool>'#10+
  158. '</avj>'#10+
  159. '</doc>';
  160. str04='<doc>'#10+
  161. '<a>Testing this</a>'#10+
  162. '<b>and this too</b>'#10+
  163. '</doc>';
  164. NodesetCompareTests: array[0..38] of TTestRec = (
  165. { same nodeset }
  166. (data: nscmp; expr: 'j[@l="12"] = j[@w="33"]'; rt: rtBool; b: True), // #70
  167. { disjoint nodesets }
  168. (data: nscmp; expr: 'j[@l="12"] = j[@l="17"]'; rt: rtBool; b: False), // #71
  169. { both have one common node }
  170. (data: nscmp2; expr: 'j[@l="12"] = j[@w="45"]'; rt: rtBool; b: True), // #72
  171. { same nodeset - unequal }
  172. (data: nscmp; expr: 'j[@l="12"] != j[@w="33"]'; rt: rtBool; b: True), // #73
  173. { disjoint - unequal }
  174. (data: nscmp; expr: 'j[@l="12"] != j[@l="17"]'; rt: rtBool; b: True), // #74
  175. { one common node - unequal }
  176. (data: nscmp2; expr: 'j[@l="12"] != j[@w="45"]'; rt: rtBool; b: True), // #75
  177. { single common node - unequal }
  178. (data: nscmp2; expr: 'j[@l="16"] != j[@w="78"]'; rt: rtBool; b: False),// #76
  179. { nodeset vs. string }
  180. (data: bool58; expr: '/doc/av//*="foo"'; rt: rtBool; b: True), // #58.1
  181. (data: bool58; expr: 'not(/doc/av//*!="foo")'; rt: rtBool; b: False), // #58.2
  182. (data: bool58; expr: '/doc/av//j="foo"'; rt: rtBool; b: True), // #58.3
  183. (data: bool58; expr: 'not(/doc/av//j!="foo")'; rt: rtBool; b: True), // #58.4
  184. { empty nodeset vs. string. Data differs, but that doesn't matter }
  185. (data: bool58; expr: '/doc/avj//k="foo"'; rt: rtBool; b: False), // #59.1
  186. (data: bool58; expr: 'not(/doc/avj//k="foo")'; rt: rtBool; b: True), // #59.2
  187. (data: bool58; expr: '/doc/avj//k!="foo"'; rt: rtBool; b: False), // #59.3
  188. (data: bool58; expr: 'not(/doc/avj//k!="foo")'; rt: rtBool; b: True), // #59.4
  189. { nodeset vs. number }
  190. (data: bool84; expr: '/doc/avj/good/*=34'; rt: rtBool; b: True), // #84.1
  191. (data: bool84; expr: 'not(/doc/avj/good/*=34)'; rt: rtBool; b: False), // #84.2
  192. (data: bool84; expr: '/doc/avj/good/*!=34'; rt: rtBool; b: True), // #84.3
  193. (data: bool84; expr: 'not(/doc/avj/good/*!=34)'; rt: rtBool; b: False),// #84.4
  194. { same with reversed order of operands }
  195. (data: bool84; expr: '34=/doc/avj/good/*'; rt: rtBool; b: True), // #84.5
  196. (data: bool84; expr: 'not(34=/doc/avj/good/*)'; rt: rtBool; b: False), // #84.6
  197. (data: bool84; expr: '34!=/doc/avj/good/*'; rt: rtBool; b: True), // #84.7
  198. (data: bool84; expr: 'not(34!=/doc/avj/good/*)'; rt: rtBool; b: False),// #84.8
  199. { nodeset vs. boolean }
  200. (data: bool85; expr: '/doc/avj/bool/*=true()'; rt: rtBool; b: True), // #85.1
  201. (data: bool85; expr: 'not(/doc/avj/bool/*=true())'; rt: rtBool; b: False), // #85.2
  202. (data: bool85; expr: '/doc/avj/bool/*!=true()'; rt: rtBool; b: False), // #85.3
  203. (data: bool85; expr: 'not(/doc/avj/bool/*!=true())'; rt: rtBool; b: True), // #85.4
  204. { same with reversed order of operands }
  205. (data: bool85; expr: 'true()=/doc/avj/bool/*'; rt: rtBool; b: True), // #85.5
  206. (data: bool85; expr: 'not(true()=/doc/avj/bool/*)'; rt: rtBool; b: False), // #85.6
  207. (data: bool85; expr: 'true()!=/doc/avj/bool/*'; rt: rtBool; b: False), // #85.7
  208. (data: bool85; expr: 'not(true()!=/doc/avj/bool/*)'; rt: rtBool; b: True), // #85.8
  209. { empty nodeset vs. boolean }
  210. (data: bool85; expr: '/doc/avj/none/*=true()'; rt: rtBool; b: False), // #86.1
  211. (data: bool85; expr: 'not(/doc/avj/none/*=true())'; rt: rtBool; b: True), // #86.2
  212. (data: bool85; expr: '/doc/avj/none/*!=true()'; rt: rtBool; b: True), // #86.3
  213. (data: bool85; expr: 'not(/doc/avj/none/*!=true())'; rt: rtBool; b: False),// #86.4
  214. { same with reversed order of operands }
  215. (data: bool85; expr: 'true()=/doc/avj/none/*'; rt: rtBool; b: False), // #86.5
  216. (data: bool85; expr: 'not(true()=/doc/avj/none/*)'; rt: rtBool; b: True), // #86.6
  217. (data: bool85; expr: 'true()!=/doc/avj/none/*'; rt: rtBool; b: True), // #86.7
  218. (data: bool85; expr: 'not(true()!=/doc/avj/none/*)'; rt: rtBool; b: False) // #86.8
  219. );
  220. EqualityTests: array[0..25] of TTestRec = (
  221. (expr: '1=1'; rt: rtBool; b: True),
  222. (expr: '1!=1'; rt: rtBool; b: False),
  223. (expr: '1=0'; rt: rtBool; b: False),
  224. (expr: '1!=0'; rt: rtBool; b: True),
  225. (expr: 'true()=true()'; rt: rtBool; b: True),
  226. (expr: 'true()!=true()'; rt: rtBool; b: False),
  227. (expr: 'true()=false()'; rt: rtBool; b: False),
  228. (expr: 'false()!=true()'; rt: rtBool; b: True),
  229. (expr: '"test"="test"'; rt: rtBool; b: True),
  230. (expr: '"test"!="test"'; rt: rtBool; b: False),
  231. (expr: '"test2"="test"'; rt: rtBool; b: False),
  232. (expr: '"test2"!="test"'; rt: rtBool; b: True),
  233. (expr: 'false()=0'; rt: rtBool; b: True),
  234. (expr: 'false()!=0'; rt: rtBool; b: False),
  235. (expr: 'false()=1'; rt: rtBool; b: False),
  236. (expr: 'false()!=1'; rt: rtBool; b: True),
  237. (expr: '0=true()'; rt: rtBool; b: False),
  238. (expr: '0!=true()'; rt: rtBool; b: True),
  239. (expr: '1=true()'; rt: rtBool; b: True),
  240. (expr: '1!=true()'; rt: rtBool; b: False),
  241. (expr: 'true()="test"'; rt: rtBool; b: True),
  242. (expr: 'false()="test"'; rt: rtBool; b: False),
  243. (expr: '"test"!=true()'; rt: rtBool; b: False),
  244. (expr: '"test"!=false()'; rt: rtBool; b: True),
  245. (expr: '"a"=0.0'; rt: rtBool; b: False),
  246. (expr: '"a"!=0.0'; rt: rtBool; b: True)
  247. );
  248. math88='<doc>'+
  249. '<n0>0</n0>'+
  250. '<n1>1</n1>'+
  251. '<n2>2</n2>'+
  252. '<n3>3</n3>'+
  253. '<n4>4</n4>'+
  254. '<n5>5</n5>'+
  255. '<n6>6</n6>'+
  256. '<n7>2</n7>'+
  257. '<n8>6</n8>'+
  258. '<n9>10</n9>'+
  259. '<n10>3</n10>'+
  260. '</doc>';
  261. math85='<doc>'+
  262. '<n0>0</n0>'+
  263. '<n1>1</n1>'+
  264. '<n2>2</n2>'+
  265. '<n3>3</n3>'+
  266. '<n4>4</n4>'+
  267. '<e>five</e>'+
  268. '</doc>';
  269. math80='<doc>'+
  270. '<n1 attrib="10">5</n1>'+
  271. '<n2 attrib="4">2</n2>'+
  272. '<div attrib="-5">-5</div>'+
  273. '<mod attrib="-2">2</mod>'+
  274. '</doc>';
  275. math69='<doc>'+
  276. '<n-1 attrib="9">3</n-1>'+
  277. '<n-2 attrib="1">7</n-2>'+
  278. '</doc>';
  279. FloatTests: array[0..70] of TTestRec = (
  280. (expr: '1'; rt: rtNumber; n: 1),
  281. (expr: '123'; rt: rtNumber; n: 123),
  282. (expr: '1.23'; rt: rtNumber; n: 1.23),
  283. (expr: '0.123'; rt: rtNumber; n: 0.123),
  284. (expr: '4.'; rt: rtNumber; n: 4),
  285. (expr: '.4'; rt: rtNumber; n: 0.4),
  286. //(expr: '1.23e3'; rt: rtNumber; n: 1230),
  287. //(expr: '1.23e-3'; rt: rtNumber; n: 0.00123),
  288. (expr: '1 div 0'; rt: rtNumber; n: Infinity),
  289. (expr: '-1 div 0'; rt: rtNumber; n: -Infinity),
  290. (expr: '0 div 0'; rt: rtNumber; n: NaN),
  291. (expr: '1 div -0'; rt: rtNumber; n: -Infinity),
  292. (expr: '(1 div 0) > 0'; rt: rtBool; b: True),
  293. (expr: '(1 div 0) < 0'; rt: rtBool; b: False),
  294. (expr: '(-1 div 0) > 0'; rt: rtBool; b: False),
  295. (expr: '(-1 div 0) < 0'; rt: rtBool; b: True),
  296. (expr: '(0 div 0) > 0'; rt: rtBool; b: False),
  297. (expr: '(0 div 0) < 0'; rt: rtBool; b: False),
  298. (expr: '(1 div -0) > 0'; rt: rtBool; b: False),
  299. (expr: '(1 div -0) < 0'; rt: rtBool; b: True),
  300. (expr: '0 div 0 = 0 div 0'; rt: rtBool; b: False),
  301. (expr: '0 div 0 != 0 div 0'; rt: rtBool; b: True),
  302. (expr: '0 div 0 > 0 div 0'; rt: rtBool; b: False),
  303. (expr: '0 div 0 < 0 div 0'; rt: rtBool; b: False),
  304. (expr: '0 div 0 >= 0 div 0'; rt: rtBool; b: False),
  305. (expr: '0 div 0 <= 0 div 0'; rt: rtBool; b: False),
  306. (expr: '1 div 0 = -1 div 0'; rt: rtBool; b: False),
  307. (expr: '1 div 0 != -1 div 0'; rt: rtBool; b: True),
  308. (expr: '1 div 0 > -1 div 0'; rt: rtBool; b: True),
  309. (expr: '1 div 0 < -1 div 0'; rt: rtBool; b: False),
  310. (expr: '1 div 0 >= -1 div 0'; rt: rtBool; b: True),
  311. (expr: '1 div 0 <= -1 div 0'; rt: rtBool; b: False),
  312. (expr: '1 div 0 = 1 div 0'; rt: rtBool; b: True),
  313. (expr: '1 div 0 != 1 div 0'; rt: rtBool; b: False),
  314. (expr: '1 div 0 > 1 div 0'; rt: rtBool; b: False),
  315. (expr: '1 div 0 < 1 div 0'; rt: rtBool; b: False),
  316. (expr: '1 div 0 >= -1 div 0'; rt: rtBool; b: True),
  317. (expr: '1 div 0 <= -1 div 0'; rt: rtBool; b: False),
  318. (expr: '-2 div 0 = -1 div 0'; rt: rtBool; b: True),
  319. (expr: '1 div floor(0.1)'; rt: rtNumber; n: Infinity),
  320. (expr: '1 div floor(-0.1)'; rt: rtNumber; n: -1),
  321. (expr: '1 div floor(-0)'; rt: rtNumber; n: -Infinity),
  322. (expr: '1 div floor(0)'; rt: rtNumber; n: Infinity),
  323. (expr: '1 div ceiling(0.1)'; rt: rtNumber; n: 1),
  324. (expr: '1 div ceiling(-0.1)'; rt: rtNumber; n: -Infinity),
  325. (expr: '1 div ceiling(-0)'; rt: rtNumber; n: -Infinity),
  326. (expr: '1 div ceiling(0)'; rt: rtNumber; n: Infinity),
  327. (expr: '1 div round(0.1)'; rt: rtNumber; n: Infinity),
  328. (expr: '1 div round(-0.1)'; rt: rtNumber; n: -Infinity),
  329. (expr: '1 div round(-0)'; rt: rtNumber; n: -Infinity),
  330. (expr: '1 div round(0)'; rt: rtNumber; n: Infinity),
  331. (expr: '1 div number("f")'; rt: rtNumber; n: NaN),
  332. (expr: 'number("f") div 1'; rt: rtNumber; n: NaN),
  333. (expr: '1 div (1 div 0)'; rt: rtNumber; n: 0),
  334. (expr: '(1 div 0) div 1'; rt: rtNumber; n: Infinity),
  335. (expr: '-(1 div 0) div 1'; rt: rtNumber; n: -Infinity),
  336. (expr: '5 mod 2'; rt: rtNumber; n: 1),
  337. (expr: '5 mod -2'; rt: rtNumber; n: 1),
  338. (expr: '-5 mod 2'; rt: rtNumber; n: -1),
  339. (expr: '-5 mod -2'; rt: rtNumber; n: -1),
  340. (expr: '2 mod number("xxx")'; rt: rtNumber; n: NaN),
  341. (expr: 'number("xxx") mod 3'; rt: rtNumber; n: NaN),
  342. (expr: '8 mod 3 = 2'; rt: rtBool; b: True),
  343. (data: math88; expr: '(n1*n2*n3*n4*n5*n6)div n7 div n8 div n9 div n10'; rt: rtNumber; n: 2),
  344. (data: math85; expr: '((((((n3+5)*(3)+(((n2)+2)*(n1 - 6)))-(n4 - n2))+(-(4-6)))))'; rt: rtNumber; n: 4),
  345. (data: math80; expr: 'div mod mod'; rt: rtNumber; n: -1),
  346. (data: math69; expr: '-(n-2/@attrib) - -(n-1/@attrib)'; rt: rtNumber; n: 8),
  347. (data: math69; expr: '-n-2/@attrib --n-1/@attrib'; rt: rtNumber; n: 8),
  348. (data: math69; expr: '-n-2 --n-1'; rt: rtNumber; n: -4),
  349. // test boolean operator short-circuting; "count(5)" acts as an error
  350. (expr: '10+30*20 or count(5)'; rt: rtBool; b: True),
  351. (expr: '75-50-25 and count(5)'; rt: rtBool; b: False),
  352. (expr: '"1" and "0"'; rt: rtBool; b: True),
  353. (expr: '0 or ""'; rt: rtBool; b: False)
  354. );
  355. math95='<doc>'+
  356. '<e>1</e>'+
  357. '<e>2</e>'+
  358. '<e>3</e>'+
  359. '<e>4</e>'+
  360. '<e>five</e>'+
  361. '</doc>';
  362. math96='<doc>'+
  363. '<e>17</e>'+
  364. '<e>-5</e>'+
  365. '<e>8</e>'+
  366. '<e>-37</e>'+
  367. '</doc>';
  368. expr01='<doc>'+
  369. '<para id="1" xml:lang="en">en</para>'+
  370. '<div xml:lang="en">'+
  371. ' <para>en</para>'+
  372. '</div>'+
  373. '<para id="3" xml:lang="EN">EN</para>'+
  374. '<para id="4" xml:lang="en-us">en-us</para>'+
  375. '</doc>';
  376. id04='<!DOCTYPE t04 ['+
  377. '<!ELEMENT t04 (a*)>'+
  378. '<!ELEMENT a EMPTY>'+
  379. '<!ATTLIST a id ID #REQUIRED>'+
  380. ']>'+
  381. '<t04>'+
  382. '<a id="a"/>'+
  383. '<a id="b"/>'+
  384. '<a id="c"/>'+
  385. '<a id="d"/>'+
  386. '</t04>';
  387. pos04='<doc>'+
  388. '<a test="true"><num>1</num></a>'+
  389. '<a><num>1191</num></a>'+
  390. '<a><num>263</num></a>'+
  391. '<a test="true"><num>2</num></a>'+
  392. '<a><num>827</num></a>'+
  393. '<a><num>256</num></a>'+
  394. '<a test="true"><num>3</num></a>'+
  395. '<a test="true"><num>4</num></a>'+
  396. '</doc>';
  397. FunctionTests: array[0..51] of TTestRec = (
  398. // last()
  399. // local-name()
  400. // namespace-uri()
  401. // name()
  402. (expr: 'boolean(0)'; rt: rtBool; b: False),
  403. (expr: 'boolean(-0)'; rt: rtBool; b: False),
  404. (expr: 'boolean(1 div 0)'; rt: rtBool; b: True),
  405. (expr: 'boolean(-1 div 0)'; rt: rtBool; b: True),
  406. (expr: 'boolean(0 div 0)'; rt: rtBool; b: False),
  407. (expr: 'boolean("")'; rt: rtBool; b: False),
  408. (expr: 'boolean("abc")'; rt: rtBool; b: True),
  409. (data: simple; expr: 'boolean(/doc)'; rt: rtBool; b: True), // #40
  410. (data: simple; expr: 'boolean(foo)'; rt: rtBool; b: False), // #41
  411. (expr: 'true()'; rt: rtBool; b: True),
  412. (expr: 'false()'; rt: rtBool; b: False),
  413. (expr: 'not(true())'; rt: rtBool; b: False),
  414. (expr: 'not(false())'; rt: rtBool; b: True),
  415. (expr: 'not("")'; rt: rtBool; b: True),
  416. // lang() tests. These ones, however, test much more than lang().
  417. (data: expr01; expr: 'para[@id="1" and lang("en")]'; rt: rtNodeStr; s: 'en'), // expression01
  418. (data: expr01; expr: 'para[@id="4" and lang("en")]'; rt: rtNodeStr; s: 'en-us'), // expression03
  419. (data: expr01; expr: 'div/para[lang("en")]'; rt: rtNodeStr; s: 'en'), // expression04
  420. (data: expr01; expr: 'para[@id="3" and lang("en")]'; rt: rtNodeStr; s: 'EN'), // expression05
  421. (data: id04; expr: 'id("c")/@id'; rt: rtNodeStr; s: 'c'), // idkey04
  422. // position() tests
  423. (data: pos04; expr: '*[@test][position()=4]/num'; rt: rtNodeStr; s: '4'),
  424. (expr: 'number("1.5")'; rt: rtNumber; n: 1.5),
  425. (expr: 'number("abc")'; rt: rtNumber; n: NaN),
  426. (expr: '-number("abc")'; rt: rtNumber; n: NaN),
  427. (expr: 'number(true())'; rt: rtNumber; n: 1.0),
  428. (expr: 'number(false())'; rt: rtNumber; n: 0),
  429. (data: math95; expr: 'sum(e)'; rt: rtNumber; n: NaN),
  430. (data: math96; expr: 'sum(e)'; rt: rtNumber; n: -17),
  431. (expr: 'floor(0.1)'; rt: rtNumber; n: 0),
  432. (expr: 'floor(-0.1)'; rt: rtNumber; n: -1),
  433. (expr: 'floor(-0)'; rt: rtNumber; n: 0),
  434. (expr: 'floor(0)'; rt: rtNumber; n: 0),
  435. (expr: 'floor(5.2)'; rt: rtNumber; n: 5),
  436. (expr: 'floor(-5.2)'; rt: rtNumber; n: -6),
  437. (expr: 'floor("NaN")'; rt: rtNumber; n: NaN),
  438. (expr: 'ceiling(0.1)'; rt: rtNumber; n: 1),
  439. (expr: 'ceiling(-0.1)'; rt: rtNumber; n: 0),
  440. (expr: 'ceiling(-0)'; rt: rtNumber; n: 0),
  441. (expr: 'ceiling(0)'; rt: rtNumber; n: 0),
  442. (expr: 'ceiling(5.2)'; rt: rtNumber; n: 6),
  443. (expr: 'ceiling(-5.2)'; rt: rtNumber; n: -5),
  444. (expr: 'ceiling("NaN")'; rt: rtNumber; n: NaN),
  445. (expr: 'round(0.1)'; rt: rtNumber; n: 0),
  446. (expr: 'round(5.2)'; rt: rtNumber; n: 5),
  447. (expr: 'round(5.5)'; rt: rtNumber; n: 6),
  448. (expr: 'round(5.6)'; rt: rtNumber; n: 6),
  449. (expr: 'round(-0.1)'; rt: rtNumber; n: 0),
  450. (expr: 'round(-5.2)'; rt: rtNumber; n: -5),
  451. (expr: 'round(-5.5)'; rt: rtNumber; n: -5),
  452. (expr: 'round(-5.6)'; rt: rtNumber; n: -6),
  453. (expr: 'round("NaN")'; rt: rtNumber; n: NaN),
  454. (expr: 'round(1 div 0)'; rt: rtNumber; n: Infinity),
  455. (expr: 'round(-1 div 0)'; rt: rtNumber; n: -Infinity)
  456. );
  457. str14 ='<doc>'#10+
  458. ' <av>'#10+
  459. ' <a>'#10+
  460. ' <b>b</b>'#10+
  461. ' <c>c</c>'#10+
  462. ' <d>d</d>'#10+
  463. ' <e>e</e>'#10+
  464. ' </a>'#10+
  465. ' <v>'#10+
  466. ' <w>w</w>'#10+
  467. ' <x>x</x>'#10+
  468. ' <y>y</y>'#10+
  469. ' <z>z</z>'#10+
  470. ' </v>'#10+
  471. ' </av>'#10+
  472. '</doc>';
  473. out14 =#10+
  474. ' b'#10+
  475. ' c'#10+
  476. ' d'#10+
  477. ' e'#10+
  478. ' ';
  479. node08='<docs xmlns:ped="http://www.ped.com"><?MyPI DoesNothing ?><!-- This is a big tree containing all letters of the alphabet -->'#10+
  480. '<a attr1="This should not be seen">A</a>'#10+
  481. '<b><c attr1="tsnbs" attr2="tsnbs">B-C</c>'#10+
  482. '<d><e><f>TextNode_between_F_and_G'#10+
  483. '<g><h><i><j><k><l><m><n><o><p><q><r><s><t><u><v><w><x><y><z><Yahoo>Yahoo</Yahoo>'#10+
  484. '</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+
  485. '</docs>';
  486. out08=#10+
  487. 'A'#10+
  488. 'B-C'#10+
  489. 'TextNode_between_F_and_G'#10+
  490. 'Yahoo'#10+
  491. 'SecondNode_after_H'#10;
  492. str30='<doc xmlns="http://xsl.lotus.com/ns2" xmlns:ns1="http://xsl.lotus.com/ns1">'#10+
  493. '<ns1:a attrib1="test" xmlns="http://xsl.lotus.com/ns2" xmlns:ns1="http://xsl.lotus.com/ns1"/>'#10+
  494. '<b ns1:attrib2="test"/>'#10+
  495. '</doc>';
  496. ns11='<doc-one xmlns="http://xsl.lotus.com/ns2" xmlns:ns1="http://xsl.lotus.com/ns1">'+
  497. ' <ns1:a-two attrib1="Goodbye" xmlns="http://xsl.lotus.com/ns2" xmlns:ns1="http://xsl.lotus.com/ns1">Hello</ns1:a-two>'+
  498. ' <b-three ns1:attrib2="Ciao">'+
  499. ' <c-four/>'+
  500. ' </b-three>'+
  501. '</doc-one>';
  502. pidata='<?a-pi data="foo"?><?b-pi data="bar"?><doc/>';
  503. StringTests: array[0..87] of TTestRec = ( // numbers refer to xalan/string/stringXX
  504. (expr: 'string(0)'; rt: rtString; s: '0'),
  505. (expr: 'string(5)'; rt: rtString; s: '5'), // #38/39
  506. (expr: 'string(0.5)'; rt: rtString; s: '0.5'),
  507. (expr: 'string(-0.5)'; rt: rtString; s: '-0.5'),
  508. (expr: 'string("test")'; rt: rtString; s: 'test'), // #40
  509. (expr: 'string("")'; rt: rtString; s: ''), // #41
  510. (expr: 'string(true())'; rt: rtString; s: 'true'),
  511. (expr: 'string(false())'; rt: rtString; s: 'false'),
  512. (expr: 'string(0 div 0)'; rt: rtString; s: 'NaN'),
  513. (expr: 'string(1 div 0)'; rt: rtString; s: 'Infinity'),
  514. (expr: 'string(-1 div 0)'; rt: rtString; s: '-Infinity'),
  515. // maybe other checks for correct numeric formats
  516. (data: str14; expr: 'string(av//*)'; rt: rtString; s: out14),
  517. (data: node08; expr: '/'; rt: rtNodeStr; s: out08),
  518. (expr: 'concat("titi","toto")'; rt: rtString; s: 'tititoto'),
  519. (expr: 'concat("titi","toto","tata")'; rt: rtString; s: 'tititototata'),
  520. (expr: 'concat("titi",''toto'')'; rt: rtString; s: 'tititoto'),
  521. (expr: 'concat("titi",''toto'',"tata","last")'; rt: rtString; s: 'tititototatalast'),
  522. (expr: 'concat("cd", 34)'; rt: rtString; s: 'cd34'), // #101
  523. (expr: 'concat(false(), "ly")'; rt: rtString; s: 'falsely'), // #104
  524. (expr: 'starts-with("tititoto","titi")'; rt: rtBool; b: True),
  525. (expr: 'starts-with("tititoto","to")'; rt: rtBool; b: False),
  526. (expr: 'starts-with("ab", "abc")'; rt: rtBool; b: False), // #46
  527. (expr: 'starts-with("abc", "bc")'; rt: rtBool; b: False), // #47
  528. (expr: 'starts-with("abc", "")'; rt: rtBool; b: True), // #48
  529. (expr: 'starts-with("", "")'; rt: rtBool; b: True), // #49
  530. (expr: 'starts-with(true(), "tr")'; rt: rtBool; b: True), // #50
  531. (expr: 'contains("tititototata","titi")'; rt: rtBool; b: True),
  532. (expr: 'contains("tititototata","toto")'; rt: rtBool; b: True),
  533. (expr: 'contains("tititototata","tata")'; rt: rtBool; b: True),
  534. (expr: 'contains("tititototata","tita")'; rt: rtBool; b: False),
  535. // 'contains(concat(.,'BC'),concat('A','B','C'))' == true // #57
  536. (expr: 'contains("ab", "abc")'; rt: rtBool; b: False), // #58
  537. (expr: 'contains("abc", "bcd")'; rt: rtBool; b: False), // #60
  538. (expr: 'contains("abc", "")'; rt: rtBool; b: True), // #61
  539. (expr: 'contains("", "")'; rt: rtBool; b: True), // #62
  540. (expr: 'contains(true(), "e")'; rt: rtBool; b: True), // #63
  541. (expr: 'substring("12345",2,3)'; rt: rtString; s: '234'),
  542. (expr: 'substring("12345",2)'; rt: rtString; s: '2345'),
  543. (expr: 'substring("12345",-4)'; rt: rtString; s: '12345'),
  544. (expr: 'substring("12345",3.4)'; rt: rtString; s: '345'),
  545. (expr: 'substring("12345",3.6)'; rt: rtString; s: '45'),
  546. (expr: 'substring("12345",1.5,2.6)'; rt: rtString; s: '234'), // #16
  547. (expr: 'substring("12345",2.2,2.2)'; rt: rtString; s: '23'),
  548. (expr: 'substring("12345",0,3)'; rt: rtString; s: '12'), // #17
  549. (expr: 'substring("12345",-8,10)'; rt: rtString; s: '1'),
  550. (expr: 'substring("12345",4,-10)'; rt: rtString; s: ''),
  551. (expr: 'substring("12345",0 div 0, 3)'; rt: rtString; s: ''), // #18
  552. (expr: 'substring("12345",1, 0 div 0)'; rt: rtString; s: ''), // #19
  553. (expr: 'substring("12345",1 div 0, 3)'; rt: rtString; s: ''),
  554. (expr: 'substring("12345",3,-1 div 0)'; rt: rtString; s: ''),
  555. (expr: 'substring("12345",-42, 1 div 0)'; rt: rtString; s: '12345'), // #20
  556. (expr: 'substring("12345",-1 div 0, 1 div 0)'; rt: rtString; s: ''), // #21
  557. (expr: 'substring("12345",-1 div 0,5)'; rt: rtString; s: ''),
  558. (expr: 'substring-before("1999/04/01","/")'; rt: rtString; s: '1999'), // #08
  559. (expr: 'substring-before("1999/04/01","a")'; rt: rtString; s: ''), // #68 modified
  560. (expr: 'substring-after("1999/04/01","/")'; rt: rtString; s: '04/01'), // #09
  561. (expr: 'substring-after("1999/04/01","19")'; rt: rtString; s: '99/04/01'),
  562. (expr: 'substring-after("1999/04/01","a")'; rt: rtString; s: ''),
  563. (expr: 'string-length("")'; rt: rtNumber; n: 0),
  564. (expr: 'string-length("titi")'; rt: rtNumber; n: 4),
  565. (data: simple; expr: 'string-length(.)'; rt: rtNumber; n: 4), // #02 modified
  566. (data: str04; expr: 'string-length(/)'; rt: rtNumber; n:27), // #04.1 modified
  567. (data: str04; expr: 'string-length(/doc/a)'; rt: rtNumber; n: 12), // #04.2
  568. (data: str04; expr: 'string-length()'; rt: rtNumber; n: 27),
  569. (expr: 'normalize-space("'#9#10#13' ab cd'#10#13#9'ef'#9#10#13' ")'; rt: rtString; s: 'ab cd ef'), // #10
  570. (expr: 'translate("bar", "abc", "ABC")'; rt: rtString; s: 'BAr'), // #11
  571. (expr: 'translate("--aaa--","abc-","ABC")'; rt: rtString; s: 'AAA'),
  572. (expr: 'translate("ddaaadddd","abcd","ABCxy")'; rt: rtString; s: 'xxAAAxxxx'), // #96
  573. (data: node08; expr: 'name(a/@attr1)'; rt: rtString; s: 'attr1'), // namespace08 modified
  574. (data: node08; expr: 'namespace-uri(a/@attr1)'; rt: rtString; s: ''),
  575. (data: node08; expr: 'local-name(a/@attr1)'; rt: rtString; s: 'attr1'),
  576. (data: pidata; expr: 'name(/processing-instruction())'; rt: rtString; s: 'a-pi'), // namespace29 modified
  577. (data: pidata; expr: 'name(/processing-instruction("b-pi"))'; rt: rtString; s: 'b-pi'),
  578. (data: pidata; expr: 'local-name(/processing-instruction())'; rt: rtString; s: 'a-pi'),
  579. (data: pidata; expr: 'namespace-uri(/processing-instruction())'; rt: rtString; s: ''),
  580. (data: node08; expr: 'name(//comment())'; rt: rtString; s: ''), // namespace30 modified
  581. (data: node08; expr: 'local-name(//comment())'; rt: rtString; s: ''),
  582. (data: node08; expr: 'namespace-uri(//comment())'; rt: rtString; s: ''),
  583. (data: node08; expr: 'name(//text())'; rt: rtString; s: ''), // namespace31 modified
  584. (data: node08; expr: 'local-name(//text())'; rt: rtString; s: ''),
  585. (data: node08; expr: 'namespace-uri(//text())'; rt: rtString; s: ''),
  586. // tests for number->string conversions at boundary conditions
  587. (expr: 'string(123456789012345678)'; rt: rtString; s: '123456789012345680'), // #132.1
  588. (expr: 'string(-123456789012345678)'; rt: rtString; s: '-123456789012345680'), // #132.2
  589. (expr: 'string(.10123456789234567893)'; rt: rtString; s: '0.10123456789234568'), // #133.1
  590. (expr: 'string(-.10123456789234567893)'; rt: rtString; s: '-0.10123456789234568'), // #133.2
  591. (expr: 'string(9.87654321012345)'; rt: rtString; s: '9.87654321012345'), // #134.1
  592. (expr: 'string(98765432101234.5)'; rt: rtString; s: '98765432101234.5'), // #134.2
  593. (expr: 'string(.0000000000000000000000000000000000000000123456789)'; rt: rtString; // #135.1
  594. s: '0.0000000000000000000000000000000000000000123456789'),
  595. (expr: 'string(-.0000000000000000000000000000000000000000123456789)'; rt: rtString; // #135.2
  596. s: '-0.0000000000000000000000000000000000000000123456789')
  597. );
  598. res1 = '<foo xmlns:baz1="http://xsl.lotus.com/ns1" xmlns:baz2="http://xsl.lotus.com/ns2"/>';
  599. nameTests: array[0..17] of TTestRec3 = (
  600. (data: str30; re: res1; expr: 'namespace-uri(baz1:a/@baz2:attrib1)'; rt: rtString; s: ''), // #30
  601. (data: str30; re: res1; expr: 'namespace-uri(baz2:b/@baz1:attrib2)'; rt: rtString; s: 'http://xsl.lotus.com/ns1'), // #31
  602. (data: str30; re: res1; expr: 'name(*)'; rt: rtString; s: 'ns1:a'), // #32
  603. (data: str30; re: res1; expr: 'name(baz1:a)'; rt: rtString; s: 'ns1:a'), // #33
  604. (data: str30; re: res1; expr: 'name(baz2:b)'; rt: rtString; s: 'b'), // #34
  605. (data: str30; re: res1; expr: 'name(baz1:a/@baz2:attrib1)'; rt: rtString; s: ''), // #35
  606. (data: str30; re: res1; expr: 'name(baz2:b/@baz1:attrib2)'; rt: rtString; s: 'ns1:attrib2'), // #36
  607. (data: str30; re: res1; expr: 'local-name(baz2:b)'; rt: rtString; s: 'b'), // namespace07
  608. (data: str30; re: res1; expr: 'local-name(baz2:b/@baz1:attrib2)'; rt: rtString; s: 'attrib2'), // namespace09
  609. (data: str30; re: res1; expr: 'local-name()'; rt: rtString; s: 'doc'), // namespace26
  610. (data: str30; re: res1; expr: 'namespace-uri()'; rt: rtString; s: 'http://xsl.lotus.com/ns2'), // namespace27
  611. (data: ns11; re: res1; expr: 'namespace-uri(baz1:a-two)'; rt: rtString; s: 'http://xsl.lotus.com/ns1'), // namespace11
  612. (data: ns11; re: res1; expr: 'namespace-uri(baz1:a-two/@attrib1)'; rt: rtString; s: ''),
  613. (data: ns11; re: res1; expr: 'namespace-uri(baz2:b-three)'; rt: rtString; s: 'http://xsl.lotus.com/ns2'),
  614. (data: ns11; re: res1; expr: 'namespace-uri(baz2:b-three/@baz1:attrib2)'; rt: rtString; s: 'http://xsl.lotus.com/ns1'),
  615. {*} (data: ns11; re: res1; expr: 'namespace-uri(baz2:b-three/c-four)'; rt: rtString; s: ''),
  616. (data: ns11; re: res1; expr: 'namespace-uri(bogus)'; rt: rtString; s: ''),
  617. (data: str30; re: res1; expr: 'name(baz1:*)'; rt: rtString; s: 'ns1:a')
  618. );
  619. ax114='<doc>'+
  620. '<foo att1="c">'+
  621. ' <foo att1="b">'+
  622. ' <foo att1="a"/>'+
  623. ' </foo>'+
  624. '</foo>'+
  625. '<baz/>'+
  626. '</doc>';
  627. ax115='<doc>'+
  628. '<foo att1="c"/>'+
  629. '<foo att1="b"/>'+
  630. '<foo att1="a"/>'+
  631. '<baz/>'+
  632. '</doc>';
  633. ax117='<chapter title="A" x="0">'+
  634. '<section title="A1" x="1">'+
  635. ' <subsection title="A1a" x="2">hello</subsection>'+
  636. ' <subsection title="A1b">ahoy</subsection>'+
  637. '</section>'+
  638. '<section title="A2">'+
  639. ' <subsection title="A2a">goodbye</subsection>'+
  640. ' <subsection title="A2b">sayonara</subsection>'+
  641. ' <subsection title="A2c">adios</subsection>'+
  642. '</section>'+
  643. '<section title="A3">'+
  644. ' <subsection title="A3a">aloha</subsection>'+
  645. ' <subsection title="A3b">'+
  646. ' <footnote x="3">A3b-1</footnote>'+
  647. ' <footnote>A3b-2</footnote>'+
  648. ' </subsection>'+
  649. ' <subsection title="A3c">shalom</subsection>'+
  650. '</section>'+
  651. '</chapter>';
  652. AxesTests: array[0..15] of TTestRec = (
  653. (data: ax117; expr: 'count(//@*)'; rt: rtNumber; n: 16),
  654. (data: ax117; expr: 'count(//@title)'; rt: rtNumber; n: 12),
  655. (data: ax117; expr: 'count(//section//@*)'; rt: rtNumber; n: 14),
  656. (data: ax117; expr: 'count(//section//@title)'; rt: rtNumber; n: 11),
  657. (data: ax117; expr: 'count(/chapter/.//@*)'; rt: rtNumber; n: 16),
  658. (data: ax117; expr: 'count(/chapter/.//@title)'; rt: rtNumber; n: 12),
  659. (data: ax117; expr: 'count(/chapter/section[1]//@*)'; rt: rtNumber; n: 5),
  660. (data: ax117; expr: 'count(/chapter/section[1]//@title)'; rt: rtNumber; n: 3),
  661. (data: ax117; expr: 'count(/chapter/section[2]//@*)'; rt: rtNumber; n: 4),
  662. (data: ax117; expr: 'count(/chapter/section[2]//@title)'; rt: rtNumber; n: 4),
  663. (data: ax117; expr: 'count(/chapter/section[3]//@*)'; rt: rtNumber; n: 5),
  664. (data: ax117; expr: 'count(/chapter/section[3]//@title)'; rt: rtNumber; n: 4),
  665. (data: simple; expr: 'local-name(namespace::*[1])'; rt: rtString; s: 'xml'), // namespace28a
  666. (data: simple; expr: 'name(namespace::*[1])'; rt: rtString; s: 'xml'), // namespace28b
  667. (data: ax117; expr: 'name(//subsection[@title="A3b"]/@title/parent::*)'; rt: rtString; s: 'subsection'), // axes96 modified
  668. (data: ax117; expr: 'name(//subsection[@title="A3b"]/@title/ancestor::*[1])'; rt: rtString; s: 'subsection') // axes97 modified
  669. );
  670. AxesTests2: array[0..3] of TTestRec3 = (
  671. (data: ax114; re: '//baz'; expr: 'preceding::foo[1]/@att1'; rt: rtNodeStr; s: 'a'),
  672. (data: ax114; re: '//baz'; expr: '(preceding::foo)[1]/@att1'; rt: rtNodeStr; s: 'c'), // won't parse
  673. (data: ax115; re: '//baz'; expr: 'preceding-sibling::foo[1]/@att1'; rt: rtNodeStr; s: 'a'),
  674. (data: ax115; re: '//baz'; expr: '(preceding-sibling::foo)[1]/@att1'; rt: rtNodeStr; s: 'c') // won't parse
  675. );
  676. pred44 = '<doc>'+
  677. '<element1>'+
  678. '<child1>Success</child1>'+
  679. '<child2>child2</child2>'+
  680. '</element1>'+
  681. '<element2>'+
  682. '<child1>Wrong node selected!!</child1>'+
  683. '</element2>'+
  684. '<element3>'+
  685. '<child1>Wrong node selected!!</child1>'+
  686. '</element3>'+
  687. '</doc>';
  688. pred11 = '<doc>'+
  689. '<a>1</a>'+
  690. '<a>2'+
  691. '<achild>target</achild>'+
  692. '</a>'+
  693. '<a>3</a>'+
  694. '<a>target</a>'+
  695. '</doc>';
  696. PredicateTests: array [0..4] of TTestRec = (
  697. (data: pred44; expr: '//child1[parent::element1]'; rt: rtNodeStr; s: 'Success'), // predicate44
  698. {should select all but last elements named 'e' }
  699. (data: math96; expr: 'sum(e[true()=following-sibling::*])'; rt: rtNumber; n: 20), // predicate03
  700. {should select two first elements}
  701. (data: math96; expr: 'sum(e[8=following-sibling::*])'; rt: rtNumber; n: 12), // predicate05
  702. (data: pred11; expr: 'a["target"=descendant::*]'; rt: rtNodeStr; s: '2target'), // predicate06
  703. (data: pred11; expr: 'a[following-sibling::*=descendant::*]'; rt: rtNodeStr; s: '2target') // predicate11
  704. );
  705. {$warnings on}
  706. var
  707. FailCount: Integer = 0;
  708. procedure CheckResult(const t: TTestRec; r: TXPathVariable); overload;
  709. begin
  710. case t.rt of
  711. rtBool:
  712. begin
  713. if (r is TXPathBooleanVariable) and (r.AsBoolean = t.b) then
  714. Exit;
  715. writeln;
  716. writeln('Failed: ', t.expr);
  717. writeln('Expected: ', t.b, ' got: ', r.AsBoolean);
  718. end;
  719. rtNumber:
  720. begin
  721. if (r is TXPathNumberVariable) then
  722. begin
  723. if IsNan(t.n) then
  724. begin
  725. if IsNan(r.AsNumber) then
  726. Exit;
  727. end
  728. else
  729. begin
  730. if IsInfinite(t.n) and (t.n = r.AsNumber) then
  731. Exit;
  732. if not IsNan(TXPathNumberVariable(r).Value) and SameValue(TXPathNumberVariable(r).Value, t.n) then
  733. Exit;
  734. end;
  735. end;
  736. writeln;
  737. writeln('Failed: ', t.expr);
  738. writeln('Expected: ', t.n, ' got: ', r.AsNumber);
  739. end;
  740. rtString:
  741. begin
  742. if (r is TXPathStringVariable) and (r.AsText = DOMString(t.s)) then
  743. Exit;
  744. writeln;
  745. writeln('Failed: ', t.expr);
  746. writeln('Expected: ', DOMString(t.s), ' got: ', r.AsText);
  747. end;
  748. rtNodeStr:
  749. begin
  750. if (r is TXPathNodeSetVariable) and (r.AsNodeSet.Count = 1) and (r.AsText = DOMString(t.s)) then
  751. Exit;
  752. writeln;
  753. writeln('Failed: ', t.expr);
  754. if r.AsNodeSet.Count > 1 then
  755. writeln('Result is not a single node');
  756. writeln('Expected: ', DOMString(t.s), ' got: ', r.AsText);
  757. end;
  758. end;
  759. Inc(FailCount);
  760. end;
  761. procedure CheckResult(const t: TTestRec3; r: TXPathVariable); overload;
  762. var
  763. temp: TTestRec;
  764. begin
  765. temp.data := t.data;
  766. temp.expr := t.expr;
  767. temp.rt := t.rt;
  768. temp.n := t.n;
  769. CheckResult(temp, r);
  770. end;
  771. function ParseString(const data: string): TXMLDocument;
  772. var
  773. parser: TDOMParser;
  774. src: TXMLInputSource;
  775. begin
  776. parser := TDOMParser.Create;
  777. try
  778. parser.Options.PreserveWhitespace := True;
  779. parser.Options.Namespaces := True;
  780. src := TXMLInputSource.Create(data);
  781. try
  782. parser.Parse(src, Result);
  783. finally
  784. src.Free;
  785. end;
  786. finally
  787. parser.Free;
  788. end;
  789. end;
  790. procedure DoSuite(const tests: array of TTestRec);
  791. var
  792. i: Integer;
  793. doc: TXMLDocument;
  794. rslt: TXPathVariable;
  795. begin
  796. for i := 0 to High(tests) do
  797. begin
  798. if tests[i].data <> '' then
  799. doc := ParseString(tests[i].data)
  800. else
  801. doc := TXMLDocument.Create;
  802. try
  803. try
  804. rslt := EvaluateXPathExpression(tests[i].expr, doc.DocumentElement);
  805. try
  806. CheckResult(tests[i], rslt);
  807. finally
  808. rslt.Free;
  809. end;
  810. except
  811. writeln;
  812. writeln('Failed: ', tests[i].expr);
  813. SysUtils.ShowException(ExceptObject, ExceptAddr);
  814. Inc(FailCount);
  815. end;
  816. finally
  817. doc.Free;
  818. end;
  819. end;
  820. end;
  821. procedure DoSuite_WithResolver(const tests: array of TTestRec3);
  822. var
  823. i: Integer;
  824. doc: TXMLDocument;
  825. rslt: TXPathVariable;
  826. nsdoc: TXMLDocument;
  827. resolver: TXPathNSResolver;
  828. begin
  829. for i := 0 to High(tests) do
  830. begin
  831. doc := ParseString(tests[i].data);
  832. try
  833. nsdoc := ParseString(tests[i].re);
  834. try
  835. try
  836. resolver := TXPathNSResolver.Create(nsdoc.DocumentElement);
  837. try
  838. rslt := EvaluateXPathExpression(tests[i].expr, doc.DocumentElement, resolver);
  839. try
  840. CheckResult(tests[i], rslt);
  841. finally
  842. rslt.Free;
  843. end;
  844. finally
  845. resolver.Free;
  846. end;
  847. except
  848. writeln;
  849. writeln('Failed: ', tests[i].expr);
  850. SysUtils.ShowException(ExceptObject, ExceptAddr);
  851. Inc(FailCount);
  852. end;
  853. finally
  854. nsdoc.Free;
  855. end;
  856. finally
  857. doc.Free;
  858. end;
  859. end;
  860. end;
  861. procedure DoSuite_WithContext(const tests: array of TTestRec3);
  862. var
  863. i: Integer;
  864. doc: TXMLDocument;
  865. rslt: TXPathVariable;
  866. context: TXPathVariable;
  867. ctxNs: TNodeSet;
  868. begin
  869. for i := 0 to High(tests) do
  870. begin
  871. doc := ParseString(tests[i].data);
  872. try
  873. context := EvaluateXPathExpression(tests[i].re, doc.DocumentElement);
  874. try
  875. try
  876. ctxNs := context.AsNodeSet;
  877. if ctxNs.Count <> 1 then
  878. raise Exception.CreateFmt('Context expression "%s" does not evaluate to a single node', [tests[i].re]);
  879. rslt := EvaluateXPathExpression(tests[i].expr, TDOMNode(ctxNs[0]));
  880. try
  881. CheckResult(tests[i], rslt);
  882. finally
  883. rslt.Free;
  884. end;
  885. except
  886. writeln;
  887. writeln('Failed: ', tests[i].expr);
  888. SysUtils.ShowException(ExceptObject, ExceptAddr);
  889. Inc(FailCount);
  890. end;
  891. finally
  892. context.Free;
  893. end;
  894. finally
  895. doc.Free;
  896. end;
  897. end;
  898. end;
  899. begin
  900. DoSuite(BaseTests);
  901. DoSuite(CompareTests);
  902. DoSuite(NodesetCompareTests);
  903. DoSuite(EqualityTests);
  904. DoSuite(FloatTests);
  905. DoSuite(FunctionTests);
  906. DoSuite(StringTests);
  907. DoSuite(AxesTests);
  908. DoSuite_WithContext(AxesTests2);
  909. DoSuite_WithResolver(nameTests);
  910. DoSuite(PredicateTests);
  911. writeln;
  912. writeln('Total failed tests: ', FailCount);
  913. end.