diff options
Diffstat (limited to 'test/test_template.py')
-rw-r--r-- | test/test_template.py | 1669 |
1 files changed, 1669 insertions, 0 deletions
diff --git a/test/test_template.py b/test/test_template.py new file mode 100644 index 0000000..62fd21d --- /dev/null +++ b/test/test_template.py @@ -0,0 +1,1669 @@ +import os + +from mako import exceptions +from mako import runtime +from mako import util +from mako.ext.preprocessors import convert_comments +from mako.lookup import TemplateLookup +from mako.template import ModuleInfo +from mako.template import ModuleTemplate +from mako.template import Template +from mako.testing.assertions import assert_raises +from mako.testing.assertions import assert_raises_message +from mako.testing.assertions import eq_ +from mako.testing.config import config +from mako.testing.fixtures import TemplateTest +from mako.testing.helpers import flatten_result +from mako.testing.helpers import result_lines + + +class ctx: + def __init__(self, a, b): + pass + + def __enter__(self): + return self + + def __exit__(self, *arg): + pass + + +class MiscTest(TemplateTest): + def test_crlf_linebreaks(self): + crlf = r""" +<% + foo = True + bar = True +%> +% if foo and \ + bar: + foo and bar +%endif +""" + crlf = crlf.replace("\n", "\r\n") + self._do_test(Template(crlf), "\r\n\r\n foo and bar\r\n") + + +class EncodingTest(TemplateTest): + def test_escapes_html_tags(self): + from mako.exceptions import html_error_template + + x = Template( + """ + X: + <% raise Exception('<span style="color:red">Foobar</span>') %> + """ + ) + + try: + x.render() + except: + # <h3>Exception: <span style="color:red">Foobar</span></h3> + markup = html_error_template().render(full=False, css=False) + assert ( + '<span style="color:red">Foobar</span></h3>'.encode("ascii") + not in markup + ) + assert ( + "<span style="color:red"" + ">Foobar</span>".encode("ascii") in markup + ) + + def test_unicode(self): + self._do_memory_test( + ( + "Alors vous imaginez ma surprise, au lever du jour, quand " + "une drôle de petite voix m’a réveillé. Elle disait: " + "« S’il vous plaît… dessine-moi un mouton! »" + ), + ( + "Alors vous imaginez ma surprise, au lever du jour, quand " + "une drôle de petite voix m’a réveillé. Elle disait: " + "« S’il vous plaît… dessine-moi un mouton! »" + ), + ) + + def test_encoding_doesnt_conflict(self): + self._do_memory_test( + ( + "Alors vous imaginez ma surprise, au lever du jour, quand " + "une drôle de petite voix m’a réveillé. Elle disait: " + "« S’il vous plaît… dessine-moi un mouton! »" + ), + ( + "Alors vous imaginez ma surprise, au lever du jour, quand " + "une drôle de petite voix m’a réveillé. Elle disait: " + "« S’il vous plaît… dessine-moi un mouton! »" + ), + output_encoding="utf-8", + ) + + def test_unicode_arg(self): + val = ( + "Alors vous imaginez ma surprise, au lever du jour, quand " + "une drôle de petite voix m’a réveillé. Elle disait: " + "« S’il vous plaît… dessine-moi un mouton! »" + ) + self._do_memory_test( + "${val}", + ( + "Alors vous imaginez ma surprise, au lever du jour, quand " + "une drôle de petite voix m’a réveillé. Elle disait: " + "« S’il vous plaît… dessine-moi un mouton! »" + ), + template_args={"val": val}, + ) + + def test_unicode_file(self): + self._do_file_test( + "unicode.html", + ( + "Alors vous imaginez ma surprise, au lever du jour, quand " + "une drôle de petite voix m’a réveillé. Elle disait: " + "« S’il vous plaît… dessine-moi un mouton! »" + ), + ) + + def test_unicode_file_code(self): + self._do_file_test( + "unicode_code.html", + ("""hi, drôle de petite voix m’a réveillé."""), + filters=flatten_result, + ) + + def test_unicode_file_lookup(self): + lookup = TemplateLookup( + directories=[config.template_base], + output_encoding="utf-8", + default_filters=["decode.utf8"], + ) + template = lookup.get_template("/chs_unicode_py3k.html") + eq_( + flatten_result(template.render_unicode(name="毛泽东")), + ("毛泽东 是 新中国的主席<br/> Welcome 你 to 北京."), + ) + + def test_unicode_bom(self): + self._do_file_test( + "bom.html", + ( + "Alors vous imaginez ma surprise, au lever du jour, quand " + "une drôle de petite voix m’a réveillé. Elle disait: " + "« S’il vous plaît… dessine-moi un mouton! »" + ), + ) + + self._do_file_test( + "bommagic.html", + ( + "Alors vous imaginez ma surprise, au lever du jour, quand " + "une drôle de petite voix m’a réveillé. Elle disait: " + "« S’il vous plaît… dessine-moi un mouton! »" + ), + ) + + assert_raises( + exceptions.CompileException, + Template, + filename=self._file_path("badbom.html"), + module_directory=config.module_base, + ) + + def test_unicode_memory(self): + val = ( + "Alors vous imaginez ma surprise, au lever du jour, quand " + "une drôle de petite voix m’a réveillé. Elle disait: " + "« S’il vous plaît… dessine-moi un mouton! »" + ) + self._do_memory_test( + ("## -*- coding: utf-8 -*-\n" + val).encode("utf-8"), + ( + "Alors vous imaginez ma surprise, au lever du jour, quand " + "une drôle de petite voix m’a réveillé. Elle disait: " + "« S’il vous plaît… dessine-moi un mouton! »" + ), + ) + + def test_unicode_text(self): + val = ( + "<%text>Alors vous imaginez ma surprise, au lever du jour, quand " + "une drôle de petite voix m’a réveillé. Elle disait: " + "« S’il vous plaît… dessine-moi un mouton! »</%text>" + ) + self._do_memory_test( + ("## -*- coding: utf-8 -*-\n" + val).encode("utf-8"), + ( + "Alors vous imaginez ma surprise, au lever du jour, quand " + "une drôle de petite voix m’a réveillé. Elle disait: " + "« S’il vous plaît… dessine-moi un mouton! »" + ), + ) + + def test_unicode_text_ccall(self): + val = """ + <%def name="foo()"> + ${capture(caller.body)} + </%def> + <%call expr="foo()"> + <%text>Alors vous imaginez ma surprise, au lever du jour, +quand une drôle de petite voix m’a réveillé. Elle disait: +« S’il vous plaît… dessine-moi un mouton! »</%text> + </%call>""" + self._do_memory_test( + ("## -*- coding: utf-8 -*-\n" + val).encode("utf-8"), + ( + "Alors vous imaginez ma surprise, au lever du jour, quand " + "une drôle de petite voix m’a réveillé. Elle disait: " + "« S’il vous plaît… dessine-moi un mouton! »" + ), + filters=flatten_result, + ) + + def test_unicode_literal_in_expr(self): + self._do_memory_test( + ( + "## -*- coding: utf-8 -*-\n" + '${"Alors vous imaginez ma surprise, au lever du jour, ' + "quand une drôle de petite voix m’a réveillé. " + "Elle disait: " + '« S’il vous plaît… dessine-moi un mouton! »"}\n' + ).encode("utf-8"), + ( + "Alors vous imaginez ma surprise, au lever du jour, " + "quand une drôle de petite voix m’a réveillé. " + "Elle disait: « S’il vous plaît… dessine-moi un mouton! »" + ), + filters=lambda s: s.strip(), + ) + + def test_unicode_literal_in_expr_file(self): + self._do_file_test( + "unicode_expr.html", + ( + "Alors vous imaginez ma surprise, au lever du jour, " + "quand une drôle de petite voix m’a réveillé. " + "Elle disait: « S’il vous plaît… dessine-moi un mouton! »" + ), + lambda t: t.strip(), + ) + + def test_unicode_literal_in_code(self): + self._do_memory_test( + ( + """## -*- coding: utf-8 -*- + <% + context.write("Alors vous imaginez ma surprise, au """ + """lever du jour, quand une drôle de petite voix m’a """ + """réveillé. Elle disait: """ + """« S’il vous plaît… dessine-moi un mouton! »") + %> + """ + ).encode("utf-8"), + ( + "Alors vous imaginez ma surprise, au lever du jour, " + "quand une drôle de petite voix m’a réveillé. " + "Elle disait: « S’il vous plaît… dessine-moi un mouton! »" + ), + filters=lambda s: s.strip(), + ) + + def test_unicode_literal_in_controlline(self): + self._do_memory_test( + ( + """## -*- coding: utf-8 -*- + <% + x = "drôle de petite voix m’a réveillé." + %> + % if x=="drôle de petite voix m’a réveillé.": + hi, ${x} + % endif + """ + ).encode("utf-8"), + ("""hi, drôle de petite voix m’a réveillé."""), + filters=lambda s: s.strip(), + ) + + def test_unicode_literal_in_tag(self): + self._do_file_test( + "unicode_arguments.html", + [ + ("x is: drôle de petite voix m’a réveillé"), + ("x is: drôle de petite voix m’a réveillé"), + ("x is: drôle de petite voix m’a réveillé"), + ("x is: drôle de petite voix m’a réveillé"), + ], + filters=result_lines, + ) + + self._do_memory_test( + util.read_file(self._file_path("unicode_arguments.html")), + [ + ("x is: drôle de petite voix m’a réveillé"), + ("x is: drôle de petite voix m’a réveillé"), + ("x is: drôle de petite voix m’a réveillé"), + ("x is: drôle de petite voix m’a réveillé"), + ], + filters=result_lines, + ) + + def test_unicode_literal_in_def(self): + self._do_memory_test( + ( + """## -*- coding: utf-8 -*- + <%def name="bello(foo, bar)"> + Foo: ${ foo } + Bar: ${ bar } + </%def> + <%call expr="bello(foo='árvíztűrő tükörfúrógép', """ + """bar='ÁRVÍZTŰRŐ TÜKÖRFÚRÓGÉP')"> + </%call>""" + ).encode("utf-8"), + ( + """Foo: árvíztűrő tükörfúrógép """ + """Bar: ÁRVÍZTŰRŐ TÜKÖRFÚRÓGÉP""" + ), + filters=flatten_result, + ) + + self._do_memory_test( + ( + "## -*- coding: utf-8 -*-\n" + """<%def name="hello(foo='árvíztűrő tükörfúrógép', """ + """bar='ÁRVÍZTŰRŐ TÜKÖRFÚRÓGÉP')">\n""" + "Foo: ${ foo }\n" + "Bar: ${ bar }\n" + "</%def>\n" + "${ hello() }" + ).encode("utf-8"), + ( + """Foo: árvíztűrő tükörfúrógép Bar: """ + """ÁRVÍZTŰRŐ TÜKÖRFÚRÓGÉP""" + ), + filters=flatten_result, + ) + + def test_input_encoding(self): + """test the 'input_encoding' flag on Template, and that unicode + objects arent double-decoded""" + + self._do_memory_test( + ("hello ${f('śląsk')}"), + ("hello śląsk"), + input_encoding="utf-8", + template_args={"f": lambda x: x}, + ) + + self._do_memory_test( + ("## -*- coding: utf-8 -*-\nhello ${f('śląsk')}"), + ("hello śląsk"), + template_args={"f": lambda x: x}, + ) + + def test_encoding(self): + self._do_memory_test( + ( + "Alors vous imaginez ma surprise, au lever du jour, quand " + "une drôle de petite voix m’a réveillé. Elle disait: " + "« S’il vous plaît… dessine-moi un mouton! »" + ), + ( + "Alors vous imaginez ma surprise, au lever du jour, quand " + "une drôle de petite voix m’a réveillé. Elle disait: " + "« S’il vous plaît… dessine-moi un mouton! »" + ).encode("utf-8"), + output_encoding="utf-8", + unicode_=False, + ) + + def test_encoding_errors(self): + self._do_memory_test( + ( + """KGB (transliteration of "КГБ") is the Russian-language """ + """abbreviation for Committee for State Security, """ + """(Russian: Комит́ет Госуд́арственной Безоп́асности """ + """(help·info); Komitet Gosudarstvennoy Bezopasnosti)""" + ), + ( + """KGB (transliteration of "КГБ") is the Russian-language """ + """abbreviation for Committee for State Security, """ + """(Russian: Комит́ет Госуд́арственной Безоп́асности """ + """(help·info); Komitet Gosudarstvennoy Bezopasnosti)""" + ).encode("iso-8859-1", "replace"), + output_encoding="iso-8859-1", + encoding_errors="replace", + unicode_=False, + ) + + def test_read_unicode(self): + lookup = TemplateLookup( + directories=[config.template_base], + filesystem_checks=True, + output_encoding="utf-8", + ) + template = lookup.get_template("/read_unicode_py3k.html") + # TODO: I've no idea what encoding this file is, Python 3.1.2 + # won't read the file even with open(...encoding='utf-8') unless + # errors is specified. or if there's some quirk in 3.1.2 + # since I'm pretty sure this test worked with py3k when I wrote it. + template.render(path=self._file_path("internationalization.html")) + + +class PageArgsTest(TemplateTest): + def test_basic(self): + template = Template( + """ + <%page args="x, y, z=7"/> + + this is page, ${x}, ${y}, ${z} +""" + ) + + assert ( + flatten_result(template.render(x=5, y=10)) + == "this is page, 5, 10, 7" + ) + assert ( + flatten_result(template.render(x=5, y=10, z=32)) + == "this is page, 5, 10, 32" + ) + assert_raises(TypeError, template.render, y=10) + + def test_inherits(self): + lookup = TemplateLookup() + lookup.put_string( + "base.tmpl", + """ + <%page args="bar" /> + ${bar} + ${pageargs['foo']} + ${self.body(**pageargs)} + """, + ) + lookup.put_string( + "index.tmpl", + """ + <%inherit file="base.tmpl" /> + <%page args="variable" /> + ${variable} + """, + ) + + self._do_test( + lookup.get_template("index.tmpl"), + "bar foo var", + filters=flatten_result, + template_args={"variable": "var", "bar": "bar", "foo": "foo"}, + ) + + def test_includes(self): + lookup = TemplateLookup() + lookup.put_string( + "incl1.tmpl", + """ + <%page args="bar" /> + ${bar} + ${pageargs['foo']} + """, + ) + lookup.put_string( + "incl2.tmpl", + """ + ${pageargs} + """, + ) + lookup.put_string( + "index.tmpl", + """ + <%include file="incl1.tmpl" args="**pageargs"/> + <%page args="variable" /> + ${variable} + <%include file="incl2.tmpl" /> + """, + ) + + self._do_test( + lookup.get_template("index.tmpl"), + "bar foo var {}", + filters=flatten_result, + template_args={"variable": "var", "bar": "bar", "foo": "foo"}, + ) + + def test_context_small(self): + ctx = runtime.Context([].append, x=5, y=4) + eq_(sorted(ctx.keys()), ["caller", "capture", "x", "y"]) + + def test_with_context(self): + template = Template( + """ + <%page args="x, y, z=7"/> + + this is page, ${x}, ${y}, ${z}, ${w} +""" + ) + # print template.code + assert ( + flatten_result(template.render(x=5, y=10, w=17)) + == "this is page, 5, 10, 7, 17" + ) + + def test_overrides_builtins(self): + template = Template( + """ + <%page args="id"/> + + this is page, id is ${id} + """ + ) + + assert ( + flatten_result(template.render(id="im the id")) + == "this is page, id is im the id" + ) + + def test_canuse_builtin_names(self): + template = Template( + """ + exception: ${Exception} + id: ${id} + """ + ) + assert ( + flatten_result( + template.render(id="some id", Exception="some exception") + ) + == "exception: some exception id: some id" + ) + + def test_builtin_names_dont_clobber_defaults_in_includes(self): + lookup = TemplateLookup() + lookup.put_string( + "test.mako", + """ + <%include file="test1.mako"/> + + """, + ) + + lookup.put_string( + "test1.mako", + """ + <%page args="id='foo'"/> + + ${id} + """, + ) + + for template in ("test.mako", "test1.mako"): + assert ( + flatten_result(lookup.get_template(template).render()) == "foo" + ) + assert ( + flatten_result(lookup.get_template(template).render(id=5)) + == "5" + ) + assert ( + flatten_result(lookup.get_template(template).render(id=id)) + == "<built-in function id>" + ) + + def test_dict_locals(self): + template = Template( + """ + <% + dict = "this is dict" + locals = "this is locals" + %> + dict: ${dict} + locals: ${locals} + """ + ) + assert ( + flatten_result(template.render()) + == "dict: this is dict locals: this is locals" + ) + + +class IncludeTest(TemplateTest): + def test_basic(self): + lookup = TemplateLookup() + lookup.put_string( + "a", + """ + this is a + <%include file="b" args="a=3,b=4,c=5"/> + """, + ) + lookup.put_string( + "b", + """ + <%page args="a,b,c"/> + this is b. ${a}, ${b}, ${c} + """, + ) + assert ( + flatten_result(lookup.get_template("a").render()) + == "this is a this is b. 3, 4, 5" + ) + + def test_localargs(self): + lookup = TemplateLookup() + lookup.put_string( + "a", + """ + this is a + <%include file="b" args="a=a,b=b,c=5"/> + """, + ) + lookup.put_string( + "b", + """ + <%page args="a,b,c"/> + this is b. ${a}, ${b}, ${c} + """, + ) + assert ( + flatten_result(lookup.get_template("a").render(a=7, b=8)) + == "this is a this is b. 7, 8, 5" + ) + + def test_viakwargs(self): + lookup = TemplateLookup() + lookup.put_string( + "a", + """ + this is a + <%include file="b" args="c=5, **context.kwargs"/> + """, + ) + lookup.put_string( + "b", + """ + <%page args="a,b,c"/> + this is b. ${a}, ${b}, ${c} + """, + ) + # print lookup.get_template("a").code + assert ( + flatten_result(lookup.get_template("a").render(a=7, b=8)) + == "this is a this is b. 7, 8, 5" + ) + + def test_include_withargs(self): + lookup = TemplateLookup() + lookup.put_string( + "a", + """ + this is a + <%include file="${i}" args="c=5, **context.kwargs"/> + """, + ) + lookup.put_string( + "b", + """ + <%page args="a,b,c"/> + this is b. ${a}, ${b}, ${c} + """, + ) + assert ( + flatten_result(lookup.get_template("a").render(a=7, b=8, i="b")) + == "this is a this is b. 7, 8, 5" + ) + + def test_within_ccall(self): + lookup = TemplateLookup() + lookup.put_string("a", """this is a""") + lookup.put_string( + "b", + """ + <%def name="bar()"> + bar: ${caller.body()} + <%include file="a"/> + </%def> + """, + ) + lookup.put_string( + "c", + """ + <%namespace name="b" file="b"/> + <%b:bar> + calling bar + </%b:bar> + """, + ) + assert ( + flatten_result(lookup.get_template("c").render()) + == "bar: calling bar this is a" + ) + + def test_include_error_handler(self): + def handle(context, error): + context.write("include error") + return True + + lookup = TemplateLookup(include_error_handler=handle) + lookup.put_string( + "a", + """ + this is a. + <%include file="b"/> + """, + ) + lookup.put_string( + "b", + """ + this is b ${1/0} end. + """, + ) + assert ( + flatten_result(lookup.get_template("a").render()) + == "this is a. this is b include error" + ) + + +class UndefinedVarsTest(TemplateTest): + def test_undefined(self): + t = Template( + """ + % if x is UNDEFINED: + undefined + % else: + x: ${x} + % endif + """ + ) + + assert result_lines(t.render(x=12)) == ["x: 12"] + assert result_lines(t.render(y=12)) == ["undefined"] + + def test_strict(self): + t = Template( + """ + % if x is UNDEFINED: + undefined + % else: + x: ${x} + % endif + """, + strict_undefined=True, + ) + + assert result_lines(t.render(x=12)) == ["x: 12"] + + assert_raises(NameError, t.render, y=12) + + l = TemplateLookup(strict_undefined=True) + l.put_string("a", "some template") + l.put_string( + "b", + """ + <%namespace name='a' file='a' import='*'/> + % if x is UNDEFINED: + undefined + % else: + x: ${x} + % endif + """, + ) + + assert result_lines(t.render(x=12)) == ["x: 12"] + + assert_raises(NameError, t.render, y=12) + + def test_expression_declared(self): + t = Template( + """ + ${",".join([t for t in ("a", "b", "c")])} + """, + strict_undefined=True, + ) + + eq_(result_lines(t.render()), ["a,b,c"]) + + t = Template( + """ + <%self:foo value="${[(val, n) for val, n in [(1, 2)]]}"/> + + <%def name="foo(value)"> + ${value} + </%def> + + """, + strict_undefined=True, + ) + + eq_(result_lines(t.render()), ["[(1, 2)]"]) + + t = Template( + """ + <%call expr="foo(value=[(val, n) for val, n in [(1, 2)]])" /> + + <%def name="foo(value)"> + ${value} + </%def> + + """, + strict_undefined=True, + ) + + eq_(result_lines(t.render()), ["[(1, 2)]"]) + + l = TemplateLookup(strict_undefined=True) + l.put_string("i", "hi, ${pageargs['y']}") + l.put_string( + "t", + """ + <%include file="i" args="y=[x for x in range(3)]" /> + """, + ) + eq_(result_lines(l.get_template("t").render()), ["hi, [0, 1, 2]"]) + + l.put_string( + "q", + """ + <%namespace name="i" file="${(str([x for x in range(3)][2]) + """ + """'i')[-1]}" /> + ${i.body(y='x')} + """, + ) + eq_(result_lines(l.get_template("q").render()), ["hi, x"]) + + t = Template( + """ + <% + y = lambda q: str(q) + %> + ${y('hi')} + """, + strict_undefined=True, + ) + eq_(result_lines(t.render()), ["hi"]) + + def test_list_comprehensions_plus_undeclared_nonstrict(self): + # traditional behavior. variable inside a list comprehension + # is treated as an "undefined", so is pulled from the context. + t = Template( + """ + t is: ${t} + + ${",".join([t for t in ("a", "b", "c")])} + """ + ) + + eq_(result_lines(t.render(t="T")), ["t is: T", "a,b,c"]) + + def test_traditional_assignment_plus_undeclared(self): + t = Template( + """ + t is: ${t} + + <% + t = 12 + %> + """ + ) + assert_raises(UnboundLocalError, t.render, t="T") + + def test_list_comprehensions_plus_undeclared_strict(self): + # with strict, a list comprehension now behaves + # like the undeclared case above. + t = Template( + """ + t is: ${t} + + ${",".join([t for t in ("a", "b", "c")])} + """, + strict_undefined=True, + ) + + eq_(result_lines(t.render(t="T")), ["t is: T", "a,b,c"]) + + +class StopRenderingTest(TemplateTest): + def test_return_in_template(self): + t = Template( + """ + Line one + <% return STOP_RENDERING %> + Line Three + """, + strict_undefined=True, + ) + + eq_(result_lines(t.render()), ["Line one"]) + + +class ReservedNameTest(TemplateTest): + def test_names_on_context(self): + for name in ("context", "loop", "UNDEFINED", "STOP_RENDERING"): + assert_raises_message( + exceptions.NameConflictError, + r"Reserved words passed to render\(\): %s" % name, + Template("x").render, + **{name: "foo"}, + ) + + def test_names_in_template(self): + for name in ("context", "loop", "UNDEFINED", "STOP_RENDERING"): + assert_raises_message( + exceptions.NameConflictError, + r"Reserved words declared in template: %s" % name, + Template, + "<%% %s = 5 %%>" % name, + ) + + def test_exclude_loop_context(self): + self._do_memory_test( + "loop is ${loop}", + "loop is 5", + template_args=dict(loop=5), + enable_loop=False, + ) + + def test_exclude_loop_template(self): + self._do_memory_test( + "<% loop = 12 %>loop is ${loop}", "loop is 12", enable_loop=False + ) + + +class ControlTest(TemplateTest): + def test_control(self): + t = Template( + """ + ## this is a template. + % for x in y: + % if 'test' in x: + yes x has test + % else: + no x does not have test + %endif + %endfor +""" + ) + assert result_lines( + t.render( + y=[ + {"test": "one"}, + {"foo": "bar"}, + {"foo": "bar", "test": "two"}, + ] + ) + ) == ["yes x has test", "no x does not have test", "yes x has test"] + + def test_blank_control_1(self): + self._do_memory_test( + """ + % if True: + % endif + """, + "", + filters=lambda s: s.strip(), + ) + + def test_blank_control_2(self): + self._do_memory_test( + """ + % if True: + % elif True: + % endif + """, + "", + filters=lambda s: s.strip(), + ) + + def test_blank_control_3(self): + self._do_memory_test( + """ + % if True: + % else: + % endif + """, + "", + filters=lambda s: s.strip(), + ) + + def test_blank_control_4(self): + self._do_memory_test( + """ + % if True: + % elif True: + % else: + % endif + """, + "", + filters=lambda s: s.strip(), + ) + + def test_blank_control_5(self): + self._do_memory_test( + """ + % for x in range(10): + % endfor + """, + "", + filters=lambda s: s.strip(), + ) + + def test_blank_control_6(self): + self._do_memory_test( + """ + % while False: + % endwhile + """, + "", + filters=lambda s: s.strip(), + ) + + def test_blank_control_7(self): + self._do_memory_test( + """ + % try: + % except: + % endtry + """, + "", + filters=lambda s: s.strip(), + ) + + def test_blank_control_8(self): + self._do_memory_test( + """ + % with ctx('x', 'w') as fp: + % endwith + """, + "", + filters=lambda s: s.strip(), + template_args={"ctx": ctx}, + ) + + def test_commented_blank_control_1(self): + self._do_memory_test( + """ + % if True: + ## comment + % endif + """, + "", + filters=lambda s: s.strip(), + ) + + def test_commented_blank_control_2(self): + self._do_memory_test( + """ + % if True: + ## comment + % elif True: + ## comment + % endif + """, + "", + filters=lambda s: s.strip(), + ) + + def test_commented_blank_control_3(self): + self._do_memory_test( + """ + % if True: + ## comment + % else: + ## comment + % endif + """, + "", + filters=lambda s: s.strip(), + ) + + def test_commented_blank_control_4(self): + self._do_memory_test( + """ + % if True: + ## comment + % elif True: + ## comment + % else: + ## comment + % endif + """, + "", + filters=lambda s: s.strip(), + ) + + def test_commented_blank_control_5(self): + self._do_memory_test( + """ + % for x in range(10): + ## comment + % endfor + """, + "", + filters=lambda s: s.strip(), + ) + + def test_commented_blank_control_6(self): + self._do_memory_test( + """ + % while False: + ## comment + % endwhile + """, + "", + filters=lambda s: s.strip(), + ) + + def test_commented_blank_control_7(self): + self._do_memory_test( + """ + % try: + ## comment + % except: + ## comment + % endtry + """, + "", + filters=lambda s: s.strip(), + ) + + def test_commented_blank_control_8(self): + self._do_memory_test( + """ + % with ctx('x', 'w') as fp: + ## comment + % endwith + """, + "", + filters=lambda s: s.strip(), + template_args={"ctx": ctx}, + ) + + def test_multiline_control(self): + t = Template( + """ + % for x in \\ + [y for y in [1,2,3]]: + ${x} + % endfor +""" + ) + # print t.code + assert flatten_result(t.render()) == "1 2 3" + + +class GlobalsTest(TemplateTest): + def test_globals(self): + self._do_memory_test( + """ + <%! + y = "hi" + %> + y is ${y} + """, + "y is hi", + filters=lambda t: t.strip(), + ) + + +class RichTracebackTest(TemplateTest): + def _do_test_traceback(self, utf8, memory, syntax): + if memory: + if syntax: + source = ( + '## coding: utf-8\n<% print "m’a réveillé. ' + "Elle disait: « S’il vous plaît… dessine-moi " + "un mouton! » %>" + ) + else: + source = ( + '## coding: utf-8\n<% print u"m’a réveillé. ' + "Elle disait: « S’il vous plaît… dessine-moi un " + 'mouton! »" + str(5/0) %>' + ) + if utf8: + source = source.encode("utf-8") + else: + source = source + templateargs = {"text": source} + else: + if syntax: + filename = "unicode_syntax_error.html" + else: + filename = "unicode_runtime_error.html" + source = util.read_file(self._file_path(filename), "rb") + if not utf8: + source = source.decode("utf-8") + templateargs = {"filename": self._file_path(filename)} + try: + template = Template(**templateargs) + if not syntax: + template.render_unicode() + assert False + except Exception: + tback = exceptions.RichTraceback() + if utf8: + assert tback.source == source.decode("utf-8") + else: + assert tback.source == source + + +for utf8 in (True, False): + for memory in (True, False): + for syntax in (True, False): + + def _do_test(self): + self._do_test_traceback(utf8, memory, syntax) + + name = "test_%s_%s_%s" % ( + utf8 and "utf8" or "unicode", + memory and "memory" or "file", + syntax and "syntax" or "runtime", + ) + _do_test.__name__ = name + setattr(RichTracebackTest, name, _do_test) + del _do_test + + +class ModuleDirTest(TemplateTest): + def teardown_method(self): + import shutil + + shutil.rmtree(config.module_base, True) + + def test_basic(self): + t = self._file_template("modtest.html") + t2 = self._file_template("subdir/modtest.html") + + eq_( + t.module.__file__, + os.path.join(config.module_base, "modtest.html.py"), + ) + eq_( + t2.module.__file__, + os.path.join(config.module_base, "subdir", "modtest.html.py"), + ) + + def test_callable(self): + def get_modname(filename, uri): + return os.path.join( + config.module_base, + os.path.dirname(uri)[1:], + "foo", + os.path.basename(filename) + ".py", + ) + + lookup = TemplateLookup( + config.template_base, modulename_callable=get_modname + ) + t = lookup.get_template("/modtest.html") + t2 = lookup.get_template("/subdir/modtest.html") + eq_( + t.module.__file__, + os.path.join(config.module_base, "foo", "modtest.html.py"), + ) + eq_( + t2.module.__file__, + os.path.join( + config.module_base, "subdir", "foo", "modtest.html.py" + ), + ) + + def test_custom_writer(self): + canary = [] + + def write_module(source, outputpath): + f = open(outputpath, "wb") + canary.append(outputpath) + f.write(source) + f.close() + + lookup = TemplateLookup( + config.template_base, + module_writer=write_module, + module_directory=config.module_base, + ) + lookup.get_template("/modtest.html") + lookup.get_template("/subdir/modtest.html") + eq_( + canary, + [ + os.path.join(config.module_base, "modtest.html.py"), + os.path.join(config.module_base, "subdir", "modtest.html.py"), + ], + ) + + +class FilenameToURITest(TemplateTest): + def test_windows_paths(self): + """test that windows filenames are handled appropriately by + Template.""" + + current_path = os.path + import ntpath + + os.path = ntpath + try: + + class NoCompileTemplate(Template): + def _compile_from_file(self, path, filename): + self.path = path + return Template("foo bar").module + + t1 = NoCompileTemplate( + filename="c:\\foo\\template.html", + module_directory="c:\\modules\\", + ) + + eq_(t1.uri, "/foo/template.html") + eq_(t1.path, "c:\\modules\\foo\\template.html.py") + + t1 = NoCompileTemplate( + filename="c:\\path\\to\\templates\\template.html", + uri="/bar/template.html", + module_directory="c:\\modules\\", + ) + + eq_(t1.uri, "/bar/template.html") + eq_(t1.path, "c:\\modules\\bar\\template.html.py") + + finally: + os.path = current_path + + def test_posix_paths(self): + """test that posixs filenames are handled appropriately by Template.""" + + current_path = os.path + import posixpath + + os.path = posixpath + try: + + class NoCompileTemplate(Template): + def _compile_from_file(self, path, filename): + self.path = path + return Template("foo bar").module + + t1 = NoCompileTemplate( + filename="/var/www/htdocs/includes/template.html", + module_directory="/var/lib/modules", + ) + + eq_(t1.uri, "/var/www/htdocs/includes/template.html") + eq_( + t1.path, + "/var/lib/modules/var/www/htdocs/includes/template.html.py", + ) + + t1 = NoCompileTemplate( + filename="/var/www/htdocs/includes/template.html", + uri="/bar/template.html", + module_directory="/var/lib/modules", + ) + + eq_(t1.uri, "/bar/template.html") + eq_(t1.path, "/var/lib/modules/bar/template.html.py") + + finally: + os.path = current_path + + def test_dont_accept_relative_outside_of_root(self): + assert_raises_message( + exceptions.TemplateLookupException, + 'Template uri "../../foo.html" is invalid - it ' + "cannot be relative outside of the root path", + Template, + "test", + uri="../../foo.html", + ) + + assert_raises_message( + exceptions.TemplateLookupException, + 'Template uri "/../../foo.html" is invalid - it ' + "cannot be relative outside of the root path", + Template, + "test", + uri="/../../foo.html", + ) + + # normalizes in the root is OK + t = Template("test", uri="foo/bar/../../foo.html") + eq_(t.uri, "foo/bar/../../foo.html") + + +class ModuleTemplateTest(TemplateTest): + def test_module_roundtrip(self): + lookup = TemplateLookup() + + template = Template( + """ + <%inherit file="base.html"/> + + % for x in range(5): + ${x} + % endfor +""", + lookup=lookup, + ) + + base = Template( + """ + This is base. + ${self.body()} +""", + lookup=lookup, + ) + + lookup.put_template("base.html", base) + lookup.put_template("template.html", template) + + assert result_lines(template.render()) == [ + "This is base.", + "0", + "1", + "2", + "3", + "4", + ] + + lookup = TemplateLookup() + template = ModuleTemplate(template.module, lookup=lookup) + base = ModuleTemplate(base.module, lookup=lookup) + + lookup.put_template("base.html", base) + lookup.put_template("template.html", template) + + assert result_lines(template.render()) == [ + "This is base.", + "0", + "1", + "2", + "3", + "4", + ] + + +class TestTemplateAPI: + def test_metadata(self): + t = Template( + """ +Text +Text +% if bar: + ${expression} +% endif + +<%include file='bar'/> + +""", + uri="/some/template", + ) + eq_( + ModuleInfo.get_module_source_metadata(t.code, full_line_map=True), + { + "full_line_map": [ + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 4, + 5, + 5, + 5, + 7, + 8, + 8, + 8, + 8, + 8, + 8, + 8, + ], + "source_encoding": "utf-8", + "filename": None, + "line_map": { + 35: 29, + 15: 0, + 22: 1, + 23: 4, + 24: 5, + 25: 5, + 26: 5, + 27: 7, + 28: 8, + 29: 8, + }, + "uri": "/some/template", + }, + ) + + def test_metadata_two(self): + t = Template( + """ +Text +Text +% if bar: + ${expression} +% endif + + <%block name="foo"> + hi block + </%block> + + +""", + uri="/some/template", + ) + eq_( + ModuleInfo.get_module_source_metadata(t.code, full_line_map=True), + { + "full_line_map": [ + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 4, + 5, + 5, + 5, + 7, + 7, + 7, + 7, + 7, + 10, + 10, + 10, + 10, + 10, + 10, + 8, + 8, + 8, + 8, + 8, + 8, + 8, + 8, + 8, + 8, + 8, + 8, + ], + "source_encoding": "utf-8", + "filename": None, + "line_map": { + 34: 10, + 40: 8, + 46: 8, + 15: 0, + 52: 46, + 24: 1, + 25: 4, + 26: 5, + 27: 5, + 28: 5, + 29: 7, + }, + "uri": "/some/template", + }, + ) + + +class PreprocessTest(TemplateTest): + def test_old_comments(self): + t = Template( + """ + im a template +# old style comment + # more old style comment + + ## new style comment + - # not a comment + - ## not a comment +""", + preprocessor=convert_comments, + ) + + assert ( + flatten_result(t.render()) + == "im a template - # not a comment - ## not a comment" + ) + + +class LexerTest(TemplateTest): + def _fixture(self): + from mako.parsetree import TemplateNode, Text + + class MyLexer: + encoding = "ascii" + + def __init__(self, *arg, **kw): + pass + + def parse(self): + t = TemplateNode("foo") + t.nodes.append( + Text( + "hello world", + source="foo", + lineno=0, + pos=0, + filename=None, + ) + ) + return t + + return MyLexer + + def _test_custom_lexer(self, template): + eq_(result_lines(template.render()), ["hello world"]) + + def test_via_template(self): + t = Template("foo", lexer_cls=self._fixture()) + self._test_custom_lexer(t) + + def test_via_lookup(self): + tl = TemplateLookup(lexer_cls=self._fixture()) + tl.put_string("foo", "foo") + t = tl.get_template("foo") + self._test_custom_lexer(t) + + +class FuturesTest(TemplateTest): + def test_future_import(self): + t = Template("${ x / y }", future_imports=["division"]) + assert result_lines(t.render(x=12, y=5)) == ["2.4"] |