Fixed #23958 -- Rewrote filter tests as unit tests.

This commit is contained in:
Preston Timmons 2014-12-03 20:21:11 -06:00 committed by Tim Graham
parent 34a06d99e0
commit 5c68870169
89 changed files with 1682 additions and 543 deletions

View File

@ -0,0 +1,46 @@
from datetime import date, timedelta
from django.test import SimpleTestCase
from ..utils import render, setup
class AddTests(SimpleTestCase):
"""
Tests for #11687 and #16676
"""
@setup({'add01': '{{ i|add:"5" }}'})
def test_add01(self):
output = render('add01', {'i': 2000})
self.assertEqual(output, '2005')
@setup({'add02': '{{ i|add:"napis" }}'})
def test_add02(self):
output = render('add02', {'i': 2000})
self.assertEqual(output, '')
@setup({'add03': '{{ i|add:16 }}'})
def test_add03(self):
output = render('add03', {'i': 'not_an_int'})
self.assertEqual(output, '')
@setup({'add04': '{{ i|add:"16" }}'})
def test_add04(self):
output = render('add04', {'i': 'not_an_int'})
self.assertEqual(output, 'not_an_int16')
@setup({'add05': '{{ l1|add:l2 }}'})
def test_add05(self):
output = render('add05', {'l1': [1, 2], 'l2': [3, 4]})
self.assertEqual(output, '[1, 2, 3, 4]')
@setup({'add06': '{{ t1|add:t2 }}'})
def test_add06(self):
output = render('add06', {'t1': (3, 4), 't2': (1, 2)})
self.assertEqual(output, '(3, 4, 1, 2)')
@setup({'add07': '{{ d|add:t }}'})
def test_add07(self):
output = render('add07', {'d': date(2000, 1, 1), 't': timedelta(10)})
self.assertEqual(output, 'Jan. 11, 2000')

View File

@ -0,0 +1,17 @@
from django.test import SimpleTestCase
from django.utils.safestring import mark_safe
from ..utils import render, setup
class AddslashesTests(SimpleTestCase):
@setup({'addslashes01': '{% autoescape off %}{{ a|addslashes }} {{ b|addslashes }}{% endautoescape %}'})
def test_addslashes01(self):
output = render('addslashes01', {"a": "<a>'", "b": mark_safe("<a>'")})
self.assertEqual(output, r"<a>\' <a>\'")
@setup({'addslashes02': '{{ a|addslashes }} {{ b|addslashes }}'})
def test_addslashes02(self):
output = render('addslashes02', {"a": "<a>'", "b": mark_safe("<a>'")})
self.assertEqual(output, r"&lt;a&gt;\&#39; <a>\'")

View File

@ -0,0 +1,29 @@
from django.test import SimpleTestCase
from ..utils import render, setup, SafeClass, UnsafeClass
class AutoescapeStringfilterTests(SimpleTestCase):
"""
Filters decorated with stringfilter still respect is_safe.
"""
@setup({'autoescape-stringfilter01': '{{ unsafe|capfirst }}'})
def test_autoescape_stringfilter01(self):
output = render('autoescape-stringfilter01', {'unsafe': UnsafeClass()})
self.assertEqual(output, 'You &amp; me')
@setup({'autoescape-stringfilter02': '{% autoescape off %}{{ unsafe|capfirst }}{% endautoescape %}'})
def test_autoescape_stringfilter02(self):
output = render('autoescape-stringfilter02', {'unsafe': UnsafeClass()})
self.assertEqual(output, 'You & me')
@setup({'autoescape-stringfilter03': '{{ safe|capfirst }}'})
def test_autoescape_stringfilter03(self):
output = render('autoescape-stringfilter03', {'safe': SafeClass()})
self.assertEqual(output, 'You &gt; me')
@setup({'autoescape-stringfilter04': '{% autoescape off %}{{ safe|capfirst }}{% endautoescape %}'})
def test_autoescape_stringfilter04(self):
output = render('autoescape-stringfilter04', {'safe': SafeClass()})
self.assertEqual(output, 'You &gt; me')

View File

@ -0,0 +1,17 @@
from django.test import SimpleTestCase
from django.utils.safestring import mark_safe
from ..utils import render, setup
class CapfirstTests(SimpleTestCase):
@setup({'capfirst01': '{% autoescape off %}{{ a|capfirst }} {{ b|capfirst }}{% endautoescape %}'})
def test_capfirst01(self):
output = render('capfirst01', {'a': 'fred>', 'b': mark_safe('fred&gt;')})
self.assertEqual(output, 'Fred> Fred&gt;')
@setup({'capfirst02': '{{ a|capfirst }} {{ b|capfirst }}'})
def test_capfirst02(self):
output = render('capfirst02', {'a': 'fred>', 'b': mark_safe('fred&gt;')})
self.assertEqual(output, 'Fred&gt; Fred&gt;')

View File

@ -0,0 +1,18 @@
from django.test import SimpleTestCase
from django.utils.safestring import mark_safe
from ..utils import render, setup
class CenterTests(SimpleTestCase):
@setup({'center01':
'{% autoescape off %}.{{ a|center:"5" }}. .{{ b|center:"5" }}.{% endautoescape %}'})
def test_center01(self):
output = render('center01', {"a": "a&b", "b": mark_safe("a&b")})
self.assertEqual(output, ". a&b . . a&b .")
@setup({'center02': '.{{ a|center:"5" }}. .{{ b|center:"5" }}.'})
def test_center02(self):
output = render('center02', {"a": "a&b", "b": mark_safe("a&b")})
self.assertEqual(output, ". a&amp;b . . a&b .")

View File

@ -0,0 +1,86 @@
from django.test import SimpleTestCase
from django.utils.safestring import mark_safe
from ..utils import render, setup
class ChainingTests(SimpleTestCase):
"""
Chaining safeness-preserving filters should not alter the safe status.
"""
@setup({'chaining01': '{{ a|capfirst|center:"7" }}.{{ b|capfirst|center:"7" }}'})
def test_chaining01(self):
output = render('chaining01', {'a': 'a < b', 'b': mark_safe('a < b')})
self.assertEqual(output, ' A &lt; b . A < b ')
@setup({'chaining02':
'{% autoescape off %}{{ a|capfirst|center:"7" }}.{{ b|capfirst|center:"7" }}{% endautoescape %}'})
def test_chaining02(self):
output = render('chaining02', {'a': 'a < b', 'b': mark_safe('a < b')})
self.assertEqual(output, ' A < b . A < b ')
# Using a filter that forces a string back to unsafe:
@setup({'chaining03': '{{ a|cut:"b"|capfirst }}.{{ b|cut:"b"|capfirst }}'})
def test_chaining03(self):
output = render('chaining03', {'a': 'a < b', 'b': mark_safe('a < b')})
self.assertEqual(output, 'A &lt; .A < ')
@setup({'chaining04':
'{% autoescape off %}{{ a|cut:"b"|capfirst }}.{{ b|cut:"b"|capfirst }}{% endautoescape %}'})
def test_chaining04(self):
output = render('chaining04', {'a': 'a < b', 'b': mark_safe('a < b')})
self.assertEqual(output, 'A < .A < ')
# Using a filter that forces safeness does not lead to double-escaping
@setup({'chaining05': '{{ a|escape|capfirst }}'})
def test_chaining05(self):
output = render('chaining05', {'a': 'a < b'})
self.assertEqual(output, 'A &lt; b')
@setup({'chaining06': '{% autoescape off %}{{ a|escape|capfirst }}{% endautoescape %}'})
def test_chaining06(self):
output = render('chaining06', {'a': 'a < b'})
self.assertEqual(output, 'A &lt; b')
# Force to safe, then back (also showing why using force_escape too
# early in a chain can lead to unexpected results).
@setup({'chaining07': '{{ a|force_escape|cut:";" }}'})
def test_chaining07(self):
output = render('chaining07', {'a': 'a < b'})
self.assertEqual(output, 'a &amp;lt b')
@setup({'chaining08': '{% autoescape off %}{{ a|force_escape|cut:";" }}{% endautoescape %}'})
def test_chaining08(self):
output = render('chaining08', {'a': 'a < b'})
self.assertEqual(output, 'a &lt b')
@setup({'chaining09': '{{ a|cut:";"|force_escape }}'})
def test_chaining09(self):
output = render('chaining09', {'a': 'a < b'})
self.assertEqual(output, 'a &lt; b')
@setup({'chaining10': '{% autoescape off %}{{ a|cut:";"|force_escape }}{% endautoescape %}'})
def test_chaining10(self):
output = render('chaining10', {'a': 'a < b'})
self.assertEqual(output, 'a &lt; b')
@setup({'chaining11': '{{ a|cut:"b"|safe }}'})
def test_chaining11(self):
output = render('chaining11', {'a': 'a < b'})
self.assertEqual(output, 'a < ')
@setup({'chaining12': '{% autoescape off %}{{ a|cut:"b"|safe }}{% endautoescape %}'})
def test_chaining12(self):
output = render('chaining12', {'a': 'a < b'})
self.assertEqual(output, 'a < ')
@setup({'chaining13': '{{ a|safe|force_escape }}'})
def test_chaining13(self):
output = render('chaining13', {"a": "a < b"})
self.assertEqual(output, 'a &lt; b')
@setup({'chaining14': '{% autoescape off %}{{ a|safe|force_escape }}{% endautoescape %}'})
def test_chaining14(self):
output = render('chaining14', {"a": "a < b"})
self.assertEqual(output, 'a &lt; b')

View File

@ -0,0 +1,39 @@
from django.test import SimpleTestCase
from django.utils.safestring import mark_safe
from ..utils import render, setup
class CutTests(SimpleTestCase):
@setup({'cut01': '{% autoescape off %}{{ a|cut:"x" }} {{ b|cut:"x" }}{% endautoescape %}'})
def test_cut01(self):
output = render('cut01', {"a": "x&y", "b": mark_safe("x&amp;y")})
self.assertEqual(output, "&y &amp;y")
@setup({'cut02': '{{ a|cut:"x" }} {{ b|cut:"x" }}'})
def test_cut02(self):
output = render('cut02', {"a": "x&y", "b": mark_safe("x&amp;y")})
self.assertEqual(output, "&amp;y &amp;y")
@setup({'cut03': '{% autoescape off %}{{ a|cut:"&" }} {{ b|cut:"&" }}{% endautoescape %}'})
def test_cut03(self):
output = render('cut03', {"a": "x&y", "b": mark_safe("x&amp;y")})
self.assertEqual(output, "xy xamp;y")
@setup({'cut04': '{{ a|cut:"&" }} {{ b|cut:"&" }}'})
def test_cut04(self):
output = render('cut04', {"a": "x&y", "b": mark_safe("x&amp;y")})
self.assertEqual(output, "xy xamp;y")
# Passing ';' to cut can break existing HTML entities, so those strings
# are auto-escaped.
@setup({'cut05': '{% autoescape off %}{{ a|cut:";" }} {{ b|cut:";" }}{% endautoescape %}'})
def test_cut05(self):
output = render('cut05', {"a": "x&y", "b": mark_safe("x&amp;y")})
self.assertEqual(output, "x&y x&ampy")
@setup({'cut06': '{{ a|cut:";" }} {{ b|cut:";" }}'})
def test_cut06(self):
output = render('cut06', {"a": "x&y", "b": mark_safe("x&amp;y")})
self.assertEqual(output, "x&amp;y x&amp;ampy")

View File

@ -0,0 +1,60 @@
from datetime import datetime, time
from django.utils import timezone
from .timezone_utils import TimezoneTestCase
from ..utils import render, setup
class DateTests(TimezoneTestCase):
@setup({'date01': '{{ d|date:"m" }}'})
def test_date01(self):
output = render('date01', {'d': datetime(2008, 1, 1)})
self.assertEqual(output, '01')
@setup({'date02': '{{ d|date }}'})
def test_date02(self):
output = render('date02', {'d': datetime(2008, 1, 1)})
self.assertEqual(output, 'Jan. 1, 2008')
@setup({'date03': '{{ d|date:"m" }}'})
def test_date03(self):
"""
#9520: Make sure |date doesn't blow up on non-dates
"""
output = render('date03', {'d': 'fail_string'})
self.assertEqual(output, '')
# ISO date formats
@setup({'date04': '{{ d|date:"o" }}'})
def test_date04(self):
output = render('date04', {'d': datetime(2008, 12, 29)})
self.assertEqual(output, '2009')
@setup({'date05': '{{ d|date:"o" }}'})
def test_date05(self):
output = render('date05', {'d': datetime(2010, 1, 3)})
self.assertEqual(output, '2009')
# Timezone name
@setup({'date06': '{{ d|date:"e" }}'})
def test_date06(self):
output = render('date06', {'d': datetime(2009, 3, 12, tzinfo=timezone.get_fixed_timezone(30))})
self.assertEqual(output, '+0030')
@setup({'date07': '{{ d|date:"e" }}'})
def test_date07(self):
output = render('date07', {'d': datetime(2009, 3, 12)})
self.assertEqual(output, '')
# #19370: Make sure |date doesn't blow up on a midnight time object
@setup({'date08': '{{ t|date:"H:i" }}'})
def test_date08(self):
output = render('date08', {'t': time(0, 1)})
self.assertEqual(output, '00:01')
@setup({'date09': '{{ t|date:"H:i" }}'})
def test_date09(self):
output = render('date09', {'t': time(0, 0)})
self.assertEqual(output, '00:00')

View File

@ -0,0 +1,47 @@
from django.test import SimpleTestCase
from django.utils.safestring import mark_safe
from ..utils import render, setup
class DefaultTests(SimpleTestCase):
"""
Literal string arguments to the default filter are always treated as
safe strings, regardless of the auto-escaping state.
Note: we have to use {"a": ""} here, otherwise the invalid template
variable string interferes with the test result.
"""
@setup({'default01': '{{ a|default:"x<" }}'})
def test_default01(self):
output = render('default01', {"a": ""})
self.assertEqual(output, "x<")
@setup({'default02': '{% autoescape off %}{{ a|default:"x<" }}{% endautoescape %}'})
def test_default02(self):
output = render('default02', {"a": ""})
self.assertEqual(output, "x<")
@setup({'default03': '{{ a|default:"x<" }}'})
def test_default03(self):
output = render('default03', {"a": mark_safe("x>")})
self.assertEqual(output, "x>")
@setup({'default04': '{% autoescape off %}{{ a|default:"x<" }}{% endautoescape %}'})
def test_default04(self):
output = render('default04', {"a": mark_safe("x>")})
self.assertEqual(output, "x>")
class DefaultIfNoneTests(SimpleTestCase):
@setup({'default_if_none01': '{{ a|default:"x<" }}'})
def test_default_if_none01(self):
output = render('default_if_none01', {"a": None})
self.assertEqual(output, "x<")
@setup({'default_if_none02': '{% autoescape off %}{{ a|default:"x<" }}{% endautoescape %}'})
def test_default_if_none02(self):
output = render('default_if_none02', {"a": None})
self.assertEqual(output, "x<")

View File

