comparison genshi/filters/tests/transform.py @ 784:67d324a62cc0 experimental-match-fastpaths

update to 0.5.x branch, up through r907 don't know how this fits in with SoC work, but I wanted to do due diligence and keep this branch working in case it someday gets considered for trunk
author aflett
date Mon, 21 Jul 2008 23:17:52 +0000
parents ee48a06a16d6
children
comparison
equal deleted inserted replaced
724:8f2c7023af94 784:67d324a62cc0
10 # This software consists of voluntary contributions made by many 10 # This software consists of voluntary contributions made by many
11 # individuals. For the exact contribution history, see the revision 11 # individuals. For the exact contribution history, see the revision
12 # history and logs, available at http://genshi.edgewall.org/log/. 12 # history and logs, available at http://genshi.edgewall.org/log/.
13 13
14 import doctest 14 import doctest
15 from pprint import pprint
15 import unittest 16 import unittest
16 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
17 import genshi.filters.transform 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
526 class MapTest(unittest.TestCase):
527 def _map(self, select, kind=None):
528 data = []
529 def record(d):
530 data.append(d)
531 return d
532 _transform(FOOBAR, Transformer(select).map(record, kind))
533 return data
534
535 def test_map_element(self):
536 self.assertEqual(
537 self._map('foo'),
538 [(QName(u'foo'), Attrs([(QName(u'name'), u'foo'),
539 (QName(u'size'), u'100')])),
540 u'FOO',
541 QName(u'foo')]
542 )
543
544 def test_map_with_text_kind(self):
545 self.assertEqual(
546 self._map('.', TEXT),
547 [u'ROOT', u'FOO', u'BAR']
548 )
549
550 def test_map_with_root_and_end_kind(self):
551 self.assertEqual(
552 self._map('.', END),
553 [QName(u'foo'), QName(u'bar'), QName(u'root')]
554 )
555
556 def test_map_with_attribute(self):
557 self.assertEqual(
558 self._map('foo/@name'),
559 [(QName(u'foo@*'), Attrs([('name', u'foo')]))]
560 )
561
562
563 class SubstituteTest(unittest.TestCase):
564 def _substitute(self, select, pattern, replace):
565 return _transform(FOOBAR, Transformer(select).substitute(pattern, replace))
566
567 def test_substitute_foo(self):
568 self.assertEqual(
569 self._substitute('foo', 'FOO|BAR', 'FOOOOO'),
570 [(None, START, u'root'),
571 (None, TEXT, u'ROOT'),
572 (ENTER, START, u'foo'),
573 (INSIDE, TEXT, u'FOOOOO'),
574 (EXIT, END, u'foo'),
575 (None, START, u'bar'),
576 (None, TEXT, u'BAR'),
577 (None, END, u'bar'),
578 (None, END, u'root')]
579 )
580
581 def test_substitute_foobar_with_group(self):
582 self.assertEqual(
583 self._substitute('foo|bar', '(FOO|BAR)', r'(\1)'),
584 [(None, START, u'root'),
585 (None, TEXT, u'ROOT'),
586 (ENTER, START, u'foo'),
587 (INSIDE, TEXT, u'(FOO)'),
588 (EXIT, END, u'foo'),
589 (ENTER, START, u'bar'),
590 (INSIDE, TEXT, u'(BAR)'),
591 (EXIT, END, u'bar'),
592 (None, END, u'root')]
593 )
594
595
596 class RenameTest(unittest.TestCase):
597 def _rename(self, select):
598 return _transform(FOOBAR, Transformer(select).rename('foobar'))
599
600 def test_rename_root(self):
601 self.assertEqual(
602 self._rename('.'),
603 [(ENTER, START, u'foobar'),
604 (INSIDE, TEXT, u'ROOT'),
605 (INSIDE, START, u'foo'),
606 (INSIDE, TEXT, u'FOO'),
607 (INSIDE, END, u'foo'),
608 (INSIDE, START, u'bar'),
609 (INSIDE, TEXT, u'BAR'),
610 (INSIDE, END, u'bar'),
611 (EXIT, END, u'foobar')]
612 )
613
614 def test_rename_element(self):
615 self.assertEqual(
616 self._rename('foo|bar'),
617 [(None, START, u'root'),
618 (None, TEXT, u'ROOT'),
619 (ENTER, START, u'foobar'),
620 (INSIDE, TEXT, u'FOO'),
621 (EXIT, END, u'foobar'),
622 (ENTER, START, u'foobar'),
623 (INSIDE, TEXT, u'BAR'),
624 (EXIT, END, u'foobar'),
625 (None, END, u'root')]
626 )
627
628 def test_rename_text(self):
629 self.assertEqual(
630 self._rename('foo/text()'),
631 [(None, START, u'root'),
632 (None, TEXT, u'ROOT'),
633 (None, START, u'foo'),
634 (OUTSIDE, TEXT, u'FOO'),
635 (None, END, u'foo'),
636 (None, START, u'bar'),
637 (None, TEXT, u'BAR'),
638 (None, END, u'bar'),
639 (None, END, u'root')]
640 )
641
642
643 class ContentTestMixin(object):
644 def _apply(self, select, content=None, html=FOOBAR):
645 class Injector(object):
646 count = 0
647
648 def __iter__(self):
649 self.count += 1
650 return iter(HTML('CONTENT %i' % self.count))
651
652 if isinstance(html, basestring):
653 html = HTML(html)
654 if content is None:
655 content = Injector()
656 elif isinstance(content, basestring):
657 content = HTML(content)
658 return _transform(html, getattr(Transformer(select), self.operation)
659 (content))
660
661
662 class ReplaceTest(unittest.TestCase, ContentTestMixin):
663 operation = 'replace'
664
665 def test_replace_element(self):
666 self.assertEqual(
667 self._apply('foo'),
668 [(None, START, u'root'),
669 (None, TEXT, u'ROOT'),
670 (None, TEXT, u'CONTENT 1'),
671 (None, START, u'bar'),
672 (None, TEXT, u'BAR'),
673 (None, END, u'bar'),
674 (None, END, u'root')]
675 )
676
677 def test_replace_text(self):
678 self.assertEqual(
679 self._apply('text()'),
680 [(None, START, u'root'),
681 (None, TEXT, u'CONTENT 1'),
682 (None, START, u'foo'),
683 (None, TEXT, u'FOO'),
684 (None, END, u'foo'),
685 (None, START, u'bar'),
686 (None, TEXT, u'BAR'),
687 (None, END, u'bar'),
688 (None, END, u'root')]
689 )
690
691 def test_replace_context(self):
692 self.assertEqual(
693 self._apply('.'),
694 [(None, TEXT, u'CONTENT 1')],
695 )
696
697 def test_replace_text_context(self):
698 self.assertEqual(
699 self._apply('.', html='foo'),
700 [(None, TEXT, u'CONTENT 1')],
701 )
702
703 def test_replace_adjacent_elements(self):
704 self.assertEqual(
705 self._apply('*'),
706 [(None, START, u'root'),
707 (None, TEXT, u'ROOT'),
708 (None, TEXT, u'CONTENT 1'),
709 (None, TEXT, u'CONTENT 2'),
710 (None, END, u'root')],
711 )
712
713 def test_replace_all(self):
714 self.assertEqual(
715 self._apply('*|text()'),
716 [(None, START, u'root'),
717 (None, TEXT, u'CONTENT 1'),
718 (None, TEXT, u'CONTENT 2'),
719 (None, TEXT, u'CONTENT 3'),
720 (None, END, u'root')],
721 )
722
723 def test_replace_with_callback(self):
724 count = [0]
725 def content():
726 count[0] += 1
727 yield '%2i.' % count[0]
728 self.assertEqual(
729 self._apply('*', content),
730 [(None, START, u'root'),
731 (None, TEXT, u'ROOT'),
732 (None, TEXT, u' 1.'),
733 (None, TEXT, u' 2.'),
734 (None, END, u'root')]
735 )
736
737
738 class BeforeTest(unittest.TestCase, ContentTestMixin):
739 operation = 'before'
740
741 def test_before_element(self):
742 self.assertEqual(
743 self._apply('foo'),
744 [(None, START, u'root'),
745 (None, TEXT, u'ROOT'),
746 (None, TEXT, u'CONTENT 1'),
747 (ENTER, START, u'foo'),
748 (INSIDE, TEXT, u'FOO'),
749 (EXIT, END, u'foo'),
750 (None, START, u'bar'),
751 (None, TEXT, u'BAR'),
752 (None, END, u'bar'),
753 (None, END, u'root')]
754 )
755
756 def test_before_text(self):
757 self.assertEqual(
758 self._apply('text()'),
759 [(None, START, u'root'),
760 (None, TEXT, u'CONTENT 1'),
761 (OUTSIDE, TEXT, u'ROOT'),
762 (None, START, u'foo'),
763 (None, TEXT, u'FOO'),
764 (None, END, u'foo'),
765 (None, START, u'bar'),
766 (None, TEXT, u'BAR'),
767 (None, END, u'bar'),
768 (None, END, u'root')]
769 )
770
771 def test_before_context(self):
772 self.assertEqual(
773 self._apply('.'),
774 [(None, TEXT, u'CONTENT 1'),
775 (ENTER, START, u'root'),
776 (INSIDE, TEXT, u'ROOT'),
777 (INSIDE, START, u'foo'),
778 (INSIDE, TEXT, u'FOO'),
779 (INSIDE, END, u'foo'),
780 (INSIDE, START, u'bar'),
781 (INSIDE, TEXT, u'BAR'),
782 (INSIDE, END, u'bar'),
783 (EXIT, END, u'root')]
784 )
785
786 def test_before_text_context(self):
787 self.assertEqual(
788 self._apply('.', html='foo'),
789 [(None, TEXT, u'CONTENT 1'),
790 (OUTSIDE, TEXT, u'foo')]
791 )
792
793 def test_before_adjacent_elements(self):
794 self.assertEqual(
795 self._apply('*'),
796 [(None, START, u'root'),
797 (None, TEXT, u'ROOT'),
798 (None, TEXT, u'CONTENT 1'),
799 (ENTER, START, u'foo'),
800 (INSIDE, TEXT, u'FOO'),
801 (EXIT, END, u'foo'),
802 (None, TEXT, u'CONTENT 2'),
803 (ENTER, START, u'bar'),
804 (INSIDE, TEXT, u'BAR'),
805 (EXIT, END, u'bar'),
806 (None, END, u'root')]
807
808 )
809
810 def test_before_all(self):
811 self.assertEqual(
812 self._apply('*|text()'),
813 [(None, START, u'root'),
814 (None, TEXT, u'CONTENT 1'),
815 (OUTSIDE, TEXT, u'ROOT'),
816 (None, TEXT, u'CONTENT 2'),
817 (ENTER, START, u'foo'),
818 (INSIDE, TEXT, u'FOO'),
819 (EXIT, END, u'foo'),
820 (None, TEXT, u'CONTENT 3'),
821 (ENTER, START, u'bar'),
822 (INSIDE, TEXT, u'BAR'),
823 (EXIT, END, u'bar'),
824 (None, END, u'root')]
825 )
826
827 def test_before_with_callback(self):
828 count = [0]
829 def content():
830 count[0] += 1
831 yield '%2i.' % count[0]
832 self.assertEqual(
833 self._apply('foo/text()', content),
834 [(None, 'START', u'root'),
835 (None, 'TEXT', u'ROOT'),
836 (None, 'START', u'foo'),
837 (None, 'TEXT', u' 1.'),
838 ('OUTSIDE', 'TEXT', u'FOO'),
839 (None, 'END', u'foo'),
840 (None, 'START', u'bar'),
841 (None, 'TEXT', u'BAR'),
842 (None, 'END', u'bar'),
843 (None, 'END', u'root')]
844 )
845
846
847 class AfterTest(unittest.TestCase, ContentTestMixin):
848 operation = 'after'
849
850 def test_after_element(self):
851 self.assertEqual(
852 self._apply('foo'),
853 [(None, START, u'root'),
854 (None, TEXT, u'ROOT'),
855 (ENTER, START, u'foo'),
856 (INSIDE, TEXT, u'FOO'),
857 (EXIT, END, u'foo'),
858 (None, TEXT, u'CONTENT 1'),
859 (None, START, u'bar'),
860 (None, TEXT, u'BAR'),
861 (None, END, u'bar'),
862 (None, END, u'root')]
863 )
864
865 def test_after_text(self):
866 self.assertEqual(
867 self._apply('text()'),
868 [(None, START, u'root'),
869 (OUTSIDE, TEXT, u'ROOT'),
870 (None, TEXT, u'CONTENT 1'),
871 (None, START, u'foo'),
872 (None, TEXT, u'FOO'),
873 (None, END, u'foo'),
874 (None, START, u'bar'),
875 (None, TEXT, u'BAR'),
876 (None, END, u'bar'),
877 (None, END, u'root')]
878 )
879
880 def test_after_context(self):
881 self.assertEqual(
882 self._apply('.'),
883 [(ENTER, START, u'root'),
884 (INSIDE, TEXT, u'ROOT'),
885 (INSIDE, START, u'foo'),
886 (INSIDE, TEXT, u'FOO'),
887 (INSIDE, END, u'foo'),
888 (INSIDE, START, u'bar'),
889 (INSIDE, TEXT, u'BAR'),
890 (INSIDE, END, u'bar'),
891 (EXIT, END, u'root'),
892 (None, TEXT, u'CONTENT 1')]
893 )
894
895 def test_after_text_context(self):
896 self.assertEqual(
897 self._apply('.', html='foo'),
898 [(OUTSIDE, TEXT, u'foo'),
899 (None, TEXT, u'CONTENT 1')]
900 )
901
902 def test_after_adjacent_elements(self):
903 self.assertEqual(
904 self._apply('*'),
905 [(None, START, u'root'),
906 (None, TEXT, u'ROOT'),
907 (ENTER, START, u'foo'),
908 (INSIDE, TEXT, u'FOO'),
909 (EXIT, END, u'foo'),
910 (None, TEXT, u'CONTENT 1'),
911 (ENTER, START, u'bar'),
912 (INSIDE, TEXT, u'BAR'),
913 (EXIT, END, u'bar'),
914 (None, TEXT, u'CONTENT 2'),
915 (None, END, u'root')]
916
917 )
918
919 def test_after_all(self):
920 self.assertEqual(
921 self._apply('*|text()'),
922 [(None, START, u'root'),
923 (OUTSIDE, TEXT, u'ROOT'),
924 (None, TEXT, u'CONTENT 1'),
925 (ENTER, START, u'foo'),
926 (INSIDE, TEXT, u'FOO'),
927 (EXIT, END, u'foo'),
928 (None, TEXT, u'CONTENT 2'),
929 (ENTER, START, u'bar'),
930 (INSIDE, TEXT, u'BAR'),
931 (EXIT, END, u'bar'),
932 (None, TEXT, u'CONTENT 3'),
933 (None, END, u'root')]
934 )
935
936 def test_after_with_callback(self):
937 count = [0]
938 def content():
939 count[0] += 1
940 yield '%2i.' % count[0]
941 self.assertEqual(
942 self._apply('foo/text()', content),
943 [(None, 'START', u'root'),
944 (None, 'TEXT', u'ROOT'),
945 (None, 'START', u'foo'),
946 ('OUTSIDE', 'TEXT', u'FOO'),
947 (None, 'TEXT', u' 1.'),
948 (None, 'END', u'foo'),
949 (None, 'START', u'bar'),
950 (None, 'TEXT', u'BAR'),
951 (None, 'END', u'bar'),
952 (None, 'END', u'root')]
953 )
954
955
956 class PrependTest(unittest.TestCase, ContentTestMixin):
957 operation = 'prepend'
958
959 def test_prepend_element(self):
960 self.assertEqual(
961 self._apply('foo'),
962 [(None, START, u'root'),
963 (None, TEXT, u'ROOT'),
964 (ENTER, START, u'foo'),
965 (None, TEXT, u'CONTENT 1'),
966 (INSIDE, TEXT, u'FOO'),
967 (EXIT, END, u'foo'),
968 (None, START, u'bar'),
969 (None, TEXT, u'BAR'),
970 (None, END, u'bar'),
971 (None, END, u'root')]
972 )
973
974 def test_prepend_text(self):
975 self.assertEqual(
976 self._apply('text()'),
977 [(None, START, u'root'),
978 (OUTSIDE, TEXT, u'ROOT'),
979 (None, START, u'foo'),
980 (None, TEXT, u'FOO'),
981 (None, END, u'foo'),
982 (None, START, u'bar'),
983 (None, TEXT, u'BAR'),
984 (None, END, u'bar'),
985 (None, END, u'root')]
986 )
987
988 def test_prepend_context(self):
989 self.assertEqual(
990 self._apply('.'),
991 [(ENTER, START, u'root'),
992 (None, TEXT, u'CONTENT 1'),
993 (INSIDE, TEXT, u'ROOT'),
994 (INSIDE, START, u'foo'),
995 (INSIDE, TEXT, u'FOO'),
996 (INSIDE, END, u'foo'),
997 (INSIDE, START, u'bar'),
998 (INSIDE, TEXT, u'BAR'),
999 (INSIDE, END, u'bar'),
1000 (EXIT, END, u'root')],
1001 )
1002
1003 def test_prepend_text_context(self):
1004 self.assertEqual(
1005 self._apply('.', html='foo'),
1006 [(OUTSIDE, TEXT, u'foo')]
1007 )
1008
1009 def test_prepend_adjacent_elements(self):
1010 self.assertEqual(
1011 self._apply('*'),
1012 [(None, START, u'root'),
1013 (None, TEXT, u'ROOT'),
1014 (ENTER, START, u'foo'),
1015 (None, TEXT, u'CONTENT 1'),
1016 (INSIDE, TEXT, u'FOO'),
1017 (EXIT, END, u'foo'),
1018 (ENTER, START, u'bar'),
1019 (None, TEXT, u'CONTENT 2'),
1020 (INSIDE, TEXT, u'BAR'),
1021 (EXIT, END, u'bar'),
1022 (None, END, u'root')]
1023
1024 )
1025
1026 def test_prepend_all(self):
1027 self.assertEqual(
1028 self._apply('*|text()'),
1029 [(None, START, u'root'),
1030 (OUTSIDE, TEXT, u'ROOT'),
1031 (ENTER, START, u'foo'),
1032 (None, TEXT, u'CONTENT 1'),
1033 (INSIDE, TEXT, u'FOO'),
1034 (EXIT, END, u'foo'),
1035 (ENTER, START, u'bar'),
1036 (None, TEXT, u'CONTENT 2'),
1037 (INSIDE, TEXT, u'BAR'),
1038 (EXIT, END, u'bar'),
1039 (None, END, u'root')]
1040 )
1041
1042 def test_prepend_with_callback(self):
1043 count = [0]
1044 def content():
1045 count[0] += 1
1046 yield '%2i.' % count[0]
1047 self.assertEqual(
1048 self._apply('foo', content),
1049 [(None, 'START', u'root'),
1050 (None, 'TEXT', u'ROOT'),
1051 (ENTER, 'START', u'foo'),
1052 (None, 'TEXT', u' 1.'),
1053 (INSIDE, 'TEXT', u'FOO'),
1054 (EXIT, 'END', u'foo'),
1055 (None, 'START', u'bar'),
1056 (None, 'TEXT', u'BAR'),
1057 (None, 'END', u'bar'),
1058 (None, 'END', u'root')]
1059 )
1060
1061
1062 class AppendTest(unittest.TestCase, ContentTestMixin):
1063 operation = 'append'
1064
1065 def test_append_element(self):
1066 self.assertEqual(
1067 self._apply('foo'),
1068 [(None, START, u'root'),
1069 (None, TEXT, u'ROOT'),
1070 (ENTER, START, u'foo'),
1071 (INSIDE, TEXT, u'FOO'),
1072 (None, TEXT, u'CONTENT 1'),
1073 (EXIT, END, u'foo'),
1074 (None, START, u'bar'),
1075 (None, TEXT, u'BAR'),
1076 (None, END, u'bar'),
1077 (None, END, u'root')]
1078 )
1079
1080 def test_append_text(self):
1081 self.assertEqual(
1082 self._apply('text()'),
1083 [(None, START, u'root'),
1084 (OUTSIDE, TEXT, u'ROOT'),
1085 (None, START, u'foo'),
1086 (None, TEXT, u'FOO'),
1087 (None, END, u'foo'),
1088 (None, START, u'bar'),
1089 (None, TEXT, u'BAR'),
1090 (None, END, u'bar'),
1091 (None, END, u'root')]
1092 )
1093
1094 def test_append_context(self):
1095 self.assertEqual(
1096 self._apply('.'),
1097 [(ENTER, START, u'root'),
1098 (INSIDE, TEXT, u'ROOT'),
1099 (INSIDE, START, u'foo'),
1100 (INSIDE, TEXT, u'FOO'),
1101 (INSIDE, END, u'foo'),
1102 (INSIDE, START, u'bar'),
1103 (INSIDE, TEXT, u'BAR'),
1104 (INSIDE, END, u'bar'),
1105 (None, TEXT, u'CONTENT 1'),
1106 (EXIT, END, u'root')],
1107 )
1108
1109 def test_append_text_context(self):
1110 self.assertEqual(
1111 self._apply('.', html='foo'),
1112 [(OUTSIDE, TEXT, u'foo')]
1113 )
1114
1115 def test_append_adjacent_elements(self):
1116 self.assertEqual(
1117 self._apply('*'),
1118 [(None, START, u'root'),
1119 (None, TEXT, u'ROOT'),
1120 (ENTER, START, u'foo'),
1121 (INSIDE, TEXT, u'FOO'),
1122 (None, TEXT, u'CONTENT 1'),
1123 (EXIT, END, u'foo'),
1124 (ENTER, START, u'bar'),
1125 (INSIDE, TEXT, u'BAR'),
1126 (None, TEXT, u'CONTENT 2'),
1127 (EXIT, END, u'bar'),
1128 (None, END, u'root')]
1129
1130 )
1131
1132 def test_append_all(self):
1133 self.assertEqual(
1134 self._apply('*|text()'),
1135 [(None, START, u'root'),
1136 (OUTSIDE, TEXT, u'ROOT'),
1137 (ENTER, START, u'foo'),
1138 (INSIDE, TEXT, u'FOO'),
1139 (None, TEXT, u'CONTENT 1'),
1140 (EXIT, END, u'foo'),
1141 (ENTER, START, u'bar'),
1142 (INSIDE, TEXT, u'BAR'),
1143 (None, TEXT, u'CONTENT 2'),
1144 (EXIT, END, u'bar'),
1145 (None, END, u'root')]
1146 )
1147
1148 def test_append_with_callback(self):
1149 count = [0]
1150 def content():
1151 count[0] += 1
1152 yield '%2i.' % count[0]
1153 self.assertEqual(
1154 self._apply('foo', content),
1155 [(None, 'START', u'root'),
1156 (None, 'TEXT', u'ROOT'),
1157 (ENTER, 'START', u'foo'),
1158 (INSIDE, 'TEXT', u'FOO'),
1159 (None, 'TEXT', u' 1.'),
1160 (EXIT, 'END', u'foo'),
1161 (None, 'START', u'bar'),
1162 (None, 'TEXT', u'BAR'),
1163 (None, 'END', u'bar'),
1164 (None, 'END', u'root')]
1165 )
1166
1167
1168
1169 class AttrTest(unittest.TestCase):
1170 def _attr(self, select, name, value):
1171 return _transform(FOOBAR, Transformer(select).attr(name, value),
1172 with_attrs=True)
1173
1174 def test_set_existing_attr(self):
1175 self.assertEqual(
1176 self._attr('foo', 'name', 'FOO'),
1177 [(None, START, (u'root', {})),
1178 (None, TEXT, u'ROOT'),
1179 (ENTER, START, (u'foo', {u'name': 'FOO', u'size': '100'})),
1180 (INSIDE, TEXT, u'FOO'),
1181 (EXIT, END, u'foo'),
1182 (None, START, (u'bar', {u'name': u'bar'})),
1183 (None, TEXT, u'BAR'),
1184 (None, END, u'bar'),
1185 (None, END, u'root')]
1186 )
1187
1188 def test_set_new_attr(self):
1189 self.assertEqual(
1190 self._attr('foo', 'title', 'FOO'),
1191 [(None, START, (u'root', {})),
1192 (None, TEXT, u'ROOT'),
1193 (ENTER, START, (u'foo', {u'name': u'foo', u'title': 'FOO', u'size': '100'})),
1194 (INSIDE, TEXT, u'FOO'),
1195 (EXIT, END, u'foo'),
1196 (None, START, (u'bar', {u'name': u'bar'})),
1197 (None, TEXT, u'BAR'),
1198 (None, END, u'bar'),
1199 (None, END, u'root')]
1200 )
1201
1202 def test_attr_from_function(self):
1203 def set(name, event):
1204 self.assertEqual(name, 'name')
1205 return event[1][1].get('name').upper()
1206
1207 self.assertEqual(
1208 self._attr('foo|bar', 'name', set),
1209 [(None, START, (u'root', {})),
1210 (None, TEXT, u'ROOT'),
1211 (ENTER, START, (u'foo', {u'name': 'FOO', u'size': '100'})),
1212 (INSIDE, TEXT, u'FOO'),
1213 (EXIT, END, u'foo'),
1214 (ENTER, START, (u'bar', {u'name': 'BAR'})),
1215 (INSIDE, TEXT, u'BAR'),
1216 (EXIT, END, u'bar'),
1217 (None, END, u'root')]
1218 )
1219
1220 def test_remove_attr(self):
1221 self.assertEqual(
1222 self._attr('foo', 'name', None),
1223 [(None, START, (u'root', {})),
1224 (None, TEXT, u'ROOT'),
1225 (ENTER, START, (u'foo', {u'size': '100'})),
1226 (INSIDE, TEXT, u'FOO'),
1227 (EXIT, END, u'foo'),
1228 (None, START, (u'bar', {u'name': u'bar'})),
1229 (None, TEXT, u'BAR'),
1230 (None, END, u'bar'),
1231 (None, END, u'root')]
1232 )
1233
1234 def test_remove_attr_with_function(self):
1235 def set(name, event):
1236 return None
1237
1238 self.assertEqual(
1239 self._attr('foo', 'name', set),
1240 [(None, START, (u'root', {})),
1241 (None, TEXT, u'ROOT'),
1242 (ENTER, START, (u'foo', {u'size': '100'})),
1243 (INSIDE, TEXT, u'FOO'),
1244 (EXIT, END, u'foo'),
1245 (None, START, (u'bar', {u'name': u'bar'})),
1246 (None, TEXT, u'BAR'),
1247 (None, END, u'bar'),
1248 (None, END, u'root')]
1249 )
1250
1251
1252 class BufferTestMixin(object):
1253 def _apply(self, select, with_attrs=False):
1254 buffer = StreamBuffer()
1255 events = buffer.events
1256
1257 class Trace(object):
1258 last = None
1259 trace = []
1260
1261 def __call__(self, stream):
1262 for event in stream:
1263 if events and hash(tuple(events)) != self.last:
1264 self.last = hash(tuple(events))
1265 self.trace.append(list(events))
1266 yield event
1267
1268 trace = Trace()
1269 output = _transform(FOOBAR, getattr(Transformer(select), self.operation)
1270 (buffer).apply(trace), with_attrs=with_attrs)
1271 simplified = []
1272 for interval in trace.trace:
1273 simplified.append(_simplify([(None, e) for e in interval],
1274 with_attrs=with_attrs))
1275 return output, simplified
1276
1277
1278 class CopyTest(unittest.TestCase, BufferTestMixin):
1279 operation = 'copy'
1280
1281 def test_copy_element(self):
1282 self.assertEqual(
1283 self._apply('foo')[1],
1284 [[(None, START, u'foo'),
1285 (None, TEXT, u'FOO'),
1286 (None, END, u'foo')]]
1287 )
1288
1289 def test_copy_adjacent_elements(self):
1290 self.assertEqual(
1291 self._apply('foo|bar')[1],
1292 [[(None, START, u'foo'),
1293 (None, TEXT, u'FOO'),
1294 (None, END, u'foo')],
1295 [(None, START, u'bar'),
1296 (None, TEXT, u'BAR'),
1297 (None, END, u'bar')]]
1298 )
1299
1300 def test_copy_all(self):
1301 self.assertEqual(
1302 self._apply('*|text()')[1],
1303 [[(None, TEXT, u'ROOT')],
1304 [(None, START, u'foo'),
1305 (None, TEXT, u'FOO'),
1306 (None, END, u'foo')],
1307 [(None, START, u'bar'),
1308 (None, TEXT, u'BAR'),
1309 (None, END, u'bar')]]
1310 )
1311
1312 def test_copy_text(self):
1313 self.assertEqual(
1314 self._apply('*/text()')[1],
1315 [[(None, TEXT, u'FOO')],
1316 [(None, TEXT, u'BAR')]]
1317 )
1318
1319 def test_copy_context(self):
1320 self.assertEqual(
1321 self._apply('.')[1],
1322 [[(None, START, u'root'),
1323 (None, TEXT, u'ROOT'),
1324 (None, START, u'foo'),
1325 (None, TEXT, u'FOO'),
1326 (None, END, u'foo'),
1327 (None, START, u'bar'),
1328 (None, TEXT, u'BAR'),
1329 (None, END, u'bar'),
1330 (None, END, u'root')]]
1331 )
1332
1333 def test_copy_attribute(self):
1334 self.assertEqual(
1335 self._apply('foo/@name', with_attrs=True)[1],
1336 [[(None, ATTR, {'name': u'foo'})]]
1337 )
1338
1339 def test_copy_attributes(self):
1340 self.assertEqual(
1341 self._apply('foo/@*', with_attrs=True)[1],
1342 [[(None, ATTR, {u'name': u'foo', u'size': u'100'})]]
1343 )
1344
1345
1346 class CutTest(unittest.TestCase, BufferTestMixin):
1347 operation = 'cut'
1348
1349 def test_cut_element(self):
1350 self.assertEqual(
1351 self._apply('foo'),
1352 ([(None, START, u'root'),
1353 (None, TEXT, u'ROOT'),
1354 (None, START, u'bar'),
1355 (None, TEXT, u'BAR'),
1356 (None, END, u'bar'),
1357 (None, END, u'root')],
1358 [[(None, START, u'foo'),
1359 (None, TEXT, u'FOO'),
1360 (None, END, u'foo')]])
1361 )
1362
1363 def test_cut_adjacent_elements(self):
1364 self.assertEqual(
1365 self._apply('foo|bar'),
1366 ([(None, START, u'root'),
1367 (None, TEXT, u'ROOT'),
1368 (BREAK, BREAK, None),
1369 (None, END, u'root')],
1370 [[(None, START, u'foo'),
1371 (None, TEXT, u'FOO'),
1372 (None, END, u'foo')],
1373 [(None, START, u'bar'),
1374 (None, TEXT, u'BAR'),
1375 (None, END, u'bar')]])
1376 )
1377
1378 def test_cut_all(self):
1379 self.assertEqual(
1380 self._apply('*|text()'),
1381 ([(None, 'START', u'root'),
1382 ('BREAK', 'BREAK', None),
1383 ('BREAK', 'BREAK', None),
1384 (None, 'END', u'root')],
1385 [[(None, 'TEXT', u'ROOT')],
1386 [(None, 'START', u'foo'),
1387 (None, 'TEXT', u'FOO'),
1388 (None, 'END', u'foo')],
1389 [(None, 'START', u'bar'),
1390 (None, 'TEXT', u'BAR'),
1391 (None, 'END', u'bar')]])
1392 )
1393
1394 def test_cut_text(self):
1395 self.assertEqual(
1396 self._apply('*/text()'),
1397 ([(None, 'START', u'root'),
1398 (None, 'TEXT', u'ROOT'),
1399 (None, 'START', u'foo'),
1400 (None, 'END', u'foo'),
1401 (None, 'START', u'bar'),
1402 (None, 'END', u'bar'),
1403 (None, 'END', u'root')],
1404 [[(None, 'TEXT', u'FOO')],
1405 [(None, 'TEXT', u'BAR')]])
1406 )
1407
1408 def test_cut_context(self):
1409 self.assertEqual(
1410 self._apply('.')[1],
1411 [[(None, 'START', u'root'),
1412 (None, 'TEXT', u'ROOT'),
1413 (None, 'START', u'foo'),
1414 (None, 'TEXT', u'FOO'),
1415 (None, 'END', u'foo'),
1416 (None, 'START', u'bar'),
1417 (None, 'TEXT', u'BAR'),
1418 (None, 'END', u'bar'),
1419 (None, 'END', u'root')]]
1420 )
1421
1422 def test_cut_attribute(self):
1423 self.assertEqual(
1424 self._apply('foo/@name', with_attrs=True),
1425 ([(None, START, (u'root', {})),
1426 (None, TEXT, u'ROOT'),
1427 (None, START, (u'foo', {u'size': u'100'})),
1428 (None, TEXT, u'FOO'),
1429 (None, END, u'foo'),
1430 (None, START, (u'bar', {u'name': u'bar'})),
1431 (None, TEXT, u'BAR'),
1432 (None, END, u'bar'),
1433 (None, END, u'root')],
1434 [[(None, ATTR, {u'name': u'foo'})]])
1435 )
1436
1437 def test_cut_attributes(self):
1438 self.assertEqual(
1439 self._apply('foo/@*', with_attrs=True),
1440 ([(None, START, (u'root', {})),
1441 (None, TEXT, u'ROOT'),
1442 (None, START, (u'foo', {})),
1443 (None, TEXT, u'FOO'),
1444 (None, END, u'foo'),
1445 (None, START, (u'bar', {u'name': u'bar'})),
1446 (None, TEXT, u'BAR'),
1447 (None, END, u'bar'),
1448 (None, END, u'root')],
1449 [[(None, ATTR, {u'name': u'foo', u'size': u'100'})]])
1450 )
1451
1452 # XXX Test this when the XPath implementation is fixed (#233).
1453 # def test_cut_attribute_or_attribute(self):
1454 # self.assertEqual(
1455 # self._apply('foo/@name | foo/@size', with_attrs=True),
1456 # ([(None, START, (u'root', {})),
1457 # (None, TEXT, u'ROOT'),
1458 # (None, START, (u'foo', {})),
1459 # (None, TEXT, u'FOO'),
1460 # (None, END, u'foo'),
1461 # (None, START, (u'bar', {u'name': u'bar'})),
1462 # (None, TEXT, u'BAR'),
1463 # (None, END, u'bar'),
1464 # (None, END, u'root')],
1465 # [[(None, ATTR, {u'name': u'foo', u'size': u'100'})]])
1466 # )
1467
1468
18 1469
19 1470
20 def suite(): 1471 def suite():
21 from genshi.input import HTML 1472 from genshi.input import HTML
22 from genshi.core import Markup 1473 from genshi.core import Markup
23 from genshi.builder import tag 1474 from genshi.builder import tag
24 suite = doctest.DocTestSuite(genshi.filters.transform, 1475 suite = unittest.TestSuite()
25 optionflags=doctest.NORMALIZE_WHITESPACE, 1476 for test in (SelectTest, InvertTest, EndTest,
26 extraglobs={'HTML': HTML, 'tag': tag, 1477 EmptyTest, RemoveTest, UnwrapText, WrapTest, FilterTest,
27 'Markup': Markup}) 1478 MapTest, SubstituteTest, RenameTest, ReplaceTest, BeforeTest,
1479 AfterTest, PrependTest, AppendTest, AttrTest, CopyTest, CutTest):
1480 suite.addTest(unittest.makeSuite(test, 'test'))
1481 suite.addTest(doctest.DocTestSuite(
1482 genshi.filters.transform, optionflags=doctest.NORMALIZE_WHITESPACE,
1483 extraglobs={'HTML': HTML, 'tag': tag, 'Markup': Markup}))
28 return suite 1484 return suite
1485
29 1486
30 if __name__ == '__main__': 1487 if __name__ == '__main__':
31 unittest.main(defaultTest='suite') 1488 unittest.main(defaultTest='suite')
Copyright (C) 2012-2017 Edgewall Software