mirror of
https://github.com/django/django.git
synced 2024-12-22 17:16:24 +00:00
55855bc6d0
Co-authored-by: Brock <bsmick97@gmail.com>
407 lines
15 KiB
Python
407 lines
15 KiB
Python
from django.template import (
|
|
Context,
|
|
Engine,
|
|
TemplateDoesNotExist,
|
|
TemplateSyntaxError,
|
|
loader,
|
|
)
|
|
from django.template.loader_tags import IncludeNode
|
|
from django.test import SimpleTestCase
|
|
|
|
from ..utils import setup
|
|
from .test_basic import basic_templates
|
|
|
|
include_fail_templates = {
|
|
"include-fail1": "{% load bad_tag %}{% badtag %}",
|
|
"include-fail2": "{% load broken_tag %}",
|
|
}
|
|
|
|
|
|
class IncludeTagTests(SimpleTestCase):
|
|
libraries = {"bad_tag": "template_tests.templatetags.bad_tag"}
|
|
|
|
@setup({"include01": '{% include "basic-syntax01" %}'}, basic_templates)
|
|
def test_include01(self):
|
|
output = self.engine.render_to_string("include01")
|
|
self.assertEqual(output, "something cool")
|
|
|
|
@setup({"include02": '{% include "basic-syntax02" %}'}, basic_templates)
|
|
def test_include02(self):
|
|
output = self.engine.render_to_string("include02", {"headline": "Included"})
|
|
self.assertEqual(output, "Included")
|
|
|
|
@setup({"include03": "{% include template_name %}"}, basic_templates)
|
|
def test_include03(self):
|
|
output = self.engine.render_to_string(
|
|
"include03",
|
|
{"template_name": "basic-syntax02", "headline": "Included"},
|
|
)
|
|
self.assertEqual(output, "Included")
|
|
|
|
@setup({"include04": 'a{% include "nonexistent" %}b'})
|
|
def test_include04(self):
|
|
template = self.engine.get_template("include04")
|
|
with self.assertRaises(TemplateDoesNotExist):
|
|
template.render(Context({}))
|
|
|
|
@setup(
|
|
{
|
|
"include 05": "template with a space",
|
|
"include06": '{% include "include 05"%}',
|
|
}
|
|
)
|
|
def test_include06(self):
|
|
output = self.engine.render_to_string("include06")
|
|
self.assertEqual(output, "template with a space")
|
|
|
|
@setup(
|
|
{"include07": '{% include "basic-syntax02" with headline="Inline" %}'},
|
|
basic_templates,
|
|
)
|
|
def test_include07(self):
|
|
output = self.engine.render_to_string("include07", {"headline": "Included"})
|
|
self.assertEqual(output, "Inline")
|
|
|
|
@setup(
|
|
{"include08": '{% include headline with headline="Dynamic" %}'}, basic_templates
|
|
)
|
|
def test_include08(self):
|
|
output = self.engine.render_to_string(
|
|
"include08", {"headline": "basic-syntax02"}
|
|
)
|
|
self.assertEqual(output, "Dynamic")
|
|
|
|
@setup(
|
|
{
|
|
"include09": (
|
|
"{{ first }}--"
|
|
'{% include "basic-syntax03" with '
|
|
"first=second|lower|upper second=first|upper %}"
|
|
"--{{ second }}"
|
|
)
|
|
},
|
|
basic_templates,
|
|
)
|
|
def test_include09(self):
|
|
output = self.engine.render_to_string(
|
|
"include09", {"first": "Ul", "second": "lU"}
|
|
)
|
|
self.assertEqual(output, "Ul--LU --- UL--lU")
|
|
|
|
@setup({"include10": '{% include "basic-syntax03" only %}'}, basic_templates)
|
|
def test_include10(self):
|
|
output = self.engine.render_to_string("include10", {"first": "1"})
|
|
if self.engine.string_if_invalid:
|
|
self.assertEqual(output, "INVALID --- INVALID")
|
|
else:
|
|
self.assertEqual(output, " --- ")
|
|
|
|
@setup(
|
|
{"include11": '{% include "basic-syntax03" only with second=2 %}'},
|
|
basic_templates,
|
|
)
|
|
def test_include11(self):
|
|
output = self.engine.render_to_string("include11", {"first": "1"})
|
|
if self.engine.string_if_invalid:
|
|
self.assertEqual(output, "INVALID --- 2")
|
|
else:
|
|
self.assertEqual(output, " --- 2")
|
|
|
|
@setup(
|
|
{"include12": '{% include "basic-syntax03" with first=1 only %}'},
|
|
basic_templates,
|
|
)
|
|
def test_include12(self):
|
|
output = self.engine.render_to_string("include12", {"second": "2"})
|
|
if self.engine.string_if_invalid:
|
|
self.assertEqual(output, "1 --- INVALID")
|
|
else:
|
|
self.assertEqual(output, "1 --- ")
|
|
|
|
@setup(
|
|
{
|
|
"include13": (
|
|
'{% autoescape off %}{% include "basic-syntax03" %}{% endautoescape %}'
|
|
)
|
|
},
|
|
basic_templates,
|
|
)
|
|
def test_include13(self):
|
|
output = self.engine.render_to_string("include13", {"first": "&"})
|
|
if self.engine.string_if_invalid:
|
|
self.assertEqual(output, "& --- INVALID")
|
|
else:
|
|
self.assertEqual(output, "& --- ")
|
|
|
|
@setup(
|
|
{
|
|
"include14": "{% autoescape off %}"
|
|
'{% include "basic-syntax03" with first=var1 only %}'
|
|
"{% endautoescape %}"
|
|
},
|
|
basic_templates,
|
|
)
|
|
def test_include14(self):
|
|
output = self.engine.render_to_string("include14", {"var1": "&"})
|
|
if self.engine.string_if_invalid:
|
|
self.assertEqual(output, "& --- INVALID")
|
|
else:
|
|
self.assertEqual(output, "& --- ")
|
|
|
|
# Include syntax errors
|
|
@setup({"include-error01": '{% include "basic-syntax01" with %}'})
|
|
def test_include_error01(self):
|
|
with self.assertRaises(TemplateSyntaxError):
|
|
self.engine.get_template("include-error01")
|
|
|
|
@setup({"include-error02": '{% include "basic-syntax01" with "no key" %}'})
|
|
def test_include_error02(self):
|
|
with self.assertRaises(TemplateSyntaxError):
|
|
self.engine.get_template("include-error02")
|
|
|
|
@setup(
|
|
{"include-error03": '{% include "basic-syntax01" with dotted.arg="error" %}'}
|
|
)
|
|
def test_include_error03(self):
|
|
with self.assertRaises(TemplateSyntaxError):
|
|
self.engine.get_template("include-error03")
|
|
|
|
@setup({"include-error04": '{% include "basic-syntax01" something_random %}'})
|
|
def test_include_error04(self):
|
|
with self.assertRaises(TemplateSyntaxError):
|
|
self.engine.get_template("include-error04")
|
|
|
|
@setup(
|
|
{"include-error05": '{% include "basic-syntax01" foo="duplicate" foo="key" %}'}
|
|
)
|
|
def test_include_error05(self):
|
|
with self.assertRaises(TemplateSyntaxError):
|
|
self.engine.get_template("include-error05")
|
|
|
|
@setup({"include-error06": '{% include "basic-syntax01" only only %}'})
|
|
def test_include_error06(self):
|
|
with self.assertRaises(TemplateSyntaxError):
|
|
self.engine.get_template("include-error06")
|
|
|
|
@setup(include_fail_templates)
|
|
def test_include_fail1(self):
|
|
with self.assertRaises(RuntimeError):
|
|
self.engine.get_template("include-fail1")
|
|
|
|
@setup(include_fail_templates)
|
|
def test_include_fail2(self):
|
|
with self.assertRaises(TemplateSyntaxError):
|
|
self.engine.get_template("include-fail2")
|
|
|
|
@setup({"include-error07": '{% include "include-fail1" %}'}, include_fail_templates)
|
|
def test_include_error07(self):
|
|
template = self.engine.get_template("include-error07")
|
|
with self.assertRaises(RuntimeError):
|
|
template.render(Context())
|
|
|
|
@setup({"include-error08": '{% include "include-fail2" %}'}, include_fail_templates)
|
|
def test_include_error08(self):
|
|
template = self.engine.get_template("include-error08")
|
|
with self.assertRaises(TemplateSyntaxError):
|
|
template.render(Context())
|
|
|
|
@setup({"include-error09": "{% include failed_include %}"}, include_fail_templates)
|
|
def test_include_error09(self):
|
|
context = Context({"failed_include": "include-fail1"})
|
|
template = self.engine.get_template("include-error09")
|
|
with self.assertRaises(RuntimeError):
|
|
template.render(context)
|
|
|
|
@setup({"include-error10": "{% include failed_include %}"}, include_fail_templates)
|
|
def test_include_error10(self):
|
|
context = Context({"failed_include": "include-fail2"})
|
|
template = self.engine.get_template("include-error10")
|
|
with self.assertRaises(TemplateSyntaxError):
|
|
template.render(context)
|
|
|
|
@setup({"include_empty": "{% include %}"})
|
|
def test_include_empty(self):
|
|
msg = (
|
|
"'include' tag takes at least one argument: the name of the "
|
|
"template to be included."
|
|
)
|
|
with self.assertRaisesMessage(TemplateSyntaxError, msg):
|
|
self.engine.get_template("include_empty")
|
|
|
|
|
|
class IncludeTests(SimpleTestCase):
|
|
def test_include_missing_template(self):
|
|
"""
|
|
The correct template is identified as not existing
|
|
when {% include %} specifies a template that does not exist.
|
|
"""
|
|
engine = Engine(app_dirs=True, debug=True)
|
|
template = engine.get_template("test_include_error.html")
|
|
with self.assertRaisesMessage(TemplateDoesNotExist, "missing.html"):
|
|
template.render(Context())
|
|
|
|
def test_extends_include_missing_baseloader(self):
|
|
"""
|
|
#12787 -- The correct template is identified as not existing
|
|
when {% extends %} specifies a template that does exist, but that
|
|
template has an {% include %} of something that does not exist.
|
|
"""
|
|
engine = Engine(app_dirs=True, debug=True)
|
|
template = engine.get_template("test_extends_error.html")
|
|
with self.assertRaisesMessage(TemplateDoesNotExist, "missing.html"):
|
|
template.render(Context())
|
|
|
|
def test_extends_include_missing_cachedloader(self):
|
|
engine = Engine(
|
|
debug=True,
|
|
loaders=[
|
|
(
|
|
"django.template.loaders.cached.Loader",
|
|
[
|
|
"django.template.loaders.app_directories.Loader",
|
|
],
|
|
),
|
|
],
|
|
)
|
|
|
|
template = engine.get_template("test_extends_error.html")
|
|
with self.assertRaisesMessage(TemplateDoesNotExist, "missing.html"):
|
|
template.render(Context())
|
|
|
|
# Repeat to ensure it still works when loading from the cache
|
|
template = engine.get_template("test_extends_error.html")
|
|
with self.assertRaisesMessage(TemplateDoesNotExist, "missing.html"):
|
|
template.render(Context())
|
|
|
|
def test_include_template_argument(self):
|
|
"""
|
|
Support any render() supporting object
|
|
"""
|
|
engine = Engine()
|
|
ctx = Context(
|
|
{
|
|
"tmpl": engine.from_string("This worked!"),
|
|
}
|
|
)
|
|
outer_tmpl = engine.from_string("{% include tmpl %}")
|
|
output = outer_tmpl.render(ctx)
|
|
self.assertEqual(output, "This worked!")
|
|
|
|
def test_include_template_iterable(self):
|
|
engine = Engine.get_default()
|
|
outer_temp = engine.from_string("{% include var %}")
|
|
tests = [
|
|
("admin/fail.html", "index.html"),
|
|
["admin/fail.html", "index.html"],
|
|
]
|
|
for template_names in tests:
|
|
with self.subTest(template_names):
|
|
output = outer_temp.render(Context({"var": template_names}))
|
|
self.assertEqual(output, "index\n")
|
|
|
|
def test_include_template_none(self):
|
|
engine = Engine.get_default()
|
|
outer_temp = engine.from_string("{% include var %}")
|
|
ctx = Context({"var": None})
|
|
msg = "No template names provided"
|
|
with self.assertRaisesMessage(TemplateDoesNotExist, msg):
|
|
outer_temp.render(ctx)
|
|
|
|
def test_include_from_loader_get_template(self):
|
|
tmpl = loader.get_template("include_tpl.html") # {% include tmpl %}
|
|
output = tmpl.render({"tmpl": loader.get_template("index.html")})
|
|
self.assertEqual(output, "index\n\n")
|
|
|
|
def test_include_immediate_missing(self):
|
|
"""
|
|
#16417 -- Include tags pointing to missing templates should not raise
|
|
an error at parsing time.
|
|
"""
|
|
Engine(debug=True).from_string('{% include "this_does_not_exist.html" %}')
|
|
|
|
def test_include_recursive(self):
|
|
comments = [
|
|
{
|
|
"comment": "A1",
|
|
"children": [
|
|
{"comment": "B1", "children": []},
|
|
{"comment": "B2", "children": []},
|
|
{"comment": "B3", "children": [{"comment": "C1", "children": []}]},
|
|
],
|
|
}
|
|
]
|
|
with self.subTest(template="recursive_include.html"):
|
|
engine = Engine(app_dirs=True)
|
|
t = engine.get_template("recursive_include.html")
|
|
self.assertEqual(
|
|
"Recursion! A1 Recursion! B1 B2 B3 Recursion! C1",
|
|
t.render(Context({"comments": comments}))
|
|
.replace(" ", "")
|
|
.replace("\n", " ")
|
|
.strip(),
|
|
)
|
|
with self.subTest(template="recursive_relative_include.html"):
|
|
engine = Engine(app_dirs=True)
|
|
t = engine.get_template("recursive_relative_include.html")
|
|
self.assertEqual(
|
|
"Recursion! A1 Recursion! B1 B2 B3 Recursion! C1",
|
|
t.render(Context({"comments": comments}))
|
|
.replace(" ", "")
|
|
.replace("\n", " ")
|
|
.strip(),
|
|
)
|
|
with self.subTest(template="tmpl"):
|
|
engine = Engine()
|
|
template = """
|
|
Recursion!
|
|
{% for c in comments %}
|
|
{{ c.comment }}
|
|
{% if c.children %}{% include tmpl with comments=c.children %}{% endif %}
|
|
{% endfor %}
|
|
"""
|
|
outer_tmpl = engine.from_string("{% include tmpl %}")
|
|
output = outer_tmpl.render(
|
|
Context({"tmpl": engine.from_string(template), "comments": comments})
|
|
)
|
|
self.assertEqual(
|
|
"Recursion! A1 Recursion! B1 B2 B3 Recursion! C1",
|
|
output.replace(" ", "").replace("\n", " ").strip(),
|
|
)
|
|
|
|
def test_include_cache(self):
|
|
"""
|
|
{% include %} keeps resolved templates constant (#27974). The
|
|
CounterNode object in the {% counter %} template tag is created once
|
|
if caching works properly. Each iteration increases the counter instead
|
|
of restarting it.
|
|
|
|
This works as a regression test only if the cached loader
|
|
isn't used, so the @setup decorator isn't used.
|
|
"""
|
|
engine = Engine(
|
|
loaders=[
|
|
(
|
|
"django.template.loaders.locmem.Loader",
|
|
{
|
|
"template": (
|
|
'{% for x in vars %}{% include "include" %}{% endfor %}'
|
|
),
|
|
"include": '{% include "next" %}',
|
|
"next": "{% load custom %}{% counter %}",
|
|
},
|
|
),
|
|
],
|
|
libraries={"custom": "template_tests.templatetags.custom"},
|
|
)
|
|
output = engine.render_to_string("template", {"vars": range(9)})
|
|
self.assertEqual(output, "012345678")
|
|
|
|
|
|
class IncludeNodeTests(SimpleTestCase):
|
|
def test_repr(self):
|
|
include_node = IncludeNode("app/template.html")
|
|
self.assertEqual(
|
|
repr(include_node),
|
|
"<IncludeNode: template='app/template.html'>",
|
|
)
|