~brad-marshall/charms/trusty/apache2-wsgi/fix-haproxy-relations

« back to all changes in this revision

Viewing changes to hooks/lib/jinja2/testsuite/filters.py

  • Committer: Robin Winslow
  • Date: 2014-05-27 14:00:44 UTC
  • Revision ID: robin.winslow@canonical.com-20140527140044-8rpmb3wx4djzwa83
Add all files

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
from jinja2._compat import text_type, implements_to_string
 
16
 
 
17
env = Environment()
 
18
 
 
19
 
 
20
class FilterTestCase(JinjaTestCase):
 
21
 
 
22
    def test_filter_calling(self):
 
23
        rv = env.call_filter('sum', [1, 2, 3])
 
24
        self.assert_equal(rv, 6)
 
25
 
 
26
    def test_capitalize(self):
 
27
        tmpl = env.from_string('{{ "foo bar"|capitalize }}')
 
28
        assert tmpl.render() == 'Foo bar'
 
29
 
 
30
    def test_center(self):
 
31
        tmpl = env.from_string('{{ "foo"|center(9) }}')
 
32
        assert tmpl.render() == '   foo   '
 
33
 
 
34
    def test_default(self):
 
35
        tmpl = env.from_string(
 
36
            "{{ missing|default('no') }}|{{ false|default('no') }}|"
 
37
            "{{ false|default('no', true) }}|{{ given|default('no') }}"
 
38
        )
 
39
        assert tmpl.render(given='yes') == 'no|False|no|yes'
 
40
 
 
41
    def test_dictsort(self):
 
42
        tmpl = env.from_string(
 
43
            '{{ foo|dictsort }}|'
 
44
            '{{ foo|dictsort(true) }}|'
 
45
            '{{ foo|dictsort(false, "value") }}'
 
46
        )
 
47
        out = tmpl.render(foo={"aa": 0, "b": 1, "c": 2, "AB": 3})
 
48
        assert out == ("[('aa', 0), ('AB', 3), ('b', 1), ('c', 2)]|"
 
49
                       "[('AB', 3), ('aa', 0), ('b', 1), ('c', 2)]|"
 
50
                       "[('aa', 0), ('b', 1), ('c', 2), ('AB', 3)]")
 
51
 
 
52
    def test_batch(self):
 
53
        tmpl = env.from_string("{{ foo|batch(3)|list }}|"
 
54
                               "{{ foo|batch(3, 'X')|list }}")
 
55
        out = tmpl.render(foo=list(range(10)))
 
56
        assert out == ("[[0, 1, 2], [3, 4, 5], [6, 7, 8], [9]]|"
 
57
                       "[[0, 1, 2], [3, 4, 5], [6, 7, 8], [9, 'X', 'X']]")
 
58
 
 
59
    def test_slice(self):
 
60
        tmpl = env.from_string('{{ foo|slice(3)|list }}|'
 
61
                               '{{ foo|slice(3, "X")|list }}')
 
62
        out = tmpl.render(foo=list(range(10)))
 
63
        assert out == ("[[0, 1, 2, 3], [4, 5, 6], [7, 8, 9]]|"
 
64
                       "[[0, 1, 2, 3], [4, 5, 6, 'X'], [7, 8, 9, 'X']]")
 
65
 
 
66
    def test_escape(self):
 
67
        tmpl = env.from_string('''{{ '<">&'|escape }}''')
 
68
        out = tmpl.render()
 
69
        assert out == '&lt;&#34;&gt;&amp;'
 
70
 
 
71
    def test_striptags(self):
 
72
        tmpl = env.from_string('''{{ foo|striptags }}''')
 
73
        out = tmpl.render(foo='  <p>just a small   \n <a href="#">'
 
74
                          'example</a> link</p>\n<p>to a webpage</p> '
 
75
                          '<!-- <p>and some commented stuff</p> -->')
 
76
        assert out == 'just a small example link to a webpage'
 
77
 
 
78
    def test_filesizeformat(self):
 
79
        tmpl = env.from_string(
 
80
            '{{ 100|filesizeformat }}|'
 
81
            '{{ 1000|filesizeformat }}|'
 
82
            '{{ 1000000|filesizeformat }}|'
 
83
            '{{ 1000000000|filesizeformat }}|'
 
84
            '{{ 1000000000000|filesizeformat }}|'
 
85
            '{{ 100|filesizeformat(true) }}|'
 
86
            '{{ 1000|filesizeformat(true) }}|'
 
87
            '{{ 1000000|filesizeformat(true) }}|'
 
88
            '{{ 1000000000|filesizeformat(true) }}|'
 
89
            '{{ 1000000000000|filesizeformat(true) }}'
 
90
        )
 
