wcs/tests/test_templates.py

1014 lines
42 KiB
Python
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# -*- coding: utf-8 -*-
import datetime
import os
import pytest
import string
try:
import langdetect
except ImportError:
langdetect = None
from django.test import override_settings
from django.utils.timezone import now
from wcs.qommon.http_request import HTTPRequest
from wcs.qommon.substitution import CompatibilityNamesDict
from wcs.qommon.template import Template, TemplateError
from wcs.variables import LazyFormData
from wcs.formdef import FormDef
from wcs import fields
from utilities import create_temporary_pub, clean_temporary_pub
@pytest.fixture
def pub():
pub = create_temporary_pub()
pub.substitutions.feed(pub)
req = HTTPRequest(None, {'SCRIPT_NAME': '/', 'SERVER_NAME': 'example.net'})
pub.set_app_dir(req)
pub.site_options.set('options', 'working_day_calendar', '')
pub.site_options.write(open(os.path.join(pub.app_dir, 'site-options.cfg'), 'w'))
return pub
def teardown_module(module):
clean_temporary_pub()
def test_template():
tmpl = Template('')
assert tmpl.render() == ''
assert tmpl.render({'foo': 'bar'}) == ''
tmpl = Template('zoo')
assert tmpl.render() == 'zoo'
assert tmpl.render({'foo': 'bar'}) == 'zoo'
# django
tmpl = Template('{{ foo }}')
assert tmpl.render() == ''
assert tmpl.render({'foo': 'bar'}) == 'bar'
tmpl = Template('{% if foo %}{{ foo }}{% endif %}')
assert tmpl.render() == ''
assert tmpl.render({'foo': 'bar'}) == 'bar'
# ezt
tmpl = Template('[foo]')
assert tmpl.render() == '[foo]'
assert tmpl.render({'foo': 'bar'}) == 'bar'
tmpl = Template('[if-any foo][foo][end]')
assert tmpl.render() == ''
assert tmpl.render({'foo': 'bar'}) == 'bar'
# mix Django/ezt: Django wins
tmpl = Template('{% if foo %}{{ foo }}[foo]{% endif %}')
assert tmpl.render({'foo': 'bar'}) == 'bar[foo]'
# django syntax error
with pytest.raises(TemplateError):
tmpl = Template('{% if foo %}{{ foo }}{% end %}', raises=True)
tmpl = Template('{% if foo %}{{ foo }}{% end %}')
assert tmpl.render({'foo': 'bar'}) == '{% if foo %}{{ foo }}{% end %}'
# ezt syntax error
with pytest.raises(TemplateError):
tmpl = Template('[if-any foo][foo][endif]', raises=True)
tmpl = Template('[if-any foo][foo][endif]')
assert tmpl.render({'foo': 'bar'}) == '[if-any foo][foo][endif]'
def test_now_and_today_variables(pub):
# create a today string, verify it contains the year, at least
today = Template('{{d}}').render({'d': datetime.date.today()})
assert datetime.date.today().strftime('%Y') in today
tmpl = Template('{{ today }}')
for mode in (None, 'lazy'):
context = pub.substitutions.get_context_variables(mode=mode)
assert tmpl.render(context) == today
tmpl = Template('{{ now }}')
for mode in (None, 'lazy'):
context = pub.substitutions.get_context_variables(mode=mode)
assert today in tmpl.render(context) # contains the date,
assert tmpl.render(context) != today # but not only
# ezt templates (legacy)
today = Template('[t]').render({'t': datetime.date.today()})
assert today == datetime.date.today().strftime('%Y-%m-%d')
now = Template('[n]').render({'n': datetime.datetime.now()})
assert now == datetime.datetime.now().strftime('%Y-%m-%d %H:%M')
tmpl = Template('[today]')
for mode in (None, 'lazy'):
context = pub.substitutions.get_context_variables(mode=mode)
assert tmpl.render(context) == today
tmpl = Template('[now]')
for mode in (None, 'lazy'):
context = pub.substitutions.get_context_variables(mode=mode)
assert tmpl.render(context) == now
def test_template_templatetag():
# check qommon templatetags are always loaded
tmpl = Template('{{ date|parse_datetime|date:"Y" }}')
assert tmpl.render({'date': '2018-06-06'}) == '2018'
# check other templatetags can be loaded
tmpl = Template('{% load i18n %}{% trans "hello" %}')
assert tmpl.render() == 'hello'
def test_startswith_templatetag():
tmpl = Template('{% if foo|startswith:"bar" %}hello{% endif %}')
assert tmpl.render() == ''
assert tmpl.render({'foo': 'bar-baz'}) == 'hello'
assert tmpl.render({'foo': 'baz-bar'}) == ''
def test_endswith_templatetag():
tmpl = Template('{% if foo|endswith:"bar" %}hello{% endif %}')
assert tmpl.render() == ''
assert tmpl.render({'foo': 'baz-bar'}) == 'hello'
assert tmpl.render({'foo': 'bar-baz'}) == ''
def test_split_templatetag():
tmpl = Template('{{ foo|split|last }}')
assert tmpl.render() == ''
assert tmpl.render({'foo': 'bar baz'}) == 'baz'
assert tmpl.render({'foo': 'baz-bar'}) == 'baz-bar'
tmpl = Template('{{ foo|split:"-"|last }}')
assert tmpl.render() == ''
assert tmpl.render({'foo': 'bar-baz'}) == 'baz'
assert tmpl.render({'foo': 'baz-bar'}) == 'bar'
def test_strip_templatetag():
tmpl = Template('{{ foo|strip }}')
assert tmpl.render() == ''
assert tmpl.render({'foo': None}) == ''
assert tmpl.render({'foo': ' foo bar '}) == 'foo bar'
assert tmpl.render({'foo': ' foo bar\t'}) == 'foo bar'
assert tmpl.render({'foo': ' félé '}) == 'félé'
tmpl = Template('{{ foo|strip:"XY" }}')
assert tmpl.render({'foo': 'XXfoo barXYX'}) == 'foo bar'
assert tmpl.render({'foo': ' foo barXX'}) == ' foo bar'
def test_removeprefix_templatetag():
tmpl = Template('{{ foo|removeprefix }}')
assert tmpl.render() == ''
assert tmpl.render({'foo': None}) == ''
assert tmpl.render({'foo': 'foo bar'}) == 'foo bar'
tmpl = Template('{{ foo|removeprefix:"" }}')
assert tmpl.render({'foo': 'foo bar'}) == 'foo bar'
tmpl = Template('{{ foo|removeprefix:"XY" }}')
assert tmpl.render({'foo': 'XYfoo barXY'}) == 'foo barXY'
assert tmpl.render({'foo': 'foo bar'}) == 'foo bar'
assert tmpl.render({'foo': 'xyfoo barXY'}) == 'xyfoo barXY'
assert tmpl.render({'foo': ' XYfoo barXY'}) == ' XYfoo barXY'
assert tmpl.render({'foo': 'XYXYfoo barXY'}) == 'XYfoo barXY'
def test_removesuffix_templatetag():
tmpl = Template('{{ foo|removesuffix }}')
assert tmpl.render() == ''
assert tmpl.render({'foo': None}) == ''
assert tmpl.render({'foo': 'foo bar'}) == 'foo bar'
tmpl = Template('{{ foo|removesuffix:"" }}')
assert tmpl.render({'foo': 'foo bar'}) == 'foo bar'
tmpl = Template('{{ foo|removesuffix:"XY" }}')
assert tmpl.render({'foo': 'XYfoo barXY'}) == 'XYfoo bar'
assert tmpl.render({'foo': 'foo bar'}) == 'foo bar'
assert tmpl.render({'foo': 'XYfoo barxy'}) == 'XYfoo barxy'
assert tmpl.render({'foo': 'XYfoo barXY '}) == 'XYfoo barXY '
assert tmpl.render({'foo': 'XYfoo barXYXY'}) == 'XYfoo barXY'
def test_unaccent_templatetag():
tmpl = Template('{{ foo|unaccent }}')
assert tmpl.render() == ''
assert tmpl.render({'foo': None}) == ''
assert tmpl.render({'foo': 'FOO bar'}) == 'FOO bar'
assert tmpl.render({'foo': 'félé'}) == 'fele'
def test_template_encoding():
# django
tmpl = Template('{{ foo }} à vélo')
assert tmpl.render() == ' à vélo'
assert tmpl.render({'foo': 'fou'}) == 'fou à vélo'
assert tmpl.render({'foo': 'félé'}) == 'félé à vélo'
tmpl = Template("{% if foo == 'félé' %}à vélo{% endif %}")
assert tmpl.render() == ''
assert tmpl.render({'foo': 'fou'}) == ''
assert tmpl.render({'foo': 'félé'}) == 'à vélo'
tmpl = Template("{% if foo.bar == 'félé' %}à vélo{% endif %}")
assert tmpl.render() == ''
assert tmpl.render({'foo': {'bar': 'fou'}}) == ''
assert tmpl.render({'foo': {'bar': 'félé'}}) == 'à vélo'
# ezt
tmpl = Template('[foo] à vélo')
assert tmpl.render() == '[foo] à vélo'
assert tmpl.render({'foo': 'fou'}) == 'fou à vélo'
assert tmpl.render({'foo': 'félé'}) == 'félé à vélo'
def test_datetime_templatetags():
tmpl = Template('{{ plop|datetime }}')
assert tmpl.render({'plop': '2017-12-21 10:32'}) == '2017-12-21 10:32'
assert tmpl.render({'plop': '21/12/2017 10h32'}) == '2017-12-21 10:32'
assert tmpl.render({'plop': '2017-12-21'}) == '2017-12-21 00:00'
assert tmpl.render({'plop': '21/12/2017'}) == '2017-12-21 00:00'
with override_settings(LANGUAGE_CODE='fr-fr'):
assert tmpl.render({'plop': '2017-12-21 10:32'}) == '21/12/2017 10:32'
assert tmpl.render({'plop': '21/12/2017 10h32'}) == '21/12/2017 10:32'
assert tmpl.render({'plop': '2017-12-21'}) == '21/12/2017 00:00'
assert tmpl.render({'plop': '21/12/2017'}) == '21/12/2017 00:00'
assert tmpl.render({'plop': '10h32'}) == ''
assert tmpl.render({'plop': 'x'}) == ''
assert tmpl.render({'plop': None}) == ''
assert tmpl.render({'plop': 3}) == ''
assert tmpl.render({'plop': {'foo': 'bar'}}) == ''
assert tmpl.render() == ''
tmpl = Template('{{ plop|datetime:"d i" }}')
assert tmpl.render({'plop': '2017-12-21 10:32'}) == '21 32'
assert tmpl.render({'plop': '2017-12-21 10:32:42'}) == '21 32'
assert tmpl.render({'plop': '21/12/2017 10:32'}) == '21 32'
assert tmpl.render({'plop': '21/12/2017 10:32:42'}) == '21 32'
assert tmpl.render({'plop': '21/12/2017 10h32'}) == '21 32'
assert tmpl.render({'plop': '21/12/2017'}) == '21 00'
assert tmpl.render({'plop': '10h32'}) == ''
assert tmpl.render({'plop': 'x'}) == ''
assert tmpl.render({'plop': None}) == ''
assert tmpl.render({'plop': 3}) == ''
assert tmpl.render({'plop': {'foo': 'bar'}}) == ''
assert tmpl.render() == ''
tmpl = Template('{% if d1|datetime > d2|datetime %}d1>d2{% else %}d1<=d2{% endif %}')
assert tmpl.render({'d1': '2017-12-22', 'd2': '2017-12-21'}) == 'd1>d2'
assert tmpl.render({'d1': '2017-12-21', 'd2': '2017-12-21'}) == 'd1<=d2'
assert tmpl.render({'d1': '2017-12-21 10:30', 'd2': '2017-12-21 09:00'}) == 'd1>d2'
assert tmpl.render({'d1': '2017-12-21 10:30', 'd2': '2017-12-21'}) == 'd1>d2'
assert tmpl.render({'d1': '2017-12-22'}) == 'd1<=d2'
assert tmpl.render({'d2': '2017-12-22'}) == 'd1<=d2'
tmpl = Template('{{ plop|date }}')
assert tmpl.render({'plop': '2017-12-21'}) == '2017-12-21'
assert tmpl.render({'plop': '21/12/2017'}) == '2017-12-21'
assert tmpl.render({'plop': '2017-12-21 10:32'}) == '2017-12-21'
assert tmpl.render({'plop': '21/12/2017 10:32'}) == '2017-12-21'
assert tmpl.render({'plop': '21/12/2017 10h32'}) == '2017-12-21'
assert tmpl.render({'plop': '21/12/2017 10:32:42'}) == '2017-12-21'
with override_settings(LANGUAGE_CODE='fr-fr'):
assert tmpl.render({'plop': '2017-12-21'}) == '21/12/2017'
assert tmpl.render({'plop': '21/12/2017'}) == '21/12/2017'
assert tmpl.render({'plop': '2017-12-21 10:32'}) == '21/12/2017'
assert tmpl.render({'plop': '21/12/2017 10:32'}) == '21/12/2017'
assert tmpl.render({'plop': '21/12/2017 10h32'}) == '21/12/2017'
assert tmpl.render({'plop': '21/12/2017 10:32:42'}) == '21/12/2017'
assert tmpl.render({'plop': '10:32'}) == ''
assert tmpl.render({'plop': 'x'}) == ''
assert tmpl.render({'plop': None}) == ''
assert tmpl.render({'plop': 3}) == ''
assert tmpl.render({'plop': {'foo': 'bar'}}) == ''
assert tmpl.render() == ''
tmpl = Template('{{ plop|date:"d" }}')
assert tmpl.render({'plop': '2017-12-21'}) == '21'
assert tmpl.render({'plop': '21/12/2017'}) == '21'
assert tmpl.render({'plop': '2017-12-21 10:32'}) == '21'
assert tmpl.render({'plop': '10:32'}) == ''
assert tmpl.render({'plop': 'x'}) == ''
assert tmpl.render({'plop': None}) == ''
assert tmpl.render({'plop': 3}) == ''
assert tmpl.render({'plop': {'foo': 'bar'}}) == ''
assert tmpl.render() == ''
tmpl = Template('{% if d1|date > d2|date %}d1>d2{% else %}d1<=d2{% endif %}')
assert tmpl.render({'d1': '2017-12-22', 'd2': '2017-12-21'}) == 'd1>d2'
assert tmpl.render({'d1': '2017-12-21', 'd2': '2017-12-21'}) == 'd1<=d2'
assert tmpl.render({'d1': '2017-12-22'}) == 'd1<=d2'
assert tmpl.render({'d2': '2017-12-22'}) == 'd1<=d2'
tmpl = Template('{{ plop|time }}')
assert tmpl.render({'plop': '10:32'}) == '10:32 a.m.'
assert tmpl.render({'plop': '2017-12-21 10:32'}) == '10:32 a.m.'
assert tmpl.render({'plop': '21/12/2017 10h32'}) == '10:32 a.m.'
assert tmpl.render({'plop': '21/12/2017'}) == 'midnight'
assert tmpl.render({'plop': 'x'}) == ''
assert tmpl.render({'plop': None}) == ''
assert tmpl.render({'plop': 3}) == ''
assert tmpl.render({'plop': {'foo': 'bar'}}) == ''
assert tmpl.render() == ''
tmpl = Template('{{ plop|time:"H i" }}')
assert tmpl.render({'plop': '10:32'}) == '10 32'
assert tmpl.render({'plop': '2017-12-21 10:32'}) == '10 32'
assert tmpl.render({'plop': '21/12/2017 10h32'}) == '10 32'
assert tmpl.render({'plop': '21/12/2017'}) == '00 00'
assert tmpl.render({'plop': 'x'}) == ''
assert tmpl.render({'plop': None}) == ''
assert tmpl.render({'plop': 3}) == ''
assert tmpl.render({'plop': {'foo': 'bar'}}) == ''
assert tmpl.render() == ''
# old fashion, with parse_*
tmpl = Template('{{ plop|parse_datetime|date:"d i" }}')
assert tmpl.render({'plop': '2017-12-21 10:32'}) == '21 32'
assert tmpl.render({'plop': '2017-12-21 10:32:42'}) == '21 32'
assert tmpl.render({'plop': '21/12/2017 10:32'}) == '21 32'
assert tmpl.render({'plop': '21/12/2017 10:32:42'}) == '21 32'
assert tmpl.render({'plop': '21/12/2017 10h32'}) == '21 32'
assert tmpl.render({'plop': 'x'}) == ''
assert tmpl.render({'plop': None}) == ''
assert tmpl.render({'plop': 3}) == ''
assert tmpl.render({'plop': {'foo': 'bar'}}) == ''
assert tmpl.render() == ''
tmpl = Template('{{ plop|parse_date|date:"d" }}')
assert tmpl.render({'plop': '2017-12-21'}) == '21'
assert tmpl.render({'plop': '21/12/2017'}) == '21'
assert tmpl.render({'plop': 'x'}) == ''
assert tmpl.render({'plop': None}) == ''
assert tmpl.render({'plop': 3}) == ''
assert tmpl.render({'plop': {'foo': 'bar'}}) == ''
assert tmpl.render() == ''
tmpl = Template('{{ plop|parse_time|date:"H i" }}')
assert tmpl.render({'plop': '10:32'}) == '10 32'
assert tmpl.render({'plop': 'x'}) == ''
assert tmpl.render({'plop': None}) == ''
assert tmpl.render({'plop': 3}) == ''
assert tmpl.render({'plop': {'foo': 'bar'}}) == ''
assert tmpl.render() == ''
def test_date_maths():
tmpl = Template('{{ plop|add_days:4 }}')
assert tmpl.render({'plop': '2017-12-21'}) == '2017-12-25'
assert tmpl.render({'plop': '2017-12-21 18:00'}) == '2017-12-25'
tmpl = Template('{{ plop|add_days:"-1" }}')
assert tmpl.render({'plop': '2017-12-21'}) == '2017-12-20'
assert tmpl.render({'plop': '2017-12-21 18:00'}) == '2017-12-20'
tmpl = Template('{{ plop|add_days:1.5 }}')
assert tmpl.render({'plop': '2017-12-21'}) == '2017-12-22'
assert tmpl.render({'plop': '2017-12-21 18:00'}) == '2017-12-22'
tmpl = Template('{{ plop|add_days:"1.5" }}')
assert tmpl.render({'plop': '2017-12-21'}) == '2017-12-22'
assert tmpl.render({'plop': '2017-12-21 18:00'}) == '2017-12-22'
tmpl = Template('{{ plop|add_hours:24 }}')
assert tmpl.render({'plop': '2017-12-21'}) == '2017-12-22 00:00'
assert tmpl.render({'plop': '2017-12-21 18:00'}) == '2017-12-22 18:00'
tmpl = Template('{{ plop|add_hours:"12.5" }}')
assert tmpl.render({'plop': '2017-12-21'}) == '2017-12-21 12:30'
assert tmpl.render({'plop': '2017-12-21 18:00'}) == '2017-12-22 06:30'
def test_variable_unicode_error_handling():
tmpl = Template('{{ form_var_éléphant }}')
assert tmpl.render() == ''
def test_decimal_templatetag():
tmpl = Template('{{ plop|decimal }}')
assert tmpl.render({'plop': 'toto'}) == '0'
assert tmpl.render({'plop': '3.14'}) == '3.14'
assert tmpl.render({'plop': '3,14'}) == '3.14'
assert tmpl.render({'plop': 3.14}) == '3.14'
assert tmpl.render({'plop': 12345.678}) == '12345.678'
assert tmpl.render({'plop': None}) == '0'
assert tmpl.render({'plop': 0}) == '0'
tmpl = Template('{{ plop|decimal:3 }}')
assert tmpl.render({'plop': '3.14'}) == '3.140'
assert tmpl.render({'plop': None}) == '0.000'
tmpl = Template('{{ plop|decimal:"3" }}')
assert tmpl.render({'plop': '3.14'}) == '3.140'
assert tmpl.render({'plop': None}) == '0.000'
tmpl = Template('{% if plop|decimal > 2 %}hello{% endif %}')
assert tmpl.render({'plop': 3}) == 'hello'
assert tmpl.render({'plop': '3'}) == 'hello'
assert tmpl.render({'plop': 2.001}) == 'hello'
assert tmpl.render({'plop': '2.001'}) == 'hello'
assert tmpl.render({'plop': 1}) == ''
assert tmpl.render({'plop': 1.99}) == ''
assert tmpl.render({'plop': '1.99'}) == ''
assert tmpl.render({'plop': 'x'}) == ''
assert tmpl.render({'plop': None}) == ''
assert tmpl.render({'plop': 0}) == ''
tmpl = Template('{% if "3"|decimal == 3 %}hello{% endif %}')
assert tmpl.render() == 'hello'
tmpl = Template('{% if "3"|decimal == 3.0 %}hello{% endif %}')
assert tmpl.render() == 'hello'
tmpl = Template('{% if 3|decimal == 3 %}hello{% endif %}')
assert tmpl.render() == 'hello'
tmpl = Template('{% if 3.0|decimal == 3 %}hello{% endif %}')
assert tmpl.render() == 'hello'
tmpl = Template('{% if 3|decimal|decimal == 3 %}hello{% endif %}')
assert tmpl.render() == 'hello'
def test_mathematics_templatetag():
tmpl = Template('{{ term1|add:term2 }}')
# using strings
assert tmpl.render({'term1': '1.1', 'term2': 0}) == '1.1'
assert tmpl.render({'term1': 'not a number', 'term2': 1.2}) == ''
assert tmpl.render({'term1': 0.3, 'term2': "1"}) == '1.3'
assert tmpl.render({'term1': 1.4, 'term2': "not a number"}) == ''
# add
assert tmpl.render({'term1': 4, 'term2': -0.9}) == '3.1'
assert tmpl.render({'term1': '4', 'term2': -0.8}) == '3.2'
assert tmpl.render({'term1': 4, 'term2': '-0.7'}) == '3.3'
assert tmpl.render({'term1': '4', 'term2': '-0.6'}) == '3.4'
assert tmpl.render({'term1': '', 'term2': 3.5}) == '3.5'
assert tmpl.render({'term1': None, 'term2': 3.5}) == '3.5'
assert tmpl.render({'term1': 3.6, 'term2': ''}) == '3.6'
assert tmpl.render({'term1': '', 'term2': ''}) == ''
assert tmpl.render({'term1': 3.6, 'term2': None}) == '3.6'
assert tmpl.render({'term1': 0, 'term2': ''}) == '0'
assert tmpl.render({'term1': '', 'term2': 0}) == '0'
assert tmpl.render({'term1': 0, 'term2': 0}) == '0'
# add using ',' instead of '.' decimal separator
assert tmpl.render({'term1': '1,1', 'term2': '2,2'}) == '3.3'
assert tmpl.render({'term1': '1,1', 'term2': '2.2'}) == '3.3'
assert tmpl.render({'term1': '1,1', 'term2': 2.2}) == '3.3'
assert tmpl.render({'term1': '1,1', 'term2': 0}) == '1.1'
assert tmpl.render({'term1': '1,1', 'term2': ''}) == '1.1'
assert tmpl.render({'term1': '1,1', 'term2': None}) == '1.1'
assert tmpl.render({'term1': '1.1', 'term2': '2,2'}) == '3.3'
assert tmpl.render({'term1': 1.1, 'term2': '2,2'}) == '3.3'
assert tmpl.render({'term1': 0, 'term2': '2,2'}) == '2.2'
assert tmpl.render({'term1': '', 'term2': '2,2'}) == '2.2'
assert tmpl.render({'term1': None, 'term2': '2,2'}) == '2.2'
# fallback to Django native add filter
assert tmpl.render({'term1': 'foo', 'term2': 'bar'}) == 'foobar'
assert tmpl.render({'term1': 'foo', 'term2': ''}) == 'foo'
assert tmpl.render({'term1': 'foo', 'term2': None}) == 'foo'
assert tmpl.render({'term1': '', 'term2': 'bar'}) == 'bar'
assert tmpl.render({'term1': '', 'term2': None}) == ''
assert tmpl.render({'term1': None, 'term2': 'bar'}) == 'bar'
assert tmpl.render({'term1': None, 'term2': ''}) == ''
assert tmpl.render({'term1': None, 'term2': None}) == ''
# subtract
tmpl = Template('{{ term1|subtract:term2 }}')
assert tmpl.render({'term1': 5.1, 'term2': 1}) == '4.1'
assert tmpl.render({'term1': '5.2', 'term2': 1}) == '4.2'
assert tmpl.render({'term1': 5.3, 'term2': '1'}) == '4.3'
assert tmpl.render({'term1': '5.4', 'term2': '1'}) == '4.4'
assert tmpl.render({'term1': '', 'term2': -4.5}) == '4.5'
assert tmpl.render({'term1': 4.6, 'term2': ''}) == '4.6'
assert tmpl.render({'term1': '', 'term2': ''}) == '0'
assert tmpl.render({'term1': 0, 'term2': ''}) == '0'
assert tmpl.render({'term1': '', 'term2': 0}) == '0'
assert tmpl.render({'term1': 0, 'term2': 0}) == '0'
# multiply
tmpl = Template('{{ term1|multiply:term2 }}')
assert tmpl.render({'term1': '3', 'term2': '2'}) == '6'
assert tmpl.render({'term1': 2.5, 'term2': 2}) == '5.0'
assert tmpl.render({'term1': '2.5', 'term2': 2}) == '5.0'
assert tmpl.render({'term1': 2.5, 'term2': '2'}) == '5.0'
assert tmpl.render({'term1': '2.5', 'term2': '2'}) == '5.0'
assert tmpl.render({'term1': '', 'term2': '2'}) == '0'
assert tmpl.render({'term1': 2.5, 'term2': ''}) == '0.0'
assert tmpl.render({'term1': '', 'term2': ''}) == '0'
assert tmpl.render({'term1': 0, 'term2': ''}) == '0'
assert tmpl.render({'term1': '', 'term2': 0}) == '0'
assert tmpl.render({'term1': 0, 'term2': 0}) == '0'
# divide
tmpl = Template('{{ term1|divide:term2 }}')
assert tmpl.render({'term1': 16, 'term2': 2}) == '8'
assert tmpl.render({'term1': 6, 'term2': 0.75}) == '8'
assert tmpl.render({'term1': '6', 'term2': 0.75}) == '8'
assert tmpl.render({'term1': 6, 'term2': '0.75'}) == '8'
assert tmpl.render({'term1': '6', 'term2': '0.75'}) == '8'
assert tmpl.render({'term1': '', 'term2': '2'}) == '0'
assert tmpl.render({'term1': 6, 'term2': ''}) == ''
assert tmpl.render({'term1': '', 'term2': ''}) == ''
assert tmpl.render({'term1': 0, 'term2': ''}) == ''
assert tmpl.render({'term1': '', 'term2': 0}) == ''
assert tmpl.render({'term1': 0, 'term2': 0}) == ''
tmpl = Template('{{ term1|divide:term2|decimal:2 }}')
assert tmpl.render({'term1': 2, 'term2': 3}) == '0.67'
def test_rounding_templatetag():
# ceil
tmpl = Template('{{ value|ceil }}')
assert tmpl.render({'value': 3.14}) == '4'
assert tmpl.render({'value': 3.99}) == '4'
assert tmpl.render({'value': -3.14}) == '-3'
assert tmpl.render({'value': -3.99}) == '-3'
assert tmpl.render({'value': 0}) == '0'
assert tmpl.render({'value': '3.14'}) == '4'
assert tmpl.render({'value': '3.99'}) == '4'
assert tmpl.render({'value': '-3.14'}) == '-3'
assert tmpl.render({'value': '-3.99'}) == '-3'
assert tmpl.render({'value': '0'}) == '0'
assert tmpl.render({'value': 'not a number'}) == '0'
assert tmpl.render({'value': ''}) == '0'
assert tmpl.render({'value': None}) == '0'
# floor
tmpl = Template('{{ value|floor }}')
assert tmpl.render({'value': 3.14}) == '3'
assert tmpl.render({'value': 3.99}) == '3'
assert tmpl.render({'value': -3.14}) == '-4'
assert tmpl.render({'value': -3.99}) == '-4'
assert tmpl.render({'value': 0}) == '0'
assert tmpl.render({'value': '3.14'}) == '3'
assert tmpl.render({'value': '3.99'}) == '3'
assert tmpl.render({'value': '-3.14'}) == '-4'
assert tmpl.render({'value': '-3.99'}) == '-4'
assert tmpl.render({'value': '0'}) == '0'
assert tmpl.render({'value': 'not a number'}) == '0'
assert tmpl.render({'value': ''}) == '0'
assert tmpl.render({'value': None}) == '0'
def test_abs_templatetag():
tmpl = Template('{{ value|abs }}')
assert tmpl.render({'value': 3.14}) == '3.14'
assert tmpl.render({'value': -3.14}) == '3.14'
assert tmpl.render({'value': 0}) == '0'
assert tmpl.render({'value': '3.14'}) == '3.14'
assert tmpl.render({'value': '-3.14'}) == '3.14'
assert tmpl.render({'value': '0'}) == '0'
assert tmpl.render({'value': 'not a number'}) == '0'
assert tmpl.render({'value': ''}) == '0'
assert tmpl.render({'value': None}) == '0'
def test_token_decimal():
tokens = [Template('{% token_decimal 4 %}').render() for i in range(100)]
assert all(len(token) == 4 for token in tokens)
assert all(token.isdigit() for token in tokens)
# check randomness, i.e. duplicates are rare
assert len(set(tokens)) > 70
t = Template('{% if token1|token_check:token2 %}ok{% endif %}')
assert t.render({'token1': tokens[0] + ' ', 'token2': tokens[0].lower()}) == 'ok'
t = Template('{% if "é"|token_check:"è" %}ok{% endif %}')
assert t.render({'token1': tokens[0] + ' ', 'token2': tokens[0].lower()}) == ''
def test_token_alphanum():
tokens = [Template('{% token_alphanum 4 %}').render() for i in range(100)]
assert all(len(token) == 4 for token in tokens)
assert all(token.upper() == token for token in tokens)
assert all(token.isalnum() for token in tokens)
# check randomness, i.e. duplicates are rare
assert len(set(tokens)) > 90
# check there are letters and digits
assert any(set(token) & set(string.ascii_uppercase) for token in tokens)
assert any(set(token) & set(string.digits) for token in tokens)
# no look-alike characters
assert not any(set(token) & set('01IiOo') for token in tokens)
t = Template('{% if token1|token_check:token2 %}ok{% endif %}')
assert t.render({'token1': tokens[0] + ' ', 'token2': tokens[0].lower()}) == 'ok'
def test_distance():
t = Template('{{ "48;2"|distance:"48.1;2.1"|floatformat }}',)
assert t.render() == '13387.2'
t = Template('{{ coords|distance:"48.1;2.1"|floatformat }}',)
assert t.render({'coords': '48;2'}) == '13387.2'
t = Template('{{ "48;2"|distance:coords|floatformat }}',)
assert t.render({'coords': '48.1;2.1'}) == '13387.2'
t = Template('{{ c1|distance:c2|floatformat }}',)
assert t.render({'c1': '48;2', 'c2': '48.1;2.1'}) == '13387.2'
assert t.render({'c1': {'lat': '48', 'lon': '2'}, 'c2': {'lat': '48.1', 'lng': '2.1'}}) == '13387.2'
assert t.render({'c1': {'lat': '48', 'lng': '2'}, 'c2': {'lat': '48.1', 'lng': '2.1'}}) == '13387.2'
class MockFormData(object):
formdef = None
geolocations = {'base': {'lat': 48, 'lon': 2}}
lazy_formdata = LazyFormData(MockFormData())
for tpl in ('{{ formdata|distance:coords|floatformat }}',
'{{ coords|distance:formdata|floatformat }}'):
t = Template(tpl,)
assert t.render({'formdata': lazy_formdata, 'coords': '48.1;2.1'}) == '13387.2'
assert t.render({'formdata': lazy_formdata, 'coords': '49.1;3.1'}) == '146821.9'
assert t.render({'formdata': lazy_formdata, 'coords': 'abc;def'}) == ''
assert t.render({'formdata': lazy_formdata, 'coords': '42'}) == ''
assert t.render({'formdata': lazy_formdata, 'coords': ''}) == ''
MockFormData.geolocations = {}
for tpl in ('{{ formdata|distance:coords|floatformat }}',
'{{ coords|distance:formdata|floatformat }}'):
t = Template(tpl,)
assert t.render({'formdata': lazy_formdata, 'coords': '49.1;3.1'}) == ''
def test_get_filter():
tmpl = Template('{{ foo|get:"bar" }}')
assert tmpl.render({'foo': {'bar': 'baz'}}) == 'baz'
tmpl = Template('{{ foo|get:0 }}')
assert tmpl.render({'foo': ['bar', 'baz']}) == 'bar'
tmpl = Template('{{ foo|get:0|default_if_none:"" }}')
assert tmpl.render({'foo': ""}) == ''
assert tmpl.render({'foo': None}) == ''
assert tmpl.render({'foo': 23}) == ''
def test_get_on_lazy_var():
FormDef.wipe()
formdef = FormDef()
formdef.name = 'lazy'
formdef.fields = [
fields.StringField(id='0', label='string', varname='foo'),
fields.StringField(id='1', label='string', varname='bar'),
]
formdef.store()
formdef.data_class().wipe()
formdata = formdef.data_class()()
formdata.just_created()
formdata.data = {
'0': 'bar',
'1': '1',
}
formdata.store()
context = CompatibilityNamesDict({
'form': LazyFormData(formdata),
'foo_dict': {'bar': 'baz'},
'foo_array': ['bar', 'baz'],
})
tmpl = Template('{{ foo_dict|get:form_var_foo }}')
assert tmpl.render(context) == 'baz'
tmpl = Template('{{ foo_array|get:form_var_bar }}')
assert tmpl.render(context) == 'baz'
def test_reproj():
class MockFormData(object):
formdef = None
geolocations = {'base': {'lat': 48, 'lon': 2}}
lazy_formdata = LazyFormData(MockFormData())
tmpl = Template('{% with form_geoloc_base|reproj:"EPSG:3946" as c %}{{c.0}}/{{c.1}}{% endwith %}')
coords = tmpl.render(CompatibilityNamesDict({'form': lazy_formdata})).split('/')
assert int(float(coords[0])) == 1625337
assert int(float(coords[1])) == 5422836
def test_phonenumber_fr():
t = Template('{{ number|phonenumber_fr }}')
assert t.render({'number': '01 23 45 67 89'}) == '01 23 45 67 89'
assert t.render({'number': '0 1 23 45 67 89'}) == '01 23 45 67 89'
assert t.render({'number': '0123456789'}) == '01 23 45 67 89'
assert t.render({'number': '01.23.45.67.89'}) == '01 23 45 67 89'
assert t.render({'number': '01 23 45 67 89'}) == '01 23 45 67 89'
assert t.render({'number': '00 33 1 23 45 67 89'}) == '00 33 1 23 45 67 89'
assert t.render({'number': '00 33 1 23 45 67 89'}) == '00 33 1 23 45 67 89'
assert t.render({'number': '+33 1 23 45 67 89'}) == '+33 1 23 45 67 89'
assert t.render({'number': '+33 (0)1 23 45 67 89'}) == '+33 1 23 45 67 89'
# drom
assert t.render({'number': '02 62 11 22 33'}) == '02 62 11 22 33'
assert t.render({'number': '00 262 11 22 33'}) == '00 262 11 22 33'
assert t.render({'number': '+262 112233'}) == '+262 11 22 33'
t = Template('{{ number|phonenumber_fr:"." }}')
assert t.render({'number': '01 23 45 67 89'}) == '01.23.45.67.89'
# unknown
assert t.render({'number': '12 3'}) == '12 3'
assert t.render({'number': 'bla bla'}) == 'bla bla'
assert t.render({'number': None}) == 'None'
t = Template('{{ number|decimal|phonenumber_fr }}')
assert t.render({'number': '1,33'}) == '1.33'
@pytest.mark.skipif('langdetect is None')
def test_language_detect():
t = Template('{{ plop|language_detect }}')
assert t.render({'plop': 'Good morning world'}) == 'en'
assert t.render({'plop': 'Bonjour tout le monde'}) == 'fr'
assert t.render({'plop': '2132133'}) == ''
@pytest.mark.parametrize('value, expected', [
(None, False),
('', False),
('foobar', False),
(42, False),
('1970-06-15T12:01:03', True),
('2500-06-15T12:01:02', False),
('1970-01-01 02:03', True),
('2500-01-01 02:03', False),
('01/01/1970 02h03', True),
('01/01/2500 02h03', False),
('1970-01-01', True),
('2500-01-01', False),
('01/01/1970', True),
('01/01/2500', False),
(datetime.datetime(1970, 6, 15, 12, 1, 3), True),
(datetime.datetime(2500, 6, 15, 12, 1, 2), False),
(datetime.date(1970, 6, 15), True),
(datetime.date(2500, 6, 15), False),
(datetime.datetime.now(), True),
(datetime.datetime.now() + datetime.timedelta(hours=1), False),
(now(), True),
(now() + datetime.timedelta(hours=1), False),
(datetime.date.today(), True),
(datetime.date.today() + datetime.timedelta(days=1), False),
])
def test_datetime_in_past(value, expected):
t = Template('{{ value|datetime_in_past }}')
assert t.render({'value': value}) == str(expected)
def test_is_working_day_settings(settings, pub):
settings.WORKING_DAY_CALENDAR = None
t = Template('{{ value|is_working_day }}')
assert t.render({'value': '2020-07-15'}) == 'False'
t = Template('{{ value|is_working_day_with_saturday }}')
assert t.render({'value': '2020-07-15'}) == 'False'
settings.WORKING_DAY_CALENDAR = ''
t = Template('{{ value|is_working_day }}')
assert t.render({'value': '2020-07-15'}) == 'False'
t = Template('{{ value|is_working_day_with_saturday }}')
assert t.render({'value': '2020-07-15'}) == 'False'
settings.WORKING_DAY_CALENDAR = 'foobar'
t = Template('{{ value|is_working_day }}')
assert t.render({'value': '2020-07-15'}) == 'False'
t = Template('{{ value|is_working_day_with_saturday }}')
assert t.render({'value': '2020-07-15'}) == 'False'
settings.WORKING_DAY_CALENDAR = 'workalendar.europe.France'
t = Template('{{ value|is_working_day }}')
assert t.render({'value': '2020-07-15'}) == 'True'
t = Template('{{ value|is_working_day_with_saturday }}')
assert t.render({'value': '2020-07-15'}) == 'True'
pub.site_options.set('options', 'working_day_calendar', 'foobar')
pub.site_options.write(open(os.path.join(pub.app_dir, 'site-options.cfg'), 'w'))
t = Template('{{ value|is_working_day }}')
assert t.render({'value': '2020-07-15'}) == 'False'
t = Template('{{ value|is_working_day_with_saturday }}')
assert t.render({'value': '2020-07-15'}) == 'False'
settings.WORKING_DAY_CALENDAR = 'foobar'
pub.site_options.set('options', 'working_day_calendar', 'workalendar.europe.France')
pub.site_options.write(open(os.path.join(pub.app_dir, 'site-options.cfg'), 'w'))
t = Template('{{ value|is_working_day }}')
assert t.render({'value': '2020-07-15'}) == 'True'
t = Template('{{ value|is_working_day_with_saturday }}')
assert t.render({'value': '2020-07-15'}) == 'True'
@pytest.mark.parametrize('value, expected', [
(None, False),
('', False),
('foobar', False),
(42, False),
('2020-07-14T12:01:03', False),
('2020-07-15T12:01:03', True),
('2020-07-14 02:03', False),
('2020-07-15 02:03', True),
('14/07/2020 02h03', False),
('15/07/2020 02h03', True),
('2020-07-14', False),
('2020-07-15', True),
('14/07/2020', False),
('15/07/2020', True),
(datetime.datetime(2020, 7, 14, 12, 1, 3), False),
(datetime.datetime(2020, 7, 15, 12, 1, 3), True),
(datetime.date(2020, 7, 14), False),
(datetime.date(2020, 7, 15), True),
])
def test_is_working_day(settings, value, expected):
settings.WORKING_DAY_CALENDAR = 'workalendar.europe.France'
t = Template('{{ value|is_working_day }}')
assert t.render({'value': value}) == str(expected)
t = Template('{{ value|is_working_day_with_saturday }}')
assert t.render({'value': value}) == str(expected)
def test_is_working_day_weekend(settings):
settings.WORKING_DAY_CALENDAR = 'workalendar.europe.France'
# check saturday
t = Template('{{ value|is_working_day }}')
assert t.render({'value': '2020-06-20'}) == 'False'
t = Template('{{ value|is_working_day_with_saturday }}')
assert t.render({'value': '2020-06-20'}) == 'True'
# check sunday
t = Template('{{ value|is_working_day }}')
assert t.render({'value': '2020-06-21'}) == 'False'
t = Template('{{ value|is_working_day_with_saturday }}')
assert t.render({'value': '2020-06-21'}) == 'False'
def test_add_working_days_settings(settings, pub):
settings.WORKING_DAY_CALENDAR = None
t = Template('{{ value|add_working_days:1 }}')
assert t.render({'value': '2020-07-13'}) == ''
t = Template('{{ value|add_working_days_with_saturday:1 }}')
assert t.render({'value': '2020-07-13'}) == ''
settings.WORKING_DAY_CALENDAR = ''
t = Template('{{ value|add_working_days:1 }}')
assert t.render({'value': '2020-07-13'}) == ''
t = Template('{{ value|add_working_days_with_saturday:1 }}')
assert t.render({'value': '2020-07-13'}) == ''
settings.WORKING_DAY_CALENDAR = 'foobar'
t = Template('{{ value|add_working_days:1 }}')
assert t.render({'value': '2020-07-13'}) == ''
t = Template('{{ value|add_working_days_with_saturday:1 }}')
assert t.render({'value': '2020-07-13'}) == ''
settings.WORKING_DAY_CALENDAR = 'workalendar.europe.France'
t = Template('{{ value|add_working_days:1 }}')
assert t.render({'value': '2020-07-13'}) == '2020-07-15'
t = Template('{{ value|add_working_days_with_saturday:1 }}')
assert t.render({'value': '2020-07-13'}) == '2020-07-15'
pub.site_options.set('options', 'working_day_calendar', 'foobar')
pub.site_options.write(open(os.path.join(pub.app_dir, 'site-options.cfg'), 'w'))
t = Template('{{ value|add_working_days:1 }}')
assert t.render({'value': '2020-07-13'}) == ''
t = Template('{{ value|add_working_days_with_saturday:1 }}')
assert t.render({'value': '2020-07-13'}) == ''
settings.WORKING_DAY_CALENDAR = 'foobar'
pub.site_options.set('options', 'working_day_calendar', 'workalendar.europe.France')
pub.site_options.write(open(os.path.join(pub.app_dir, 'site-options.cfg'), 'w'))
t = Template('{{ value|add_working_days:1 }}')
assert t.render({'value': '2020-07-13'}) == '2020-07-15'
t = Template('{{ value|add_working_days_with_saturday:1 }}')
assert t.render({'value': '2020-07-13'}) == '2020-07-15'
def test_add_working_days_arg(settings):
settings.WORKING_DAY_CALENDAR = 'workalendar.europe.France'
t = Template('{{ value|add_working_days:"foobar" }}')
assert t.render({'value': '2020-07-13'}) == ''
t = Template('{{ value|add_working_days_with_saturday:"foobar" }}')
assert t.render({'value': '2020-07-13'}) == ''
t = Template('{{ value|add_working_days:2 }}')
assert t.render({'value': '2020-07-13'}) == '2020-07-16'
t = Template('{{ value|add_working_days_with_saturday:2 }}')
assert t.render({'value': '2020-07-13'}) == '2020-07-16'
@pytest.mark.parametrize('value, expected', [
(None, ''),
('', ''),
('foobar', ''),
(42, ''),
('2020-07-13T12:01:03', '2020-07-15'),
('2020-07-13 02:03', '2020-07-15'),
('13/07/2020 02h03', '2020-07-15'),
('2020-07-13', '2020-07-15'),
('13/07/2020', '2020-07-15'),
(datetime.datetime(2020, 7, 13, 12, 1, 3), '2020-07-15'),
(datetime.date(2020, 7, 13), '2020-07-15'),
])
def test_add_working_days(settings, value, expected):
settings.WORKING_DAY_CALENDAR = 'workalendar.europe.France'
t = Template('{{ value|add_working_days:1 }}')
assert t.render({'value': value}) == str(expected)
t = Template('{{ value|add_working_days_with_saturday:1 }}')
assert t.render({'value': value}) == str(expected)
def test_add_working_days_weekend(settings):
settings.WORKING_DAY_CALENDAR = 'workalendar.europe.France'
t = Template('{{ value|add_working_days:1 }}')
assert t.render({'value': '2020-06-19'}) == '2020-06-22'
t = Template('{{ value|add_working_days_with_saturday:1 }}')
assert t.render({'value': '2020-06-19'}) == '2020-06-20'
def test_adjust_to_working_day_settings(settings, pub):
settings.WORKING_DAY_CALENDAR = None
t = Template('{{ value|adjust_to_working_day }}')
assert t.render({'value': '2020-07-13'}) == ''
t = Template('{{ value|adjust_to_working_day_with_saturday }}')
assert t.render({'value': '2020-07-13'}) == ''
settings.WORKING_DAY_CALENDAR = ''
t = Template('{{ value|adjust_to_working_day }}')
assert t.render({'value': '2020-07-13'}) == ''
t = Template('{{ value|adjust_to_working_day_with_saturday }}')
assert t.render({'value': '2020-07-13'}) == ''
settings.WORKING_DAY_CALENDAR = 'foobar'
t = Template('{{ value|adjust_to_working_day }}')
assert t.render({'value': '2020-07-13'}) == ''
t = Template('{{ value|adjust_to_working_day_with_saturday }}')
assert t.render({'value': '2020-07-13'}) == ''
settings.WORKING_DAY_CALENDAR = 'workalendar.europe.France'
t = Template('{{ value|adjust_to_working_day }}')
assert t.render({'value': '2020-07-14'}) == '2020-07-15'
t = Template('{{ value|adjust_to_working_day_with_saturday }}')
assert t.render({'value': '2020-07-14'}) == '2020-07-15'
pub.site_options.set('options', 'working_day_calendar', 'foobar')
pub.site_options.write(open(os.path.join(pub.app_dir, 'site-options.cfg'), 'w'))
t = Template('{{ value|adjust_to_working_day }}')
assert t.render({'value': '2020-07-13'}) == ''
t = Template('{{ value|adjust_to_working_day_with_saturday }}')
assert t.render({'value': '2020-07-13'}) == ''
settings.WORKING_DAY_CALENDAR = 'foobar'
pub.site_options.set('options', 'working_day_calendar', 'workalendar.europe.France')
pub.site_options.write(open(os.path.join(pub.app_dir, 'site-options.cfg'), 'w'))
t = Template('{{ value|adjust_to_working_day }}')
assert t.render({'value': '2020-07-14'}) == '2020-07-15'
t = Template('{{ value|adjust_to_working_day_with_saturday }}')
assert t.render({'value': '2020-07-14'}) == '2020-07-15'
@pytest.mark.parametrize('value, expected', [
(None, ''),
('', ''),
('foobar', ''),
(42, ''),
('2020-07-14T12:01:03', '2020-07-15'),
('2020-07-14 02:03', '2020-07-15'),
('14/07/2020 02h03', '2020-07-15'),
('2020-07-14', '2020-07-15'),
('14/07/2020', '2020-07-15'),
(datetime.datetime(2020, 7, 14, 12, 1, 3), '2020-07-15'),
(datetime.date(2020, 7, 14), '2020-07-15'),
(datetime.date(2020, 7, 15), '2020-07-15'),
])
def test_adjust_to_working_day(settings, value, expected):
settings.WORKING_DAY_CALENDAR = 'workalendar.europe.France'
t = Template('{{ value|adjust_to_working_day }}')
assert t.render({'value': value}) == str(expected)
t = Template('{{ value|adjust_to_working_day_with_saturday }}')
assert t.render({'value': value}) == str(expected)
def test_adjust_to_working_day_weekend(settings):
settings.WORKING_DAY_CALENDAR = 'workalendar.europe.France'
t = Template('{{ value|adjust_to_working_day }}')
assert t.render({'value': '2020-06-20'}) == '2020-06-22'
t = Template('{{ value|adjust_to_working_day_with_saturday }}')
assert t.render({'value': '2020-06-20'}) == '2020-06-20'
def test_sum():
tmpl = Template('{{ "2 29.5 9,5 .5"|split|sum }}')
assert tmpl.render({}) == '41.5'
tmpl = Template('{{ list|sum }}')
assert tmpl.render({'list': [1, 2, '3']}) == '6'
assert tmpl.render({'list': [1, 2, 'x']}) == '3'
assert tmpl.render({'list': [None, 2.0, 'x']}) == '2'
assert tmpl.render({'list': []}) == '0'
assert tmpl.render({'list': None}) == '' # list is not iterable
assert tmpl.render({'list': '123'}) == '' # consider string as not iterable
assert tmpl.render({}) == ''
def test_getlist():
class FakeBlock:
def getlist(self, key):
return {'foo': ['foo1', 'foo2'], 'bar': ['bar1', 'bar2']}[key]
tmpl = Template('{% for x in egg|getlist:coin %}{{x}}{% endfor %}')
assert tmpl.render({'egg': FakeBlock(), 'coin': 'foo'}) == 'foo1foo2'
assert tmpl.render({'egg': FakeBlock(), 'coin': 'bar'}) == 'bar1bar2'
tmpl = Template('{{ egg|getlist:"foo"|length }}')
assert tmpl.render({'egg': FakeBlock()}) == '2'
assert tmpl.render({}) == '0'
assert tmpl.render({'egg': None}) == '0'
assert tmpl.render({'egg': 'spam'}) == '0'
assert tmpl.render({'egg': 42}) == '0'
def test_django_contrib_humanize_filters():
tmpl = Template('{{ foo|intcomma }}')
assert tmpl.render({'foo': 10000}) == '10,000'
assert tmpl.render({'foo': '10000'}) == '10,000'
with override_settings(LANGUAGE_CODE='fr-fr'):
assert tmpl.render({'foo': 10000}) == '10 000'
assert tmpl.render({'foo': '10000'}) == '10 000'