tests.py 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191
  1. import sys
  2. from django.template import (
  3. Context, Engine, TemplateDoesNotExist, TemplateSyntaxError,
  4. )
  5. from django.template.base import UNKNOWN_SOURCE
  6. from django.test import SimpleTestCase, override_settings
  7. from django.urls import NoReverseMatch
  8. from django.utils import translation
  9. from django.utils.html import escape
  10. class TemplateTestMixin:
  11. def _engine(self, **kwargs):
  12. return Engine(debug=self.debug_engine, **kwargs)
  13. def test_string_origin(self):
  14. template = self._engine().from_string('string template')
  15. self.assertEqual(template.origin.name, UNKNOWN_SOURCE)
  16. self.assertIsNone(template.origin.loader_name)
  17. self.assertEqual(template.source, 'string template')
  18. @override_settings(SETTINGS_MODULE=None)
  19. def test_url_reverse_no_settings_module(self):
  20. """
  21. #9005 -- url tag shouldn't require settings.SETTINGS_MODULE to
  22. be set.
  23. """
  24. t = self._engine().from_string('{% url will_not_match %}')
  25. c = Context()
  26. with self.assertRaises(NoReverseMatch):
  27. t.render(c)
  28. def test_url_reverse_view_name(self):
  29. """
  30. #19827 -- url tag should keep original strack trace when reraising
  31. exception.
  32. """
  33. t = self._engine().from_string('{% url will_not_match %}')
  34. c = Context()
  35. try:
  36. t.render(c)
  37. except NoReverseMatch:
  38. tb = sys.exc_info()[2]
  39. depth = 0
  40. while tb.tb_next is not None:
  41. tb = tb.tb_next
  42. depth += 1
  43. self.assertGreater(depth, 5, "The traceback context was lost when reraising the traceback.")
  44. def test_no_wrapped_exception(self):
  45. """
  46. # 16770 -- The template system doesn't wrap exceptions, but annotates
  47. them.
  48. """
  49. engine = self._engine()
  50. c = Context({"coconuts": lambda: 42 / 0})
  51. t = engine.from_string("{{ coconuts }}")
  52. with self.assertRaises(ZeroDivisionError) as e:
  53. t.render(c)
  54. if self.debug_engine:
  55. debug = e.exception.template_debug
  56. self.assertEqual(debug['start'], 0)
  57. self.assertEqual(debug['end'], 14)
  58. def test_invalid_block_suggestion(self):
  59. """
  60. Error messages should include the unexpected block name and be in all
  61. English.
  62. """
  63. engine = self._engine()
  64. msg = (
  65. "Invalid block tag on line 1: 'endblock', expected 'elif', 'else' "
  66. "or 'endif'. Did you forget to register or load this tag?"
  67. )
  68. with self.settings(USE_I18N=True), translation.override('de'):
  69. with self.assertRaisesMessage(TemplateSyntaxError, msg):
  70. engine.from_string("{% if 1 %}lala{% endblock %}{% endif %}")
  71. def test_unknown_block_tag(self):
  72. engine = self._engine()
  73. msg = (
  74. "Invalid block tag on line 1: 'foobar'. Did you forget to "
  75. "register or load this tag?"
  76. )
  77. with self.assertRaisesMessage(TemplateSyntaxError, msg):
  78. engine.from_string("lala{% foobar %}")
  79. def test_compile_filter_expression_error(self):
  80. """
  81. 19819 -- Make sure the correct token is highlighted for
  82. FilterExpression errors.
  83. """
  84. engine = self._engine()
  85. msg = "Could not parse the remainder: '@bar' from 'foo@bar'"
  86. with self.assertRaisesMessage(TemplateSyntaxError, msg) as e:
  87. engine.from_string("{% if 1 %}{{ foo@bar }}{% endif %}")
  88. if self.debug_engine:
  89. debug = e.exception.template_debug
  90. self.assertEqual((debug['start'], debug['end']), (10, 23))
  91. self.assertEqual((debug['during']), '{{ foo@bar }}')
  92. def test_compile_tag_error(self):
  93. """
  94. Errors raised while compiling nodes should include the token
  95. information.
  96. """
  97. engine = self._engine(
  98. libraries={'bad_tag': 'template_tests.templatetags.bad_tag'},
  99. )
  100. with self.assertRaises(RuntimeError) as e:
  101. engine.from_string("{% load bad_tag %}{% badtag %}")
  102. if self.debug_engine:
  103. self.assertEqual(e.exception.template_debug['during'], '{% badtag %}')
  104. def test_compile_tag_error_27584(self):
  105. engine = self._engine(
  106. app_dirs=True,
  107. libraries={'tag_27584': 'template_tests.templatetags.tag_27584'},
  108. )
  109. t = engine.get_template('27584_parent.html')
  110. with self.assertRaises(TemplateSyntaxError) as e:
  111. t.render(Context())
  112. if self.debug_engine:
  113. self.assertEqual(e.exception.template_debug['during'], '{% badtag %}')
  114. def test_compile_tag_error_27956(self):
  115. """Errors in a child of {% extends %} are displayed correctly."""
  116. engine = self._engine(
  117. app_dirs=True,
  118. libraries={'tag_27584': 'template_tests.templatetags.tag_27584'},
  119. )
  120. t = engine.get_template('27956_child.html')
  121. with self.assertRaises(TemplateSyntaxError) as e:
  122. t.render(Context())
  123. if self.debug_engine:
  124. self.assertEqual(e.exception.template_debug['during'], '{% badtag %}')
  125. def test_render_tag_error_in_extended_block(self):
  126. """Errors in extended block are displayed correctly."""
  127. e = self._engine(app_dirs=True)
  128. template = e.get_template('test_extends_block_error.html')
  129. context = Context()
  130. with self.assertRaises(TemplateDoesNotExist) as cm:
  131. template.render(context)
  132. if self.debug_engine:
  133. self.assertEqual(
  134. cm.exception.template_debug['during'],
  135. escape('{% include "missing.html" %}'),
  136. )
  137. def test_super_errors(self):
  138. """
  139. #18169 -- NoReverseMatch should not be silence in block.super.
  140. """
  141. engine = self._engine(app_dirs=True)
  142. t = engine.get_template('included_content.html')
  143. with self.assertRaises(NoReverseMatch):
  144. t.render(Context())
  145. def test_extends_generic_template(self):
  146. """
  147. #24338 -- Allow extending django.template.backends.django.Template
  148. objects.
  149. """
  150. engine = self._engine()
  151. parent = engine.from_string('{% block content %}parent{% endblock %}')
  152. child = engine.from_string(
  153. '{% extends parent %}{% block content %}child{% endblock %}')
  154. self.assertEqual(child.render(Context({'parent': parent})), 'child')
  155. def test_node_origin(self):
  156. """
  157. #25848 -- Set origin on Node so debugging tools can determine which
  158. template the node came from even if extending or including templates.
  159. """
  160. template = self._engine().from_string('content')
  161. for node in template.nodelist:
  162. self.assertEqual(node.origin, template.origin)
  163. class TemplateTests(TemplateTestMixin, SimpleTestCase):
  164. debug_engine = False
  165. class DebugTemplateTests(TemplateTestMixin, SimpleTestCase):
  166. debug_engine = True