@ -0,0 +1,33 @@
from django.test import SimpleTestCase
from django.utils.safestring import mark_safe
from ..utils import render, setup
class EscapeTests(SimpleTestCase):
"""
The "escape" filter works the same whether autoescape is on or off,
but it has no effect on strings already marked as safe.
"""
@setup({'escape01': '{{ a|escape }} {{ b|escape }}'})
def test_escape01(self):
output = render('escape01', {"a": "x&y", "b": mark_safe("x&y")})
self.assertEqual(output, "x&amp;y x&y")
@setup({'escape02': '{% autoescape off %}{{ a|escape }} {{ b|escape }}{% endautoescape %}'})
def test_escape02(self):
output = render('escape02', {"a": "x&y", "b": mark_safe("x&y")})
self.assertEqual(output, "x&amp;y x&y")
# It is only applied once, regardless of the number of times it
# appears in a chain.
@setup({'escape03': '{% autoescape off %}{{ a|escape|escape }}{% endautoescape %}'})
def test_escape03(self):
output = render('escape03', {"a": "x&y"})
self.assertEqual(output, "x&amp;y")
@setup({'escape04': '{{ a|escape|escape }}'})
def test_escape04(self):
output = render('escape04', {"a": "x&y"})
self.assertEqual(output, "x&amp;y")

View File

@ -0,0 +1,20 @@
from django.test import SimpleTestCase
from ..utils import render, setup
class EscapejsTests(SimpleTestCase):
@setup({'escapejs01': '{{ a|escapejs }}'})
def test_escapejs01(self):
output = render('escapejs01', {'a': 'testing\r\njavascript \'string" <b>escaping</b>'})
self.assertEqual(output, 'testing\\u000D\\u000Ajavascript '
'\\u0027string\\u0022 \\u003Cb\\u003E'
'escaping\\u003C/b\\u003E')
@setup({'escapejs02': '{% autoescape off %}{{ a|escapejs }}{% endautoescape %}'})
def test_escapejs02(self):
output = render('escapejs02', {'a': 'testing\r\njavascript \'string" <b>escaping</b>'})
self.assertEqual(output, 'testing\\u000D\\u000Ajavascript '
'\\u0027string\\u0022 \\u003Cb\\u003E'
'escaping\\u003C/b\\u003E')

View File

@ -0,0 +1,17 @@
from django.test import SimpleTestCase
from django.utils.safestring import mark_safe
from ..utils import render, setup
class FirstTests(SimpleTestCase):
@setup({'first01': '{{ a|first }} {{ b|first }}'})
def test_first01(self):
output = render('first01', {"a": ["a&b", "x"], "b": [mark_safe("a&b"), "x"]})
self.assertEqual(output, "a&amp;b a&b")
@setup({'first02': '{% autoescape off %}{{ a|first }} {{ b|first }}{% endautoescape %}'})
def test_first02(self):
output = render('first02', {"a": ["a&b", "x"], "b": [mark_safe("a&b"), "x"]})
self.assertEqual(output, "a&b a&b")

View File

@ -0,0 +1,18 @@
from django.test import SimpleTestCase
from django.utils.safestring import mark_safe
from ..utils import render, setup
class FloatformatTests(SimpleTestCase):
@setup({'floatformat01':
'{% autoescape off %}{{ a|floatformat }} {{ b|floatformat }}{% endautoescape %}'})
def test_floatformat01(self):
output = render('floatformat01', {"a": "1.42", "b": mark_safe("1.42")})
self.assertEqual(output, "1.4 1.4")
@setup({'floatformat02': '{{ a|floatformat }} {{ b|floatformat }}'})
def test_floatformat02(self):
output = render('floatformat02', {"a": "1.42", "b": mark_safe("1.42")})
self.assertEqual(output, "1.4 1.4")

View File

@ -0,0 +1,52 @@
from django.test import SimpleTestCase
from ..utils import render, setup
class ForceEscapeTests(SimpleTestCase):
"""
Force_escape is applied immediately. It can be used to provide
double-escaping, for example.
"""
@setup({'force-escape01': '{% autoescape off %}{{ a|force_escape }}{% endautoescape %}'})
def test_force_escape01(self):
output = render('force-escape01', {"a": "x&y"})
self.assertEqual(output, "x&amp;y")
@setup({'force-escape02': '{{ a|force_escape }}'})
def test_force_escape02(self):
output = render('force-escape02', {"a": "x&y"})
self.assertEqual(output, "x&amp;y")
@setup({'force-escape03': '{% autoescape off %}{{ a|force_escape|force_escape }}{% endautoescape %}'})
def test_force_escape03(self):
output = render('force-escape03', {"a": "x&y"})
self.assertEqual(output, "x&amp;amp;y")
@setup({'force-escape04': '{{ a|force_escape|force_escape }}'})
def test_force_escape04(self):
output = render('force-escape04', {"a": "x&y"})
self.assertEqual(output, "x&amp;amp;y")
# Because the result of force_escape is "safe", an additional
# escape filter has no effect.
@setup({'force-escape05': '{% autoescape off %}{{ a|force_escape|escape }}{% endautoescape %}'})
def test_force_escape05(self):
output = render('force-escape05', {"a": "x&y"})
self.assertEqual(output, "x&amp;y")
@setup({'force-escape06': '{{ a|force_escape|escape }}'})
def test_force_escape06(self):
output = render('force-escape06', {"a": "x&y"})
self.assertEqual(output, "x&amp;y")
@setup({'force-escape07': '{% autoescape off %}{{ a|escape|force_escape }}{% endautoescape %}'})
def test_force_escape07(self):
output = render('force-escape07', {"a": "x&y"})
self.assertEqual(output, "x&amp;y")
@setup({'force-escape08': '{{ a|escape|force_escape }}'})
def test_force_escape08(self):
output = render('force-escape08', {"a": "x&y"})
self.assertEqual(output, "x&amp;y")

View File

@ -0,0 +1,30 @@
from django.test import SimpleTestCase
from django.utils.safestring import mark_safe
from ..utils import render, setup
class IriencodeTests(SimpleTestCase):
"""
Ensure iriencode keeps safe strings.
"""
@setup({'iriencode01': '{{ url|iriencode }}'})
def test_iriencode01(self):
output = render('iriencode01', {'url': '?test=1&me=2'})
self.assertEqual(output, '?test=1&amp;me=2')
@setup({'iriencode02': '{% autoescape off %}{{ url|iriencode }}{% endautoescape %}'})
def test_iriencode02(self):
output = render('iriencode02', {'url': '?test=1&me=2'})
self.assertEqual(output, '?test=1&me=2')
@setup({'iriencode03': '{{ url|iriencode }}'})
def test_iriencode03(self):
output = render('iriencode03', {'url': mark_safe('?test=1&me=2')})
self.assertEqual(output, '?test=1&me=2')
@setup({'iriencode04': '{% autoescape off %}{{ url|iriencode }}{% endautoescape %}'})
def test_iriencode04(self):
output = render('iriencode04', {'url': mark_safe('?test=1&me=2')})
self.assertEqual(output, '?test=1&me=2')

View File

@ -0,0 +1,49 @@
from django.test import SimpleTestCase
from django.utils.safestring import mark_safe
from ..utils import render, setup
class JoinTests(SimpleTestCase):
@setup({'join01': '{{ a|join:", " }}'})
def test_join01(self):
output = render('join01', {'a': ['alpha', 'beta & me']})
self.assertEqual(output, 'alpha, beta &amp; me')
@setup({'join02': '{% autoescape off %}{{ a|join:", " }}{% endautoescape %}'})
def test_join02(self):
output = render('join02', {'a': ['alpha', 'beta & me']})
self.assertEqual(output, 'alpha, beta & me')
@setup({'join03': '{{ a|join:" &amp; " }}'})
def test_join03(self):
output = render('join03', {'a': ['alpha', 'beta & me']})
self.assertEqual(output, 'alpha &amp; beta &amp; me')
@setup({'join04': '{% autoescape off %}{{ a|join:" &amp; " }}{% endautoescape %}'})
def test_join04(self):
output = render('join04', {'a': ['alpha', 'beta & me']})
self.assertEqual(output, 'alpha &amp; beta & me')
# #11377 Test that joining with unsafe joiners doesn't result in
# unsafe strings
@setup({'join05': '{{ a|join:var }}'})
def test_join05(self):
output = render('join05', {'a': ['alpha', 'beta & me'], 'var': ' & '})
self.assertEqual(output, 'alpha &amp; beta &amp; me')
@setup({'join06': '{{ a|join:var }}'})
def test_join06(self):
output = render('join06', {'a': ['alpha', 'beta & me'], 'var': mark_safe(' & ')})
self.assertEqual(output, 'alpha & beta &amp; me')
@setup({'join07': '{{ a|join:var|lower }}'})
def test_join07(self):
output = render('join07', {'a': ['Alpha', 'Beta & me'], 'var': ' & '})
self.assertEqual(output, 'alpha &amp; beta &amp; me')
@setup({'join08': '{{ a|join:var|lower }}'})
def test_join08(self):
output = render('join08', {'a': ['Alpha', 'Beta & me'], 'var': mark_safe(' & ')})
self.assertEqual(output, 'alpha & beta &amp; me')

View File

@ -0,0 +1,17 @@
from django.test import SimpleTestCase
from django.utils.safestring import mark_safe
from ..utils import render, setup
class LastTests(SimpleTestCase):
@setup({'last01': '{{ a|last }} {{ b|last }}'})
def test_last01(self):
output = render('last01', {"a": ["x", "a&b"], "b": ["x", mark_safe("a&b")]})
self.assertEqual(output, "a&amp;b a&b")
@setup({'last02': '{% autoescape off %}{{ a|last }} {{ b|last }}{% endautoescape %}'})
def test_last02(self):
output = render('last02', {"a": ["x", "a&b"], "b": ["x", mark_safe("a&b")]})
self.assertEqual(output, "a&b a&b")

View File

@ -0,0 +1,43 @@
from django.test import SimpleTestCase
from django.utils.safestring import mark_safe
from ..utils import render, setup
class LengthTests(SimpleTestCase):
@setup({'length01': '{{ list|length }}'})
def test_length01(self):
output = render('length01', {'list': ['4', None, True, {}]})
self.assertEqual(output, '4')
@setup({'length02': '{{ list|length }}'})
def test_length02(self):
output = render('length02', {'list': []})
self.assertEqual(output, '0')
@setup({'length03': '{{ string|length }}'})
def test_length03(self):
output = render('length03', {'string': ''})
self.assertEqual(output, '0')
@setup({'length04': '{{ string|length }}'})
def test_length04(self):
output = render('length04', {'string': 'django'})
self.assertEqual(output, '6')
@setup({'length05': '{% if string|length == 6 %}Pass{% endif %}'})
def test_length05(self):
output = render('length05', {'string': mark_safe('django')})
self.assertEqual(output, 'Pass')
# Invalid uses that should fail silently.
@setup({'length06': '{{ int|length }}'})
def test_length06(self):
output = render('length06', {'int': 7})
self.assertEqual(output, '0')
@setup({'length07': '{{ None|length }}'})
def test_length07(self):
output = render('length07', {'None': None})
self.assertEqual(output, '0')

View File

@ -0,0 +1,63 @@
from django.test import SimpleTestCase
from ..utils import render, setup
class LengthIsTests(SimpleTestCase):
@setup({'length_is01': '{% if some_list|length_is:"4" %}Four{% endif %}'})
def test_length_is01(self):
output = render('length_is01', {'some_list': ['4', None, True, {}]})
self.assertEqual(output, 'Four')
@setup({'length_is02': '{% if some_list|length_is:"4" %}Four{% else %}Not Four{% endif %}'})
def test_length_is02(self):
output = render('length_is02', {'some_list': ['4', None, True, {}, 17]})
self.assertEqual(output, 'Not Four')
@setup({'length_is03': '{% if mystring|length_is:"4" %}Four{% endif %}'})
def test_length_is03(self):
output = render('length_is03', {'mystring': 'word'})
self.assertEqual(output, 'Four')
@setup({'length_is04': '{% if mystring|length_is:"4" %}Four{% else %}Not Four{% endif %}'})
def test_length_is04(self):
output = render('length_is04', {'mystring': 'Python'})
self.assertEqual(output, 'Not Four')
@setup({'length_is05': '{% if mystring|length_is:"4" %}Four{% else %}Not Four{% endif %}'})
def test_length_is05(self):
output = render('length_is05', {'mystring': ''})
self.assertEqual(output, 'Not Four')
@setup({'length_is06': '{% with var|length as my_length %}{{ my_length }}{% endwith %}'})
def test_length_is06(self):
output = render('length_is06', {'var': 'django'})
self.assertEqual(output, '6')
# Boolean return value from length_is should not be coerced to a string
@setup({'length_is07': '{% if "X"|length_is:0 %}Length is 0{% else %}Length not 0{% endif %}'})
def test_length_is07(self):
output = render('length_is07', {})
self.assertEqual(output, 'Length not 0')
@setup({'length_is08': '{% if "X"|length_is:1 %}Length is 1{% else %}Length not 1{% endif %}'})
def test_length_is08(self):
output = render('length_is08', {})
self.assertEqual(output, 'Length is 1')
# Invalid uses that should fail silently.
@setup({'length_is09': '{{ var|length_is:"fish" }}'})
def test_length_is09(self):
output = render('length_is09', {'var': 'django'})
self.assertEqual(output, '')
@setup({'length_is10': '{{ int|length_is:"1" }}'})
def test_length_is10(self):
output = render('length_is10', {'int': 7})
self.assertEqual(output, '')
@setup({'length_is11': '{{ none|length_is:"1" }}'})
def test_length_is11(self):
output = render('length_is11', {'none': None})
self.assertEqual(output, '')

View File

@ -0,0 +1,22 @@
from django.test import SimpleTestCase
from django.utils.safestring import mark_safe
from ..utils import render, setup
class LinebreaksTests(SimpleTestCase):
"""
The contents in "linebreaks" are escaped according to the current
autoescape setting.
"""
@setup({'linebreaks01': '{{ a|linebreaks }} {{ b|linebreaks }}'})
def test_linebreaks01(self):
output = render('linebreaks01', {"a": "x&\ny", "b": mark_safe("x&\ny")})
self.assertEqual(output, "<p>x&amp;<br />y</p> <p>x&<br />y</p>")
@setup({'linebreaks02':
'{% autoescape off %}{{ a|linebreaks }} {{ b|linebreaks }}{% endautoescape %}'})
def test_linebreaks02(self):
output = render('linebreaks02', {"a": "x&\ny", "b": mark_safe("x&\ny")})
self.assertEqual(output, "<p>x&<br />y</p> <p>x&<br />y</p>")

View File

@ -0,0 +1,22 @@
from django.test import SimpleTestCase
from django.utils.safestring import mark_safe
from ..utils import render, setup
class LinebreaksbrTests(SimpleTestCase):
"""
The contents in "linebreaksbr" are escaped according to the current
autoescape setting.
"""
@setup({'linebreaksbr01': '{{ a|linebreaksbr }} {{ b|linebreaksbr }}'})
def test_linebreaksbr01(self):
output = render('linebreaksbr01', {"a": "x&\ny", "b": mark_safe("x&\ny")})
self.assertEqual(output, "x&amp;<br />y x&<br />y")
@setup({'linebreaksbr02':
'{% autoescape off %}{{ a|linebreaksbr }} {{ b|linebreaksbr }}{% endautoescape %}'})
def test_linebreaksbr02(self):
output = render('linebreaksbr02', {"a": "x&\ny", "b": mark_safe("x&\ny")})
self.assertEqual(output, "x&<br />y x&<br />y")

