round filter support+test negative precission in the round and use power of 10 instea...
[jinja2.git] / jinja2 / testsuite / filters.py
1 # -*- coding: utf-8 -*-
2 """
3     jinja2.testsuite.filters
4     ~~~~~~~~~~~~~~~~~~~~~~~~
5
6     Tests for the jinja filters.
7
8     :copyright: (c) 2010 by the Jinja Team.
9     :license: BSD, see LICENSE for more details.
10 """
11 import unittest
12 from jinja2.testsuite import JinjaTestCase
13
14 from jinja2 import Markup, Environment
15
16 env = Environment()
17
18
19 class FilterTestCase(JinjaTestCase):
20
21     def test_capitalize(self):
22         tmpl = env.from_string('{{ "foo bar"|capitalize }}')
23         assert tmpl.render() == 'Foo bar'
24
25     def test_center(self):
26         tmpl = env.from_string('{{ "foo"|center(9) }}')
27         assert tmpl.render() == '   foo   '
28
29     def test_default(self):
30         tmpl = env.from_string(
31             "{{ missing|default('no') }}|{{ false|default('no') }}|"
32             "{{ false|default('no', true) }}|{{ given|default('no') }}"
33         )
34         assert tmpl.render(given='yes') == 'no|False|no|yes'
35
36     def test_dictsort(self):
37         tmpl = env.from_string(
38             '{{ foo|dictsort }}|'
39             '{{ foo|dictsort(true) }}|'
40             '{{ foo|dictsort(false, "value") }}'
41         )
42         out = tmpl.render(foo={"aa": 0, "b": 1, "c": 2, "AB": 3})
43         assert out == ("[('aa', 0), ('AB', 3), ('b', 1), ('c', 2)]|"
44                        "[('AB', 3), ('aa', 0), ('b', 1), ('c', 2)]|"
45                        "[('aa', 0), ('b', 1), ('c', 2), ('AB', 3)]")
46
47     def test_batch(self):
48         tmpl = env.from_string("{{ foo|batch(3)|list }}|"
49                                "{{ foo|batch(3, 'X')|list }}")
50         out = tmpl.render(foo=range(10))
51         assert out == ("[[0, 1, 2], [3, 4, 5], [6, 7, 8], [9]]|"
52                        "[[0, 1, 2], [3, 4, 5], [6, 7, 8], [9, 'X', 'X']]")
53
54     def test_slice(self):
55         tmpl = env.from_string('{{ foo|slice(3)|list }}|'
56                                '{{ foo|slice(3, "X")|list }}')
57         out = tmpl.render(foo=range(10))
58         assert out == ("[[0, 1, 2, 3], [4, 5, 6], [7, 8, 9]]|"
59                        "[[0, 1, 2, 3], [4, 5, 6, 'X'], [7, 8, 9, 'X']]")
60
61     def test_escape(self):
62         tmpl = env.from_string('''{{ '<">&'|escape }}''')
63         out = tmpl.render()
64         assert out == '&lt;&#34;&gt;&amp;'
65
66     def test_striptags(self):
67         tmpl = env.from_string('''{{ foo|striptags }}''')
68         out = tmpl.render(foo='  <p>just a small   \n <a href="#">'
69                           'example</a> link</p>\n<p>to a webpage</p> '
70                           '<!-- <p>and some commented stuff</p> -->')
71         assert out == 'just a small example link to a webpage'
72
73     def test_filesizeformat(self):
74         tmpl = env.from_string(
75             '{{ 100|filesizeformat }}|'
76             '{{ 1000|filesizeformat }}|'
77             '{{ 1000000|filesizeformat }}|'
78             '{{ 1000000000|filesizeformat }}|'
79             '{{ 1000000000000|filesizeformat }}|'
80             '{{ 100|filesizeformat(true) }}|'
81             '{{ 1000|filesizeformat(true) }}|'
82             '{{ 1000000|filesizeformat(true) }}|'
83             '{{ 1000000000|filesizeformat(true) }}|'
84             '{{ 1000000000000|filesizeformat(true) }}'
85         )
86         out = tmpl.render()
87         assert out == (
88             '100 Bytes|1.0 KB|1.0 MB|1.0 GB|1000.0 GB|'
89             '100 Bytes|1000 Bytes|976.6 KiB|953.7 MiB|931.3 GiB'
90         )
91
92     def test_first(self):
93         tmpl = env.from_string('{{ foo|first }}')
94         out = tmpl.render(foo=range(10))
95         assert out == '0'
96
97     def test_float(self):
98         tmpl = env.from_string('{{ "42"|float }}|'
99                                '{{ "ajsghasjgd"|float }}|'
100                                '{{ "32.32"|float }}')
101         out = tmpl.render()
102         assert out == '42.0|0.0|32.32'
103
104     def test_format(self):
105         tmpl = env.from_string('''{{ "%s|%s"|format("a", "b") }}''')
106         out = tmpl.render()
107         assert out == 'a|b'
108
109     def test_indent(self):
110         tmpl = env.from_string('{{ foo|indent(2) }}|{{ foo|indent(2, true) }}')
111         text = '\n'.join([' '.join(['foo', 'bar'] * 2)] * 2)
112         out = tmpl.render(foo=text)
113         assert out == ('foo bar foo bar\n  foo bar foo bar|  '
114                        'foo bar foo bar\n  foo bar foo bar')
115
116     def test_int(self):
117         tmpl = env.from_string('{{ "42"|int }}|{{ "ajsghasjgd"|int }}|'
118                                '{{ "32.32"|int }}')
119         out = tmpl.render()
120         assert out == '42|0|32'
121
122     def test_join(self):
123         tmpl = env.from_string('{{ [1, 2, 3]|join("|") }}')
124         out = tmpl.render()
125         assert out == '1|2|3'
126
127         env2 = Environment(autoescape=True)
128         tmpl = env2.from_string('{{ ["<foo>", "<span>foo</span>"|safe]|join }}')
129         assert tmpl.render() == '&lt;foo&gt;<span>foo</span>'
130
131     def test_last(self):
132         tmpl = env.from_string('''{{ foo|last }}''')
133         out = tmpl.render(foo=range(10))
134         assert out == '9'
135
136     def test_length(self):
137         tmpl = env.from_string('''{{ "hello world"|length }}''')
138         out = tmpl.render()
139         assert out == '11'
140
141     def test_lower(self):
142         tmpl = env.from_string('''{{ "FOO"|lower }}''')
143         out = tmpl.render()
144         assert out == 'foo'
145
146     def test_pprint(self):
147         from pprint import pformat
148         tmpl = env.from_string('''{{ data|pprint }}''')
149         data = range(1000)
150         assert tmpl.render(data=data) == pformat(data)
151
152     def test_random(self):
153         tmpl = env.from_string('''{{ seq|random }}''')
154         seq = range(100)
155         for _ in range(10):
156             assert int(tmpl.render(seq=seq)) in seq
157
158     def test_reverse(self):
159         tmpl = env.from_string('{{ "foobar"|reverse|join }}|'
160                                '{{ [1, 2, 3]|reverse|list }}')
161         assert tmpl.render() == 'raboof|[3, 2, 1]'
162
163     def test_string(self):
164         x = [1, 2, 3, 4, 5]
165         tmpl = env.from_string('''{{ obj|string }}''')
166         assert tmpl.render(obj=x) == unicode(x)
167
168     def test_title(self):
169         tmpl = env.from_string('''{{ "foo bar"|title }}''')
170         assert tmpl.render() == "Foo Bar"
171
172     def test_truncate(self):
173         tmpl = env.from_string(
174             '{{ data|truncate(15, true, ">>>") }}|'
175             '{{ data|truncate(15, false, ">>>") }}|'
176             '{{ smalldata|truncate(15) }}'
177         )
178         out = tmpl.render(data='foobar baz bar' * 1000,
179                           smalldata='foobar baz bar')
180         assert out == 'foobar baz barf>>>|foobar baz >>>|foobar baz bar'
181
182     def test_upper(self):
183         tmpl = env.from_string('{{ "foo"|upper }}')
184         assert tmpl.render() == 'FOO'
185
186     def test_urlize(self):
187         tmpl = env.from_string('{{ "foo http://www.example.com/ bar"|urlize }}')
188         assert tmpl.render() == 'foo <a href="http://www.example.com/">'\
189                                 'http://www.example.com/</a> bar'
190
191     def test_wordcount(self):
192         tmpl = env.from_string('{{ "foo bar baz"|wordcount }}')
193         assert tmpl.render() == '3'
194
195     def test_block(self):
196         tmpl = env.from_string('{% filter lower|escape %}<HEHE>{% endfilter %}')
197         assert tmpl.render() == '&lt;hehe&gt;'
198
199     def test_chaining(self):
200         tmpl = env.from_string('''{{ ['<foo>', '<bar>']|first|upper|escape }}''')
201         assert tmpl.render() == '&lt;FOO&gt;'
202
203     def test_sum(self):
204         tmpl = env.from_string('''{{ [1, 2, 3, 4, 5, 6]|sum }}''')
205         assert tmpl.render() == '21'
206
207     def test_abs(self):
208         tmpl = env.from_string('''{{ -1|abs }}|{{ 1|abs }}''')
209         return tmpl.render() == '1|1'
210
211     def test_round_positive(self):
212         tmpl = env.from_string('{{ 2.7|round }}|{{ 2.1|round }}|'
213                                "{{ 2.1234|round(3, 'floor') }}|"
214                                "{{ 2.1|round(0, 'ceil') }}")
215         assert tmpl.render() == '3.0|2.0|2.123|3.0', tmpl.render()
216
217     def test_round_negative(self):
218         tmpl = env.from_string('{{ 21.3|round(-1)}}|'
219                                "{{ 21.3|round(-1, 'ceil')}}|"
220                                "{{ 21.3|round(-1, 'floor')}}")
221         assert tmpl.render() == '20.0|30.0|20.0',tmpl.render()
222
223     def test_xmlattr(self):
224         tmpl = env.from_string("{{ {'foo': 42, 'bar': 23, 'fish': none, "
225                                "'spam': missing, 'blub:blub': '<?>'}|xmlattr }}")
226         out = tmpl.render().split()
227         assert len(out) == 3
228         assert 'foo="42"' in out
229         assert 'bar="23"' in out
230         assert 'blub:blub="&lt;?&gt;"' in out
231
232     def test_sort1(self):
233         tmpl = env.from_string('{{ [2, 3, 1]|sort }}|{{ [2, 3, 1]|sort(true) }}')
234         assert tmpl.render() == '[1, 2, 3]|[3, 2, 1]'
235
236     def test_sort2(self):
237         tmpl = env.from_string('{{ "".join(["c", "A", "b", "D"]|sort(false, true)) }}')
238         assert tmpl.render() == 'AbcD'
239
240     def test_groupby(self):
241         tmpl = env.from_string('''
242         {%- for grouper, list in [{'foo': 1, 'bar': 2},
243                                   {'foo': 2, 'bar': 3},
244                                   {'foo': 1, 'bar': 1},
245                                   {'foo': 3, 'bar': 4}]|groupby('foo') -%}
246             {{ grouper }}{% for x in list %}: {{ x.foo }}, {{ x.bar }}{% endfor %}|
247         {%- endfor %}''')
248         assert tmpl.render().split('|') == [
249             "1: 1, 2: 1, 1",
250             "2: 2, 3",
251             "3: 3, 4",
252             ""
253         ]
254
255     def test_filtertag(self):
256         tmpl = env.from_string("{% filter upper|replace('FOO', 'foo') %}"
257                                "foobar{% endfilter %}")
258         assert tmpl.render() == 'fooBAR'
259
260     def test_replace(self):
261         env = Environment()
262         tmpl = env.from_string('{{ string|replace("o", 42) }}')
263         assert tmpl.render(string='<foo>') == '<f4242>'
264         env = Environment(autoescape=True)
265         tmpl = env.from_string('{{ string|replace("o", 42) }}')
266         assert tmpl.render(string='<foo>') == '&lt;f4242&gt;'
267         tmpl = env.from_string('{{ string|replace("<", 42) }}')
268         assert tmpl.render(string='<foo>') == '42foo&gt;'
269         tmpl = env.from_string('{{ string|replace("o", ">x<") }}')
270         assert tmpl.render(string=Markup('foo')) == 'f&gt;x&lt;&gt;x&lt;'
271
272     def test_forceescape(self):
273         tmpl = env.from_string('{{ x|forceescape }}')
274         assert tmpl.render(x=Markup('<div />')) == u'&lt;div /&gt;'
275
276     def test_safe(self):
277         env = Environment(autoescape=True)
278         tmpl = env.from_string('{{ "<div>foo</div>"|safe }}')
279         assert tmpl.render() == '<div>foo</div>'
280         tmpl = env.from_string('{{ "<div>foo</div>" }}')
281         assert tmpl.render() == '&lt;div&gt;foo&lt;/div&gt;'
282
283     def test_sort2(self):
284         tmpl = env.from_string('''{{ ['foo', 'Bar', 'blah']|sort }}''')
285         assert tmpl.render() == "['Bar', 'blah', 'foo']"
286
287
288 def suite():
289     suite = unittest.TestSuite()
290     suite.addTest(unittest.makeSuite(FilterTestCase))
291     return suite