Run `./2to3.py -w jinja2`
[jinja2.git] / jinja2 / testsuite / core_tags.py
1 # -*- coding: utf-8 -*-
2 """
3     jinja2.testsuite.core_tags
4     ~~~~~~~~~~~~~~~~~~~~~~~~~~
5
6     Test the core tags like for and if.
7
8     :copyright: (c) 2010 by the Jinja Team.
9     :license: BSD, see LICENSE for more details.
10 """
11 import unittest
12
13 from jinja2.testsuite import JinjaTestCase
14
15 from jinja2 import Environment, TemplateSyntaxError, UndefinedError, \
16      DictLoader
17
18 env = Environment()
19
20
21 class ForLoopTestCase(JinjaTestCase):
22
23     def test_simple(self):
24         tmpl = env.from_string('{% for item in seq %}{{ item }}{% endfor %}')
25         assert tmpl.render(seq=list(range(10))) == '0123456789'
26
27     def test_else(self):
28         tmpl = env.from_string('{% for item in seq %}XXX{% else %}...{% endfor %}')
29         assert tmpl.render() == '...'
30
31     def test_empty_blocks(self):
32         tmpl = env.from_string('<{% for item in seq %}{% else %}{% endfor %}>')
33         assert tmpl.render() == '<>'
34
35     def test_context_vars(self):
36         tmpl = env.from_string('''{% for item in seq -%}
37         {{ loop.index }}|{{ loop.index0 }}|{{ loop.revindex }}|{{
38             loop.revindex0 }}|{{ loop.first }}|{{ loop.last }}|{{
39            loop.length }}###{% endfor %}''')
40         one, two, _ = tmpl.render(seq=[0, 1]).split('###')
41         (one_index, one_index0, one_revindex, one_revindex0, one_first,
42          one_last, one_length) = one.split('|')
43         (two_index, two_index0, two_revindex, two_revindex0, two_first,
44          two_last, two_length) = two.split('|')
45
46         assert int(one_index) == 1 and int(two_index) == 2
47         assert int(one_index0) == 0 and int(two_index0) == 1
48         assert int(one_revindex) == 2 and int(two_revindex) == 1
49         assert int(one_revindex0) == 1 and int(two_revindex0) == 0
50         assert one_first == 'True' and two_first == 'False'
51         assert one_last == 'False' and two_last == 'True'
52         assert one_length == two_length == '2'
53
54     def test_cycling(self):
55         tmpl = env.from_string('''{% for item in seq %}{{
56             loop.cycle('<1>', '<2>') }}{% endfor %}{%
57             for item in seq %}{{ loop.cycle(*through) }}{% endfor %}''')
58         output = tmpl.render(seq=list(range(4)), through=('<1>', '<2>'))
59         assert output == '<1><2>' * 4
60
61     def test_scope(self):
62         tmpl = env.from_string('{% for item in seq %}{% endfor %}{{ item }}')
63         output = tmpl.render(seq=list(range(10)))
64         assert not output
65
66     def test_varlen(self):
67         def inner():
68             for item in range(5):
69                 yield item
70         tmpl = env.from_string('{% for item in iter %}{{ item }}{% endfor %}')
71         output = tmpl.render(iter=inner())
72         assert output == '01234'
73
74     def test_noniter(self):
75         tmpl = env.from_string('{% for item in none %}...{% endfor %}')
76         self.assert_raises(TypeError, tmpl.render)
77
78     def test_recursive(self):
79         tmpl = env.from_string('''{% for item in seq recursive -%}
80             [{{ item.a }}{% if item.b %}<{{ loop(item.b) }}>{% endif %}]
81         {%- endfor %}''')
82         assert tmpl.render(seq=[
83             dict(a=1, b=[dict(a=1), dict(a=2)]),
84             dict(a=2, b=[dict(a=1), dict(a=2)]),
85             dict(a=3, b=[dict(a='a')])
86         ]) == '[1<[1][2]>][2<[1][2]>][3<[a]>]'
87
88     def test_looploop(self):
89         tmpl = env.from_string('''{% for row in table %}
90             {%- set rowloop = loop -%}
91             {% for cell in row -%}
92                 [{{ rowloop.index }}|{{ loop.index }}]
93             {%- endfor %}
94         {%- endfor %}''')
95         assert tmpl.render(table=['ab', 'cd']) == '[1|1][1|2][2|1][2|2]'
96
97     def test_reversed_bug(self):
98         tmpl = env.from_string('{% for i in items %}{{ i }}'
99                                '{% if not loop.last %}'
100                                ',{% endif %}{% endfor %}')
101         assert tmpl.render(items=reversed([3, 2, 1])) == '1,2,3'
102
103     def test_loop_errors(self):
104         tmpl = env.from_string('''{% for item in [1] if loop.index
105                                       == 0 %}...{% endfor %}''')
106         self.assert_raises(UndefinedError, tmpl.render)
107         tmpl = env.from_string('''{% for item in [] %}...{% else
108             %}{{ loop }}{% endfor %}''')
109         assert tmpl.render() == ''
110
111     def test_loop_filter(self):
112         tmpl = env.from_string('{% for item in range(10) if item '
113                                'is even %}[{{ item }}]{% endfor %}')
114         assert tmpl.render() == '[0][2][4][6][8]'
115         tmpl = env.from_string('''
116             {%- for item in range(10) if item is even %}[{{
117                 loop.index }}:{{ item }}]{% endfor %}''')
118         assert tmpl.render() == '[1:0][2:2][3:4][4:6][5:8]'
119
120     def test_loop_unassignable(self):
121         self.assert_raises(TemplateSyntaxError, env.from_string,
122                            '{% for loop in seq %}...{% endfor %}')
123
124     def test_scoped_special_var(self):
125         t = env.from_string('{% for s in seq %}[{{ loop.first }}{% for c in s %}'
126                             '|{{ loop.first }}{% endfor %}]{% endfor %}')
127         assert t.render(seq=('ab', 'cd')) == '[True|True|False][False|True|False]'
128
129     def test_scoped_loop_var(self):
130         t = env.from_string('{% for x in seq %}{{ loop.first }}'
131                             '{% for y in seq %}{% endfor %}{% endfor %}')
132         assert t.render(seq='ab') == 'TrueFalse'
133         t = env.from_string('{% for x in seq %}{% for y in seq %}'
134                             '{{ loop.first }}{% endfor %}{% endfor %}')
135         assert t.render(seq='ab') == 'TrueFalseTrueFalse'
136
137     def test_recursive_empty_loop_iter(self):
138         t = env.from_string('''
139         {%- for item in foo recursive -%}{%- endfor -%}
140         ''')
141         assert t.render(dict(foo=[])) == ''
142
143     def test_call_in_loop(self):
144         t = env.from_string('''
145         {%- macro do_something() -%}
146             [{{ caller() }}]
147         {%- endmacro %}
148
149         {%- for i in [1, 2, 3] %}
150             {%- call do_something() -%}
151                 {{ i }}
152             {%- endcall %}
153         {%- endfor -%}
154         ''')
155         assert t.render() == '[1][2][3]'
156
157     def test_scoping_bug(self):
158         t = env.from_string('''
159         {%- for item in foo %}...{{ item }}...{% endfor %}
160         {%- macro item(a) %}...{{ a }}...{% endmacro %}
161         {{- item(2) -}}
162         ''')
163         assert t.render(foo=(1,)) == '...1......2...'
164
165     def test_unpacking(self):
166         tmpl = env.from_string('{% for a, b, c in [[1, 2, 3]] %}'
167             '{{ a }}|{{ b }}|{{ c }}{% endfor %}')
168         assert tmpl.render() == '1|2|3'
169
170
171 class IfConditionTestCase(JinjaTestCase):
172
173     def test_simple(self):
174         tmpl = env.from_string('''{% if true %}...{% endif %}''')
175         assert tmpl.render() == '...'
176
177     def test_elif(self):
178         tmpl = env.from_string('''{% if false %}XXX{% elif true
179             %}...{% else %}XXX{% endif %}''')
180         assert tmpl.render() == '...'
181
182     def test_else(self):
183         tmpl = env.from_string('{% if false %}XXX{% else %}...{% endif %}')
184         assert tmpl.render() == '...'
185
186     def test_empty(self):
187         tmpl = env.from_string('[{% if true %}{% else %}{% endif %}]')
188         assert tmpl.render() == '[]'
189
190     def test_complete(self):
191         tmpl = env.from_string('{% if a %}A{% elif b %}B{% elif c == d %}'
192                                'C{% else %}D{% endif %}')
193         assert tmpl.render(a=0, b=False, c=42, d=42.0) == 'C'
194
195     def test_no_scope(self):
196         tmpl = env.from_string('{% if a %}{% set foo = 1 %}{% endif %}{{ foo }}')
197         assert tmpl.render(a=True) == '1'
198         tmpl = env.from_string('{% if true %}{% set foo = 1 %}{% endif %}{{ foo }}')
199         assert tmpl.render() == '1'
200
201
202 class MacrosTestCase(JinjaTestCase):
203     env = Environment(trim_blocks=True)
204
205     def test_simple(self):
206         tmpl = self.env.from_string('''\
207 {% macro say_hello(name) %}Hello {{ name }}!{% endmacro %}
208 {{ say_hello('Peter') }}''')
209         assert tmpl.render() == 'Hello Peter!'
210
211     def test_scoping(self):
212         tmpl = self.env.from_string('''\
213 {% macro level1(data1) %}
214 {% macro level2(data2) %}{{ data1 }}|{{ data2 }}{% endmacro %}
215 {{ level2('bar') }}{% endmacro %}
216 {{ level1('foo') }}''')
217         assert tmpl.render() == 'foo|bar'
218
219     def test_arguments(self):
220         tmpl = self.env.from_string('''\
221 {% macro m(a, b, c='c', d='d') %}{{ a }}|{{ b }}|{{ c }}|{{ d }}{% endmacro %}
222 {{ m() }}|{{ m('a') }}|{{ m('a', 'b') }}|{{ m(1, 2, 3) }}''')
223         assert tmpl.render() == '||c|d|a||c|d|a|b|c|d|1|2|3|d'
224
225     def test_varargs(self):
226         tmpl = self.env.from_string('''\
227 {% macro test() %}{{ varargs|join('|') }}{% endmacro %}\
228 {{ test(1, 2, 3) }}''')
229         assert tmpl.render() == '1|2|3'
230
231     def test_simple_call(self):
232         tmpl = self.env.from_string('''\
233 {% macro test() %}[[{{ caller() }}]]{% endmacro %}\
234 {% call test() %}data{% endcall %}''')
235         assert tmpl.render() == '[[data]]'
236
237     def test_complex_call(self):
238         tmpl = self.env.from_string('''\
239 {% macro test() %}[[{{ caller('data') }}]]{% endmacro %}\
240 {% call(data) test() %}{{ data }}{% endcall %}''')
241         assert tmpl.render() == '[[data]]'
242
243     def test_caller_undefined(self):
244         tmpl = self.env.from_string('''\
245 {% set caller = 42 %}\
246 {% macro test() %}{{ caller is not defined }}{% endmacro %}\
247 {{ test() }}''')
248         assert tmpl.render() == 'True'
249
250     def test_include(self):
251         self.env = Environment(loader=DictLoader({'include':
252             '{% macro test(foo) %}[{{ foo }}]{% endmacro %}'}))
253         tmpl = self.env.from_string('{% from "include" import test %}{{ test("foo") }}')
254         assert tmpl.render() == '[foo]'
255
256     def test_macro_api(self):
257         tmpl = self.env.from_string('{% macro foo(a, b) %}{% endmacro %}'
258                                '{% macro bar() %}{{ varargs }}{{ kwargs }}{% endmacro %}'
259                                '{% macro baz() %}{{ caller() }}{% endmacro %}')
260         assert tmpl.module.foo.arguments == ('a', 'b')
261         assert tmpl.module.foo.defaults == ()
262         assert tmpl.module.foo.name == 'foo'
263         assert not tmpl.module.foo.caller
264         assert not tmpl.module.foo.catch_kwargs
265         assert not tmpl.module.foo.catch_varargs
266         assert tmpl.module.bar.arguments == ()
267         assert tmpl.module.bar.defaults == ()
268         assert not tmpl.module.bar.caller
269         assert tmpl.module.bar.catch_kwargs
270         assert tmpl.module.bar.catch_varargs
271         assert tmpl.module.baz.caller
272
273     def test_callself(self):
274         tmpl = self.env.from_string('{% macro foo(x) %}{{ x }}{% if x > 1 %}|'
275                                     '{{ foo(x - 1) }}{% endif %}{% endmacro %}'
276                                     '{{ foo(5) }}')
277         assert tmpl.render() == '5|4|3|2|1'
278
279
280 def suite():
281     suite = unittest.TestSuite()
282     suite.addTest(unittest.makeSuite(ForLoopTestCase))
283     suite.addTest(unittest.makeSuite(IfConditionTestCase))
284     suite.addTest(unittest.makeSuite(MacrosTestCase))
285     return suite