template_test.py
Go to the documentation of this file.
00001 from __future__ import absolute_import, division, with_statement
00002 
00003 import os
00004 import traceback
00005 
00006 from tornado.escape import utf8, native_str, to_unicode
00007 from tornado.template import Template, DictLoader, ParseError, Loader
00008 from tornado.testing import LogTrapTestCase
00009 from tornado.util import b, bytes_type, ObjectDict
00010 
00011 
00012 class TemplateTest(LogTrapTestCase):
00013     def test_simple(self):
00014         template = Template("Hello {{ name }}!")
00015         self.assertEqual(template.generate(name="Ben"),
00016                          b("Hello Ben!"))
00017 
00018     def test_bytes(self):
00019         template = Template("Hello {{ name }}!")
00020         self.assertEqual(template.generate(name=utf8("Ben")),
00021                          b("Hello Ben!"))
00022 
00023     def test_expressions(self):
00024         template = Template("2 + 2 = {{ 2 + 2 }}")
00025         self.assertEqual(template.generate(), b("2 + 2 = 4"))
00026 
00027     def test_comment(self):
00028         template = Template("Hello{# TODO i18n #} {{ name }}!")
00029         self.assertEqual(template.generate(name=utf8("Ben")),
00030                          b("Hello Ben!"))
00031 
00032     def test_include(self):
00033         loader = DictLoader({
00034                 "index.html": '{% include "header.html" %}\nbody text',
00035                 "header.html": "header text",
00036                 })
00037         self.assertEqual(loader.load("index.html").generate(),
00038                          b("header text\nbody text"))
00039 
00040     def test_extends(self):
00041         loader = DictLoader({
00042                 "base.html": """\
00043 <title>{% block title %}default title{% end %}</title>
00044 <body>{% block body %}default body{% end %}</body>
00045 """,
00046                 "page.html": """\
00047 {% extends "base.html" %}
00048 {% block title %}page title{% end %}
00049 {% block body %}page body{% end %}
00050 """,
00051                 })
00052         self.assertEqual(loader.load("page.html").generate(),
00053                          b("<title>page title</title>\n<body>page body</body>\n"))
00054 
00055     def test_relative_load(self):
00056         loader = DictLoader({
00057                 "a/1.html": "{% include '2.html' %}",
00058                 "a/2.html": "{% include '../b/3.html' %}",
00059                 "b/3.html": "ok",
00060                 })
00061         self.assertEqual(loader.load("a/1.html").generate(),
00062                          b("ok"))
00063 
00064     def test_escaping(self):
00065         self.assertRaises(ParseError, lambda: Template("{{"))
00066         self.assertRaises(ParseError, lambda: Template("{%"))
00067         self.assertEqual(Template("{{!").generate(), b("{{"))
00068         self.assertEqual(Template("{%!").generate(), b("{%"))
00069         self.assertEqual(Template("{{ 'expr' }} {{!jquery expr}}").generate(),
00070                          b("expr {{jquery expr}}"))
00071 
00072     def test_unicode_template(self):
00073         template = Template(utf8(u"\u00e9"))
00074         self.assertEqual(template.generate(), utf8(u"\u00e9"))
00075 
00076     def test_unicode_literal_expression(self):
00077         # Unicode literals should be usable in templates.  Note that this
00078         # test simulates unicode characters appearing directly in the
00079         # template file (with utf8 encoding), i.e. \u escapes would not
00080         # be used in the template file itself.
00081         if str is unicode:
00082             # python 3 needs a different version of this test since
00083             # 2to3 doesn't run on template internals
00084             template = Template(utf8(u'{{ "\u00e9" }}'))
00085         else:
00086             template = Template(utf8(u'{{ u"\u00e9" }}'))
00087         self.assertEqual(template.generate(), utf8(u"\u00e9"))
00088 
00089     def test_custom_namespace(self):
00090         loader = DictLoader({"test.html": "{{ inc(5) }}"}, namespace={"inc": lambda x: x + 1})
00091         self.assertEqual(loader.load("test.html").generate(), b("6"))
00092 
00093     def test_apply(self):
00094         def upper(s):
00095             return s.upper()
00096         template = Template(utf8("{% apply upper %}foo{% end %}"))
00097         self.assertEqual(template.generate(upper=upper), b("FOO"))
00098 
00099     def test_if(self):
00100         template = Template(utf8("{% if x > 4 %}yes{% else %}no{% end %}"))
00101         self.assertEqual(template.generate(x=5), b("yes"))
00102         self.assertEqual(template.generate(x=3), b("no"))
00103 
00104     def test_try(self):
00105         template = Template(utf8("""{% try %}
00106 try{% set y = 1/x %}
00107 {% except %}-except
00108 {% else %}-else
00109 {% finally %}-finally
00110 {% end %}"""))
00111         self.assertEqual(template.generate(x=1), b("\ntry\n-else\n-finally\n"))
00112         self.assertEqual(template.generate(x=0), b("\ntry-except\n-finally\n"))
00113 
00114     def test_comment_directive(self):
00115         template = Template(utf8("{% comment blah blah %}foo"))
00116         self.assertEqual(template.generate(), b("foo"))
00117 
00118 
00119 class StackTraceTest(LogTrapTestCase):
00120     def test_error_line_number_expression(self):
00121         loader = DictLoader({"test.html": """one
00122 two{{1/0}}
00123 three
00124         """})
00125         try:
00126             loader.load("test.html").generate()
00127         except ZeroDivisionError:
00128             self.assertTrue("# test.html:2" in traceback.format_exc())
00129 
00130     def test_error_line_number_directive(self):
00131         loader = DictLoader({"test.html": """one
00132 two{%if 1/0%}
00133 three{%end%}
00134         """})
00135         try:
00136             loader.load("test.html").generate()
00137         except ZeroDivisionError:
00138             self.assertTrue("# test.html:2" in traceback.format_exc())
00139 
00140     def test_error_line_number_module(self):
00141         loader = DictLoader({
00142             "base.html": "{% module Template('sub.html') %}",
00143             "sub.html": "{{1/0}}",
00144         }, namespace={"_modules": ObjectDict({"Template": lambda path, **kwargs: loader.load(path).generate(**kwargs)})})
00145         try:
00146             loader.load("base.html").generate()
00147         except ZeroDivisionError:
00148             exc_stack = traceback.format_exc()
00149             self.assertTrue('# base.html:1' in exc_stack)
00150             self.assertTrue('# sub.html:1' in exc_stack)
00151 
00152     def test_error_line_number_include(self):
00153         loader = DictLoader({
00154             "base.html": "{% include 'sub.html' %}",
00155             "sub.html": "{{1/0}}",
00156         })
00157         try:
00158             loader.load("base.html").generate()
00159         except ZeroDivisionError:
00160             self.assertTrue("# sub.html:1 (via base.html:1)" in
00161                             traceback.format_exc())
00162 
00163     def test_error_line_number_extends_base_error(self):
00164         loader = DictLoader({
00165             "base.html": "{{1/0}}",
00166             "sub.html": "{% extends 'base.html' %}",
00167         })
00168         try:
00169             loader.load("sub.html").generate()
00170         except ZeroDivisionError:
00171             exc_stack = traceback.format_exc()
00172         self.assertTrue("# base.html:1" in exc_stack)
00173 
00174     def test_error_line_number_extends_sub_error(self):
00175         loader = DictLoader({
00176             "base.html": "{% block 'block' %}{% end %}",
00177             "sub.html": """
00178 {% extends 'base.html' %}
00179 {% block 'block' %}
00180 {{1/0}}
00181 {% end %}
00182             """})
00183         try:
00184             loader.load("sub.html").generate()
00185         except ZeroDivisionError:
00186             self.assertTrue("# sub.html:4 (via base.html:1)" in
00187                             traceback.format_exc())
00188 
00189     def test_multi_includes(self):
00190         loader = DictLoader({
00191                 "a.html": "{% include 'b.html' %}",
00192                 "b.html": "{% include 'c.html' %}",
00193                 "c.html": "{{1/0}}",
00194                 })
00195         try:
00196             loader.load("a.html").generate()
00197         except ZeroDivisionError:
00198             self.assertTrue("# c.html:1 (via b.html:1, a.html:1)" in
00199                             traceback.format_exc())
00200 
00201 
00202 class AutoEscapeTest(LogTrapTestCase):
00203     def setUp(self):
00204         self.templates = {
00205             "escaped.html": "{% autoescape xhtml_escape %}{{ name }}",
00206             "unescaped.html": "{% autoescape None %}{{ name }}",
00207             "default.html": "{{ name }}",
00208 
00209             "include.html": """\
00210 escaped: {% include 'escaped.html' %}
00211 unescaped: {% include 'unescaped.html' %}
00212 default: {% include 'default.html' %}
00213 """,
00214 
00215             "escaped_block.html": """\
00216 {% autoescape xhtml_escape %}\
00217 {% block name %}base: {{ name }}{% end %}""",
00218             "unescaped_block.html": """\
00219 {% autoescape None %}\
00220 {% block name %}base: {{ name }}{% end %}""",
00221 
00222             # Extend a base template with different autoescape policy,
00223             # with and without overriding the base's blocks
00224             "escaped_extends_unescaped.html": """\
00225 {% autoescape xhtml_escape %}\
00226 {% extends "unescaped_block.html" %}""",
00227             "escaped_overrides_unescaped.html": """\
00228 {% autoescape xhtml_escape %}\
00229 {% extends "unescaped_block.html" %}\
00230 {% block name %}extended: {{ name }}{% end %}""",
00231             "unescaped_extends_escaped.html": """\
00232 {% autoescape None %}\
00233 {% extends "escaped_block.html" %}""",
00234             "unescaped_overrides_escaped.html": """\
00235 {% autoescape None %}\
00236 {% extends "escaped_block.html" %}\
00237 {% block name %}extended: {{ name }}{% end %}""",
00238 
00239             "raw_expression.html": """\
00240 {% autoescape xhtml_escape %}\
00241 expr: {{ name }}
00242 raw: {% raw name %}""",
00243             }
00244 
00245     def test_default_off(self):
00246         loader = DictLoader(self.templates, autoescape=None)
00247         name = "Bobby <table>s"
00248         self.assertEqual(loader.load("escaped.html").generate(name=name),
00249                          b("Bobby &lt;table&gt;s"))
00250         self.assertEqual(loader.load("unescaped.html").generate(name=name),
00251                          b("Bobby <table>s"))
00252         self.assertEqual(loader.load("default.html").generate(name=name),
00253                          b("Bobby <table>s"))
00254 
00255         self.assertEqual(loader.load("include.html").generate(name=name),
00256                          b("escaped: Bobby &lt;table&gt;s\n"
00257                            "unescaped: Bobby <table>s\n"
00258                            "default: Bobby <table>s\n"))
00259 
00260     def test_default_on(self):
00261         loader = DictLoader(self.templates, autoescape="xhtml_escape")
00262         name = "Bobby <table>s"
00263         self.assertEqual(loader.load("escaped.html").generate(name=name),
00264                          b("Bobby &lt;table&gt;s"))
00265         self.assertEqual(loader.load("unescaped.html").generate(name=name),
00266                          b("Bobby <table>s"))
00267         self.assertEqual(loader.load("default.html").generate(name=name),
00268                          b("Bobby &lt;table&gt;s"))
00269 
00270         self.assertEqual(loader.load("include.html").generate(name=name),
00271                          b("escaped: Bobby &lt;table&gt;s\n"
00272                            "unescaped: Bobby <table>s\n"
00273                            "default: Bobby &lt;table&gt;s\n"))
00274 
00275     def test_unextended_block(self):
00276         loader = DictLoader(self.templates)
00277         name = "<script>"
00278         self.assertEqual(loader.load("escaped_block.html").generate(name=name),
00279                          b("base: &lt;script&gt;"))
00280         self.assertEqual(loader.load("unescaped_block.html").generate(name=name),
00281                          b("base: <script>"))
00282 
00283     def test_extended_block(self):
00284         loader = DictLoader(self.templates)
00285 
00286         def render(name):
00287             return loader.load(name).generate(name="<script>")
00288         self.assertEqual(render("escaped_extends_unescaped.html"),
00289                          b("base: <script>"))
00290         self.assertEqual(render("escaped_overrides_unescaped.html"),
00291                          b("extended: &lt;script&gt;"))
00292 
00293         self.assertEqual(render("unescaped_extends_escaped.html"),
00294                          b("base: &lt;script&gt;"))
00295         self.assertEqual(render("unescaped_overrides_escaped.html"),
00296                          b("extended: <script>"))
00297 
00298     def test_raw_expression(self):
00299         loader = DictLoader(self.templates)
00300 
00301         def render(name):
00302             return loader.load(name).generate(name='<>&"')
00303         self.assertEqual(render("raw_expression.html"),
00304                          b("expr: &lt;&gt;&amp;&quot;\n"
00305                            "raw: <>&\""))
00306 
00307     def test_custom_escape(self):
00308         loader = DictLoader({"foo.py":
00309                              "{% autoescape py_escape %}s = {{ name }}\n"})
00310 
00311         def py_escape(s):
00312             self.assertEqual(type(s), bytes_type)
00313             return repr(native_str(s))
00314 
00315         def render(template, name):
00316             return loader.load(template).generate(py_escape=py_escape,
00317                                                   name=name)
00318         self.assertEqual(render("foo.py", "<html>"),
00319                          b("s = '<html>'\n"))
00320         self.assertEqual(render("foo.py", "';sys.exit()"),
00321                          b("""s = "';sys.exit()"\n"""))
00322         self.assertEqual(render("foo.py", ["not a string"]),
00323                          b("""s = "['not a string']"\n"""))
00324 
00325 
00326 class TemplateLoaderTest(LogTrapTestCase):
00327     def setUp(self):
00328         self.loader = Loader(os.path.join(os.path.dirname(__file__), "templates"))
00329 
00330     def test_utf8_in_file(self):
00331         tmpl = self.loader.load("utf8.html")
00332         result = tmpl.generate()
00333         self.assertEqual(to_unicode(result).strip(), u"H\u00e9llo")


rosbridge_server
Author(s): Jonathan Mace
autogenerated on Thu Jan 2 2014 11:53:55