91
        out = tmpl.render()
 
92
        self.assert_equal(out, (
 
93
            '100 Bytes|1.0 kB|1.0 MB|1.0 GB|1.0 TB|100 Bytes|'
 
94
            '1000 Bytes|976.6 KiB|953.7 MiB|931.3 GiB'
 
95
        ))
 
96
 
 
97
    def test_filesizeformat_issue59(self):
 
98
        tmpl = env.from_string(
 
99
            '{{ 300|filesizeformat }}|'
 
100
            '{{ 3000|filesizeformat }}|'
 
101
            '{{ 3000000|filesizeformat }}|'
 
102
            '{{ 3000000000|filesizeformat }}|'
 
103
            '{{ 3000000000000|filesizeformat }}|'
 
104
            '{{ 300|filesizeformat(true) }}|'
 
105
            '{{ 3000|filesizeformat(true) }}|'
 
106
            '{{ 3000000|filesizeformat(true) }}'
 
107
        )
 
108
        out = tmpl.render()
 
109
        self.assert_equal(out, (
 
110
            '300 Bytes|3.0 kB|3.0 MB|3.0 GB|3.0 TB|300 Bytes|'
 
111
            '2.9 KiB|2.9 MiB'
 
112
        ))
 
113
 
 
114
 
 
115
    def test_first(self):
 
116
        tmpl = env.from_string('{{ foo|first }}')
 
117
        out = tmpl.render(foo=list(range(10)))
 
118
        assert out == '0'
 
119
 
 
120
    def test_float(self):
 
121
        tmpl = env.from_string('{{ "42"|float }}|'
 
122
                               '{{ "ajsghasjgd"|float }}|'
 
123
                               '{{ "32.32"|float }}')
 
124
        out = tmpl.render()
 
125
        assert out == '42.0|0.0|32.32'
 
126
 
 
127
    def test_format(self):
 
128
        tmpl = env.from_string('''{{ "%s|%s"|format("a", "b") }}''')
 
129
        out = tmpl.render()
 
130
        assert out == 'a|b'
 
131
 
 
132
    def test_indent(self):
 
133
        tmpl = env.from_string('{{ foo|indent(2) }}|{{ foo|indent(2, true) }}')
 
134
        text = '\n'.join([' '.join(['foo', 'bar'] * 2)] * 2)
 
135
        out = tmpl.render(foo=text)
 
136
        assert out == ('foo bar foo bar\n  foo bar foo bar|  '
 
137
                       'foo bar foo bar\n  foo bar foo bar')
 
138
 
 
139
    def test_int(self):
 
140
        tmpl = env.from_string('{{ "42"|int }}|{{ "ajsghasjgd"|int }}|'
 
141
                               '{{ "32.32"|int }}')
 
142
        out = tmpl.render()
 
143
        assert out == '42|0|32'
 
144
 
 
145
    def test_join(self):
 
146
        tmpl = env.from_string('{{ [1, 2, 3]|join("|") }}')
 
147
        out = tmpl.render()
 
148
        assert out == '1|2|3'
 
149
 
 
150
        env2 = Environment(autoescape=True)
 
151
        tmpl = env2.from_string('{{ ["<foo>", "<span>foo</span>"|safe]|join }}')
 
152
        assert tmpl.render() == '&lt;foo&gt;<span>foo</span>'
 
153
 
 
154
    def test_join_attribute(self):
 
155
        class User(object):
 
156
            def __init__(self, username):
 
157
                self.username = username
 
158
        tmpl = env.from_string('''{{ users|join(', ', 'username') }}''')
 
159
        assert tmpl.render(users=map(User, ['foo', 'bar'])) == 'foo, bar'
 
160
 
 
161
    def test_last(self):
 
162
        tmpl = env.from_string('''{{ foo|last }}''')
 
163
        out = tmpl.render(foo=list(range(10)))
 
164
        assert out == '9'
 
165
 
 
166
    def test_length(self):
 
167
        tmpl = env.from_string('''{{ "hello world"|length }}''')
 
168
        out = tmpl.render()
 
169
        assert out == '11'
 
170
 
 
171
    def test_lower(self):
 
