Mercurial > genshi > genshi-test
annotate genshi/tests/path.py @ 835:155c499496fe
Added XPath unit test for #271 (was already incorrectly committed in [1043], oops)
author | cmlenz |
---|---|
date | Tue, 17 Mar 2009 14:36:23 +0000 |
parents | fbcb799ee03b |
children | 266aa2e347f5 |
rev | line source |
---|---|
1 | 1 # -*- coding: utf-8 -*- |
2 # | |
66
822089ae65ce
Switch copyright to Edgewall and URLs to markup.edgewall.org.
cmlenz
parents:
38
diff
changeset
|
3 # Copyright (C) 2006 Edgewall Software |
1 | 4 # All rights reserved. |
5 # | |
6 # This software is licensed as described in the file COPYING, which | |
7 # you should have received as part of this distribution. The terms | |
230 | 8 # are also available at http://genshi.edgewall.org/wiki/License. |
1 | 9 # |
10 # This software consists of voluntary contributions made by many | |
11 # individuals. For the exact contribution history, see the revision | |
230 | 12 # history and logs, available at http://genshi.edgewall.org/log/. |
1 | 13 |
14 import doctest | |
15 import unittest | |
16 | |
230 | 17 from genshi.input import XML |
818 | 18 from genshi.path import Path, PathParser, PathSyntaxError, GenericStrategy, \ |
19 SingleStepStrategy, SimplePathStrategy | |
26
039fc5b87405
* Split out the XPath tests into a separate `unittest`-based file.
cmlenz
parents:
1
diff
changeset
|
20 |
039fc5b87405
* Split out the XPath tests into a separate `unittest`-based file.
cmlenz
parents:
1
diff
changeset
|
21 |
818 | 22 class FakePath(Path): |
23 def __init__(self, strategy): | |
24 self.strategy = strategy | |
25 def test(self, ignore_context = False): | |
26 return self.strategy.test(ignore_context) | |
27 | |
832 | 28 |
26
039fc5b87405
* Split out the XPath tests into a separate `unittest`-based file.
cmlenz
parents:
1
diff
changeset
|
29 class PathTestCase(unittest.TestCase): |
039fc5b87405
* Split out the XPath tests into a separate `unittest`-based file.
cmlenz
parents:
1
diff
changeset
|
30 |
818 | 31 strategies = [GenericStrategy, SingleStepStrategy, SimplePathStrategy] |
32 | |
111
8a4d9064f363
Some fixes and more unit tests for the XPath engine.
cmlenz
parents:
106
diff
changeset
|
33 def test_error_no_absolute_path(self): |
8a4d9064f363
Some fixes and more unit tests for the XPath engine.
cmlenz
parents:
106
diff
changeset
|
34 self.assertRaises(PathSyntaxError, Path, '/root') |
8a4d9064f363
Some fixes and more unit tests for the XPath engine.
cmlenz
parents:
106
diff
changeset
|
35 |
8a4d9064f363
Some fixes and more unit tests for the XPath engine.
cmlenz
parents:
106
diff
changeset
|
36 def test_error_unsupported_axis(self): |
137 | 37 self.assertRaises(PathSyntaxError, Path, '..') |
111
8a4d9064f363
Some fixes and more unit tests for the XPath engine.
cmlenz
parents:
106
diff
changeset
|
38 self.assertRaises(PathSyntaxError, Path, 'parent::ma') |
8a4d9064f363
Some fixes and more unit tests for the XPath engine.
cmlenz
parents:
106
diff
changeset
|
39 |
26
039fc5b87405
* Split out the XPath tests into a separate `unittest`-based file.
cmlenz
parents:
1
diff
changeset
|
40 def test_1step(self): |
38
fec9f4897415
Fix for #2 (incorrect context node in path expressions). Still some paths that produce incorrect results, but the common case seems to work now.
cmlenz
parents:
27
diff
changeset
|
41 xml = XML('<root><elem/></root>') |
832 | 42 self._test_eval( |
43 path = 'elem', | |
44 equiv = '<Path "child::elem">', | |
45 input = xml, | |
46 output = '<elem/>' | |
47 ) | |
48 self._test_eval( | |
49 path = 'elem', | |
50 equiv = '<Path "child::elem">', | |
51 input = xml, | |
52 output = '<elem/>' | |
53 ) | |
54 self._test_eval( | |
55 path = 'child::elem', | |
56 equiv = '<Path "child::elem">', | |
57 input = xml, | |
58 output = '<elem/>' | |
59 ) | |
60 self._test_eval( | |
61 path = '//elem', | |
62 equiv = '<Path "descendant-or-self::elem">', | |
63 input = xml, | |
64 output = '<elem/>' | |
65 ) | |
66 self._test_eval( | |
67 path = 'descendant::elem', | |
68 equiv = '<Path "descendant::elem">', | |
69 input = xml, | |
70 output = '<elem/>' | |
71 ) | |
106
61fa4cadb766
Complete rewrite of the XPath parsing, which was a mess before. Closes #19.
cmlenz
parents:
66
diff
changeset
|
72 |
61fa4cadb766
Complete rewrite of the XPath parsing, which was a mess before. Closes #19.
cmlenz
parents:
66
diff
changeset
|
73 def test_1step_self(self): |
61fa4cadb766
Complete rewrite of the XPath parsing, which was a mess before. Closes #19.
cmlenz
parents:
66
diff
changeset
|
74 xml = XML('<root><elem/></root>') |
832 | 75 self._test_eval( |
76 path = '.', | |
77 equiv = '<Path "self::node()">', | |
78 input = xml, | |
79 output = '<root><elem/></root>' | |
80 ) | |
81 self._test_eval( | |
82 path = 'self::node()', | |
83 equiv = '<Path "self::node()">', | |
84 input = xml, | |
85 output = '<root><elem/></root>' | |
86 ) | |
106
61fa4cadb766
Complete rewrite of the XPath parsing, which was a mess before. Closes #19.
cmlenz
parents:
66
diff
changeset
|
87 |
26
039fc5b87405
* Split out the XPath tests into a separate `unittest`-based file.
cmlenz
parents:
1
diff
changeset
|
88 def test_1step_wildcard(self): |
38
fec9f4897415
Fix for #2 (incorrect context node in path expressions). Still some paths that produce incorrect results, but the common case seems to work now.
cmlenz
parents:
27
diff
changeset
|
89 xml = XML('<root><elem/></root>') |
832 | 90 self._test_eval( |
91 path = '*', | |
92 equiv = '<Path "child::*">', | |
93 input = xml, | |
94 output = '<elem/>' | |
95 ) | |
96 self._test_eval( | |
97 path = 'child::*', | |
98 equiv = '<Path "child::*">', | |
99 input = xml, | |
100 output = '<elem/>' | |
101 ) | |
102 self._test_eval( | |
103 path = 'child::node()', | |
104 equiv = '<Path "child::node()">', | |
105 input = xml, | |
106 output = '<elem/>' | |
107 ) | |
108 self._test_eval( | |
109 path = '//*', | |
110 equiv = '<Path "descendant-or-self::*">', | |
111 input = xml, | |
112 output = '<root><elem/></root>' | |
113 ) | |
106
61fa4cadb766
Complete rewrite of the XPath parsing, which was a mess before. Closes #19.
cmlenz
parents:
66
diff
changeset
|
114 |
26
039fc5b87405
* Split out the XPath tests into a separate `unittest`-based file.
cmlenz
parents:
1
diff
changeset
|
115 def test_1step_attribute(self): |
832 | 116 self._test_eval( |
117 path = '@foo', | |
118 equiv = '<Path "attribute::foo">', | |
119 input = XML('<root/>'), | |
120 output = '' | |
121 ) | |
111
8a4d9064f363
Some fixes and more unit tests for the XPath engine.
cmlenz
parents:
106
diff
changeset
|
122 xml = XML('<root foo="bar"/>') |
832 | 123 self._test_eval( |
124 path = '@foo', | |
125 equiv = '<Path "attribute::foo">', | |
126 input = xml, | |
127 output = 'bar' | |
128 ) | |
129 self._test_eval( | |
130 path = './@foo', | |
131 equiv = '<Path "self::node()/attribute::foo">', | |
132 input = xml, | |
133 output = 'bar' | |
134 ) | |
26
039fc5b87405
* Split out the XPath tests into a separate `unittest`-based file.
cmlenz
parents:
1
diff
changeset
|
135 |
111
8a4d9064f363
Some fixes and more unit tests for the XPath engine.
cmlenz
parents:
106
diff
changeset
|
136 def test_1step_text(self): |
8a4d9064f363
Some fixes and more unit tests for the XPath engine.
cmlenz
parents:
106
diff
changeset
|
137 xml = XML('<root>Hey</root>') |
832 | 138 self._test_eval( |
139 path = 'text()', | |
140 equiv = '<Path "child::text()">', | |
141 input = xml, | |
142 output = 'Hey' | |
143 ) | |
144 self._test_eval( | |
145 path = './text()', | |
146 equiv = '<Path "self::node()/child::text()">', | |
147 input = xml, | |
148 output = 'Hey' | |
149 ) | |
150 self._test_eval( | |
151 path = '//text()', | |
152 equiv = '<Path "descendant-or-self::text()">', | |
153 input = xml, | |
154 output = 'Hey' | |
155 ) | |
156 self._test_eval( | |
157 path = './/text()', | |
158 equiv = '<Path "self::node()/descendant-or-self::node()/child::text()">', | |
159 input = xml, | |
160 output = 'Hey' | |
161 ) | |
26
039fc5b87405
* Split out the XPath tests into a separate `unittest`-based file.
cmlenz
parents:
1
diff
changeset
|
162 |
039fc5b87405
* Split out the XPath tests into a separate `unittest`-based file.
cmlenz
parents:
1
diff
changeset
|
163 def test_2step(self): |
039fc5b87405
* Split out the XPath tests into a separate `unittest`-based file.
cmlenz
parents:
1
diff
changeset
|
164 xml = XML('<root><foo/><bar/></root>') |
832 | 165 self._test_eval('*', input=xml, output='<foo/><bar/>') |
166 self._test_eval('bar', input=xml, output='<bar/>') | |
167 self._test_eval('baz', input=xml, output='') | |
26
039fc5b87405
* Split out the XPath tests into a separate `unittest`-based file.
cmlenz
parents:
1
diff
changeset
|
168 |
145
56d534eb53f9
* Fix error in expression evaluation when the expression evaluates to an iterable that does not produce event tuples.
cmlenz
parents:
138
diff
changeset
|
169 def test_2step_attribute(self): |
56d534eb53f9
* Fix error in expression evaluation when the expression evaluates to an iterable that does not produce event tuples.
cmlenz
parents:
138
diff
changeset
|
170 xml = XML('<elem class="x"><span id="joe">Hey Joe</span></elem>') |
832 | 171 self._test_eval('@*', input=xml, output='x') |
172 self._test_eval('./@*', input=xml, output='x') | |
173 self._test_eval('.//@*', input=xml, output='xjoe') | |
174 self._test_eval('*/@*', input=xml, output='joe') | |
145
56d534eb53f9
* Fix error in expression evaluation when the expression evaluates to an iterable that does not produce event tuples.
cmlenz
parents:
138
diff
changeset
|
175 |
215 | 176 xml = XML('<elem><foo id="1"/><foo id="2"/></elem>') |
832 | 177 self._test_eval('@*', input=xml, output='') |
178 self._test_eval('foo/@*', input=xml, output='12') | |
145
56d534eb53f9
* Fix error in expression evaluation when the expression evaluates to an iterable that does not produce event tuples.
cmlenz
parents:
138
diff
changeset
|
179 |
26
039fc5b87405
* Split out the XPath tests into a separate `unittest`-based file.
cmlenz
parents:
1
diff
changeset
|
180 def test_2step_complex(self): |
039fc5b87405
* Split out the XPath tests into a separate `unittest`-based file.
cmlenz
parents:
1
diff
changeset
|
181 xml = XML('<root><foo><bar/></foo></root>') |
832 | 182 self._test_eval( |
183 path = 'foo/bar', | |
184 equiv = '<Path "child::foo/child::bar">', | |
185 input = xml, | |
186 output = '<bar/>' | |
187 ) | |
188 self._test_eval( | |
189 path = './bar', | |
190 equiv = '<Path "self::node()/child::bar">', | |
191 input = xml, | |
192 output = '' | |
193 ) | |
194 self._test_eval( | |
195 path = 'foo/*', | |
196 equiv = '<Path "child::foo/child::*">', | |
197 input = xml, | |
198 output = '<bar/>' | |
199 ) | |
26
039fc5b87405
* Split out the XPath tests into a separate `unittest`-based file.
cmlenz
parents:
1
diff
changeset
|
200 xml = XML('<root><foo><bar id="1"/></foo><bar id="2"/></root>') |
832 | 201 self._test_eval( |
202 path = './bar', | |
203 equiv = '<Path "self::node()/child::bar">', | |
204 input = xml, | |
205 output = '<bar id="2"/>' | |
206 ) | |
833 | 207 xml = XML('''<table> |
208 <tr><td>1</td><td>One</td></tr> | |
209 <tr><td>2</td><td>Two</td></tr> | |
210 </table>''') | |
211 self._test_eval( | |
212 path = 'tr/td[1]', | |
213 input = xml, | |
214 output = '<td>1</td><td>2</td>' | |
215 ) | |
835
155c499496fe
Added XPath unit test for #271 (was already incorrectly committed in [1043], oops)
cmlenz
parents:
834
diff
changeset
|
216 xml = XML('''<ul> |
834 | 217 <li>item1 |
218 <ul><li>subitem11</li></ul> | |
219 </li> | |
220 <li>item2 | |
221 <ul><li>subitem21</li></ul> | |
222 </li> | |
223 </ul>''') | |
224 self._test_eval( | |
225 path = 'li[2]/ul', | |
226 input = xml, | |
227 output = '<ul><li>subitem21</li></ul>' | |
228 ) | |
26
039fc5b87405
* Split out the XPath tests into a separate `unittest`-based file.
cmlenz
parents:
1
diff
changeset
|
229 |
039fc5b87405
* Split out the XPath tests into a separate `unittest`-based file.
cmlenz
parents:
1
diff
changeset
|
230 def test_2step_text(self): |
039fc5b87405
* Split out the XPath tests into a separate `unittest`-based file.
cmlenz
parents:
1
diff
changeset
|
231 xml = XML('<root><item>Foo</item></root>') |
832 | 232 self._test_eval( |
233 path = 'item/text()', | |
234 equiv = '<Path "child::item/child::text()">', | |
235 input = xml, | |
236 output = 'Foo' | |
237 ) | |
238 self._test_eval( | |
239 path = '*/text()', | |
240 equiv = '<Path "child::*/child::text()">', | |
241 input = xml, | |
242 output = 'Foo' | |
243 ) | |
244 self._test_eval( | |
245 path = '//text()', | |
246 equiv = '<Path "descendant-or-self::text()">', | |
247 input = xml, | |
248 output = 'Foo' | |
249 ) | |
250 self._test_eval( | |
251 path = './text()', | |
252 equiv = '<Path "self::node()/child::text()">', | |
253 input = xml, | |
254 output = '' | |
255 ) | |
26
039fc5b87405
* Split out the XPath tests into a separate `unittest`-based file.
cmlenz
parents:
1
diff
changeset
|
256 xml = XML('<root><item>Foo</item><item>Bar</item></root>') |
832 | 257 self._test_eval( |
258 path = 'item/text()', | |
259 equiv = '<Path "child::item/child::text()">', | |
260 input = xml, | |
261 output = 'FooBar' | |
262 ) | |
263 xml = XML('<root><item><name>Foo</name><sub><name>Bar</name></sub></item></root>') | |
264 self._test_eval( | |
265 path = 'item/name/text()', | |
266 equiv = '<Path "child::item/child::name/child::text()">', | |
267 input = xml, | |
268 output = 'Foo' | |
269 ) | |
26
039fc5b87405
* Split out the XPath tests into a separate `unittest`-based file.
cmlenz
parents:
1
diff
changeset
|
270 |
039fc5b87405
* Split out the XPath tests into a separate `unittest`-based file.
cmlenz
parents:
1
diff
changeset
|
271 def test_3step(self): |
039fc5b87405
* Split out the XPath tests into a separate `unittest`-based file.
cmlenz
parents:
1
diff
changeset
|
272 xml = XML('<root><foo><bar/></foo></root>') |
832 | 273 self._test_eval( |
274 path = 'foo/*', | |
275 equiv = '<Path "child::foo/child::*">', | |
276 input = xml, | |
277 output = '<bar/>' | |
278 ) | |
26
039fc5b87405
* Split out the XPath tests into a separate `unittest`-based file.
cmlenz
parents:
1
diff
changeset
|
279 |
039fc5b87405
* Split out the XPath tests into a separate `unittest`-based file.
cmlenz
parents:
1
diff
changeset
|
280 def test_3step_complex(self): |
832 | 281 self._test_eval( |
282 path = '*/bar', | |
283 equiv = '<Path "child::*/child::bar">', | |
284 input = XML('<root><foo><bar/></foo></root>'), | |
285 output = '<bar/>' | |
286 ) | |
287 self._test_eval( | |
288 path = '//bar', | |
289 equiv = '<Path "descendant-or-self::bar">', | |
290 input = XML('<root><foo><bar id="1"/></foo><bar id="2"/></root>'), | |
291 output = '<bar id="1"/><bar id="2"/>' | |
292 ) | |
138 | 293 |
832 | 294 def test_3step_complex_text(self): |
295 xml = XML('<root><item><bar>Some text </bar><baz><bar>in here.</bar></baz></item></root>') | |
296 self._test_eval( | |
297 path = 'item/bar/text()', | |
298 equiv = '<Path "child::item/child::bar/child::text()">', | |
299 input = xml, | |
300 output = 'Some text ' | |
301 ) | |
302 self._test_eval( | |
303 path = 'item//bar/text()', | |
304 equiv = '<Path "child::item/descendant-or-self::node()/child::bar/child::text()">', | |
305 input = xml, | |
306 output = 'Some text in here.' | |
307 ) | |
106
61fa4cadb766
Complete rewrite of the XPath parsing, which was a mess before. Closes #19.
cmlenz
parents:
66
diff
changeset
|
308 |
61fa4cadb766
Complete rewrite of the XPath parsing, which was a mess before. Closes #19.
cmlenz
parents:
66
diff
changeset
|
309 def test_node_type_comment(self): |
61fa4cadb766
Complete rewrite of the XPath parsing, which was a mess before. Closes #19.
cmlenz
parents:
66
diff
changeset
|
310 xml = XML('<root><!-- commented --></root>') |
832 | 311 self._test_eval( |
312 path = 'comment()', | |
313 equiv = '<Path "child::comment()">', | |
314 input = xml, | |
315 output = '<!-- commented -->' | |
316 ) | |
106
61fa4cadb766
Complete rewrite of the XPath parsing, which was a mess before. Closes #19.
cmlenz
parents:
66
diff
changeset
|
317 |
61fa4cadb766
Complete rewrite of the XPath parsing, which was a mess before. Closes #19.
cmlenz
parents:
66
diff
changeset
|
318 def test_node_type_text(self): |
61fa4cadb766
Complete rewrite of the XPath parsing, which was a mess before. Closes #19.
cmlenz
parents:
66
diff
changeset
|
319 xml = XML('<root>Some text <br/>in here.</root>') |
832 | 320 self._test_eval( |
321 path = 'text()', | |
322 equiv = '<Path "child::text()">', | |
323 input = xml, | |
324 output = 'Some text in here.' | |
325 ) | |
106
61fa4cadb766
Complete rewrite of the XPath parsing, which was a mess before. Closes #19.
cmlenz
parents:
66
diff
changeset
|
326 |
61fa4cadb766
Complete rewrite of the XPath parsing, which was a mess before. Closes #19.
cmlenz
parents:
66
diff
changeset
|
327 def test_node_type_node(self): |
61fa4cadb766
Complete rewrite of the XPath parsing, which was a mess before. Closes #19.
cmlenz
parents:
66
diff
changeset
|
328 xml = XML('<root>Some text <br/>in here.</root>') |
832 | 329 self._test_eval( |
330 path = 'node()', | |
331 equiv = '<Path "child::node()">', | |
332 input = xml, | |
333 output = 'Some text <br/>in here.' | |
334 ) | |
106
61fa4cadb766
Complete rewrite of the XPath parsing, which was a mess before. Closes #19.
cmlenz
parents:
66
diff
changeset
|
335 |
61fa4cadb766
Complete rewrite of the XPath parsing, which was a mess before. Closes #19.
cmlenz
parents:
66
diff
changeset
|
336 def test_node_type_processing_instruction(self): |
61fa4cadb766
Complete rewrite of the XPath parsing, which was a mess before. Closes #19.
cmlenz
parents:
66
diff
changeset
|
337 xml = XML('<?python x = 2 * 3 ?><root><?php echo("x") ?></root>') |
832 | 338 self._test_eval( |
339 path = '//processing-instruction()', | |
340 equiv = '<Path "descendant-or-self::processing-instruction()">', | |
341 input = xml, | |
342 output = '<?python x = 2 * 3 ?><?php echo("x") ?>' | |
343 ) | |
344 self._test_eval( | |
345 path = 'processing-instruction()', | |
346 equiv = '<Path "child::processing-instruction()">', | |
347 input = xml, | |
348 output = '<?php echo("x") ?>' | |
349 ) | |
350 self._test_eval( | |
351 path = 'processing-instruction("php")', | |
352 equiv = '<Path "child::processing-instruction(\"php\")">', | |
353 input = xml, | |
354 output = '<?php echo("x") ?>' | |
355 ) | |
106
61fa4cadb766
Complete rewrite of the XPath parsing, which was a mess before. Closes #19.
cmlenz
parents:
66
diff
changeset
|
356 |
61fa4cadb766
Complete rewrite of the XPath parsing, which was a mess before. Closes #19.
cmlenz
parents:
66
diff
changeset
|
357 def test_simple_union(self): |
259
6f11ad260890
Fix bug in evaluating XPath expressions using the union operator `|`, which caused any path but the first to get out of sync with the event stream, and the whole thing returning too few results.
cmlenz
parents:
234
diff
changeset
|
358 xml = XML("""<body>1<br />2<br />3<br /></body>""") |
832 | 359 self._test_eval( |
360 path = '*|text()', | |
361 equiv = '<Path "child::*|child::text()">', | |
362 input = xml, | |
363 output = '1<br/>2<br/>3<br/>' | |
364 ) | |
26
039fc5b87405
* Split out the XPath tests into a separate `unittest`-based file.
cmlenz
parents:
1
diff
changeset
|
365 |
121
22a7080ed242
Added support for the XPath functions `name()`, `namespace-uri()`, `local-name()`, and `not()`.
cmlenz
parents:
111
diff
changeset
|
366 def test_predicate_name(self): |
22a7080ed242
Added support for the XPath functions `name()`, `namespace-uri()`, `local-name()`, and `not()`.
cmlenz
parents:
111
diff
changeset
|
367 xml = XML('<root><foo/><bar/></root>') |
832 | 368 self._test_eval('*[name()="foo"]', input=xml, output='<foo/>') |
121
22a7080ed242
Added support for the XPath functions `name()`, `namespace-uri()`, `local-name()`, and `not()`.
cmlenz
parents:
111
diff
changeset
|
369 |
22a7080ed242
Added support for the XPath functions `name()`, `namespace-uri()`, `local-name()`, and `not()`.
cmlenz
parents:
111
diff
changeset
|
370 def test_predicate_localname(self): |
22a7080ed242
Added support for the XPath functions `name()`, `namespace-uri()`, `local-name()`, and `not()`.
cmlenz
parents:
111
diff
changeset
|
371 xml = XML('<root><foo xmlns="NS"/><bar/></root>') |
832 | 372 self._test_eval('*[local-name()="foo"]', input=xml, |
373 output='<foo xmlns="NS"/>') | |
121
22a7080ed242
Added support for the XPath functions `name()`, `namespace-uri()`, `local-name()`, and `not()`.
cmlenz
parents:
111
diff
changeset
|
374 |
22a7080ed242
Added support for the XPath functions `name()`, `namespace-uri()`, `local-name()`, and `not()`.
cmlenz
parents:
111
diff
changeset
|
375 def test_predicate_namespace(self): |
22a7080ed242
Added support for the XPath functions `name()`, `namespace-uri()`, `local-name()`, and `not()`.
cmlenz
parents:
111
diff
changeset
|
376 xml = XML('<root><foo xmlns="NS"/><bar/></root>') |
832 | 377 self._test_eval('*[namespace-uri()="NS"]', input=xml, |
378 output='<foo xmlns="NS"/>') | |
121
22a7080ed242
Added support for the XPath functions `name()`, `namespace-uri()`, `local-name()`, and `not()`.
cmlenz
parents:
111
diff
changeset
|
379 |
22a7080ed242
Added support for the XPath functions `name()`, `namespace-uri()`, `local-name()`, and `not()`.
cmlenz
parents:
111
diff
changeset
|
380 def test_predicate_not_name(self): |
22a7080ed242
Added support for the XPath functions `name()`, `namespace-uri()`, `local-name()`, and `not()`.
cmlenz
parents:
111
diff
changeset
|
381 xml = XML('<root><foo/><bar/></root>') |
832 | 382 self._test_eval('*[not(name()="foo")]', input=xml, |
383 output='<bar/>') | |
121
22a7080ed242
Added support for the XPath functions `name()`, `namespace-uri()`, `local-name()`, and `not()`.
cmlenz
parents:
111
diff
changeset
|
384 |
26
039fc5b87405
* Split out the XPath tests into a separate `unittest`-based file.
cmlenz
parents:
1
diff
changeset
|
385 def test_predicate_attr(self): |
039fc5b87405
* Split out the XPath tests into a separate `unittest`-based file.
cmlenz
parents:
1
diff
changeset
|
386 xml = XML('<root><item/><item important="very"/></root>') |
832 | 387 self._test_eval('item[@important]', input=xml, |
388 output='<item important="very"/>') | |
389 self._test_eval('item[@important="very"]', input=xml, | |
390 output='<item important="very"/>') | |
26
039fc5b87405
* Split out the XPath tests into a separate `unittest`-based file.
cmlenz
parents:
1
diff
changeset
|
391 |
106
61fa4cadb766
Complete rewrite of the XPath parsing, which was a mess before. Closes #19.
cmlenz
parents:
66
diff
changeset
|
392 def test_predicate_attr_equality(self): |
26
039fc5b87405
* Split out the XPath tests into a separate `unittest`-based file.
cmlenz
parents:
1
diff
changeset
|
393 xml = XML('<root><item/><item important="notso"/></root>') |
832 | 394 self._test_eval('item[@important="very"]', input=xml, output='') |
395 self._test_eval('item[@important!="very"]', input=xml, | |
396 output='<item/><item important="notso"/>') | |
162
f767cf98e3e3
Implement the XPath relational operators and the `round()` function.
cmlenz
parents:
155
diff
changeset
|
397 |
f767cf98e3e3
Implement the XPath relational operators and the `round()` function.
cmlenz
parents:
155
diff
changeset
|
398 def test_predicate_attr_greater_than(self): |
f767cf98e3e3
Implement the XPath relational operators and the `round()` function.
cmlenz
parents:
155
diff
changeset
|
399 xml = XML('<root><item priority="3"/></root>') |
832 | 400 self._test_eval('item[@priority>3]', input=xml, output='') |
401 self._test_eval('item[@priority>2]', input=xml, | |
402 output='<item priority="3"/>') | |
162
f767cf98e3e3
Implement the XPath relational operators and the `round()` function.
cmlenz
parents:
155
diff
changeset
|
403 |
f767cf98e3e3
Implement the XPath relational operators and the `round()` function.
cmlenz
parents:
155
diff
changeset
|
404 def test_predicate_attr_less_than(self): |
f767cf98e3e3
Implement the XPath relational operators and the `round()` function.
cmlenz
parents:
155
diff
changeset
|
405 xml = XML('<root><item priority="3"/></root>') |
832 | 406 self._test_eval('item[@priority<3]', input=xml, output='') |
407 self._test_eval('item[@priority<4]', input=xml, | |
408 output='<item priority="3"/>') | |
1 | 409 |
106
61fa4cadb766
Complete rewrite of the XPath parsing, which was a mess before. Closes #19.
cmlenz
parents:
66
diff
changeset
|
410 def test_predicate_attr_and(self): |
61fa4cadb766
Complete rewrite of the XPath parsing, which was a mess before. Closes #19.
cmlenz
parents:
66
diff
changeset
|
411 xml = XML('<root><item/><item important="very"/></root>') |
832 | 412 self._test_eval('item[@important and @important="very"]', |
413 input=xml, output='<item important="very"/>') | |
414 self._test_eval('item[@important and @important="notso"]', | |
415 input=xml, output='') | |
106
61fa4cadb766
Complete rewrite of the XPath parsing, which was a mess before. Closes #19.
cmlenz
parents:
66
diff
changeset
|
416 |
61fa4cadb766
Complete rewrite of the XPath parsing, which was a mess before. Closes #19.
cmlenz
parents:
66
diff
changeset
|
417 def test_predicate_attr_or(self): |
61fa4cadb766
Complete rewrite of the XPath parsing, which was a mess before. Closes #19.
cmlenz
parents:
66
diff
changeset
|
418 xml = XML('<root><item/><item important="very"/></root>') |
832 | 419 self._test_eval('item[@urgent or @important]', input=xml, |
420 output='<item important="very"/>') | |
421 self._test_eval('item[@urgent or @notso]', input=xml, output='') | |
106
61fa4cadb766
Complete rewrite of the XPath parsing, which was a mess before. Closes #19.
cmlenz
parents:
66
diff
changeset
|
422 |
155
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
423 def test_predicate_boolean_function(self): |
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
424 xml = XML('<root><foo>bar</foo></root>') |
832 | 425 self._test_eval('*[boolean("")]', input=xml, output='') |
426 self._test_eval('*[boolean("yo")]', input=xml, | |
427 output='<foo>bar</foo>') | |
428 self._test_eval('*[boolean(0)]', input=xml, output='') | |
429 self._test_eval('*[boolean(42)]', input=xml, | |
430 output='<foo>bar</foo>') | |
431 self._test_eval('*[boolean(false())]', input=xml, output='') | |
432 self._test_eval('*[boolean(true())]', input=xml, | |
433 output='<foo>bar</foo>') | |
155
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
434 |
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
435 def test_predicate_ceil_function(self): |
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
436 xml = XML('<root><foo>bar</foo></root>') |
832 | 437 self._test_eval('*[ceiling("4.5")=5]', input=xml, |
438 output='<foo>bar</foo>') | |
155
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
439 |
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
440 def test_predicate_concat_function(self): |
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
441 xml = XML('<root><foo>bar</foo></root>') |
832 | 442 self._test_eval('*[name()=concat("f", "oo")]', input=xml, |
443 output='<foo>bar</foo>') | |
155
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
444 |
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
445 def test_predicate_contains_function(self): |
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
446 xml = XML('<root><foo>bar</foo></root>') |
832 | 447 self._test_eval('*[contains(name(), "oo")]', input=xml, |
448 output='<foo>bar</foo>') | |
155
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
449 |
534
cccb6c748609
Add XPath `matches()` function which, of course, supports the Python regular
athomas
parents:
413
diff
changeset
|
450 def test_predicate_matches_function(self): |
cccb6c748609
Add XPath `matches()` function which, of course, supports the Python regular
athomas
parents:
413
diff
changeset
|
451 xml = XML('<root><foo>bar</foo><bar>foo</bar></root>') |
832 | 452 self._test_eval('*[matches(name(), "foo|bar")]', input=xml, |
453 output='<foo>bar</foo><bar>foo</bar>') | |
534
cccb6c748609
Add XPath `matches()` function which, of course, supports the Python regular
athomas
parents:
413
diff
changeset
|
454 |
155
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
455 def test_predicate_false_function(self): |
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
456 xml = XML('<root><foo>bar</foo></root>') |
832 | 457 self._test_eval('*[false()]', input=xml, output='') |
155
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
458 |
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
459 def test_predicate_floor_function(self): |
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
460 xml = XML('<root><foo>bar</foo></root>') |
832 | 461 self._test_eval('*[floor("4.5")=4]', input=xml, |
462 output='<foo>bar</foo>') | |
155
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
463 |
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
464 def test_predicate_normalize_space_function(self): |
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
465 xml = XML('<root><foo>bar</foo></root>') |
832 | 466 self._test_eval('*[normalize-space(" foo bar ")="foo bar"]', |
467 input=xml, output='<foo>bar</foo>') | |
155
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
468 |
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
469 def test_predicate_number_function(self): |
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
470 xml = XML('<root><foo>bar</foo></root>') |
832 | 471 self._test_eval('*[number("3.0")=3]', input=xml, |
472 output='<foo>bar</foo>') | |
473 self._test_eval('*[number("3.0")=3.0]', input=xml, | |
474 output='<foo>bar</foo>') | |
475 self._test_eval('*[number("0.1")=.1]', input=xml, | |
476 output='<foo>bar</foo>') | |
155
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
477 |
162
f767cf98e3e3
Implement the XPath relational operators and the `round()` function.
cmlenz
parents:
155
diff
changeset
|
478 def test_predicate_round_function(self): |
f767cf98e3e3
Implement the XPath relational operators and the `round()` function.
cmlenz
parents:
155
diff
changeset
|
479 xml = XML('<root><foo>bar</foo></root>') |
832 | 480 self._test_eval('*[round("4.4")=4]', input=xml, |
481 output='<foo>bar</foo>') | |
482 self._test_eval('*[round("4.6")=5]', input=xml, | |
483 output='<foo>bar</foo>') | |
162
f767cf98e3e3
Implement the XPath relational operators and the `round()` function.
cmlenz
parents:
155
diff
changeset
|
484 |
155
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
485 def test_predicate_starts_with_function(self): |
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
486 xml = XML('<root><foo>bar</foo></root>') |
832 | 487 self._test_eval('*[starts-with(name(), "f")]', input=xml, |
488 output='<foo>bar</foo>') | |
489 self._test_eval('*[starts-with(name(), "b")]', input=xml, | |
490 output='') | |
155
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
491 |
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
492 def test_predicate_string_length_function(self): |
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
493 xml = XML('<root><foo>bar</foo></root>') |
832 | 494 self._test_eval('*[string-length(name())=3]', input=xml, |
495 output='<foo>bar</foo>') | |
155
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
496 |
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
497 def test_predicate_substring_function(self): |
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
498 xml = XML('<root><foo>bar</foo></root>') |
832 | 499 self._test_eval('*[substring(name(), 1)="oo"]', input=xml, |
500 output='<foo>bar</foo>') | |
501 self._test_eval('*[substring(name(), 1, 1)="o"]', input=xml, | |
502 output='<foo>bar</foo>') | |
155
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
503 |
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
504 def test_predicate_substring_after_function(self): |
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
505 xml = XML('<root><foo>bar</foo></root>') |
832 | 506 self._test_eval('*[substring-after(name(), "f")="oo"]', input=xml, |
507 output='<foo>bar</foo>') | |
155
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
508 |
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
509 def test_predicate_substring_before_function(self): |
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
510 xml = XML('<root><foo>bar</foo></root>') |
832 | 511 self._test_eval('*[substring-before(name(), "oo")="f"]', |
512 input=xml, output='<foo>bar</foo>') | |
155
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
513 |
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
514 def test_predicate_translate_function(self): |
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
515 xml = XML('<root><foo>bar</foo></root>') |
832 | 516 self._test_eval('*[translate(name(), "fo", "ba")="baa"]', |
517 input=xml, output='<foo>bar</foo>') | |
155
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
518 |
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
519 def test_predicate_true_function(self): |
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
520 xml = XML('<root><foo>bar</foo></root>') |
832 | 521 self._test_eval('*[true()]', input=xml, output='<foo>bar</foo>') |
155
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
522 |
179
a2e0a7986d19
Implemented support for XPath variables in predicates (#31).
cmlenz
parents:
164
diff
changeset
|
523 def test_predicate_variable(self): |
a2e0a7986d19
Implemented support for XPath variables in predicates (#31).
cmlenz
parents:
164
diff
changeset
|
524 xml = XML('<root><foo>bar</foo></root>') |
832 | 525 self._test_eval( |
526 path = '*[name()=$bar]', | |
527 input = xml, | |
528 output = '<foo>bar</foo>', | |
529 variables = {'bar': 'foo'} | |
530 ) | |
224
e4dad1145f84
Implement support for namespace prefixes in XPath expressions.
cmlenz
parents:
216
diff
changeset
|
531 |
228
f79b20a50919
Add support for position predicates in XPath expressions.
cmlenz
parents:
224
diff
changeset
|
532 def test_predicate_position(self): |
f79b20a50919
Add support for position predicates in XPath expressions.
cmlenz
parents:
224
diff
changeset
|
533 xml = XML('<root><foo id="a1"/><foo id="a2"/><foo id="a3"/></root>') |
832 | 534 self._test_eval('*[2]', input=xml, output='<foo id="a2"/>') |
228
f79b20a50919
Add support for position predicates in XPath expressions.
cmlenz
parents:
224
diff
changeset
|
535 |
f79b20a50919
Add support for position predicates in XPath expressions.
cmlenz
parents:
224
diff
changeset
|
536 def test_predicate_attr_and_position(self): |
f79b20a50919
Add support for position predicates in XPath expressions.
cmlenz
parents:
224
diff
changeset
|
537 xml = XML('<root><foo/><foo id="a1"/><foo id="a2"/></root>') |
832 | 538 self._test_eval('*[@id][2]', input=xml, output='<foo id="a2"/>') |
228
f79b20a50919
Add support for position predicates in XPath expressions.
cmlenz
parents:
224
diff
changeset
|
539 |
f79b20a50919
Add support for position predicates in XPath expressions.
cmlenz
parents:
224
diff
changeset
|
540 def test_predicate_position_and_attr(self): |
f79b20a50919
Add support for position predicates in XPath expressions.
cmlenz
parents:
224
diff
changeset
|
541 xml = XML('<root><foo/><foo id="a1"/><foo id="a2"/></root>') |
832 | 542 self._test_eval('*[1][@id]', input=xml, output='') |
543 self._test_eval('*[2][@id]', input=xml, output='<foo id="a1"/>') | |
818 | 544 |
545 def test_predicate_advanced_position(self): | |
546 xml = XML('<root><a><b><c><d><e/></d></c></b></a></root>') | |
832 | 547 self._test_eval( 'descendant-or-self::*/' |
818 | 548 'descendant-or-self::*/' |
549 'descendant-or-self::*[2]/' | |
832 | 550 'self::*/descendant::*[3]', input=xml, |
551 output='<d><e/></d>') | |
818 | 552 |
553 def test_predicate_child_position(self): | |
554 xml = XML('\ | |
555 <root><a><b>1</b><b>2</b><b>3</b></a><a><b>4</b><b>5</b></a></root>') | |
832 | 556 self._test_eval('//a/b[2]', input=xml, output='<b>2</b><b>5</b>') |
557 self._test_eval('//a/b[3]', input=xml, output='<b>3</b>') | |
228
f79b20a50919
Add support for position predicates in XPath expressions.
cmlenz
parents:
224
diff
changeset
|
558 |
224
e4dad1145f84
Implement support for namespace prefixes in XPath expressions.
cmlenz
parents:
216
diff
changeset
|
559 def test_name_with_namespace(self): |
e4dad1145f84
Implement support for namespace prefixes in XPath expressions.
cmlenz
parents:
216
diff
changeset
|
560 xml = XML('<root xmlns:f="FOO"><f:foo>bar</f:foo></root>') |
832 | 561 self._test_eval( |
562 path = 'f:foo', | |
563 equiv = '<Path "child::f:foo">', | |
564 input = xml, | |
565 output = '<foo xmlns="FOO">bar</foo>', | |
566 namespaces = {'f': 'FOO'} | |
567 ) | |
224
e4dad1145f84
Implement support for namespace prefixes in XPath expressions.
cmlenz
parents:
216
diff
changeset
|
568 |
e4dad1145f84
Implement support for namespace prefixes in XPath expressions.
cmlenz
parents:
216
diff
changeset
|
569 def test_wildcard_with_namespace(self): |
e4dad1145f84
Implement support for namespace prefixes in XPath expressions.
cmlenz
parents:
216
diff
changeset
|
570 xml = XML('<root xmlns:f="FOO"><f:foo>bar</f:foo></root>') |
832 | 571 self._test_eval( |
572 path = 'f:*', | |
573 equiv = '<Path "child::f:*">', | |
574 input = xml, | |
575 output = '<foo xmlns="FOO">bar</foo>', | |
576 namespaces = {'f': 'FOO'} | |
577 ) | |
224
e4dad1145f84
Implement support for namespace prefixes in XPath expressions.
cmlenz
parents:
216
diff
changeset
|
578 |
384 | 579 def test_predicate_termination(self): |
580 """ | |
581 Verify that a patch matching the self axis with a predicate doesn't | |
582 cause an infinite loop. See <http://genshi.edgewall.org/ticket/82>. | |
583 """ | |
584 xml = XML('<ul flag="1"><li>a</li><li>b</li></ul>') | |
832 | 585 self._test_eval('.[@flag="1"]/*', input=xml, |
586 output='<li>a</li><li>b</li>') | |
384 | 587 |
588 xml = XML('<ul flag="1"><li>a</li><li>b</li></ul>') | |
832 | 589 self._test_eval('.[@flag="0"]/*', input=xml, output='') |
384 | 590 |
410
3460b04daeac
Improve the handling of namespaces in serialization.
cmlenz
parents:
384
diff
changeset
|
591 def test_attrname_with_namespace(self): |
3460b04daeac
Improve the handling of namespaces in serialization.
cmlenz
parents:
384
diff
changeset
|
592 xml = XML('<root xmlns:f="FOO"><foo f:bar="baz"/></root>') |
832 | 593 self._test_eval('foo[@f:bar]', input=xml, |
594 output='<foo xmlns:ns1="FOO" ns1:bar="baz"/>', | |
595 namespaces={'f': 'FOO'}) | |
410
3460b04daeac
Improve the handling of namespaces in serialization.
cmlenz
parents:
384
diff
changeset
|
596 |
3460b04daeac
Improve the handling of namespaces in serialization.
cmlenz
parents:
384
diff
changeset
|
597 def test_attrwildcard_with_namespace(self): |
3460b04daeac
Improve the handling of namespaces in serialization.
cmlenz
parents:
384
diff
changeset
|
598 xml = XML('<root xmlns:f="FOO"><foo f:bar="baz"/></root>') |
832 | 599 self._test_eval('foo[@f:*]', input=xml, |
600 output='<foo xmlns:ns1="FOO" ns1:bar="baz"/>', | |
601 namespaces={'f': 'FOO'}) | |
602 | |
818 | 603 def test_self_and_descendant(self): |
604 xml = XML('<root><foo/></root>') | |
832 | 605 self._test_eval('self::root', input=xml, output='<root><foo/></root>') |
606 self._test_eval('self::foo', input=xml, output='') | |
607 self._test_eval('descendant::root', input=xml, output='') | |
608 self._test_eval('descendant::foo', input=xml, output='<foo/>') | |
609 self._test_eval('descendant-or-self::root', input=xml, | |
610 output='<root><foo/></root>') | |
611 self._test_eval('descendant-or-self::foo', input=xml, output='<foo/>') | |
179
a2e0a7986d19
Implemented support for XPath variables in predicates (#31).
cmlenz
parents:
164
diff
changeset
|
612 |
818 | 613 def test_long_simple_paths(self): |
614 xml = XML('<root><a><b><a><d><a><b><a><b><a><b><a><c>!' | |
615 '</c></a></b></a></b></a></b></a></d></a></b></a></root>') | |
832 | 616 self._test_eval('//a/b/a/b/a/c', input=xml, output='<c>!</c>') |
617 self._test_eval('//a/b/a/c', input=xml, output='<c>!</c>') | |
618 self._test_eval('//a/c', input=xml, output='<c>!</c>') | |
619 self._test_eval('//c', input=xml, output='<c>!</c>') | |
818 | 620 # Please note that a//b is NOT the same as a/descendant::b |
621 # it is a/descendant-or-self::node()/b, which SimplePathStrategy | |
622 # does NOT support | |
832 | 623 self._test_eval('a/b/descendant::a/c', input=xml, output='<c>!</c>') |
624 self._test_eval('a/b/descendant::a/d/descendant::a/c', | |
625 input=xml, output='<c>!</c>') | |
626 self._test_eval('a/b/descendant::a/d/a/c', input=xml, output='') | |
627 self._test_eval('//d/descendant::b/descendant::b/descendant::b' | |
628 '/descendant::c', input=xml, output='<c>!</c>') | |
629 self._test_eval('//d/descendant::b/descendant::b/descendant::b' | |
630 '/descendant::b/descendant::c', input=xml, | |
631 output='') | |
632 | |
818 | 633 def _test_support(self, strategy_class, text): |
634 path = PathParser(text, None, -1).parse()[0] | |
635 return strategy_class.supports(path) | |
832 | 636 |
818 | 637 def test_simple_strategy_support(self): |
638 self.assert_(self._test_support(SimplePathStrategy, 'a/b')) | |
639 self.assert_(self._test_support(SimplePathStrategy, 'self::a/b')) | |
640 self.assert_(self._test_support(SimplePathStrategy, 'descendant::a/b')) | |
641 self.assert_(self._test_support(SimplePathStrategy, | |
642 'descendant-or-self::a/b')) | |
643 self.assert_(self._test_support(SimplePathStrategy, '//a/b')) | |
644 self.assert_(self._test_support(SimplePathStrategy, 'a/@b')) | |
645 self.assert_(self._test_support(SimplePathStrategy, 'a/text()')) | |
646 | |
647 # a//b is a/descendant-or-self::node()/b | |
648 self.assert_(not self._test_support(SimplePathStrategy, 'a//b')) | |
649 self.assert_(not self._test_support(SimplePathStrategy, 'node()/@a')) | |
650 self.assert_(not self._test_support(SimplePathStrategy, '@a')) | |
651 self.assert_(not self._test_support(SimplePathStrategy, 'foo:bar')) | |
652 self.assert_(not self._test_support(SimplePathStrategy, 'a/@foo:bar')) | |
1 | 653 |
832 | 654 def _test_strategies(self, input, path, output, |
655 namespaces=None, variables=None): | |
656 for strategy in self.strategies: | |
657 if not strategy.supports(path): | |
658 continue | |
659 s = strategy(path) | |
660 rendered = FakePath(s).select(input, namespaces=namespaces, | |
661 variables=variables).render() | |
662 msg = 'Bad render using %s strategy' % str(strategy) | |
663 msg += '\nExpected:\t%r' % output | |
664 msg += '\nRendered:\t%r' % rendered | |
665 self.assertEqual(output, rendered, msg) | |
666 | |
667 def _test_eval(self, path, equiv=None, input=None, output='', | |
668 namespaces=None, variables=None): | |
669 path = Path(path) | |
670 if equiv is not None: | |
671 self.assertEqual(equiv, repr(path)) | |
672 | |
673 if input is None: | |
674 return | |
675 | |
676 rendered = path.select(input, namespaces=namespaces, | |
677 variables=variables).render() | |
678 msg = 'Bad output using whole path' | |
679 msg += '\nExpected:\t%r' % output | |
680 msg += '\nRendered:\t%r' % rendered | |
681 self.assertEqual(output, rendered, msg) | |
682 | |
683 if len(path.paths) == 1: | |
684 self._test_strategies(input, path.paths[0], output, | |
685 namespaces=namespaces, variables=variables) | |
686 | |
687 | |
1 | 688 def suite(): |
689 suite = unittest.TestSuite() | |
111
8a4d9064f363
Some fixes and more unit tests for the XPath engine.
cmlenz
parents:
106
diff
changeset
|
690 suite.addTest(doctest.DocTestSuite(Path.__module__)) |
26
039fc5b87405
* Split out the XPath tests into a separate `unittest`-based file.
cmlenz
parents:
1
diff
changeset
|
691 suite.addTest(unittest.makeSuite(PathTestCase, 'test')) |
1 | 692 return suite |
693 | |
832 | 694 |
1 | 695 if __name__ == '__main__': |
696 unittest.main(defaultTest='suite') |