View File

@ -0,0 +1,30 @@
from django.test import SimpleTestCase
from django.utils.safestring import mark_safe
from ..utils import render, setup
class LinenumbersTests(SimpleTestCase):
"""
The contents of "linenumbers" is escaped according to the current
autoescape setting.
"""
@setup({'linenumbers01': '{{ a|linenumbers }} {{ b|linenumbers }}'})
def test_linenumbers01(self):
output = render(
'linenumbers01',
{'a': 'one\n<two>\nthree', 'b': mark_safe('one\n&lt;two&gt;\nthree')},
)
self.assertEqual(output, '1. one\n2. &lt;two&gt;\n3. three '
'1. one\n2. &lt;two&gt;\n3. three')
@setup({'linenumbers02':
'{% autoescape off %}{{ a|linenumbers }} {{ b|linenumbers }}{% endautoescape %}'})
def test_linenumbers02(self):
output = render(
'linenumbers02',
{'a': 'one\n<two>\nthree', 'b': mark_safe('one\n&lt;two&gt;\nthree')},
)
self.assertEqual(output, '1. one\n2. <two>\n3. three '
'1. one\n2. &lt;two&gt;\n3. three')

View File

@ -0,0 +1,17 @@
from django.test import SimpleTestCase
from django.utils.safestring import mark_safe
from ..utils import render, setup
class LjustTests(SimpleTestCase):
@setup({'ljust01': '{% autoescape off %}.{{ a|ljust:"5" }}. .{{ b|ljust:"5" }}.{% endautoescape %}'})
def test_ljust01(self):
output = render('ljust01', {"a": "a&b", "b": mark_safe("a&b")})
self.assertEqual(output, ".a&b . .a&b .")
@setup({'ljust02': '.{{ a|ljust:"5" }}. .{{ b|ljust:"5" }}.'})
def test_ljust02(self):
output = render('ljust02', {"a": "a&b", "b": mark_safe("a&b")})
self.assertEqual(output, ".a&amp;b . .a&b .")

View File

@ -0,0 +1,17 @@
from django.test import SimpleTestCase
from django.utils.safestring import mark_safe
from ..utils import render, setup
class LowerTests(SimpleTestCase):
@setup({'lower01': '{% autoescape off %}{{ a|lower }} {{ b|lower }}{% endautoescape %}'})
def test_lower01(self):
output = render('lower01', {"a": "Apple & banana", "b": mark_safe("Apple &amp; banana")})
self.assertEqual(output, "apple & banana apple &amp; banana")
@setup({'lower02': '{{ a|lower }} {{ b|lower }}'})
def test_lower02(self):
output = render('lower02', {"a": "Apple & banana", "b": mark_safe("Apple &amp; banana")})
self.assertEqual(output, "apple &amp; banana apple &amp; banana")

View File

@ -0,0 +1,33 @@
from django.test import SimpleTestCase
from django.test.utils import str_prefix
from django.utils.safestring import mark_safe
from ..utils import render, setup
class MakeListTests(SimpleTestCase):
"""
The make_list filter can destroy existing escaping, so the results are
escaped.
"""
@setup({'make_list01': '{% autoescape off %}{{ a|make_list }}{% endautoescape %}'})
def test_make_list01(self):
output = render('make_list01', {"a": mark_safe("&")})
self.assertEqual(output, str_prefix("[%(_)s'&']"))
@setup({'make_list02': '{{ a|make_list }}'})
def test_make_list02(self):
output = render('make_list02', {"a": mark_safe("&")})
self.assertEqual(output, str_prefix("[%(_)s&#39;&amp;&#39;]"))
@setup({'make_list03':
'{% autoescape off %}{{ a|make_list|stringformat:"s"|safe }}{% endautoescape %}'})
def test_make_list03(self):
output = render('make_list03', {"a": mark_safe("&")})
self.assertEqual(output, str_prefix("[%(_)s'&']"))
@setup({'make_list04': '{{ a|make_list|stringformat:"s"|safe }}'})
def test_make_list04(self):
output = render('make_list04', {"a": mark_safe("&")})
self.assertEqual(output, str_prefix("[%(_)s'&']"))

View File

@ -0,0 +1,35 @@
from django.test import SimpleTestCase
from django.utils.safestring import mark_safe
from ..utils import render, setup
class Phone2numericTests(SimpleTestCase):
@setup({'phone2numeric01': '{{ a|phone2numeric }} {{ b|phone2numeric }}'})
def test_phone2numeric01(self):
output = render(
'phone2numeric01',
{'a': '<1-800-call-me>', 'b': mark_safe('<1-800-call-me>')},
)
self.assertEqual(output, '&lt;1-800-2255-63&gt; <1-800-2255-63>')
@setup({'phone2numeric02':
'{% autoescape off %}{{ a|phone2numeric }} {{ b|phone2numeric }}{% endautoescape %}'})
def test_phone2numeric02(self):
output = render(
'phone2numeric02',
{'a': '<1-800-call-me>', 'b': mark_safe('<1-800-call-me>')},
)
self.assertEqual(output, '<1-800-2255-63> <1-800-2255-63>')
@setup({'phone2numeric03': '{{ a|phone2numeric }}'})
def test_phone2numeric03(self):
output = render(
'phone2numeric03',
{'a': 'How razorback-jumping frogs can level six piqued gymnasts!'},
)
self.assertEqual(
output,
'469 729672225-5867464 37647 226 53835 749 747833 49662787!'
)

View File

@ -0,0 +1,17 @@
from django.test import SimpleTestCase
from django.utils.safestring import mark_safe
from ..utils import render, setup
class RandomTests(SimpleTestCase):
@setup({'random01': '{{ a|random }} {{ b|random }}'})
def test_random01(self):
output = render('random01', {'a': ['a&b', 'a&b'], 'b': [mark_safe('a&b'), mark_safe('a&b')]})
self.assertEqual(output, 'a&amp;b a&b')
@setup({'random02': '{% autoescape off %}{{ a|random }} {{ b|random }}{% endautoescape %}'})
def test_random02(self):
output = render('random02', {'a': ['a&b', 'a&b'], 'b': [mark_safe('a&b'), mark_safe('a&b')]})
self.assertEqual(output, 'a&b a&b')

View File

@ -0,0 +1,37 @@
import warnings
from django.test import SimpleTestCase
from django.utils.deprecation import RemovedInDjango20Warning
from django.utils.safestring import mark_safe
from ..utils import render, setup
class RemovetagsTests(SimpleTestCase):
@setup({'removetags01': '{{ a|removetags:"a b" }} {{ b|removetags:"a b" }}'})
def test_removetags01(self):
with warnings.catch_warnings():
warnings.simplefilter('ignore', RemovedInDjango20Warning)
output = render(
'removetags01',
{
'a': '<a>x</a> <p><b>y</b></p>',
'b': mark_safe('<a>x</a> <p><b>y</b></p>'),
},
)
self.assertEqual(output, 'x &lt;p&gt;y&lt;/p&gt; x <p>y</p>')
@setup({'removetags02':
'{% autoescape off %}{{ a|removetags:"a b" }} {{ b|removetags:"a b" }}{% endautoescape %}'})
def test_removetags02(self):
with warnings.catch_warnings():
warnings.simplefilter('ignore', RemovedInDjango20Warning)
output = render(
'removetags02',
{
'a': '<a>x</a> <p><b>y</b></p>',
'b': mark_safe('<a>x</a> <p><b>y</b></p>'),
},
)
self.assertEqual(output, 'x <p>y</p> x <p>y</p>')

View File

@ -0,0 +1,17 @@
from django.test import SimpleTestCase
from django.utils.safestring import mark_safe
from ..utils import render, setup
class RjustTests(SimpleTestCase):
@setup({'rjust01': '{% autoescape off %}.{{ a|rjust:"5" }}. .{{ b|rjust:"5" }}.{% endautoescape %}'})
def test_rjust01(self):
output = render('rjust01', {"a": "a&b", "b": mark_safe("a&b")})
self.assertEqual(output, ". a&b. . a&b.")
@setup({'rjust02': '.{{ a|rjust:"5" }}. .{{ b|rjust:"5" }}.'})
def test_rjust02(self):
output = render('rjust02', {"a": "a&b", "b": mark_safe("a&b")})
self.assertEqual(output, ". a&amp;b. . a&b.")

View File

@ -0,0 +1,16 @@
from django.test import SimpleTestCase
from ..utils import render, setup
class SafeTests(SimpleTestCase):
@setup({'safe01': '{{ a }} -- {{ a|safe }}'})
def test_safe01(self):
output = render('safe01', {'a': '<b>hello</b>'})
self.assertEqual(output, '&lt;b&gt;hello&lt;/b&gt; -- <b>hello</b>')
@setup({'safe02': '{% autoescape off %}{{ a }} -- {{ a|safe }}{% endautoescape %}'})
def test_safe02(self):
output = render('safe02', {'a': '<b>hello</b>'})
self.assertEqual(output, '<b>hello</b> -- <b>hello</b>')

View File

@ -0,0 +1,17 @@
from django.test import SimpleTestCase
from ..utils import render, setup
class SafeseqTests(SimpleTestCase):
@setup({'safeseq01': '{{ a|join:", " }} -- {{ a|safeseq|join:", " }}'})
def test_safeseq01(self):
output = render('safeseq01', {'a': ['&', '<']})
self.assertEqual(output, '&amp;, &lt; -- &, <')
@setup({'safeseq02':
'{% autoescape off %}{{ a|join:", " }} -- {{ a|safeseq|join:", " }}{% endautoescape %}'})
def test_safeseq02(self):
output = render('safeseq02', {'a': ['&', '<']})
self.assertEqual(output, '&, < -- &, <')

View File

@ -0,0 +1,17 @@
from django.test import SimpleTestCase
from django.utils.safestring import mark_safe
from ..utils import render, setup
class SliceTests(SimpleTestCase):
@setup({'slice01': '{{ a|slice:"1:3" }} {{ b|slice:"1:3" }}'})
def test_slice01(self):
output = render('slice01', {'a': 'a&b', 'b': mark_safe('a&b')})
self.assertEqual(output, '&amp;b &b')
@setup({'slice02': '{% autoescape off %}{{ a|slice:"1:3" }} {{ b|slice:"1:3" }}{% endautoescape %}'})
def test_slice02(self):
output = render('slice02', {'a': 'a&b', 'b': mark_safe('a&b')})
self.assertEqual(output, '&b &b')

View File

@ -0,0 +1,21 @@
from django.test import SimpleTestCase
from django.utils.safestring import mark_safe
from ..utils import render, setup
class SlugifyTests(SimpleTestCase):
"""
Running slugify on a pre-escaped string leads to odd behavior,
but the result is still safe.
"""
@setup({'slugify01': '{% autoescape off %}{{ a|slugify }} {{ b|slugify }}{% endautoescape %}'})
def test_slugify01(self):
output = render('slugify01', {'a': 'a & b', 'b': mark_safe('a &amp; b')})
self.assertEqual(output, 'a-b a-amp-b')
@setup({'slugify02': '{{ a|slugify }} {{ b|slugify }}'})
def test_slugify02(self):
output = render('slugify02', {'a': 'a & b', 'b': mark_safe('a &amp; b')})
self.assertEqual(output, 'a-b a-amp-b')

View File

@ -0,0 +1,22 @@
from django.test import SimpleTestCase
from django.utils.safestring import mark_safe
from ..utils import render, setup
class StringformatTests(SimpleTestCase):
"""
Notice that escaping is applied *after* any filters, so the string
formatting here only needs to deal with pre-escaped characters.
"""
@setup({'stringformat01':
'{% autoescape off %}.{{ a|stringformat:"5s" }}. .{{ b|stringformat:"5s" }}.{% endautoescape %}'})
def test_stringformat01(self):
output = render('stringformat01', {'a': 'a<b', 'b': mark_safe('a<b')})
self.assertEqual(output, '. a<b. . a<b.')
@setup({'stringformat02': '.{{ a|stringformat:"5s" }}. .{{ b|stringformat:"5s" }}.'})
def test_stringformat02(self):
output = render('stringformat02', {'a': 'a<b', 'b': mark_safe('a<b')})
self.assertEqual(output, '. a&lt;b. . a<b.')

View File

@ -0,0 +1,29 @@
from django.test import SimpleTestCase
from django.utils.safestring import mark_safe
from ..utils import render, setup
class StriptagsTests(SimpleTestCase):
@setup({'striptags01': '{{ a|striptags }} {{ b|striptags }}'})
def test_striptags01(self):
output = render(
'striptags01',
{
'a': '<a>x</a> <p><b>y</b></p>',
'b': mark_safe('<a>x</a> <p><b>y</b></p>'),
},
)
self.assertEqual(output, 'x y x y')
@setup({'striptags02': '{% autoescape off %}{{ a|striptags }} {{ b|striptags }}{% endautoescape %}'})
def test_striptags02(self):
output = render(
'striptags02',
{
'a': '<a>x</a> <p><b>y</b></p>',
'b': mark_safe('<a>x</a> <p><b>y</b></p>'),
},
)
self.assertEqual(output, 'x y x y')

View File

@ -0,0 +1,42 @@
from datetime import time
from django.utils import timezone
from .timezone_utils import TimezoneTestCase
from ..utils import render, setup
class TimeTests(TimezoneTestCase):
"""
#20693: Timezone support for the time template filter
"""
@setup({'time01': '{{ dt|time:"e:O:T:Z" }}'})
def test_time01(self):
output = render('time01', {'dt': self.now_tz_i})
self.assertEqual(output, '+0315:+0315:+0315:11700')
@setup({'time02': '{{ dt|time:"e:T" }}'})
def test_time02(self):
output = render('time02', {'dt': self.now})
self.assertEqual(output, ':' + self.now_tz.tzinfo.tzname(self.now_tz))
@setup({'time03': '{{ t|time:"P:e:O:T:Z" }}'})
def test_time03(self):
output = render('time03', {'t': time(4, 0, tzinfo=timezone.get_fixed_timezone(30))})
self.assertEqual(output, '4 a.m.::::')
@setup({'time04': '{{ t|time:"P:e:O:T:Z" }}'})
def test_time04(self):
output = render('time04', {'t': time(4, 0)})
self.assertEqual(output, '4 a.m.::::')
@setup({'time05': '{{ d|time:"P:e:O:T:Z" }}'})
def test_time05(self):
output = render('time05', {'d': self.today})
self.assertEqual(output, '')
@setup({'time06': '{{ obj|time:"P:e:O:T:Z" }}'})
def test_time06(self):
output = render('time06', {'obj': 'non-datetime-value'})
self.assertEqual(output, '')

View File

