mirror of
https://github.com/janeczku/calibre-web
synced 2024-09-17 17:59:48 +00:00
306 lines
12 KiB
Python
306 lines
12 KiB
Python
|
# -*- coding: utf-8 -*-
|
||
|
"""
|
||
|
jinja2.testsuite.core_tags
|
||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||
|
|
||
|
Test the core tags like for and if.
|
||
|
|
||
|
:copyright: (c) 2010 by the Jinja Team.
|
||
|
:license: BSD, see LICENSE for more details.
|
||
|
"""
|
||
|
import unittest
|
||
|
|
||
|
from jinja2.testsuite import JinjaTestCase
|
||
|
|
||
|
from jinja2 import Environment, TemplateSyntaxError, UndefinedError, \
|
||
|
DictLoader
|
||
|
|
||
|
env = Environment()
|
||
|
|
||
|
|
||
|
class ForLoopTestCase(JinjaTestCase):
|
||
|
|
||
|
def test_simple(self):
|
||
|
tmpl = env.from_string('{% for item in seq %}{{ item }}{% endfor %}')
|
||
|
assert tmpl.render(seq=list(range(10))) == '0123456789'
|
||
|
|
||
|
def test_else(self):
|
||
|
tmpl = env.from_string('{% for item in seq %}XXX{% else %}...{% endfor %}')
|
||
|
assert tmpl.render() == '...'
|
||
|
|
||
|
def test_empty_blocks(self):
|
||
|
tmpl = env.from_string('<{% for item in seq %}{% else %}{% endfor %}>')
|
||
|
assert tmpl.render() == '<>'
|
||
|
|
||
|
def test_context_vars(self):
|
||
|
tmpl = env.from_string('''{% for item in seq -%}
|
||
|
{{ loop.index }}|{{ loop.index0 }}|{{ loop.revindex }}|{{
|
||
|
loop.revindex0 }}|{{ loop.first }}|{{ loop.last }}|{{
|
||
|
loop.length }}###{% endfor %}''')
|
||
|
one, two, _ = tmpl.render(seq=[0, 1]).split('###')
|
||
|
(one_index, one_index0, one_revindex, one_revindex0, one_first,
|
||
|
one_last, one_length) = one.split('|')
|
||
|
(two_index, two_index0, two_revindex, two_revindex0, two_first,
|
||
|
two_last, two_length) = two.split('|')
|
||
|
|
||
|
assert int(one_index) == 1 and int(two_index) == 2
|
||
|
assert int(one_index0) == 0 and int(two_index0) == 1
|
||
|
assert int(one_revindex) == 2 and int(two_revindex) == 1
|
||
|
assert int(one_revindex0) == 1 and int(two_revindex0) == 0
|
||
|
assert one_first == 'True' and two_first == 'False'
|
||
|
assert one_last == 'False' and two_last == 'True'
|
||
|
assert one_length == two_length == '2'
|
||
|
|
||
|
def test_cycling(self):
|
||
|
tmpl = env.from_string('''{% for item in seq %}{{
|
||
|
loop.cycle('<1>', '<2>') }}{% endfor %}{%
|
||
|
for item in seq %}{{ loop.cycle(*through) }}{% endfor %}''')
|
||
|
output = tmpl.render(seq=list(range(4)), through=('<1>', '<2>'))
|
||
|
assert output == '<1><2>' * 4
|
||
|
|
||
|
def test_scope(self):
|
||
|
tmpl = env.from_string('{% for item in seq %}{% endfor %}{{ item }}')
|
||
|
output = tmpl.render(seq=list(range(10)))
|
||
|
assert not output
|
||
|
|
||
|
def test_varlen(self):
|
||
|
def inner():
|
||
|
for item in range(5):
|
||
|
yield item
|
||
|
tmpl = env.from_string('{% for item in iter %}{{ item }}{% endfor %}')
|
||
|
output = tmpl.render(iter=inner())
|
||
|
assert output == '01234'
|
||
|
|
||
|
def test_noniter(self):
|
||
|
tmpl = env.from_string('{% for item in none %}...{% endfor %}')
|
||
|
self.assert_raises(TypeError, tmpl.render)
|
||
|
|
||
|
def test_recursive(self):
|
||
|
tmpl = env.from_string('''{% for item in seq recursive -%}
|
||
|
[{{ item.a }}{% if item.b %}<{{ loop(item.b) }}>{% endif %}]
|
||
|
{%- endfor %}''')
|
||
|
assert tmpl.render(seq=[
|
||
|
dict(a=1, b=[dict(a=1), dict(a=2)]),
|
||
|
dict(a=2, b=[dict(a=1), dict(a=2)]),
|
||
|
dict(a=3, b=[dict(a='a')])
|
||
|
]) == '[1<[1][2]>][2<[1][2]>][3<[a]>]'
|
||
|
|
||
|
def test_recursive_depth0(self):
|
||
|
tmpl = env.from_string('''{% for item in seq recursive -%}
|
||
|
[{{ loop.depth0 }}:{{ item.a }}{% if item.b %}<{{ loop(item.b) }}>{% endif %}]
|
||
|
{%- endfor %}''')
|
||
|
self.assertEqual(tmpl.render(seq=[
|
||
|
dict(a=1, b=[dict(a=1), dict(a=2)]),
|
||
|
dict(a=2, b=[dict(a=1), dict(a=2)]),
|
||
|
dict(a=3, b=[dict(a='a')])
|
||
|
]), '[0:1<[1:1][1:2]>][0:2<[1:1][1:2]>][0:3<[1:a]>]')
|
||
|
|
||
|
def test_recursive_depth(self):
|
||
|
tmpl = env.from_string('''{% for item in seq recursive -%}
|
||
|
[{{ loop.depth }}:{{ item.a }}{% if item.b %}<{{ loop(item.b) }}>{% endif %}]
|
||
|
{%- endfor %}''')
|
||
|
self.assertEqual(tmpl.render(seq=[
|
||
|
dict(a=1, b=[dict(a=1), dict(a=2)]),
|
||
|
dict(a=2, b=[dict(a=1), dict(a=2)]),
|
||
|
dict(a=3, b=[dict(a='a')])
|
||
|
]), '[1:1<[2:1][2:2]>][1:2<[2:1][2:2]>][1:3<[2:a]>]')
|
||
|
|
||
|
def test_looploop(self):
|
||
|
tmpl = env.from_string('''{% for row in table %}
|
||
|
{%- set rowloop = loop -%}
|
||
|
{% for cell in row -%}
|
||
|
[{{ rowloop.index }}|{{ loop.index }}]
|
||
|
{%- endfor %}
|
||
|
{%- endfor %}''')
|
||
|
assert tmpl.render(table=['ab', 'cd']) == '[1|1][1|2][2|1][2|2]'
|
||
|
|
||
|
def test_reversed_bug(self):
|
||
|
tmpl = env.from_string('{% for i in items %}{{ i }}'
|
||
|
'{% if not loop.last %}'
|
||
|
',{% endif %}{% endfor %}')
|
||
|
assert tmpl.render(items=reversed([3, 2, 1])) == '1,2,3'
|
||
|
|
||
|
def test_loop_errors(self):
|
||
|
tmpl = env.from_string('''{% for item in [1] if loop.index
|
||
|
== 0 %}...{% endfor %}''')
|
||
|
self.assert_raises(UndefinedError, tmpl.render)
|
||
|
tmpl = env.from_string('''{% for item in [] %}...{% else
|
||
|
%}{{ loop }}{% endfor %}''')
|
||
|
assert tmpl.render() == ''
|
||
|
|
||
|
def test_loop_filter(self):
|
||
|
tmpl = env.from_string('{% for item in range(10) if item '
|
||
|
'is even %}[{{ item }}]{% endfor %}')
|
||
|
assert tmpl.render() == '[0][2][4][6][8]'
|
||
|
tmpl = env.from_string('''
|
||
|
{%- for item in range(10) if item is even %}[{{
|
||
|
loop.index }}:{{ item }}]{% endfor %}''')
|
||
|
assert tmpl.render() == '[1:0][2:2][3:4][4:6][5:8]'
|
||
|
|
||
|
def test_loop_unassignable(self):
|
||
|
self.assert_raises(TemplateSyntaxError, env.from_string,
|
||
|
'{% for loop in seq %}...{% endfor %}')
|
||
|
|
||
|
def test_scoped_special_var(self):
|
||
|
t = env.from_string('{% for s in seq %}[{{ loop.first }}{% for c in s %}'
|
||
|
'|{{ loop.first }}{% endfor %}]{% endfor %}')
|
||
|
assert t.render(seq=('ab', 'cd')) == '[True|True|False][False|True|False]'
|
||
|
|
||
|
def test_scoped_loop_var(self):
|
||
|
t = env.from_string('{% for x in seq %}{{ loop.first }}'
|
||
|
'{% for y in seq %}{% endfor %}{% endfor %}')
|
||
|
assert t.render(seq='ab') == 'TrueFalse'
|
||
|
t = env.from_string('{% for x in seq %}{% for y in seq %}'
|
||
|
'{{ loop.first }}{% endfor %}{% endfor %}')
|
||
|
assert t.render(seq='ab') == 'TrueFalseTrueFalse'
|
||
|
|
||
|
def test_recursive_empty_loop_iter(self):
|
||
|
t = env.from_string('''
|
||
|
{%- for item in foo recursive -%}{%- endfor -%}
|
||
|
''')
|
||
|
assert t.render(dict(foo=[])) == ''
|
||
|
|
||
|
def test_call_in_loop(self):
|
||
|
t = env.from_string('''
|
||
|
{%- macro do_something() -%}
|
||
|
[{{ caller() }}]
|
||
|
{%- endmacro %}
|
||
|
|
||
|
{%- for i in [1, 2, 3] %}
|
||
|
{%- call do_something() -%}
|
||
|
{{ i }}
|
||
|
{%- endcall %}
|
||
|
{%- endfor -%}
|
||
|
''')
|
||
|
assert t.render() == '[1][2][3]'
|
||
|
|
||
|
def test_scoping_bug(self):
|
||
|
t = env.from_string('''
|
||
|
{%- for item in foo %}...{{ item }}...{% endfor %}
|
||
|
{%- macro item(a) %}...{{ a }}...{% endmacro %}
|
||
|
{{- item(2) -}}
|
||
|
''')
|
||
|
assert t.render(foo=(1,)) == '...1......2...'
|
||
|
|
||
|
def test_unpacking(self):
|
||
|
tmpl = env.from_string('{% for a, b, c in [[1, 2, 3]] %}'
|
||
|
'{{ a }}|{{ b }}|{{ c }}{% endfor %}')
|
||
|
assert tmpl.render() == '1|2|3'
|
||
|
|
||
|
|
||
|
class IfConditionTestCase(JinjaTestCase):
|
||
|
|
||
|
def test_simple(self):
|
||
|
tmpl = env.from_string('''{% if true %}...{% endif %}''')
|
||
|
assert tmpl.render() == '...'
|
||
|
|
||
|
def test_elif(self):
|
||
|
tmpl = env.from_string('''{% if false %}XXX{% elif true
|
||
|
%}...{% else %}XXX{% endif %}''')
|
||
|
assert tmpl.render() == '...'
|
||
|
|
||
|
def test_else(self):
|
||
|
tmpl = env.from_string('{% if false %}XXX{% else %}...{% endif %}')
|
||
|
assert tmpl.render() == '...'
|
||
|
|
||
|
def test_empty(self):
|
||
|
tmpl = env.from_string('[{% if true %}{% else %}{% endif %}]')
|
||
|
assert tmpl.render() == '[]'
|
||
|
|
||
|
def test_complete(self):
|
||
|
tmpl = env.from_string('{% if a %}A{% elif b %}B{% elif c == d %}'
|
||
|
'C{% else %}D{% endif %}')
|
||
|
assert tmpl.render(a=0, b=False, c=42, d=42.0) == 'C'
|
||
|
|
||
|
def test_no_scope(self):
|
||
|
tmpl = env.from_string('{% if a %}{% set foo = 1 %}{% endif %}{{ foo }}')
|
||
|
assert tmpl.render(a=True) == '1'
|
||
|
tmpl = env.from_string('{% if true %}{% set foo = 1 %}{% endif %}{{ foo }}')
|
||
|
assert tmpl.render() == '1'
|
||
|
|
||
|
|
||
|
class MacrosTestCase(JinjaTestCase):
|
||
|
env = Environment(trim_blocks=True)
|
||
|
|
||
|
def test_simple(self):
|
||
|
tmpl = self.env.from_string('''\
|
||
|
{% macro say_hello(name) %}Hello {{ name }}!{% endmacro %}
|
||
|
{{ say_hello('Peter') }}''')
|
||
|
assert tmpl.render() == 'Hello Peter!'
|
||
|
|
||
|
def test_scoping(self):
|
||
|
tmpl = self.env.from_string('''\
|
||
|
{% macro level1(data1) %}
|
||
|
{% macro level2(data2) %}{{ data1 }}|{{ data2 }}{% endmacro %}
|
||
|
{{ level2('bar') }}{% endmacro %}
|
||
|
{{ level1('foo') }}''')
|
||
|
assert tmpl.render() == 'foo|bar'
|
||
|
|
||
|
def test_arguments(self):
|
||
|
tmpl = self.env.from_string('''\
|
||
|
{% macro m(a, b, c='c', d='d') %}{{ a }}|{{ b }}|{{ c }}|{{ d }}{% endmacro %}
|
||
|
{{ m() }}|{{ m('a') }}|{{ m('a', 'b') }}|{{ m(1, 2, 3) }}''')
|
||
|
assert tmpl.render() == '||c|d|a||c|d|a|b|c|d|1|2|3|d'
|
||
|
|
||
|
def test_varargs(self):
|
||
|
tmpl = self.env.from_string('''\
|
||
|
{% macro test() %}{{ varargs|join('|') }}{% endmacro %}\
|
||
|
{{ test(1, 2, 3) }}''')
|
||
|
assert tmpl.render() == '1|2|3'
|
||
|
|
||
|
def test_simple_call(self):
|
||
|
tmpl = self.env.from_string('''\
|
||
|
{% macro test() %}[[{{ caller() }}]]{% endmacro %}\
|
||
|
{% call test() %}data{% endcall %}''')
|
||
|
assert tmpl.render() == '[[data]]'
|
||
|
|
||
|
def test_complex_call(self):
|
||
|
tmpl = self.env.from_string('''\
|
||
|
{% macro test() %}[[{{ caller('data') }}]]{% endmacro %}\
|
||
|
{% call(data) test() %}{{ data }}{% endcall %}''')
|
||
|
assert tmpl.render() == '[[data]]'
|
||
|
|
||
|
def test_caller_undefined(self):
|
||
|
tmpl = self.env.from_string('''\
|
||
|
{% set caller = 42 %}\
|
||
|
{% macro test() %}{{ caller is not defined }}{% endmacro %}\
|
||
|
{{ test() }}''')
|
||
|
assert tmpl.render() == 'True'
|
||
|
|
||
|
def test_include(self):
|
||
|
self.env = Environment(loader=DictLoader({'include':
|
||
|
'{% macro test(foo) %}[{{ foo }}]{% endmacro %}'}))
|
||
|
tmpl = self.env.from_string('{% from "include" import test %}{{ test("foo") }}')
|
||
|
assert tmpl.render() == '[foo]'
|
||
|
|
||
|
def test_macro_api(self):
|
||
|
tmpl = self.env.from_string('{% macro foo(a, b) %}{% endmacro %}'
|
||
|
'{% macro bar() %}{{ varargs }}{{ kwargs }}{% endmacro %}'
|
||
|
'{% macro baz() %}{{ caller() }}{% endmacro %}')
|
||
|
assert tmpl.module.foo.arguments == ('a', 'b')
|
||
|
assert tmpl.module.foo.defaults == ()
|
||
|
assert tmpl.module.foo.name == 'foo'
|
||
|
assert not tmpl.module.foo.caller
|
||
|
assert not tmpl.module.foo.catch_kwargs
|
||
|
assert not tmpl.module.foo.catch_varargs
|
||
|
assert tmpl.module.bar.arguments == ()
|
||
|
assert tmpl.module.bar.defaults == ()
|
||
|
assert not tmpl.module.bar.caller
|
||
|
assert tmpl.module.bar.catch_kwargs
|
||
|
assert tmpl.module.bar.catch_varargs
|
||
|
assert tmpl.module.baz.caller
|
||
|
|
||
|
def test_callself(self):
|
||
|
tmpl = self.env.from_string('{% macro foo(x) %}{{ x }}{% if x > 1 %}|'
|
||
|
'{{ foo(x - 1) }}{% endif %}{% endmacro %}'
|
||
|
'{{ foo(5) }}')
|
||
|
assert tmpl.render() == '5|4|3|2|1'
|
||
|
|
||
|
|
||
|
def suite():
|
||
|
suite = unittest.TestSuite()
|
||
|
suite.addTest(unittest.makeSuite(ForLoopTestCase))
|
||
|
suite.addTest(unittest.makeSuite(IfConditionTestCase))
|
||
|
suite.addTest(unittest.makeSuite(MacrosTestCase))
|
||
|
return suite
|