regression.py 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279
  1. # -*- coding: utf-8 -*-
  2. """
  3. jinja2.testsuite.regression
  4. ~~~~~~~~~~~~~~~~~~~~~~~~~~~
  5. Tests corner cases and bugs.
  6. :copyright: (c) 2010 by the Jinja Team.
  7. :license: BSD, see LICENSE for more details.
  8. """
  9. import unittest
  10. from jinja2.testsuite import JinjaTestCase
  11. from jinja2 import Template, Environment, DictLoader, TemplateSyntaxError, \
  12. TemplateNotFound, PrefixLoader
  13. from jinja2._compat import text_type
  14. env = Environment()
  15. class CornerTestCase(JinjaTestCase):
  16. def test_assigned_scoping(self):
  17. t = env.from_string('''
  18. {%- for item in (1, 2, 3, 4) -%}
  19. [{{ item }}]
  20. {%- endfor %}
  21. {{- item -}}
  22. ''')
  23. assert t.render(item=42) == '[1][2][3][4]42'
  24. t = env.from_string('''
  25. {%- for item in (1, 2, 3, 4) -%}
  26. [{{ item }}]
  27. {%- endfor %}
  28. {%- set item = 42 %}
  29. {{- item -}}
  30. ''')
  31. assert t.render() == '[1][2][3][4]42'
  32. t = env.from_string('''
  33. {%- set item = 42 %}
  34. {%- for item in (1, 2, 3, 4) -%}
  35. [{{ item }}]
  36. {%- endfor %}
  37. {{- item -}}
  38. ''')
  39. assert t.render() == '[1][2][3][4]42'
  40. def test_closure_scoping(self):
  41. t = env.from_string('''
  42. {%- set wrapper = "<FOO>" %}
  43. {%- for item in (1, 2, 3, 4) %}
  44. {%- macro wrapper() %}[{{ item }}]{% endmacro %}
  45. {{- wrapper() }}
  46. {%- endfor %}
  47. {{- wrapper -}}
  48. ''')
  49. assert t.render() == '[1][2][3][4]<FOO>'
  50. t = env.from_string('''
  51. {%- for item in (1, 2, 3, 4) %}
  52. {%- macro wrapper() %}[{{ item }}]{% endmacro %}
  53. {{- wrapper() }}
  54. {%- endfor %}
  55. {%- set wrapper = "<FOO>" %}
  56. {{- wrapper -}}
  57. ''')
  58. assert t.render() == '[1][2][3][4]<FOO>'
  59. t = env.from_string('''
  60. {%- for item in (1, 2, 3, 4) %}
  61. {%- macro wrapper() %}[{{ item }}]{% endmacro %}
  62. {{- wrapper() }}
  63. {%- endfor %}
  64. {{- wrapper -}}
  65. ''')
  66. assert t.render(wrapper=23) == '[1][2][3][4]23'
  67. class BugTestCase(JinjaTestCase):
  68. def test_keyword_folding(self):
  69. env = Environment()
  70. env.filters['testing'] = lambda value, some: value + some
  71. assert env.from_string("{{ 'test'|testing(some='stuff') }}") \
  72. .render() == 'teststuff'
  73. def test_extends_output_bugs(self):
  74. env = Environment(loader=DictLoader({
  75. 'parent.html': '(({% block title %}{% endblock %}))'
  76. }))
  77. t = env.from_string('{% if expr %}{% extends "parent.html" %}{% endif %}'
  78. '[[{% block title %}title{% endblock %}]]'
  79. '{% for item in [1, 2, 3] %}({{ item }}){% endfor %}')
  80. assert t.render(expr=False) == '[[title]](1)(2)(3)'
  81. assert t.render(expr=True) == '((title))'
  82. def test_urlize_filter_escaping(self):
  83. tmpl = env.from_string('{{ "http://www.example.org/<foo"|urlize }}')
  84. assert tmpl.render() == '<a href="http://www.example.org/&lt;foo">http://www.example.org/&lt;foo</a>'
  85. def test_loop_call_loop(self):
  86. tmpl = env.from_string('''
  87. {% macro test() %}
  88. {{ caller() }}
  89. {% endmacro %}
  90. {% for num1 in range(5) %}
  91. {% call test() %}
  92. {% for num2 in range(10) %}
  93. {{ loop.index }}
  94. {% endfor %}
  95. {% endcall %}
  96. {% endfor %}
  97. ''')
  98. assert tmpl.render().split() == [text_type(x) for x in range(1, 11)] * 5
  99. def test_weird_inline_comment(self):
  100. env = Environment(line_statement_prefix='%')
  101. self.assert_raises(TemplateSyntaxError, env.from_string,
  102. '% for item in seq {# missing #}\n...% endfor')
  103. def test_old_macro_loop_scoping_bug(self):
  104. tmpl = env.from_string('{% for i in (1, 2) %}{{ i }}{% endfor %}'
  105. '{% macro i() %}3{% endmacro %}{{ i() }}')
  106. assert tmpl.render() == '123'
  107. def test_partial_conditional_assignments(self):
  108. tmpl = env.from_string('{% if b %}{% set a = 42 %}{% endif %}{{ a }}')
  109. assert tmpl.render(a=23) == '23'
  110. assert tmpl.render(b=True) == '42'
  111. def test_stacked_locals_scoping_bug(self):
  112. env = Environment(line_statement_prefix='#')
  113. t = env.from_string('''\
  114. # for j in [1, 2]:
  115. # set x = 1
  116. # for i in [1, 2]:
  117. # print x
  118. # if i % 2 == 0:
  119. # set x = x + 1
  120. # endif
  121. # endfor
  122. # endfor
  123. # if a
  124. # print 'A'
  125. # elif b
  126. # print 'B'
  127. # elif c == d
  128. # print 'C'
  129. # else
  130. # print 'D'
  131. # endif
  132. ''')
  133. assert t.render(a=0, b=False, c=42, d=42.0) == '1111C'
  134. def test_stacked_locals_scoping_bug_twoframe(self):
  135. t = Template('''
  136. {% set x = 1 %}
  137. {% for item in foo %}
  138. {% if item == 1 %}
  139. {% set x = 2 %}
  140. {% endif %}
  141. {% endfor %}
  142. {{ x }}
  143. ''')
  144. rv = t.render(foo=[1]).strip()
  145. assert rv == u'1'
  146. def test_call_with_args(self):
  147. t = Template("""{% macro dump_users(users) -%}
  148. <ul>
  149. {%- for user in users -%}
  150. <li><p>{{ user.username|e }}</p>{{ caller(user) }}</li>
  151. {%- endfor -%}
  152. </ul>
  153. {%- endmacro -%}
  154. {% call(user) dump_users(list_of_user) -%}
  155. <dl>
  156. <dl>Realname</dl>
  157. <dd>{{ user.realname|e }}</dd>
  158. <dl>Description</dl>
  159. <dd>{{ user.description }}</dd>
  160. </dl>
  161. {% endcall %}""")
  162. assert [x.strip() for x in t.render(list_of_user=[{
  163. 'username':'apo',
  164. 'realname':'something else',
  165. 'description':'test'
  166. }]).splitlines()] == [
  167. u'<ul><li><p>apo</p><dl>',
  168. u'<dl>Realname</dl>',
  169. u'<dd>something else</dd>',
  170. u'<dl>Description</dl>',
  171. u'<dd>test</dd>',
  172. u'</dl>',
  173. u'</li></ul>'
  174. ]
  175. def test_empty_if_condition_fails(self):
  176. self.assert_raises(TemplateSyntaxError, Template, '{% if %}....{% endif %}')
  177. self.assert_raises(TemplateSyntaxError, Template, '{% if foo %}...{% elif %}...{% endif %}')
  178. self.assert_raises(TemplateSyntaxError, Template, '{% for x in %}..{% endfor %}')
  179. def test_recursive_loop_bug(self):
  180. tpl1 = Template("""
  181. {% for p in foo recursive%}
  182. {{p.bar}}
  183. {% for f in p.fields recursive%}
  184. {{f.baz}}
  185. {{p.bar}}
  186. {% if f.rec %}
  187. {{ loop(f.sub) }}
  188. {% endif %}
  189. {% endfor %}
  190. {% endfor %}
  191. """)
  192. tpl2 = Template("""
  193. {% for p in foo%}
  194. {{p.bar}}
  195. {% for f in p.fields recursive%}
  196. {{f.baz}}
  197. {{p.bar}}
  198. {% if f.rec %}
  199. {{ loop(f.sub) }}
  200. {% endif %}
  201. {% endfor %}
  202. {% endfor %}
  203. """)
  204. def test_else_loop_bug(self):
  205. t = Template('''
  206. {% for x in y %}
  207. {{ loop.index0 }}
  208. {% else %}
  209. {% for i in range(3) %}{{ i }}{% endfor %}
  210. {% endfor %}
  211. ''')
  212. self.assertEqual(t.render(y=[]).strip(), '012')
  213. def test_correct_prefix_loader_name(self):
  214. env = Environment(loader=PrefixLoader({
  215. 'foo': DictLoader({})
  216. }))
  217. try:
  218. env.get_template('foo/bar.html')
  219. except TemplateNotFound as e:
  220. assert e.name == 'foo/bar.html'
  221. else:
  222. assert False, 'expected error here'
  223. def test_contextfunction_callable_classes(self):
  224. from jinja2.utils import contextfunction
  225. class CallableClass(object):
  226. @contextfunction
  227. def __call__(self, ctx):
  228. return ctx.resolve('hello')
  229. tpl = Template("""{{ callableclass() }}""")
  230. output = tpl.render(callableclass = CallableClass(), hello = 'TEST')
  231. expected = 'TEST'
  232. self.assert_equal(output, expected)
  233. def suite():
  234. suite = unittest.TestSuite()
  235. suite.addTest(unittest.makeSuite(CornerTestCase))
  236. suite.addTest(unittest.makeSuite(BugTestCase))
  237. return suite