combo/tests/test_public_templatetags.py

877 lines
41 KiB
Python
Raw 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.

import datetime
import os
import shutil
import time
import pytest
from django.core.files import File
from django.core.files.storage import default_storage
from django.template import Context, Template
from django.template.exceptions import TemplateSyntaxError
from django.test import override_settings
from django.test.client import RequestFactory
from django.contrib.auth.models import User, Group, AnonymousUser
from django.utils.six import StringIO
from django.utils.timezone import now
from combo.data.models import Page, TextCell
from combo.apps.assets.models import Asset
from combo.profile.utils import get_user_from_name_id
pytestmark = pytest.mark.django_db
def test_strptime():
t = Template('{{ someday|strptime:"%Y-%m-%d"|date:"Y" }}')
assert t.render(Context({'someday': '2015-04-15'})) == '2015'
assert t.render(Context({'someday': 'foobar'})) == ''
assert t.render(Context({'someday': None})) == ''
assert t.render(Context({'someday': {'foo': 'bar'}})) == ''
assert t.render(Context({'someday': ['foo', 'bar']})) == ''
def test_parse_datetime():
t = Template('{{ someday|parse_datetime|date:"Y m d H i s T" }}')
expected = '2015 04 15 13 11 12 UTC'
assert t.render(Context({'someday': '2015-04-15T13:11:12'})) == expected
assert t.render(Context({'someday': '2015-04-15 13:11:12'})) == expected
assert t.render(Context({'someday': '2015-04-15T13:11:12Z'})) == expected
assert t.render(Context({'someday': '2015-04-15T13:11:12+00:00'})) == expected
assert t.render(Context({'someday': '2015-04-15T13:11:12.12345'})) == expected
assert t.render(Context({'someday': '2015-04-15T13:11:12.12345Z'})) == expected
assert t.render(Context({'someday': '2015-04-15T13:11:12.12345+00:00'})) == expected
assert (
t.render(Context({'someday': time.localtime(time.mktime((2015, 4, 15, 13, 11, 12, 0, 0, 0)))}))
== expected
)
assert t.render(Context({'someday': '2015-04-15T13:11'})) == '2015 04 15 13 11 00 UTC'
assert t.render(Context({'someday': '2015-04-15T13'})) == ''
assert t.render(Context({'someday': 'foobar'})) == ''
assert t.render(Context({'someday': ''})) == ''
assert t.render(Context({'someday': None})) == ''
assert t.render(Context({'someday': {'foo': 'bar'}})) == ''
assert t.render(Context({'someday': ['foo', 'bar']})) == ''
t = Template('{{ someday|parse_date|date:"Y m d" }}')
expected = '2015 04 15'
assert t.render(Context({'someday': '2015-04-15'})) == expected
assert t.render(Context({'someday': '2015-04-15T13:11:12Z'})) == expected
assert t.render(Context({'someday': 'foobar'})) == ''
assert t.render(Context({'someday': ''})) == ''
assert t.render(Context({'someday': None})) == ''
assert t.render(Context({'someday': {'foo': 'bar'}})) == ''
assert t.render(Context({'someday': ['foo', 'bar']})) == ''
t = Template('{{ someday|parse_time|date:"H i s" }}')
expected = '13 11 12'
assert t.render(Context({'someday': '13:11:12'})) == expected
assert t.render(Context({'someday': '13:11:12Z'})) == expected
assert t.render(Context({'someday': '13:11:12+00:00'})) == expected
assert t.render(Context({'someday': '13:11:12.12345'})) == expected
assert t.render(Context({'someday': '13:11:12.12345Z'})) == expected
assert t.render(Context({'someday': '13:11:12.12345+00:00'})) == expected
assert t.render(Context({'someday': '13:11'})) == '13 11 00'
assert t.render(Context({'someday': '13:99'})) == ''
assert t.render(Context({'someday': '13'})) == ''
assert t.render(Context({'someday': 'foobar'})) == ''
assert t.render(Context({'someday': ''})) == ''
assert t.render(Context({'someday': None})) == ''
assert t.render(Context({'someday': {'foo': 'bar'}})) == ''
assert t.render(Context({'someday': ['foo', 'bar']})) == ''
def test_has_role():
t = Template('{{ request.user|has_role:"Role1" }}')
request = RequestFactory().get('/')
user = User(username='foo', email='foo@example.net')
user.save()
request.user = user
context = Context({'request': request})
assert t.render(context) == 'False'
group = Group(name='Role1')
group.save()
user.groups.add(group)
user.save()
assert t.render(context) == 'True'
t = Template('{{ request.user|has_role:"Role2" }}')
assert t.render(context) == 'False'
group = Group(name='Role2')
group.save()
user.groups.add(group)
user.save()
assert t.render(context) == 'True'
# no request, no user, anonymous user
context = Context()
assert t.render(context) == 'False'
request = RequestFactory().get('/')
context = Context({'request': request})
assert t.render(context) == 'False'
request.user = AnonymousUser()
assert t.render(context) == 'False'
context['selected_user'] = get_user_from_name_id('unknown')
t = Template('{{ selected_user|has_role:"Role2" }}')
assert t.render(context) == 'False'
def test_get():
t = Template('{{ foo|get:"foo-bar" }}')
context = Context({'foo': {'foo-bar': 'hello'}})
assert t.render(context) == 'hello'
context = Context({'foo': {'bar-foo': 'hello'}})
assert t.render(context) == 'None'
context = Context({'foo': None})
assert t.render(context) == 'None'
t = Template('{{ foo|get:"foo-bar"|default:"" }}')
context = Context({'foo': {'rab': 'hello'}})
assert t.render(context) == ''
t = Template('{{ foo|get:key }}')
context = Context({'foo': {'foo-bar': 'hello'}, 'key': 'foo-bar'})
assert t.render(context) == 'hello'
def test_getlist():
# nothing in context
t = Template('{% for v in values|getlist:"foo" %}{{ v }},{% endfor %}')
context = Context()
assert t.render(context) == ''
# non value
t = Template('{% for v in values|getlist:"foo" %}{{ v }},{% endfor %}')
context = Context({'values': None})
assert t.render(context) == ''
# not a list
t = Template('{% for v in values|getlist:"foo" %}{{ v }},{% endfor %}')
context = Context({'values': 'foo'})
assert t.render(context) == 'None,None,None,'
# not a list of dict
t = Template('{% for v in values|getlist:"foo" %}{{ v }},{% endfor %}')
context = Context({'values': ['foo']})
assert t.render(context) == 'None,'
t = Template('{% for v in values|getlist:"foo" %}{{ v }},{% endfor %}')
context = Context({'values': [{'foo': 'bar'}, {'foo': 'baz'}]})
assert t.render(context) == 'bar,baz,'
t = Template('{% for v in values|getlist:"unknown" %}{{ v }},{% endfor %}')
context = Context({'values': [{'foo': 'bar'}, {'foo': 'baz'}]})
assert t.render(context) == 'None,None,'
t = Template('{% for v in values|getlist:"k"|getlist:"v" %}{{ v }},{% endfor %}')
context = Context({'values': [{'k': {'v': 'bar'}}, {'k': {'v': 'baz'}}]})
assert t.render(context) == 'bar,baz,'
t = Template('{% for v in values|getlist:"k"|getlist:"unknown" %}{{ v }},{% endfor %}')
context = Context({'values': [{'k': {'v': 'bar'}}, {'k': {'v': 'baz'}}]})
assert t.render(context) == 'None,None,'
t = Template('{% for v in values|getlist:"k"|getlist:"v" %}{{ v }},{% endfor %}')
context = Context({'values': [{'k': None}, {'k': {'v': 'baz'}}]})
assert t.render(context) == 'None,baz,'
def test_split():
t = Template('{% for x in plop|split %}{{x}}<br>{% endfor %}')
assert t.render(Context({'plop': 'ab cd ef'})) == 'ab<br>cd<br>ef<br>'
t = Template('{% for x in plop|split:"|" %}{{x}} {% endfor %}')
assert t.render(Context({'plop': 'ab|cd|ef'})) == 'ab cd ef '
t = Template('{% for x in plop|split:"|" %}{{x}} {% endfor %}')
assert t.render(Context({'plop': 42})) == '42 '
def test_strip_templatetag():
tmpl = Template('{{ foo|strip }}')
assert tmpl.render(Context()) == ''
assert tmpl.render(Context({'foo': None})) == ''
assert tmpl.render(Context({'foo': ' foo bar '})) == 'foo bar'
assert tmpl.render(Context({'foo': ' foo bar\t'})) == 'foo bar'
assert tmpl.render(Context({'foo': ' félé '})) == 'félé'
tmpl = Template('{{ foo|strip:"XY" }}')
assert tmpl.render(Context({'foo': 'XXfoo barXYX'})) == 'foo bar'
assert tmpl.render(Context({'foo': ' foo barXX'})) == ' foo bar'
def test_removeprefix_templatetag():
with pytest.raises(TemplateSyntaxError, match='removeprefix requires 2 arguments, 1 provided'):
tmpl = Template('{{ foo|removeprefix }}')
tmpl = Template('{{ foo|removeprefix:"" }}')
assert tmpl.render(Context({'foo': 'foo bar'})) == 'foo bar'
tmpl = Template('{{ foo|removeprefix:"XY" }}')
assert tmpl.render(Context({'foo': 'XYfoo barXY'})) == 'foo barXY'
assert tmpl.render(Context({'foo': 'foo bar'})) == 'foo bar'
assert tmpl.render(Context({'foo': 'xyfoo barXY'})) == 'xyfoo barXY'
assert tmpl.render(Context({'foo': ' XYfoo barXY'})) == ' XYfoo barXY'
assert tmpl.render(Context({'foo': 'XYXYfoo barXY'})) == 'XYfoo barXY'
def test_removesuffix_templatetag():
with pytest.raises(TemplateSyntaxError, match='removesuffix requires 2 arguments, 1 provided'):
tmpl = Template('{{ foo|removesuffix }}')
tmpl = Template('{{ foo|removesuffix:"" }}')
assert tmpl.render(Context({'foo': 'foo bar'})) == 'foo bar'
tmpl = Template('{{ foo|removesuffix:"XY" }}')
assert tmpl.render(Context({'foo': 'XYfoo barXY'})) == 'XYfoo bar'
assert tmpl.render(Context({'foo': 'foo bar'})) == 'foo bar'
assert tmpl.render(Context({'foo': 'XYfoo barxy'})) == 'XYfoo barxy'
assert tmpl.render(Context({'foo': 'XYfoo barXY '})) == 'XYfoo barXY '
assert tmpl.render(Context({'foo': 'XYfoo barXYXY'})) == 'XYfoo barXY'
def test_get_group():
context = Context(
{
'cities': [
{'name': 'Mumbai', 'population': '19,000,000', 'country': 'India'},
{'name': 'New York', 'population': '20,000,000', 'country': 'USA'},
{'name': 'Calcutta', 'population': '15,000,000', 'country': 'India'},
{'name': 'Chicago', 'population': '7,000,000', 'country': 'USA'},
{'name': 'Tokyo', 'population': '33,000,000', 'country': 'Japan'},
]
}
)
t = Template(
'{% regroup cities by country as country_list %}'
'{% for c in country_list|get_group:"USA" %}{{c.name}},{% endfor %}'
)
assert t.render(context) == 'New York,Chicago,'
def test_asset_template_tags():
for path in ('uploads', 'assets'):
if os.path.exists(default_storage.path(path)):
shutil.rmtree(default_storage.path(path))
assert Asset.objects.count() == 0
with override_settings(COMBO_ASSET_SLOTS={'collectivity:banner': {'label': 'Banner'}}):
t = Template(
'''{% load assets %}{% get_asset "collectivity:banner" as banner %}{% if banner %}BANNER{% endif %}'''
)
assert t.render(Context()) == ''
t = Template('''{% load assets %}{% asset_url "collectivity:banner" %}''')
assert t.render(Context()) == ''
t = Template('''{% load assets %}{% asset_css_url "collectivity:banner" %}''')
assert t.render(Context()) == 'none'
t = Template(
'''{% load assets %}{% get_asset "collectivity:banner" as banner %}{% if banner %}BANNER{% endif %}'''
)
Asset(key='collectivity:banner', asset=File(StringIO('test'), 'test.png')).save()
assert t.render(Context()) == 'BANNER'
t = Template('''{% load assets %}{% asset_url "collectivity:banner" %}''')
assert t.render(Context()) == '/media/assets/test.png'
t = Template('''{% load assets %}{% asset_css_url "collectivity:banner" %}''')
assert t.render(Context()) == 'url(/media/assets/test.png)'
page = Page(title='Home', slug='index', template_name='standard')
page.save()
t = Template('''{% load assets %}{% asset_url page.picture "collectivity:banner" %}''')
assert t.render(Context()) == '/media/assets/test.png'
t = Template('''{% load assets %}{% asset_css_url page.picture "collectivity:banner" %}''')
assert t.render(Context()) == 'url(/media/assets/test.png)'
page.picture = File(StringIO('test'), 'test2.png')
page.save()
t = Template('''{% load assets %}{% asset_url page.picture "collectivity:banner" %}''')
assert t.render(Context({'page': page})) == '/media/page-pictures/test2.png'
# pass image to sorl.thumbnail
t = Template('''{% load assets %}{% asset_url page.picture "collectivity:banner" size="200x200" %}''')
assert t.render(Context()).startswith('/media/cache/')
# unless file is missing
os.remove(page.picture.path)
del page.picture.file
t = Template('''{% load assets %}{% asset_url page.picture "collectivity:banner" size="200x200" %}''')
assert t.render(Context({'page': page})) == '/media/page-pictures/test2.png'
# unless it's in SVG
page.picture = File(StringIO('test'), 'test2.svg')
page.save()
t = Template('''{% load assets %}{% asset_url page.picture "collectivity:banner" size="200x200" %}''')
assert t.render(Context({'page': page})) == '/media/page-pictures/test2.svg'
cell = TextCell()
with override_settings(COMBO_CELL_ASSET_SLOTS={'data_textcell': {'picture': {'prefix': 'Picture'}}}):
# no slug
t = Template(
'''{% load assets %}{% get_asset cell=cell type='picture' as banner %}{% if banner %}BANNER{% endif %}'''
)
assert t.render(Context({'cell': cell})) == ''
# no asset
cell.slug = 'foobar'
t = Template(
'''{% load assets %}{% get_asset cell=cell type='picture' as banner %}{% if banner %}BANNER{% endif %}'''
)
assert t.render(Context({'cell': cell})) == ''
# ok
Asset.objects.create(key=cell.get_asset_slot_key('picture'), asset=File(StringIO('test'), 'test.png'))
t = Template(
'''{% load assets %}{% get_asset cell=cell type='picture' as banner %}{% if banner %}BANNER{% endif %}'''
)
assert t.render(Context({'cell': cell})) == 'BANNER'
# no context: AttributeError
t = Template(
'''{% load assets %}{% get_asset cell=cell type='picture' as banner %}{% if banner %}BANNER{% endif %}'''
)
assert t.render(Context()) == ''
with override_settings(COMBO_CELL_ASSET_SLOTS={}):
# cell type not defined in COMBO_CELL_ASSET_SLOTS
t = Template(
'''{% load assets %}{% get_asset cell=cell type='picture' as banner %}{% if banner %}BANNER{% endif %}'''
)
assert t.render(Context({'cell': cell})) == ''
def test_startswith():
t = Template('{% if foo|startswith:"bar" %}ok{% endif %}')
context = Context({'foo': None})
assert t.render(context) == ''
context = Context({'foo': 'xx'})
assert t.render(context) == ''
context = Context({'foo': 'bar'})
assert t.render(context) == 'ok'
def test_endswith_templatetag():
tmpl = Template('{% if foo|endswith:"bar" %}ok{% endif %}')
assert tmpl.render(Context({'foo': None})) == ''
assert tmpl.render(Context({'foo': 'bar-baz'})) == ''
assert tmpl.render(Context({'foo': 'baz-bar'})) == 'ok'
def test_datetime_templatetags():
tmpl = Template('{{ plop|datetime }}')
assert tmpl.render(Context({'plop': '2017-12-21 10:32'})) == 'Dec. 21, 2017, 10:32 a.m.'
assert tmpl.render(Context({'plop': '21/12/2017 10h32'})) == 'Dec. 21, 2017, 10:32 a.m.'
assert tmpl.render(Context({'plop': '2017-12-21'})) == 'Dec. 21, 2017, midnight'
assert tmpl.render(Context({'plop': '21/12/2017'})) == 'Dec. 21, 2017, midnight'
assert tmpl.render(Context({'plop': '10h32'})) == ''
assert tmpl.render(Context({'plop': 'x'})) == ''
assert tmpl.render(Context({'plop': None})) == ''
assert tmpl.render(Context({'plop': 3})) == ''
assert tmpl.render(Context({'plop': {'foo': 'bar'}})) == ''
assert tmpl.render(Context()) == ''
tmpl = Template('{{ plop|datetime:"d i" }}')
assert tmpl.render(Context({'plop': '2017-12-21 10:32'})) == '21 32'
assert tmpl.render(Context({'plop': '2017-12-21 10:32:42'})) == '21 32'
assert tmpl.render(Context({'plop': '21/12/2017 10:32'})) == '21 32'
assert tmpl.render(Context({'plop': '21/12/2017 10:32:42'})) == '21 32'
assert tmpl.render(Context({'plop': '21/12/2017 10h32'})) == '21 32'
assert tmpl.render(Context({'plop': '21/12/2017'})) == '21 00'
assert tmpl.render(Context({'plop': '10h32'})) == ''
assert tmpl.render(Context({'plop': 'x'})) == ''
assert tmpl.render(Context({'plop': None})) == ''
assert tmpl.render(Context({'plop': 3})) == ''
assert tmpl.render(Context({'plop': {'foo': 'bar'}})) == ''
assert tmpl.render(Context()) == ''
tmpl = Template('{% if d1|datetime > d2|datetime %}d1>d2{% else %}d1<=d2{% endif %}')
assert tmpl.render(Context({'d1': '2017-12-22', 'd2': '2017-12-21'})) == 'd1>d2'
assert tmpl.render(Context({'d1': '2017-12-21', 'd2': '2017-12-21'})) == 'd1<=d2'
assert tmpl.render(Context({'d1': '2017-12-21 10:30', 'd2': '2017-12-21 09:00'})) == 'd1>d2'
assert tmpl.render(Context({'d1': '2017-12-21 10:30', 'd2': '2017-12-21'})) == 'd1>d2'
assert tmpl.render(Context({'d1': '2017-12-22'})) == 'd1<=d2'
assert tmpl.render(Context({'d2': '2017-12-22'})) == 'd1<=d2'
tmpl = Template('{{ plop|date }}')
assert tmpl.render(Context({'plop': '2017-12-21'})) == 'Dec. 21, 2017'
assert tmpl.render(Context({'plop': '21/12/2017'})) == 'Dec. 21, 2017'
assert tmpl.render(Context({'plop': '2017-12-21 10:32'})) == 'Dec. 21, 2017'
assert tmpl.render(Context({'plop': '21/12/2017 10:32'})) == 'Dec. 21, 2017'
assert tmpl.render(Context({'plop': '21/12/2017 10h32'})) == 'Dec. 21, 2017'
assert tmpl.render(Context({'plop': '21/12/2017 10:32:42'})) == 'Dec. 21, 2017'
assert tmpl.render(Context({'plop': '10:32'})) == ''
assert tmpl.render(Context({'plop': 'x'})) == ''
assert tmpl.render(Context({'plop': None})) == ''
assert tmpl.render(Context({'plop': 3})) == ''
assert tmpl.render(Context({'plop': {'foo': 'bar'}})) == ''
assert tmpl.render(Context()) == ''
tmpl = Template('{{ plop|date:"d" }}')
assert tmpl.render(Context({'plop': '2017-12-21'})) == '21'
assert tmpl.render(Context({'plop': '21/12/2017'})) == '21'
assert tmpl.render(Context({'plop': '2017-12-21 10:32'})) == '21'
assert tmpl.render(Context({'plop': '10:32'})) == ''
assert tmpl.render(Context({'plop': 'x'})) == ''
assert tmpl.render(Context({'plop': None})) == ''
assert tmpl.render(Context({'plop': 3})) == ''
assert tmpl.render(Context({'plop': {'foo': 'bar'}})) == ''
assert tmpl.render(Context()) == ''
tmpl = Template('{% if d1|date > d2|date %}d1>d2{% else %}d1<=d2{% endif %}')
assert tmpl.render(Context({'d1': '2017-12-22', 'd2': '2017-12-21'})) == 'd1>d2'
assert tmpl.render(Context({'d1': '2017-12-21', 'd2': '2017-12-21'})) == 'd1<=d2'
assert tmpl.render(Context({'d1': '2017-12-22'})) == 'd1<=d2'
assert tmpl.render(Context({'d2': '2017-12-22'})) == 'd1<=d2'
tmpl = Template('{{ plop|time }}')
assert tmpl.render(Context({'plop': '10:32'})) == '10:32 a.m.'
assert tmpl.render(Context({'plop': '2017-12-21 10:32'})) == '10:32 a.m.'
assert tmpl.render(Context({'plop': '21/12/2017 10h32'})) == '10:32 a.m.'
assert tmpl.render(Context({'plop': '21/12/2017'})) == 'midnight'
assert tmpl.render(Context({'plop': 'x'})) == ''
assert tmpl.render(Context({'plop': None})) == ''
assert tmpl.render(Context({'plop': 3})) == ''
assert tmpl.render(Context({'plop': {'foo': 'bar'}})) == ''
assert tmpl.render(Context()) == ''
tmpl = Template('{{ plop|time:"H i" }}')
assert tmpl.render(Context({'plop': '10:32'})) == '10 32'
assert tmpl.render(Context({'plop': '2017-12-21 10:32'})) == '10 32'
assert tmpl.render(Context({'plop': '21/12/2017 10h32'})) == '10 32'
assert tmpl.render(Context({'plop': '21/12/2017'})) == '00 00'
assert tmpl.render(Context({'plop': 'x'})) == ''
assert tmpl.render(Context({'plop': None})) == ''
assert tmpl.render(Context({'plop': 3})) == ''
assert tmpl.render(Context({'plop': {'foo': 'bar'}})) == ''
assert tmpl.render(Context()) == ''
# old fashion, with parse_*
tmpl = Template('{{ plop|parse_datetime|date:"d i" }}')
assert tmpl.render(Context({'plop': '2017-12-21 10:32'})) == '21 32'
assert tmpl.render(Context({'plop': '2017-12-21 10:32:42'})) == '21 32'
assert tmpl.render(Context({'plop': '21/12/2017 10:32'})) == '21 32'
assert tmpl.render(Context({'plop': '21/12/2017 10:32:42'})) == '21 32'
assert tmpl.render(Context({'plop': '21/12/2017 10h32'})) == '21 32'
assert tmpl.render(Context({'plop': 'x'})) == ''
assert tmpl.render(Context({'plop': None})) == ''
assert tmpl.render(Context({'plop': 3})) == ''
assert tmpl.render(Context({'plop': {'foo': 'bar'}})) == ''
assert tmpl.render(Context()) == ''
tmpl = Template('{{ plop|parse_date|date:"d" }}')
assert tmpl.render(Context({'plop': '2017-12-21'})) == '21'
assert tmpl.render(Context({'plop': '21/12/2017'})) == '21'
assert tmpl.render(Context({'plop': 'x'})) == ''
assert tmpl.render(Context({'plop': None})) == ''
assert tmpl.render(Context({'plop': 3})) == ''
assert tmpl.render(Context({'plop': {'foo': 'bar'}})) == ''
assert tmpl.render(Context()) == ''
tmpl = Template('{{ plop|parse_time|date:"H i" }}')
assert tmpl.render(Context({'plop': '10:32'})) == '10 32'
assert tmpl.render(Context({'plop': 'x'})) == ''
assert tmpl.render(Context({'plop': None})) == ''
assert tmpl.render(Context({'plop': 3})) == ''
assert tmpl.render(Context({'plop': {'foo': 'bar'}})) == ''
assert tmpl.render(Context()) == ''
def test_date_maths():
tmpl = Template('{{ plop|add_days:4 }}')
assert tmpl.render(Context({'plop': '2017-12-21'})) == 'Dec. 25, 2017'
assert tmpl.render(Context({'plop': '2017-12-21 18:00'})) == 'Dec. 25, 2017'
tmpl = Template('{{ plop|add_days:"-1" }}')
assert tmpl.render(Context({'plop': '2017-12-21'})) == 'Dec. 20, 2017'
assert tmpl.render(Context({'plop': '2017-12-21 18:00'})) == 'Dec. 20, 2017'
tmpl = Template('{{ plop|add_days:1.5 }}')
assert tmpl.render(Context({'plop': '2017-12-21'})) == 'Dec. 22, 2017'
assert tmpl.render(Context({'plop': '2017-12-21 18:00'})) == 'Dec. 22, 2017'
tmpl = Template('{{ plop|add_days:"1.5" }}')
assert tmpl.render(Context({'plop': '2017-12-21'})) == 'Dec. 22, 2017'
assert tmpl.render(Context({'plop': '2017-12-21 18:00'})) == 'Dec. 22, 2017'
tmpl = Template('{{ plop|add_hours:24 }}')
assert tmpl.render(Context({'plop': '2017-12-21'})) == 'Dec. 22, 2017, midnight'
assert tmpl.render(Context({'plop': '2017-12-21 18:00'})) == 'Dec. 22, 2017, 6 p.m.'
tmpl = Template('{{ plop|add_hours:"12.5" }}')
assert tmpl.render(Context({'plop': '2017-12-21'})) == 'Dec. 21, 2017, 12:30 p.m.'
assert tmpl.render(Context({'plop': '2017-12-21 18:00'})) == 'Dec. 22, 2017, 6:30 a.m.'
def test_age_in():
context = {
'form_var_datefield': time.strptime('2018-07-31', '%Y-%m-%d'),
'form_var_datefield2': time.strptime('2018-08-31', '%Y-%m-%d'),
'form_var_datestring': '2018-07-31',
'today': datetime.date.today(),
'now': datetime.datetime.now(),
}
for condition_value in ( # hope date is > 2018
# age_in_days
'"1970-01-01"|age_in_days > 0',
'"01/01/1970"|age_in_days > 0',
'"2500-01-01"|age_in_days < 0',
'"01/01/2500"|age_in_days < 0',
'form_var_datefield|age_in_days > 50',
'form_var_datefield|age_in_days:form_var_datestring == 0',
'form_var_datefield|age_in_days:form_var_datefield2 == 31',
'form_var_datefield2|age_in_days:form_var_datefield == -31',
'form_var_datefield|age_in_days:form_var_datefield == 0',
'form_var_datestring|age_in_days:form_var_datefield == 0',
'form_var_datestring|age_in_days:form_var_datestring == 0',
'today|add_days:-5|age_in_days == 5',
'today|add_days:5|age_in_days == -5',
'today|age_in_days == 0',
# with datetimes
'"1970-01-01 02:03"|age_in_days > 0',
'"01/01/1970 02h03"|age_in_days > 0',
'"2500-01-01 02:03"|age_in_days < 0',
'"01/01/2500 02h03"|age_in_days < 0',
'now|age_in_days == 0',
'now|add_hours:-24|age_in_days == 1',
'now|add_hours:24|age_in_days == -1',
'"2010-11-12 13:14"|age_in_days:"2010-11-12 13:14" == 0',
'"2010-11-12 13:14"|age_in_days:"2010-11-12 12:14" == 0',
'"2010-11-12 13:14"|age_in_days:"2010-11-12 14:14" == 0',
'"2010-11-12 13:14"|age_in_days:"2010-11-13 13:13" == 1',
'"2010-11-12 13:14"|age_in_days:"2010-11-13 13:15" == 1',
# age_in_hours
'now|add_hours:-5|age_in_hours == 5',
'now|add_hours:25|age_in_hours == -24',
'now|age_in_hours == 0',
'"2010-11-12 13:14"|age_in_hours:"2010-11-12 13:14" == 0',
'"2010-11-12 13:14"|age_in_hours:"2010-11-12 12:14" == -1',
'"2010-11-12 13:14"|age_in_hours:"2010-11-12 14:14" == 1',
'"2010-11-12 13:14"|age_in_hours:"2010-11-13 13:13" == 23',
'"2010-11-12 13:14"|age_in_hours:"2010-11-13 13:15" == 24',
'"1970-01-01 02:03"|age_in_hours > 0',
'"01/01/1970 02h03"|age_in_hours > 0',
'"2500-01-01 02:03"|age_in_hours < 0',
'"01/01/2500 02h03"|age_in_hours < 0',
# with dates
'"1970-01-01"|age_in_hours > 0',
'"01/01/1970"|age_in_hours > 0',
'"2500-01-01"|age_in_hours < 0',
'"01/01/2500"|age_in_hours < 0',
'form_var_datefield|age_in_hours > 1200',
'form_var_datefield|age_in_hours:form_var_datestring == 0',
'form_var_datefield|age_in_hours:form_var_datefield2 == 744', # 31*24
'form_var_datefield2|age_in_hours:form_var_datefield == -744',
'form_var_datefield|age_in_hours:form_var_datefield == 0',
'form_var_datestring|age_in_hours:form_var_datefield == 0',
'form_var_datestring|age_in_hours:form_var_datestring == 0',
'today|add_days:-1|age_in_hours >= 24',
'today|add_days:1|age_in_hours <= -0',
'today|add_days:1|age_in_hours >= -24',
'today|age_in_hours >= 0',
# age_in_years
'"1970-01-01"|age_in_years > 0',
'"01/01/1970"|age_in_years > 0',
'"2500-01-01"|age_in_years < 0',
'"01/01/2500"|age_in_years < 0',
'form_var_datefield|age_in_years:"2019-07-31" == 1',
'form_var_datefield|age_in_years:"2019-09-20" == 1',
'form_var_datefield|age_in_years:"2020-07-30" == 1',
'form_var_datefield|age_in_years:"2020-07-31" == 2',
'form_var_datestring|age_in_years:"2019-07-31" == 1',
'today|age_in_years == 0',
'today|add_days:-500|age_in_years == 1',
'today|add_days:-300|age_in_years == 0',
'today|add_days:300|age_in_years == -1',
'now|age_in_years == 0',
'now|add_days:-500|age_in_years == 1',
'now|add_days:-300|age_in_years == 0',
'now|add_days:300|age_in_years == -1',
'"1970-01-01 02:03"|age_in_years > 0',
'"2500-01-01 02:03"|age_in_years < 0',
# age_in_months
'form_var_datefield|age_in_months:form_var_datefield2 == 1',
'form_var_datefield2|age_in_months:form_var_datefield == -1',
'form_var_datefield|age_in_months:"2019-07-31" == 12',
'form_var_datefield|age_in_months:"2019-08-20" == 12',
'form_var_datefield|age_in_months:"2019-09-20" == 13',
'form_var_datestring|age_in_months:"2019-09-20" == 13',
'"1970-01-01"|age_in_months > 0',
'"01/01/1970"|age_in_months > 0',
'"2500-01-01"|age_in_months < 0',
'"01/01/2500"|age_in_months < 0',
'"1970-01-01 02:03"|age_in_months > 0',
'"2500-01-01 02:03"|age_in_months < 0',
# fail produce empty string
'foobar|age_in_days == ""',
'"foobar"|age_in_days == ""',
'"1970-01-01"|age_in_days:"foobar" == ""',
'foobar|age_in_hours == ""',
'"foobar"|age_in_hours == ""',
'"1970-01-01"|age_in_hours:"foobar" == ""',
'foobar|age_in_years == ""',
'"foobar"|age_in_years == ""',
'"1970-01-01"|age_in_years:"foobar" == ""',
'foobar|age_in_months == ""',
'"foobar"|age_in_months == ""',
'"1970-01-01"|age_in_months:"foobar" == ""',
):
tmpl = Template('{%% if %s %%}Good{%% endif %%}' % condition_value)
assert tmpl.render(Context(context)) == 'Good'
@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(Context({'value': value})) == str(expected)
def test_decimal_templatetag():
tmpl = Template('{{ plop|decimal }}')
assert tmpl.render(Context({'plop': 'toto'})) == '0'
assert tmpl.render(Context({'plop': '3.14'})) == '3.14'
assert tmpl.render(Context({'plop': '3,14'})) == '3.14'
assert tmpl.render(Context({'plop': 3.14})) == '3.14'
assert tmpl.render(Context({'plop': 12345.678})) == '12345.678'
assert tmpl.render(Context({'plop': None})) == '0'
assert tmpl.render(Context({'plop': 0})) == '0'
tmpl = Template('{{ plop|decimal:3 }}')
assert tmpl.render(Context({'plop': '3.14'})) == '3.140'
assert tmpl.render(Context({'plop': None})) == '0.000'
tmpl = Template('{{ plop|decimal:"3" }}')
assert tmpl.render(Context({'plop': '3.14'})) == '3.140'
assert tmpl.render(Context({'plop': None})) == '0.000'
tmpl = Template('{% if plop|decimal > 2 %}hello{% endif %}')
assert tmpl.render(Context({'plop': 3})) == 'hello'
assert tmpl.render(Context({'plop': '3'})) == 'hello'
assert tmpl.render(Context({'plop': 2.001})) == 'hello'
assert tmpl.render(Context({'plop': '2.001'})) == 'hello'
assert tmpl.render(Context({'plop': 1})) == ''
assert tmpl.render(Context({'plop': 1.99})) == ''
assert tmpl.render(Context({'plop': '1.99'})) == ''
assert tmpl.render(Context({'plop': 'x'})) == ''
assert tmpl.render(Context({'plop': None})) == ''
assert tmpl.render(Context({'plop': 0})) == ''
tmpl = Template('{% if "3"|decimal == 3 %}hello{% endif %}')
assert tmpl.render(Context()) == 'hello'
tmpl = Template('{% if "3"|decimal == 3.0 %}hello{% endif %}')
assert tmpl.render(Context()) == 'hello'
tmpl = Template('{% if 3|decimal == 3 %}hello{% endif %}')
assert tmpl.render(Context()) == 'hello'
tmpl = Template('{% if 3.0|decimal == 3 %}hello{% endif %}')
assert tmpl.render(Context()) == 'hello'
tmpl = Template('{% if 3|decimal|decimal == 3 %}hello{% endif %}')
assert tmpl.render(Context()) == 'hello'
def test_mathematics_templatetag():
tmpl = Template('{{ term1|add:term2 }}')
# using strings
assert tmpl.render(Context({'term1': '1.1', 'term2': 0})) == '1.1'
assert tmpl.render(Context({'term1': 'not a number', 'term2': 1.2})) == ''
assert tmpl.render(Context({'term1': 0.3, 'term2': "1"})) == '1.3'
assert tmpl.render(Context({'term1': 1.4, 'term2': "not a number"})) == ''
# add
assert tmpl.render(Context({'term1': 4, 'term2': -0.9})) == '3.1'
assert tmpl.render(Context({'term1': '4', 'term2': -0.8})) == '3.2'
assert tmpl.render(Context({'term1': 4, 'term2': '-0.7'})) == '3.3'
assert tmpl.render(Context({'term1': '4', 'term2': '-0.6'})) == '3.4'
assert tmpl.render(Context({'term1': '', 'term2': 3.5})) == '3.5'
assert tmpl.render(Context({'term1': None, 'term2': 3.5})) == '3.5'
assert tmpl.render(Context({'term1': 3.6, 'term2': ''})) == '3.6'
assert tmpl.render(Context({'term1': '', 'term2': ''})) == ''
assert tmpl.render(Context({'term1': 3.6, 'term2': None})) == '3.6'
assert tmpl.render(Context({'term1': 0, 'term2': ''})) == '0'
assert tmpl.render(Context({'term1': '', 'term2': 0})) == '0'
assert tmpl.render(Context({'term1': 0, 'term2': 0})) == '0'
# if term is '' or None and other term is decimal
assert tmpl.render(Context({'term1': '', 'term2': 2.2})) == '2.2'
assert tmpl.render(Context({'term1': None, 'term2': 2.2})) == '2.2'
assert tmpl.render(Context({'term1': 2.2, 'term2': ''})) == '2.2'
assert tmpl.render(Context({'term1': 2.2, 'term2': None})) == '2.2'
# add using ',' instead of '.' decimal separator
assert tmpl.render(Context({'term1': '1,1', 'term2': '2,2'})) == '3.3'
assert tmpl.render(Context({'term1': '1,1', 'term2': '2.2'})) == '3.3'
assert tmpl.render(Context({'term1': '1,1', 'term2': 2.2})) == '3.3'
assert tmpl.render(Context({'term1': '1,1', 'term2': 0})) == '1.1'
assert tmpl.render(Context({'term1': '1,1', 'term2': ''})) == '1.1'
assert tmpl.render(Context({'term1': '1,1', 'term2': None})) == '1.1'
assert tmpl.render(Context({'term1': '1.1', 'term2': '2,2'})) == '3.3'
assert tmpl.render(Context({'term1': 1.1, 'term2': '2,2'})) == '3.3'
assert tmpl.render(Context({'term1': 0, 'term2': '2,2'})) == '2.2'
assert tmpl.render(Context({'term1': '', 'term2': '2,2'})) == '2.2'
assert tmpl.render(Context({'term1': None, 'term2': '2,2'})) == '2.2'
# subtract
tmpl = Template('{{ term1|subtract:term2 }}')
assert tmpl.render(Context({'term1': 5.1, 'term2': 1})) == '4.1'
assert tmpl.render(Context({'term1': '5.2', 'term2': 1})) == '4.2'
assert tmpl.render(Context({'term1': 5.3, 'term2': '1'})) == '4.3'
assert tmpl.render(Context({'term1': '5.4', 'term2': '1'})) == '4.4'
assert tmpl.render(Context({'term1': '', 'term2': -4.5})) == '4.5'
assert tmpl.render(Context({'term1': 4.6, 'term2': ''})) == '4.6'
assert tmpl.render(Context({'term1': '', 'term2': ''})) == '0'
assert tmpl.render(Context({'term1': 0, 'term2': ''})) == '0'
assert tmpl.render(Context({'term1': '', 'term2': 0})) == '0'
assert tmpl.render(Context({'term1': 0, 'term2': 0})) == '0'
# multiply
tmpl = Template('{{ term1|multiply:term2 }}')
assert tmpl.render(Context({'term1': '3', 'term2': '2'})) == '6'
assert tmpl.render(Context({'term1': 2.5, 'term2': 2})) == '5.0'
assert tmpl.render(Context({'term1': '2.5', 'term2': 2})) == '5.0'
assert tmpl.render(Context({'term1': 2.5, 'term2': '2'})) == '5.0'
assert tmpl.render(Context({'term1': '2.5', 'term2': '2'})) == '5.0'
assert tmpl.render(Context({'term1': '', 'term2': '2'})) == '0'
assert tmpl.render(Context({'term1': 2.5, 'term2': ''})) == '0.0'
assert tmpl.render(Context({'term1': '', 'term2': ''})) == '0'
assert tmpl.render(Context({'term1': 0, 'term2': ''})) == '0'
assert tmpl.render(Context({'term1': '', 'term2': 0})) == '0'
assert tmpl.render(Context({'term1': 0, 'term2': 0})) == '0'
# divide
tmpl = Template('{{ term1|divide:term2 }}')
assert tmpl.render(Context({'term1': 16, 'term2': 2})) == '8'
assert tmpl.render(Context({'term1': 6, 'term2': 0.75})) == '8'
assert tmpl.render(Context({'term1': '6', 'term2': 0.75})) == '8'
assert tmpl.render(Context({'term1': 6, 'term2': '0.75'})) == '8'
assert tmpl.render(Context({'term1': '6', 'term2': '0.75'})) == '8'
assert tmpl.render(Context({'term1': '', 'term2': '2'})) == '0'
assert tmpl.render(Context({'term1': 6, 'term2': ''})) == ''
assert tmpl.render(Context({'term1': '', 'term2': ''})) == ''
assert tmpl.render(Context({'term1': 0, 'term2': ''})) == ''
assert tmpl.render(Context({'term1': '', 'term2': 0})) == ''
assert tmpl.render(Context({'term1': 0, 'term2': 0})) == ''
tmpl = Template('{{ term1|divide:term2|decimal:2 }}')
assert tmpl.render(Context({'term1': 2, 'term2': 3})) == '0.67'
def test_concatenation_templatetag():
tmpl = Template('{{ term1|add:term2 }}')
# fallback to Django native add filter
assert tmpl.render(Context({'term1': 'foo', 'term2': 'bar'})) == 'foobar'
assert tmpl.render(Context({'term1': 'foo', 'term2': ''})) == 'foo'
assert tmpl.render(Context({'term1': 'foo', 'term2': None})) == 'foo'
assert tmpl.render(Context({'term1': 'foo', 'term2': 0})) == ''
assert tmpl.render(Context({'term1': '', 'term2': 'bar'})) == 'bar'
assert tmpl.render(Context({'term1': '', 'term2': ''})) == ''
assert tmpl.render(Context({'term1': '', 'term2': None})) == ''
assert tmpl.render(Context({'term1': None, 'term2': 'bar'})) == 'bar'
assert tmpl.render(Context({'term1': None, 'term2': ''})) == ''
assert tmpl.render(Context({'term1': None, 'term2': None})) == ''
assert tmpl.render(Context({'term1': 0, 'term2': 'bar'})) == ''
def test_rounding_templatetag():
# ceil
tmpl = Template('{{ value|ceil }}')
assert tmpl.render(Context({'value': 3.14})) == '4'
assert tmpl.render(Context({'value': 3.99})) == '4'
assert tmpl.render(Context({'value': -3.14})) == '-3'
assert tmpl.render(Context({'value': -3.99})) == '-3'
assert tmpl.render(Context({'value': 0})) == '0'
assert tmpl.render(Context({'value': '3.14'})) == '4'
assert tmpl.render(Context({'value': '3.99'})) == '4'
assert tmpl.render(Context({'value': '-3.14'})) == '-3'
assert tmpl.render(Context({'value': '-3.99'})) == '-3'
assert tmpl.render(Context({'value': '0'})) == '0'
assert tmpl.render(Context({'value': 'not a number'})) == '0'
assert tmpl.render(Context({'value': ''})) == '0'
assert tmpl.render(Context({'value': None})) == '0'
# floor
tmpl = Template('{{ value|floor }}')
assert tmpl.render(Context({'value': 3.14})) == '3'
assert tmpl.render(Context({'value': 3.99})) == '3'
assert tmpl.render(Context({'value': -3.14})) == '-4'
assert tmpl.render(Context({'value': -3.99})) == '-4'
assert tmpl.render(Context({'value': 0})) == '0'
assert tmpl.render(Context({'value': '3.14'})) == '3'
assert tmpl.render(Context({'value': '3.99'})) == '3'
assert tmpl.render(Context({'value': '-3.14'})) == '-4'
assert tmpl.render(Context({'value': '-3.99'})) == '-4'
assert tmpl.render(Context({'value': '0'})) == '0'
assert tmpl.render(Context({'value': 'not a number'})) == '0'
assert tmpl.render(Context({'value': ''})) == '0'
assert tmpl.render(Context({'value': None})) == '0'
def test_abs_templatetag():
tmpl = Template('{{ value|abs }}')
assert tmpl.render(Context({'value': 3.14})) == '3.14'
assert tmpl.render(Context({'value': -3.14})) == '3.14'
assert tmpl.render(Context({'value': 0})) == '0'
assert tmpl.render(Context({'value': '3.14'})) == '3.14'
assert tmpl.render(Context({'value': '-3.14'})) == '3.14'
assert tmpl.render(Context({'value': '0'})) == '0'
assert tmpl.render(Context({'value': 'not a number'})) == '0'
assert tmpl.render(Context({'value': ''})) == '0'
assert tmpl.render(Context({'value': None})) == '0'
def test_json_script():
tmpl = Template('{{ plop|json_script:"toto" }}')
assert (
tmpl.render(Context({'plop': {'a': 'b'}}))
== '<script id="toto" type="application/json">{"a": "b"}</script>'
)
def test_phonenumber_fr():
t = Template('{{ number|phonenumber_fr }}')
assert t.render(Context({'number': '01 23 45 67 89'})) == '01 23 45 67 89'
assert t.render(Context({'number': '0 1 23 45 67 89'})) == '01 23 45 67 89'
assert t.render(Context({'number': '0123456789'})) == '01 23 45 67 89'
assert t.render(Context({'number': '01.23.45.67.89'})) == '01 23 45 67 89'
assert t.render(Context({'number': '01 23 45 67 89'})) == '01 23 45 67 89'
assert t.render(Context({'number': '00 33 1 23 45 67 89'})) == '00 33 1 23 45 67 89'
assert t.render(Context({'number': '00 33 1 23 45 67 89'})) == '00 33 1 23 45 67 89'
assert t.render(Context({'number': '+33 1 23 45 67 89'})) == '+33 1 23 45 67 89'
assert t.render(Context({'number': '+33 (0)1 23 45 67 89'})) == '+33 1 23 45 67 89'
# drom
assert t.render(Context({'number': '02 62 11 22 33'})) == '02 62 11 22 33'
assert t.render(Context({'number': '00 262 11 22 33'})) == '00 262 11 22 33'
assert t.render(Context({'number': '+262 112233'})) == '+262 11 22 33'
t = Template('{{ number|phonenumber_fr:"." }}')
assert t.render(Context({'number': '01 23 45 67 89'})) == '01.23.45.67.89'
# unknown
assert t.render(Context({'number': '12 3'})) == '12 3'
assert t.render(Context({'number': 'bla bla'})) == 'bla bla'
assert t.render(Context({'number': None})) == 'None'
t = Template('{{ number|decimal|phonenumber_fr }}')
assert t.render(Context({'number': '1,33'})) == '1.33'
def test_django_contrib_humanize_filters():
tmpl = Template('{{ foo|intcomma }}')
assert tmpl.render(Context({'foo': 10000})) == '10,000'
assert tmpl.render(Context({'foo': '10000'})) == '10,000'
with override_settings(LANGUAGE_CODE='fr-fr'):
assert tmpl.render(Context({'foo': 10000})) == '10 000'
assert tmpl.render(Context({'foo': '10000'})) == '10 000'