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