# -*- coding: utf-8 -*- # # Copyright (C) 2006-2010 Edgewall Software # All rights reserved. # # This software is licensed as described in the file COPYING, which # you should have received as part of this distribution. The terms # are also available at http://genshi.edgewall.org/wiki/License. # # This software consists of voluntary contributions made by many # individuals. For the exact contribution history, see the revision # history and logs, available at http://genshi.edgewall.org/log/. import doctest import re import sys import unittest from genshi.compat import IS_PYTHON2 from genshi.template import directives, MarkupTemplate, TextTemplate, \ TemplateRuntimeError, TemplateSyntaxError class AttrsDirectiveTestCase(unittest.TestCase): """Tests for the `py:attrs` template directive.""" def test_combined_with_loop(self): """ Verify that the directive has access to the loop variables. """ tmpl = MarkupTemplate(""" """) items = [{'id': 1}, {'id': 2}] self.assertEqual(""" """, tmpl.generate(items=items).render(encoding=None)) def test_update_existing_attr(self): """ Verify that an attribute value that evaluates to `None` removes an existing attribute of that name. """ tmpl = MarkupTemplate(""" """) self.assertEqual(""" """, tmpl.generate().render(encoding=None)) def test_remove_existing_attr(self): """ Verify that an attribute value that evaluates to `None` removes an existing attribute of that name. """ tmpl = MarkupTemplate(""" """) self.assertEqual(""" """, tmpl.generate().render(encoding=None)) class ChooseDirectiveTestCase(unittest.TestCase): """Tests for the `py:choose` template directive and the complementary directives `py:when` and `py:otherwise`.""" def test_multiple_true_whens(self): """ Verify that, if multiple `py:when` bodies match, only the first is output. """ tmpl = MarkupTemplate("""
1 2 3
""") self.assertEqual("""
1
""", tmpl.generate().render(encoding=None)) def test_otherwise(self): tmpl = MarkupTemplate("""
hidden hello
""") self.assertEqual("""
hello
""", tmpl.generate().render(encoding=None)) def test_nesting(self): """ Verify that `py:choose` blocks can be nested: """ tmpl = MarkupTemplate("""
2 3
""") self.assertEqual("""
3
""", tmpl.generate().render(encoding=None)) def test_complex_nesting(self): """ Verify more complex nesting. """ tmpl = MarkupTemplate("""
OK FAIL
""") self.assertEqual("""
OK
""", tmpl.generate().render(encoding=None)) def test_complex_nesting_otherwise(self): """ Verify more complex nesting using otherwise. """ tmpl = MarkupTemplate("""
FAIL OK
""") self.assertEqual("""
OK
""", tmpl.generate().render(encoding=None)) def test_when_with_strip(self): """ Verify that a when directive with a strip directive actually strips of the outer element. """ tmpl = MarkupTemplate("""
foo
""") self.assertEqual(""" foo """, tmpl.generate().render(encoding=None)) def test_when_outside_choose(self): """ Verify that a `when` directive outside of a `choose` directive is reported as an error. """ tmpl = MarkupTemplate("""
""") self.assertRaises(TemplateRuntimeError, str, tmpl.generate()) def test_otherwise_outside_choose(self): """ Verify that an `otherwise` directive outside of a `choose` directive is reported as an error. """ tmpl = MarkupTemplate("""
""") self.assertRaises(TemplateRuntimeError, str, tmpl.generate()) def test_when_without_test(self): """ Verify that an `when` directive that doesn't have a `test` attribute is reported as an error. """ tmpl = MarkupTemplate("""
foo
""") self.assertRaises(TemplateRuntimeError, str, tmpl.generate()) def test_when_without_test_but_with_choose_value(self): """ Verify that an `when` directive that doesn't have a `test` attribute works as expected as long as the parent `choose` directive has a test expression. """ tmpl = MarkupTemplate("""
foo
""") self.assertEqual(""" foo """, tmpl.generate(foo='Yeah').render(encoding=None)) def test_otherwise_without_test(self): """ Verify that an `otherwise` directive can be used without a `test` attribute. """ tmpl = MarkupTemplate("""
foo
""") self.assertEqual(""" foo """, tmpl.generate().render(encoding=None)) def test_as_element(self): """ Verify that the directive can also be used as an element. """ tmpl = MarkupTemplate(""" 1 2 3 """) self.assertEqual(""" 1 """, tmpl.generate().render(encoding=None)) def test_in_text_template(self): """ Verify that the directive works as expected in a text template. """ tmpl = TextTemplate("""#choose #when 1 == 1 1 #end #when 2 == 2 2 #end #when 3 == 3 3 #end #end""") self.assertEqual(""" 1\n""", tmpl.generate().render(encoding=None)) class DefDirectiveTestCase(unittest.TestCase): """Tests for the `py:def` template directive.""" def test_function_with_strip(self): """ Verify that a named template function with a strip directive actually strips of the outer element. """ tmpl = MarkupTemplate("""
${what}
${echo('foo')}
""") self.assertEqual(""" foo """, tmpl.generate().render(encoding=None)) def test_exec_in_replace(self): tmpl = MarkupTemplate("""

