template_test.py
Go to the documentation of this file.
00001 from __future__ import absolute_import, division, print_function, with_statement
00002 
00003 import os
00004 import sys
00005 import traceback
00006 
00007 from tornado.escape import utf8, native_str, to_unicode
00008 from tornado.template import Template, DictLoader, ParseError, Loader
00009 from tornado.test.util import unittest
00010 from tornado.util import u, bytes_type, ObjectDict, unicode_type
00011 
00012 
00013 class TemplateTest(unittest.TestCase):
00014     def test_simple(self):
00015         template = Template("Hello {{ name }}!")
00016         self.assertEqual(template.generate(name="Ben"),
00017                          b"Hello Ben!")
00018 
00019     def test_bytes(self):
00020         template = Template("Hello {{ name }}!")
00021         self.assertEqual(template.generate(name=utf8("Ben")),
00022                          b"Hello Ben!")
00023 
00024     def test_expressions(self):
00025         template = Template("2 + 2 = {{ 2 + 2 }}")
00026         self.assertEqual(template.generate(), b"2 + 2 = 4")
00027 
00028     def test_comment(self):
00029         template = Template("Hello{# TODO i18n #} {{ name }}!")
00030         self.assertEqual(template.generate(name=utf8("Ben")),
00031                          b"Hello Ben!")
00032 
00033     def test_include(self):
00034         loader = DictLoader({
00035             "index.html": '{% include "header.html" %}\nbody text',
00036             "header.html": "header text",
00037         })
00038         self.assertEqual(loader.load("index.html").generate(),
00039                          b"header text\nbody text")
00040 
00041     def test_extends(self):
00042         loader = DictLoader({
00043             "base.html": """\
00044 <title>{% block title %}default title{% end %}</title>
00045 <body>{% block body %}default body{% end %}</body>
00046 """,
00047             "page.html": """\
00048 {% extends "base.html" %}
00049 {% block title %}page title{% end %}
00050 {% block body %}page body{% end %}
00051 """,
00052         })
00053         self.assertEqual(loader.load("page.html").generate(),
00054                          b"<title>page title</title>\n<body>page body</body>\n")
00055 
00056     def test_relative_load(self):
00057         loader = DictLoader({
00058             "a/1.html": "{% include '2.html' %}",
00059             "a/2.html": "{% include '../b/3.html' %}",
00060             "b/3.html": "ok",
00061         })
00062         self.assertEqual(loader.load("a/1.html").generate(),
00063                          b"ok")
00064 
00065     def test_escaping(self):
00066         self.assertRaises(ParseError, lambda: Template("{{"))
00067         self.assertRaises(ParseError, lambda: Template("{%"))
00068         self.assertEqual(Template("{{!").generate(), b"{{")
00069         self.assertEqual(Template("{%!").generate(), b"{%")
00070         self.assertEqual(Template("{{ 'expr' }} {{!jquery expr}}").generate(),
00071                          b"expr {{jquery expr}}")
00072 
00073     def test_unicode_template(self):
00074         template = Template(utf8(u("\u00e9")))
00075         self.assertEqual(template.generate(), utf8(u("\u00e9")))
00076 
00077     def test_unicode_literal_expression(self):
00078         # Unicode literals should be usable in templates.  Note that this
00079         # test simulates unicode characters appearing directly in the
00080         # template file (with utf8 encoding), i.e. \u escapes would not
00081         # be used in the template file itself.
00082         if str is unicode_type:
00083             # python 3 needs a different version of this test since
00084             # 2to3 doesn't run on template internals
00085             template = Template(utf8(u('{{ "\u00e9" }}')))
00086         else:
00087             template = Template(utf8(u('{{ u"\u00e9" }}')))
00088         self.assertEqual(template.generate(), utf8(u("\u00e9")))
00089 
00090     def test_custom_namespace(self):
00091         loader = DictLoader({"test.html": "{{ inc(5) }}"}, namespace={"inc": lambda x: x + 1})
00092         self.assertEqual(loader.load("test.html").generate(), b"6")
00093 
00094     def test_apply(self):
00095         def upper(s):
00096             return s.upper()
00097         template = Template(utf8("{% apply upper %}foo{% end %}"))
00098         self.assertEqual(template.generate(upper=upper), b"FOO")
00099 
00100     def test_unicode_apply(self):
00101         def upper(s):
00102             return to_unicode(s).upper()
00103         template = Template(utf8(u("{% apply upper %}foo \u00e9{% end %}")))
00104         self.assertEqual(template.generate(upper=upper), utf8(u("FOO \u00c9")))
00105 
00106     def test_bytes_apply(self):
00107         def upper(s):
00108             return utf8(to_unicode(s).upper())
00109         template = Template(utf8(u("{% apply upper %}foo \u00e9{% end %}")))
00110         self.assertEqual(template.generate(upper=upper), utf8(u("FOO \u00c9")))
00111 
00112     def test_if(self):
00113         template = Template(utf8("{% if x > 4 %}yes{% else %}no{% end %}"))
00114         self.assertEqual(template.generate(x=5), b"yes")
00115         self.assertEqual(template.generate(x=3), b"no")
00116 
00117     def test_if_empty_body(self):
00118         template = Template(utf8("{% if True %}{% else %}{% end %}"))
00119         self.assertEqual(template.generate(), b"")
00120 
00121     def test_try(self):
00122         template = Template(utf8("""{% try %}
00123 try{% set y = 1/x %}
00124 {% except %}-except
00125 {% else %}-else
00126 {% finally %}-finally
00127 {% end %}"""))
00128         self.assertEqual(template.generate(x=1), b"\ntry\n-else\n-finally\n")
00129         self.assertEqual(template.generate(x=0), b"\ntry-except\n-finally\n")
00130 
00131     def test_comment_directive(self):
00132         template = Template(utf8("{% comment blah blah %}foo"))
00133         self.assertEqual(template.generate(), b"foo")
00134 
00135     def test_break_continue(self):
00136         template = Template(utf8("""\
00137 {% for i in range(10) %}
00138     {% if i == 2 %}
00139         {% continue %}
00140     {% end %}
00141     {{ i }}
00142     {% if i == 6 %}
00143         {% break %}
00144     {% end %}
00145 {% end %}"""))
00146         result = template.generate()
00147         # remove extraneous whitespace
00148         result = b''.join(result.split())
00149         self.assertEqual(result, b"013456")
00150 
00151     def test_break_outside_loop(self):
00152         try:
00153             Template(utf8("{% break %}"))
00154             raise Exception("Did not get expected exception")
00155         except ParseError:
00156             pass
00157 
00158     def test_break_in_apply(self):
00159         # This test verifies current behavior, although of course it would
00160         # be nice if apply didn't cause seemingly unrelated breakage
00161         try:
00162             Template(utf8("{% for i in [] %}{% apply foo %}{% break %}{% end %}{% end %}"))
00163             raise Exception("Did not get expected exception")
00164         except ParseError:
00165             pass
00166 
00167     @unittest.skipIf(sys.version_info >= division.getMandatoryRelease(),
00168                      'no testable future imports')
00169     def test_no_inherit_future(self):
00170         # This file has from __future__ import division...
00171         self.assertEqual(1 / 2, 0.5)
00172         # ...but the template doesn't
00173         template = Template('{{ 1 / 2 }}')
00174         self.assertEqual(template.generate(), '0')
00175 
00176 
00177 class StackTraceTest(unittest.TestCase):
00178     def test_error_line_number_expression(self):
00179         loader = DictLoader({"test.html": """one
00180 two{{1/0}}
00181 three
00182         """})
00183         try:
00184             loader.load("test.html").generate()
00185             self.fail("did not get expected exception")
00186         except ZeroDivisionError:
00187             self.assertTrue("# test.html:2" in traceback.format_exc())
00188 
00189     def test_error_line_number_directive(self):
00190         loader = DictLoader({"test.html": """one
00191 two{%if 1/0%}
00192 three{%end%}
00193         """})
00194         try:
00195             loader.load("test.html").generate()
00196             self.fail("did not get expected exception")
00197         except ZeroDivisionError:
00198             self.assertTrue("# test.html:2" in traceback.format_exc())
00199 
00200     def test_error_line_number_module(self):
00201         loader = DictLoader({
00202             "base.html": "{% module Template('sub.html') %}",
00203             "sub.html": "{{1/0}}",
00204         }, namespace={"_tt_modules": ObjectDict({"Template": lambda path, **kwargs: loader.load(path).generate(**kwargs)})})
00205         try:
00206             loader.load("base.html").generate()
00207             self.fail("did not get expected exception")
00208         except ZeroDivisionError:
00209             exc_stack = traceback.format_exc()
00210             self.assertTrue('# base.html:1' in exc_stack)
00211             self.assertTrue('# sub.html:1' in exc_stack)
00212 
00213     def test_error_line_number_include(self):
00214         loader = DictLoader({
00215             "base.html": "{% include 'sub.html' %}",
00216             "sub.html": "{{1/0}}",
00217         })
00218         try:
00219             loader.load("base.html").generate()
00220             self.fail("did not get expected exception")
00221         except ZeroDivisionError:
00222             self.assertTrue("# sub.html:1 (via base.html:1)" in
00223                             traceback.format_exc())
00224 
00225     def test_error_line_number_extends_base_error(self):
00226         loader = DictLoader({
00227             "base.html": "{{1/0}}",
00228             "sub.html": "{% extends 'base.html' %}",
00229         })
00230         try:
00231             loader.load("sub.html").generate()
00232             self.fail("did not get expected exception")
00233         except ZeroDivisionError:
00234             exc_stack = traceback.format_exc()
00235         self.assertTrue("# base.html:1" in exc_stack)
00236 
00237     def test_error_line_number_extends_sub_error(self):
00238         loader = DictLoader({
00239             "base.html": "{% block 'block' %}{% end %}",
00240             "sub.html": """
00241 {% extends 'base.html' %}
00242 {% block 'block' %}
00243 {{1/0}}
00244 {% end %}
00245             """})
00246         try:
00247             loader.load("sub.html").generate()
00248             self.fail("did not get expected exception")
00249         except ZeroDivisionError:
00250             self.assertTrue("# sub.html:4 (via base.html:1)" in
00251                             traceback.format_exc())
00252 
00253     def test_multi_includes(self):
00254         loader = DictLoader({
00255             "a.html": "{% include 'b.html' %}",
00256             "b.html": "{% include 'c.html' %}",
00257             "c.html": "{{1/0}}",
00258         })
00259         try:
00260             loader.load("a.html").generate()
00261             self.fail("did not get expected exception")
00262         except ZeroDivisionError:
00263             self.assertTrue("# c.html:1 (via b.html:1, a.html:1)" in
00264                             traceback.format_exc())
00265 
00266 
00267 class AutoEscapeTest(unittest.TestCase):
00268     def setUp(self):
00269         self.templates = {
00270             "escaped.html": "{% autoescape xhtml_escape %}{{ name }}",
00271             "unescaped.html": "{% autoescape None %}{{ name }}",
00272             "default.html": "{{ name }}",
00273 
00274             "include.html": """\
00275 escaped: {% include 'escaped.html' %}
00276 unescaped: {% include 'unescaped.html' %}
00277 default: {% include 'default.html' %}
00278 """,
00279 
00280             "escaped_block.html": """\
00281 {% autoescape xhtml_escape %}\
00282 {% block name %}base: {{ name }}{% end %}""",
00283             "unescaped_block.html": """\
00284 {% autoescape None %}\
00285 {% block name %}base: {{ name }}{% end %}""",
00286 
00287             # Extend a base template with different autoescape policy,
00288             # with and without overriding the base's blocks
00289             "escaped_extends_unescaped.html": """\
00290 {% autoescape xhtml_escape %}\
00291 {% extends "unescaped_block.html" %}""",
00292             "escaped_overrides_unescaped.html": """\
00293 {% autoescape xhtml_escape %}\
00294 {% extends "unescaped_block.html" %}\
00295 {% block name %}extended: {{ name }}{% end %}""",
00296             "unescaped_extends_escaped.html": """\
00297 {% autoescape None %}\
00298 {% extends "escaped_block.html" %}""",
00299             "unescaped_overrides_escaped.html": """\
00300 {% autoescape None %}\
00301 {% extends "escaped_block.html" %}\
00302 {% block name %}extended: {{ name }}{% end %}""",
00303 
00304             "raw_expression.html": """\
00305 {% autoescape xhtml_escape %}\
00306 expr: {{ name }}
00307 raw: {% raw name %}""",
00308         }
00309 
00310     def test_default_off(self):
00311         loader = DictLoader(self.templates, autoescape=None)
00312         name = "Bobby <table>s"
00313         self.assertEqual(loader.load("escaped.html").generate(name=name),
00314                          b"Bobby &lt;table&gt;s")
00315         self.assertEqual(loader.load("unescaped.html").generate(name=name),
00316                          b"Bobby <table>s")
00317         self.assertEqual(loader.load("default.html").generate(name=name),
00318                          b"Bobby <table>s")
00319 
00320         self.assertEqual(loader.load("include.html").generate(name=name),
00321                          b"escaped: Bobby &lt;table&gt;s\n"
00322                          b"unescaped: Bobby <table>s\n"
00323                          b"default: Bobby <table>s\n")
00324 
00325     def test_default_on(self):
00326         loader = DictLoader(self.templates, autoescape="xhtml_escape")
00327         name = "Bobby <table>s"
00328         self.assertEqual(loader.load("escaped.html").generate(name=name),
00329                          b"Bobby &lt;table&gt;s")
00330         self.assertEqual(loader.load("unescaped.html").generate(name=name),
00331                          b"Bobby <table>s")
00332         self.assertEqual(loader.load("default.html").generate(name=name),
00333                          b"Bobby &lt;table&gt;s")
00334 
00335         self.assertEqual(loader.load("include.html").generate(name=name),
00336                          b"escaped: Bobby &lt;table&gt;s\n"
00337                          b"unescaped: Bobby <table>s\n"
00338                          b"default: Bobby &lt;table&gt;s\n")
00339 
00340     def test_unextended_block(self):
00341         loader = DictLoader(self.templates)
00342         name = "<script>"
00343         self.assertEqual(loader.load("escaped_block.html").generate(name=name),
00344                          b"base: &lt;script&gt;")
00345         self.assertEqual(loader.load("unescaped_block.html").generate(name=name),
00346                          b"base: <script>")
00347 
00348     def test_extended_block(self):
00349         loader = DictLoader(self.templates)
00350 
00351         def render(name):
00352             return loader.load(name).generate(name="<script>")
00353         self.assertEqual(render("escaped_extends_unescaped.html"),
00354                          b"base: <script>")
00355         self.assertEqual(render("escaped_overrides_unescaped.html"),
00356                          b"extended: &lt;script&gt;")
00357 
00358         self.assertEqual(render("unescaped_extends_escaped.html"),
00359                          b"base: &lt;script&gt;")
00360         self.assertEqual(render("unescaped_overrides_escaped.html"),
00361                          b"extended: <script>")
00362 
00363     def test_raw_expression(self):
00364         loader = DictLoader(self.templates)
00365 
00366         def render(name):
00367             return loader.load(name).generate(name='<>&"')
00368         self.assertEqual(render("raw_expression.html"),
00369                          b"expr: &lt;&gt;&amp;&quot;\n"
00370                          b"raw: <>&\"")
00371 
00372     def test_custom_escape(self):
00373         loader = DictLoader({"foo.py":
00374                              "{% autoescape py_escape %}s = {{ name }}\n"})
00375 
00376         def py_escape(s):
00377             self.assertEqual(type(s), bytes_type)
00378             return repr(native_str(s))
00379 
00380         def render(template, name):
00381             return loader.load(template).generate(py_escape=py_escape,
00382                                                   name=name)
00383         self.assertEqual(render("foo.py", "<html>"),
00384                          b"s = '<html>'\n")
00385         self.assertEqual(render("foo.py", "';sys.exit()"),
00386                          b"""s = "';sys.exit()"\n""")
00387         self.assertEqual(render("foo.py", ["not a string"]),
00388                          b"""s = "['not a string']"\n""")
00389 
00390     def test_minimize_whitespace(self):
00391         # Whitespace including newlines is allowed within template tags
00392         # and directives, and this is one way to avoid long lines while
00393         # keeping extra whitespace out of the rendered output.
00394         loader = DictLoader({'foo.txt': """\
00395 {% for i in items
00396   %}{% if i > 0 %}, {% end %}{#
00397   #}{{i
00398   }}{% end
00399 %}""",
00400                              })
00401         self.assertEqual(loader.load("foo.txt").generate(items=range(5)),
00402                          b"0, 1, 2, 3, 4")
00403 
00404 
00405 class TemplateLoaderTest(unittest.TestCase):
00406     def setUp(self):
00407         self.loader = Loader(os.path.join(os.path.dirname(__file__), "templates"))
00408 
00409     def test_utf8_in_file(self):
00410         tmpl = self.loader.load("utf8.html")
00411         result = tmpl.generate()
00412         self.assertEqual(to_unicode(result).strip(), u("H\u00e9llo"))


rosbridge_tools
Author(s): Jonathan Mace
autogenerated on Sat Dec 27 2014 11:25:59