blob: ef33de7ec608f6c194b2d6c32cb71e229fd74578 [file] [log] [blame]
Armin Ronacher3da90312008-05-23 16:37:28 +02001# -*- coding: utf-8 -*-
2"""
3 unit test for some extensions
4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5
Armin Ronacher62ccd1b2009-01-04 14:26:19 +01006 :copyright: (c) 2009 by the Jinja Team.
Armin Ronacher3da90312008-05-23 16:37:28 +02007 :license: BSD, see LICENSE for more details.
8"""
Armin Ronacher3e3a9be2008-06-14 12:44:15 +02009import re
Armin Ronacher6df604e2008-05-23 22:18:38 +020010from jinja2 import Environment, nodes
Armin Ronacherd02fc7d2008-06-14 14:19:47 +020011from jinja2.ext import Extension
12from jinja2.lexer import Token, count_newlines
Armin Ronacher6df604e2008-05-23 22:18:38 +020013
14
15importable_object = 23
16
17
Armin Ronacher9e6400e2009-09-14 14:58:01 -070018_gettext_re = re.compile(r'_\((.*?)\)(?s)')
Armin Ronacher3e3a9be2008-06-14 12:44:15 +020019
20
Armin Ronacher6df604e2008-05-23 22:18:38 +020021class TestExtension(Extension):
22 tags = set(['test'])
23 ext_attr = 42
24
25 def parse(self, parser):
26 return nodes.Output([self.call_method('_dump', [
27 nodes.EnvironmentAttribute('sandboxed'),
28 self.attr('ext_attr'),
29 nodes.ImportedName(__name__ + '.importable_object'),
30 nodes.ContextReference()
31 ])]).set_lineno(parser.stream.next().lineno)
32
33 def _dump(self, sandboxed, ext_attr, imported_object, context):
34 return '%s|%s|%s|%s' % (
35 sandboxed,
36 ext_attr,
37 imported_object,
38 context.blocks
39 )
Armin Ronacher3da90312008-05-23 16:37:28 +020040
41
Armin Ronacher3e3a9be2008-06-14 12:44:15 +020042class PreprocessorExtension(Extension):
43
44 def preprocess(self, source, name, filename=None):
45 return source.replace('[[TEST]]', '({{ foo }})')
46
47
48class StreamFilterExtension(Extension):
49
50 def filter_stream(self, stream):
51 for token in stream:
Armin Ronacher9e6400e2009-09-14 14:58:01 -070052 if token.type == 'data':
Armin Ronacher3e3a9be2008-06-14 12:44:15 +020053 for t in self.interpolate(token):
54 yield t
55 else:
56 yield token
57
Armin Ronacher3e3a9be2008-06-14 12:44:15 +020058 def interpolate(self, token):
59 pos = 0
60 end = len(token.value)
61 lineno = token.lineno
62 while 1:
63 match = _gettext_re.search(token.value, pos)
64 if match is None:
65 break
66 value = token.value[pos:match.start()]
67 if value:
68 yield Token(lineno, 'data', value)
Armin Ronacherd02fc7d2008-06-14 14:19:47 +020069 lineno += count_newlines(token.value)
Armin Ronacher3e3a9be2008-06-14 12:44:15 +020070 yield Token(lineno, 'variable_begin', None)
71 yield Token(lineno, 'name', 'gettext')
72 yield Token(lineno, 'lparen', None)
73 yield Token(lineno, 'string', match.group(1))
74 yield Token(lineno, 'rparen', None)
75 yield Token(lineno, 'variable_end', None)
76 pos = match.end()
77 if pos < end:
78 yield Token(lineno, 'data', token.value[pos:])
79
80
Armin Ronacher3da90312008-05-23 16:37:28 +020081def test_loop_controls():
82 env = Environment(extensions=['jinja2.ext.loopcontrols'])
83
84 tmpl = env.from_string('''
85 {%- for item in [1, 2, 3, 4] %}
86 {%- if item % 2 == 0 %}{% continue %}{% endif -%}
87 {{ item }}
88 {%- endfor %}''')
89 assert tmpl.render() == '13'
90
91 tmpl = env.from_string('''
92 {%- for item in [1, 2, 3, 4] %}
93 {%- if item > 2 %}{% break %}{% endif -%}
94 {{ item }}
95 {%- endfor %}''')
96 assert tmpl.render() == '12'
97
98
99def test_do():
100 env = Environment(extensions=['jinja2.ext.do'])
101 tmpl = env.from_string('''
102 {%- set items = [] %}
103 {%- for char in "foo" %}
104 {%- do items.append(loop.index0 ~ char) %}
105 {%- endfor %}{{ items|join(', ') }}''')
106 assert tmpl.render() == '0f, 1o, 2o'
Armin Ronacher6df604e2008-05-23 22:18:38 +0200107
108
Armin Ronacher9b4cc9f2010-02-07 03:55:15 +0100109def test_with():
110 env = Environment(extensions=['jinja2.ext.with_'])
111 tmpl = env.from_string('''\
112 {% with a=42, b=23 -%}
113 {{ a }} = {{ b }}
114 {% endwith -%}
115 {{ a }} = {{ b }}\
116 ''')
117 assert [x.strip() for x in tmpl.render(a=1, b=2).splitlines()] \
118 == ['42 = 23', '1 = 2']
119
120
Armin Ronacher6df604e2008-05-23 22:18:38 +0200121def test_extension_nodes():
122 env = Environment(extensions=[TestExtension])
123 tmpl = env.from_string('{% test %}')
124 assert tmpl.render() == 'False|42|23|{}'
Armin Ronacher9cf95912008-05-24 19:54:43 +0200125
126
127def test_identifier():
128 assert TestExtension.identifier == __name__ + '.TestExtension'
Armin Ronacher9f258ff2008-05-24 22:28:52 +0200129
130
131def test_rebinding():
132 original = Environment(extensions=[TestExtension])
133 overlay = original.overlay()
134 for env in original, overlay:
135 for ext in env.extensions.itervalues():
136 assert ext.environment is env
Armin Ronacher3e3a9be2008-06-14 12:44:15 +0200137
138
139def test_preprocessor_extension():
140 env = Environment(extensions=[PreprocessorExtension])
141 tmpl = env.from_string('{[[TEST]]}')
142 assert tmpl.render(foo=42) == '{(42)}'
143
144
145def test_streamfilter_extension():
146 env = Environment(extensions=[StreamFilterExtension])
Armin Ronacher9e6400e2009-09-14 14:58:01 -0700147 env.globals['gettext'] = lambda x: x.upper()
Armin Ronacher3e3a9be2008-06-14 12:44:15 +0200148 tmpl = env.from_string('Foo _(bar) Baz')
Armin Ronacher9e6400e2009-09-14 14:58:01 -0700149 out = tmpl.render()
150 assert out == 'Foo BAR Baz'
Armin Ronacher271a0eb2009-02-11 22:49:08 +0100151
152
153class WithExtension(Extension):
154 tags = frozenset(['with'])
155
156 def parse(self, parser):
157 lineno = parser.stream.next().lineno
158 value = parser.parse_expression()
159 parser.stream.expect('name:as')
160 name = parser.stream.expect('name')
161
162 body = parser.parse_statements(['name:endwith'], drop_needle=True)
163 body.insert(0, nodes.Assign(nodes.Name(name.value, 'store'), value))
164 return nodes.Scope(body)
165
166
167def test_with_extension():
168 env = Environment(extensions=[WithExtension])
169 t = env.from_string('{{ a }}{% with 2 as a %}{{ a }}{% endwith %}{{ a }}')
170 assert t.render(a=1) == '121'
171
172 t = env.from_string('{% with 2 as a %}{{ a }}{% endwith %}{{ a }}')
173 assert t.render(a=3) == '23'