@ -0,0 +1,118 @@
from __future__ import unicode_literals
from datetime import datetime, timedelta
from django.test.utils import requires_tz_support
from .timezone_utils import TimezoneTestCase
from ..utils import render, setup
class TimesinceTests(TimezoneTestCase):
"""
#20246 - \xa0 in output avoids line-breaks between value and unit
"""
# Default compare with datetime.now()
@setup({'timesince01': '{{ a|timesince }}'})
def test_timesince01(self):
output = render('timesince01', {'a': datetime.now() + timedelta(minutes=-1, seconds=-10)})
self.assertEqual(output, '1\xa0minute')
@setup({'timesince02': '{{ a|timesince }}'})
def test_timesince02(self):
output = render('timesince02', {'a': datetime.now() - timedelta(days=1, minutes=1)})
self.assertEqual(output, '1\xa0day')
@setup({'timesince03': '{{ a|timesince }}'})
def test_timesince03(self):
output = render('timesince03', {'a': datetime.now() - timedelta(hours=1, minutes=25, seconds=10)})
self.assertEqual(output, '1\xa0hour, 25\xa0minutes')
# Compare to a given parameter
@setup({'timesince04': '{{ a|timesince:b }}'})
def test_timesince04(self):
output = render(
'timesince04',
{'a': self.now - timedelta(days=2), 'b': self.now - timedelta(days=1)},
)
self.assertEqual(output, '1\xa0day')
@setup({'timesince05': '{{ a|timesince:b }}'})
def test_timesince05(self):
output = render(
'timesince05',
{'a': self.now - timedelta(days=2, minutes=1), 'b': self.now - timedelta(days=2)},
)
self.assertEqual(output, '1\xa0minute')
# Check that timezone is respected
@setup({'timesince06': '{{ a|timesince:b }}'})
def test_timesince06(self):
output = render('timesince06', {'a': self.now_tz - timedelta(hours=8), 'b': self.now_tz})
self.assertEqual(output, '8\xa0hours')
# Tests for #7443
@setup({'timesince07': '{{ earlier|timesince }}'})
def test_timesince07(self):
output = render('timesince07', {'earlier': self.now - timedelta(days=7)})
self.assertEqual(output, '1\xa0week')
@setup({'timesince08': '{{ earlier|timesince:now }}'})
def test_timesince08(self):
output = render('timesince08', {'now': self.now, 'earlier': self.now - timedelta(days=7)})
self.assertEqual(output, '1\xa0week')
@setup({'timesince09': '{{ later|timesince }}'})
def test_timesince09(self):
output = render('timesince09', {'later': self.now + timedelta(days=7)})
self.assertEqual(output, '0\xa0minutes')
@setup({'timesince10': '{{ later|timesince:now }}'})
def test_timesince10(self):
output = render('timesince10', {'now': self.now, 'later': self.now + timedelta(days=7)})
self.assertEqual(output, '0\xa0minutes')
# Ensures that differing timezones are calculated correctly.
@setup({'timesince11': '{{ a|timesince }}'})
def test_timesince11(self):
output = render('timesince11', {'a': self.now})
self.assertEqual(output, '0\xa0minutes')
@requires_tz_support
@setup({'timesince12': '{{ a|timesince }}'})
def test_timesince12(self):
output = render('timesince12', {'a': self.now_tz})
self.assertEqual(output, '0\xa0minutes')
@requires_tz_support
@setup({'timesince13': '{{ a|timesince }}'})
def test_timesince13(self):
output = render('timesince13', {'a': self.now_tz_i})
self.assertEqual(output, '0\xa0minutes')
@setup({'timesince14': '{{ a|timesince:b }}'})
def test_timesince14(self):
output = render('timesince14', {'a': self.now_tz, 'b': self.now_tz_i})
self.assertEqual(output, '0\xa0minutes')
@setup({'timesince15': '{{ a|timesince:b }}'})
def test_timesince15(self):
output = render('timesince15', {'a': self.now, 'b': self.now_tz_i})
self.assertEqual(output, '')
@setup({'timesince16': '{{ a|timesince:b }}'})
def test_timesince16(self):
output = render('timesince16', {'a': self.now_tz_i, 'b': self.now})
self.assertEqual(output, '')
# Tests for #9065 (two date objects).
@setup({'timesince17': '{{ a|timesince:b }}'})
def test_timesince17(self):
output = render('timesince17', {'a': self.today, 'b': self.today})
self.assertEqual(output, '0\xa0minutes')
@setup({'timesince18': '{{ a|timesince:b }}'})
def test_timesince18(self):
output = render('timesince18', {'a': self.today, 'b': self.today + timedelta(hours=24)})
self.assertEqual(output, '1\xa0day')

View File

@ -0,0 +1,94 @@
from __future__ import unicode_literals
from datetime import datetime, timedelta
from django.test.utils import requires_tz_support
from .timezone_utils import TimezoneTestCase
from ..utils import render, setup
class TimeuntilTests(TimezoneTestCase):
# Default compare with datetime.now()
@setup({'timeuntil01': '{{ a|timeuntil }}'})
def test_timeuntil01(self):
output = render('timeuntil01', {'a': datetime.now() + timedelta(minutes=2, seconds=10)})
self.assertEqual(output, '2\xa0minutes')
@setup({'timeuntil02': '{{ a|timeuntil }}'})
def test_timeuntil02(self):
output = render('timeuntil02', {'a': (datetime.now() + timedelta(days=1, seconds=10))})
self.assertEqual(output, '1\xa0day')
@setup({'timeuntil03': '{{ a|timeuntil }}'})
def test_timeuntil03(self):
output = render('timeuntil03', {'a': (datetime.now() + timedelta(hours=8, minutes=10, seconds=10))})
self.assertEqual(output, '8\xa0hours, 10\xa0minutes')
# Compare to a given parameter
@setup({'timeuntil04': '{{ a|timeuntil:b }}'})
def test_timeuntil04(self):
output = render(
'timeuntil04',
{'a': self.now - timedelta(days=1), 'b': self.now - timedelta(days=2)},
)
self.assertEqual(output, '1\xa0day')
@setup({'timeuntil05': '{{ a|timeuntil:b }}'})
def test_timeuntil05(self):
output = render(
'timeuntil05',
{'a': self.now - timedelta(days=2), 'b': self.now - timedelta(days=2, minutes=1)},
)
self.assertEqual(output, '1\xa0minute')
# Regression for #7443
@setup({'timeuntil06': '{{ earlier|timeuntil }}'})
def test_timeuntil06(self):
output = render('timeuntil06', {'earlier': self.now - timedelta(days=7)})
self.assertEqual(output, '0\xa0minutes')
@setup({'timeuntil07': '{{ earlier|timeuntil:now }}'})
def test_timeuntil07(self):
output = render('timeuntil07', {'now': self.now, 'earlier': self.now - timedelta(days=7)})
self.assertEqual(output, '0\xa0minutes')
@setup({'timeuntil08': '{{ later|timeuntil }}'})
def test_timeuntil08(self):
output = render('timeuntil08', {'later': self.now + timedelta(days=7, hours=1)})
self.assertEqual(output, '1\xa0week')
@setup({'timeuntil09': '{{ later|timeuntil:now }}'})
def test_timeuntil09(self):
output = render('timeuntil09', {'now': self.now, 'later': self.now + timedelta(days=7)})
self.assertEqual(output, '1\xa0week')
# Ensures that differing timezones are calculated correctly.
@requires_tz_support
@setup({'timeuntil10': '{{ a|timeuntil }}'})
def test_timeuntil10(self):
output = render('timeuntil10', {'a': self.now_tz})
self.assertEqual(output, '0\xa0minutes')
@requires_tz_support
@setup({'timeuntil11': '{{ a|timeuntil }}'})
def test_timeuntil11(self):
output = render('timeuntil11', {'a': self.now_tz_i})
self.assertEqual(output, '0\xa0minutes')
@setup({'timeuntil12': '{{ a|timeuntil:b }}'})
def test_timeuntil12(self):
output = render('timeuntil12', {'a': self.now_tz_i, 'b': self.now_tz})
self.assertEqual(output, '0\xa0minutes')
# Regression for #9065 (two date objects).
@setup({'timeuntil13': '{{ a|timeuntil:b }}'})
def test_timeuntil13(self):
output = render('timeuntil13', {'a': self.today, 'b': self.today})
self.assertEqual(output, '0\xa0minutes')
@setup({'timeuntil14': '{{ a|timeuntil:b }}'})
def test_timeuntil14(self):
output = render('timeuntil14', {'a': self.today, 'b': self.today - timedelta(hours=24)})
self.assertEqual(output, '1\xa0day')

View File

@ -0,0 +1,16 @@
from django.test import SimpleTestCase
from ..utils import render, setup
class TitleTests(SimpleTestCase):
@setup({'title1': '{{ a|title }}'})
def test_title1(self):
output = render('title1', {'a': 'JOE\'S CRAB SHACK'})
self.assertEqual(output, 'Joe&#39;s Crab Shack')
@setup({'title2': '{{ a|title }}'})
def test_title2(self):
output = render('title2', {'a': '555 WEST 53RD STREET'})
self.assertEqual(output, '555 West 53rd Street')

View File

@ -0,0 +1,16 @@
from django.test import SimpleTestCase
from ..utils import render, setup
class TruncatecharsTests(SimpleTestCase):
@setup({'truncatechars01': '{{ a|truncatechars:5 }}'})
def test_truncatechars01(self):
output = render('truncatechars01', {'a': 'Testing, testing'})
self.assertEqual(output, 'Te...')
@setup({'truncatechars02': '{{ a|truncatechars:7 }}'})
def test_truncatechars02(self):
output = render('truncatechars02', {'a': 'Testing'})
self.assertEqual(output, 'Testing')

View File

@ -0,0 +1,18 @@
from django.test import SimpleTestCase
from django.utils.safestring import mark_safe
from ..utils import render, setup
class TruncatewordsTests(SimpleTestCase):
@setup({'truncatewords01':
'{% autoescape off %}{{ a|truncatewords:"2" }} {{ b|truncatewords:"2"}}{% endautoescape %}'})
def test_truncatewords01(self):
output = render('truncatewords01', {'a': 'alpha & bravo', 'b': mark_safe('alpha &amp; bravo')})
self.assertEqual(output, 'alpha & ... alpha &amp; ...')
@setup({'truncatewords02': '{{ a|truncatewords:"2" }} {{ b|truncatewords:"2"}}'})
def test_truncatewords02(self):
output = render('truncatewords02', {'a': 'alpha & bravo', 'b': mark_safe('alpha &amp; bravo')})
self.assertEqual(output, 'alpha &amp; ... alpha &amp; ...')

View File

@ -0,0 +1,75 @@
import warnings
from django.test import SimpleTestCase
from django.utils.deprecation import RemovedInDjango20Warning
from django.utils.safestring import mark_safe
from ..utils import render, setup
class UnorderedListTests(SimpleTestCase):
@setup({'unordered_list01': '{{ a|unordered_list }}'})
def test_unordered_list01(self):
output = render('unordered_list01', {'a': ['x>', ['<y']]})
self.assertEqual(output, '\t<li>x&gt;\n\t<ul>\n\t\t<li>&lt;y</li>\n\t</ul>\n\t</li>')
@setup({'unordered_list02': '{% autoescape off %}{{ a|unordered_list }}{% endautoescape %}'})
def test_unordered_list02(self):
with warnings.catch_warnings():
warnings.simplefilter('ignore', RemovedInDjango20Warning)
output = render('unordered_list02', {'a': ['x>', ['<y']]})
self.assertEqual(output, '\t<li>x>\n\t<ul>\n\t\t<li><y</li>\n\t</ul>\n\t</li>')
@setup({'unordered_list03': '{{ a|unordered_list }}'})
def test_unordered_list03(self):
output = render('unordered_list03', {'a': ['x>', [mark_safe('<y')]]})
self.assertEqual(output, '\t<li>x&gt;\n\t<ul>\n\t\t<li><y</li>\n\t</ul>\n\t</li>')
@setup({'unordered_list04': '{% autoescape off %}{{ a|unordered_list }}{% endautoescape %}'})
def test_unordered_list04(self):
output = render('unordered_list04', {'a': ['x>', [mark_safe('<y')]]})
self.assertEqual(output, '\t<li>x>\n\t<ul>\n\t\t<li><y</li>\n\t</ul>\n\t</li>')
@setup({'unordered_list05': '{% autoescape off %}{{ a|unordered_list }}{% endautoescape %}'})
def test_unordered_list05(self):
output = render('unordered_list05', {'a': ['x>', ['<y']]})
self.assertEqual(output, '\t<li>x>\n\t<ul>\n\t\t<li><y</li>\n\t</ul>\n\t</li>')
class DeprecatedUnorderedListSyntaxTests(SimpleTestCase):
@setup({'unordered_list01': '{{ a|unordered_list }}'})
def test_unordered_list01(self):
with warnings.catch_warnings():
warnings.simplefilter('ignore', RemovedInDjango20Warning)
output = render('unordered_list01', {'a': ['x>', [['<y', []]]]})
self.assertEqual(output, '\t<li>x&gt;\n\t<ul>\n\t\t<li>&lt;y</li>\n\t</ul>\n\t</li>')
@setup({'unordered_list02': '{% autoescape off %}{{ a|unordered_list }}{% endautoescape %}'})
def test_unordered_list02(self):
with warnings.catch_warnings():
warnings.simplefilter('ignore', RemovedInDjango20Warning)
output = render('unordered_list02', {'a': ['x>', [['<y', []]]]})
self.assertEqual(output, '\t<li>x>\n\t<ul>\n\t\t<li><y</li>\n\t</ul>\n\t</li>')
@setup({'unordered_list03': '{{ a|unordered_list }}'})
def test_unordered_list03(self):
with warnings.catch_warnings():
warnings.simplefilter('ignore', RemovedInDjango20Warning)
output = render('unordered_list03', {'a': ['x>', [[mark_safe('<y'), []]]]})
self.assertEqual(output, '\t<li>x&gt;\n\t<ul>\n\t\t<li><y</li>\n\t</ul>\n\t</li>')
@setup({'unordered_list04': '{% autoescape off %}{{ a|unordered_list }}{% endautoescape %}'})
def test_unordered_list04(self):
with warnings.catch_warnings():
warnings.simplefilter('ignore', RemovedInDjango20Warning)
output = render('unordered_list04', {'a': ['x>', [[mark_safe('<y'), []]]]})
self.assertEqual(output, '\t<li>x>\n\t<ul>\n\t\t<li><y</li>\n\t</ul>\n\t</li>')
@setup({'unordered_list05': '{% autoescape off %}{{ a|unordered_list }}{% endautoescape %}'})
def test_unordered_list05(self):
with warnings.catch_warnings():
warnings.simplefilter('ignore', RemovedInDjango20Warning)
output = render('unordered_list05', {'a': ['x>', [['<y', []]]]})
self.assertEqual(output, '\t<li>x>\n\t<ul>\n\t\t<li><y</li>\n\t</ul>\n\t</li>')

View File

@ -0,0 +1,21 @@
from django.test import SimpleTestCase
from django.utils.safestring import mark_safe
from ..utils import render, setup
class UpperTests(SimpleTestCase):
"""
The "upper" filter messes up entities (which are case-sensitive),
so it's not safe for non-escaping purposes.
"""
@setup({'upper01': '{% autoescape off %}{{ a|upper }} {{ b|upper }}{% endautoescape %}'})
def test_upper01(self):
output = render('upper01', {'a': 'a & b', 'b': mark_safe('a &amp; b')})
self.assertEqual(output, 'A & B A &AMP; B')
@setup({'upper02': '{{ a|upper }} {{ b|upper }}'})
def test_upper02(self):
output = render('upper02', {'a': 'a & b', 'b': mark_safe('a &amp; b')})
self.assertEqual(output, 'A &amp; B A &amp;AMP; B')

View File