${greeting}, ${name}!

""") self.assertEqual("""

hello, world!

""", tmpl.generate().render(encoding=None)) def test_as_element(self): """ Verify that the directive can also be used as an element. """ tmpl = MarkupTemplate(""" ${what} ${echo('foo')} """) self.assertEqual(""" foo """, tmpl.generate().render(encoding=None)) def test_nested_defs(self): """ Verify that a template function defined inside a conditional block can be called from outside that block. """ tmpl = MarkupTemplate(""" ${what} ${what} ${echo('foo')} """) self.assertEqual(""" foo """, tmpl.generate(semantic=True).render(encoding=None)) def test_function_with_default_arg(self): """ Verify that keyword arguments work with `py:def` directives. """ tmpl = MarkupTemplate(""" ${what} ${echo('foo')} """) self.assertEqual(""" foo """, tmpl.generate().render(encoding=None)) def test_invocation_in_attribute(self): tmpl = MarkupTemplate(""" ${what or 'something'}

bar

""") self.assertEqual("""

bar

""", tmpl.generate().render(encoding=None)) def test_invocation_in_attribute_none(self): tmpl = MarkupTemplate(""" ${None}

bar

""") self.assertEqual("""

bar

""", tmpl.generate().render(encoding=None)) def test_function_raising_typeerror(self): def badfunc(): raise TypeError tmpl = MarkupTemplate("""
${badfunc()}
""") self.assertRaises(TypeError, list, tmpl.generate(badfunc=badfunc)) def test_def_in_matched(self): tmpl = MarkupTemplate(""" ${select('*')} ${maketitle(True)} """) self.assertEqual(""" True """, tmpl.generate().render(encoding=None)) def test_in_text_template(self): """ Verify that the directive works as expected in a text template. """ tmpl = TextTemplate(""" #def echo(greeting, name='world') ${greeting}, ${name}! #end ${echo('Hi', name='you')} """) self.assertEqual(""" Hi, you! """, tmpl.generate().render(encoding=None)) def test_function_with_star_args(self): """ Verify that a named template function using "star arguments" works as expected. """ tmpl = MarkupTemplate("""
${repr(args)} ${repr(sorted(kwargs.items()))}
${f(1, 2, a=3, b=4)}
""") self.assertEqual("""
[1, 2] [('a', 3), ('b', 4)]
""", tmpl.generate().render(encoding=None)) class ForDirectiveTestCase(unittest.TestCase): """Tests for the `py:for` template directive.""" def test_loop_with_strip(self): """ Verify that the combining the `py:for` directive with `py:strip` works correctly. """ tmpl = MarkupTemplate("""
${item}
""") self.assertEqual(""" 1 2 3 4 5 """, tmpl.generate(items=range(1, 6)).render(encoding=None)) def test_as_element(self): """ Verify that the directive can also be used as an element. """ tmpl = MarkupTemplate(""" ${item} """) self.assertEqual(""" 1 2 3 4 5 """, tmpl.generate(items=range(1, 6)).render(encoding=None)) def test_multi_assignment(self): """ Verify that assignment to tuples works correctly. """ tmpl = MarkupTemplate("""