172
        tmpl = env.from_string('''{{ "FOO"|lower }}''')
 
173
        out = tmpl.render()
 
174
        assert out == 'foo'
 
175
 
 
176
    def test_pprint(self):
 
177
        from pprint import pformat
 
178
        tmpl = env.from_string('''{{ data|pprint }}''')
 
179
        data = list(range(1000))
 
180
        assert tmpl.render(data=data) == pformat(data)
 
181
 
 
182
    def test_random(self):
 
183
        tmpl = env.from_string('''{{ seq|random }}''')
 
184
        seq = list(range(100))
 
185
        for _ in range(10):
 
186
            assert int(tmpl.render(seq=seq)) in seq
 
187
 
 
188
    def test_reverse(self):
 
189
        tmpl = env.from_string('{{ "foobar"|reverse|join }}|'
 
190
                               '{{ [1, 2, 3]|reverse|list }}')
 
191
        assert tmpl.render() == 'raboof|[3, 2, 1]'
 
192
 
 
193
    def test_string(self):
 
194
        x = [1, 2, 3, 4, 5]
 
195
        tmpl = env.from_string('''{{ obj|string }}''')
 
196
        assert tmpl.render(obj=x) == text_type(x)
 
197
 
 
198
    def test_title(self):
 
199
        tmpl = env.from_string('''{{ "foo bar"|title }}''')
 
200
        assert tmpl.render() == "Foo Bar"
 
201
        tmpl = env.from_string('''{{ "foo's bar"|title }}''')
 
202
        assert tmpl.render() == "Foo's Bar"
 
203
        tmpl = env.from_string('''{{ "foo   bar"|title }}''')
 
204
        assert tmpl.render() == "Foo   Bar"
 
205
        tmpl = env.from_string('''{{ "f bar f"|title }}''')
 
206
        assert tmpl.render() == "F Bar F"
 
207
        tmpl = env.from_string('''{{ "foo-bar"|title }}''')
 
208
        assert tmpl.render() == "Foo-Bar"
 
209
        tmpl = env.from_string('''{{ "foo\tbar"|title }}''')
 
210
        assert tmpl.render() == "Foo\tBar"
 
211
        tmpl = env.from_string('''{{ "FOO\tBAR"|title }}''')
 
212
        assert tmpl.render() == "Foo\tBar"
 
213
 
 
214
    def test_truncate(self):
 
215
        tmpl = env.from_string(
 
216
            '{{ data|truncate(15, true, ">>>") }}|'
 
217
            '{{ data|truncate(15, false, ">>>") }}|'
 
218
            '{{ smalldata|truncate(15) }}'
 
219
        )
 
220
        out = tmpl.render(data='foobar baz bar' * 1000,
 
221
                          smalldata='foobar baz bar')
 
222
        assert out == 'foobar baz barf>>>|foobar baz >>>|foobar baz bar'
 
223
 
 
224
    def test_upper(self):
 
225
        tmpl = env.from_string('{{ "foo"|upper }}')
 
226
        assert tmpl.render() == 'FOO'
 
227
 
 
228
    def test_urlize(self):
 
229
        tmpl = env.from_string('{{ "foo http://www.example.com/ bar"|urlize }}')
 
230
        assert tmpl.render() == 'foo <a href="http://www.example.com/">'\
 
231
                                'http://www.example.com/</a> bar'
 
232
 
 
233
    def test_wordcount(self):
 
234
        tmpl = env.from_string('{{ "foo bar baz"|wordcount }}')
 
235
        assert tmpl.render() == '3'
 
236
 
 
237
    def test_block(self):
 
238
        tmpl = env.from_string('{% filter lower|escape %}<HEHE>{% endfilter %}')
 
239
        assert tmpl.render() == '&lt;hehe&gt;'
 
240
 
 
241
    def test_chaining(self):
 
242
        tmpl = env.from_string('''{{ ['<foo>', '<bar>']|first|upper|escape }}''')
 
243
        assert tmpl.render() == '&lt;FOO&gt;'
 
244
 
 
245
    def test_sum(self):
 
246
        tmpl = env.from_string('''{{ [1, 2, 3, 4, 5, 6]|sum }}''')
 
247
        assert tmpl.render() == '21'
 
248
 
 
249
    def test_sum_attributes(self):
 
250
        tmpl = env.from_string('''{{ values|sum('value') }}''')
 