@ -0,0 +1,16 @@
from django.test import SimpleTestCase
from ..utils import render, setup
class UrlencodeTests(SimpleTestCase):
@setup({'urlencode01': '{{ url|urlencode }}'})
def test_urlencode01(self):
output = render('urlencode01', {'url': '/test&"/me?/'})
self.assertEqual(output, '/test%26%22/me%3F/')
@setup({'urlencode02': '/test/{{ urlbit|urlencode:"" }}/'})
def test_urlencode02(self):
output = render('urlencode02', {'urlbit': 'escape/slash'})
self.assertEqual(output, '/test/escape%2Fslash/')

View File

@ -0,0 +1,70 @@
from django.test import SimpleTestCase
from django.utils.safestring import mark_safe
from ..utils import render, setup
class UrlizeTests(SimpleTestCase):
@setup({'urlize01': '{% autoescape off %}{{ a|urlize }} {{ b|urlize }}{% endautoescape %}'})
def test_urlize01(self):
output = render(
'urlize01',
{'a': 'http://example.com/?x=&y=', 'b': mark_safe('http://example.com?x=&amp;y=&lt;2&gt;')},
)
self.assertEqual(
output,
'<a href="http://example.com/?x=&y=" rel="nofollow">http://example.com/?x=&y=</a> '
'<a href="http://example.com?x=&y=%3C2%3E" rel="nofollow">http://example.com?x=&amp;y=&lt;2&gt;</a>'
)
@setup({'urlize02': '{{ a|urlize }} {{ b|urlize }}'})
def test_urlize02(self):
output = render(
'urlize02',
{'a': "http://example.com/?x=&y=", 'b': mark_safe("http://example.com?x=&amp;y=")},
)
self.assertEqual(
output,
'<a href="http://example.com/?x=&y=" rel="nofollow">http://example.com/?x=&amp;y=</a> '
'<a href="http://example.com?x=&y=" rel="nofollow">http://example.com?x=&amp;y=</a>'
)
@setup({'urlize03': '{% autoescape off %}{{ a|urlize }}{% endautoescape %}'})
def test_urlize03(self):
output = render('urlize03', {'a': mark_safe("a &amp; b")})
self.assertEqual(output, 'a &amp; b')
@setup({'urlize04': '{{ a|urlize }}'})
def test_urlize04(self):
output = render('urlize04', {'a': mark_safe("a &amp; b")})
self.assertEqual(output, 'a &amp; b')
# This will lead to a nonsense result, but at least it won't be
# exploitable for XSS purposes when auto-escaping is on.
@setup({'urlize05': '{% autoescape off %}{{ a|urlize }}{% endautoescape %}'})
def test_urlize05(self):
output = render('urlize05', {'a': "<script>alert('foo')</script>"})
self.assertEqual(output, "<script>alert('foo')</script>")
@setup({'urlize06': '{{ a|urlize }}'})
def test_urlize06(self):
output = render('urlize06', {'a': "<script>alert('foo')</script>"})
self.assertEqual(output, '&lt;script&gt;alert(&#39;foo&#39;)&lt;/script&gt;')
# mailto: testing for urlize
@setup({'urlize07': '{{ a|urlize }}'})
def test_urlize07(self):
output = render('urlize07', {'a': "Email me at me@example.com"})
self.assertEqual(
output,
'Email me at <a href="mailto:me@example.com">me@example.com</a>',
)
@setup({'urlize08': '{{ a|urlize }}'})
def test_urlize08(self):
output = render('urlize08', {'a': "Email me at <me@example.com>"})
self.assertEqual(
output,
'Email me at &lt;<a href="mailto:me@example.com">me@example.com</a>&gt;',
)

View File

@ -0,0 +1,38 @@
from django.test import SimpleTestCase
from django.utils.safestring import mark_safe
from ..utils import render, setup
class UrlizetruncTests(SimpleTestCase):
@setup({'urlizetrunc01':
'{% autoescape off %}{{ a|urlizetrunc:"8" }} {{ b|urlizetrunc:"8" }}{% endautoescape %}'})
def test_urlizetrunc01(self):
output = render(
'urlizetrunc01',
{
'a': '"Unsafe" http://example.com/x=&y=',
'b': mark_safe('&quot;Safe&quot; http://example.com?x=&amp;y='),
},
)
self.assertEqual(
output,
'"Unsafe" <a href="http://example.com/x=&y=" rel="nofollow">http:...</a> '
'&quot;Safe&quot; <a href="http://example.com?x=&y=" rel="nofollow">http:...</a>'
)
@setup({'urlizetrunc02': '{{ a|urlizetrunc:"8" }} {{ b|urlizetrunc:"8" }}'})
def test_urlizetrunc02(self):
output = render(
'urlizetrunc02',
{
'a': '"Unsafe" http://example.com/x=&y=',
'b': mark_safe('&quot;Safe&quot; http://example.com?x=&amp;y='),
},
)
self.assertEqual(
output,
'&quot;Unsafe&quot; <a href="http://example.com/x=&y=" rel="nofollow">http:...</a> '
'&quot;Safe&quot; <a href="http://example.com?x=&y=" rel="nofollow">http:...</a>'
)

View File

@ -0,0 +1,17 @@
from django.test import SimpleTestCase
from django.utils.safestring import mark_safe
from ..utils import render, setup
class WordcountTests(SimpleTestCase):
@setup({'wordcount01': '{% autoescape off %}{{ a|wordcount }} {{ b|wordcount }}{% endautoescape %}'})
def test_wordcount01(self):
output = render('wordcount01', {'a': 'a & b', 'b': mark_safe('a &amp; b')})
self.assertEqual(output, '3 3')
@setup({'wordcount02': '{{ a|wordcount }} {{ b|wordcount }}'})
def test_wordcount02(self):
output = render('wordcount02', {'a': 'a & b', 'b': mark_safe('a &amp; b')})
self.assertEqual(output, '3 3')

View File

@ -0,0 +1,18 @@
from django.test import SimpleTestCase
from django.utils.safestring import mark_safe
from ..utils import render, setup
class WordwrapTests(SimpleTestCase):
@setup({'wordwrap01':
'{% autoescape off %}{{ a|wordwrap:"3" }} {{ b|wordwrap:"3" }}{% endautoescape %}'})
def test_wordwrap01(self):
output = render('wordwrap01', {'a': 'a & b', 'b': mark_safe('a & b')})
self.assertEqual(output, 'a &\nb a &\nb')
@setup({'wordwrap02': '{{ a|wordwrap:"3" }} {{ b|wordwrap:"3" }}'})
def test_wordwrap02(self):
output = render('wordwrap02', {'a': 'a & b', 'b': mark_safe('a & b')})
self.assertEqual(output, 'a &amp;\nb a &\nb')

View File

@ -0,0 +1,17 @@
from datetime import date, datetime
from django.test import SimpleTestCase
from django.utils import timezone
class TimezoneTestCase(SimpleTestCase):
def setUp(self):
self.now = datetime.now()
self.now_tz = timezone.make_aware(
self.now, timezone.get_default_timezone(),
)
self.now_tz_i = timezone.localtime(
self.now_tz, timezone.get_fixed_timezone(195),
)
self.today = date.today()

View File