key=$k, value=$v

""") self.assertEqual("""

key=a, value=1

key=b, value=2

""", tmpl.generate(items=(('a', 1), ('b', 2))) .render(encoding=None)) def test_nested_assignment(self): """ Verify that assignment to nested tuples works correctly. """ tmpl = MarkupTemplate("""

$idx: key=$k, value=$v

""") self.assertEqual("""

0: key=a, value=1

1: key=b, value=2

""", tmpl.generate(items=enumerate([('a', 1), ('b', 2)])) .render(encoding=None)) def test_not_iterable(self): """ Verify that assignment to nested tuples works correctly. """ tmpl = MarkupTemplate(""" $item """, filename='test.html') try: list(tmpl.generate(foo=12)) self.fail('Expected TemplateRuntimeError') except TypeError as e: assert (str(e) == "iteration over non-sequence" or str(e) == "'int' object is not iterable") exc_type, exc_value, exc_traceback = sys.exc_info() frame = exc_traceback.tb_next frames = [] while frame.tb_next: frame = frame.tb_next frames.append(frame) expected_iter_str = "u'iter(foo)'" if IS_PYTHON2 else "'iter(foo)'" self.assertEqual("" % expected_iter_str, frames[-1].tb_frame.f_code.co_name) self.assertEqual('test.html', frames[-1].tb_frame.f_code.co_filename) self.assertEqual(2, frames[-1].tb_lineno) def test_for_with_empty_value(self): """ Verify an empty 'for' value is an error """ try: MarkupTemplate(""" empty """, filename='test.html').generate() self.fail('ExpectedTemplateSyntaxError') except TemplateSyntaxError as e: self.assertEqual('test.html', e.filename) if sys.version_info[:2] > (2,4): self.assertEqual(2, e.lineno) class IfDirectiveTestCase(unittest.TestCase): """Tests for the `py:if` template directive.""" def test_loop_with_strip(self): """ Verify that the combining the `py:if` directive with `py:strip` works correctly. """ tmpl = MarkupTemplate(""" ${bar} """) self.assertEqual(""" Hello """, tmpl.generate(foo=True, bar='Hello').render(encoding=None)) def test_as_element(self): """ Verify that the directive can also be used as an element. """ tmpl = MarkupTemplate(""" ${bar} """) self.assertEqual(""" Hello """, tmpl.generate(foo=True, bar='Hello').render(encoding=None)) class MatchDirectiveTestCase(unittest.TestCase): """Tests for the `py:match` template directive.""" def test_with_strip(self): """ Verify that a match template can produce the same kind of element that it matched without entering an infinite recursion. """ tmpl = MarkupTemplate("""
${select('text()')}
Hey Joe
""") self.assertEqual("""
Hey Joe
""", tmpl.generate().render(encoding=None)) def test_without_strip(self): """ Verify that a match template can produce the same kind of element that it matched without entering an infinite recursion. """ tmpl = MarkupTemplate("""
${select('text()')}
Hey Joe
""") self.assertEqual("""
Hey Joe
""", tmpl.generate().render(encoding=None)) def test_as_element(self): """ Verify that the directive can also be used as an element. """ tmpl = MarkupTemplate("""
${select('text()')}
Hey Joe
""") self.assertEqual("""
Hey Joe
""", tmpl.generate().render(encoding=None)) def test_recursive_match_1(self): """ Match directives are applied recursively, meaning that they are also applied to any content they may have produced themselves: """ tmpl = MarkupTemplate("""
${select('*')}
""") self.assertEqual("""
""", tmpl.generate().render(encoding=None)) def test_recursive_match_2(self): """ When two or more match templates match the same element and also themselves output the element they match, avoiding recursion is even more complex, but should work. """ tmpl = MarkupTemplate("""