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 | |
| 6 | :copyright: 2007 by Armin Ronacher. |
| 7 | :license: BSD, see LICENSE for more details. |
| 8 | """ |
Armin Ronacher | 1cc232c | 2007-09-07 17:52:41 +0200 | [diff] [blame] | 9 | from jinja import Environment, DictLoader |
| 10 | from jinja.exceptions import TemplateSyntaxError |
| 11 | |
Armin Ronacher | ecc051b | 2007-06-01 18:25:28 +0200 | [diff] [blame] | 12 | |
| 13 | CALL = '''{{ foo('a', c='d', e='f', *['b'], **{'g': 'h'}) }}''' |
| 14 | SLICING = '''{{ [1, 2, 3][:] }}|{{ [1, 2, 3][::-1] }}''' |
| 15 | ATTR = '''{{ foo.bar }}|{{ foo['bar'] }}''' |
| 16 | SUBSCRIPT = '''{{ foo[0] }}|{{ foo[-1] }}''' |
| 17 | KEYATTR = '''{{ {'items': 'foo'}.items }}|{{ {}.items() }}''' |
Armin Ronacher | 1cc232c | 2007-09-07 17:52:41 +0200 | [diff] [blame] | 18 | TUPLE = '''{{ () }}|{{ (1,) }}|{{ (1, 2) }}''' |
Armin Ronacher | ecc051b | 2007-06-01 18:25:28 +0200 | [diff] [blame] | 19 | MATH = '''{{ (1 + 1 * 2) - 3 / 2 }}|{{ 2**3 }}''' |
| 20 | DIV = '''{{ 3 // 2 }}|{{ 3 / 2 }}|{{ 3 % 2 }}''' |
| 21 | UNARY = '''{{ +3 }}|{{ -3 }}''' |
Armin Ronacher | 1cc232c | 2007-09-07 17:52:41 +0200 | [diff] [blame] | 22 | CONCAT = '''{{ [1, 2] ~ 'foo' }}''' |
Armin Ronacher | ecc051b | 2007-06-01 18:25:28 +0200 | [diff] [blame] | 23 | COMPARE = '''{{ 1 > 0 }}|{{ 1 >= 1 }}|{{ 2 < 3 }}|{{ 2 == 2 }}|{{ 1 <= 1 }}''' |
Armin Ronacher | 1cc232c | 2007-09-07 17:52:41 +0200 | [diff] [blame] | 24 | INOP = '''{{ 1 in [1, 2, 3] }}|{{ 1 not in [1, 2, 3] }}''' |
| 25 | LITERALS = '''{{ [] }}|{{ {} }}|{{ () }}|{{ '' }}|{{ @() }}''' |
Armin Ronacher | ecc051b | 2007-06-01 18:25:28 +0200 | [diff] [blame] | 26 | BOOL = '''{{ true and false }}|{{ false or true }}|{{ not false }}''' |
Armin Ronacher | db69d0a | 2007-06-02 01:35:53 +0200 | [diff] [blame] | 27 | GROUPING = '''{{ (true and false) or (false and true) and not false }}''' |
Armin Ronacher | 1cc232c | 2007-09-07 17:52:41 +0200 | [diff] [blame] | 28 | CONDEXPR = '''{{ 0 if true else 1 }}''' |
| 29 | DJANGOATTR = '''{{ [1, 2, 3].0 }}''' |
| 30 | FILTERPRIORITY = '''{{ "foo"|upper + "bar"|upper }}''' |
Armin Ronacher | 1dcdac5 | 2007-12-09 22:53:46 +0100 | [diff] [blame^] | 31 | REGEX = r'''{{ @/\S+/.findall('foo bar baz') }}''' |
Armin Ronacher | 1cc232c | 2007-09-07 17:52:41 +0200 | [diff] [blame] | 32 | TUPLETEMPLATES = [ |
| 33 | '{{ () }}', |
| 34 | '{{ (1, 2) }}', |
| 35 | '{{ (1, 2,) }}', |
| 36 | '{{ 1, }}', |
| 37 | '{{ 1, 2 }}', |
| 38 | '{% for foo, bar in seq %}...{% endfor %}', |
| 39 | '{% for x in foo, bar %}...{% endfor %}', |
| 40 | '{% for x in foo, %}...{% endfor %}', |
| 41 | '{% for x in foo, recursive %}...{% endfor %}', |
| 42 | '{% for x in foo, bar recursive %}...{% endfor %}', |
| 43 | '{% for x, in foo, recursive %}...{% endfor %}' |
| 44 | ] |
| 45 | TRAILINGCOMMA = '''{{ (1, 2,) }}|{{ [1, 2,] }}|{{ {1: 2,} }}|{{ @(1, 2,) }}''' |
Armin Ronacher | ecc051b | 2007-06-01 18:25:28 +0200 | [diff] [blame] | 46 | |
| 47 | |
| 48 | def test_call(): |
| 49 | from jinja import Environment |
| 50 | env = Environment() |
| 51 | env.globals['foo'] = lambda a, b, c, e, g: a + b + c + e + g |
| 52 | tmpl = env.from_string(CALL) |
| 53 | assert tmpl.render() == 'abdfh' |
| 54 | |
| 55 | |
| 56 | def test_slicing(env): |
| 57 | tmpl = env.from_string(SLICING) |
| 58 | assert tmpl.render() == '[1, 2, 3]|[3, 2, 1]' |
| 59 | |
| 60 | |
| 61 | def test_attr(env): |
| 62 | tmpl = env.from_string(ATTR) |
| 63 | assert tmpl.render(foo={'bar': 42}) == '42|42' |
| 64 | |
| 65 | |
| 66 | def test_subscript(env): |
| 67 | tmpl = env.from_string(SUBSCRIPT) |
| 68 | assert tmpl.render(foo=[0, 1, 2]) == '0|2' |
| 69 | |
| 70 | |
| 71 | def test_keyattr(env): |
| 72 | tmpl = env.from_string(KEYATTR) |
| 73 | assert tmpl.render() == 'foo|[]' |
| 74 | |
| 75 | |
| 76 | def test_tuple(env): |
| 77 | tmpl = env.from_string(TUPLE) |
Armin Ronacher | 1cc232c | 2007-09-07 17:52:41 +0200 | [diff] [blame] | 78 | assert tmpl.render() == '()|(1,)|(1, 2)' |
Armin Ronacher | ecc051b | 2007-06-01 18:25:28 +0200 | [diff] [blame] | 79 | |
| 80 | |
| 81 | def test_math(env): |
| 82 | tmpl = env.from_string(MATH) |
| 83 | assert tmpl.render() == '1.5|8' |
| 84 | |
| 85 | |
| 86 | def test_div(env): |
| 87 | tmpl = env.from_string(DIV) |
| 88 | assert tmpl.render() == '1|1.5|1' |
| 89 | |
| 90 | |
| 91 | def test_unary(env): |
| 92 | tmpl = env.from_string(UNARY) |
| 93 | assert tmpl.render() == '3|-3' |
| 94 | |
| 95 | |
Armin Ronacher | 1cc232c | 2007-09-07 17:52:41 +0200 | [diff] [blame] | 96 | def test_concat(env): |
| 97 | tmpl = env.from_string(CONCAT) |
| 98 | assert tmpl.render() == '[1, 2]foo' |
| 99 | |
| 100 | |
Armin Ronacher | ecc051b | 2007-06-01 18:25:28 +0200 | [diff] [blame] | 101 | def test_compare(env): |
| 102 | tmpl = env.from_string(COMPARE) |
| 103 | assert tmpl.render() == 'True|True|True|True|True' |
| 104 | |
| 105 | |
Armin Ronacher | 1cc232c | 2007-09-07 17:52:41 +0200 | [diff] [blame] | 106 | def test_inop(env): |
| 107 | tmpl = env.from_string(INOP) |
| 108 | assert tmpl.render() == 'True|False' |
| 109 | |
| 110 | |
Armin Ronacher | ecc051b | 2007-06-01 18:25:28 +0200 | [diff] [blame] | 111 | def test_literals(env): |
| 112 | tmpl = env.from_string(LITERALS) |
Armin Ronacher | 1dcdac5 | 2007-12-09 22:53:46 +0100 | [diff] [blame^] | 113 | assert tmpl.render().lower() == '[]|{}|()||set([])' |
Armin Ronacher | ecc051b | 2007-06-01 18:25:28 +0200 | [diff] [blame] | 114 | |
| 115 | |
| 116 | def test_bool(env): |
| 117 | tmpl = env.from_string(BOOL) |
| 118 | assert tmpl.render() == 'False|True|True' |
Armin Ronacher | db69d0a | 2007-06-02 01:35:53 +0200 | [diff] [blame] | 119 | |
| 120 | |
| 121 | def test_grouping(env): |
| 122 | tmpl = env.from_string(GROUPING) |
| 123 | assert tmpl.render() == 'False' |
Armin Ronacher | 1cc232c | 2007-09-07 17:52:41 +0200 | [diff] [blame] | 124 | |
| 125 | |
| 126 | def test_django_attr(env): |
| 127 | tmpl = env.from_string(DJANGOATTR) |
| 128 | assert tmpl.render() == '1' |
| 129 | |
| 130 | |
| 131 | def test_conditional_expression(env): |
| 132 | tmpl = env.from_string(CONDEXPR) |
| 133 | assert tmpl.render() == '0' |
| 134 | |
| 135 | |
| 136 | def test_filter_priority(env): |
| 137 | tmpl = env.from_string(FILTERPRIORITY) |
| 138 | assert tmpl.render() == 'FOOBAR' |
| 139 | |
| 140 | |
| 141 | def test_function_calls(env): |
| 142 | tests = [ |
| 143 | (True, '*foo, bar'), |
| 144 | (True, '*foo, *bar'), |
| 145 | (True, '*foo, bar=42'), |
| 146 | (True, '**foo, *bar'), |
| 147 | (True, '**foo, bar'), |
| 148 | (False, 'foo, bar'), |
| 149 | (False, 'foo, bar=42'), |
| 150 | (False, 'foo, bar=23, *args'), |
| 151 | (False, 'a, b=c, *d, **e'), |
| 152 | (False, '*foo, **bar') |
| 153 | ] |
| 154 | for should_fail, sig in tests: |
| 155 | if should_fail: |
| 156 | try: |
| 157 | print env.from_string('{{ foo(%s) }}' % sig) |
| 158 | except TemplateSyntaxError: |
| 159 | continue |
| 160 | assert False, 'expected syntax error' |
| 161 | else: |
| 162 | env.from_string('foo(%s)' % sig) |
| 163 | |
| 164 | |
| 165 | def test_regex(env): |
| 166 | tmpl = env.from_string(REGEX) |
| 167 | assert tmpl.render() == "['foo', 'bar', 'baz']" |
| 168 | |
| 169 | |
| 170 | def test_tuple_expr(env): |
| 171 | for tmpl in TUPLETEMPLATES: |
| 172 | assert env.from_string(tmpl) |
| 173 | |
| 174 | |
| 175 | def test_trailing_comma(env): |
| 176 | tmpl = env.from_string(TRAILINGCOMMA) |
Armin Ronacher | 1dcdac5 | 2007-12-09 22:53:46 +0100 | [diff] [blame^] | 177 | assert tmpl.render().lower() == '(1, 2)|[1, 2]|{1: 2}|set([1, 2])' |
Armin Ronacher | 1cc232c | 2007-09-07 17:52:41 +0200 | [diff] [blame] | 178 | |
| 179 | |
| 180 | def test_extends_position(): |
| 181 | env = Environment(loader=DictLoader({ |
| 182 | 'empty': '[{% block empty %}{% endblock %}]' |
| 183 | })) |
| 184 | tests = [ |
| 185 | ('{% extends "empty" %}', '[!]'), |
| 186 | (' {% extends "empty" %}', '[!]'), |
| 187 | (' !\n', ' !\n!'), |
| 188 | ('{# foo #} {% extends "empty" %}', '[!]'), |
| 189 | ('{% set foo = "blub" %}{% extends "empty" %}', None) |
| 190 | ] |
| 191 | |
| 192 | for tmpl, expected_output in tests: |
| 193 | try: |
| 194 | tmpl = env.from_string(tmpl + '{% block empty %}!{% endblock %}') |
| 195 | except TemplateSyntaxError: |
| 196 | assert expected_output is None, 'got syntax error' |
| 197 | else: |
| 198 | assert expected_output == tmpl.render() |