@ -1,387 +0,0 @@
# -*- coding: utf-8 -*-
"""
Tests for template filters (as opposed to template tags).
The tests are hidden inside a function so that things like timestamps and
timezones are only evaluated at the moment of execution and will therefore be
consistent.
"""
from __future__ import unicode_literals
from datetime import date, datetime, time, timedelta
from django.test.utils import str_prefix, TZ_SUPPORT
from django.utils.safestring import mark_safe
from django.utils import timezone
from .syntax_tests.utils import SafeClass, UnsafeClass
# RESULT SYNTAX --
# 'template_name': ('template contents', 'context dict',
# 'expected string output' or Exception class)
def get_filter_tests():
now = datetime.now()
now_tz = timezone.make_aware(now, timezone.get_default_timezone())
now_tz_i = timezone.localtime(now_tz, timezone.get_fixed_timezone(195))
today = date.today()
# NOTE: \xa0 avoids wrapping between value and unit
return {
# Default compare with datetime.now()
'filter-timesince01': ('{{ a|timesince }}', {'a': datetime.now() + timedelta(minutes=-1, seconds=-10)}, '1\xa0minute'),
'filter-timesince02': ('{{ a|timesince }}', {'a': datetime.now() - timedelta(days=1, minutes=1)}, '1\xa0day'),
'filter-timesince03': ('{{ a|timesince }}', {'a': datetime.now() - timedelta(hours=1, minutes=25, seconds=10)}, '1\xa0hour, 25\xa0minutes'),
# Compare to a given parameter
'filter-timesince04': ('{{ a|timesince:b }}', {'a': now - timedelta(days=2), 'b': now - timedelta(days=1)}, '1\xa0day'),
'filter-timesince05': ('{{ a|timesince:b }}', {'a': now - timedelta(days=2, minutes=1), 'b': now - timedelta(days=2)}, '1\xa0minute'),
# Check that timezone is respected
'filter-timesince06': ('{{ a|timesince:b }}', {'a': now_tz - timedelta(hours=8), 'b': now_tz}, '8\xa0hours'),
# Regression for #7443
'filter-timesince07': ('{{ earlier|timesince }}', {'earlier': now - timedelta(days=7)}, '1\xa0week'),
'filter-timesince08': ('{{ earlier|timesince:now }}', {'now': now, 'earlier': now - timedelta(days=7)}, '1\xa0week'),
'filter-timesince09': ('{{ later|timesince }}', {'later': now + timedelta(days=7)}, '0\xa0minutes'),
'filter-timesince10': ('{{ later|timesince:now }}', {'now': now, 'later': now + timedelta(days=7)}, '0\xa0minutes'),
# Ensures that differing timezones are calculated correctly
# Tests trying to compare a timezone-aware 'now' to now aren't supported on no-tz-support systems (e.g Windows).
'filter-timesince11': ('{{ a|timesince }}', {'a': now}, '0\xa0minutes'),
'filter-timesince12': ('{{ a|timesince }}', {'a': now_tz}, '0\xa0minutes') if TZ_SUPPORT else ('', {}, ''),
'filter-timesince13': ('{{ a|timesince }}', {'a': now_tz_i}, '0\xa0minutes') if TZ_SUPPORT else ('', {}, ''),
'filter-timesince14': ('{{ a|timesince:b }}', {'a': now_tz, 'b': now_tz_i}, '0\xa0minutes'),
'filter-timesince15': ('{{ a|timesince:b }}', {'a': now, 'b': now_tz_i}, ''),
'filter-timesince16': ('{{ a|timesince:b }}', {'a': now_tz_i, 'b': now}, ''),
# Regression for #9065 (two date objects).
'filter-timesince17': ('{{ a|timesince:b }}', {'a': today, 'b': today}, '0\xa0minutes'),
'filter-timesince18': ('{{ a|timesince:b }}', {'a': today, 'b': today + timedelta(hours=24)}, '1\xa0day'),
# Default compare with datetime.now()
'filter-timeuntil01': ('{{ a|timeuntil }}', {'a': datetime.now() + timedelta(minutes=2, seconds=10)}, '2\xa0minutes'),
'filter-timeuntil02': ('{{ a|timeuntil }}', {'a': (datetime.now() + timedelta(days=1, seconds=10))}, '1\xa0day'),
'filter-timeuntil03': ('{{ a|timeuntil }}', {'a': (datetime.now() + timedelta(hours=8, minutes=10, seconds=10))}, '8\xa0hours, 10\xa0minutes'),
# Compare to a given parameter
'filter-timeuntil04': ('{{ a|timeuntil:b }}', {'a': now - timedelta(days=1), 'b': now - timedelta(days=2)}, '1\xa0day'),
'filter-timeuntil05': ('{{ a|timeuntil:b }}', {'a': now - timedelta(days=2), 'b': now - timedelta(days=2, minutes=1)}, '1\xa0minute'),
# Regression for #7443
'filter-timeuntil06': ('{{ earlier|timeuntil }}', {'earlier': now - timedelta(days=7)}, '0\xa0minutes'),
'filter-timeuntil07': ('{{ earlier|timeuntil:now }}', {'now': now, 'earlier': now - timedelta(days=7)}, '0\xa0minutes'),
'filter-timeuntil08': ('{{ later|timeuntil }}', {'later': now + timedelta(days=7, hours=1)}, '1\xa0week'),
'filter-timeuntil09': ('{{ later|timeuntil:now }}', {'now': now, 'later': now + timedelta(days=7)}, '1\xa0week'),
# Ensures that differing timezones are calculated correctly
# Tests trying to compare a timezone-aware 'now' to now aren't supported on no-tz-support systems (e.g Windows).
'filter-timeuntil10': ('{{ a|timeuntil }}', {'a': now_tz}, '0\xa0minutes') if TZ_SUPPORT else ('', {}, ''),
'filter-timeuntil11': ('{{ a|timeuntil }}', {'a': now_tz_i}, '0\xa0minutes') if TZ_SUPPORT else ('', {}, ''),
'filter-timeuntil12': ('{{ a|timeuntil:b }}', {'a': now_tz_i, 'b': now_tz}, '0\xa0minutes'),
# Regression for #9065 (two date objects).
'filter-timeuntil13': ('{{ a|timeuntil:b }}', {'a': today, 'b': today}, '0\xa0minutes'),
'filter-timeuntil14': ('{{ a|timeuntil:b }}', {'a': today, 'b': today - timedelta(hours=24)}, '1\xa0day'),
'filter-addslash01': ("{% autoescape off %}{{ a|addslashes }} {{ b|addslashes }}{% endautoescape %}", {"a": "<a>'", "b": mark_safe("<a>'")}, r"<a>\' <a>\'"),
'filter-addslash02': ("{{ a|addslashes }} {{ b|addslashes }}", {"a": "<a>'", "b": mark_safe("<a>'")}, r"&lt;a&gt;\&#39; <a>\'"),
'filter-capfirst01': ("{% autoescape off %}{{ a|capfirst }} {{ b|capfirst }}{% endautoescape %}", {"a": "fred>", "b": mark_safe("fred&gt;")}, "Fred> Fred&gt;"),
'filter-capfirst02': ("{{ a|capfirst }} {{ b|capfirst }}", {"a": "fred>", "b": mark_safe("fred&gt;")}, "Fred&gt; Fred&gt;"),
'filter-floatformat01': ("{% autoescape off %}{{ a|floatformat }} {{ b|floatformat }}{% endautoescape %}", {"a": "1.42", "b": mark_safe("1.42")}, "1.4 1.4"),
'filter-floatformat02': ("{{ a|floatformat }} {{ b|floatformat }}", {"a": "1.42", "b": mark_safe("1.42")}, "1.4 1.4"),
# The contents of "linenumbers" is escaped according to the current
# autoescape setting.
'filter-linenumbers01': ("{{ a|linenumbers }} {{ b|linenumbers }}", {"a": "one\n<two>\nthree", "b": mark_safe("one\n&lt;two&gt;\nthree")}, "1. one\n2. &lt;two&gt;\n3. three 1. one\n2. &lt;two&gt;\n3. three"),
'filter-linenumbers02': ("{% autoescape off %}{{ a|linenumbers }} {{ b|linenumbers }}{% endautoescape %}", {"a": "one\n<two>\nthree", "b": mark_safe("one\n&lt;two&gt;\nthree")}, "1. one\n2. <two>\n3. three 1. one\n2. &lt;two&gt;\n3. three"),
'filter-lower01': ("{% autoescape off %}{{ a|lower }} {{ b|lower }}{% endautoescape %}", {"a": "Apple & banana", "b": mark_safe("Apple &amp; banana")}, "apple & banana apple &amp; banana"),
'filter-lower02': ("{{ a|lower }} {{ b|lower }}", {"a": "Apple & banana", "b": mark_safe("Apple &amp; banana")}, "apple &amp; banana apple &amp; banana"),
# The make_list filter can destroy existing escaping, so the results are
# escaped.
'filter-make_list01': ("{% autoescape off %}{{ a|make_list }}{% endautoescape %}", {"a": mark_safe("&")}, str_prefix("[%(_)s'&']")),
'filter-make_list02': ("{{ a|make_list }}", {"a": mark_safe("&")}, str_prefix("[%(_)s&#39;&amp;&#39;]")),
'filter-make_list03': ('{% autoescape off %}{{ a|make_list|stringformat:"s"|safe }}{% endautoescape %}', {"a": mark_safe("&")}, str_prefix("[%(_)s'&']")),
'filter-make_list04': ('{{ a|make_list|stringformat:"s"|safe }}', {"a": mark_safe("&")}, str_prefix("[%(_)s'&']")),
# Running slugify on a pre-escaped string leads to odd behavior,
# but the result is still safe.
'filter-slugify01': ("{% autoescape off %}{{ a|slugify }} {{ b|slugify }}{% endautoescape %}", {"a": "a & b", "b": mark_safe("a &amp; b")}, "a-b a-amp-b"),
'filter-slugify02': ("{{ a|slugify }} {{ b|slugify }}", {"a": "a & b", "b": mark_safe("a &amp; b")}, "a-b a-amp-b"),
# Notice that escaping is applied *after* any filters, so the string
# formatting here only needs to deal with pre-escaped characters.
'filter-stringformat01': ('{% autoescape off %}.{{ a|stringformat:"5s" }}. .{{ b|stringformat:"5s" }}.{% endautoescape %}',
{"a": "a<b", "b": mark_safe("a<b")}, ". a<b. . a<b."),
'filter-stringformat02': ('.{{ a|stringformat:"5s" }}. .{{ b|stringformat:"5s" }}.', {"a": "a<b", "b": mark_safe("a<b")},
". a&lt;b. . a<b."),
# Test the title filter
'filter-title1': ('{{ a|title }}', {'a': 'JOE\'S CRAB SHACK'}, 'Joe&#39;s Crab Shack'),
'filter-title2': ('{{ a|title }}', {'a': '555 WEST 53RD STREET'}, '555 West 53rd Street'),
'filter-truncatewords01': ('{% autoescape off %}{{ a|truncatewords:"2" }} {{ b|truncatewords:"2"}}{% endautoescape %}',
{"a": "alpha & bravo", "b": mark_safe("alpha &amp; bravo")}, "alpha & ... alpha &amp; ..."),
'filter-truncatewords02': ('{{ a|truncatewords:"2" }} {{ b|truncatewords:"2"}}',
{"a": "alpha & bravo", "b": mark_safe("alpha &amp; bravo")}, "alpha &amp; ... alpha &amp; ..."),
'filter-truncatechars01': ('{{ a|truncatechars:5 }}', {'a': "Testing, testing"}, "Te..."),
'filter-truncatechars02': ('{{ a|truncatechars:7 }}', {'a': "Testing"}, "Testing"),
# The "upper" filter messes up entities (which are case-sensitive),
# so it's not safe for non-escaping purposes.
'filter-upper01': ('{% autoescape off %}{{ a|upper }} {{ b|upper }}{% endautoescape %}', {"a": "a & b", "b": mark_safe("a &amp; b")}, "A & B A &AMP; B"),
'filter-upper02': ('{{ a|upper }} {{ b|upper }}', {"a": "a & b", "b": mark_safe("a &amp; b")}, "A &amp; B A &amp;AMP; B"),
'filter-urlize01': (
'{% autoescape off %}{{ a|urlize }} {{ b|urlize }}{% endautoescape %}',
{"a": "http://example.com/?x=&y=", "b": mark_safe("http://example.com?x=&amp;y=&lt;2&gt;")},
'<a href="http://example.com/?x=&y=" rel="nofollow">http://example.com/?x=&y=</a> '
'<a href="http://example.com?x=&y=%3C2%3E" rel="nofollow">http://example.com?x=&amp;y=&lt;2&gt;</a>'),
'filter-urlize02': (
'{{ a|urlize }} {{ b|urlize }}',
{"a": "http://example.com/?x=&y=", "b": mark_safe("http://example.com?x=&amp;y=")},
'<a href="http://example.com/?x=&y=" rel="nofollow">http://example.com/?x=&amp;y=</a> '
'<a href="http://example.com?x=&y=" rel="nofollow">http://example.com?x=&amp;y=</a>'),
'filter-urlize03': ('{% autoescape off %}{{ a|urlize }}{% endautoescape %}', {"a": mark_safe("a &amp; b")}, 'a &amp; b'),
'filter-urlize04': ('{{ a|urlize }}', {"a": mark_safe("a &amp; b")}, 'a &amp; b'),
# This will lead to a nonsense result, but at least it won't be
# exploitable for XSS purposes when auto-escaping is on.
'filter-urlize05': ('{% autoescape off %}{{ a|urlize }}{% endautoescape %}', {"a": "<script>alert('foo')</script>"}, "<script>alert('foo')</script>"),
'filter-urlize06': ('{{ a|urlize }}', {"a": "<script>alert('foo')</script>"}, '&lt;script&gt;alert(&#39;foo&#39;)&lt;/script&gt;'),
# mailto: testing for urlize
'filter-urlize07': ('{{ a|urlize }}', {"a": "Email me at me@example.com"}, 'Email me at <a href="mailto:me@example.com">me@example.com</a>'),
'filter-urlize08': ('{{ a|urlize }}', {"a": "Email me at <me@example.com>"}, 'Email me at &lt;<a href="mailto:me@example.com">me@example.com</a>&gt;'),
'filter-urlizetrunc01': (
'{% autoescape off %}{{ a|urlizetrunc:"8" }} {{ b|urlizetrunc:"8" }}{% endautoescape %}',
{"a": '"Unsafe" http://example.com/x=&y=', "b": mark_safe('&quot;Safe&quot; http://example.com?x=&amp;y=')},
'"Unsafe" <a href="http://example.com/x=&y=" rel="nofollow">http:...</a> '
'&quot;Safe&quot; <a href="http://example.com?x=&y=" rel="nofollow">http:...</a>'),
'filter-urlizetrunc02': (
'{{ a|urlizetrunc:"8" }} {{ b|urlizetrunc:"8" }}',
{"a": '"Unsafe" http://example.com/x=&y=', "b": mark_safe('&quot;Safe&quot; http://example.com?x=&amp;y=')},
'&quot;Unsafe&quot; <a href="http://example.com/x=&y=" rel="nofollow">http:...</a> '
'&quot;Safe&quot; <a href="http://example.com?x=&y=" rel="nofollow">http:...</a>'),
'filter-wordcount01': ('{% autoescape off %}{{ a|wordcount }} {{ b|wordcount }}{% endautoescape %}', {"a": "a & b", "b": mark_safe("a &amp; b")}, "3 3"),
'filter-wordcount02': ('{{ a|wordcount }} {{ b|wordcount }}', {"a": "a & b", "b": mark_safe("a &amp; b")}, "3 3"),
'filter-wordwrap01': ('{% autoescape off %}{{ a|wordwrap:"3" }} {{ b|wordwrap:"3" }}{% endautoescape %}', {"a": "a & b", "b": mark_safe("a & b")}, "a &\nb a &\nb"),
'filter-wordwrap02': ('{{ a|wordwrap:"3" }} {{ b|wordwrap:"3" }}', {"a": "a & b", "b": mark_safe("a & b")}, "a &amp;\nb a &\nb"),
'filter-ljust01': ('{% autoescape off %}.{{ a|ljust:"5" }}. .{{ b|ljust:"5" }}.{% endautoescape %}', {"a": "a&b", "b": mark_safe("a&b")}, ".a&b . .a&b ."),
'filter-ljust02': ('.{{ a|ljust:"5" }}. .{{ b|ljust:"5" }}.', {"a": "a&b", "b": mark_safe("a&b")}, ".a&amp;b . .a&b ."),
'filter-rjust01': ('{% autoescape off %}.{{ a|rjust:"5" }}. .{{ b|rjust:"5" }}.{% endautoescape %}', {"a": "a&b", "b": mark_safe("a&b")}, ". a&b. . a&b."),
'filter-rjust02': ('.{{ a|rjust:"5" }}. .{{ b|rjust:"5" }}.', {"a": "a&b", "b": mark_safe("a&b")}, ". a&amp;b. . a&b."),
'filter-center01': ('{% autoescape off %}.{{ a|center:"5" }}. .{{ b|center:"5" }}.{% endautoescape %}', {"a": "a&b", "b": mark_safe("a&b")}, ". a&b . . a&b ."),
'filter-center02': ('.{{ a|center:"5" }}. .{{ b|center:"5" }}.', {"a": "a&b", "b": mark_safe("a&b")}, ". a&amp;b . . a&b ."),
'filter-cut01': ('{% autoescape off %}{{ a|cut:"x" }} {{ b|cut:"x" }}{% endautoescape %}', {"a": "x&y", "b": mark_safe("x&amp;y")}, "&y &amp;y"),
'filter-cut02': ('{{ a|cut:"x" }} {{ b|cut:"x" }}', {"a": "x&y", "b": mark_safe("x&amp;y")}, "&amp;y &amp;y"),
'filter-cut03': ('{% autoescape off %}{{ a|cut:"&" }} {{ b|cut:"&" }}{% endautoescape %}', {"a": "x&y", "b": mark_safe("x&amp;y")}, "xy xamp;y"),
'filter-cut04': ('{{ a|cut:"&" }} {{ b|cut:"&" }}', {"a": "x&y", "b": mark_safe("x&amp;y")}, "xy xamp;y"),
# Passing ';' to cut can break existing HTML entities, so those strings
# are auto-escaped.
'filter-cut05': ('{% autoescape off %}{{ a|cut:";" }} {{ b|cut:";" }}{% endautoescape %}', {"a": "x&y", "b": mark_safe("x&amp;y")}, "x&y x&ampy"),
'filter-cut06': ('{{ a|cut:";" }} {{ b|cut:";" }}', {"a": "x&y", "b": mark_safe("x&amp;y")}, "x&amp;y x&amp;ampy"),
# The "escape" filter works the same whether autoescape is on or off,
# but it has no effect on strings already marked as safe.
'filter-escape01': ('{{ a|escape }} {{ b|escape }}', {"a": "x&y", "b": mark_safe("x&y")}, "x&amp;y x&y"),
'filter-escape02': ('{% autoescape off %}{{ a|escape }} {{ b|escape }}{% endautoescape %}', {"a": "x&y", "b": mark_safe("x&y")}, "x&amp;y x&y"),
# It is only applied once, regardless of the number of times it
# appears in a chain.
'filter-escape03': ('{% autoescape off %}{{ a|escape|escape }}{% endautoescape %}', {"a": "x&y"}, "x&amp;y"),
'filter-escape04': ('{{ a|escape|escape }}', {"a": "x&y"}, "x&amp;y"),
# Force_escape is applied immediately. It can be used to provide
# double-escaping, for example.
'filter-force-escape01': ('{% autoescape off %}{{ a|force_escape }}{% endautoescape %}', {"a": "x&y"}, "x&amp;y"),
'filter-force-escape02': ('{{ a|force_escape }}', {"a": "x&y"}, "x&amp;y"),
'filter-force-escape03': ('{% autoescape off %}{{ a|force_escape|force_escape }}{% endautoescape %}', {"a": "x&y"}, "x&amp;amp;y"),
'filter-force-escape04': ('{{ a|force_escape|force_escape }}', {"a": "x&y"}, "x&amp;amp;y"),
# Because the result of force_escape is "safe", an additional
# escape filter has no effect.
'filter-force-escape05': ('{% autoescape off %}{{ a|force_escape|escape }}{% endautoescape %}', {"a": "x&y"}, "x&amp;y"),
'filter-force-escape06': ('{{ a|force_escape|escape }}', {"a": "x&y"}, "x&amp;y"),
'filter-force-escape07': ('{% autoescape off %}{{ a|escape|force_escape }}{% endautoescape %}', {"a": "x&y"}, "x&amp;y"),
'filter-force-escape08': ('{{ a|escape|force_escape }}', {"a": "x&y"}, "x&amp;y"),
# The contents in "linebreaks" and "linebreaksbr" are escaped
# according to the current autoescape setting.
'filter-linebreaks01': ('{{ a|linebreaks }} {{ b|linebreaks }}', {"a": "x&\ny", "b": mark_safe("x&\ny")}, "<p>x&amp;<br />y</p> <p>x&<br />y</p>"),
'filter-linebreaks02': ('{% autoescape off %}{{ a|linebreaks }} {{ b|linebreaks }}{% endautoescape %}', {"a": "x&\ny", "b": mark_safe("x&\ny")}, "<p>x&<br />y</p> <p>x&<br />y</p>"),
'filter-linebreaksbr01': ('{{ a|linebreaksbr }} {{ b|linebreaksbr }}', {"a": "x&\ny", "b": mark_safe("x&\ny")}, "x&amp;<br />y x&<br />y"),
'filter-linebreaksbr02': ('{% autoescape off %}{{ a|linebreaksbr }} {{ b|linebreaksbr }}{% endautoescape %}', {"a": "x&\ny", "b": mark_safe("x&\ny")}, "x&<br />y x&<br />y"),
'filter-safe01': ("{{ a }} -- {{ a|safe }}", {"a": "<b>hello</b>"}, "&lt;b&gt;hello&lt;/b&gt; -- <b>hello</b>"),
'filter-safe02': ("{% autoescape off %}{{ a }} -- {{ a|safe }}{% endautoescape %}", {"a": "<b>hello</b>"}, "<b>hello</b> -- <b>hello</b>"),
'filter-safeseq01': ('{{ a|join:", " }} -- {{ a|safeseq|join:", " }}', {"a": ["&", "<"]}, "&amp;, &lt; -- &, <"),
'filter-safeseq02': ('{% autoescape off %}{{ a|join:", " }} -- {{ a|safeseq|join:", " }}{% endautoescape %}', {"a": ["&", "<"]}, "&, < -- &, <"),
'filter-removetags01': ('{{ a|removetags:"a b" }} {{ b|removetags:"a b" }}', {"a": "<a>x</a> <p><b>y</b></p>", "b": mark_safe("<a>x</a> <p><b>y</b></p>")}, "x &lt;p&gt;y&lt;/p&gt; x <p>y</p>"),
'filter-removetags02': ('{% autoescape off %}{{ a|removetags:"a b" }} {{ b|removetags:"a b" }}{% endautoescape %}', {"a": "<a>x</a> <p><b>y</b></p>", "b": mark_safe("<a>x</a> <p><b>y</b></p>")}, "x <p>y</p> x <p>y</p>"),
'filter-striptags01': ('{{ a|striptags }} {{ b|striptags }}', {"a": "<a>x</a> <p><b>y</b></p>", "b": mark_safe("<a>x</a> <p><b>y</b></p>")}, "x y x y"),
'filter-striptags02': ('{% autoescape off %}{{ a|striptags }} {{ b|striptags }}{% endautoescape %}', {"a": "<a>x</a> <p><b>y</b></p>", "b": mark_safe("<a>x</a> <p><b>y</b></p>")}, "x y x y"),
'filter-first01': ('{{ a|first }} {{ b|first }}', {"a": ["a&b", "x"], "b": [mark_safe("a&b"), "x"]}, "a&amp;b a&b"),
'filter-first02': ('{% autoescape off %}{{ a|first }} {{ b|first }}{% endautoescape %}', {"a": ["a&b", "x"], "b": [mark_safe("a&b"), "x"]}, "a&b a&b"),
'filter-last01': ('{{ a|last }} {{ b|last }}', {"a": ["x", "a&b"], "b": ["x", mark_safe("a&b")]}, "a&amp;b a&b"),
'filter-last02': ('{% autoescape off %}{{ a|last }} {{ b|last }}{% endautoescape %}', {"a": ["x", "a&b"], "b": ["x", mark_safe("a&b")]}, "a&b a&b"),
'filter-random01': ('{{ a|random }} {{ b|random }}', {"a": ["a&b", "a&b"], "b": [mark_safe("a&b"), mark_safe("a&b")]}, "a&amp;b a&b"),
'filter-random02': ('{% autoescape off %}{{ a|random }} {{ b|random }}{% endautoescape %}', {"a": ["a&b", "a&b"], "b": [mark_safe("a&b"), mark_safe("a&b")]}, "a&b a&b"),
'filter-slice01': ('{{ a|slice:"1:3" }} {{ b|slice:"1:3" }}', {"a": "a&b", "b": mark_safe("a&b")}, "&amp;b &b"),
'filter-slice02': ('{% autoescape off %}{{ a|slice:"1:3" }} {{ b|slice:"1:3" }}{% endautoescape %}', {"a": "a&b", "b": mark_safe("a&b")}, "&b &b"),
'filter-unordered_list01': ('{{ a|unordered_list }}', {"a": ["x>", [["<y", []]]]}, "\t<li>x&gt;\n\t<ul>\n\t\t<li>&lt;y</li>\n\t</ul>\n\t</li>"),
'filter-unordered_list02': ('{% autoescape off %}{{ a|unordered_list }}{% endautoescape %}', {"a": ["x>", [["<y", []]]]}, "\t<li>x>\n\t<ul>\n\t\t<li><y</li>\n\t</ul>\n\t</li>"),
'filter-unordered_list03': ('{{ a|unordered_list }}', {"a": ["x>", [[mark_safe("<y"), []]]]}, "\t<li>x&gt;\n\t<ul>\n\t\t<li><y</li>\n\t</ul>\n\t</li>"),
'filter-unordered_list04': ('{% autoescape off %}{{ a|unordered_list }}{% endautoescape %}', {"a": ["x>", [[mark_safe("<y"), []]]]}, "\t<li>x>\n\t<ul>\n\t\t<li><y</li>\n\t</ul>\n\t</li>"),
'filter-unordered_list05': ('{% autoescape off %}{{ a|unordered_list }}{% endautoescape %}', {"a": ["x>", [["<y", []]]]}, "\t<li>x>\n\t<ul>\n\t\t<li><y</li>\n\t</ul>\n\t</li>"),
# Literal string arguments to the default filter are always treated as
# safe strings, regardless of the auto-escaping state.
#
# Note: we have to use {"a": ""} here, otherwise the invalid template
# variable string interferes with the test result.
'filter-default01': ('{{ a|default:"x<" }}', {"a": ""}, "x<"),
'filter-default02': ('{% autoescape off %}{{ a|default:"x<" }}{% endautoescape %}', {"a": ""}, "x<"),
'filter-default03': ('{{ a|default:"x<" }}', {"a": mark_safe("x>")}, "x>"),
'filter-default04': ('{% autoescape off %}{{ a|default:"x<" }}{% endautoescape %}', {"a": mark_safe("x>")}, "x>"),
'filter-default_if_none01': ('{{ a|default:"x<" }}', {"a": None}, "x<"),
'filter-default_if_none02': ('{% autoescape off %}{{ a|default:"x<" }}{% endautoescape %}', {"a": None}, "x<"),
'filter-phone2numeric01': ('{{ a|phone2numeric }} {{ b|phone2numeric }}', {"a": "<1-800-call-me>", "b": mark_safe("<1-800-call-me>")}, "&lt;1-800-2255-63&gt; <1-800-2255-63>"),
'filter-phone2numeric02': ('{% autoescape off %}{{ a|phone2numeric }} {{ b|phone2numeric }}{% endautoescape %}', {"a": "<1-800-call-me>", "b": mark_safe("<1-800-call-me>")}, "<1-800-2255-63> <1-800-2255-63>"),
'filter-phone2numeric03': ('{{ a|phone2numeric }}', {"a": "How razorback-jumping frogs can level six piqued gymnasts!"}, "469 729672225-5867464 37647 226 53835 749 747833 49662787!"),
# Ensure iriencode keeps safe strings:
'filter-iriencode01': ('{{ url|iriencode }}', {'url': '?test=1&me=2'}, '?test=1&amp;me=2'),
'filter-iriencode02': ('{% autoescape off %}{{ url|iriencode }}{% endautoescape %}', {'url': '?test=1&me=2'}, '?test=1&me=2'),
'filter-iriencode03': ('{{ url|iriencode }}', {'url': mark_safe('?test=1&me=2')}, '?test=1&me=2'),
'filter-iriencode04': ('{% autoescape off %}{{ url|iriencode }}{% endautoescape %}', {'url': mark_safe('?test=1&me=2')}, '?test=1&me=2'),
# urlencode
'filter-urlencode01': ('{{ url|urlencode }}', {'url': '/test&"/me?/'}, '/test%26%22/me%3F/'),
'filter-urlencode02': ('/test/{{ urlbit|urlencode:"" }}/', {'urlbit': 'escape/slash'}, '/test/escape%2Fslash/'),
# Chaining a bunch of safeness-preserving filters should not alter
# the safe status either way.
'chaining01': ('{{ a|capfirst|center:"7" }}.{{ b|capfirst|center:"7" }}', {"a": "a < b", "b": mark_safe("a < b")}, " A &lt; b . A < b "),
'chaining02': ('{% autoescape off %}{{ a|capfirst|center:"7" }}.{{ b|capfirst|center:"7" }}{% endautoescape %}', {"a": "a < b", "b": mark_safe("a < b")}, " A < b . A < b "),
# Using a filter that forces a string back to unsafe:
'chaining03': ('{{ a|cut:"b"|capfirst }}.{{ b|cut:"b"|capfirst }}', {"a": "a < b", "b": mark_safe("a < b")}, "A &lt; .A < "),
'chaining04': ('{% autoescape off %}{{ a|cut:"b"|capfirst }}.{{ b|cut:"b"|capfirst }}{% endautoescape %}', {"a": "a < b", "b": mark_safe("a < b")}, "A < .A < "),
# Using a filter that forces safeness does not lead to double-escaping
'chaining05': ('{{ a|escape|capfirst }}', {"a": "a < b"}, "A &lt; b"),
'chaining06': ('{% autoescape off %}{{ a|escape|capfirst }}{% endautoescape %}', {"a": "a < b"}, "A &lt; b"),
# Force to safe, then back (also showing why using force_escape too
# early in a chain can lead to unexpected results).
'chaining07': ('{{ a|force_escape|cut:";" }}', {"a": "a < b"}, "a &amp;lt b"),
'chaining08': ('{% autoescape off %}{{ a|force_escape|cut:";" }}{% endautoescape %}', {"a": "a < b"}, "a &lt b"),
'chaining09': ('{{ a|cut:";"|force_escape }}', {"a": "a < b"}, "a &lt; b"),
'chaining10': ('{% autoescape off %}{{ a|cut:";"|force_escape }}{% endautoescape %}', {"a": "a < b"}, "a &lt; b"),
'chaining11': ('{{ a|cut:"b"|safe }}', {"a": "a < b"}, "a < "),
'chaining12': ('{% autoescape off %}{{ a|cut:"b"|safe }}{% endautoescape %}', {"a": "a < b"}, "a < "),
'chaining13': ('{{ a|safe|force_escape }}', {"a": "a < b"}, "a &lt; b"),
'chaining14': ('{% autoescape off %}{{ a|safe|force_escape }}{% endautoescape %}', {"a": "a < b"}, "a &lt; b"),
# Filters decorated with stringfilter still respect is_safe.
'autoescape-stringfilter01': (r'{{ unsafe|capfirst }}', {'unsafe': UnsafeClass()}, 'You &amp; me'),
'autoescape-stringfilter02': (r'{% autoescape off %}{{ unsafe|capfirst }}{% endautoescape %}', {'unsafe': UnsafeClass()}, 'You & me'),
'autoescape-stringfilter03': (r'{{ safe|capfirst }}', {'safe': SafeClass()}, 'You &gt; me'),
'autoescape-stringfilter04': (r'{% autoescape off %}{{ safe|capfirst }}{% endautoescape %}', {'safe': SafeClass()}, 'You &gt; me'),
'escapejs01': (r'{{ a|escapejs }}', {'a': 'testing\r\njavascript \'string" <b>escaping</b>'}, 'testing\\u000D\\u000Ajavascript \\u0027string\\u0022 \\u003Cb\\u003Eescaping\\u003C/b\\u003E'),
'escapejs02': (r'{% autoescape off %}{{ a|escapejs }}{% endautoescape %}', {'a': 'testing\r\njavascript \'string" <b>escaping</b>'}, 'testing\\u000D\\u000Ajavascript \\u0027string\\u0022 \\u003Cb\\u003Eescaping\\u003C/b\\u003E'),
# length filter.
'length01': ('{{ list|length }}', {'list': ['4', None, True, {}]}, '4'),
'length02': ('{{ list|length }}', {'list': []}, '0'),
'length03': ('{{ string|length }}', {'string': ''}, '0'),
'length04': ('{{ string|length }}', {'string': 'django'}, '6'),
'length05': ('{% if string|length == 6 %}Pass{% endif %}', {'string': mark_safe('django')}, 'Pass'),
# Invalid uses that should fail silently.
'length06': ('{{ int|length }}', {'int': 7}, '0'),
'length07': ('{{ None|length }}', {'None': None}, '0'),
# length_is filter.
'length_is01': ('{% if some_list|length_is:"4" %}Four{% endif %}', {'some_list': ['4', None, True, {}]}, 'Four'),
'length_is02': ('{% if some_list|length_is:"4" %}Four{% else %}Not Four{% endif %}', {'some_list': ['4', None, True, {}, 17]}, 'Not Four'),
'length_is03': ('{% if mystring|length_is:"4" %}Four{% endif %}', {'mystring': 'word'}, 'Four'),
'length_is04': ('{% if mystring|length_is:"4" %}Four{% else %}Not Four{% endif %}', {'mystring': 'Python'}, 'Not Four'),
'length_is05': ('{% if mystring|length_is:"4" %}Four{% else %}Not Four{% endif %}', {'mystring': ''}, 'Not Four'),
'length_is06': ('{% with var|length as my_length %}{{ my_length }}{% endwith %}', {'var': 'django'}, '6'),
# Boolean return value from length_is should not be coerced to a string
'length_is07': (r'{% if "X"|length_is:0 %}Length is 0{% else %}Length not 0{% endif %}', {}, 'Length not 0'),
'length_is08': (r'{% if "X"|length_is:1 %}Length is 1{% else %}Length not 1{% endif %}', {}, 'Length is 1'),
# Invalid uses that should fail silently.
'length_is09': ('{{ var|length_is:"fish" }}', {'var': 'django'}, ''),
'length_is10': ('{{ int|length_is:"1" }}', {'int': 7}, ''),
'length_is11': ('{{ none|length_is:"1" }}', {'none': None}, ''),
'join01': (r'{{ a|join:", " }}', {'a': ['alpha', 'beta & me']}, 'alpha, beta &amp; me'),
'join02': (r'{% autoescape off %}{{ a|join:", " }}{% endautoescape %}', {'a': ['alpha', 'beta & me']}, 'alpha, beta & me'),
'join03': (r'{{ a|join:" &amp; " }}', {'a': ['alpha', 'beta & me']}, 'alpha &amp; beta &amp; me'),
'join04': (r'{% autoescape off %}{{ a|join:" &amp; " }}{% endautoescape %}', {'a': ['alpha', 'beta & me']}, 'alpha &amp; beta & me'),
# Test that joining with unsafe joiners don't result in unsafe strings (#11377)
'join05': (r'{{ a|join:var }}', {'a': ['alpha', 'beta & me'], 'var': ' & '}, 'alpha &amp; beta &amp; me'),
'join06': (r'{{ a|join:var }}', {'a': ['alpha', 'beta & me'], 'var': mark_safe(' & ')}, 'alpha & beta &amp; me'),
'join07': (r'{{ a|join:var|lower }}', {'a': ['Alpha', 'Beta & me'], 'var': ' & '}, 'alpha &amp; beta &amp; me'),
'join08': (r'{{ a|join:var|lower }}', {'a': ['Alpha', 'Beta & me'], 'var': mark_safe(' & ')}, 'alpha & beta &amp; me'),
'date01': (r'{{ d|date:"m" }}', {'d': datetime(2008, 1, 1)}, '01'),
'date02': (r'{{ d|date }}', {'d': datetime(2008, 1, 1)}, 'Jan. 1, 2008'),
# Ticket 9520: Make sure |date doesn't blow up on non-dates
'date03': (r'{{ d|date:"m" }}', {'d': 'fail_string'}, ''),
# ISO date formats
'date04': (r'{{ d|date:"o" }}', {'d': datetime(2008, 12, 29)}, '2009'),
'date05': (r'{{ d|date:"o" }}', {'d': datetime(2010, 1, 3)}, '2009'),
# Timezone name
'date06': (r'{{ d|date:"e" }}', {'d': datetime(2009, 3, 12, tzinfo=timezone.get_fixed_timezone(30))}, '+0030'),
'date07': (r'{{ d|date:"e" }}', {'d': datetime(2009, 3, 12)}, ''),
# Ticket 19370: Make sure |date doesn't blow up on a midnight time object
'date08': (r'{{ t|date:"H:i" }}', {'t': time(0, 1)}, '00:01'),
'date09': (r'{{ t|date:"H:i" }}', {'t': time(0, 0)}, '00:00'),
# Ticket 20693: Add timezone support to built-in time template filter
'time01': (r'{{ dt|time:"e:O:T:Z" }}', {'dt': now_tz_i}, '+0315:+0315:+0315:11700'),
'time02': (r'{{ dt|time:"e:T" }}', {'dt': now}, ':' + now_tz.tzinfo.tzname(now_tz)),
'time03': (r'{{ t|time:"P:e:O:T:Z" }}', {'t': time(4, 0, tzinfo=timezone.get_fixed_timezone(30))}, '4 a.m.::::'),
'time04': (r'{{ t|time:"P:e:O:T:Z" }}', {'t': time(4, 0)}, '4 a.m.::::'),
'time05': (r'{{ d|time:"P:e:O:T:Z" }}', {'d': today}, ''),
'time06': (r'{{ obj|time:"P:e:O:T:Z" }}', {'obj': 'non-datetime-value'}, ''),
# Tests for #11687 and #16676
'add01': (r'{{ i|add:"5" }}', {'i': 2000}, '2005'),
'add02': (r'{{ i|add:"napis" }}', {'i': 2000}, ''),
'add03': (r'{{ i|add:16 }}', {'i': 'not_an_int'}, ''),
'add04': (r'{{ i|add:"16" }}', {'i': 'not_an_int'}, 'not_an_int16'),
'add05': (r'{{ l1|add:l2 }}', {'l1': [1, 2], 'l2': [3, 4]}, '[1, 2, 3, 4]'),
'add06': (r'{{ t1|add:t2 }}', {'t1': (3, 4), 't2': (1, 2)}, '(3, 4, 1, 2)'),
'add07': (r'{{ d|add:t }}', {'d': date(2000, 1, 1), 't': timedelta(10)}, 'Jan. 11, 2000'),
}

