1 # -*- coding: utf-8 -*-
6 Tests for the extensions.
8 :copyright: (c) 2010 by the Jinja Team.
9 :license: BSD, see LICENSE for more details.
14 from jinja2.testsuite import JinjaTestCase, filesystem_loader
16 from jinja2 import Environment, DictLoader, contextfunction, nodes
17 from jinja2.exceptions import TemplateAssertionError
18 from jinja2.ext import Extension
19 from jinja2.lexer import Token, count_newlines
20 from jinja2.utils import next
24 from io import BytesIO
26 from StringIO import StringIO as BytesIO
29 importable_object = 23
31 _gettext_re = re.compile(r'_\((.*?)\)(?s)')
35 'master.html': '<title>{{ page_title|default(_("missing")) }}</title>'
36 '{% block body %}{% endblock %}',
37 'child.html': '{% extends "master.html" %}{% block body %}'
38 '{% trans %}watch out{% endtrans %}{% endblock %}',
39 'plural.html': '{% trans user_count %}One user online{% pluralize %}'
40 '{{ user_count }} users online{% endtrans %}',
41 'stringformat.html': '{{ _("User: %d")|format(user_count) }}'
48 'watch out': 'pass auf',
49 'One user online': 'Ein Benutzer online',
50 '%(user_count)s users online': '%(user_count)s Benutzer online',
51 'User: %d': 'Benutzer: %d'
57 def gettext(context, string):
58 language = context.get('LANGUAGE', 'en')
59 return languages.get(language, {}).get(string, string)
63 def ngettext(context, s, p, n):
64 language = context.get('LANGUAGE', 'en')
66 return languages.get(language, {}).get(p, p)
67 return languages.get(language, {}).get(s, s)
70 i18n_env = Environment(
71 loader=DictLoader(templates),
72 extensions=['jinja2.ext.i18n']
74 i18n_env.globals.update({
81 class TestExtension(Extension):
85 def parse(self, parser):
86 return nodes.Output([self.call_method('_dump', [
87 nodes.EnvironmentAttribute('sandboxed'),
88 self.attr('ext_attr'),
89 nodes.ImportedName(__name__ + '.importable_object'),
90 nodes.ContextReference()
91 ])]).set_lineno(next(parser.stream).lineno)
93 def _dump(self, sandboxed, ext_attr, imported_object, context):
94 return '%s|%s|%s|%s' % (
102 class PreprocessorExtension(Extension):
104 def preprocess(self, source, name, filename=None):
105 return source.replace('[[TEST]]', '({{ foo }})')
108 class StreamFilterExtension(Extension):
110 def filter_stream(self, stream):
112 if token.type == 'data':
113 for t in self.interpolate(token):
118 def interpolate(self, token):
120 end = len(token.value)
121 lineno = token.lineno
123 match = _gettext_re.search(token.value, pos)
126 value = token.value[pos:match.start()]
128 yield Token(lineno, 'data', value)
129 lineno += count_newlines(token.value)
130 yield Token(lineno, 'variable_begin', None)
131 yield Token(lineno, 'name', 'gettext')
132 yield Token(lineno, 'lparen', None)
133 yield Token(lineno, 'string', match.group(1))
134 yield Token(lineno, 'rparen', None)
135 yield Token(lineno, 'variable_end', None)
138 yield Token(lineno, 'data', token.value[pos:])
141 class ExtensionsTestCase(JinjaTestCase):
143 def test_loop_controls(self):
144 env = Environment(extensions=['jinja2.ext.loopcontrols'])
146 tmpl = env.from_string('''
147 {%- for item in [1, 2, 3, 4] %}
148 {%- if item % 2 == 0 %}{% continue %}{% endif -%}
151 assert tmpl.render() == '13'
153 tmpl = env.from_string('''
154 {%- for item in [1, 2, 3, 4] %}
155 {%- if item > 2 %}{% break %}{% endif -%}
158 assert tmpl.render() == '12'
161 env = Environment(extensions=['jinja2.ext.do'])
162 tmpl = env.from_string('''
163 {%- set items = [] %}
164 {%- for char in "foo" %}
165 {%- do items.append(loop.index0 ~ char) %}
166 {%- endfor %}{{ items|join(', ') }}''')
167 assert tmpl.render() == '0f, 1o, 2o'
170 env = Environment(extensions=['jinja2.ext.with_'])
171 tmpl = env.from_string('''\
172 {% with a=42, b=23 -%}
177 assert [x.strip() for x in tmpl.render(a=1, b=2).splitlines()] \
178 == ['42 = 23', '1 = 2']
180 def test_extension_nodes(self):
181 env = Environment(extensions=[TestExtension])
182 tmpl = env.from_string('{% test %}')
183 assert tmpl.render() == 'False|42|23|{}'
185 def test_identifier(self):
186 assert TestExtension.identifier == __name__ + '.TestExtension'
188 def test_rebinding(self):
189 original = Environment(extensions=[TestExtension])
190 overlay = original.overlay()
191 for env in original, overlay:
192 for ext in env.extensions.itervalues():
193 assert ext.environment is env
195 def test_preprocessor_extension(self):
196 env = Environment(extensions=[PreprocessorExtension])
197 tmpl = env.from_string('{[[TEST]]}')
198 assert tmpl.render(foo=42) == '{(42)}'
200 def test_streamfilter_extension(self):
201 env = Environment(extensions=[StreamFilterExtension])
202 env.globals['gettext'] = lambda x: x.upper()
203 tmpl = env.from_string('Foo _(bar) Baz')
205 assert out == 'Foo BAR Baz'
208 class InternationalizationTestCase(JinjaTestCase):
210 def test_trans(self):
211 tmpl = i18n_env.get_template('child.html')
212 assert tmpl.render(LANGUAGE='de') == '<title>fehlend</title>pass auf'
214 def test_trans_plural(self):
215 tmpl = i18n_env.get_template('plural.html')
216 assert tmpl.render(LANGUAGE='de', user_count=1) == 'Ein Benutzer online'
217 assert tmpl.render(LANGUAGE='de', user_count=2) == '2 Benutzer online'
219 def test_complex_plural(self):
220 tmpl = i18n_env.from_string('{% trans foo=42, count=2 %}{{ count }} item{% '
221 'pluralize count %}{{ count }} items{% endtrans %}')
222 assert tmpl.render() == '2 items'
223 self.assert_raises(TemplateAssertionError, i18n_env.from_string,
224 '{% trans foo %}...{% pluralize bar %}...{% endtrans %}')
226 def test_trans_stringformatting(self):
227 tmpl = i18n_env.get_template('stringformat.html')
228 assert tmpl.render(LANGUAGE='de', user_count=5) == 'Benutzer: 5'
230 def test_extract(self):
231 from jinja2.ext import babel_extract
233 {{ gettext('Hello World') }}
234 {% trans %}Hello World{% endtrans %}
235 {% trans %}{{ users }} user{% pluralize %}{{ users }} users{% endtrans %}
236 '''.encode('ascii')) # make python 3 happy
237 assert list(babel_extract(source, ('gettext', 'ngettext', '_'), [], {})) == [
238 (2, 'gettext', u'Hello World', []),
239 (3, 'gettext', u'Hello World', []),
240 (4, 'ngettext', (u'%(users)s user', u'%(users)s users', None), [])
243 def test_comment_extract(self):
244 from jinja2.ext import babel_extract
247 {{ gettext('Hello World') }}
248 {% trans %}Hello World{% endtrans %}{# trans second #}
250 {% trans %}{{ users }} user{% pluralize %}{{ users }} users{% endtrans %}
251 '''.encode('utf-8')) # make python 3 happy
252 assert list(babel_extract(source, ('gettext', 'ngettext', '_'), ['trans', ':'], {})) == [
253 (3, 'gettext', u'Hello World', ['first']),
254 (4, 'gettext', u'Hello World', ['second']),
255 (6, 'ngettext', (u'%(users)s user', u'%(users)s users', None), ['third'])
260 suite = unittest.TestSuite()
261 suite.addTest(unittest.makeSuite(ExtensionsTestCase))
262 suite.addTest(unittest.makeSuite(InternationalizationTestCase))