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