Mercurial > genshi > genshi-test
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') |