View File

@ -2,7 +2,7 @@ from django.template.base import TemplateSyntaxError
from django.test import SimpleTestCase
from django.utils.safestring import mark_safe
from .utils import render, setup, SafeClass, UnsafeClass
from ..utils import render, setup, SafeClass, UnsafeClass
class AutoescapeTagTests(SimpleTestCase):

View File

@ -3,7 +3,7 @@ from django.template.base import Context, TemplateSyntaxError
from django.template.loader import get_template
from django.test import SimpleTestCase
from .utils import render, setup, SilentGetItemClass, SilentAttrClass, SomeClass
from ..utils import render, setup, SilentGetItemClass, SilentAttrClass, SomeClass
basic_templates = {

View File

@ -1,6 +1,6 @@
from django.test import SimpleTestCase
from .utils import render, setup
from ..utils import render, setup
class BuiltinsTests(SimpleTestCase):

View File

@ -3,7 +3,7 @@ from django.template.base import TemplateSyntaxError
from django.template.loader import get_template
from django.test import SimpleTestCase
from .utils import render, setup
from ..utils import render, setup
class CacheTagTests(SimpleTestCase):

View File

@ -1,6 +1,6 @@
from django.test import SimpleTestCase
from .utils import render, setup
from ..utils import render, setup
class CommentSyntaxTests(SimpleTestCase):

View File

@ -5,7 +5,7 @@ from django.template.loader import get_template
from django.test import SimpleTestCase
from django.utils.deprecation import RemovedInDjango20Warning
from .utils import render, setup
from ..utils import render, setup
class CycleTagTests(SimpleTestCase):

View File

@ -4,7 +4,7 @@ from django.template.loader import get_template
from django.test import SimpleTestCase
from .test_extends import inheritance_templates
from .utils import render, setup
from ..utils import render, setup
class ExceptionsTests(SimpleTestCase):

View File

@ -1,7 +1,7 @@
from django.template.base import Template
from django.test import SimpleTestCase
from .utils import render, setup
from ..utils import render, setup
inheritance_templates = {

View File

@ -8,7 +8,7 @@ from django.template.loader import get_template
from django.test import SimpleTestCase
from django.utils.deprecation import RemovedInDjango20Warning
from .utils import render, setup, SomeClass, SomeOtherException, UTF8Class
from ..utils import render, setup, SomeClass, SomeOtherException, UTF8Class
class FilterSyntaxTests(SimpleTestCase):

View File

@ -2,7 +2,7 @@ from django.template.base import TemplateSyntaxError
from django.template.loader import get_template
from django.test import SimpleTestCase
from .utils import render, setup
from ..utils import render, setup
class FilterTagTests(SimpleTestCase):

View File

@ -5,7 +5,7 @@ from django.template.loader import get_template
from django.test import SimpleTestCase
from django.utils.deprecation import RemovedInDjango20Warning
from .utils import render, setup
from ..utils import render, setup
class FirstOfTagTests(SimpleTestCase):

View File

@ -5,7 +5,7 @@ from django.template.base import TemplateSyntaxError
from django.test import SimpleTestCase
from django.utils.deprecation import RemovedInDjango20Warning
from .utils import render, setup
from ..utils import render, setup
class ForTagTests(SimpleTestCase):

View File

@ -5,7 +5,7 @@ from django.conf import settings
from django.test import SimpleTestCase
from django.utils.safestring import mark_safe
from .utils import render, setup
from ..utils import render, setup
class I18nTagTests(SimpleTestCase):

View File

@ -2,7 +2,7 @@ from django.template.base import TemplateSyntaxError
from django.template.loader import get_template
from django.test import SimpleTestCase
from .utils import render, setup, TestObj
from ..utils import render, setup, TestObj
class IfTagTests(SimpleTestCase):

View File

@ -1,6 +1,6 @@
from django.test import SimpleTestCase
from .utils import render, setup
from ..utils import render, setup
class IfChangedTagTests(SimpleTestCase):

View File

@ -1,6 +1,6 @@
from django.test import SimpleTestCase
from .utils import render, setup
from ..utils import render, setup
class IfEqualTagTests(SimpleTestCase):

View File

@ -4,7 +4,7 @@ from django.template.loader import get_template
from django.test import SimpleTestCase
from .test_basic import basic_templates
from .utils import render, setup
from ..utils import render, setup
include_fail_templates = {

View File

@ -1,7 +1,7 @@
from django.conf import settings
from django.test import SimpleTestCase
from .utils import render, setup
from ..utils import render, setup
class InvalidStringTests(SimpleTestCase):

View File

@ -1,7 +1,7 @@
from django.conf import settings
from django.test import SimpleTestCase
from .utils import render, setup
from ..utils import render, setup
class ListIndexTests(SimpleTestCase):

View File

@ -2,7 +2,7 @@ from django.template.base import TemplateSyntaxError
from django.template.loader import get_template
from django.test import SimpleTestCase
from .utils import render, setup
from ..utils import render, setup
class LoadTagTests(SimpleTestCase):

View File

@ -1,6 +1,6 @@
from django.test import SimpleTestCase
from .utils import render, setup
from ..utils import render, setup
class LoremTagTests(SimpleTestCase):

View File

@ -1,6 +1,6 @@
from django.test import SimpleTestCase
from .utils import render, setup
from ..utils import render, setup
multiline_string = """

View File

@ -2,7 +2,7 @@ from django.template.base import TemplateSyntaxError
from django.template.loader import get_template
from django.test import SimpleTestCase
from .utils import render, setup
from ..utils import render, setup
class NamedEndblockTests(SimpleTestCase):

View File

@ -3,7 +3,7 @@ from datetime import datetime
from django.test import SimpleTestCase
from django.utils.formats import date_format
from .utils import render, setup
from ..utils import render, setup
class NowTagTests(SimpleTestCase):

View File

@ -3,7 +3,7 @@ from unittest import skipIf
from django.conf import settings
from django.test import SimpleTestCase
from .utils import render, setup
from ..utils import render, setup
try:
import numpy

View File

@ -4,7 +4,7 @@ from django.template.base import TemplateSyntaxError
from django.template.loader import get_template
from django.test import SimpleTestCase
from .utils import render, setup
from ..utils import render, setup
class RegroupTagTests(SimpleTestCase):

View File

@ -1,7 +1,7 @@
from django.conf import settings
from django.test import SimpleTestCase
from .utils import setup
from ..utils import setup
class SetupTests(SimpleTestCase):

View File

@ -2,7 +2,7 @@ from django.template.base import TemplateSyntaxError
from django.template.loader import get_template
from django.test import SimpleTestCase
from .utils import render, setup
from ..utils import render, setup
class SimpleTagTests(SimpleTestCase):

View File

@ -1,6 +1,6 @@
from django.test import SimpleTestCase
from .utils import render, setup
from ..utils import render, setup
class SpacelessTagTests(SimpleTestCase):

View File

@ -5,7 +5,7 @@ from django.test import override_settings, SimpleTestCase
from django.utils._os import upath
from django.utils.deprecation import RemovedInDjango19Warning
from .utils import render, setup
from ..utils import render, setup
cwd = os.path.dirname(os.path.abspath(upath(__file__)))

View File

@ -2,7 +2,7 @@ from django.conf import settings
from django.test import override_settings, SimpleTestCase
from django.utils.six.moves.urllib.parse import urljoin
from .utils import render, setup
from ..utils import render, setup
@override_settings(MEDIA_URL="/media/", STATIC_URL="/static/")

View File

@ -2,7 +2,7 @@ from django.template.base import TemplateSyntaxError
from django.template.loader import get_template
from django.test import SimpleTestCase
from .utils import render, setup
from ..utils import render, setup
class TemplateTagTests(SimpleTestCase):

View File

@ -7,7 +7,7 @@ from django.template.loader import get_template
from django.test import override_settings, SimpleTestCase
from django.utils.deprecation import RemovedInDjango20Warning
from .utils import render, setup
from ..utils import render, setup
@override_settings(ROOT_URLCONF='template_tests.urls')

View File

@ -2,7 +2,7 @@ from django.template.base import TemplateSyntaxError
from django.template.loader import get_template
from django.test import SimpleTestCase
from .utils import render, setup
from ..utils import render, setup
class VerbatimTagTests(SimpleTestCase):

View File

@ -3,7 +3,7 @@ from django.template.loader import get_template
from django.test import SimpleTestCase
from django.utils import six
from .utils import render, setup
from ..utils import render, setup
class WidthRatioTagTests(SimpleTestCase):

View File

@ -2,7 +2,7 @@ from django.conf import settings
from django.template.base import TemplateSyntaxError
from django.test import SimpleTestCase
from .utils import render, setup
from ..utils import render, setup
class WithTagTests(SimpleTestCase):

View File

@ -3,9 +3,7 @@ from __future__ import unicode_literals
import os
import sys
import traceback
import unittest
import warnings
from django import template
from django.contrib.auth.models import Group
@ -15,17 +13,7 @@ from django.template.engine import Engine
from django.template.loaders import app_directories, filesystem
from django.test import RequestFactory, SimpleTestCase
from django.test.utils import override_settings, extend_sys_path
from django.utils.deprecation import RemovedInDjango19Warning, RemovedInDjango20Warning
from django.utils._os import upath
from django.utils import six
from django.utils import translation
from . import filters
from .syntax_tests.utils import register_test_tags, ShouldNotExecuteException
class ContextStackException(Exception):
pass
class TemplateLoaderTests(SimpleTestCase):
@ -393,114 +381,6 @@ class TemplateRegressionTests(SimpleTestCase):
self.assertIn("清風", t1.render(c1))
# Set ALLOWED_INCLUDE_ROOTS so that ssi works.
@override_settings(TEMPLATE_DEBUG=False, ROOT_URLCONF='template_tests.urls')
class TemplateTests(SimpleTestCase):
@register_test_tags
def test_templates(self):
template_tests = filters.get_filter_tests()
templates = dict((name, t[0]) for name, t in six.iteritems(template_tests))
with override_settings(TEMPLATE_LOADERS=[
('django.template.loaders.cached.Loader', [
('django.template.loaders.locmem.Loader', templates),
]),
]):
failures = []
tests = sorted(template_tests.items())
# Warm the URL reversing cache. This ensures we don't pay the cost
# warming the cache during one of the tests.
urlresolvers.reverse('named.client', args=(0,))
for name, vals in tests:
# Set TEMPLATE_STRING_IF_INVALID to a known string.
expected_invalid_str = 'INVALID'
if isinstance(vals[2], tuple):
normal_string_result = vals[2][0]
invalid_string_result = vals[2][1]
if isinstance(invalid_string_result, tuple):
expected_invalid_str = 'INVALID %s'
invalid_string_result = invalid_string_result[0] % invalid_string_result[1]
try:
template_debug_result = vals[2][2]
except IndexError:
template_debug_result = normal_string_result
else:
normal_string_result = vals[2]
invalid_string_result = vals[2]
template_debug_result = vals[2]
with translation.override(vals[1].get('LANGUAGE_CODE', 'en-us')):
for invalid_str, template_debug, result in [
('', False, normal_string_result),
(expected_invalid_str, False, invalid_string_result),
('', True, template_debug_result)
]:
with override_settings(TEMPLATE_STRING_IF_INVALID=invalid_str,
TEMPLATE_DEBUG=template_debug):
for is_cached in (False, True):
try:
try:
with warnings.catch_warnings():
# Ignore pending deprecations of loading 'ssi' and 'url' tags from future.
warnings.filterwarnings("ignore", category=RemovedInDjango19Warning, module='django.templatetags.future')
# Ignore deprecations of loading 'cycle' and 'firstof' tags from future.
warnings.filterwarnings("ignore", category=RemovedInDjango20Warning, module="django.templatetags.future")
test_template = loader.get_template(name)
except ShouldNotExecuteException:
failures.append("Template test (Cached='%s', TEMPLATE_STRING_IF_INVALID='%s', TEMPLATE_DEBUG=%s): %s -- FAILED. Template loading invoked method that shouldn't have been invoked." % (is_cached, invalid_str, template_debug, name))
try:
with warnings.catch_warnings():
# Ignore deprecations of using the wrong number of variables with the 'for' tag.
# and warnings for {% url %} reversing by dotted path
warnings.filterwarnings("ignore", category=RemovedInDjango20Warning, module="django.template.defaulttags")
# Ignore deprecations of old style unordered_list
# and removetags.
warnings.filterwarnings("ignore", category=RemovedInDjango20Warning, module="django.template.defaultfilters")
# Ignore numpy deprecation warnings (#23890)
warnings.filterwarnings(
"ignore",
"Using a non-integer number instead of an "
"integer will result in an error in the future",
DeprecationWarning
)
output = self.render(test_template, vals)
except ShouldNotExecuteException:
failures.append("Template test (Cached='%s', TEMPLATE_STRING_IF_INVALID='%s', TEMPLATE_DEBUG=%s): %s -- FAILED. Template rendering invoked method that shouldn't have been invoked." % (is_cached, invalid_str, template_debug, name))
except ContextStackException:
failures.append("Template test (Cached='%s', TEMPLATE_STRING_IF_INVALID='%s', TEMPLATE_DEBUG=%s): %s -- FAILED. Context stack was left imbalanced" % (is_cached, invalid_str, template_debug, name))
continue
except Exception:
exc_type, exc_value, exc_tb = sys.exc_info()
if exc_type != result:
tb = '\n'.join(traceback.format_exception(exc_type, exc_value, exc_tb))
failures.append("Template test (Cached='%s', TEMPLATE_STRING_IF_INVALID='%s', TEMPLATE_DEBUG=%s): %s -- FAILED. Got %s, exception: %s\n%s" % (is_cached, invalid_str, template_debug, name, exc_type, exc_value, tb))
continue
if output != result:
failures.append("Template test (Cached='%s', TEMPLATE_STRING_IF_INVALID='%s', TEMPLATE_DEBUG=%s): %s -- FAILED. Expected %r, got %r" % (is_cached, invalid_str, template_debug, name, result, output))
Engine.get_default().template_loaders[0].reset()
self.assertEqual(failures, [], "Tests failed:\n%s\n%s" %
('-' * 70, ("\n%s\n" % ('-' * 70)).join(failures)))
def render(self, test_template, vals):
context = template.Context(vals[1])
before_stack_size = len(context.dicts)
output = test_template.render(context)
if len(context.dicts) != before_stack_size:
raise ContextStackException
return output
class TemplateTagLoading(SimpleTestCase):
def setUp(self):