251
        assert tmpl.render(values=[
 
252
            {'value': 23},
 
253
            {'value': 1},
 
254
            {'value': 18},
 
255
        ]) == '42'
 
256
 
 
257
    def test_sum_attributes_nested(self):
 
258
        tmpl = env.from_string('''{{ values|sum('real.value') }}''')
 
259
        assert tmpl.render(values=[
 
260
            {'real': {'value': 23}},
 
261
            {'real': {'value': 1}},
 
262
            {'real': {'value': 18}},
 
263
        ]) == '42'
 
264
 
 
265
    def test_sum_attributes_tuple(self):
 
266
        tmpl = env.from_string('''{{ values.items()|sum('1') }}''')
 
267
        assert tmpl.render(values={
 
268
            'foo': 23,
 
269
            'bar': 1,
 
270
            'baz': 18,
 
271
        }) == '42'
 
272
 
 
273
    def test_abs(self):
 
274
        tmpl = env.from_string('''{{ -1|abs }}|{{ 1|abs }}''')
 
275
        assert tmpl.render() == '1|1', tmpl.render()
 
276
 
 
277
    def test_round_positive(self):
 
278
        tmpl = env.from_string('{{ 2.7|round }}|{{ 2.1|round }}|'
 
279
                               "{{ 2.1234|round(3, 'floor') }}|"
 
280
                               "{{ 2.1|round(0, 'ceil') }}")
 
281
        assert tmpl.render() == '3.0|2.0|2.123|3.0', tmpl.render()
 
282
 
 
283
    def test_round_negative(self):
 
284
        tmpl = env.from_string('{{ 21.3|round(-1)}}|'
 
285
                               "{{ 21.3|round(-1, 'ceil')}}|"
 
286
                               "{{ 21.3|round(-1, 'floor')}}")
 
287
        assert tmpl.render() == '20.0|30.0|20.0',tmpl.render()
 
288
 
 
289
    def test_xmlattr(self):
 
290
        tmpl = env.from_string("{{ {'foo': 42, 'bar': 23, 'fish': none, "
 
291
                               "'spam': missing, 'blub:blub': '<?>'}|xmlattr }}")
 
292
        out = tmpl.render().split()
 
293
        assert len(out) == 3
 
294
        assert 'foo="42"' in out
 
295
        assert 'bar="23"' in out
 
296
        assert 'blub:blub="&lt;?&gt;"' in out
 
297
 
 
298
    def test_sort1(self):
 
299
        tmpl = env.from_string('{{ [2, 3, 1]|sort }}|{{ [2, 3, 1]|sort(true) }}')
 
300
        assert tmpl.render() == '[1, 2, 3]|[3, 2, 1]'
 
301
 
 
302
    def test_sort2(self):
 
303
        tmpl = env.from_string('{{ "".join(["c", "A", "b", "D"]|sort) }}')
 
304
        assert tmpl.render() == 'AbcD'
 
305
 
 
306
    def test_sort3(self):
 
307
        tmpl = env.from_string('''{{ ['foo', 'Bar', 'blah']|sort }}''')
 
308
        assert tmpl.render() == "['Bar', 'blah', 'foo']"
 
309
 
 
310
    def test_sort4(self):
 
311
        @implements_to_string
 
312
        class Magic(object):
 
313
            def __init__(self, value):
 
314
                self.value = value
 
315
            def __str__(self):
 
316
                return text_type(self.value)
 
317
        tmpl = env.from_string('''{{ items|sort(attribute='value')|join }}''')
 
318
        assert tmpl.render(items=map(Magic, [3, 2, 4, 1])) == '1234'
 
319
 
 
320
    def test_groupby(self):
 
321
        tmpl = env.from_string('''
 
322
        {%- for grouper, list in [{'foo': 1, 'bar': 2},
 
323
                                  {'foo': 2, 'bar': 3},
 
324
                                  {'foo': 1, 'bar': 1},
 
325
                                  {'foo': 3, 'bar': 4}]|groupby('foo') -%}
 
326
            {{ grouper }}{% for x in list %}: {{ x.foo }}, {{ x.bar }}{% endfor %}|
 
327
        {%- endfor %}''')
 
328
        assert tmpl.render().split('|') == [
 
329
            "1: 1, 2: 1, 1",
 
330
            "2: 2, 3",
 
331
            "3: 3, 4",
 
332
            ""
 
333
        ]
 
334
 
 
335
    def test_groupby_tuple_index(self):
 
