comparison genshi/filters/tests/transform.py @ 820:1837f39efd6f experimental-inline

Sync (old) experimental inline branch with trunk@1027.
author cmlenz
date Wed, 11 Mar 2009 17:51:06 +0000
parents
children 09cc3627654c
comparison
equal deleted inserted replaced
500:0742f421caba 820:1837f39efd6f
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'),
547 [(QName(u'foo'), Attrs([(QName(u'name'), u'foo'),
548 (QName(u'size'), u'100')])),
549 u'FOO',
550 QName(u'foo')]
551 )
552
553 def test_map_with_text_kind(self):
554 self.assertEqual(
555 self._map('.', TEXT),
556 [u'ROOT', u'FOO', u'BAR']
557 )
558
559 def test_map_with_root_and_end_kind(self):
560 self.assertEqual(
561 self._map('.', END),
562 [QName(u'foo'), QName(u'bar'), QName(u'root')]
563 )
564
565 def test_map_with_attribute(self):
566 self.assertEqual(
567 self._map('foo/@name'),
568 [(QName(u'foo@*'), Attrs([('name', u'foo')]))]
569 )
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')
Copyright (C) 2012-2017 Edgewall Software