blob: 0c307ecbc6662c200583ecbfedd4e5d3945babdb [file] [log] [blame]
Armin Ronacherab45b842007-03-18 20:47:50 +01001# -*- coding: utf-8 -*-
2"""
3 unit test for loop functions
4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5
6 :copyright: 2007 by Armin Ronacher.
7 :license: BSD, see LICENSE for more details.
8"""
Armin Ronacher10f3ba22008-04-18 11:30:37 +02009from py.test import raises
Armin Ronacher9f258ff2008-05-24 22:28:52 +020010from jinja2.exceptions import UndefinedError, TemplateSyntaxError
Armin Ronacher10f3ba22008-04-18 11:30:37 +020011
Armin Ronacherab45b842007-03-18 20:47:50 +010012
13SIMPLE = '''{% for item in seq %}{{ item }}{% endfor %}'''
14ELSE = '''{% for item in seq %}XXX{% else %}...{% endfor %}'''
15EMPTYBLOCKS = '''<{% for item in seq %}{% else %}{% endfor %}>'''
16CONTEXTVARS = '''{% for item in seq %}\
17{{ loop.index }}|{{ loop.index0 }}|{{ loop.revindex }}|{{
18 loop.revindex0 }}|{{ loop.first }}|{{ loop.last }}|{{
Armin Ronacher10f3ba22008-04-18 11:30:37 +020019 loop.length }}###{% endfor %}'''
20CYCLING = '''{% for item in seq %}{{ loop.cycle('<1>', '<2>') }}{% endfor %}\
21{% for item in seq %}{{ loop.cycle(*through) }}{% endfor %}'''
Armin Ronacherab45b842007-03-18 20:47:50 +010022SCOPE = '''{% for item in seq %}{% endfor %}{{ item }}'''
Armin Ronacher6dba4d62007-05-21 23:41:36 +020023VARLEN = '''{% for item in iter %}{{ item }}{% endfor %}'''
Armin Ronacher9bcd4112007-05-29 14:17:24 +020024NONITER = '''{% for item in none %}...{% endfor %}'''
Armin Ronacher66a93442008-05-11 23:42:19 +020025RECURSIVE = '''{% for item in seq recursive -%}
Armin Ronacherb455c312008-05-11 23:43:07 +020026 [{{ item.a }}{% if item.b %}<{{ loop(item.b) }}>{% endif %}]
Armin Ronacher66a93442008-05-11 23:42:19 +020027{%- endfor %}'''
Armin Ronacher24db4512008-05-19 09:28:17 +020028LOOPLOOP = '''{% for row in table %}
29 {%- set rowloop = loop -%}
30 {% for cell in row -%}
31 [{{ rowloop.index }}|{{ loop.index }}]
32 {%- endfor %}
33{%- endfor %}'''
Armin Ronacher105f0dc2008-05-23 16:12:47 +020034LOOPERROR1 = '''\
35{% for item in [1] if loop.index == 0 %}...{% endfor %}'''
36LOOPERROR2 = '''\
37{% for item in [] %}...{% else %}{{ loop }}{% endfor %}'''
Armin Ronacher6df604e2008-05-23 22:18:38 +020038LOOPFILTER = '''\
39{% for item in range(10) if item is even %}[{{ item }}]{% endfor %}'''
40EXTENDEDLOOPFILTER = '''\
41{% for item in range(10) if item is even %}[{{ loop.index
42}}:{{ item }}]{% endfor %}'''
Armin Ronacher9f258ff2008-05-24 22:28:52 +020043LOOPUNASSIGNABLE = '''\
44{% for loop in seq %}...{% endfor %}'''
Armin Ronacherab45b842007-03-18 20:47:50 +010045
46
47def test_simple(env):
48 tmpl = env.from_string(SIMPLE)
49 assert tmpl.render(seq=range(10)) == '0123456789'
50
51
52def test_else(env):
53 tmpl = env.from_string(ELSE)
54 assert tmpl.render() == '...'
55
56
57def test_empty_blocks(env):
58 tmpl = env.from_string(EMPTYBLOCKS)
59 assert tmpl.render() == '<>'
60
61
62def test_context_vars(env):
63 tmpl = env.from_string(CONTEXTVARS)
64 one, two, _ = tmpl.render(seq=[0, 1]).split('###')
65 (one_index, one_index0, one_revindex, one_revindex0, one_first,
Armin Ronacher10f3ba22008-04-18 11:30:37 +020066 one_last, one_length) = one.split('|')
Armin Ronacherab45b842007-03-18 20:47:50 +010067 (two_index, two_index0, two_revindex, two_revindex0, two_first,
Armin Ronacher10f3ba22008-04-18 11:30:37 +020068 two_last, two_length) = two.split('|')
Armin Ronacherab45b842007-03-18 20:47:50 +010069
70 assert int(one_index) == 1 and int(two_index) == 2
71 assert int(one_index0) == 0 and int(two_index0) == 1
72 assert int(one_revindex) == 2 and int(two_revindex) == 1
73 assert int(one_revindex0) == 1 and int(two_revindex0) == 0
74 assert one_first == 'True' and two_first == 'False'
75 assert one_last == 'False' and two_last == 'True'
Armin Ronacherab45b842007-03-18 20:47:50 +010076 assert one_length == two_length == '2'
77
78
79def test_cycling(env):
80 tmpl = env.from_string(CYCLING)
81 output = tmpl.render(seq=range(4), through=('<1>', '<2>'))
82 assert output == '<1><2>' * 4
83
84
85def test_scope(env):
86 tmpl = env.from_string(SCOPE)
87 output = tmpl.render(seq=range(10))
88 assert not output
Armin Ronacher6dba4d62007-05-21 23:41:36 +020089
90
91def test_varlen(env):
92 def inner():
93 for item in range(5):
94 yield item
95 tmpl = env.from_string(VARLEN)
96 output = tmpl.render(iter=inner())
97 assert output == '01234'
Armin Ronacher9bcd4112007-05-29 14:17:24 +020098
99
100def test_noniter(env):
101 tmpl = env.from_string(NONITER)
Armin Ronacher10f3ba22008-04-18 11:30:37 +0200102 raises(TypeError, tmpl.render)
Armin Ronacher66a93442008-05-11 23:42:19 +0200103
104
105def test_recursive(env):
106 tmpl = env.from_string(RECURSIVE)
107 assert tmpl.render(seq=[
108 dict(a=1, b=[dict(a=1), dict(a=2)]),
109 dict(a=2, b=[dict(a=1), dict(a=2)]),
110 dict(a=3, b=[dict(a='a')])
Armin Ronacherb455c312008-05-11 23:43:07 +0200111 ]) == '[1<[1][2]>][2<[1][2]>][3<[a]>]'
Armin Ronacher24db4512008-05-19 09:28:17 +0200112
113
114def test_looploop(env):
115 tmpl = env.from_string(LOOPLOOP)
116 assert tmpl.render(table=['ab', 'cd']) == '[1|1][1|2][2|1][2|2]'
Armin Ronacher105f0dc2008-05-23 16:12:47 +0200117
118
Armin Ronacher547d0b62008-07-04 16:35:10 +0200119def test_reversed_bug(env):
120 tmpl = env.from_string('{% for i in items %}{{ i }}{% if not loop.last %}'
121 ',{% endif %}{% endfor %}')
122 assert tmpl.render(items=reversed([3, 2, 1])) == '1,2,3'
123
124
Armin Ronacher105f0dc2008-05-23 16:12:47 +0200125def test_loop_errors(env):
126 tmpl = env.from_string(LOOPERROR1)
127 raises(UndefinedError, tmpl.render)
128 tmpl = env.from_string(LOOPERROR2)
129 assert tmpl.render() == ''
Armin Ronacher6df604e2008-05-23 22:18:38 +0200130
131
132def test_loop_filter(env):
133 tmpl = env.from_string(LOOPFILTER)
134 assert tmpl.render() == '[0][2][4][6][8]'
135 tmpl = env.from_string(EXTENDEDLOOPFILTER)
136 assert tmpl.render() == '[1:0][2:2][3:4][4:6][5:8]'
Armin Ronacher9f258ff2008-05-24 22:28:52 +0200137
138
139def test_loop_unassignable(env):
140 raises(TemplateSyntaxError, env.from_string, LOOPUNASSIGNABLE)
Armin Ronacherff53c782008-08-13 18:55:50 +0200141
142
143def test_scoped_special_var(env):
144 t = env.from_string('{% for s in seq %}[{{ loop.first }}{% for c in s %}'
145 '|{{ loop.first }}{% endfor %}]{% endfor %}')
146 assert t.render(seq=('ab', 'cd')) == '[True|True|False][False|True|False]'
Armin Ronacher833a3b52008-08-14 12:31:12 +0200147
148
149def test_scoped_loop_var(env):
150 t = env.from_string('{% for x in seq %}{{ loop.first }}'
151 '{% for y in seq %}{% endfor %}{% endfor %}')
152 assert t.render(seq='ab') == 'TrueFalse'
153 t = env.from_string('{% for x in seq %}{% for y in seq %}'
154 '{{ loop.first }}{% endfor %}{% endfor %}')
155 assert t.render(seq='ab') == 'TrueFalseTrueFalse'