336
        tmpl = env.from_string('''
 
337
        {%- for grouper, list in [('a', 1), ('a', 2), ('b', 1)]|groupby(0) -%}
 
338
            {{ grouper }}{% for x in list %}:{{ x.1 }}{% endfor %}|
 
339
        {%- endfor %}''')
 
340
        assert tmpl.render() == 'a:1:2|b:1|'
 
341
 
 
342
    def test_groupby_multidot(self):
 
343
        class Date(object):
 
344
            def __init__(self, day, month, year):
 
345
                self.day = day
 
346
                self.month = month
 
347
                self.year = year
 
348
        class Article(object):
 
349
            def __init__(self, title, *date):
 
350
                self.date = Date(*date)
 
351
                self.title = title
 
352
        articles = [
 
353
            Article('aha', 1, 1, 1970),
 
354
            Article('interesting', 2, 1, 1970),
 
355
            Article('really?', 3, 1, 1970),
 
356
            Article('totally not', 1, 1, 1971)
 
357
        ]
 
358
        tmpl = env.from_string('''
 
359
        {%- for year, list in articles|groupby('date.year') -%}
 
360
            {{ year }}{% for x in list %}[{{ x.title }}]{% endfor %}|
 
361
        {%- endfor %}''')
 
362
        assert tmpl.render(articles=articles).split('|') == [
 
363
            '1970[aha][interesting][really?]',
 
364
            '1971[totally not]',
 
365
            ''
 
366
        ]
 
367
 
 
368
    def test_filtertag(self):
 
369
        tmpl = env.from_string("{% filter upper|replace('FOO', 'foo') %}"
 
370
                               "foobar{% endfilter %}")
 
371
        assert tmpl.render() == 'fooBAR'
 
372
 
 
373
    def test_replace(self):
 
374
        env = Environment()
 
375
        tmpl = env.from_string('{{ string|replace("o", 42) }}')
 
376
        assert tmpl.render(string='<foo>') == '<f4242>'
 
377
        env = Environment(autoescape=True)
 
378
        tmpl = env.from_string('{{ string|replace("o", 42) }}')
 
379
        assert tmpl.render(string='<foo>') == '&lt;f4242&gt;'
 
380
        tmpl = env.from_string('{{ string|replace("<", 42) }}')
 
381
        assert tmpl.render(string='<foo>') == '42foo&gt;'
 
382
        tmpl = env.from_string('{{ string|replace("o", ">x<") }}')
 
383
        assert tmpl.render(string=Markup('foo')) == 'f&gt;x&lt;&gt;x&lt;'
 
384
 
 
385
    def test_forceescape(self):
 
386
        tmpl = env.from_string('{{ x|forceescape }}')
 
387
        assert tmpl.render(x=Markup('<div />')) == u'&lt;div /&gt;'
 
388
 
 
389
    def test_safe(self):
 
390
        env = Environment(autoescape=True)
 
391
        tmpl = env.from_string('{{ "<div>foo</div>"|safe }}')
 
392
        assert tmpl.render() == '<div>foo</div>'
 
393
        tmpl = env.from_string('{{ "<div>foo</div>" }}')
 
394
        assert tmpl.render() == '&lt;div&gt;foo&lt;/div&gt;'
 
395
 
 
396
    def test_urlencode(self):
 
397
        env = Environment(autoescape=True)
 
398
        tmpl = env.from_string('{{ "Hello, world!"|urlencode }}')
 
399
        assert tmpl.render() == 'Hello%2C%20world%21'
 
400
        tmpl = env.from_string('{{ o|urlencode }}')
 
401
        assert tmpl.render(o=u"Hello, world\u203d") == "Hello%2C%20world%E2%80%BD"
 
402
        assert tmpl.render(o=(("f", 1),)) == "f=1"
 
403
        assert tmpl.render(o=(('f', 1), ("z", 2))) == "f=1&amp;z=2"
 
404
        assert tmpl.render(o=((u"\u203d", 1),)) == "%E2%80%BD=1"
 
405
        assert tmpl.render(o={u"\u203d": 1}) == "%E2%80%BD=1"
 
406
        assert tmpl.render(o={0: 1}) == "0=1"
 
407
 
 
408
    def test_simple_map(self):
 
409
        env = Environment()
 
410
        tmpl = env.from_string('{{ ["1", "2", "3"]|map("int")|sum }}')
 
411
        self.assertEqual(tmpl.render(), '6')
 
412
 
 
413
    def test_attribute_map(self):
 
