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.test import SimpleTestCase
from django.utils.safestring import mark_safe from django.utils.safestring import mark_safe
from .utils import render, setup, SafeClass, UnsafeClass from ..utils import render, setup, SafeClass, UnsafeClass
class AutoescapeTagTests(SimpleTestCase): 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.template.loader import get_template
from django.test import SimpleTestCase from django.test import SimpleTestCase
from .utils import render, setup, SilentGetItemClass, SilentAttrClass, SomeClass from ..utils import render, setup, SilentGetItemClass, SilentAttrClass, SomeClass
basic_templates = { basic_templates = {

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -8,7 +8,7 @@ from django.template.loader import get_template
from django.test import SimpleTestCase from django.test import SimpleTestCase
from django.utils.deprecation import RemovedInDjango20Warning 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): class FilterSyntaxTests(SimpleTestCase):

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,6 +1,6 @@
from django.test import SimpleTestCase from django.test import SimpleTestCase
from .utils import render, setup from ..utils import render, setup
class SpacelessTagTests(SimpleTestCase): 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._os import upath
from django.utils.deprecation import RemovedInDjango19Warning 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__))) 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.test import override_settings, SimpleTestCase
from django.utils.six.moves.urllib.parse import urljoin 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/") @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.template.loader import get_template
from django.test import SimpleTestCase from django.test import SimpleTestCase
from .utils import render, setup from ..utils import render, setup
class TemplateTagTests(SimpleTestCase): 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.test import override_settings, SimpleTestCase
from django.utils.deprecation import RemovedInDjango20Warning from django.utils.deprecation import RemovedInDjango20Warning
from .utils import render, setup from ..utils import render, setup
@override_settings(ROOT_URLCONF='template_tests.urls') @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.template.loader import get_template
from django.test import SimpleTestCase from django.test import SimpleTestCase
from .utils import render, setup from ..utils import render, setup
class VerbatimTagTests(SimpleTestCase): class VerbatimTagTests(SimpleTestCase):

View File

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

View File

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

View File

@ -3,9 +3,7 @@ from __future__ import unicode_literals
import os import os
import sys import sys
import traceback
import unittest import unittest
import warnings
from django import template from django import template
from django.contrib.auth.models import Group 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.template.loaders import app_directories, filesystem
from django.test import RequestFactory, SimpleTestCase from django.test import RequestFactory, SimpleTestCase
from django.test.utils import override_settings, extend_sys_path 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._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): class TemplateLoaderTests(SimpleTestCase):
@ -393,114 +381,6 @@ class TemplateRegressionTests(SimpleTestCase):
self.assertIn("清風", t1.render(c1)) 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): class TemplateTagLoading(SimpleTestCase):
def setUp(self): def setUp(self):