Mercurial > genshi > genshi-test
annotate genshi/filters/tests/transform.py @ 916:872726bac135 experimental-py3k
add support for python 3 to genshi.filters:
* minor changes to track encoding=None API change in core genshi modules.
* renamed genshi/filters/tests/html.py to test_html.py to avoid clashes with Python 3 top-level html module when running tests subset.
* did not rename genshi/filters/html.py.
* i18n filters:
* ugettext and friends are gone in Python 3 (and only gettext and friends exist and they now handle unicode)
* Some \ line continuations inside doctests confused 2to3 and so were removed them.
* Testing picked up a problem (already present in trunk) where Translator.__call__ could end up defining gettext as an endlessly recursive function. Noted with a TODO.
author | hodgestar |
---|---|
date | Sun, 24 Oct 2010 22:21:28 +0000 |
parents | 24733a5854d9 |
children |
rev | line source |
---|---|
501
3073ac688651
Added new markup transformation filter contributed by Alec Thomas (#122). This provides gorgeous jQuery-inspired stream transformation capabilities based on XPath expressions.
cmlenz
parents:
diff
changeset
|
1 # -*- coding: utf-8 -*- |
3073ac688651
Added new markup transformation filter contributed by Alec Thomas (#122). This provides gorgeous jQuery-inspired stream transformation capabilities based on XPath expressions.
cmlenz
parents:
diff
changeset
|
2 # |
3073ac688651
Added new markup transformation filter contributed by Alec Thomas (#122). This provides gorgeous jQuery-inspired stream transformation capabilities based on XPath expressions.
cmlenz
parents:
diff
changeset
|
3 # Copyright (C) 2007 Edgewall Software |
3073ac688651
Added new markup transformation filter contributed by Alec Thomas (#122). This provides gorgeous jQuery-inspired stream transformation capabilities based on XPath expressions.
cmlenz
parents:
diff
changeset
|
4 # All rights reserved. |
3073ac688651
Added new markup transformation filter contributed by Alec Thomas (#122). This provides gorgeous jQuery-inspired stream transformation capabilities based on XPath expressions.
cmlenz
parents:
diff
changeset
|
5 # |
3073ac688651
Added new markup transformation filter contributed by Alec Thomas (#122). This provides gorgeous jQuery-inspired stream transformation capabilities based on XPath expressions.
cmlenz
parents:
diff
changeset
|
6 # This software is licensed as described in the file COPYING, which |
3073ac688651
Added new markup transformation filter contributed by Alec Thomas (#122). This provides gorgeous jQuery-inspired stream transformation capabilities based on XPath expressions.
cmlenz
parents:
diff
changeset
|
7 # you should have received as part of this distribution. The terms |
3073ac688651
Added new markup transformation filter contributed by Alec Thomas (#122). This provides gorgeous jQuery-inspired stream transformation capabilities based on XPath expressions.
cmlenz
parents:
diff
changeset
|
8 # are also available at http://genshi.edgewall.org/wiki/License. |
3073ac688651
Added new markup transformation filter contributed by Alec Thomas (#122). This provides gorgeous jQuery-inspired stream transformation capabilities based on XPath expressions.
cmlenz
parents:
diff
changeset
|
9 # |
3073ac688651
Added new markup transformation filter contributed by Alec Thomas (#122). This provides gorgeous jQuery-inspired stream transformation capabilities based on XPath expressions.
cmlenz
parents:
diff
changeset
|
10 # This software consists of voluntary contributions made by many |
3073ac688651
Added new markup transformation filter contributed by Alec Thomas (#122). This provides gorgeous jQuery-inspired stream transformation capabilities based on XPath expressions.
cmlenz
parents:
diff
changeset
|
11 # individuals. For the exact contribution history, see the revision |
3073ac688651
Added new markup transformation filter contributed by Alec Thomas (#122). This provides gorgeous jQuery-inspired stream transformation capabilities based on XPath expressions.
cmlenz
parents:
diff
changeset
|
12 # history and logs, available at http://genshi.edgewall.org/log/. |
3073ac688651
Added new markup transformation filter contributed by Alec Thomas (#122). This provides gorgeous jQuery-inspired stream transformation capabilities based on XPath expressions.
cmlenz
parents:
diff
changeset
|
13 |
3073ac688651
Added new markup transformation filter contributed by Alec Thomas (#122). This provides gorgeous jQuery-inspired stream transformation capabilities based on XPath expressions.
cmlenz
parents:
diff
changeset
|
14 import doctest |
744 | 15 from pprint import pprint |
501
3073ac688651
Added new markup transformation filter contributed by Alec Thomas (#122). This provides gorgeous jQuery-inspired stream transformation capabilities based on XPath expressions.
cmlenz
parents:
diff
changeset
|
16 import unittest |
3073ac688651
Added new markup transformation filter contributed by Alec Thomas (#122). This provides gorgeous jQuery-inspired stream transformation capabilities based on XPath expressions.
cmlenz
parents:
diff
changeset
|
17 |
744 | 18 from genshi import HTML |
19 from genshi.builder import Element | |
20 from genshi.core import START, END, TEXT, QName, Attrs | |
21 from genshi.filters.transform import Transformer, StreamBuffer, ENTER, EXIT, \ | |
22 OUTSIDE, INSIDE, ATTR, BREAK | |
501
3073ac688651
Added new markup transformation filter contributed by Alec Thomas (#122). This provides gorgeous jQuery-inspired stream transformation capabilities based on XPath expressions.
cmlenz
parents:
diff
changeset
|
23 import genshi.filters.transform |
3073ac688651
Added new markup transformation filter contributed by Alec Thomas (#122). This provides gorgeous jQuery-inspired stream transformation capabilities based on XPath expressions.
cmlenz
parents:
diff
changeset
|
24 |
3073ac688651
Added new markup transformation filter contributed by Alec Thomas (#122). This provides gorgeous jQuery-inspired stream transformation capabilities based on XPath expressions.
cmlenz
parents:
diff
changeset
|
25 |
744 | 26 FOO = '<root>ROOT<foo name="foo">FOO</foo></root>' |
27 FOOBAR = '<root>ROOT<foo name="foo" size="100">FOO</foo><bar name="bar">BAR</bar></root>' | |
28 | |
29 | |
30 def _simplify(stream, with_attrs=False): | |
31 """Simplify a marked stream.""" | |
32 def _generate(): | |
33 for mark, (kind, data, pos) in stream: | |
34 if kind is START: | |
35 if with_attrs: | |
36 data = (unicode(data[0]), dict((unicode(k), v) | |
37 for k, v in data[1])) | |
38 else: | |
39 data = unicode(data[0]) | |
40 elif kind is END: | |
41 data = unicode(data) | |
42 elif kind is ATTR: | |
43 kind = ATTR | |
44 data = dict((unicode(k), v) for k, v in data[1]) | |
45 yield mark, kind, data | |
46 return list(_generate()) | |
47 | |
48 | |
49 def _transform(html, transformer, with_attrs=False): | |
50 """Apply transformation returning simplified marked stream.""" | |
916 | 51 if isinstance(html, basestring) and not isinstance(html, unicode): |
52 html = HTML(html, encoding='utf-8') | |
53 elif isinstance(html, unicode): | |
54 html = HTML(html, encoding='utf-8') | |
744 | 55 stream = transformer(html, keep_marks=True) |
56 return _simplify(stream, with_attrs) | |
57 | |
58 | |
59 class SelectTest(unittest.TestCase): | |
60 """Test .select()""" | |
61 def _select(self, select): | |
916 | 62 html = HTML(FOOBAR, encoding='utf-8') |
744 | 63 if isinstance(select, basestring): |
64 select = [select] | |
65 transformer = Transformer(select[0]) | |
66 for sel in select[1:]: | |
67 transformer = transformer.select(sel) | |
68 return _transform(html, transformer) | |
69 | |
70 def test_select_single_element(self): | |
71 self.assertEqual( | |
72 self._select('foo'), | |
73 [(None, START, u'root'), | |
74 (None, TEXT, u'ROOT'), | |
75 (ENTER, START, u'foo'), | |
76 (INSIDE, TEXT, u'FOO'), | |
77 (EXIT, END, u'foo'), | |
78 (None, START, u'bar'), | |
79 (None, TEXT, u'BAR'), | |
80 (None, END, u'bar'), | |
81 (None, END, u'root')], | |
82 ) | |
83 | |
84 def test_select_context(self): | |
85 self.assertEqual( | |
86 self._select('.'), | |
87 [(ENTER, START, u'root'), | |
88 (INSIDE, TEXT, u'ROOT'), | |
89 (INSIDE, START, u'foo'), | |
90 (INSIDE, TEXT, u'FOO'), | |
91 (INSIDE, END, u'foo'), | |
92 (INSIDE, START, u'bar'), | |
93 (INSIDE, TEXT, u'BAR'), | |
94 (INSIDE, END, u'bar'), | |
95 (EXIT, END, u'root')] | |
96 ) | |
97 | |
98 def test_select_inside_select(self): | |
99 self.assertEqual( | |
100 self._select(['.', 'foo']), | |
101 [(None, START, u'root'), | |
102 (None, TEXT, u'ROOT'), | |
103 (ENTER, START, u'foo'), | |
104 (INSIDE, TEXT, u'FOO'), | |
105 (EXIT, END, u'foo'), | |
106 (None, START, u'bar'), | |
107 (None, TEXT, u'BAR'), | |
108 (None, END, u'bar'), | |
109 (None, END, u'root')], | |
110 ) | |
111 | |
112 def test_select_text(self): | |
113 self.assertEqual( | |
114 self._select('*/text()'), | |
115 [(None, START, u'root'), | |
116 (None, TEXT, u'ROOT'), | |
117 (None, START, u'foo'), | |
118 (OUTSIDE, TEXT, u'FOO'), | |
119 (None, END, u'foo'), | |
120 (None, START, u'bar'), | |
121 (OUTSIDE, TEXT, u'BAR'), | |
122 (None, END, u'bar'), | |
123 (None, END, u'root')], | |
124 ) | |
125 | |
126 def test_select_attr(self): | |
127 self.assertEqual( | |
128 self._select('foo/@name'), | |
129 [(None, START, u'root'), | |
130 (None, TEXT, u'ROOT'), | |
131 (ATTR, ATTR, {'name': u'foo'}), | |
132 (None, START, u'foo'), | |
133 (None, TEXT, u'FOO'), | |
134 (None, END, u'foo'), | |
135 (None, START, u'bar'), | |
136 (None, TEXT, u'BAR'), | |
137 (None, END, u'bar'), | |
138 (None, END, u'root')] | |
139 ) | |
140 | |
141 def test_select_text_context(self): | |
142 self.assertEqual( | |
916 | 143 list(Transformer('.')(HTML(u'foo'), keep_marks=True)), |
744 | 144 [('OUTSIDE', ('TEXT', u'foo', (None, 1, 0)))], |
145 ) | |
146 | |
147 | |
148 class InvertTest(unittest.TestCase): | |
149 def _invert(self, select): | |
150 return _transform(FOO, Transformer(select).invert()) | |
151 | |
152 def test_invert_element(self): | |
153 self.assertEqual( | |
154 self._invert('foo'), | |
155 [(OUTSIDE, START, u'root'), | |
156 (OUTSIDE, TEXT, u'ROOT'), | |
157 (None, START, u'foo'), | |
158 (None, TEXT, u'FOO'), | |
159 (None, END, u'foo'), | |
160 (OUTSIDE, END, u'root')] | |
161 ) | |
162 | |
163 def test_invert_inverted_element(self): | |
164 self.assertEqual( | |
165 _transform(FOO, Transformer('foo').invert().invert()), | |
166 [(None, START, u'root'), | |
167 (None, TEXT, u'ROOT'), | |
168 (OUTSIDE, START, u'foo'), | |
169 (OUTSIDE, TEXT, u'FOO'), | |
170 (OUTSIDE, END, u'foo'), | |
171 (None, END, u'root')] | |
172 ) | |
173 | |
174 def test_invert_text(self): | |
175 self.assertEqual( | |
176 self._invert('foo/text()'), | |
177 [(OUTSIDE, START, u'root'), | |
178 (OUTSIDE, TEXT, u'ROOT'), | |
179 (OUTSIDE, START, u'foo'), | |
180 (None, TEXT, u'FOO'), | |
181 (OUTSIDE, END, u'foo'), | |
182 (OUTSIDE, END, u'root')] | |
183 ) | |
184 | |
185 def test_invert_attribute(self): | |
186 self.assertEqual( | |
187 self._invert('foo/@name'), | |
188 [(OUTSIDE, START, u'root'), | |
189 (OUTSIDE, TEXT, u'ROOT'), | |
190 (None, ATTR, {'name': u'foo'}), | |
191 (OUTSIDE, START, u'foo'), | |
192 (OUTSIDE, TEXT, u'FOO'), | |
193 (OUTSIDE, END, u'foo'), | |
194 (OUTSIDE, END, u'root')] | |
195 ) | |
196 | |
197 def test_invert_context(self): | |
198 self.assertEqual( | |
199 self._invert('.'), | |
200 [(None, START, u'root'), | |
201 (None, TEXT, u'ROOT'), | |
202 (None, START, u'foo'), | |
203 (None, TEXT, u'FOO'), | |
204 (None, END, u'foo'), | |
205 (None, END, u'root')] | |
206 ) | |
207 | |
208 def test_invert_text_context(self): | |
209 self.assertEqual( | |
916 | 210 _simplify(Transformer('.').invert()(HTML(u'foo'), keep_marks=True)), |
744 | 211 [(None, 'TEXT', u'foo')], |
212 ) | |
213 | |
214 | |
215 | |
216 class EndTest(unittest.TestCase): | |
217 def test_end(self): | |
218 stream = _transform(FOO, Transformer('foo').end()) | |
219 self.assertEqual( | |
220 stream, | |
221 [(OUTSIDE, START, u'root'), | |
222 (OUTSIDE, TEXT, u'ROOT'), | |
223 (OUTSIDE, START, u'foo'), | |
224 (OUTSIDE, TEXT, u'FOO'), | |
225 (OUTSIDE, END, u'foo'), | |
226 (OUTSIDE, END, u'root')] | |
227 ) | |
228 | |
229 | |
230 class EmptyTest(unittest.TestCase): | |
231 def _empty(self, select): | |
232 return _transform(FOO, Transformer(select).empty()) | |
233 | |
234 def test_empty_element(self): | |
235 self.assertEqual( | |
236 self._empty('foo'), | |
237 [(None, START, u'root'), | |
238 (None, TEXT, u'ROOT'), | |
239 (ENTER, START, u'foo'), | |
240 (EXIT, END, u'foo'), | |
241 (None, END, u'root')], | |
242 ) | |
243 | |
244 def test_empty_text(self): | |
245 self.assertEqual( | |
246 self._empty('foo/text()'), | |
247 [(None, START, u'root'), | |
248 (None, TEXT, u'ROOT'), | |
249 (None, START, u'foo'), | |
250 (OUTSIDE, TEXT, u'FOO'), | |
251 (None, END, u'foo'), | |
252 (None, END, u'root')] | |
253 ) | |
254 | |
255 def test_empty_attr(self): | |
256 self.assertEqual( | |
257 self._empty('foo/@name'), | |
258 [(None, START, u'root'), | |
259 (None, TEXT, u'ROOT'), | |
260 (ATTR, ATTR, {'name': u'foo'}), | |
261 (None, START, u'foo'), | |
262 (None, TEXT, u'FOO'), | |
263 (None, END, u'foo'), | |
264 (None, END, u'root')] | |
265 ) | |
266 | |
267 def test_empty_context(self): | |
268 self.assertEqual( | |
269 self._empty('.'), | |
270 [(ENTER, START, u'root'), | |
271 (EXIT, END, u'root')] | |
272 ) | |
273 | |
274 def test_empty_text_context(self): | |
275 self.assertEqual( | |
916 | 276 _simplify(Transformer('.')(HTML(u'foo'), keep_marks=True)), |
744 | 277 [(OUTSIDE, TEXT, u'foo')], |
278 ) | |
279 | |
280 | |
281 class RemoveTest(unittest.TestCase): | |
282 def _remove(self, select): | |
283 return _transform(FOO, Transformer(select).remove()) | |
284 | |
285 def test_remove_element(self): | |
286 self.assertEqual( | |
287 self._remove('foo|bar'), | |
288 [(None, START, u'root'), | |
289 (None, TEXT, u'ROOT'), | |
290 (None, END, u'root')] | |
291 ) | |
292 | |
293 def test_remove_text(self): | |
294 self.assertEqual( | |
295 self._remove('//text()'), | |
296 [(None, START, u'root'), | |
297 (None, START, u'foo'), | |
298 (None, END, u'foo'), | |
299 (None, END, u'root')] | |
300 ) | |
301 | |
302 def test_remove_attr(self): | |
303 self.assertEqual( | |
304 self._remove('foo/@name'), | |
305 [(None, START, u'root'), | |
306 (None, TEXT, u'ROOT'), | |
307 (None, START, u'foo'), | |
308 (None, TEXT, u'FOO'), | |
309 (None, END, u'foo'), | |
310 (None, END, u'root')] | |
311 ) | |
312 | |
313 def test_remove_context(self): | |
314 self.assertEqual( | |
315 self._remove('.'), | |
316 [], | |
317 ) | |
318 | |
319 def test_remove_text_context(self): | |
320 self.assertEqual( | |
321 _transform('foo', Transformer('.').remove()), | |
322 [], | |
323 ) | |
324 | |
325 | |
326 class UnwrapText(unittest.TestCase): | |
327 def _unwrap(self, select): | |
328 return _transform(FOO, Transformer(select).unwrap()) | |
329 | |
330 def test_unwrap_element(self): | |
331 self.assertEqual( | |
332 self._unwrap('foo'), | |
333 [(None, START, u'root'), | |
334 (None, TEXT, u'ROOT'), | |
335 (INSIDE, TEXT, u'FOO'), | |
336 (None, END, u'root')] | |
337 ) | |
338 | |
339 def test_unwrap_text(self): | |
340 self.assertEqual( | |
341 self._unwrap('foo/text()'), | |
342 [(None, START, u'root'), | |
343 (None, TEXT, u'ROOT'), | |
344 (None, START, u'foo'), | |
345 (OUTSIDE, TEXT, u'FOO'), | |
346 (None, END, u'foo'), | |
347 (None, END, u'root')] | |
348 ) | |
349 | |
350 def test_unwrap_attr(self): | |
351 self.assertEqual( | |
352 self._unwrap('foo/@name'), | |
353 [(None, START, u'root'), | |
354 (None, TEXT, u'ROOT'), | |
355 (ATTR, ATTR, {'name': u'foo'}), | |
356 (None, START, u'foo'), | |
357 (None, TEXT, u'FOO'), | |
358 (None, END, u'foo'), | |
359 (None, END, u'root')] | |
360 ) | |
361 | |
362 def test_unwrap_adjacent(self): | |
363 self.assertEqual( | |
364 _transform(FOOBAR, Transformer('foo|bar').unwrap()), | |
365 [(None, START, u'root'), | |
366 (None, TEXT, u'ROOT'), | |
367 (INSIDE, TEXT, u'FOO'), | |
368 (INSIDE, TEXT, u'BAR'), | |
369 (None, END, u'root')] | |
370 ) | |
371 | |
372 def test_unwrap_root(self): | |
373 self.assertEqual( | |
374 self._unwrap('.'), | |
375 [(INSIDE, TEXT, u'ROOT'), | |
376 (INSIDE, START, u'foo'), | |
377 (INSIDE, TEXT, u'FOO'), | |
378 (INSIDE, END, u'foo')] | |
379 ) | |
380 | |
381 def test_unwrap_text_root(self): | |
382 self.assertEqual( | |
383 _transform('foo', Transformer('.').unwrap()), | |
384 [(OUTSIDE, TEXT, 'foo')], | |
385 ) | |
386 | |
387 | |
388 class WrapTest(unittest.TestCase): | |
389 def _wrap(self, select, wrap='wrap'): | |
390 return _transform(FOO, Transformer(select).wrap(wrap)) | |
391 | |
392 def test_wrap_element(self): | |
393 self.assertEqual( | |
394 self._wrap('foo'), | |
395 [(None, START, u'root'), | |
396 (None, TEXT, u'ROOT'), | |
397 (None, START, u'wrap'), | |
398 (ENTER, START, u'foo'), | |
399 (INSIDE, TEXT, u'FOO'), | |
400 (EXIT, END, u'foo'), | |
401 (None, END, u'wrap'), | |
402 (None, END, u'root')] | |
403 ) | |
404 | |
405 def test_wrap_adjacent_elements(self): | |
406 self.assertEqual( | |
407 _transform(FOOBAR, Transformer('foo|bar').wrap('wrap')), | |
408 [(None, START, u'root'), | |
409 (None, TEXT, u'ROOT'), | |
410 (None, START, u'wrap'), | |
411 (ENTER, START, u'foo'), | |
412 (INSIDE, TEXT, u'FOO'), | |
413 (EXIT, END, u'foo'), | |
414 (None, END, u'wrap'), | |
415 (None, START, u'wrap'), | |
416 (ENTER, START, u'bar'), | |
417 (INSIDE, TEXT, u'BAR'), | |
418 (EXIT, END, u'bar'), | |
419 (None, END, u'wrap'), | |
420 (None, END, u'root')] | |
421 ) | |
422 | |
423 def test_wrap_text(self): | |
424 self.assertEqual( | |
425 self._wrap('foo/text()'), | |
426 [(None, START, u'root'), | |
427 (None, TEXT, u'ROOT'), | |
428 (None, START, u'foo'), | |
429 (None, START, u'wrap'), | |
430 (OUTSIDE, TEXT, u'FOO'), | |
431 (None, END, u'wrap'), | |
432 (None, END, u'foo'), | |
433 (None, END, u'root')] | |
434 ) | |
435 | |
436 def test_wrap_root(self): | |
437 self.assertEqual( | |
438 self._wrap('.'), | |
439 [(None, START, u'wrap'), | |
440 (ENTER, START, u'root'), | |
441 (INSIDE, TEXT, u'ROOT'), | |
442 (INSIDE, START, u'foo'), | |
443 (INSIDE, TEXT, u'FOO'), | |
444 (INSIDE, END, u'foo'), | |
445 (EXIT, END, u'root'), | |
446 (None, END, u'wrap')] | |
447 ) | |
448 | |
449 def test_wrap_text_root(self): | |
450 self.assertEqual( | |
451 _transform('foo', Transformer('.').wrap('wrap')), | |
452 [(None, START, u'wrap'), | |
453 (OUTSIDE, TEXT, u'foo'), | |
454 (None, END, u'wrap')], | |
455 ) | |
456 | |
457 def test_wrap_with_element(self): | |
458 element = Element('a', href='http://localhost') | |
459 self.assertEqual( | |
460 _transform('foo', Transformer('.').wrap(element), with_attrs=True), | |
461 [(None, START, (u'a', {u'href': u'http://localhost'})), | |
462 (OUTSIDE, TEXT, u'foo'), | |
463 (None, END, u'a')] | |
464 ) | |
465 | |
466 | |
467 class FilterTest(unittest.TestCase): | |
468 def _filter(self, select, html=FOOBAR): | |
469 """Returns a list of lists of filtered elements.""" | |
470 output = [] | |
471 def filtered(stream): | |
472 interval = [] | |
473 output.append(interval) | |
474 for event in stream: | |
475 interval.append(event) | |
476 yield event | |
477 _transform(html, Transformer(select).filter(filtered)) | |
478 simplified = [] | |
479 for sub in output: | |
480 simplified.append(_simplify([(None, event) for event in sub])) | |
481 return simplified | |
482 | |
483 def test_filter_element(self): | |
484 self.assertEqual( | |
485 self._filter('foo'), | |
486 [[(None, START, u'foo'), | |
487 (None, TEXT, u'FOO'), | |
488 (None, END, u'foo')]] | |
489 ) | |
490 | |
491 def test_filter_adjacent_elements(self): | |
492 self.assertEqual( | |
493 self._filter('foo|bar'), | |
494 [[(None, START, u'foo'), | |
495 (None, TEXT, u'FOO'), | |
496 (None, END, u'foo')], | |
497 [(None, START, u'bar'), | |
498 (None, TEXT, u'BAR'), | |
499 (None, END, u'bar')]] | |
500 ) | |
501 | |
502 def test_filter_text(self): | |
503 self.assertEqual( | |
504 self._filter('*/text()'), | |
505 [[(None, TEXT, u'FOO')], | |
506 [(None, TEXT, u'BAR')]] | |
507 ) | |
508 def test_filter_root(self): | |
509 self.assertEqual( | |
510 self._filter('.'), | |
511 [[(None, START, u'root'), | |
512 (None, TEXT, u'ROOT'), | |
513 (None, START, u'foo'), | |
514 (None, TEXT, u'FOO'), | |
515 (None, END, u'foo'), | |
516 (None, START, u'bar'), | |
517 (None, TEXT, u'BAR'), | |
518 (None, END, u'bar'), | |
519 (None, END, u'root')]] | |
520 ) | |
521 | |
522 def test_filter_text_root(self): | |
523 self.assertEqual( | |
524 self._filter('.', 'foo'), | |
525 [[(None, TEXT, u'foo')]]) | |
526 | |
800
1d7b582b09a4
Fix for filter transformation, closing #290. Thanks to Stephen Compall for reporting the problem and providing a patch.
cmlenz
parents:
744
diff
changeset
|
527 def test_filter_after_outside(self): |
1d7b582b09a4
Fix for filter transformation, closing #290. Thanks to Stephen Compall for reporting the problem and providing a patch.
cmlenz
parents:
744
diff
changeset
|
528 stream = _transform( |
1d7b582b09a4
Fix for filter transformation, closing #290. Thanks to Stephen Compall for reporting the problem and providing a patch.
cmlenz
parents:
744
diff
changeset
|
529 '<root>x</root>', Transformer('//root/text()').filter(lambda x: x)) |
1d7b582b09a4
Fix for filter transformation, closing #290. Thanks to Stephen Compall for reporting the problem and providing a patch.
cmlenz
parents:
744
diff
changeset
|
530 self.assertEqual( |
1d7b582b09a4
Fix for filter transformation, closing #290. Thanks to Stephen Compall for reporting the problem and providing a patch.
cmlenz
parents:
744
diff
changeset
|
531 list(stream), |
1d7b582b09a4
Fix for filter transformation, closing #290. Thanks to Stephen Compall for reporting the problem and providing a patch.
cmlenz
parents:
744
diff
changeset
|
532 [(None, START, u'root'), |
1d7b582b09a4
Fix for filter transformation, closing #290. Thanks to Stephen Compall for reporting the problem and providing a patch.
cmlenz
parents:
744
diff
changeset
|
533 (OUTSIDE, TEXT, u'x'), |
1d7b582b09a4
Fix for filter transformation, closing #290. Thanks to Stephen Compall for reporting the problem and providing a patch.
cmlenz
parents:
744
diff
changeset
|
534 (None, END, u'root')]) |
1d7b582b09a4
Fix for filter transformation, closing #290. Thanks to Stephen Compall for reporting the problem and providing a patch.
cmlenz
parents:
744
diff
changeset
|
535 |
744 | 536 |
537 class MapTest(unittest.TestCase): | |
538 def _map(self, select, kind=None): | |
539 data = [] | |
540 def record(d): | |
541 data.append(d) | |
542 return d | |
543 _transform(FOOBAR, Transformer(select).map(record, kind)) | |
544 return data | |
545 | |
546 def test_map_element(self): | |
547 self.assertEqual( | |
548 self._map('foo'), | |
857
24733a5854d9
Avoid unicode literals in `repr`s of `QName` and `Namespace` when not necessary.
cmlenz
parents:
800
diff
changeset
|
549 [(QName('foo'), Attrs([(QName('name'), u'foo'), |
24733a5854d9
Avoid unicode literals in `repr`s of `QName` and `Namespace` when not necessary.
cmlenz
parents:
800
diff
changeset
|
550 (QName('size'), u'100')])), |
744 | 551 u'FOO', |
857
24733a5854d9
Avoid unicode literals in `repr`s of `QName` and `Namespace` when not necessary.
cmlenz
parents:
800
diff
changeset
|
552 QName('foo')] |
24733a5854d9
Avoid unicode literals in `repr`s of `QName` and `Namespace` when not necessary.
cmlenz
parents:
800
diff
changeset
|
553 ) |
744 | 554 |
555 def test_map_with_text_kind(self): | |
556 self.assertEqual( | |
557 self._map('.', TEXT), | |
558 [u'ROOT', u'FOO', u'BAR'] | |
857
24733a5854d9
Avoid unicode literals in `repr`s of `QName` and `Namespace` when not necessary.
cmlenz
parents:
800
diff
changeset
|
559 ) |
744 | 560 |
561 def test_map_with_root_and_end_kind(self): | |
562 self.assertEqual( | |
563 self._map('.', END), | |
857
24733a5854d9
Avoid unicode literals in `repr`s of `QName` and `Namespace` when not necessary.
cmlenz
parents:
800
diff
changeset
|
564 [QName('foo'), QName('bar'), QName('root')] |
24733a5854d9
Avoid unicode literals in `repr`s of `QName` and `Namespace` when not necessary.
cmlenz
parents:
800
diff
changeset
|
565 ) |
744 | 566 |
567 def test_map_with_attribute(self): | |
568 self.assertEqual( | |
569 self._map('foo/@name'), | |
857
24733a5854d9
Avoid unicode literals in `repr`s of `QName` and `Namespace` when not necessary.
cmlenz
parents:
800
diff
changeset
|
570 [(QName('foo@*'), Attrs([('name', u'foo')]))] |
24733a5854d9
Avoid unicode literals in `repr`s of `QName` and `Namespace` when not necessary.
cmlenz
parents:
800
diff
changeset
|
571 ) |
744 | 572 |
573 | |
574 class SubstituteTest(unittest.TestCase): | |
575 def _substitute(self, select, pattern, replace): | |
576 return _transform(FOOBAR, Transformer(select).substitute(pattern, replace)) | |
577 | |
578 def test_substitute_foo(self): | |
579 self.assertEqual( | |
580 self._substitute('foo', 'FOO|BAR', 'FOOOOO'), | |
581 [(None, START, u'root'), | |
582 (None, TEXT, u'ROOT'), | |
583 (ENTER, START, u'foo'), | |
584 (INSIDE, TEXT, u'FOOOOO'), | |
585 (EXIT, END, u'foo'), | |
586 (None, START, u'bar'), | |
587 (None, TEXT, u'BAR'), | |
588 (None, END, u'bar'), | |
589 (None, END, u'root')] | |
590 ) | |
591 | |
592 def test_substitute_foobar_with_group(self): | |
593 self.assertEqual( | |
594 self._substitute('foo|bar', '(FOO|BAR)', r'(\1)'), | |
595 [(None, START, u'root'), | |
596 (None, TEXT, u'ROOT'), | |
597 (ENTER, START, u'foo'), | |
598 (INSIDE, TEXT, u'(FOO)'), | |
599 (EXIT, END, u'foo'), | |
600 (ENTER, START, u'bar'), | |
601 (INSIDE, TEXT, u'(BAR)'), | |
602 (EXIT, END, u'bar'), | |
603 (None, END, u'root')] | |
604 ) | |
605 | |
606 | |
607 class RenameTest(unittest.TestCase): | |
608 def _rename(self, select): | |
609 return _transform(FOOBAR, Transformer(select).rename('foobar')) | |
610 | |
611 def test_rename_root(self): | |
612 self.assertEqual( | |
613 self._rename('.'), | |
614 [(ENTER, START, u'foobar'), | |
615 (INSIDE, TEXT, u'ROOT'), | |
616 (INSIDE, START, u'foo'), | |
617 (INSIDE, TEXT, u'FOO'), | |
618 (INSIDE, END, u'foo'), | |
619 (INSIDE, START, u'bar'), | |
620 (INSIDE, TEXT, u'BAR'), | |
621 (INSIDE, END, u'bar'), | |
622 (EXIT, END, u'foobar')] | |
623 ) | |
624 | |
625 def test_rename_element(self): | |
626 self.assertEqual( | |
627 self._rename('foo|bar'), | |
628 [(None, START, u'root'), | |
629 (None, TEXT, u'ROOT'), | |
630 (ENTER, START, u'foobar'), | |
631 (INSIDE, TEXT, u'FOO'), | |
632 (EXIT, END, u'foobar'), | |
633 (ENTER, START, u'foobar'), | |
634 (INSIDE, TEXT, u'BAR'), | |
635 (EXIT, END, u'foobar'), | |
636 (None, END, u'root')] | |
637 ) | |
638 | |
639 def test_rename_text(self): | |
640 self.assertEqual( | |
641 self._rename('foo/text()'), | |
642 [(None, START, u'root'), | |
643 (None, TEXT, u'ROOT'), | |
644 (None, START, u'foo'), | |
645 (OUTSIDE, TEXT, u'FOO'), | |
646 (None, END, u'foo'), | |
647 (None, START, u'bar'), | |
648 (None, TEXT, u'BAR'), | |
649 (None, END, u'bar'), | |
650 (None, END, u'root')] | |
651 ) | |
652 | |
653 | |
654 class ContentTestMixin(object): | |
655 def _apply(self, select, content=None, html=FOOBAR): | |
656 class Injector(object): | |
657 count = 0 | |
658 | |
659 def __iter__(self): | |
660 self.count += 1 | |
916 | 661 return iter(HTML(u'CONTENT %i' % self.count)) |
744 | 662 |
916 | 663 if isinstance(html, basestring) and not isinstance(html, unicode): |
664 html = HTML(html, encoding='utf-8') | |
665 else: | |
744 | 666 html = HTML(html) |
667 if content is None: | |
668 content = Injector() | |
669 elif isinstance(content, basestring): | |
670 content = HTML(content) | |
671 return _transform(html, getattr(Transformer(select), self.operation) | |
672 (content)) | |
673 | |
674 | |
675 class ReplaceTest(unittest.TestCase, ContentTestMixin): | |
676 operation = 'replace' | |
677 | |
678 def test_replace_element(self): | |
679 self.assertEqual( | |
680 self._apply('foo'), | |
681 [(None, START, u'root'), | |
682 (None, TEXT, u'ROOT'), | |
683 (None, TEXT, u'CONTENT 1'), | |
684 (None, START, u'bar'), | |
685 (None, TEXT, u'BAR'), | |
686 (None, END, u'bar'), | |
687 (None, END, u'root')] | |
688 ) | |
689 | |
690 def test_replace_text(self): | |
691 self.assertEqual( | |
692 self._apply('text()'), | |
693 [(None, START, u'root'), | |
694 (None, TEXT, u'CONTENT 1'), | |
695 (None, START, u'foo'), | |
696 (None, TEXT, u'FOO'), | |
697 (None, END, u'foo'), | |
698 (None, START, u'bar'), | |
699 (None, TEXT, u'BAR'), | |
700 (None, END, u'bar'), | |
701 (None, END, u'root')] | |
702 ) | |
703 | |
704 def test_replace_context(self): | |
705 self.assertEqual( | |
706 self._apply('.'), | |
707 [(None, TEXT, u'CONTENT 1')], | |
708 ) | |
709 | |
710 def test_replace_text_context(self): | |
711 self.assertEqual( | |
712 self._apply('.', html='foo'), | |
713 [(None, TEXT, u'CONTENT 1')], | |
714 ) | |
715 | |
716 def test_replace_adjacent_elements(self): | |
717 self.assertEqual( | |
718 self._apply('*'), | |
719 [(None, START, u'root'), | |
720 (None, TEXT, u'ROOT'), | |
721 (None, TEXT, u'CONTENT 1'), | |
722 (None, TEXT, u'CONTENT 2'), | |
723 (None, END, u'root')], | |
724 ) | |
725 | |
726 def test_replace_all(self): | |
727 self.assertEqual( | |
728 self._apply('*|text()'), | |
729 [(None, START, u'root'), | |
730 (None, TEXT, u'CONTENT 1'), | |
731 (None, TEXT, u'CONTENT 2'), | |
732 (None, TEXT, u'CONTENT 3'), | |
733 (None, END, u'root')], | |
734 ) | |
735 | |
736 def test_replace_with_callback(self): | |
737 count = [0] | |
738 def content(): | |
739 count[0] += 1 | |
740 yield '%2i.' % count[0] | |
741 self.assertEqual( | |
742 self._apply('*', content), | |
743 [(None, START, u'root'), | |
744 (None, TEXT, u'ROOT'), | |
745 (None, TEXT, u' 1.'), | |
746 (None, TEXT, u' 2.'), | |
747 (None, END, u'root')] | |
748 ) | |
749 | |
750 | |
751 class BeforeTest(unittest.TestCase, ContentTestMixin): | |
752 operation = 'before' | |
753 | |
754 def test_before_element(self): | |
755 self.assertEqual( | |
756 self._apply('foo'), | |
757 [(None, START, u'root'), | |
758 (None, TEXT, u'ROOT'), | |
759 (None, TEXT, u'CONTENT 1'), | |
760 (ENTER, START, u'foo'), | |
761 (INSIDE, TEXT, u'FOO'), | |
762 (EXIT, END, u'foo'), | |
763 (None, START, u'bar'), | |
764 (None, TEXT, u'BAR'), | |
765 (None, END, u'bar'), | |
766 (None, END, u'root')] | |
767 ) | |
768 | |
769 def test_before_text(self): | |
770 self.assertEqual( | |
771 self._apply('text()'), | |
772 [(None, START, u'root'), | |
773 (None, TEXT, u'CONTENT 1'), | |
774 (OUTSIDE, TEXT, u'ROOT'), | |
775 (None, START, u'foo'), | |
776 (None, TEXT, u'FOO'), | |
777 (None, END, u'foo'), | |
778 (None, START, u'bar'), | |
779 (None, TEXT, u'BAR'), | |
780 (None, END, u'bar'), | |
781 (None, END, u'root')] | |
782 ) | |
783 | |
784 def test_before_context(self): | |
785 self.assertEqual( | |
786 self._apply('.'), | |
787 [(None, TEXT, u'CONTENT 1'), | |
788 (ENTER, START, u'root'), | |
789 (INSIDE, TEXT, u'ROOT'), | |
790 (INSIDE, START, u'foo'), | |
791 (INSIDE, TEXT, u'FOO'), | |
792 (INSIDE, END, u'foo'), | |
793 (INSIDE, START, u'bar'), | |
794 (INSIDE, TEXT, u'BAR'), | |
795 (INSIDE, END, u'bar'), | |
796 (EXIT, END, u'root')] | |
797 ) | |
798 | |
799 def test_before_text_context(self): | |
800 self.assertEqual( | |
801 self._apply('.', html='foo'), | |
802 [(None, TEXT, u'CONTENT 1'), | |
803 (OUTSIDE, TEXT, u'foo')] | |
804 ) | |
805 | |
806 def test_before_adjacent_elements(self): | |
807 self.assertEqual( | |
808 self._apply('*'), | |
809 [(None, START, u'root'), | |
810 (None, TEXT, u'ROOT'), | |
811 (None, TEXT, u'CONTENT 1'), | |
812 (ENTER, START, u'foo'), | |
813 (INSIDE, TEXT, u'FOO'), | |
814 (EXIT, END, u'foo'), | |
815 (None, TEXT, u'CONTENT 2'), | |
816 (ENTER, START, u'bar'), | |
817 (INSIDE, TEXT, u'BAR'), | |
818 (EXIT, END, u'bar'), | |
819 (None, END, u'root')] | |
820 | |
821 ) | |
822 | |
823 def test_before_all(self): | |
824 self.assertEqual( | |
825 self._apply('*|text()'), | |
826 [(None, START, u'root'), | |
827 (None, TEXT, u'CONTENT 1'), | |
828 (OUTSIDE, TEXT, u'ROOT'), | |
829 (None, TEXT, u'CONTENT 2'), | |
830 (ENTER, START, u'foo'), | |
831 (INSIDE, TEXT, u'FOO'), | |
832 (EXIT, END, u'foo'), | |
833 (None, TEXT, u'CONTENT 3'), | |
834 (ENTER, START, u'bar'), | |
835 (INSIDE, TEXT, u'BAR'), | |
836 (EXIT, END, u'bar'), | |
837 (None, END, u'root')] | |
838 ) | |
839 | |
840 def test_before_with_callback(self): | |
841 count = [0] | |
842 def content(): | |
843 count[0] += 1 | |
844 yield '%2i.' % count[0] | |
845 self.assertEqual( | |
846 self._apply('foo/text()', content), | |
847 [(None, 'START', u'root'), | |
848 (None, 'TEXT', u'ROOT'), | |
849 (None, 'START', u'foo'), | |
850 (None, 'TEXT', u' 1.'), | |
851 ('OUTSIDE', 'TEXT', u'FOO'), | |
852 (None, 'END', u'foo'), | |
853 (None, 'START', u'bar'), | |
854 (None, 'TEXT', u'BAR'), | |
855 (None, 'END', u'bar'), | |
856 (None, 'END', u'root')] | |
857 ) | |
858 | |
859 | |
860 class AfterTest(unittest.TestCase, ContentTestMixin): | |
861 operation = 'after' | |
862 | |
863 def test_after_element(self): | |
864 self.assertEqual( | |
865 self._apply('foo'), | |
866 [(None, START, u'root'), | |
867 (None, TEXT, u'ROOT'), | |
868 (ENTER, START, u'foo'), | |
869 (INSIDE, TEXT, u'FOO'), | |
870 (EXIT, END, u'foo'), | |
871 (None, TEXT, u'CONTENT 1'), | |
872 (None, START, u'bar'), | |
873 (None, TEXT, u'BAR'), | |
874 (None, END, u'bar'), | |
875 (None, END, u'root')] | |
876 ) | |
877 | |
878 def test_after_text(self): | |
879 self.assertEqual( | |
880 self._apply('text()'), | |
881 [(None, START, u'root'), | |
882 (OUTSIDE, TEXT, u'ROOT'), | |
883 (None, TEXT, u'CONTENT 1'), | |
884 (None, START, u'foo'), | |
885 (None, TEXT, u'FOO'), | |
886 (None, END, u'foo'), | |
887 (None, START, u'bar'), | |
888 (None, TEXT, u'BAR'), | |
889 (None, END, u'bar'), | |
890 (None, END, u'root')] | |
891 ) | |
892 | |
893 def test_after_context(self): | |
894 self.assertEqual( | |
895 self._apply('.'), | |
896 [(ENTER, START, u'root'), | |
897 (INSIDE, TEXT, u'ROOT'), | |
898 (INSIDE, START, u'foo'), | |
899 (INSIDE, TEXT, u'FOO'), | |
900 (INSIDE, END, u'foo'), | |
901 (INSIDE, START, u'bar'), | |
902 (INSIDE, TEXT, u'BAR'), | |
903 (INSIDE, END, u'bar'), | |
904 (EXIT, END, u'root'), | |
905 (None, TEXT, u'CONTENT 1')] | |
906 ) | |
907 | |
908 def test_after_text_context(self): | |
909 self.assertEqual( | |
910 self._apply('.', html='foo'), | |
911 [(OUTSIDE, TEXT, u'foo'), | |
912 (None, TEXT, u'CONTENT 1')] | |
913 ) | |
914 | |
915 def test_after_adjacent_elements(self): | |
916 self.assertEqual( | |
917 self._apply('*'), | |
918 [(None, START, u'root'), | |
919 (None, TEXT, u'ROOT'), | |
920 (ENTER, START, u'foo'), | |
921 (INSIDE, TEXT, u'FOO'), | |
922 (EXIT, END, u'foo'), | |
923 (None, TEXT, u'CONTENT 1'), | |
924 (ENTER, START, u'bar'), | |
925 (INSIDE, TEXT, u'BAR'), | |
926 (EXIT, END, u'bar'), | |
927 (None, TEXT, u'CONTENT 2'), | |
928 (None, END, u'root')] | |
929 | |
930 ) | |
931 | |
932 def test_after_all(self): | |
933 self.assertEqual( | |
934 self._apply('*|text()'), | |
935 [(None, START, u'root'), | |
936 (OUTSIDE, TEXT, u'ROOT'), | |
937 (None, TEXT, u'CONTENT 1'), | |
938 (ENTER, START, u'foo'), | |
939 (INSIDE, TEXT, u'FOO'), | |
940 (EXIT, END, u'foo'), | |
941 (None, TEXT, u'CONTENT 2'), | |
942 (ENTER, START, u'bar'), | |
943 (INSIDE, TEXT, u'BAR'), | |
944 (EXIT, END, u'bar'), | |
945 (None, TEXT, u'CONTENT 3'), | |
946 (None, END, u'root')] | |
947 ) | |
948 | |
949 def test_after_with_callback(self): | |
950 count = [0] | |
951 def content(): | |
952 count[0] += 1 | |
953 yield '%2i.' % count[0] | |
954 self.assertEqual( | |
955 self._apply('foo/text()', content), | |
956 [(None, 'START', u'root'), | |
957 (None, 'TEXT', u'ROOT'), | |
958 (None, 'START', u'foo'), | |
959 ('OUTSIDE', 'TEXT', u'FOO'), | |
960 (None, 'TEXT', u' 1.'), | |
961 (None, 'END', u'foo'), | |
962 (None, 'START', u'bar'), | |
963 (None, 'TEXT', u'BAR'), | |
964 (None, 'END', u'bar'), | |
965 (None, 'END', u'root')] | |
966 ) | |
967 | |
968 | |
969 class PrependTest(unittest.TestCase, ContentTestMixin): | |
970 operation = 'prepend' | |
971 | |
972 def test_prepend_element(self): | |
973 self.assertEqual( | |
974 self._apply('foo'), | |
975 [(None, START, u'root'), | |
976 (None, TEXT, u'ROOT'), | |
977 (ENTER, START, u'foo'), | |
978 (None, TEXT, u'CONTENT 1'), | |
979 (INSIDE, TEXT, u'FOO'), | |
980 (EXIT, END, u'foo'), | |
981 (None, START, u'bar'), | |
982 (None, TEXT, u'BAR'), | |
983 (None, END, u'bar'), | |
984 (None, END, u'root')] | |
985 ) | |
986 | |
987 def test_prepend_text(self): | |
988 self.assertEqual( | |
989 self._apply('text()'), | |
990 [(None, START, u'root'), | |
991 (OUTSIDE, TEXT, u'ROOT'), | |
992 (None, START, u'foo'), | |
993 (None, TEXT, u'FOO'), | |
994 (None, END, u'foo'), | |
995 (None, START, u'bar'), | |
996 (None, TEXT, u'BAR'), | |
997 (None, END, u'bar'), | |
998 (None, END, u'root')] | |
999 ) | |
1000 | |
1001 def test_prepend_context(self): | |
1002 self.assertEqual( | |
1003 self._apply('.'), | |
1004 [(ENTER, START, u'root'), | |
1005 (None, TEXT, u'CONTENT 1'), | |
1006 (INSIDE, TEXT, u'ROOT'), | |
1007 (INSIDE, START, u'foo'), | |
1008 (INSIDE, TEXT, u'FOO'), | |
1009 (INSIDE, END, u'foo'), | |
1010 (INSIDE, START, u'bar'), | |
1011 (INSIDE, TEXT, u'BAR'), | |
1012 (INSIDE, END, u'bar'), | |
1013 (EXIT, END, u'root')], | |
1014 ) | |
1015 | |
1016 def test_prepend_text_context(self): | |
1017 self.assertEqual( | |
1018 self._apply('.', html='foo'), | |
1019 [(OUTSIDE, TEXT, u'foo')] | |
1020 ) | |
1021 | |
1022 def test_prepend_adjacent_elements(self): | |
1023 self.assertEqual( | |
1024 self._apply('*'), | |
1025 [(None, START, u'root'), | |
1026 (None, TEXT, u'ROOT'), | |
1027 (ENTER, START, u'foo'), | |
1028 (None, TEXT, u'CONTENT 1'), | |
1029 (INSIDE, TEXT, u'FOO'), | |
1030 (EXIT, END, u'foo'), | |
1031 (ENTER, START, u'bar'), | |
1032 (None, TEXT, u'CONTENT 2'), | |
1033 (INSIDE, TEXT, u'BAR'), | |
1034 (EXIT, END, u'bar'), | |
1035 (None, END, u'root')] | |
1036 | |
1037 ) | |
1038 | |
1039 def test_prepend_all(self): | |
1040 self.assertEqual( | |
1041 self._apply('*|text()'), | |
1042 [(None, START, u'root'), | |
1043 (OUTSIDE, TEXT, u'ROOT'), | |
1044 (ENTER, START, u'foo'), | |
1045 (None, TEXT, u'CONTENT 1'), | |
1046 (INSIDE, TEXT, u'FOO'), | |
1047 (EXIT, END, u'foo'), | |
1048 (ENTER, START, u'bar'), | |
1049 (None, TEXT, u'CONTENT 2'), | |
1050 (INSIDE, TEXT, u'BAR'), | |
1051 (EXIT, END, u'bar'), | |
1052 (None, END, u'root')] | |
1053 ) | |
1054 | |
1055 def test_prepend_with_callback(self): | |
1056 count = [0] | |
1057 def content(): | |
1058 count[0] += 1 | |
1059 yield '%2i.' % count[0] | |
1060 self.assertEqual( | |
1061 self._apply('foo', content), | |
1062 [(None, 'START', u'root'), | |
1063 (None, 'TEXT', u'ROOT'), | |
1064 (ENTER, 'START', u'foo'), | |
1065 (None, 'TEXT', u' 1.'), | |
1066 (INSIDE, 'TEXT', u'FOO'), | |
1067 (EXIT, 'END', u'foo'), | |
1068 (None, 'START', u'bar'), | |
1069 (None, 'TEXT', u'BAR'), | |
1070 (None, 'END', u'bar'), | |
1071 (None, 'END', u'root')] | |
1072 ) | |
1073 | |
1074 | |
1075 class AppendTest(unittest.TestCase, ContentTestMixin): | |
1076 operation = 'append' | |
1077 | |
1078 def test_append_element(self): | |
1079 self.assertEqual( | |
1080 self._apply('foo'), | |
1081 [(None, START, u'root'), | |
1082 (None, TEXT, u'ROOT'), | |
1083 (ENTER, START, u'foo'), | |
1084 (INSIDE, TEXT, u'FOO'), | |
1085 (None, TEXT, u'CONTENT 1'), | |
1086 (EXIT, END, u'foo'), | |
1087 (None, START, u'bar'), | |
1088 (None, TEXT, u'BAR'), | |
1089 (None, END, u'bar'), | |
1090 (None, END, u'root')] | |
1091 ) | |
1092 | |
1093 def test_append_text(self): | |
1094 self.assertEqual( | |
1095 self._apply('text()'), | |
1096 [(None, START, u'root'), | |
1097 (OUTSIDE, TEXT, u'ROOT'), | |
1098 (None, START, u'foo'), | |
1099 (None, TEXT, u'FOO'), | |
1100 (None, END, u'foo'), | |
1101 (None, START, u'bar'), | |
1102 (None, TEXT, u'BAR'), | |
1103 (None, END, u'bar'), | |
1104 (None, END, u'root')] | |
1105 ) | |
1106 | |
1107 def test_append_context(self): | |
1108 self.assertEqual( | |
1109 self._apply('.'), | |
1110 [(ENTER, START, u'root'), | |
1111 (INSIDE, TEXT, u'ROOT'), | |
1112 (INSIDE, START, u'foo'), | |
1113 (INSIDE, TEXT, u'FOO'), | |
1114 (INSIDE, END, u'foo'), | |
1115 (INSIDE, START, u'bar'), | |
1116 (INSIDE, TEXT, u'BAR'), | |
1117 (INSIDE, END, u'bar'), | |
1118 (None, TEXT, u'CONTENT 1'), | |
1119 (EXIT, END, u'root')], | |
1120 ) | |
1121 | |
1122 def test_append_text_context(self): | |
1123 self.assertEqual( | |
1124 self._apply('.', html='foo'), | |
1125 [(OUTSIDE, TEXT, u'foo')] | |
1126 ) | |
1127 | |
1128 def test_append_adjacent_elements(self): | |
1129 self.assertEqual( | |
1130 self._apply('*'), | |
1131 [(None, START, u'root'), | |
1132 (None, TEXT, u'ROOT'), | |
1133 (ENTER, START, u'foo'), | |
1134 (INSIDE, TEXT, u'FOO'), | |
1135 (None, TEXT, u'CONTENT 1'), | |
1136 (EXIT, END, u'foo'), | |
1137 (ENTER, START, u'bar'), | |
1138 (INSIDE, TEXT, u'BAR'), | |
1139 (None, TEXT, u'CONTENT 2'), | |
1140 (EXIT, END, u'bar'), | |
1141 (None, END, u'root')] | |
1142 | |
1143 ) | |
1144 | |
1145 def test_append_all(self): | |
1146 self.assertEqual( | |
1147 self._apply('*|text()'), | |
1148 [(None, START, u'root'), | |
1149 (OUTSIDE, TEXT, u'ROOT'), | |
1150 (ENTER, START, u'foo'), | |
1151 (INSIDE, TEXT, u'FOO'), | |
1152 (None, TEXT, u'CONTENT 1'), | |
1153 (EXIT, END, u'foo'), | |
1154 (ENTER, START, u'bar'), | |
1155 (INSIDE, TEXT, u'BAR'), | |
1156 (None, TEXT, u'CONTENT 2'), | |
1157 (EXIT, END, u'bar'), | |
1158 (None, END, u'root')] | |
1159 ) | |
1160 | |
1161 def test_append_with_callback(self): | |
1162 count = [0] | |
1163 def content(): | |
1164 count[0] += 1 | |
1165 yield '%2i.' % count[0] | |
1166 self.assertEqual( | |
1167 self._apply('foo', content), | |
1168 [(None, 'START', u'root'), | |
1169 (None, 'TEXT', u'ROOT'), | |
1170 (ENTER, 'START', u'foo'), | |
1171 (INSIDE, 'TEXT', u'FOO'), | |
1172 (None, 'TEXT', u' 1.'), | |
1173 (EXIT, 'END', u'foo'), | |
1174 (None, 'START', u'bar'), | |
1175 (None, 'TEXT', u'BAR'), | |
1176 (None, 'END', u'bar'), | |
1177 (None, 'END', u'root')] | |
1178 ) | |
1179 | |
1180 | |
1181 | |
1182 class AttrTest(unittest.TestCase): | |
1183 def _attr(self, select, name, value): | |
1184 return _transform(FOOBAR, Transformer(select).attr(name, value), | |
1185 with_attrs=True) | |
1186 | |
1187 def test_set_existing_attr(self): | |
1188 self.assertEqual( | |
1189 self._attr('foo', 'name', 'FOO'), | |
1190 [(None, START, (u'root', {})), | |
1191 (None, TEXT, u'ROOT'), | |
1192 (ENTER, START, (u'foo', {u'name': 'FOO', u'size': '100'})), | |
1193 (INSIDE, TEXT, u'FOO'), | |
1194 (EXIT, END, u'foo'), | |
1195 (None, START, (u'bar', {u'name': u'bar'})), | |
1196 (None, TEXT, u'BAR'), | |
1197 (None, END, u'bar'), | |
1198 (None, END, u'root')] | |
1199 ) | |
1200 | |
1201 def test_set_new_attr(self): | |
1202 self.assertEqual( | |
1203 self._attr('foo', 'title', 'FOO'), | |
1204 [(None, START, (u'root', {})), | |
1205 (None, TEXT, u'ROOT'), | |
1206 (ENTER, START, (u'foo', {u'name': u'foo', u'title': 'FOO', u'size': '100'})), | |
1207 (INSIDE, TEXT, u'FOO'), | |
1208 (EXIT, END, u'foo'), | |
1209 (None, START, (u'bar', {u'name': u'bar'})), | |
1210 (None, TEXT, u'BAR'), | |
1211 (None, END, u'bar'), | |
1212 (None, END, u'root')] | |
1213 ) | |
1214 | |
1215 def test_attr_from_function(self): | |
1216 def set(name, event): | |
1217 self.assertEqual(name, 'name') | |
1218 return event[1][1].get('name').upper() | |
1219 | |
1220 self.assertEqual( | |
1221 self._attr('foo|bar', 'name', set), | |
1222 [(None, START, (u'root', {})), | |
1223 (None, TEXT, u'ROOT'), | |
1224 (ENTER, START, (u'foo', {u'name': 'FOO', u'size': '100'})), | |
1225 (INSIDE, TEXT, u'FOO'), | |
1226 (EXIT, END, u'foo'), | |
1227 (ENTER, START, (u'bar', {u'name': 'BAR'})), | |
1228 (INSIDE, TEXT, u'BAR'), | |
1229 (EXIT, END, u'bar'), | |
1230 (None, END, u'root')] | |
1231 ) | |
1232 | |
1233 def test_remove_attr(self): | |
1234 self.assertEqual( | |
1235 self._attr('foo', 'name', None), | |
1236 [(None, START, (u'root', {})), | |
1237 (None, TEXT, u'ROOT'), | |
1238 (ENTER, START, (u'foo', {u'size': '100'})), | |
1239 (INSIDE, TEXT, u'FOO'), | |
1240 (EXIT, END, u'foo'), | |
1241 (None, START, (u'bar', {u'name': u'bar'})), | |
1242 (None, TEXT, u'BAR'), | |
1243 (None, END, u'bar'), | |
1244 (None, END, u'root')] | |
1245 ) | |
1246 | |
1247 def test_remove_attr_with_function(self): | |
1248 def set(name, event): | |
1249 return None | |
1250 | |
1251 self.assertEqual( | |
1252 self._attr('foo', 'name', set), | |
1253 [(None, START, (u'root', {})), | |
1254 (None, TEXT, u'ROOT'), | |
1255 (ENTER, START, (u'foo', {u'size': '100'})), | |
1256 (INSIDE, TEXT, u'FOO'), | |
1257 (EXIT, END, u'foo'), | |
1258 (None, START, (u'bar', {u'name': u'bar'})), | |
1259 (None, TEXT, u'BAR'), | |
1260 (None, END, u'bar'), | |
1261 (None, END, u'root')] | |
1262 ) | |
1263 | |
1264 | |
1265 class BufferTestMixin(object): | |
1266 def _apply(self, select, with_attrs=False): | |
1267 buffer = StreamBuffer() | |
1268 events = buffer.events | |
1269 | |
1270 class Trace(object): | |
1271 last = None | |
1272 trace = [] | |
1273 | |
1274 def __call__(self, stream): | |
1275 for event in stream: | |
1276 if events and hash(tuple(events)) != self.last: | |
1277 self.last = hash(tuple(events)) | |
1278 self.trace.append(list(events)) | |
1279 yield event | |
1280 | |
1281 trace = Trace() | |
1282 output = _transform(FOOBAR, getattr(Transformer(select), self.operation) | |
1283 (buffer).apply(trace), with_attrs=with_attrs) | |
1284 simplified = [] | |
1285 for interval in trace.trace: | |
1286 simplified.append(_simplify([(None, e) for e in interval], | |
1287 with_attrs=with_attrs)) | |
1288 return output, simplified | |
1289 | |
1290 | |
1291 class CopyTest(unittest.TestCase, BufferTestMixin): | |
1292 operation = 'copy' | |
1293 | |
1294 def test_copy_element(self): | |
1295 self.assertEqual( | |
1296 self._apply('foo')[1], | |
1297 [[(None, START, u'foo'), | |
1298 (None, TEXT, u'FOO'), | |
1299 (None, END, u'foo')]] | |
1300 ) | |
1301 | |
1302 def test_copy_adjacent_elements(self): | |
1303 self.assertEqual( | |
1304 self._apply('foo|bar')[1], | |
1305 [[(None, START, u'foo'), | |
1306 (None, TEXT, u'FOO'), | |
1307 (None, END, u'foo')], | |
1308 [(None, START, u'bar'), | |
1309 (None, TEXT, u'BAR'), | |
1310 (None, END, u'bar')]] | |
1311 ) | |
1312 | |
1313 def test_copy_all(self): | |
1314 self.assertEqual( | |
1315 self._apply('*|text()')[1], | |
1316 [[(None, TEXT, u'ROOT')], | |
1317 [(None, START, u'foo'), | |
1318 (None, TEXT, u'FOO'), | |
1319 (None, END, u'foo')], | |
1320 [(None, START, u'bar'), | |
1321 (None, TEXT, u'BAR'), | |
1322 (None, END, u'bar')]] | |
1323 ) | |
1324 | |
1325 def test_copy_text(self): | |
1326 self.assertEqual( | |
1327 self._apply('*/text()')[1], | |
1328 [[(None, TEXT, u'FOO')], | |
1329 [(None, TEXT, u'BAR')]] | |
1330 ) | |
1331 | |
1332 def test_copy_context(self): | |
1333 self.assertEqual( | |
1334 self._apply('.')[1], | |
1335 [[(None, START, u'root'), | |
1336 (None, TEXT, u'ROOT'), | |
1337 (None, START, u'foo'), | |
1338 (None, TEXT, u'FOO'), | |
1339 (None, END, u'foo'), | |
1340 (None, START, u'bar'), | |
1341 (None, TEXT, u'BAR'), | |
1342 (None, END, u'bar'), | |
1343 (None, END, u'root')]] | |
1344 ) | |
1345 | |
1346 def test_copy_attribute(self): | |
1347 self.assertEqual( | |
1348 self._apply('foo/@name', with_attrs=True)[1], | |
1349 [[(None, ATTR, {'name': u'foo'})]] | |
1350 ) | |
1351 | |
1352 def test_copy_attributes(self): | |
1353 self.assertEqual( | |
1354 self._apply('foo/@*', with_attrs=True)[1], | |
1355 [[(None, ATTR, {u'name': u'foo', u'size': u'100'})]] | |
1356 ) | |
1357 | |
1358 | |
1359 class CutTest(unittest.TestCase, BufferTestMixin): | |
1360 operation = 'cut' | |
1361 | |
1362 def test_cut_element(self): | |
1363 self.assertEqual( | |
1364 self._apply('foo'), | |
1365 ([(None, START, u'root'), | |
1366 (None, TEXT, u'ROOT'), | |
1367 (None, START, u'bar'), | |
1368 (None, TEXT, u'BAR'), | |
1369 (None, END, u'bar'), | |
1370 (None, END, u'root')], | |
1371 [[(None, START, u'foo'), | |
1372 (None, TEXT, u'FOO'), | |
1373 (None, END, u'foo')]]) | |
1374 ) | |
1375 | |
1376 def test_cut_adjacent_elements(self): | |
1377 self.assertEqual( | |
1378 self._apply('foo|bar'), | |
1379 ([(None, START, u'root'), | |
1380 (None, TEXT, u'ROOT'), | |
1381 (BREAK, BREAK, None), | |
1382 (None, END, u'root')], | |
1383 [[(None, START, u'foo'), | |
1384 (None, TEXT, u'FOO'), | |
1385 (None, END, u'foo')], | |
1386 [(None, START, u'bar'), | |
1387 (None, TEXT, u'BAR'), | |
1388 (None, END, u'bar')]]) | |
1389 ) | |
1390 | |
1391 def test_cut_all(self): | |
1392 self.assertEqual( | |
1393 self._apply('*|text()'), | |
1394 ([(None, 'START', u'root'), | |
1395 ('BREAK', 'BREAK', None), | |
1396 ('BREAK', 'BREAK', None), | |
1397 (None, 'END', u'root')], | |
1398 [[(None, 'TEXT', u'ROOT')], | |
1399 [(None, 'START', u'foo'), | |
1400 (None, 'TEXT', u'FOO'), | |
1401 (None, 'END', u'foo')], | |
1402 [(None, 'START', u'bar'), | |
1403 (None, 'TEXT', u'BAR'), | |
1404 (None, 'END', u'bar')]]) | |
1405 ) | |
1406 | |
1407 def test_cut_text(self): | |
1408 self.assertEqual( | |
1409 self._apply('*/text()'), | |
1410 ([(None, 'START', u'root'), | |
1411 (None, 'TEXT', u'ROOT'), | |
1412 (None, 'START', u'foo'), | |
1413 (None, 'END', u'foo'), | |
1414 (None, 'START', u'bar'), | |
1415 (None, 'END', u'bar'), | |
1416 (None, 'END', u'root')], | |
1417 [[(None, 'TEXT', u'FOO')], | |
1418 [(None, 'TEXT', u'BAR')]]) | |
1419 ) | |
1420 | |
1421 def test_cut_context(self): | |
1422 self.assertEqual( | |
1423 self._apply('.')[1], | |
1424 [[(None, 'START', u'root'), | |
1425 (None, 'TEXT', u'ROOT'), | |
1426 (None, 'START', u'foo'), | |
1427 (None, 'TEXT', u'FOO'), | |
1428 (None, 'END', u'foo'), | |
1429 (None, 'START', u'bar'), | |
1430 (None, 'TEXT', u'BAR'), | |
1431 (None, 'END', u'bar'), | |
1432 (None, 'END', u'root')]] | |
1433 ) | |
1434 | |
1435 def test_cut_attribute(self): | |
1436 self.assertEqual( | |
1437 self._apply('foo/@name', with_attrs=True), | |
1438 ([(None, START, (u'root', {})), | |
1439 (None, TEXT, u'ROOT'), | |
1440 (None, START, (u'foo', {u'size': u'100'})), | |
1441 (None, TEXT, u'FOO'), | |
1442 (None, END, u'foo'), | |
1443 (None, START, (u'bar', {u'name': u'bar'})), | |
1444 (None, TEXT, u'BAR'), | |
1445 (None, END, u'bar'), | |
1446 (None, END, u'root')], | |
1447 [[(None, ATTR, {u'name': u'foo'})]]) | |
1448 ) | |
1449 | |
1450 def test_cut_attributes(self): | |
1451 self.assertEqual( | |
1452 self._apply('foo/@*', with_attrs=True), | |
1453 ([(None, START, (u'root', {})), | |
1454 (None, TEXT, u'ROOT'), | |
1455 (None, START, (u'foo', {})), | |
1456 (None, TEXT, u'FOO'), | |
1457 (None, END, u'foo'), | |
1458 (None, START, (u'bar', {u'name': u'bar'})), | |
1459 (None, TEXT, u'BAR'), | |
1460 (None, END, u'bar'), | |
1461 (None, END, u'root')], | |
1462 [[(None, ATTR, {u'name': u'foo', u'size': u'100'})]]) | |
1463 ) | |
1464 | |
1465 # XXX Test this when the XPath implementation is fixed (#233). | |
1466 # def test_cut_attribute_or_attribute(self): | |
1467 # self.assertEqual( | |
1468 # self._apply('foo/@name | foo/@size', with_attrs=True), | |
1469 # ([(None, START, (u'root', {})), | |
1470 # (None, TEXT, u'ROOT'), | |
1471 # (None, START, (u'foo', {})), | |
1472 # (None, TEXT, u'FOO'), | |
1473 # (None, END, u'foo'), | |
1474 # (None, START, (u'bar', {u'name': u'bar'})), | |
1475 # (None, TEXT, u'BAR'), | |
1476 # (None, END, u'bar'), | |
1477 # (None, END, u'root')], | |
1478 # [[(None, ATTR, {u'name': u'foo', u'size': u'100'})]]) | |
1479 # ) | |
1480 | |
1481 | |
1482 | |
1483 | |
501
3073ac688651
Added new markup transformation filter contributed by Alec Thomas (#122). This provides gorgeous jQuery-inspired stream transformation capabilities based on XPath expressions.
cmlenz
parents:
diff
changeset
|
1484 def suite(): |
3073ac688651
Added new markup transformation filter contributed by Alec Thomas (#122). This provides gorgeous jQuery-inspired stream transformation capabilities based on XPath expressions.
cmlenz
parents:
diff
changeset
|
1485 from genshi.input import HTML |
668 | 1486 from genshi.core import Markup |
1487 from genshi.builder import tag | |
744 | 1488 suite = unittest.TestSuite() |
1489 for test in (SelectTest, InvertTest, EndTest, | |
1490 EmptyTest, RemoveTest, UnwrapText, WrapTest, FilterTest, | |
1491 MapTest, SubstituteTest, RenameTest, ReplaceTest, BeforeTest, | |
1492 AfterTest, PrependTest, AppendTest, AttrTest, CopyTest, CutTest): | |
1493 suite.addTest(unittest.makeSuite(test, 'test')) | |
1494 suite.addTest(doctest.DocTestSuite( | |
1495 genshi.filters.transform, optionflags=doctest.NORMALIZE_WHITESPACE, | |
1496 extraglobs={'HTML': HTML, 'tag': tag, 'Markup': Markup})) | |
501
3073ac688651
Added new markup transformation filter contributed by Alec Thomas (#122). This provides gorgeous jQuery-inspired stream transformation capabilities based on XPath expressions.
cmlenz
parents:
diff
changeset
|
1497 return suite |
3073ac688651
Added new markup transformation filter contributed by Alec Thomas (#122). This provides gorgeous jQuery-inspired stream transformation capabilities based on XPath expressions.
cmlenz
parents:
diff
changeset
|
1498 |
744 | 1499 |
501
3073ac688651
Added new markup transformation filter contributed by Alec Thomas (#122). This provides gorgeous jQuery-inspired stream transformation capabilities based on XPath expressions.
cmlenz
parents:
diff
changeset
|
1500 if __name__ == '__main__': |
3073ac688651
Added new markup transformation filter contributed by Alec Thomas (#122). This provides gorgeous jQuery-inspired stream transformation capabilities based on XPath expressions.
cmlenz
parents:
diff
changeset
|
1501 unittest.main(defaultTest='suite') |