414
        class User(object):
 
415
            def __init__(self, name):
 
416
                self.name = name
 
417
        env = Environment()
 
418
        users = [
 
419
            User('john'),
 
420
            User('jane'),
 
421
            User('mike'),
 
422
        ]
 
423
        tmpl = env.from_string('{{ users|map(attribute="name")|join("|") }}')
 
424
        self.assertEqual(tmpl.render(users=users), 'john|jane|mike')
 
425
 
 
426
    def test_empty_map(self):
 
427
        env = Environment()
 
428
        tmpl = env.from_string('{{ none|map("upper")|list }}')
 
429
        self.assertEqual(tmpl.render(), '[]')
 
430
 
 
431
    def test_simple_select(self):
 
432
        env = Environment()
 
433
        tmpl = env.from_string('{{ [1, 2, 3, 4, 5]|select("odd")|join("|") }}')
 
434
        self.assertEqual(tmpl.render(), '1|3|5')
 
435
 
 
436
    def test_bool_select(self):
 
437
        env = Environment()
 
438
        tmpl = env.from_string('{{ [none, false, 0, 1, 2, 3, 4, 5]|select|join("|") }}')
 
439
        self.assertEqual(tmpl.render(), '1|2|3|4|5')
 
440
 
 
441
    def test_simple_reject(self):
 
442
        env = Environment()
 
443
        tmpl = env.from_string('{{ [1, 2, 3, 4, 5]|reject("odd")|join("|") }}')
 
444
        self.assertEqual(tmpl.render(), '2|4')
 
445
 
 
446
    def test_bool_reject(self):
 
447
        env = Environment()
 
448
        tmpl = env.from_string('{{ [none, false, 0, 1, 2, 3, 4, 5]|reject|join("|") }}')
 
449
        self.assertEqual(tmpl.render(), 'None|False|0')
 
450
 
 
451
    def test_simple_select_attr(self):
 
452
        class User(object):
 
453
            def __init__(self, name, is_active):
 
454
                self.name = name
 
455
                self.is_active = is_active
 
456
        env = Environment()
 
457
        users = [
 
458
            User('john', True),
 
459
            User('jane', True),
 
460
            User('mike', False),
 
461
        ]
 
462
        tmpl = env.from_string('{{ users|selectattr("is_active")|'
 
463
            'map(attribute="name")|join("|") }}')
 
464
        self.assertEqual(tmpl.render(users=users), 'john|jane')
 
465
 
 
466
    def test_simple_reject_attr(self):
 
467
        class User(object):
 
468
            def __init__(self, name, is_active):
 
469
                self.name = name
 
470
                self.is_active = is_active
 
471
        env = Environment()
 
472
        users = [
 
473
            User('john', True),
 
474
            User('jane', True),
 
475
            User('mike', False),
 
476
        ]
 
477
        tmpl = env.from_string('{{ users|rejectattr("is_active")|'
 
478
            'map(attribute="name")|join("|") }}')
 
479
        self.assertEqual(tmpl.render(users=users), 'mike')
 
480
 
 
481
    def test_func_select_attr(self):
 
482
        class User(object):
 
483
            def __init__(self, id, name):
 
484
                self.id = id
 
485
                self.name = name
 
486
        env = Environment()
 
487
        users = [
 
488
            User(1, 'john'),
 
489
            User(2, 'jane'),
 
490
            User(3, 'mike'),
 
491
        ]
 
492
        tmpl = env.from_string('{{ users|selectattr("id", "odd")|'
 
493
            'map(attribute="name")|join("|") }}')
 
494
        self.assertEqual(tmpl.render(users=users), 'john|mike')
 
495
 
 
496
    def test_func_reject_attr(self):
 
497
        class User(object):
 
498
            def __init__(self, id, name):
 
499
                self.id = id
 
500
                self.name = name
 
501
        env = Environment()
 
502
        users = [
 
503
            User(1, 'john'),
 
504
            User(2, 'jane'),
 
505
            User(3, 'mike'),
 
506
        ]
 
507
        tmpl = env.from_string('{{ users|rejectattr("id", "odd")|'
 
508
            'map(attribute="name")|join("|") }}')
 
509
        self.assertEqual(tmpl.render(users=users), 'jane')
 
510
 
 
511
 
 
512
def suite():
 
513
    suite = unittest.TestSuite()
 
514
    suite.addTest(unittest.makeSuite(FilterTestCase))
 
515
    return suite