- from django.template.base import TemplateSyntaxError 
- from django.template.context import Context 
- from django.template.loader_tags import BlockContext, BlockNode 
- from django.test import SimpleTestCase 
- from ..utils import SilentAttrClass, SilentGetItemClass, SomeClass, setup 
- basic_templates = {
- "basic-syntax01": "something cool", 
- "basic-syntax02": "{{ headline }}", 
- "basic-syntax03": "{{ first }} --- {{ second }}", 
- }
- class BasicSyntaxTests(SimpleTestCase): 
- @setup(basic_templates) 
- def test_basic_syntax01(self): 
- """ 
- Plain text should go through the template parser untouched.
- """
- output = self.engine.render_to_string("basic-syntax01") 
- self.assertEqual(output, "something cool") 
- @setup(basic_templates) 
- def test_basic_syntax02(self): 
- """ 
- Variables should be replaced with their value in the current
- context
- """
- output = self.engine.render_to_string("basic-syntax02", {"headline": "Success"}) 
- self.assertEqual(output, "Success") 
- @setup(basic_templates) 
- def test_basic_syntax03(self): 
- """ 
- More than one replacement variable is allowed in a template
- """
- output = self.engine.render_to_string( 
- "basic-syntax03", {"first": 1, "second": 2} 
- )
- self.assertEqual(output, "1 --- 2") 
- @setup({"basic-syntax04": "as{{ missing }}df"}) 
- def test_basic_syntax04(self): 
- """ 
- Fail silently when a variable is not found in the current context
- """
- output = self.engine.render_to_string("basic-syntax04") 
- if self.engine.string_if_invalid: 
- self.assertEqual(output, "asINVALIDdf") 
- else: 
- self.assertEqual(output, "asdf") 
- @setup({"basic-syntax06": "{{ multi word variable }}"}) 
- def test_basic_syntax06(self): 
- """ 
- A variable may not contain more than one word
- """
- with self.assertRaises(TemplateSyntaxError): 
- self.engine.get_template("basic-syntax06") 
- @setup({"basic-syntax07": "{{ }}"}) 
- def test_basic_syntax07(self): 
- """ 
- Raise TemplateSyntaxError for empty variable tags.
- """
- with self.assertRaisesMessage( 
- TemplateSyntaxError, "Empty variable tag on line 1" 
- ):
- self.engine.get_template("basic-syntax07") 
- @setup({"basic-syntax08": "{{ }}"}) 
- def test_basic_syntax08(self): 
- """ 
- Raise TemplateSyntaxError for empty variable tags.
- """
- with self.assertRaisesMessage( 
- TemplateSyntaxError, "Empty variable tag on line 1" 
- ):
- self.engine.get_template("basic-syntax08") 
- @setup({"basic-syntax09": "{{ var.method }}"}) 
- def test_basic_syntax09(self): 
- """ 
- Attribute syntax allows a template to call an object's attribute
- """
- output = self.engine.render_to_string("basic-syntax09", {"var": SomeClass()}) 
- self.assertEqual(output, "SomeClass.method") 
- @setup({"basic-syntax10": "{{ var.otherclass.method }}"}) 
- def test_basic_syntax10(self): 
- """ 
- Multiple levels of attribute access are allowed.
- """
- output = self.engine.render_to_string("basic-syntax10", {"var": SomeClass()}) 
- self.assertEqual(output, "OtherClass.method") 
- @setup({"basic-syntax11": "{{ var.blech }}"}) 
- def test_basic_syntax11(self): 
- """ 
- Fail silently when a variable's attribute isn't found.
- """
- output = self.engine.render_to_string("basic-syntax11", {"var": SomeClass()}) 
- if self.engine.string_if_invalid: 
- self.assertEqual(output, "INVALID") 
- else: 
- self.assertEqual(output, "") 
- @setup({"basic-syntax12": "{{ var.__dict__ }}"}) 
- def test_basic_syntax12(self): 
- """ 
- Raise TemplateSyntaxError when trying to access a variable
- beginning with an underscore.
- """
- with self.assertRaises(TemplateSyntaxError): 
- self.engine.get_template("basic-syntax12") 
- # Raise TemplateSyntaxError when trying to access a variable 
- # containing an illegal character. 
- @setup({"basic-syntax13": "{{ va>r }}"}) 
- def test_basic_syntax13(self): 
- with self.assertRaises(TemplateSyntaxError): 
- self.engine.get_template("basic-syntax13") 
- @setup({"basic-syntax14": "{{ (var.r) }}"}) 
- def test_basic_syntax14(self): 
- with self.assertRaises(TemplateSyntaxError): 
- self.engine.get_template("basic-syntax14") 
- @setup({"basic-syntax15": "{{ sp%am }}"}) 
- def test_basic_syntax15(self): 
- with self.assertRaises(TemplateSyntaxError): 
- self.engine.get_template("basic-syntax15") 
- @setup({"basic-syntax16": "{{ eggs! }}"}) 
- def test_basic_syntax16(self): 
- with self.assertRaises(TemplateSyntaxError): 
- self.engine.get_template("basic-syntax16") 
- @setup({"basic-syntax17": "{{ moo? }}"}) 
- def test_basic_syntax17(self): 
- with self.assertRaises(TemplateSyntaxError): 
- self.engine.get_template("basic-syntax17") 
- @setup({"basic-syntax18": "{{ foo.bar }}"}) 
- def test_basic_syntax18(self): 
- """ 
- Attribute syntax allows a template to call a dictionary key's
- value.
- """
- output = self.engine.render_to_string("basic-syntax18", {"foo": {"bar": "baz"}}) 
- self.assertEqual(output, "baz") 
- @setup({"basic-syntax19": "{{ foo.spam }}"}) 
- def test_basic_syntax19(self): 
- """ 
- Fail silently when a variable's dictionary key isn't found.
- """
- output = self.engine.render_to_string("basic-syntax19", {"foo": {"bar": "baz"}}) 
- if self.engine.string_if_invalid: 
- self.assertEqual(output, "INVALID") 
- else: 
- self.assertEqual(output, "") 
- @setup({"basic-syntax20": "{{ var.method2 }}"}) 
- def test_basic_syntax20(self): 
- """ 
- Fail silently when accessing a non-simple method
- """
- output = self.engine.render_to_string("basic-syntax20", {"var": SomeClass()}) 
- if self.engine.string_if_invalid: 
- self.assertEqual(output, "INVALID") 
- else: 
- self.assertEqual(output, "") 
- @setup({"basic-syntax20b": "{{ var.method5 }}"}) 
- def test_basic_syntax20b(self): 
- """ 
- Don't silence a TypeError if it was raised inside a callable.
- """
- template = self.engine.get_template("basic-syntax20b") 
- with self.assertRaises(TypeError): 
- template.render(Context({"var": SomeClass()})) 
- # Don't get confused when parsing something that is almost, but not 
- # quite, a template tag. 
- @setup({"basic-syntax21": "a {{ moo %} b"}) 
- def test_basic_syntax21(self): 
- output = self.engine.render_to_string("basic-syntax21") 
- self.assertEqual(output, "a {{ moo %} b") 
- @setup({"basic-syntax22": "{{ moo #}"}) 
- def test_basic_syntax22(self): 
- output = self.engine.render_to_string("basic-syntax22") 
- self.assertEqual(output, "{{ moo #}") 
- @setup({"basic-syntax23": "{{ moo #} {{ cow }}"}) 
- def test_basic_syntax23(self): 
- """ 
- Treat "moo #} {{ cow" as the variable. Not ideal, but costly to work
- around, so this triggers an error.
- """
- with self.assertRaises(TemplateSyntaxError): 
- self.engine.get_template("basic-syntax23") 
- @setup({"basic-syntax24": "{{ moo\n }}"}) 
- def test_basic_syntax24(self): 
- """ 
- Embedded newlines make it not-a-tag.
- """
- output = self.engine.render_to_string("basic-syntax24") 
- self.assertEqual(output, "{{ moo\n }}") 
- # Literal strings are permitted inside variables, mostly for i18n 
- # purposes. 
- @setup({"basic-syntax25": '{{ "fred" }}'}) 
- def test_basic_syntax25(self): 
- output = self.engine.render_to_string("basic-syntax25") 
- self.assertEqual(output, "fred") 
- @setup({"basic-syntax26": r'{{ "\"fred\"" }}'}) 
- def test_basic_syntax26(self): 
- output = self.engine.render_to_string("basic-syntax26") 
- self.assertEqual(output, '"fred"') 
- @setup({"basic-syntax27": r'{{ _("\"fred\"") }}'}) 
- def test_basic_syntax27(self): 
- output = self.engine.render_to_string("basic-syntax27") 
- self.assertEqual(output, '"fred"') 
- # #12554 -- Make sure a silent_variable_failure Exception is 
- # suppressed on dictionary and attribute lookup. 
- @setup({"basic-syntax28": "{{ a.b }}"}) 
- def test_basic_syntax28(self): 
- output = self.engine.render_to_string( 
- "basic-syntax28", {"a": SilentGetItemClass()} 
- )
- if self.engine.string_if_invalid: 
- self.assertEqual(output, "INVALID") 
- else: 
- self.assertEqual(output, "") 
- @setup({"basic-syntax29": "{{ a.b }}"}) 
- def test_basic_syntax29(self): 
- output = self.engine.render_to_string( 
- "basic-syntax29", {"a": SilentAttrClass()} 
- )
- if self.engine.string_if_invalid: 
- self.assertEqual(output, "INVALID") 
- else: 
- self.assertEqual(output, "") 
- # Something that starts like a number but has an extra lookup works 
- # as a lookup. 
- @setup({"basic-syntax30": "{{ 1.2.3 }}"}) 
- def test_basic_syntax30(self): 
- output = self.engine.render_to_string( 
- "basic-syntax30", {"1": {"2": {"3": "d"}}} 
- )
- self.assertEqual(output, "d") 
- @setup({"basic-syntax31": "{{ 1.2.3 }}"}) 
- def test_basic_syntax31(self): 
- output = self.engine.render_to_string( 
- "basic-syntax31", 
- {"1": {"2": ("a", "b", "c", "d")}}, 
- )
- self.assertEqual(output, "d") 
- @setup({"basic-syntax32": "{{ 1.2.3 }}"}) 
- def test_basic_syntax32(self): 
- output = self.engine.render_to_string( 
- "basic-syntax32", 
- {"1": (("x", "x", "x", "x"), ("y", "y", "y", "y"), ("a", "b", "c", "d"))}, 
- )
- self.assertEqual(output, "d") 
- @setup({"basic-syntax33": "{{ 1.2.3 }}"}) 
- def test_basic_syntax33(self): 
- output = self.engine.render_to_string( 
- "basic-syntax33", 
- {"1": ("xxxx", "yyyy", "abcd")}, 
- )
- self.assertEqual(output, "d") 
- @setup({"basic-syntax34": "{{ 1.2.3 }}"}) 
- def test_basic_syntax34(self): 
- output = self.engine.render_to_string( 
- "basic-syntax34", {"1": ({"x": "x"}, {"y": "y"}, {"z": "z", "3": "d"})} 
- )
- self.assertEqual(output, "d") 
- # Numbers are numbers even if their digits are in the context. 
- @setup({"basic-syntax35": "{{ 1 }}"}) 
- def test_basic_syntax35(self): 
- output = self.engine.render_to_string("basic-syntax35", {"1": "abc"}) 
- self.assertEqual(output, "1") 
- @setup({"basic-syntax36": "{{ 1.2 }}"}) 
- def test_basic_syntax36(self): 
- output = self.engine.render_to_string("basic-syntax36", {"1": "abc"}) 
- self.assertEqual(output, "1.2") 
- @setup({"basic-syntax37": "{{ callable }}"}) 
- def test_basic_syntax37(self): 
- """ 
- Call methods in the top level of the context.
- """
- output = self.engine.render_to_string( 
- "basic-syntax37", {"callable": lambda: "foo bar"} 
- )
- self.assertEqual(output, "foo bar") 
- @setup({"basic-syntax38": "{{ var.callable }}"}) 
- def test_basic_syntax38(self): 
- """ 
- Call methods returned from dictionary lookups.
- """
- output = self.engine.render_to_string( 
- "basic-syntax38", {"var": {"callable": lambda: "foo bar"}} 
- )
- self.assertEqual(output, "foo bar") 
- @setup({"template": "{% block content %}"}) 
- def test_unclosed_block(self): 
- msg = "Unclosed tag on line 1: 'block'. Looking for one of: endblock." 
- with self.assertRaisesMessage(TemplateSyntaxError, msg): 
- self.engine.render_to_string("template") 
- @setup({"template": "{% if a %}"}) 
- def test_unclosed_block2(self): 
- msg = "Unclosed tag on line 1: 'if'. Looking for one of: elif, else, endif." 
- with self.assertRaisesMessage(TemplateSyntaxError, msg): 
- self.engine.render_to_string("template") 
- @setup({"tpl-str": "%s", "tpl-percent": "%%", "tpl-weird-percent": "% %s"}) 
- def test_ignores_strings_that_look_like_format_interpolation(self): 
- output = self.engine.render_to_string("tpl-str") 
- self.assertEqual(output, "%s") 
- output = self.engine.render_to_string("tpl-percent") 
- self.assertEqual(output, "%%") 
- output = self.engine.render_to_string("tpl-weird-percent") 
- self.assertEqual(output, "% %s") 
- class BlockContextTests(SimpleTestCase): 
- def test_repr(self): 
- block_context = BlockContext() 
- block_context.add_blocks({"content": BlockNode("content", [])}) 
- self.assertEqual( 
- repr(block_context), 
- "<BlockContext: blocks=defaultdict(<class 'list'>, " 
- "{'content': [<Block Node: content. Contents: []>]})>", 
- )