1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335
|
from django.template.base import TemplateSyntaxError
from django.template.context import Context
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')
|