""" Unit tests for template.py These tests assume the following template syntax: FILTER_SEPARATOR = '|' VARIABLE_ATTRIBUTE_SEPARATOR = '.' BLOCK_TAG_START = '{%' BLOCK_TAG_END = '%}' VARIABLE_TAG_START = '{{' VARIABLE_TAG_END = '}}' """ from django.core import template import unittest class RandomSyntaxErrorsCheck(unittest.TestCase): def testTagsOnOneLine(self): "Tags straddling more than one line are not interpreted" c = template.Context({'key':'value'}) t = template.Template('

{{key\n}}

') expected = '

{{key\n}}

' self.assertEqual(expected, t.render(c)) class PlainTextCheck(unittest.TestCase): def testPlainText(self): "Plain text should go through the template parser untouched" c = template.Context() t = template.Template('

Success

') expected = '

Success

' self.assertEqual(expected, t.render(c)) class VariableSubstitutionCheck(unittest.TestCase): def testSingleTag(self): "Variables should be replaced with their value in the current context" c = template.Context({'headline':'Success'}) t = template.Template('

{{headline}}

') expected = '

Success

' self.assertEqual(expected, t.render(c)) def testDoubleTag(self): "More than one replacement variable is allowed in a template" c = template.Context({'firsttag':'it', 'secondtag':'worked'}) t = template.Template('

{{firsttag}} {{secondtag}}

') expected = '

it worked

' self.assertEqual(expected, t.render(c)) def testNonexistentVariable(self): "Fail silently when a variable is not found in the current context" c = template.Context({}) t = template.Template('

{{unknownvar}}

') expected = '

' self.assertEqual(expected, t.render(c)) def testVariablesWithSpaces(self): "A replacement-variable tag may not contain more than one word" t = '

{{multi word tag}}

' self.assertRaises(template.TemplateSyntaxError, template.Template, t) def testEmptyTag(self): "Raise TemplateSyntaxError for empty variable tags" t = '{{ }}' self.assertRaises(template.TemplateSyntaxError, template.Template, t) t = '{{ }}' self.assertRaises(template.TemplateSyntaxError, template.Template, t) def testIntegerContextValue(self): "Accept integers as variable values" c = template.Context({'var':55}) t = template.Template('

{{var}}

') expected = '

55

' self.assertEqual(expected, t.render(c)) def textIntegerContextKey(self): "Accept integers as variable keys" c = template.Context({55:'var'}) t = template.Template('

{{55}}

') expected = '

var

' self.assertEqual(expected, t.render(c)) def testVariableAttributeAccess1(self): "Attribute syntax allows a template to call an object's attribute" class AClass: pass obj = AClass() obj.att = 'attvalue' c = template.Context({'var':obj}) t = template.Template('

{{ var.att }}

') expected = '

attvalue

' self.assertEqual(expected, t.render(c)) def testVariableAttributeAccess2(self): "Attribute syntax allows a template to call an object's attribute (with getattr defined)" class AClass: def __getattr__(self, attr): return "attvalue" obj = AClass() c = template.Context({'var':obj}) t = template.Template('

{{ var.att }}

') expected = '

attvalue

' self.assertEqual(expected, t.render(c)) def testVariableAttributeAccessMultiple(self): "Multiple levels of attribute access are allowed" class AClass: pass obj = AClass() obj.article = AClass() obj.article.section = AClass() obj.article.section.title = 'Headline' c = template.Context({'obj':obj}) t = template.Template('

{{ obj.article.section.title }}

') expected = '

Headline

' self.assertEqual(expected, t.render(c)) def testNonexistentVariableAttributeObject(self): "Fail silently when a variable's attribute isn't found" class AClass: pass obj = AClass() obj.att = 'attvalue' c = template.Context({'var':obj}) t = template.Template('

{{ var.nonexistentatt }}

') expected = '

' self.assertEqual(expected, t.render(c)) def testIllegalUnderscoreInVariableName(self): "Raise TemplateSyntaxError when trying to access a variable beginning with an underscore" t = '

{{ var._att }}

' self.assertRaises(template.TemplateSyntaxError, template.Template, t) t = '

{{ _att }}

' self.assertRaises(template.TemplateSyntaxError, template.Template, t) def testIllegalCharacterInVariableName(self): "Raise TemplateSyntaxError when trying to access a variable containing an illegal character" t = '

{{ (blah }}

' self.assertRaises(template.TemplateSyntaxError, template.Template, t) t = '

{{ (blah.test) }}

' self.assertRaises(template.TemplateSyntaxError, template.Template, t) t = '

{{ bl(ah.test) }}

' self.assertRaises(template.TemplateSyntaxError, template.Template, t) def testVariableAttributeDictionary(self): "Attribute syntax allows a template to call a dictionary key's value" obj = {'att':'attvalue'} c = template.Context({'var':obj}) t = template.Template('

{{ var.att }}

') expected = '

attvalue

' self.assertEqual(expected, t.render(c)) def testNonexistentVariableAttributeDictionary(self): "Fail silently when a variable's dictionary key isn't found" obj = {'att':'attvalue'} c = template.Context({'var':obj}) t = template.Template('

{{ var.nonexistentatt }}

') expected = '

' self.assertEqual(expected, t.render(c)) def testVariableAttributeCallable(self): "Attribute syntax allows a template to call a simple method" class AClass: def hello(self): return 'hi' obj = AClass() c = template.Context({'var':obj}) t = template.Template('

{{ var.hello }}

') expected = '

hi

' self.assertEqual(expected, t.render(c)) def testVariableAttributeCallableWrongArguments(self): "Fail silently when accessing a non-simple method" class AClass: def hello(self, name): return 'hi, %s' % name obj = AClass() c = template.Context({'var':obj}) t = template.Template('

{{ var.hello }}

') expected = '

' self.assertEqual(expected, t.render(c)) class VariableFiltersCheck(unittest.TestCase): def setUp(self): self.c = template.Context({'var':'Hello There Programmer'}) def tearDown(self): self.c = None def testUpper(self): "The 'upper' filter converts a string into all uppercase" t = template.Template('

{{ var|upper }}

') expected = '

HELLO THERE PROGRAMMER

' self.assertEqual(expected, t.render(self.c)) def testLower(self): "The 'lower' filter converts a string into all lowercase" t = template.Template('

{{ var|lower }}

') expected = '

hello there programmer

' self.assertEqual(expected, t.render(self.c)) def testUpperThenLower(self): "Filters may be applied in succession (upper|lower)" t = template.Template('

{{ var|upper|lower }}

') expected = '

hello there programmer

' self.assertEqual(expected, t.render(self.c)) def testLowerThenUpper(self): "Filters may be applied in succession (lower|upper)" t = template.Template('

{{ var|lower|upper }}

') expected = '

HELLO THERE PROGRAMMER

' self.assertEqual(expected, t.render(self.c)) def testSpaceBetweenVariableAndFilterPipe(self): "Raise TemplateSyntaxError for space between a variable and filter pipe" t = '

{{ var |lower }}

' self.assertRaises(template.TemplateSyntaxError, template.Template, t) def testSpaceBetweenFilterPipeAndFilterName1(self): "Raise TemplateSyntaxError for space after a filter pipe" t = '

{{ var| lower }}

' expected = '

Hello There Programmer

' self.assertRaises(template.TemplateSyntaxError, template.Template, t) def testNonexistentFilter(self): "Raise TemplateSyntaxError for a nonexistent filter" t = '

{{ var|nonexistentfilter }}

' self.assertRaises(template.TemplateSyntaxError, template.Template, t) def testDefaultFilter1(self): "Ignore the default argument when a variable passed through the 'default' filter already exists" c = template.Context({'var':'Variable'}) t = template.Template('

{{ var|default:"Default" }}

') expected = '

Variable

' self.assertEqual(expected, t.render(c)) def testDefaultFilter2(self): "Use the default argument when a variable passed through the 'default' filter doesn't exist" c = template.Context({'var':'Variable'}) t = template.Template('

{{ nonvar|default:"Default" }}

') expected = '

Default

' self.assertEqual(expected, t.render(c)) def testDefaultFilter3(self): "Use the default argument when a variable passed through the 'default' filter doesn't exist (spaces)" c = template.Context({'var':'Variable'}) t = template.Template('

{{ nonvar|default:"Default value" }}

') expected = '

Default value

' self.assertEqual(expected, t.render(c)) def testDefaultFilter4(self): "Use the default argument when a variable passed through the 'default' filter doesn't exist (quoted)" c = template.Context({'var':'Variable'}) t = template.Template('

{{ nonvar|default:"Default \"quoted\" value" }}

') expected = '

Default "quoted" value

' self.assertEqual(expected, t.render(c)) def testDefaultFilter4(self): "Use the default argument when a variable passed through the 'default' filter doesn't exist (escaped backslash)" c = template.Context({'var':'Variable'}) t = template.Template('

{{ nonvar|default:"Default \\\\ slash" }}

') expected = '

Default \\ slash

' self.assertEqual(expected, t.render(c)) def testDefaultFilter4(self): "Use the default argument when a variable passed through the 'default' filter doesn't exist (single backslash)" t = '

{{ nonvar|default:"Default \\ slash" }}

' self.assertRaises(template.TemplateSyntaxError, template.Template, t) def testIllegalCharacterInFilterName(self): "Raise TemplateSyntaxError when trying to access a filter containing an illegal character" t = '

{{ blah|(lower) }}

' self.assertRaises(template.TemplateSyntaxError, template.Template, t) t = '

{{ blah|low(er) }}

' self.assertRaises(template.TemplateSyntaxError, template.Template, t) class BlockTagCheck(unittest.TestCase): def testNonexistentTag(self): "Raise TemplateSyntaxError for invalid block tags" t = '

{% not-a-tag %}

' self.assertRaises(template.TemplateSyntaxError, template.Template, t) def testEmptyTag(self): "Raise TemplateSyntaxError for empty block tags" t = '{% %}' self.assertRaises(template.TemplateSyntaxError, template.Template, t) class FirstOfCheck(unittest.TestCase): def testFirstOfDisplaysFirstIfSet(self): "A firstof tag should display the first item if it evaluates to true somehow" c = template.Context({'first': 'one', 'second': 'two'}) t = template.Template('

{% firstof first second %}

') expected = '

one

' self.assertEqual(expected, t.render(c)) def testFirstOfDisplaysSecondIfFirstIsFalse(self): "A firstof tag should display the second item if it evaluates to true and the first is false" c = template.Context({'first': '', 'second': 'two'}) t = template.Template('

{% firstof first second %}

') expected = '

two

' self.assertEqual(expected, t.render(c)) def testFirstOfRaisesErrorIfEmpty(self): "A firstof tag should raise a syntax error if it doesn't have any arguments" t = '{% firstof %}' self.assertRaises(template.TemplateSyntaxError, template.Template, t) def testFirstOfDoesNothingIfAllAreFalse(self): "A firstof tag should display nothing if no arguments evaluate to true" c = template.Context({'first': '', 'second': False}) t = template.Template('

{% firstof first second third %}

') expected = '

' self.assertEqual(expected, t.render(c)) def testFirstOfWorksWithInts(self): "Can a firstof tag display an integer?" c = template.Context({'first': 1, 'second': False}) t = template.Template('

{% firstof first second %}

') expected = '

1

' self.assertEqual(expected, t.render(c)) class IfStatementCheck(unittest.TestCase): def testSingleIfStatementTrue(self): "An if statement should display its contents if the test evaluates true" c = template.Context({'test':True}) t = template.Template('

{% if test %}Yes{% endif %}

') expected = '

Yes

' self.assertEqual(expected, t.render(c)) def testSingleIfStatementFalse(self): "An if statement should not display its contents if the test is false" c = template.Context({'test':False}) t = template.Template('

{% if test %}Should not see this{% endif %}

') expected = '

' self.assertEqual(expected, t.render(c)) def testNestedIfStatementTrueThenTrue(self): "Nested if statements should work properly (case 1)" c = template.Context({'test1':True, 'test2':True}) t = template.Template('

{% if test1 %} First {% if test2 %} Second {% endif %} First again {% endif %}

') expected = '

First Second First again

' self.assertEqual(expected, t.render(c)) def testNestedIfStatementTrueThenFalse(self): "Nested if statements should work properly (case 2)" c = template.Context({'test1':True, 'test2':False}) t = template.Template('

{% if test1 %} First {% if test2 %} Second {% endif %} First again {% endif %}

') expected = '

First First again

' self.assertEqual(expected, t.render(c)) def testNestedIfStatementFalseThenTrue(self): "Nested if statements should work properly (case 3)" c = template.Context({'test1':False, 'test2':True}) t = template.Template('

{% if test1 %} First {% if test2 %} Second {% endif %} First again {% endif %}

') expected = '

' self.assertEqual(expected, t.render(c)) def testNestedIfStatementFalseThenFalse(self): "Nested if statements should work properly (case 4)" c = template.Context({'test1':False, 'test2':False}) t = template.Template('

{% if test1 %} First {% if test2 %} Second {% endif %} First again {% endif %}

') expected = '

' self.assertEqual(expected, t.render(c)) def testElseIfTrue(self): "An else statement should not execute if the test evaluates to true" c = template.Context({'test':True}) t = template.Template('

{% if test %}Correct{% else %}Incorrect{% endif %}

') expected = '

Correct

' self.assertEqual(expected, t.render(c)) def testElseIfFalse(self): "An else statement should execute if the test evaluates to false" c = template.Context({'test':False}) t = template.Template('

{% if test %}Incorrect{% else %}Correct{% endif %}

') expected = '

Correct

' self.assertEqual(expected, t.render(c)) def testNonClosedIfTag(self): "Raise TemplateSyntaxError for non-closed 'if' tags" c = template.Context({'test':True}) t = '

{% if test %}

' self.assertRaises(template.TemplateSyntaxError, template.Template, t) def testNonexistentTest(self): "Fail silently when an if statement accesses a nonexistent test" c = template.Context({'var':'value'}) t = template.Template('

{% if nonexistent %}Hello{% endif %}

') expected = '

' self.assertEqual(expected, t.render(c)) def testIfTagNoArgs(self): "If statements must have one argument (case 1)" t = '

{% if %}Hello{% endif %}

' self.assertRaises(template.TemplateSyntaxError, template.Template, t) def testIfTagManyArgs(self): "If statements must have one argument (case 2)" t = '

{% if multiple tests %}Hello{% endif %}

' self.assertRaises(template.TemplateSyntaxError, template.Template, t) def testAttributeAccessInIfNode(self): "An if node should resolve a variable's attributes before checking it as a test" class AClass: pass obj = AClass() obj.article = AClass() obj.article.section = AClass() obj.article.section.title = 'Headline' c = template.Context({'obj':obj}) t = template.Template('

{% if obj.article.section.title %}Hello{% endif %}

') expected = '

Hello

' self.assertEqual(expected, t.render(c)) t = template.Template('

{% if obj.article.section.not_here %}Hello{% endif %}

') expected = '

' self.assertEqual(expected, t.render(c)) def testIfNot(self): "If statements supports 'not' as an optional argument" t = template.Template('{% if not a %}Not a{% endif %}') c = template.Context({'a': False}) expected = 'Not a' self.assertEqual(expected, t.render(c)) c['a'] = True expected = '' self.assertEqual(expected, t.render(c)) def testIfOr(self): "If statements support 'or'" t = template.Template('{% if a or b %}Hello{% endif %}') c = template.Context({'a': False, 'b': True}) expected = 'Hello' self.assertEqual(expected, t.render(c)) c['b'] = False expected = '' self.assertEqual(expected, t.render(c)) def testIfOrNot(self): "If statements support 'or' clauses with optional 'not's" t = template.Template('{% if a or not b or c%}Hello{% endif %}') c = template.Context({'a': False, 'b': False, 'c': False}) expected = 'Hello' self.assertEqual(expected, t.render(c)) c['b'] = True expected = '' self.assertEqual(expected, t.render(c)) class ForLoopCheck(unittest.TestCase): def testNormalForLoop(self): "A for loop should work as expected, given one or more values" c = template.Context({'pieces': ('1', '2', '3')}) t = template.Template('

{% for piece in pieces %}{{ piece }}{% endfor %}

') expected = '

123

' self.assertEqual(expected, t.render(c)) def testBlankForLoop(self): "A for loop should work as expected, given an empty list" c = template.Context({'pieces': []}) t = template.Template('

{% for piece in pieces %}{{ piece }}{% endfor %}

') expected = '

' self.assertEqual(expected, t.render(c)) def testInvalidForTagFourWords(self): "Raise TemplateSyntaxError if a 'for' statement is not exactly 4 words" t = '

{% for article %}

' self.assertRaises(template.TemplateSyntaxError, template.Template, t) def testInvalidForTagThirdWord(self): "Raise TemplateSyntaxError if 3rd word in a 'for' statement isn't 'in'" t = '

{% for article NOTIN blah %}{% endfor %}

' self.assertRaises(template.TemplateSyntaxError, template.Template, t) def testNonClosedForTag(self): "Raise TemplateSyntaxError for non-closed 'for' tags" t = '

{% for i in numbers %}{{ i }}

' self.assertRaises(template.TemplateSyntaxError, template.Template, t) def testNonexistentVariable1(self): "Fail silently in loops with nonexistent variables in defn" c = template.Context({'var':'value'}) t = template.Template('

{% for i in nonexistent %}

{{ var }}

{% endfor %}

') expected = '

' self.assertEqual(expected, t.render(c)) def testNonexistentVariable2(self): "Raise TemplateSyntaxError in loops with nonexistent variables in loop" c = template.Context({'set':('val1', 'val2')}) t = template.Template('

{% for i in set %}

{{ nonexistent }}

{% endfor %}

') expected = '

' self.assertEqual(expected, t.render(c)) def testAttributeAccessInForNode(self): "A for node should resolve a variable's attributes before looping through it" c = template.Context({'article': {'authors':('Simon', 'Adrian')}}) t = template.Template('

{% for i in article.authors %}{{ i }}{% endfor %}

') self.assertEqual('

SimonAdrian

', t.render(c)) t = template.Template('

{% for i in article.nonexistent %}{{ i }}{% endfor %}

') self.assertEqual('

', t.render(c)) def testForLoopFirst(self): "A for loop's 'first' variable should work as expected" c = template.Context({'pieces': ('1', '2', '3')}) t = template.Template('

{% for piece in pieces %}{% if forloop.first %}

First

{% endif %}{{ piece }}{% endfor %}') expected = '

First

123' self.assertEqual(expected, t.render(c)) def testForLoopLast(self): "A for loop's 'last' variable should work as expected" c = template.Context({'pieces': ('1', '2', '3')}) t = template.Template('

{% for piece in pieces %}{% if forloop.last %}

Last

{% endif %}{{ piece }}{% endfor %}') expected = '

12

Last

3' self.assertEqual(expected, t.render(c)) class CycleNodeCheck(unittest.TestCase): def testNormalUsage(self): "A cycle tag should work as expected" c = template.Context({'set':range(10)}) t = template.Template('{% for i in set %}{% cycle red, green %}-{{ i }} {% endfor %}') expected = 'red-0 green-1 red-2 green-3 red-4 green-5 red-6 green-7 red-8 green-9 ' self.assertEqual(expected, t.render(c)) def testNoArguments(self): "Raise TemplateSyntaxError in cycle tags with no arguments" t = '{% cycle %}' self.assertRaises(template.TemplateSyntaxError, template.Template, t) def testOneArgument(self): "Raise TemplateSyntaxError in cycle tags with only one argument" t = '{% cycle hello %}' self.assertRaises(template.TemplateSyntaxError, template.Template, t) def testExtraInitialSpaces(self): "Extra spaces around cycle tags and their arguments should be ignored" c = template.Context({'set':range(5)}) t = template.Template('{% for i in set %}{% cycle red, green %}{% endfor %}') expected = 'redgreenredgreenred' self.assertEqual(expected, t.render(c)) class TemplateTagNodeCheck(unittest.TestCase): def testNormalUsage(self): "A templatetag tag should work as expected" c = template.Context() t = template.Template('{% templatetag openblock %}{% templatetag closeblock %}{% templatetag openvariable %}{% templatetag closevariable %}') expected = '{%%}{{}}' self.assertEqual(expected, t.render(c)) def testNoArguments(self): "Raise TemplateSyntaxError in templatetag tags with no arguments" t = '{% templatetag %}' self.assertRaises(template.TemplateSyntaxError, template.Template, t) def testTwoArguments(self): "Raise TemplateSyntaxError in templatetag tags with more than one argument" t = '{% templatetag hello goodbye %}' self.assertRaises(template.TemplateSyntaxError, template.Template, t) t = '{% templatetag hello goodbye helloagain %}' self.assertRaises(template.TemplateSyntaxError, template.Template, t) def testBadArgument(self): "Raise TemplateSyntaxError in templatetag tags with invalid arguments" t = '{% templatetag hello %}' self.assertRaises(template.TemplateSyntaxError, template.Template, t) class PluginFilterCheck(unittest.TestCase): def custom_filter(self, value, arg): "Temporary filter used to verify the filter plugin system is working" return "_%s_%s_" % (value, arg) def testPluginFilter(self): "Plugin support allows for custom filters" template.register_filter('unittest', self.custom_filter, True) c = template.Context({'var':'value'}) t = template.Template('{{ var|unittest:"hello" }}') expected = '_value_hello_' self.assertEqual(expected, t.render(c)) template.unregister_filter('unittest') def testUnregisterPluginFilter(self): "Plugin support allows custom filters to be unregistered" template.register_filter('unittest', self.custom_filter, True) c = template.Context({'var':'value'}) t = template.Template('{{ var|unittest:"hello" }}') rendered = t.render(c) # should run with no exception template.unregister_filter('unittest') class PluginTagCheck(unittest.TestCase): class CustomNode(template.Node): "Prints argument" def __init__(self, arg): self.arg = arg def render(self, context): return '_%s_' % self.arg def do_custom_node(self, parser, token): "Handle the 'unittest' custom tag" bits = token.contents.split() return self.CustomNode(bits[1]) def testPluginTag(self): "Plugin support allows for custom tags" template.register_tag('unittest', self.do_custom_node) c = template.Context({}) t = template.Template('{% unittest hello %}') expected = '_hello_' self.assertEqual(expected, t.render(c)) template.unregister_tag('unittest') def testUnregisterPluginTag(self): "Plugin support allows custom tags to be unregistered" template.register_tag('unittest', self.do_custom_node) c = template.Context({}) t = template.Template('{% unittest hello %}') rendered = t.render(c) # should run with no exception del(t) template.unregister_tag('unittest') t = '{% unittest hello %}' self.assertRaises(template.TemplateSyntaxError, template.Template, t) class ContextUsageCheck(unittest.TestCase): def testVariableContext2(self): "Variables should fall through additional block-level contexts" c = template.Context({'global':'out', 'set': ('1', '2', '3')}) t = template.Template('

{{ global }}

{% for i in set %}

{{ i }} {{ global }}

{% endfor %}') expected = '

out

1 out

2 out

3 out

' self.assertEqual(expected, t.render(c)) def testVariableContext2(self): "Variables set within a block statement override like-named variables within their scope" c = template.Context({'i':'out', 'set': ('1', '2', '3')}) t = template.Template('

{{ i }}

{% for i in set %}

{{ i }}

{% endfor %}{{ i }}') expected = '

out

1

2

3

out' self.assertEqual(expected, t.render(c)) def testVariableContextDelete(self): "Variables can be deleted from the current context" c = template.Context({'a':'first', 'b':'second'}) del c['a'] self.assertEqual(c.__repr__(), template.Context({'b':'second'}).__repr__()) def testInvalidVariableContextDelete(self): "Raise KeyError if code tries to delete a variable that doesn't exist in the current context" c = template.Context({'a':'first'}) self.assertRaises(KeyError, c.__delitem__, 'b') class AdvancedUsageCheck(unittest.TestCase): def testIfInsideFor(self): "An if statement should be executed repeatedly inside a for statement" c = template.Context({'set':(True, False, True, True, False)}) t = template.Template('') expected = '' self.assertEqual(expected, t.render(c)) def testIfElseInsideFor(self): "An if/else statement should be executed repeatedly inside a for statement" c = template.Context({'set':(True, False, True, True, False)}) t = template.Template('') expected = '' self.assertEqual(expected, t.render(c)) def testForInsideIf_True(self): "A for loop inside an if statement should be executed if the test=true" c = template.Context({'test':True, 'set':('1', '2', '3')}) t = template.Template('{% if test %}{% endif %}') expected = '' self.assertEqual(expected, t.render(c)) def testForInsideIf_False(self): "A for loop inside an if statement shouldn't be executed if the test=false" c = template.Context({'test':False, 'set':('1', '2', '3')}) t = template.Template('{% if test %}{% endif %}') expected = '' self.assertEqual(expected, t.render(c)) def testForInsideIfInsideFor(self): "A for loop inside an if statement inside a for loop should work properly" c = template.Context({'set1': (True, False, False, False, True), 'set2': ('1', '2', '3')}) t = template.Template('{% for i in set1 %}{% if i %}{% for j in set2 %}{{ j }}{% endfor %}{% endif %}{% endfor %}') expected = '123123' self.assertEqual(expected, t.render(c)) def testMultipleRendersWhenCompiled(self): "A template can render multiple contexts without having to be recompiled" t = template.Template('{% for i in set1 %}{% if i %}{% for j in set2 %}{{ j }}{% endfor %}{% endif %}{% endfor %}') c = template.Context({'set1': (True, False, False, False, False), 'set2': ('1', '2', '3')}) self.assertEqual('123', t.render(c)) c = template.Context({'set1': (True, True, False, False, False), 'set2': ('1', '2', '3')}) self.assertEqual('123123', t.render(c)) c = template.Context({'set1': (True, True, True, False, False), 'set2': ('1', '2', '3')}) self.assertEqual('123123123', t.render(c)) c = template.Context({'set1': (True, True, True, True, False), 'set2': ('1', '2', '3')}) self.assertEqual('123123123123', t.render(c)) c = template.Context({'set1': (True, True, True, True, True), 'set2': ('1', '2', '3')}) self.assertEqual('123123123123123', t.render(c)) def tests(): s = unittest.TestLoader().loadTestsFromName(__name__) unittest.TextTestRunner(verbosity=0).run(s) if __name__ == "__main__": tests()