Edgewall Software

source: trunk/genshi/template/tests/markup.py

Last change on this file was 1257, checked in by hodgestar, 10 years ago

Fix infinite recursion in template inlining (fixes #584).

  • Property svn:eol-style set to native
File size: 27.8 KB
Line 
1# -*- coding: utf-8 -*-
2#
3# Copyright (C) 2006-2009 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
14import doctest
15import os
16import pickle
17import shutil
18import sys
19import tempfile
20import unittest
21
22from genshi.compat import BytesIO, StringIO
23from genshi.core import Markup
24from genshi.input import XML
25from genshi.template.base import BadDirectiveError, TemplateSyntaxError
26from genshi.template.loader import TemplateLoader, TemplateNotFound
27from genshi.template.markup import MarkupTemplate
28
29
30class MarkupTemplateTestCase(unittest.TestCase):
31    """Tests for markup template processing."""
32
33    def test_parse_fileobj(self):
34        fileobj = StringIO('<root> ${var} $var</root>')
35        tmpl = MarkupTemplate(fileobj)
36        self.assertEqual('<root> 42 42</root>', str(tmpl.generate(var=42)))
37
38    def test_parse_stream(self):
39        stream = XML('<root> ${var} $var</root>')
40        tmpl = MarkupTemplate(stream)
41        self.assertEqual('<root> 42 42</root>', str(tmpl.generate(var=42)))
42
43    def test_pickle(self):
44        stream = XML('<root>$var</root>')
45        tmpl = MarkupTemplate(stream)
46        buf = BytesIO()
47        pickle.dump(tmpl, buf, 2)
48        buf.seek(0)
49        unpickled = pickle.load(buf)
50        self.assertEqual('<root>42</root>', str(unpickled.generate(var=42)))
51
52    def test_interpolate_mixed3(self):
53        tmpl = MarkupTemplate('<root> ${var} $var</root>')
54        self.assertEqual('<root> 42 42</root>', str(tmpl.generate(var=42)))
55
56    def test_interpolate_leading_trailing_space(self):
57        tmpl = MarkupTemplate('<root>${    foo    }</root>')
58        self.assertEqual('<root>bar</root>', str(tmpl.generate(foo='bar')))
59
60    def test_interpolate_multiline(self):
61        tmpl = MarkupTemplate("""<root>${dict(
62          bar = 'baz'
63        )[foo]}</root>""")
64        self.assertEqual('<root>baz</root>', str(tmpl.generate(foo='bar')))
65
66    def test_interpolate_non_string_attrs(self):
67        tmpl = MarkupTemplate('<root attr="${1}"/>')
68        self.assertEqual('<root attr="1"/>', str(tmpl.generate()))
69
70    def test_interpolate_list_result(self):
71        tmpl = MarkupTemplate('<root>$foo</root>')
72        self.assertEqual('<root>buzz</root>', str(tmpl.generate(foo=('buzz',))))
73
74    def test_empty_attr(self):
75        tmpl = MarkupTemplate('<root attr=""/>')
76        self.assertEqual('<root attr=""/>', str(tmpl.generate()))
77
78    def test_empty_attr_interpolated(self):
79        tmpl = MarkupTemplate('<root attr="$attr"/>')
80        self.assertEqual('<root attr=""/>', str(tmpl.generate(attr='')))
81
82    def test_bad_directive_error(self):
83        xml = '<p xmlns:py="http://genshi.edgewall.org/" py:do="nothing" />'
84        try:
85            tmpl = MarkupTemplate(xml, filename='test.html')
86        except BadDirectiveError, e:
87            self.assertEqual('test.html', e.filename)
88            self.assertEqual(1, e.lineno)
89
90    def test_directive_value_syntax_error(self):
91        xml = """<p xmlns:py="http://genshi.edgewall.org/" py:if="bar'" />"""
92        try:
93            tmpl = MarkupTemplate(xml, filename='test.html').generate()
94            self.fail('Expected TemplateSyntaxError')
95        except TemplateSyntaxError, e:
96            self.assertEqual('test.html', e.filename)
97            self.assertEqual(1, e.lineno)
98
99    def test_expression_syntax_error(self):
100        xml = """<p>
101          Foo <em>${bar"}</em>
102        </p>"""
103        try:
104            tmpl = MarkupTemplate(xml, filename='test.html')
105            self.fail('Expected TemplateSyntaxError')
106        except TemplateSyntaxError, e:
107            self.assertEqual('test.html', e.filename)
108            self.assertEqual(2, e.lineno)
109
110    def test_expression_syntax_error_multi_line(self):
111        xml = """<p><em></em>
112
113 ${bar"}
114
115        </p>"""
116        try:
117            tmpl = MarkupTemplate(xml, filename='test.html')
118            self.fail('Expected TemplateSyntaxError')
119        except TemplateSyntaxError, e:
120            self.assertEqual('test.html', e.filename)
121            self.assertEqual(3, e.lineno)
122
123    def test_markup_noescape(self):
124        """
125        Verify that outputting context data that is a `Markup` instance is not
126        escaped.
127        """
128        tmpl = MarkupTemplate("""<div xmlns:py="http://genshi.edgewall.org/">
129          $myvar
130        </div>""")
131        self.assertEqual("""<div>
132          <b>foo</b>
133        </div>""", str(tmpl.generate(myvar=Markup('<b>foo</b>'))))
134
135    def test_text_noescape_quotes(self):
136        """
137        Verify that outputting context data in text nodes doesn't escape
138        quotes.
139        """
140        tmpl = MarkupTemplate("""<div xmlns:py="http://genshi.edgewall.org/">
141          $myvar
142        </div>""")
143        self.assertEqual("""<div>
144          "foo"
145        </div>""", str(tmpl.generate(myvar='"foo"')))
146
147    def test_attr_escape_quotes(self):
148        """
149        Verify that outputting context data in attribtes escapes quotes.
150        """
151        tmpl = MarkupTemplate("""<div xmlns:py="http://genshi.edgewall.org/">
152          <elem class="$myvar"/>
153        </div>""")
154        self.assertEqual("""<div>
155          <elem class="&#34;foo&#34;"/>
156        </div>""", str(tmpl.generate(myvar='"foo"')))
157
158    def test_directive_element(self):
159        tmpl = MarkupTemplate("""<div xmlns:py="http://genshi.edgewall.org/">
160          <py:if test="myvar">bar</py:if>
161        </div>""")
162        self.assertEqual("""<div>
163          bar
164        </div>""", str(tmpl.generate(myvar='"foo"')))
165
166    def test_normal_comment(self):
167        tmpl = MarkupTemplate("""<div xmlns:py="http://genshi.edgewall.org/">
168          <!-- foo bar -->
169        </div>""")
170        self.assertEqual("""<div>
171          <!-- foo bar -->
172        </div>""", str(tmpl.generate()))
173
174    def test_template_comment(self):
175        tmpl = MarkupTemplate("""<div xmlns:py="http://genshi.edgewall.org/">
176          <!-- !foo -->
177          <!--!bar-->
178        </div>""")
179        self.assertEqual("""<div>
180        </div>""", str(tmpl.generate()))
181
182    def test_parse_with_same_namespace_nested(self):
183        tmpl = MarkupTemplate("""<div xmlns:py="http://genshi.edgewall.org/">
184          <span xmlns:py="http://genshi.edgewall.org/">
185          </span>
186        </div>""")
187        self.assertEqual("""<div>
188          <span>
189          </span>
190        </div>""", str(tmpl.generate()))
191
192    def test_latin1_encoded_with_xmldecl(self):
193        tmpl = MarkupTemplate(u"""<?xml version="1.0" encoding="iso-8859-1" ?>
194        <div xmlns:py="http://genshi.edgewall.org/">
195          \xf6
196        </div>""".encode('iso-8859-1'), encoding='iso-8859-1')
197        self.assertEqual(u"""<?xml version="1.0" encoding="iso-8859-1"?>\n<div>
198          \xf6
199        </div>""", unicode(tmpl.generate()))
200
201    def test_latin1_encoded_explicit_encoding(self):
202        tmpl = MarkupTemplate(u"""<div xmlns:py="http://genshi.edgewall.org/">
203          \xf6
204        </div>""".encode('iso-8859-1'), encoding='iso-8859-1')
205        self.assertEqual(u"""<div>
206          \xf6
207        </div>""", unicode(tmpl.generate()))
208
209    def test_exec_with_trailing_space(self):
210        """
211        Verify that a code block processing instruction with trailing space
212        does not cause a syntax error (see ticket #127).
213        """
214        MarkupTemplate("""<foo>
215          <?python
216            bar = 42
217          ?>
218        </foo>""")
219
220    def test_exec_import(self):
221        tmpl = MarkupTemplate("""<?python from datetime import timedelta ?>
222        <div xmlns:py="http://genshi.edgewall.org/">
223          ${timedelta(days=2)}
224        </div>""")
225        self.assertEqual("""<div>
226          2 days, 0:00:00
227        </div>""", str(tmpl.generate()))
228
229    def test_exec_def(self):
230        tmpl = MarkupTemplate("""
231        <?python
232        def foo():
233            return 42
234        ?>
235        <div xmlns:py="http://genshi.edgewall.org/">
236          ${foo()}
237        </div>""")
238        self.assertEqual("""<div>
239          42
240        </div>""", str(tmpl.generate()))
241
242    def test_namespace_on_removed_elem(self):
243        """
244        Verify that a namespace declaration on an element that is removed from
245        the generated stream does not get pushed up to the next non-stripped
246        element (see ticket #107).
247        """
248        tmpl = MarkupTemplate("""<?xml version="1.0"?>
249        <Test xmlns:py="http://genshi.edgewall.org/">
250          <Size py:if="0" xmlns:t="test">Size</Size>
251          <Item/>
252        </Test>""")
253        self.assertEqual("""<?xml version="1.0"?>\n<Test>
254         
255          <Item/>
256        </Test>""", str(tmpl.generate()))
257
258    def test_include_in_loop(self):
259        dirname = tempfile.mkdtemp(suffix='genshi_test')
260        try:
261            file1 = open(os.path.join(dirname, 'tmpl1.html'), 'w')
262            try:
263                file1.write("""<div>Included $idx</div>""")
264            finally:
265                file1.close()
266
267            file2 = open(os.path.join(dirname, 'tmpl2.html'), 'w')
268            try:
269                file2.write("""<html xmlns:xi="http://www.w3.org/2001/XInclude"
270                                     xmlns:py="http://genshi.edgewall.org/">
271                  <xi:include href="${name}.html" py:for="idx in range(3)" />
272                </html>""")
273            finally:
274                file2.close()
275
276            loader = TemplateLoader([dirname])
277            tmpl = loader.load('tmpl2.html')
278            self.assertEqual("""<html>
279                  <div>Included 0</div><div>Included 1</div><div>Included 2</div>
280                </html>""", tmpl.generate(name='tmpl1').render(encoding=None))
281        finally:
282            shutil.rmtree(dirname)
283
284    def test_dynamic_include_href(self):
285        dirname = tempfile.mkdtemp(suffix='genshi_test')
286        try:
287            file1 = open(os.path.join(dirname, 'tmpl1.html'), 'w')
288            try:
289                file1.write("""<div>Included</div>""")
290            finally:
291                file1.close()
292
293            file2 = open(os.path.join(dirname, 'tmpl2.html'), 'w')
294            try:
295                file2.write("""<html xmlns:xi="http://www.w3.org/2001/XInclude"
296                                     xmlns:py="http://genshi.edgewall.org/">
297                  <xi:include href="${name}.html" />
298                </html>""")
299            finally:
300                file2.close()
301
302            loader = TemplateLoader([dirname])
303            tmpl = loader.load('tmpl2.html')
304            self.assertEqual("""<html>
305                  <div>Included</div>
306                </html>""", tmpl.generate(name='tmpl1').render(encoding=None))
307        finally:
308            shutil.rmtree(dirname)
309
310    def test_select_included_elements(self):
311        dirname = tempfile.mkdtemp(suffix='genshi_test')
312        try:
313            file1 = open(os.path.join(dirname, 'tmpl1.html'), 'w')
314            try:
315                file1.write("""<li>$item</li>""")
316            finally:
317                file1.close()
318
319            file2 = open(os.path.join(dirname, 'tmpl2.html'), 'w')
320            try:
321                file2.write("""<html xmlns:xi="http://www.w3.org/2001/XInclude"
322                                     xmlns:py="http://genshi.edgewall.org/">
323                  <ul py:match="ul">${select('li')}</ul>
324                  <ul py:with="items=(1, 2, 3)">
325                    <xi:include href="tmpl1.html" py:for="item in items" />
326                  </ul>
327                </html>""")
328            finally:
329                file2.close()
330
331            loader = TemplateLoader([dirname])
332            tmpl = loader.load('tmpl2.html')
333            self.assertEqual("""<html>
334                  <ul><li>1</li><li>2</li><li>3</li></ul>
335                </html>""", tmpl.generate().render(encoding=None))
336        finally:
337            shutil.rmtree(dirname)
338
339    def test_fallback_when_include_found(self):
340        dirname = tempfile.mkdtemp(suffix='genshi_test')
341        try:
342            file1 = open(os.path.join(dirname, 'tmpl1.html'), 'w')
343            try:
344                file1.write("""<div>Included</div>""")
345            finally:
346                file1.close()
347
348            file2 = open(os.path.join(dirname, 'tmpl2.html'), 'w')
349            try:
350                file2.write("""<html xmlns:xi="http://www.w3.org/2001/XInclude">
351                  <xi:include href="tmpl1.html"><xi:fallback>
352                    Missing</xi:fallback></xi:include>
353                </html>""")
354            finally:
355                file2.close()
356
357            loader = TemplateLoader([dirname])
358            tmpl = loader.load('tmpl2.html')
359            self.assertEqual("""<html>
360                  <div>Included</div>
361                </html>""", tmpl.generate().render(encoding=None))
362        finally:
363            shutil.rmtree(dirname)
364
365    def test_error_when_include_not_found(self):
366        dirname = tempfile.mkdtemp(suffix='genshi_test')
367        try:
368            file2 = open(os.path.join(dirname, 'tmpl2.html'), 'w')
369            try:
370                file2.write("""<html xmlns:xi="http://www.w3.org/2001/XInclude">
371                  <xi:include href="tmpl1.html"/>
372                </html>""")
373            finally:
374                file2.close()
375
376            loader = TemplateLoader([dirname], auto_reload=True)
377            tmpl = loader.load('tmpl2.html')
378            self.assertRaises(TemplateNotFound, tmpl.generate().render)
379        finally:
380            shutil.rmtree(dirname)
381
382    def test_fallback_when_include_not_found(self):
383        dirname = tempfile.mkdtemp(suffix='genshi_test')
384        try:
385            file2 = open(os.path.join(dirname, 'tmpl2.html'), 'w')
386            try:
387                file2.write("""<html xmlns:xi="http://www.w3.org/2001/XInclude">
388                  <xi:include href="tmpl1.html"><xi:fallback>
389                  Missing</xi:fallback></xi:include>
390                </html>""")
391            finally:
392                file2.close()
393
394            loader = TemplateLoader([dirname])
395            tmpl = loader.load('tmpl2.html')
396            self.assertEqual("""<html>
397                  Missing
398                </html>""", tmpl.generate().render(encoding=None))
399        finally:
400            shutil.rmtree(dirname)
401
402    def test_fallback_when_auto_reload_true(self):
403        dirname = tempfile.mkdtemp(suffix='genshi_test')
404        try:
405            file2 = open(os.path.join(dirname, 'tmpl2.html'), 'w')
406            try:
407                file2.write("""<html xmlns:xi="http://www.w3.org/2001/XInclude">
408                  <xi:include href="tmpl1.html"><xi:fallback>
409                    Missing</xi:fallback></xi:include>
410                </html>""")
411            finally:
412                file2.close()
413
414            loader = TemplateLoader([dirname], auto_reload=True)
415            tmpl = loader.load('tmpl2.html')
416            self.assertEqual("""<html>
417                    Missing
418                </html>""", tmpl.generate().render(encoding=None))
419        finally:
420            shutil.rmtree(dirname)
421
422    def test_include_in_fallback(self):
423        dirname = tempfile.mkdtemp(suffix='genshi_test')
424        try:
425            file1 = open(os.path.join(dirname, 'tmpl1.html'), 'w')
426            try:
427                file1.write("""<div>Included</div>""")
428            finally:
429                file1.close()
430
431            file2 = open(os.path.join(dirname, 'tmpl3.html'), 'w')
432            try:
433                file2.write("""<html xmlns:xi="http://www.w3.org/2001/XInclude">
434                  <xi:include href="tmpl2.html">
435                    <xi:fallback>
436                      <xi:include href="tmpl1.html">
437                        <xi:fallback>Missing</xi:fallback>
438                      </xi:include>
439                    </xi:fallback>
440                  </xi:include>
441                </html>""")
442            finally:
443                file2.close()
444
445            loader = TemplateLoader([dirname])
446            tmpl = loader.load('tmpl3.html')
447            self.assertEqual("""<html>
448                      <div>Included</div>
449                </html>""", tmpl.generate().render(encoding=None))
450        finally:
451            shutil.rmtree(dirname)
452
453    def test_nested_include_fallback(self):
454        dirname = tempfile.mkdtemp(suffix='genshi_test')
455        try:
456            file2 = open(os.path.join(dirname, 'tmpl3.html'), 'w')
457            try:
458                file2.write("""<html xmlns:xi="http://www.w3.org/2001/XInclude">
459                  <xi:include href="tmpl2.html">
460                    <xi:fallback>
461                      <xi:include href="tmpl1.html">
462                        <xi:fallback>Missing</xi:fallback>
463                      </xi:include>
464                    </xi:fallback>
465                  </xi:include>
466                </html>""")
467            finally:
468                file2.close()
469
470            loader = TemplateLoader([dirname])
471            tmpl = loader.load('tmpl3.html')
472            self.assertEqual("""<html>
473                      Missing
474                </html>""", tmpl.generate().render(encoding=None))
475        finally:
476            shutil.rmtree(dirname)
477
478    def test_nested_include_in_fallback(self):
479        dirname = tempfile.mkdtemp(suffix='genshi_test')
480        try:
481            file1 = open(os.path.join(dirname, 'tmpl2.html'), 'w')
482            try:
483                file1.write("""<div>Included</div>""")
484            finally:
485                file1.close()
486
487            file2 = open(os.path.join(dirname, 'tmpl3.html'), 'w')
488            try:
489                file2.write("""<html xmlns:xi="http://www.w3.org/2001/XInclude">
490                  <xi:include href="tmpl2.html">
491                    <xi:fallback>
492                      <xi:include href="tmpl1.html" />
493                    </xi:fallback>
494                  </xi:include>
495                </html>""")
496            finally:
497                file2.close()
498
499            loader = TemplateLoader([dirname])
500            tmpl = loader.load('tmpl3.html')
501            self.assertEqual("""<html>
502                  <div>Included</div>
503                </html>""", tmpl.generate().render(encoding=None))
504        finally:
505            shutil.rmtree(dirname)
506
507    def test_include_fallback_with_directive(self):
508        dirname = tempfile.mkdtemp(suffix='genshi_test')
509        try:
510            file2 = open(os.path.join(dirname, 'tmpl2.html'), 'w')
511            try:
512                file2.write("""<html xmlns:xi="http://www.w3.org/2001/XInclude"
513                      xmlns:py="http://genshi.edgewall.org/">
514                  <xi:include href="tmpl1.html"><xi:fallback>
515                    <py:if test="True">tmpl1.html not found</py:if>
516                  </xi:fallback></xi:include>
517                </html>""")
518            finally:
519                file2.close()
520
521            loader = TemplateLoader([dirname])
522            tmpl = loader.load('tmpl2.html')
523            self.assertEqual("""<html>
524                    tmpl1.html not found
525                </html>""", tmpl.generate(debug=True).render(encoding=None))
526        finally:
527            shutil.rmtree(dirname)
528
529    def test_include_inlined(self):
530        dirname = tempfile.mkdtemp(suffix='genshi_test')
531        try:
532            file1 = open(os.path.join(dirname, 'tmpl1.html'), 'w')
533            try:
534                file1.write("""<div>Included</div>""")
535            finally:
536                file1.close()
537
538            file2 = open(os.path.join(dirname, 'tmpl2.html'), 'w')
539            try:
540                file2.write("""<html xmlns:xi="http://www.w3.org/2001/XInclude"
541                                     xmlns:py="http://genshi.edgewall.org/">
542                  <xi:include href="tmpl1.html" />
543                </html>""")
544            finally:
545                file2.close()
546
547            loader = TemplateLoader([dirname], auto_reload=False)
548            tmpl = loader.load('tmpl2.html')
549            # if not inlined the following would be 5
550            self.assertEqual(7, len(tmpl.stream))
551            self.assertEqual("""<html>
552                  <div>Included</div>
553                </html>""", tmpl.generate().render(encoding=None))
554        finally:
555            shutil.rmtree(dirname)
556
557    def test_include_inlined_in_loop(self):
558        dirname = tempfile.mkdtemp(suffix='genshi_test')
559        try:
560            file1 = open(os.path.join(dirname, 'tmpl1.html'), 'w')
561            try:
562                file1.write("""<div>Included $idx</div>""")
563            finally:
564                file1.close()
565
566            file2 = open(os.path.join(dirname, 'tmpl2.html'), 'w')
567            try:
568                file2.write("""<html xmlns:xi="http://www.w3.org/2001/XInclude"
569                                     xmlns:py="http://genshi.edgewall.org/">
570                  <xi:include href="tmpl1.html" py:for="idx in range(3)" />
571                </html>""")
572            finally:
573                file2.close()
574
575            loader = TemplateLoader([dirname], auto_reload=False)
576            tmpl = loader.load('tmpl2.html')
577            self.assertEqual("""<html>
578                  <div>Included 0</div><div>Included 1</div><div>Included 2</div>
579                </html>""", tmpl.generate().render(encoding=None))
580        finally:
581            shutil.rmtree(dirname)
582
583    def test_include_inline_recursive(self):
584        dirname = tempfile.mkdtemp(suffix='genshi_test')
585        try:
586            file1 = open(os.path.join(dirname, 'tmpl1.html'), 'w')
587            try:
588                file1.write(
589                    '<div xmlns:xi="http://www.w3.org/2001/XInclude"'
590                    '                xmlns:py="http://genshi.edgewall.org/">'
591                    '$depth'
592                    '<py:with vars="depth = depth + 1">'
593                    '<xi:include href="tmpl1.html"'
594                    '            py:if="depth &lt; 3"/>'
595                    '</py:with>'
596                    '</div>'
597                )
598            finally:
599                file1.close()
600
601            loader = TemplateLoader([dirname], auto_reload=False)
602            tmpl = loader.load(os.path.join(dirname, 'tmpl1.html'))
603            self.assertEqual(
604                "<div>0<div>1<div>2</div></div></div>",
605                tmpl.generate(depth=0).render(encoding=None))
606        finally:
607            shutil.rmtree(dirname)
608
609    def test_allow_exec_false(self):
610        xml = ("""<?python
611          title = "A Genshi Template"
612          ?>
613          <html xmlns:py="http://genshi.edgewall.org/">
614            <head>
615              <title py:content="title">This is replaced.</title>
616            </head>
617        </html>""")
618        try:
619            tmpl = MarkupTemplate(xml, filename='test.html',
620                                  allow_exec=False)
621            self.fail('Expected SyntaxError')
622        except TemplateSyntaxError, e:
623            pass
624
625    def test_allow_exec_true(self): 
626        xml = ("""<?python
627          title = "A Genshi Template"
628          ?>
629          <html xmlns:py="http://genshi.edgewall.org/">
630            <head>
631              <title py:content="title">This is replaced.</title>
632            </head>
633        </html>""")
634        tmpl = MarkupTemplate(xml, filename='test.html', allow_exec=True)
635
636    def test_exec_in_match(self): 
637        xml = ("""<html xmlns:py="http://genshi.edgewall.org/">
638          <py:match path="body/p">
639            <?python title="wakka wakka wakka" ?>
640            ${title}
641          </py:match>
642          <body><p>moot text</p></body>
643        </html>""")
644        tmpl = MarkupTemplate(xml, filename='test.html', allow_exec=True)
645        self.assertEqual("""<html>
646          <body>
647            wakka wakka wakka
648          </body>
649        </html>""", tmpl.generate().render(encoding=None))
650
651    def test_with_in_match(self): 
652        xml = ("""<html xmlns:py="http://genshi.edgewall.org/">
653          <py:match path="body/p">
654            <h1>${select('text()')}</h1>
655            ${select('.')}
656          </py:match>
657          <body><p py:with="foo='bar'">${foo}</p></body>
658        </html>""")
659        tmpl = MarkupTemplate(xml, filename='test.html')
660        self.assertEqual("""<html>
661          <body>
662            <h1>bar</h1>
663            <p>bar</p>
664          </body>
665        </html>""", tmpl.generate().render(encoding=None))
666
667    def test_nested_include_matches(self):
668        # See ticket #157
669        dirname = tempfile.mkdtemp(suffix='genshi_test')
670        try:
671            file1 = open(os.path.join(dirname, 'tmpl1.html'), 'w')
672            try:
673                file1.write("""<html xmlns:py="http://genshi.edgewall.org/" py:strip="">
674   <div class="target">Some content.</div>
675</html>""")
676            finally:
677                file1.close()
678
679            file2 = open(os.path.join(dirname, 'tmpl2.html'), 'w')
680            try:
681                file2.write("""<html xmlns:py="http://genshi.edgewall.org/"
682    xmlns:xi="http://www.w3.org/2001/XInclude">
683  <body>
684    <h1>Some full html document that includes file1.html</h1>
685    <xi:include href="tmpl1.html" />
686  </body>
687</html>""")
688            finally:
689                file2.close()
690
691            file3 = open(os.path.join(dirname, 'tmpl3.html'), 'w')
692            try:
693                file3.write("""<html xmlns:py="http://genshi.edgewall.org/"
694    xmlns:xi="http://www.w3.org/2001/XInclude" py:strip="">
695  <div py:match="div[@class='target']" py:attrs="select('@*')">
696    Some added stuff.
697    ${select('*|text()')}
698  </div>
699  <xi:include href="tmpl2.html" />
700</html>
701""")
702            finally:
703                file3.close()
704
705            loader = TemplateLoader([dirname])
706            tmpl = loader.load('tmpl3.html')
707            self.assertEqual("""
708  <html>
709  <body>
710    <h1>Some full html document that includes file1.html</h1>
711   <div class="target">
712    Some added stuff.
713    Some content.
714  </div>
715  </body>
716</html>
717""", tmpl.generate().render(encoding=None))
718        finally:
719            shutil.rmtree(dirname)
720
721    def test_nested_matches_without_buffering(self):
722        xml = ("""<html xmlns:py="http://genshi.edgewall.org/">
723          <py:match path="body" once="true" buffer="false">
724            <body>
725              ${select('*|text')}
726              And some other stuff...
727            </body>
728          </py:match>
729          <body>
730            <span py:match="span">Foo</span>
731            <span>Bar</span>
732          </body>
733        </html>""")
734        tmpl = MarkupTemplate(xml, filename='test.html')
735        self.assertEqual("""<html>
736            <body>
737              <span>Foo</span>
738              And some other stuff...
739            </body>
740        </html>""", tmpl.generate().render(encoding=None))
741
742    def test_match_without_select(self):
743        # See <http://genshi.edgewall.org/ticket/243>
744        xml = ("""<html xmlns:py="http://genshi.edgewall.org/">
745          <py:match path="body" buffer="false">
746            <body>
747              This replaces the other text.
748            </body>
749          </py:match>
750          <body>
751            This gets replaced.
752          </body>
753        </html>""")
754        tmpl = MarkupTemplate(xml, filename='test.html')
755        self.assertEqual("""<html>
756            <body>
757              This replaces the other text.
758            </body>
759        </html>""", tmpl.generate().render(encoding=None))
760
761    def test_match_tail_handling(self): 
762        # See <http://genshi.edgewall.org/ticket/399>
763        xml = ("""<rhyme xmlns:py="http://genshi.edgewall.org/">
764          <py:match path="*[@type]">
765            ${select('.')}
766          </py:match>
767
768          <lines>
769            <first type="one">fish</first>
770            <second type="two">fish</second>
771            <third type="red">fish</third>
772            <fourth type="blue">fish</fourth>
773          </lines>
774        </rhyme>""") 
775        tmpl = MarkupTemplate(xml, filename='test.html') 
776        self.assertEqual("""<rhyme>
777          <lines>
778            <first type="one">fish</first>
779            <second type="two">fish</second>
780            <third type="red">fish</third>
781            <fourth type="blue">fish</fourth>
782          </lines>
783        </rhyme>""", tmpl.generate().render(encoding=None)) 
784
785
786def suite():
787    suite = unittest.TestSuite()
788    suite.addTest(doctest.DocTestSuite(MarkupTemplate.__module__))
789    suite.addTest(unittest.makeSuite(MarkupTemplateTestCase, 'test'))
790    return suite
791
792if __name__ == '__main__':
793    unittest.main(defaultTest='suite')
Note: See TracBrowser for help on using the repository browser.