Removed optional speedups extension hack.
[jinja2.git] / tests / test_syntax.py
1 # -*- coding: utf-8 -*-
2 """
3     unit test for expression syntax
4     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5
6     :copyright: 2007 by Armin Ronacher.
7     :license: BSD, see LICENSE for more details.
8 """
9 from py.test import raises
10 from jinja2 import Environment, DictLoader
11 from jinja2.exceptions import TemplateSyntaxError, UndefinedError
12
13
14 CALL = '''{{ foo('a', c='d', e='f', *['b'], **{'g': 'h'}) }}'''
15 SLICING = '''{{ [1, 2, 3][:] }}|{{ [1, 2, 3][::-1] }}'''
16 ATTR = '''{{ foo.bar }}|{{ foo['bar'] }}'''
17 SUBSCRIPT = '''{{ foo[0] }}|{{ foo[-1] }}'''
18 TUPLE = '''{{ () }}|{{ (1,) }}|{{ (1, 2) }}'''
19 MATH = '''{{ (1 + 1 * 2) - 3 / 2 }}|{{ 2**3 }}'''
20 DIV = '''{{ 3 // 2 }}|{{ 3 / 2 }}|{{ 3 % 2 }}'''
21 UNARY = '''{{ +3 }}|{{ -3 }}'''
22 CONCAT = '''{{ [1, 2] ~ 'foo' }}'''
23 COMPARE = '''{{ 1 > 0 }}|{{ 1 >= 1 }}|{{ 2 < 3 }}|{{ 2 == 2 }}|{{ 1 <= 1 }}'''
24 INOP = '''{{ 1 in [1, 2, 3] }}|{{ 1 not in [1, 2, 3] }}'''
25 LITERALS = '''{{ [] }}|{{ {} }}|{{ () }}'''
26 BOOL = '''{{ true and false }}|{{ false or true }}|{{ not false }}'''
27 GROUPING = '''{{ (true and false) or (false and true) and not false }}'''
28 CONDEXPR = '''{{ 0 if true else 1 }}'''
29 DJANGOATTR = '''{{ [1, 2, 3].0 }}|{{ [[1]].0.0 }}'''
30 FILTERPRIORITY = '''{{ "foo"|upper + "bar"|upper }}'''
31 TUPLETEMPLATES = [
32     '{{ () }}',
33     '{{ (1, 2) }}',
34     '{{ (1, 2,) }}',
35     '{{ 1, }}',
36     '{{ 1, 2 }}',
37     '{% for foo, bar in seq %}...{% endfor %}',
38     '{% for x in foo, bar %}...{% endfor %}',
39     '{% for x in foo, %}...{% endfor %}'
40 ]
41 TRAILINGCOMMA = '''{{ (1, 2,) }}|{{ [1, 2,] }}|{{ {1: 2,} }}'''
42
43
44 def test_call():
45     from jinja2 import Environment
46     env = Environment()
47     env.globals['foo'] = lambda a, b, c, e, g: a + b + c + e + g
48     tmpl = env.from_string(CALL)
49     assert tmpl.render() == 'abdfh'
50
51
52 def test_slicing(env):
53     tmpl = env.from_string(SLICING)
54     assert tmpl.render() == '[1, 2, 3]|[3, 2, 1]'
55
56
57 def test_attr(env):
58     tmpl = env.from_string(ATTR)
59     assert tmpl.render(foo={'bar': 42}) == '42|42'
60
61
62 def test_subscript(env):
63     tmpl = env.from_string(SUBSCRIPT)
64     assert tmpl.render(foo=[0, 1, 2]) == '0|2'
65
66
67 def test_tuple(env):
68     tmpl = env.from_string(TUPLE)
69     assert tmpl.render() == '()|(1,)|(1, 2)'
70
71
72 def test_math(env):
73     tmpl = env.from_string(MATH)
74     assert tmpl.render() == '1.5|8'
75
76
77 def test_div(env):
78     tmpl = env.from_string(DIV)
79     assert tmpl.render() == '1|1.5|1'
80
81
82 def test_unary(env):
83     tmpl = env.from_string(UNARY)
84     assert tmpl.render() == '3|-3'
85
86
87 def test_concat(env):
88     tmpl = env.from_string(CONCAT)
89     assert tmpl.render() == '[1, 2]foo'
90
91
92 def test_compare(env):
93     tmpl = env.from_string(COMPARE)
94     assert tmpl.render() == 'True|True|True|True|True'
95
96
97 def test_inop(env):
98     tmpl = env.from_string(INOP)
99     assert tmpl.render() == 'True|False'
100
101
102 def test_literals(env):
103     tmpl = env.from_string(LITERALS)
104     assert tmpl.render().lower() == '[]|{}|()'
105
106
107 def test_bool(env):
108     tmpl = env.from_string(BOOL)
109     assert tmpl.render() == 'False|True|True'
110
111
112 def test_grouping(env):
113     tmpl = env.from_string(GROUPING)
114     assert tmpl.render() == 'False'
115
116
117 def test_django_attr(env):
118     tmpl = env.from_string(DJANGOATTR)
119     assert tmpl.render() == '1|1'
120
121
122 def test_conditional_expression(env):
123     tmpl = env.from_string(CONDEXPR)
124     assert tmpl.render() == '0'
125
126
127 def test_short_conditional_expression(env):
128     tmpl = env.from_string('<{{ 1 if false }}>')
129     assert tmpl.render() == '<>'
130
131     tmpl = env.from_string('<{{ (1 if false).bar }}>')
132     raises(UndefinedError, tmpl.render)
133
134
135 def test_filter_priority(env):
136     tmpl = env.from_string(FILTERPRIORITY)
137     assert tmpl.render() == 'FOOBAR'
138
139
140 def test_function_calls(env):
141     tests = [
142         (True, '*foo, bar'),
143         (True, '*foo, *bar'),
144         (True, '*foo, bar=42'),
145         (True, '**foo, *bar'),
146         (True, '**foo, bar'),
147         (False, 'foo, bar'),
148         (False, 'foo, bar=42'),
149         (False, 'foo, bar=23, *args'),
150         (False, 'a, b=c, *d, **e'),
151         (False, '*foo, **bar')
152     ]
153     for should_fail, sig in tests:
154         if should_fail:
155             raises(TemplateSyntaxError, env.from_string, '{{ foo(%s) }}' % sig)
156         else:
157             env.from_string('foo(%s)' % sig)
158
159
160 def test_tuple_expr(env):
161     for tmpl in TUPLETEMPLATES:
162         print tmpl
163         assert env.from_string(tmpl)
164
165
166 def test_trailing_comma(env):
167     tmpl = env.from_string(TRAILINGCOMMA)
168     assert tmpl.render().lower() == '(1, 2)|[1, 2]|{1: 2}'
169
170
171 def test_block_end_name(env):
172     env.from_string('{% block foo %}...{% endblock foo %}')
173     raises(TemplateSyntaxError, env.from_string, '{% block x %}{% endblock y %}')
174
175
176 def test_contant_casing(env):
177     for const in True, False, None:
178         tmpl = env.from_string('{{ %s }}|{{ %s }}|{{ %s }}' % (
179             str(const), str(const).lower(), str(const).upper()
180         ))
181         assert tmpl.render() == '%s|%s|' % (const, const)
182
183
184 def test_test_chaining(env):
185     raises(TemplateSyntaxError, env.from_string, '{{ foo is string is sequence }}')
186     env.from_string('{{ 42 is string or 42 is number }}').render() == 'True'
187
188
189 def test_string_concatenation(env):
190     tmpl = env.from_string('{{ "foo" "bar" "baz" }}')
191     assert tmpl.render() == 'foobarbaz'