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