test_basic.py 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316
  1. from django.conf import settings
  2. from django.template.base import Context, TemplateSyntaxError
  3. from django.template.loader import get_template
  4. from django.test import SimpleTestCase
  5. from .utils import render, setup, SilentGetItemClass, SilentAttrClass, SomeClass
  6. basic_templates = {
  7. 'basic-syntax01': 'something cool',
  8. 'basic-syntax02': '{{ headline }}',
  9. 'basic-syntax03': '{{ first }} --- {{ second }}',
  10. }
  11. class BasicSyntaxTests(SimpleTestCase):
  12. @setup(basic_templates)
  13. def test_basic_syntax01(self):
  14. """
  15. Plain text should go through the template parser untouched.
  16. """
  17. output = render('basic-syntax01')
  18. self.assertEqual(output, "something cool")
  19. @setup(basic_templates)
  20. def test_basic_syntax02(self):
  21. """
  22. Variables should be replaced with their value in the current
  23. context
  24. """
  25. output = render('basic-syntax02', {'headline': 'Success'})
  26. self.assertEqual(output, 'Success')
  27. @setup(basic_templates)
  28. def test_basic_syntax03(self):
  29. """
  30. More than one replacement variable is allowed in a template
  31. """
  32. output = render('basic-syntax03', {"first": 1, "second": 2})
  33. self.assertEqual(output, '1 --- 2')
  34. @setup({'basic-syntax04': 'as{{ missing }}df'})
  35. def test_basic_syntax04(self):
  36. """
  37. Fail silently when a variable is not found in the current context
  38. """
  39. output = render('basic-syntax04')
  40. if settings.TEMPLATE_STRING_IF_INVALID:
  41. self.assertEqual(output, 'asINVALIDdf')
  42. else:
  43. self.assertEqual(output, 'asdf')
  44. @setup({'basic-syntax06': '{{ multi word variable }}'})
  45. def test_basic_syntax06(self):
  46. """
  47. A variable may not contain more than one word
  48. """
  49. with self.assertRaises(TemplateSyntaxError):
  50. get_template('basic-syntax06')
  51. @setup({'basic-syntax07': '{{ }}'})
  52. def test_basic_syntax07(self):
  53. """
  54. Raise TemplateSyntaxError for empty variable tags.
  55. """
  56. with self.assertRaises(TemplateSyntaxError):
  57. get_template('basic-syntax07')
  58. @setup({'basic-syntax08': '{{ }}'})
  59. def test_basic_syntax08(self):
  60. """
  61. Raise TemplateSyntaxError for empty variable tags.
  62. """
  63. with self.assertRaises(TemplateSyntaxError):
  64. get_template('basic-syntax08')
  65. @setup({'basic-syntax09': '{{ var.method }}'})
  66. def test_basic_syntax09(self):
  67. """
  68. Attribute syntax allows a template to call an object's attribute
  69. """
  70. output = render('basic-syntax09', {'var': SomeClass()})
  71. self.assertEqual(output, 'SomeClass.method')
  72. @setup({'basic-syntax10': '{{ var.otherclass.method }}'})
  73. def test_basic_syntax10(self):
  74. """
  75. Multiple levels of attribute access are allowed.
  76. """
  77. output = render('basic-syntax10', {'var': SomeClass()})
  78. self.assertEqual(output, 'OtherClass.method')
  79. @setup({'basic-syntax11': '{{ var.blech }}'})
  80. def test_basic_syntax11(self):
  81. """
  82. Fail silently when a variable's attribute isn't found.
  83. """
  84. output = render('basic-syntax11', {'var': SomeClass()})
  85. if settings.TEMPLATE_STRING_IF_INVALID:
  86. self.assertEqual(output, 'INVALID')
  87. else:
  88. self.assertEqual(output, '')
  89. @setup({'basic-syntax12': '{{ var.__dict__ }}'})
  90. def test_basic_syntax12(self):
  91. """
  92. Raise TemplateSyntaxError when trying to access a variable
  93. beginning with an underscore.
  94. """
  95. with self.assertRaises(TemplateSyntaxError):
  96. get_template('basic-syntax12')
  97. # Raise TemplateSyntaxError when trying to access a variable
  98. # containing an illegal character.
  99. @setup({'basic-syntax13': "{{ va>r }}"})
  100. def test_basic_syntax13(self):
  101. with self.assertRaises(TemplateSyntaxError):
  102. get_template('basic-syntax13')
  103. @setup({'basic-syntax14': "{{ (var.r) }}"})
  104. def test_basic_syntax14(self):
  105. with self.assertRaises(TemplateSyntaxError):
  106. get_template('basic-syntax14')
  107. @setup({'basic-syntax15': "{{ sp%am }}"})
  108. def test_basic_syntax15(self):
  109. with self.assertRaises(TemplateSyntaxError):
  110. get_template('basic-syntax15')
  111. @setup({'basic-syntax16': "{{ eggs! }}"})
  112. def test_basic_syntax16(self):
  113. with self.assertRaises(TemplateSyntaxError):
  114. get_template('basic-syntax16')
  115. @setup({'basic-syntax17': "{{ moo? }}"})
  116. def test_basic_syntax17(self):
  117. with self.assertRaises(TemplateSyntaxError):
  118. get_template('basic-syntax17')
  119. @setup({'basic-syntax18': "{{ foo.bar }}"})
  120. def test_basic_syntax18(self):
  121. """
  122. Attribute syntax allows a template to call a dictionary key's
  123. value.
  124. """
  125. output = render('basic-syntax18', {"foo": {"bar": "baz"}})
  126. self.assertEqual(output, "baz")
  127. @setup({'basic-syntax19': "{{ foo.spam }}"})
  128. def test_basic_syntax19(self):
  129. """
  130. Fail silently when a variable's dictionary key isn't found.
  131. """
  132. output = render('basic-syntax19', {"foo": {"bar": "baz"}})
  133. if settings.TEMPLATE_STRING_IF_INVALID:
  134. self.assertEqual(output, 'INVALID')
  135. else:
  136. self.assertEqual(output, '')
  137. @setup({'basic-syntax20': "{{ var.method2 }}"})
  138. def test_basic_syntax20(self):
  139. """
  140. Fail silently when accessing a non-simple method
  141. """
  142. output = render('basic-syntax20', {'var': SomeClass()})
  143. if settings.TEMPLATE_STRING_IF_INVALID:
  144. self.assertEqual(output, 'INVALID')
  145. else:
  146. self.assertEqual(output, '')
  147. @setup({'basic-syntax20b': "{{ var.method5 }}"})
  148. def test_basic_syntax20b(self):
  149. """
  150. Don't silence a TypeError if it was raised inside a callable.
  151. """
  152. template = get_template('basic-syntax20b')
  153. with self.assertRaises(TypeError):
  154. template.render(Context({'var': SomeClass()}))
  155. # Don't get confused when parsing something that is almost, but not
  156. # quite, a template tag.
  157. @setup({'basic-syntax21': "a {{ moo %} b"})
  158. def test_basic_syntax21(self):
  159. output = render('basic-syntax21')
  160. self.assertEqual(output, "a {{ moo %} b")
  161. @setup({'basic-syntax22': "{{ moo #}"})
  162. def test_basic_syntax22(self):
  163. output = render('basic-syntax22')
  164. self.assertEqual(output, "{{ moo #}")
  165. @setup({'basic-syntax23': "{{ moo #} {{ cow }}"})
  166. def test_basic_syntax23(self):
  167. """
  168. Treat "moo #} {{ cow" as the variable. Not ideal, but costly to work
  169. around, so this triggers an error.
  170. """
  171. with self.assertRaises(TemplateSyntaxError):
  172. get_template('basic-syntax23')
  173. @setup({'basic-syntax24': "{{ moo\n }}"})
  174. def test_basic_syntax24(self):
  175. """
  176. Embedded newlines make it not-a-tag.
  177. """
  178. output = render('basic-syntax24')
  179. self.assertEqual(output, "{{ moo\n }}")
  180. # Literal strings are permitted inside variables, mostly for i18n
  181. # purposes.
  182. @setup({'basic-syntax25': '{{ "fred" }}'})
  183. def test_basic_syntax25(self):
  184. output = render('basic-syntax25')
  185. self.assertEqual(output, "fred")
  186. @setup({'basic-syntax26': r'{{ "\"fred\"" }}'})
  187. def test_basic_syntax26(self):
  188. output = render('basic-syntax26')
  189. self.assertEqual(output, "\"fred\"")
  190. @setup({'basic-syntax27': r'{{ _("\"fred\"") }}'})
  191. def test_basic_syntax27(self):
  192. output = render('basic-syntax27')
  193. self.assertEqual(output, "\"fred\"")
  194. # #12554 -- Make sure a silent_variable_failure Exception is
  195. # suppressed on dictionary and attribute lookup.
  196. @setup({'basic-syntax28': "{{ a.b }}"})
  197. def test_basic_syntax28(self):
  198. output = render('basic-syntax28', {'a': SilentGetItemClass()})
  199. if settings.TEMPLATE_STRING_IF_INVALID:
  200. self.assertEqual(output, 'INVALID')
  201. else:
  202. self.assertEqual(output, '')
  203. @setup({'basic-syntax29': "{{ a.b }}"})
  204. def test_basic_syntax29(self):
  205. output = render('basic-syntax29', {'a': SilentAttrClass()})
  206. if settings.TEMPLATE_STRING_IF_INVALID:
  207. self.assertEqual(output, 'INVALID')
  208. else:
  209. self.assertEqual(output, '')
  210. # Something that starts like a number but has an extra lookup works
  211. # as a lookup.
  212. @setup({'basic-syntax30': "{{ 1.2.3 }}"})
  213. def test_basic_syntax30(self):
  214. output = render(
  215. 'basic-syntax30',
  216. {"1": {"2": {"3": "d"}}}
  217. )
  218. self.assertEqual(output, 'd')
  219. @setup({'basic-syntax31': "{{ 1.2.3 }}"})
  220. def test_basic_syntax31(self):
  221. output = render(
  222. 'basic-syntax31',
  223. {"1": {"2": ("a", "b", "c", "d")}},
  224. )
  225. self.assertEqual(output, 'd')
  226. @setup({'basic-syntax32': "{{ 1.2.3 }}"})
  227. def test_basic_syntax32(self):
  228. output = render(
  229. 'basic-syntax32',
  230. {"1": (("x", "x", "x", "x"), ("y", "y", "y", "y"), ("a", "b", "c", "d"))},
  231. )
  232. self.assertEqual(output, 'd')
  233. @setup({'basic-syntax33': "{{ 1.2.3 }}"})
  234. def test_basic_syntax33(self):
  235. output = render(
  236. 'basic-syntax33',
  237. {"1": ("xxxx", "yyyy", "abcd")},
  238. )
  239. self.assertEqual(output, 'd')
  240. @setup({'basic-syntax34': "{{ 1.2.3 }}"})
  241. def test_basic_syntax34(self):
  242. output = render(
  243. 'basic-syntax34',
  244. {"1": ({"x": "x"}, {"y": "y"}, {"z": "z", "3": "d"})}
  245. )
  246. self.assertEqual(output, 'd')
  247. # Numbers are numbers even if their digits are in the context.
  248. @setup({'basic-syntax35': "{{ 1 }}"})
  249. def test_basic_syntax35(self):
  250. output = render('basic-syntax35', {"1": "abc"})
  251. self.assertEqual(output, '1')
  252. @setup({'basic-syntax36': "{{ 1.2 }}"})
  253. def test_basic_syntax36(self):
  254. output = render('basic-syntax36', {"1": "abc"})
  255. self.assertEqual(output, '1.2')
  256. @setup({'basic-syntax37': '{{ callable }}'})
  257. def test_basic_syntax37(self):
  258. """
  259. Call methods in the top level of the context.
  260. """
  261. output = render('basic-syntax37', {"callable": lambda: "foo bar"})
  262. self.assertEqual(output, 'foo bar')
  263. @setup({'basic-syntax38': '{{ var.callable }}'})
  264. def test_basic_syntax38(self):
  265. """
  266. Call methods returned from dictionary lookups.
  267. """
  268. output = render('basic-syntax38', {"var": {"callable": lambda: "foo bar"}})
  269. self.assertEqual(output, 'foo bar')