From 3810dc3070468abd3a3d9beec406a5aa3edd6b52 Mon Sep 17 00:00:00 2001 From: Preston Timmons Date: Sat, 6 Apr 2013 13:51:40 -0500 Subject: Modified template_tests for unittest2 discovery. --- tests/template_tests/callables.py | 113 ---------- tests/template_tests/context.py | 16 -- tests/template_tests/custom.py | 377 --------------------------------- tests/template_tests/loaders.py | 156 -------------- tests/template_tests/nodelist.py | 58 ----- tests/template_tests/parser.py | 95 --------- tests/template_tests/response.py | 352 ------------------------------ tests/template_tests/smartif.py | 53 ----- tests/template_tests/test_callables.py | 113 ++++++++++ tests/template_tests/test_context.py | 16 ++ tests/template_tests/test_custom.py | 377 +++++++++++++++++++++++++++++++++ tests/template_tests/test_loaders.py | 156 ++++++++++++++ tests/template_tests/test_nodelist.py | 58 +++++ tests/template_tests/test_parser.py | 95 +++++++++ tests/template_tests/test_response.py | 352 ++++++++++++++++++++++++++++++ tests/template_tests/test_smartif.py | 53 +++++ tests/template_tests/test_unicode.py | 32 +++ tests/template_tests/tests.py | 18 +- tests/template_tests/unicode.py | 32 --- 19 files changed, 1261 insertions(+), 1261 deletions(-) delete mode 100644 tests/template_tests/callables.py delete mode 100644 tests/template_tests/context.py delete mode 100644 tests/template_tests/custom.py delete mode 100644 tests/template_tests/loaders.py delete mode 100644 tests/template_tests/nodelist.py delete mode 100644 tests/template_tests/parser.py delete mode 100644 tests/template_tests/response.py delete mode 100644 tests/template_tests/smartif.py create mode 100644 tests/template_tests/test_callables.py create mode 100644 tests/template_tests/test_context.py create mode 100644 tests/template_tests/test_custom.py create mode 100644 tests/template_tests/test_loaders.py create mode 100644 tests/template_tests/test_nodelist.py create mode 100644 tests/template_tests/test_parser.py create mode 100644 tests/template_tests/test_response.py create mode 100644 tests/template_tests/test_smartif.py create mode 100644 tests/template_tests/test_unicode.py delete mode 100644 tests/template_tests/unicode.py diff --git a/tests/template_tests/callables.py b/tests/template_tests/callables.py deleted file mode 100644 index 882a8c6e06..0000000000 --- a/tests/template_tests/callables.py +++ /dev/null @@ -1,113 +0,0 @@ -from __future__ import unicode_literals - -from django import template -from django.utils.unittest import TestCase - -class CallableVariablesTests(TestCase): - - def test_callable(self): - - class Doodad(object): - def __init__(self, value): - self.num_calls = 0 - self.value = value - def __call__(self): - self.num_calls += 1 - return {"the_value": self.value} - - my_doodad = Doodad(42) - c = template.Context({"my_doodad": my_doodad}) - - # We can't access ``my_doodad.value`` in the template, because - # ``my_doodad.__call__`` will be invoked first, yielding a dictionary - # without a key ``value``. - t = template.Template('{{ my_doodad.value }}') - self.assertEqual(t.render(c), '') - - # We can confirm that the doodad has been called - self.assertEqual(my_doodad.num_calls, 1) - - # But we can access keys on the dict that's returned - # by ``__call__``, instead. - t = template.Template('{{ my_doodad.the_value }}') - self.assertEqual(t.render(c), '42') - self.assertEqual(my_doodad.num_calls, 2) - - def test_alters_data(self): - - class Doodad(object): - alters_data = True - def __init__(self, value): - self.num_calls = 0 - self.value = value - def __call__(self): - self.num_calls += 1 - return {"the_value": self.value} - - my_doodad = Doodad(42) - c = template.Context({"my_doodad": my_doodad}) - - # Since ``my_doodad.alters_data`` is True, the template system will not - # try to call our doodad but will use TEMPLATE_STRING_IF_INVALID - t = template.Template('{{ my_doodad.value }}') - self.assertEqual(t.render(c), '') - t = template.Template('{{ my_doodad.the_value }}') - self.assertEqual(t.render(c), '') - - # Double-check that the object was really never called during the - # template rendering. - self.assertEqual(my_doodad.num_calls, 0) - - def test_do_not_call(self): - - class Doodad(object): - do_not_call_in_templates = True - def __init__(self, value): - self.num_calls = 0 - self.value = value - def __call__(self): - self.num_calls += 1 - return {"the_value": self.value} - - my_doodad = Doodad(42) - c = template.Context({"my_doodad": my_doodad}) - - # Since ``my_doodad.do_not_call_in_templates`` is True, the template - # system will not try to call our doodad. We can access its attributes - # as normal, and we don't have access to the dict that it returns when - # called. - t = template.Template('{{ my_doodad.value }}') - self.assertEqual(t.render(c), '42') - t = template.Template('{{ my_doodad.the_value }}') - self.assertEqual(t.render(c), '') - - # Double-check that the object was really never called during the - # template rendering. - self.assertEqual(my_doodad.num_calls, 0) - - def test_do_not_call_and_alters_data(self): - # If we combine ``alters_data`` and ``do_not_call_in_templates``, the - # ``alters_data`` attribute will not make any difference in the - # template system's behavior. - - class Doodad(object): - do_not_call_in_templates = True - alters_data = True - def __init__(self, value): - self.num_calls = 0 - self.value = value - def __call__(self): - self.num_calls += 1 - return {"the_value": self.value} - - my_doodad = Doodad(42) - c = template.Context({"my_doodad": my_doodad}) - - t = template.Template('{{ my_doodad.value }}') - self.assertEqual(t.render(c), '42') - t = template.Template('{{ my_doodad.the_value }}') - self.assertEqual(t.render(c), '') - - # Double-check that the object was really never called during the - # template rendering. - self.assertEqual(my_doodad.num_calls, 0) diff --git a/tests/template_tests/context.py b/tests/template_tests/context.py deleted file mode 100644 index 05c1dd57b9..0000000000 --- a/tests/template_tests/context.py +++ /dev/null @@ -1,16 +0,0 @@ -# coding: utf-8 -from django.template import Context -from django.utils.unittest import TestCase - - -class ContextTests(TestCase): - def test_context(self): - c = Context({"a": 1, "b": "xyzzy"}) - self.assertEqual(c["a"], 1) - self.assertEqual(c.push(), {}) - c["a"] = 2 - self.assertEqual(c["a"], 2) - self.assertEqual(c.get("a"), 2) - self.assertEqual(c.pop(), {"a": 2}) - self.assertEqual(c["a"], 1) - self.assertEqual(c.get("foo", 42), 42) diff --git a/tests/template_tests/custom.py b/tests/template_tests/custom.py deleted file mode 100644 index 4aea08237d..0000000000 --- a/tests/template_tests/custom.py +++ /dev/null @@ -1,377 +0,0 @@ -from __future__ import absolute_import, unicode_literals - -from django import template -from django.utils import six -from django.utils.unittest import TestCase - -from .templatetags import custom - - -class CustomFilterTests(TestCase): - def test_filter(self): - t = template.Template("{% load custom %}{{ string|trim:5 }}") - self.assertEqual( - t.render(template.Context({"string": "abcdefghijklmnopqrstuvwxyz"})), - "abcde" - ) - - -class CustomTagTests(TestCase): - def verify_tag(self, tag, name): - self.assertEqual(tag.__name__, name) - self.assertEqual(tag.__doc__, 'Expected %s __doc__' % name) - self.assertEqual(tag.__dict__['anything'], 'Expected %s __dict__' % name) - - def test_simple_tags(self): - c = template.Context({'value': 42}) - - t = template.Template('{% load custom %}{% no_params %}') - self.assertEqual(t.render(c), 'no_params - Expected result') - - t = template.Template('{% load custom %}{% one_param 37 %}') - self.assertEqual(t.render(c), 'one_param - Expected result: 37') - - t = template.Template('{% load custom %}{% explicit_no_context 37 %}') - self.assertEqual(t.render(c), 'explicit_no_context - Expected result: 37') - - t = template.Template('{% load custom %}{% no_params_with_context %}') - self.assertEqual(t.render(c), 'no_params_with_context - Expected result (context value: 42)') - - t = template.Template('{% load custom %}{% params_and_context 37 %}') - self.assertEqual(t.render(c), 'params_and_context - Expected result (context value: 42): 37') - - t = template.Template('{% load custom %}{% simple_two_params 37 42 %}') - self.assertEqual(t.render(c), 'simple_two_params - Expected result: 37, 42') - - t = template.Template('{% load custom %}{% simple_one_default 37 %}') - self.assertEqual(t.render(c), 'simple_one_default - Expected result: 37, hi') - - t = template.Template('{% load custom %}{% simple_one_default 37 two="hello" %}') - self.assertEqual(t.render(c), 'simple_one_default - Expected result: 37, hello') - - t = template.Template('{% load custom %}{% simple_one_default one=99 two="hello" %}') - self.assertEqual(t.render(c), 'simple_one_default - Expected result: 99, hello') - - six.assertRaisesRegex(self, template.TemplateSyntaxError, - "'simple_one_default' received unexpected keyword argument 'three'", - template.Template, '{% load custom %}{% simple_one_default 99 two="hello" three="foo" %}') - - t = template.Template('{% load custom %}{% simple_one_default 37 42 %}') - self.assertEqual(t.render(c), 'simple_one_default - Expected result: 37, 42') - - t = template.Template('{% load custom %}{% simple_unlimited_args 37 %}') - self.assertEqual(t.render(c), 'simple_unlimited_args - Expected result: 37, hi') - - t = template.Template('{% load custom %}{% simple_unlimited_args 37 42 56 89 %}') - self.assertEqual(t.render(c), 'simple_unlimited_args - Expected result: 37, 42, 56, 89') - - t = template.Template('{% load custom %}{% simple_only_unlimited_args %}') - self.assertEqual(t.render(c), 'simple_only_unlimited_args - Expected result: ') - - t = template.Template('{% load custom %}{% simple_only_unlimited_args 37 42 56 89 %}') - self.assertEqual(t.render(c), 'simple_only_unlimited_args - Expected result: 37, 42, 56, 89') - - six.assertRaisesRegex(self, template.TemplateSyntaxError, - "'simple_two_params' received too many positional arguments", - template.Template, '{% load custom %}{% simple_two_params 37 42 56 %}') - - six.assertRaisesRegex(self, template.TemplateSyntaxError, - "'simple_one_default' received too many positional arguments", - template.Template, '{% load custom %}{% simple_one_default 37 42 56 %}') - - t = template.Template('{% load custom %}{% simple_unlimited_args_kwargs 37 40|add:2 56 eggs="scrambled" four=1|add:3 %}') - self.assertEqual(t.render(c), 'simple_unlimited_args_kwargs - Expected result: 37, 42, 56 / eggs=scrambled, four=4') - - six.assertRaisesRegex(self, template.TemplateSyntaxError, - "'simple_unlimited_args_kwargs' received some positional argument\(s\) after some keyword argument\(s\)", - template.Template, '{% load custom %}{% simple_unlimited_args_kwargs 37 40|add:2 eggs="scrambled" 56 four=1|add:3 %}') - - six.assertRaisesRegex(self, template.TemplateSyntaxError, - "'simple_unlimited_args_kwargs' received multiple values for keyword argument 'eggs'", - template.Template, '{% load custom %}{% simple_unlimited_args_kwargs 37 eggs="scrambled" eggs="scrambled" %}') - - def test_simple_tag_registration(self): - # Test that the decorators preserve the decorated function's docstring, name and attributes. - self.verify_tag(custom.no_params, 'no_params') - self.verify_tag(custom.one_param, 'one_param') - self.verify_tag(custom.explicit_no_context, 'explicit_no_context') - self.verify_tag(custom.no_params_with_context, 'no_params_with_context') - self.verify_tag(custom.params_and_context, 'params_and_context') - self.verify_tag(custom.simple_unlimited_args_kwargs, 'simple_unlimited_args_kwargs') - self.verify_tag(custom.simple_tag_without_context_parameter, 'simple_tag_without_context_parameter') - - def test_simple_tag_missing_context(self): - # The 'context' parameter must be present when takes_context is True - six.assertRaisesRegex(self, template.TemplateSyntaxError, - "'simple_tag_without_context_parameter' is decorated with takes_context=True so it must have a first argument of 'context'", - template.Template, '{% load custom %}{% simple_tag_without_context_parameter 123 %}') - - def test_inclusion_tags(self): - c = template.Context({'value': 42}) - - t = template.Template('{% load custom %}{% inclusion_no_params %}') - self.assertEqual(t.render(c), 'inclusion_no_params - Expected result\n') - - t = template.Template('{% load custom %}{% inclusion_one_param 37 %}') - self.assertEqual(t.render(c), 'inclusion_one_param - Expected result: 37\n') - - t = template.Template('{% load custom %}{% inclusion_explicit_no_context 37 %}') - self.assertEqual(t.render(c), 'inclusion_explicit_no_context - Expected result: 37\n') - - t = template.Template('{% load custom %}{% inclusion_no_params_with_context %}') - self.assertEqual(t.render(c), 'inclusion_no_params_with_context - Expected result (context value: 42)\n') - - t = template.Template('{% load custom %}{% inclusion_params_and_context 37 %}') - self.assertEqual(t.render(c), 'inclusion_params_and_context - Expected result (context value: 42): 37\n') - - t = template.Template('{% load custom %}{% inclusion_two_params 37 42 %}') - self.assertEqual(t.render(c), 'inclusion_two_params - Expected result: 37, 42\n') - - t = template.Template('{% load custom %}{% inclusion_one_default 37 %}') - self.assertEqual(t.render(c), 'inclusion_one_default - Expected result: 37, hi\n') - - t = template.Template('{% load custom %}{% inclusion_one_default 37 two="hello" %}') - self.assertEqual(t.render(c), 'inclusion_one_default - Expected result: 37, hello\n') - - t = template.Template('{% load custom %}{% inclusion_one_default one=99 two="hello" %}') - self.assertEqual(t.render(c), 'inclusion_one_default - Expected result: 99, hello\n') - - six.assertRaisesRegex(self, template.TemplateSyntaxError, - "'inclusion_one_default' received unexpected keyword argument 'three'", - template.Template, '{% load custom %}{% inclusion_one_default 99 two="hello" three="foo" %}') - - t = template.Template('{% load custom %}{% inclusion_one_default 37 42 %}') - self.assertEqual(t.render(c), 'inclusion_one_default - Expected result: 37, 42\n') - - t = template.Template('{% load custom %}{% inclusion_unlimited_args 37 %}') - self.assertEqual(t.render(c), 'inclusion_unlimited_args - Expected result: 37, hi\n') - - t = template.Template('{% load custom %}{% inclusion_unlimited_args 37 42 56 89 %}') - self.assertEqual(t.render(c), 'inclusion_unlimited_args - Expected result: 37, 42, 56, 89\n') - - t = template.Template('{% load custom %}{% inclusion_only_unlimited_args %}') - self.assertEqual(t.render(c), 'inclusion_only_unlimited_args - Expected result: \n') - - t = template.Template('{% load custom %}{% inclusion_only_unlimited_args 37 42 56 89 %}') - self.assertEqual(t.render(c), 'inclusion_only_unlimited_args - Expected result: 37, 42, 56, 89\n') - - six.assertRaisesRegex(self, template.TemplateSyntaxError, - "'inclusion_two_params' received too many positional arguments", - template.Template, '{% load custom %}{% inclusion_two_params 37 42 56 %}') - - six.assertRaisesRegex(self, template.TemplateSyntaxError, - "'inclusion_one_default' received too many positional arguments", - template.Template, '{% load custom %}{% inclusion_one_default 37 42 56 %}') - - six.assertRaisesRegex(self, template.TemplateSyntaxError, - "'inclusion_one_default' did not receive value\(s\) for the argument\(s\): 'one'", - template.Template, '{% load custom %}{% inclusion_one_default %}') - - six.assertRaisesRegex(self, template.TemplateSyntaxError, - "'inclusion_unlimited_args' did not receive value\(s\) for the argument\(s\): 'one'", - template.Template, '{% load custom %}{% inclusion_unlimited_args %}') - - t = template.Template('{% load custom %}{% inclusion_unlimited_args_kwargs 37 40|add:2 56 eggs="scrambled" four=1|add:3 %}') - self.assertEqual(t.render(c), 'inclusion_unlimited_args_kwargs - Expected result: 37, 42, 56 / eggs=scrambled, four=4\n') - - six.assertRaisesRegex(self, template.TemplateSyntaxError, - "'inclusion_unlimited_args_kwargs' received some positional argument\(s\) after some keyword argument\(s\)", - template.Template, '{% load custom %}{% inclusion_unlimited_args_kwargs 37 40|add:2 eggs="scrambled" 56 four=1|add:3 %}') - - six.assertRaisesRegex(self, template.TemplateSyntaxError, - "'inclusion_unlimited_args_kwargs' received multiple values for keyword argument 'eggs'", - template.Template, '{% load custom %}{% inclusion_unlimited_args_kwargs 37 eggs="scrambled" eggs="scrambled" %}') - - def test_include_tag_missing_context(self): - # The 'context' parameter must be present when takes_context is True - six.assertRaisesRegex(self, template.TemplateSyntaxError, - "'inclusion_tag_without_context_parameter' is decorated with takes_context=True so it must have a first argument of 'context'", - template.Template, '{% load custom %}{% inclusion_tag_without_context_parameter 123 %}') - - def test_inclusion_tags_from_template(self): - c = template.Context({'value': 42}) - - t = template.Template('{% load custom %}{% inclusion_no_params_from_template %}') - self.assertEqual(t.render(c), 'inclusion_no_params_from_template - Expected result\n') - - t = template.Template('{% load custom %}{% inclusion_one_param_from_template 37 %}') - self.assertEqual(t.render(c), 'inclusion_one_param_from_template - Expected result: 37\n') - - t = template.Template('{% load custom %}{% inclusion_explicit_no_context_from_template 37 %}') - self.assertEqual(t.render(c), 'inclusion_explicit_no_context_from_template - Expected result: 37\n') - - t = template.Template('{% load custom %}{% inclusion_no_params_with_context_from_template %}') - self.assertEqual(t.render(c), 'inclusion_no_params_with_context_from_template - Expected result (context value: 42)\n') - - t = template.Template('{% load custom %}{% inclusion_params_and_context_from_template 37 %}') - self.assertEqual(t.render(c), 'inclusion_params_and_context_from_template - Expected result (context value: 42): 37\n') - - t = template.Template('{% load custom %}{% inclusion_two_params_from_template 37 42 %}') - self.assertEqual(t.render(c), 'inclusion_two_params_from_template - Expected result: 37, 42\n') - - t = template.Template('{% load custom %}{% inclusion_one_default_from_template 37 %}') - self.assertEqual(t.render(c), 'inclusion_one_default_from_template - Expected result: 37, hi\n') - - t = template.Template('{% load custom %}{% inclusion_one_default_from_template 37 42 %}') - self.assertEqual(t.render(c), 'inclusion_one_default_from_template - Expected result: 37, 42\n') - - t = template.Template('{% load custom %}{% inclusion_unlimited_args_from_template 37 %}') - self.assertEqual(t.render(c), 'inclusion_unlimited_args_from_template - Expected result: 37, hi\n') - - t = template.Template('{% load custom %}{% inclusion_unlimited_args_from_template 37 42 56 89 %}') - self.assertEqual(t.render(c), 'inclusion_unlimited_args_from_template - Expected result: 37, 42, 56, 89\n') - - t = template.Template('{% load custom %}{% inclusion_only_unlimited_args_from_template %}') - self.assertEqual(t.render(c), 'inclusion_only_unlimited_args_from_template - Expected result: \n') - - t = template.Template('{% load custom %}{% inclusion_only_unlimited_args_from_template 37 42 56 89 %}') - self.assertEqual(t.render(c), 'inclusion_only_unlimited_args_from_template - Expected result: 37, 42, 56, 89\n') - - def test_inclusion_tag_registration(self): - # Test that the decorators preserve the decorated function's docstring, name and attributes. - self.verify_tag(custom.inclusion_no_params, 'inclusion_no_params') - self.verify_tag(custom.inclusion_one_param, 'inclusion_one_param') - self.verify_tag(custom.inclusion_explicit_no_context, 'inclusion_explicit_no_context') - self.verify_tag(custom.inclusion_no_params_with_context, 'inclusion_no_params_with_context') - self.verify_tag(custom.inclusion_params_and_context, 'inclusion_params_and_context') - self.verify_tag(custom.inclusion_two_params, 'inclusion_two_params') - self.verify_tag(custom.inclusion_one_default, 'inclusion_one_default') - self.verify_tag(custom.inclusion_unlimited_args, 'inclusion_unlimited_args') - self.verify_tag(custom.inclusion_only_unlimited_args, 'inclusion_only_unlimited_args') - self.verify_tag(custom.inclusion_tag_without_context_parameter, 'inclusion_tag_without_context_parameter') - self.verify_tag(custom.inclusion_tag_use_l10n, 'inclusion_tag_use_l10n') - self.verify_tag(custom.inclusion_tag_current_app, 'inclusion_tag_current_app') - self.verify_tag(custom.inclusion_unlimited_args_kwargs, 'inclusion_unlimited_args_kwargs') - - def test_15070_current_app(self): - """ - Test that inclusion tag passes down `current_app` of context to the - Context of the included/rendered template as well. - """ - c = template.Context({}) - t = template.Template('{% load custom %}{% inclusion_tag_current_app %}') - self.assertEqual(t.render(c).strip(), 'None') - - c.current_app = 'advanced' - self.assertEqual(t.render(c).strip(), 'advanced') - - def test_15070_use_l10n(self): - """ - Test that inclusion tag passes down `use_l10n` of context to the - Context of the included/rendered template as well. - """ - c = template.Context({}) - t = template.Template('{% load custom %}{% inclusion_tag_use_l10n %}') - self.assertEqual(t.render(c).strip(), 'None') - - c.use_l10n = True - self.assertEqual(t.render(c).strip(), 'True') - - def test_assignment_tags(self): - c = template.Context({'value': 42}) - - t = template.Template('{% load custom %}{% assignment_no_params as var %}The result is: {{ var }}') - self.assertEqual(t.render(c), 'The result is: assignment_no_params - Expected result') - - t = template.Template('{% load custom %}{% assignment_one_param 37 as var %}The result is: {{ var }}') - self.assertEqual(t.render(c), 'The result is: assignment_one_param - Expected result: 37') - - t = template.Template('{% load custom %}{% assignment_explicit_no_context 37 as var %}The result is: {{ var }}') - self.assertEqual(t.render(c), 'The result is: assignment_explicit_no_context - Expected result: 37') - - t = template.Template('{% load custom %}{% assignment_no_params_with_context as var %}The result is: {{ var }}') - self.assertEqual(t.render(c), 'The result is: assignment_no_params_with_context - Expected result (context value: 42)') - - t = template.Template('{% load custom %}{% assignment_params_and_context 37 as var %}The result is: {{ var }}') - self.assertEqual(t.render(c), 'The result is: assignment_params_and_context - Expected result (context value: 42): 37') - - t = template.Template('{% load custom %}{% assignment_two_params 37 42 as var %}The result is: {{ var }}') - self.assertEqual(t.render(c), 'The result is: assignment_two_params - Expected result: 37, 42') - - t = template.Template('{% load custom %}{% assignment_one_default 37 as var %}The result is: {{ var }}') - self.assertEqual(t.render(c), 'The result is: assignment_one_default - Expected result: 37, hi') - - t = template.Template('{% load custom %}{% assignment_one_default 37 two="hello" as var %}The result is: {{ var }}') - self.assertEqual(t.render(c), 'The result is: assignment_one_default - Expected result: 37, hello') - - t = template.Template('{% load custom %}{% assignment_one_default one=99 two="hello" as var %}The result is: {{ var }}') - self.assertEqual(t.render(c), 'The result is: assignment_one_default - Expected result: 99, hello') - - six.assertRaisesRegex(self, template.TemplateSyntaxError, - "'assignment_one_default' received unexpected keyword argument 'three'", - template.Template, '{% load custom %}{% assignment_one_default 99 two="hello" three="foo" as var %}') - - t = template.Template('{% load custom %}{% assignment_one_default 37 42 as var %}The result is: {{ var }}') - self.assertEqual(t.render(c), 'The result is: assignment_one_default - Expected result: 37, 42') - - t = template.Template('{% load custom %}{% assignment_unlimited_args 37 as var %}The result is: {{ var }}') - self.assertEqual(t.render(c), 'The result is: assignment_unlimited_args - Expected result: 37, hi') - - t = template.Template('{% load custom %}{% assignment_unlimited_args 37 42 56 89 as var %}The result is: {{ var }}') - self.assertEqual(t.render(c), 'The result is: assignment_unlimited_args - Expected result: 37, 42, 56, 89') - - t = template.Template('{% load custom %}{% assignment_only_unlimited_args as var %}The result is: {{ var }}') - self.assertEqual(t.render(c), 'The result is: assignment_only_unlimited_args - Expected result: ') - - t = template.Template('{% load custom %}{% assignment_only_unlimited_args 37 42 56 89 as var %}The result is: {{ var }}') - self.assertEqual(t.render(c), 'The result is: assignment_only_unlimited_args - Expected result: 37, 42, 56, 89') - - six.assertRaisesRegex(self, template.TemplateSyntaxError, - "'assignment_one_param' tag takes at least 2 arguments and the second last argument must be 'as'", - template.Template, '{% load custom %}{% assignment_one_param 37 %}The result is: {{ var }}') - - six.assertRaisesRegex(self, template.TemplateSyntaxError, - "'assignment_one_param' tag takes at least 2 arguments and the second last argument must be 'as'", - template.Template, '{% load custom %}{% assignment_one_param 37 as %}The result is: {{ var }}') - - six.assertRaisesRegex(self, template.TemplateSyntaxError, - "'assignment_one_param' tag takes at least 2 arguments and the second last argument must be 'as'", - template.Template, '{% load custom %}{% assignment_one_param 37 ass var %}The result is: {{ var }}') - - six.assertRaisesRegex(self, template.TemplateSyntaxError, - "'assignment_two_params' received too many positional arguments", - template.Template, '{% load custom %}{% assignment_two_params 37 42 56 as var %}The result is: {{ var }}') - - six.assertRaisesRegex(self, template.TemplateSyntaxError, - "'assignment_one_default' received too many positional arguments", - template.Template, '{% load custom %}{% assignment_one_default 37 42 56 as var %}The result is: {{ var }}') - - six.assertRaisesRegex(self, template.TemplateSyntaxError, - "'assignment_one_default' did not receive value\(s\) for the argument\(s\): 'one'", - template.Template, '{% load custom %}{% assignment_one_default as var %}The result is: {{ var }}') - - six.assertRaisesRegex(self, template.TemplateSyntaxError, - "'assignment_unlimited_args' did not receive value\(s\) for the argument\(s\): 'one'", - template.Template, '{% load custom %}{% assignment_unlimited_args as var %}The result is: {{ var }}') - - t = template.Template('{% load custom %}{% assignment_unlimited_args_kwargs 37 40|add:2 56 eggs="scrambled" four=1|add:3 as var %}The result is: {{ var }}') - self.assertEqual(t.render(c), 'The result is: assignment_unlimited_args_kwargs - Expected result: 37, 42, 56 / eggs=scrambled, four=4') - - six.assertRaisesRegex(self, template.TemplateSyntaxError, - "'assignment_unlimited_args_kwargs' received some positional argument\(s\) after some keyword argument\(s\)", - template.Template, '{% load custom %}{% assignment_unlimited_args_kwargs 37 40|add:2 eggs="scrambled" 56 four=1|add:3 as var %}The result is: {{ var }}') - - six.assertRaisesRegex(self, template.TemplateSyntaxError, - "'assignment_unlimited_args_kwargs' received multiple values for keyword argument 'eggs'", - template.Template, '{% load custom %}{% assignment_unlimited_args_kwargs 37 eggs="scrambled" eggs="scrambled" as var %}The result is: {{ var }}') - - def test_assignment_tag_registration(self): - # Test that the decorators preserve the decorated function's docstring, name and attributes. - self.verify_tag(custom.assignment_no_params, 'assignment_no_params') - self.verify_tag(custom.assignment_one_param, 'assignment_one_param') - self.verify_tag(custom.assignment_explicit_no_context, 'assignment_explicit_no_context') - self.verify_tag(custom.assignment_no_params_with_context, 'assignment_no_params_with_context') - self.verify_tag(custom.assignment_params_and_context, 'assignment_params_and_context') - self.verify_tag(custom.assignment_one_default, 'assignment_one_default') - self.verify_tag(custom.assignment_two_params, 'assignment_two_params') - self.verify_tag(custom.assignment_unlimited_args, 'assignment_unlimited_args') - self.verify_tag(custom.assignment_only_unlimited_args, 'assignment_only_unlimited_args') - self.verify_tag(custom.assignment_unlimited_args, 'assignment_unlimited_args') - self.verify_tag(custom.assignment_unlimited_args_kwargs, 'assignment_unlimited_args_kwargs') - self.verify_tag(custom.assignment_tag_without_context_parameter, 'assignment_tag_without_context_parameter') - - def test_assignment_tag_missing_context(self): - # The 'context' parameter must be present when takes_context is True - six.assertRaisesRegex(self, template.TemplateSyntaxError, - "'assignment_tag_without_context_parameter' is decorated with takes_context=True so it must have a first argument of 'context'", - template.Template, '{% load custom %}{% assignment_tag_without_context_parameter 123 as var %}') diff --git a/tests/template_tests/loaders.py b/tests/template_tests/loaders.py deleted file mode 100644 index b77965203f..0000000000 --- a/tests/template_tests/loaders.py +++ /dev/null @@ -1,156 +0,0 @@ -""" -Test cases for the template loaders - -Note: This test requires setuptools! -""" - -from django.conf import settings - -if __name__ == '__main__': - settings.configure() - -import sys -import pkg_resources -import imp -import os.path - -from django.template import TemplateDoesNotExist, Context -from django.template.loaders.eggs import Loader as EggLoader -from django.template import loader -from django.utils import unittest, six -from django.utils._os import upath -from django.utils.six import StringIO - - -# Mock classes and objects for pkg_resources functions. -class MockProvider(pkg_resources.NullProvider): - def __init__(self, module): - pkg_resources.NullProvider.__init__(self, module) - self.module = module - - def _has(self, path): - return path in self.module._resources - - def _isdir(self, path): - return False - - def get_resource_stream(self, manager, resource_name): - return self.module._resources[resource_name] - - def _get(self, path): - return self.module._resources[path].read() - -class MockLoader(object): - pass - -def create_egg(name, resources): - """ - Creates a mock egg with a list of resources. - - name: The name of the module. - resources: A dictionary of resources. Keys are the names and values the data. - """ - egg = imp.new_module(name) - egg.__loader__ = MockLoader() - egg._resources = resources - sys.modules[name] = egg - - -class EggLoaderTest(unittest.TestCase): - def setUp(self): - pkg_resources._provider_factories[MockLoader] = MockProvider - - self.empty_egg = create_egg("egg_empty", {}) - self.egg_1 = create_egg("egg_1", { - os.path.normcase('templates/y.html'): StringIO("y"), - os.path.normcase('templates/x.txt'): StringIO("x"), - }) - self._old_installed_apps = settings.INSTALLED_APPS - settings.INSTALLED_APPS = [] - - def tearDown(self): - settings.INSTALLED_APPS = self._old_installed_apps - - def test_empty(self): - "Loading any template on an empty egg should fail" - settings.INSTALLED_APPS = ['egg_empty'] - egg_loader = EggLoader() - self.assertRaises(TemplateDoesNotExist, egg_loader.load_template_source, "not-existing.html") - - def test_non_existing(self): - "Template loading fails if the template is not in the egg" - settings.INSTALLED_APPS = ['egg_1'] - egg_loader = EggLoader() - self.assertRaises(TemplateDoesNotExist, egg_loader.load_template_source, "not-existing.html") - - def test_existing(self): - "A template can be loaded from an egg" - settings.INSTALLED_APPS = ['egg_1'] - egg_loader = EggLoader() - contents, template_name = egg_loader.load_template_source("y.html") - self.assertEqual(contents, "y") - self.assertEqual(template_name, "egg:egg_1:templates/y.html") - - def test_not_installed(self): - "Loading an existent template from an egg not included in INSTALLED_APPS should fail" - settings.INSTALLED_APPS = [] - egg_loader = EggLoader() - self.assertRaises(TemplateDoesNotExist, egg_loader.load_template_source, "y.html") - -class CachedLoader(unittest.TestCase): - def setUp(self): - self.old_TEMPLATE_LOADERS = settings.TEMPLATE_LOADERS - settings.TEMPLATE_LOADERS = ( - ('django.template.loaders.cached.Loader', ( - 'django.template.loaders.filesystem.Loader', - ) - ), - ) - def tearDown(self): - settings.TEMPLATE_LOADERS = self.old_TEMPLATE_LOADERS - - def test_templatedir_caching(self): - "Check that the template directories form part of the template cache key. Refs #13573" - # Retrive a template specifying a template directory to check - t1, name = loader.find_template('test.html', (os.path.join(os.path.dirname(upath(__file__)), 'templates', 'first'),)) - # Now retrieve the same template name, but from a different directory - t2, name = loader.find_template('test.html', (os.path.join(os.path.dirname(upath(__file__)), 'templates', 'second'),)) - - # The two templates should not have the same content - self.assertNotEqual(t1.render(Context({})), t2.render(Context({}))) - -class RenderToStringTest(unittest.TestCase): - - def setUp(self): - self._old_TEMPLATE_DIRS = settings.TEMPLATE_DIRS - settings.TEMPLATE_DIRS = ( - os.path.join(os.path.dirname(upath(__file__)), 'templates'), - ) - - def tearDown(self): - settings.TEMPLATE_DIRS = self._old_TEMPLATE_DIRS - - def test_basic(self): - self.assertEqual(loader.render_to_string('test_context.html'), 'obj:') - - def test_basic_context(self): - self.assertEqual(loader.render_to_string('test_context.html', - {'obj': 'test'}), 'obj:test') - - def test_existing_context_kept_clean(self): - context = Context({'obj': 'before'}) - output = loader.render_to_string('test_context.html', {'obj': 'after'}, - context_instance=context) - self.assertEqual(output, 'obj:after') - self.assertEqual(context['obj'], 'before') - - def test_empty_list(self): - six.assertRaisesRegex(self, TemplateDoesNotExist, - 'No template names provided$', - loader.render_to_string, []) - - - def test_select_templates_from_empty_list(self): - six.assertRaisesRegex(self, TemplateDoesNotExist, - 'No template names provided$', - loader.select_template, []) diff --git a/tests/template_tests/nodelist.py b/tests/template_tests/nodelist.py deleted file mode 100644 index 97aa5af6a7..0000000000 --- a/tests/template_tests/nodelist.py +++ /dev/null @@ -1,58 +0,0 @@ -from django.template import VariableNode, Context -from django.template.loader import get_template_from_string -from django.utils.unittest import TestCase -from django.test.utils import override_settings - -class NodelistTest(TestCase): - - def test_for(self): - source = '{% for i in 1 %}{{ a }}{% endfor %}' - template = get_template_from_string(source) - vars = template.nodelist.get_nodes_by_type(VariableNode) - self.assertEqual(len(vars), 1) - - def test_if(self): - source = '{% if x %}{{ a }}{% endif %}' - template = get_template_from_string(source) - vars = template.nodelist.get_nodes_by_type(VariableNode) - self.assertEqual(len(vars), 1) - - def test_ifequal(self): - source = '{% ifequal x y %}{{ a }}{% endifequal %}' - template = get_template_from_string(source) - vars = template.nodelist.get_nodes_by_type(VariableNode) - self.assertEqual(len(vars), 1) - - def test_ifchanged(self): - source = '{% ifchanged x %}{{ a }}{% endifchanged %}' - template = get_template_from_string(source) - vars = template.nodelist.get_nodes_by_type(VariableNode) - self.assertEqual(len(vars), 1) - - -class ErrorIndexTest(TestCase): - """ - Checks whether index of error is calculated correctly in - template debugger in for loops. Refs ticket #5831 - """ - @override_settings(DEBUG=True, TEMPLATE_DEBUG = True) - def test_correct_exception_index(self): - tests = [ - ('{% load bad_tag %}{% for i in range %}{% badsimpletag %}{% endfor %}', (38, 56)), - ('{% load bad_tag %}{% for i in range %}{% for j in range %}{% badsimpletag %}{% endfor %}{% endfor %}', (58, 76)), - ('{% load bad_tag %}{% for i in range %}{% badsimpletag %}{% for j in range %}Hello{% endfor %}{% endfor %}', (38, 56)), - ('{% load bad_tag %}{% for i in range %}{% for j in five %}{% badsimpletag %}{% endfor %}{% endfor %}', (38, 57)), - ('{% load bad_tag %}{% for j in five %}{% badsimpletag %}{% endfor %}', (18, 37)), - ] - context = Context({ - 'range': range(5), - 'five': 5, - }) - for source, expected_error_source_index in tests: - template = get_template_from_string(source) - try: - template.render(context) - except (RuntimeError, TypeError) as e: - error_source_index = e.django_template_source[1] - self.assertEqual(error_source_index, - expected_error_source_index) diff --git a/tests/template_tests/parser.py b/tests/template_tests/parser.py deleted file mode 100644 index 9422da80d7..0000000000 --- a/tests/template_tests/parser.py +++ /dev/null @@ -1,95 +0,0 @@ -""" -Testing some internals of the template processing. These are *not* examples to be copied in user code. -""" -from __future__ import unicode_literals - -from django.template import (TokenParser, FilterExpression, Parser, Variable, - Template, TemplateSyntaxError) -from django.test.utils import override_settings -from django.utils.unittest import TestCase -from django.utils import six - - -class ParserTests(TestCase): - def test_token_parsing(self): - # Tests for TokenParser behavior in the face of quoted strings with - # spaces. - - p = TokenParser("tag thevar|filter sometag") - self.assertEqual(p.tagname, "tag") - self.assertEqual(p.value(), "thevar|filter") - self.assertTrue(p.more()) - self.assertEqual(p.tag(), "sometag") - self.assertFalse(p.more()) - - p = TokenParser('tag "a value"|filter sometag') - self.assertEqual(p.tagname, "tag") - self.assertEqual(p.value(), '"a value"|filter') - self.assertTrue(p.more()) - self.assertEqual(p.tag(), "sometag") - self.assertFalse(p.more()) - - p = TokenParser("tag 'a value'|filter sometag") - self.assertEqual(p.tagname, "tag") - self.assertEqual(p.value(), "'a value'|filter") - self.assertTrue(p.more()) - self.assertEqual(p.tag(), "sometag") - self.assertFalse(p.more()) - - def test_filter_parsing(self): - c = {"article": {"section": "News"}} - p = Parser("") - - def fe_test(s, val): - self.assertEqual(FilterExpression(s, p).resolve(c), val) - - fe_test("article.section", "News") - fe_test("article.section|upper", "NEWS") - fe_test('"News"', "News") - fe_test("'News'", "News") - fe_test(r'"Some \"Good\" News"', 'Some "Good" News') - fe_test(r'"Some \"Good\" News"', 'Some "Good" News') - fe_test(r"'Some \'Bad\' News'", "Some 'Bad' News") - - fe = FilterExpression(r'"Some \"Good\" News"', p) - self.assertEqual(fe.filters, []) - self.assertEqual(fe.var, 'Some "Good" News') - - # Filtered variables should reject access of attributes beginning with - # underscores. - self.assertRaises(TemplateSyntaxError, - FilterExpression, "article._hidden|upper", p - ) - - def test_variable_parsing(self): - c = {"article": {"section": "News"}} - self.assertEqual(Variable("article.section").resolve(c), "News") - self.assertEqual(Variable('"News"').resolve(c), "News") - self.assertEqual(Variable("'News'").resolve(c), "News") - - # Translated strings are handled correctly. - self.assertEqual(Variable("_(article.section)").resolve(c), "News") - self.assertEqual(Variable('_("Good News")').resolve(c), "Good News") - self.assertEqual(Variable("_('Better News')").resolve(c), "Better News") - - # Escaped quotes work correctly as well. - self.assertEqual( - Variable(r'"Some \"Good\" News"').resolve(c), 'Some "Good" News' - ) - self.assertEqual( - Variable(r"'Some \'Better\' News'").resolve(c), "Some 'Better' News" - ) - - # Variables should reject access of attributes beginning with - # underscores. - self.assertRaises(TemplateSyntaxError, - Variable, "article._hidden" - ) - - @override_settings(DEBUG=True, TEMPLATE_DEBUG=True) - def test_compile_filter_error(self): - # regression test for #19819 - msg = "Could not parse the remainder: '@bar' from 'foo@bar'" - with six.assertRaisesRegex(self, TemplateSyntaxError, msg) as cm: - Template("{% if 1 %}{{ foo@bar }}{% endif %}") - self.assertEqual(cm.exception.django_template_source[1], (10, 23)) diff --git a/tests/template_tests/response.py b/tests/template_tests/response.py deleted file mode 100644 index d0ab121b02..0000000000 --- a/tests/template_tests/response.py +++ /dev/null @@ -1,352 +0,0 @@ -from __future__ import unicode_literals - -import os -import pickle -import time -from datetime import datetime - -from django.test import RequestFactory, TestCase -from django.conf import settings -from django.template import Template, Context -from django.template.response import (TemplateResponse, SimpleTemplateResponse, - ContentNotRenderedError) -from django.test.utils import override_settings -from django.utils._os import upath - -def test_processor(request): - return {'processors': 'yes'} -test_processor_name = 'template_tests.response.test_processor' - - -# A test middleware that installs a temporary URLConf -class CustomURLConfMiddleware(object): - def process_request(self, request): - request.urlconf = 'template_tests.alternate_urls' - - -class SimpleTemplateResponseTest(TestCase): - - def _response(self, template='foo', *args, **kwargs): - return SimpleTemplateResponse(Template(template), *args, **kwargs) - - def test_template_resolving(self): - response = SimpleTemplateResponse('first/test.html') - response.render() - self.assertEqual(response.content, b'First template\n') - - templates = ['foo.html', 'second/test.html', 'first/test.html'] - response = SimpleTemplateResponse(templates) - response.render() - self.assertEqual(response.content, b'Second template\n') - - response = self._response() - response.render() - self.assertEqual(response.content, b'foo') - - def test_explicit_baking(self): - # explicit baking - response = self._response() - self.assertFalse(response.is_rendered) - response.render() - self.assertTrue(response.is_rendered) - - def test_render(self): - # response is not re-rendered without the render call - response = self._response().render() - self.assertEqual(response.content, b'foo') - - # rebaking doesn't change the rendered content - response.template_name = Template('bar{{ baz }}') - response.render() - self.assertEqual(response.content, b'foo') - - # but rendered content can be overridden by manually - # setting content - response.content = 'bar' - self.assertEqual(response.content, b'bar') - - def test_iteration_unrendered(self): - # unrendered response raises an exception on iteration - response = self._response() - self.assertFalse(response.is_rendered) - - def iteration(): - for x in response: - pass - self.assertRaises(ContentNotRenderedError, iteration) - self.assertFalse(response.is_rendered) - - def test_iteration_rendered(self): - # iteration works for rendered responses - response = self._response().render() - res = [x for x in response] - self.assertEqual(res, [b'foo']) - - def test_content_access_unrendered(self): - # unrendered response raises an exception when content is accessed - response = self._response() - self.assertFalse(response.is_rendered) - self.assertRaises(ContentNotRenderedError, lambda: response.content) - self.assertFalse(response.is_rendered) - - def test_content_access_rendered(self): - # rendered response content can be accessed - response = self._response().render() - self.assertEqual(response.content, b'foo') - - def test_set_content(self): - # content can be overriden - response = self._response() - self.assertFalse(response.is_rendered) - response.content = 'spam' - self.assertTrue(response.is_rendered) - self.assertEqual(response.content, b'spam') - response.content = 'baz' - self.assertEqual(response.content, b'baz') - - def test_dict_context(self): - response = self._response('{{ foo }}{{ processors }}', - {'foo': 'bar'}) - self.assertEqual(response.context_data, {'foo': 'bar'}) - response.render() - self.assertEqual(response.content, b'bar') - - def test_context_instance(self): - response = self._response('{{ foo }}{{ processors }}', - Context({'foo': 'bar'})) - self.assertEqual(response.context_data.__class__, Context) - response.render() - self.assertEqual(response.content, b'bar') - - def test_kwargs(self): - response = self._response(content_type = 'application/json', status=504) - self.assertEqual(response['content-type'], 'application/json') - self.assertEqual(response.status_code, 504) - - def test_args(self): - response = SimpleTemplateResponse('', {}, 'application/json', 504) - self.assertEqual(response['content-type'], 'application/json') - self.assertEqual(response.status_code, 504) - - def test_post_callbacks(self): - "Rendering a template response triggers the post-render callbacks" - post = [] - - def post1(obj): - post.append('post1') - def post2(obj): - post.append('post2') - - response = SimpleTemplateResponse('first/test.html', {}) - response.add_post_render_callback(post1) - response.add_post_render_callback(post2) - - # When the content is rendered, all the callbacks are invoked, too. - response.render() - self.assertEqual(response.content, b'First template\n') - self.assertEqual(post, ['post1','post2']) - - - def test_pickling(self): - # Create a template response. The context is - # known to be unpickleable (e.g., a function). - response = SimpleTemplateResponse('first/test.html', { - 'value': 123, - 'fn': datetime.now, - }) - self.assertRaises(ContentNotRenderedError, - pickle.dumps, response) - - # But if we render the response, we can pickle it. - response.render() - pickled_response = pickle.dumps(response) - unpickled_response = pickle.loads(pickled_response) - - self.assertEqual(unpickled_response.content, response.content) - self.assertEqual(unpickled_response['content-type'], response['content-type']) - self.assertEqual(unpickled_response.status_code, response.status_code) - - # ...and the unpickled reponse doesn't have the - # template-related attributes, so it can't be re-rendered - template_attrs = ('template_name', 'context_data', '_post_render_callbacks') - for attr in template_attrs: - self.assertFalse(hasattr(unpickled_response, attr)) - - # ...and requesting any of those attributes raises an exception - for attr in template_attrs: - with self.assertRaises(AttributeError): - getattr(unpickled_response, attr) - - def test_repickling(self): - response = SimpleTemplateResponse('first/test.html', { - 'value': 123, - 'fn': datetime.now, - }) - self.assertRaises(ContentNotRenderedError, - pickle.dumps, response) - - response.render() - pickled_response = pickle.dumps(response) - unpickled_response = pickle.loads(pickled_response) - repickled_response = pickle.dumps(unpickled_response) - - def test_pickling_cookie(self): - response = SimpleTemplateResponse('first/test.html', { - 'value': 123, - 'fn': datetime.now, - }) - - response.cookies['key'] = 'value' - - response.render() - pickled_response = pickle.dumps(response, pickle.HIGHEST_PROTOCOL) - unpickled_response = pickle.loads(pickled_response) - - self.assertEqual(unpickled_response.cookies['key'].value, 'value') - - -@override_settings( - TEMPLATE_CONTEXT_PROCESSORS=[test_processor_name], - TEMPLATE_DIRS=(os.path.join(os.path.dirname(upath(__file__)), 'templates')), -) -class TemplateResponseTest(TestCase): - - def setUp(self): - self.factory = RequestFactory() - - def _response(self, template='foo', *args, **kwargs): - return TemplateResponse(self.factory.get('/'), Template(template), - *args, **kwargs) - - def test_render(self): - response = self._response('{{ foo }}{{ processors }}').render() - self.assertEqual(response.content, b'yes') - - def test_render_with_requestcontext(self): - response = self._response('{{ foo }}{{ processors }}', - {'foo': 'bar'}).render() - self.assertEqual(response.content, b'baryes') - - def test_render_with_context(self): - response = self._response('{{ foo }}{{ processors }}', - Context({'foo': 'bar'})).render() - self.assertEqual(response.content, b'bar') - - def test_kwargs(self): - response = self._response(content_type = 'application/json', - status=504) - self.assertEqual(response['content-type'], 'application/json') - self.assertEqual(response.status_code, 504) - - def test_args(self): - response = TemplateResponse(self.factory.get('/'), '', {}, - 'application/json', 504) - self.assertEqual(response['content-type'], 'application/json') - self.assertEqual(response.status_code, 504) - - def test_custom_app(self): - response = self._response('{{ foo }}', current_app="foobar") - - rc = response.resolve_context(response.context_data) - - self.assertEqual(rc.current_app, 'foobar') - - def test_pickling(self): - # Create a template response. The context is - # known to be unpickleable (e.g., a function). - response = TemplateResponse(self.factory.get('/'), - 'first/test.html', { - 'value': 123, - 'fn': datetime.now, - }) - self.assertRaises(ContentNotRenderedError, - pickle.dumps, response) - - # But if we render the response, we can pickle it. - response.render() - pickled_response = pickle.dumps(response) - unpickled_response = pickle.loads(pickled_response) - - self.assertEqual(unpickled_response.content, response.content) - self.assertEqual(unpickled_response['content-type'], response['content-type']) - self.assertEqual(unpickled_response.status_code, response.status_code) - - # ...and the unpickled reponse doesn't have the - # template-related attributes, so it can't be re-rendered - template_attrs = ('template_name', 'context_data', - '_post_render_callbacks', '_request', '_current_app') - for attr in template_attrs: - self.assertFalse(hasattr(unpickled_response, attr)) - - # ...and requesting any of those attributes raises an exception - for attr in template_attrs: - with self.assertRaises(AttributeError): - getattr(unpickled_response, attr) - - def test_repickling(self): - response = SimpleTemplateResponse('first/test.html', { - 'value': 123, - 'fn': datetime.now, - }) - self.assertRaises(ContentNotRenderedError, - pickle.dumps, response) - - response.render() - pickled_response = pickle.dumps(response) - unpickled_response = pickle.loads(pickled_response) - repickled_response = pickle.dumps(unpickled_response) - - -class CustomURLConfTest(TestCase): - urls = 'template_tests.urls' - - def setUp(self): - self.old_MIDDLEWARE_CLASSES = settings.MIDDLEWARE_CLASSES - settings.MIDDLEWARE_CLASSES = list(settings.MIDDLEWARE_CLASSES) + [ - 'template_tests.response.CustomURLConfMiddleware' - ] - - def tearDown(self): - settings.MIDDLEWARE_CLASSES = self.old_MIDDLEWARE_CLASSES - - def test_custom_urlconf(self): - response = self.client.get('/template_response_view/') - self.assertEqual(response.status_code, 200) - self.assertContains(response, 'This is where you can find the snark: /snark/') - - -class CacheMiddlewareTest(TestCase): - urls = 'template_tests.alternate_urls' - - def setUp(self): - self.old_MIDDLEWARE_CLASSES = settings.MIDDLEWARE_CLASSES - self.CACHE_MIDDLEWARE_SECONDS = settings.CACHE_MIDDLEWARE_SECONDS - - settings.CACHE_MIDDLEWARE_SECONDS = 2.0 - settings.MIDDLEWARE_CLASSES = list(settings.MIDDLEWARE_CLASSES) + [ - 'django.middleware.cache.FetchFromCacheMiddleware', - 'django.middleware.cache.UpdateCacheMiddleware', - ] - - def tearDown(self): - settings.MIDDLEWARE_CLASSES = self.old_MIDDLEWARE_CLASSES - settings.CACHE_MIDDLEWARE_SECONDS = self.CACHE_MIDDLEWARE_SECONDS - - def test_middleware_caching(self): - response = self.client.get('/template_response_view/') - self.assertEqual(response.status_code, 200) - - time.sleep(1.0) - - response2 = self.client.get('/template_response_view/') - self.assertEqual(response2.status_code, 200) - - self.assertEqual(response.content, response2.content) - - time.sleep(2.0) - - # Let the cache expire and test again - response2 = self.client.get('/template_response_view/') - self.assertEqual(response2.status_code, 200) - - self.assertNotEqual(response.content, response2.content) diff --git a/tests/template_tests/smartif.py b/tests/template_tests/smartif.py deleted file mode 100644 index 3a705ca663..0000000000 --- a/tests/template_tests/smartif.py +++ /dev/null @@ -1,53 +0,0 @@ -from django.template.smartif import IfParser -from django.utils import unittest - -class SmartIfTests(unittest.TestCase): - - def assertCalcEqual(self, expected, tokens): - self.assertEqual(expected, IfParser(tokens).parse().eval({})) - - # We only test things here that are difficult to test elsewhere - # Many other tests are found in the main tests for builtin template tags - # Test parsing via the printed parse tree - def test_not(self): - var = IfParser(["not", False]).parse() - self.assertEqual("(not (literal False))", repr(var)) - self.assertTrue(var.eval({})) - - self.assertFalse(IfParser(["not", True]).parse().eval({})) - - def test_or(self): - var = IfParser([True, "or", False]).parse() - self.assertEqual("(or (literal True) (literal False))", repr(var)) - self.assertTrue(var.eval({})) - - def test_in(self): - list_ = [1,2,3] - self.assertCalcEqual(True, [1, 'in', list_]) - self.assertCalcEqual(False, [1, 'in', None]) - self.assertCalcEqual(False, [None, 'in', list_]) - - def test_not_in(self): - list_ = [1,2,3] - self.assertCalcEqual(False, [1, 'not', 'in', list_]) - self.assertCalcEqual(True, [4, 'not', 'in', list_]) - self.assertCalcEqual(False, [1, 'not', 'in', None]) - self.assertCalcEqual(True, [None, 'not', 'in', list_]) - - def test_precedence(self): - # (False and False) or True == True <- we want this one, like Python - # False and (False or True) == False - self.assertCalcEqual(True, [False, 'and', False, 'or', True]) - - # True or (False and False) == True <- we want this one, like Python - # (True or False) and False == False - self.assertCalcEqual(True, [True, 'or', False, 'and', False]) - - # (1 or 1) == 2 -> False - # 1 or (1 == 2) -> True <- we want this one - self.assertCalcEqual(True, [1, 'or', 1, '==', 2]) - - self.assertCalcEqual(True, [True, '==', True, 'or', True, '==', False]) - - self.assertEqual("(or (and (== (literal 1) (literal 2)) (literal 3)) (literal 4))", - repr(IfParser([1, '==', 2, 'and', 3, 'or', 4]).parse())) diff --git a/tests/template_tests/test_callables.py b/tests/template_tests/test_callables.py new file mode 100644 index 0000000000..882a8c6e06 --- /dev/null +++ b/tests/template_tests/test_callables.py @@ -0,0 +1,113 @@ +from __future__ import unicode_literals + +from django import template +from django.utils.unittest import TestCase + +class CallableVariablesTests(TestCase): + + def test_callable(self): + + class Doodad(object): + def __init__(self, value): + self.num_calls = 0 + self.value = value + def __call__(self): + self.num_calls += 1 + return {"the_value": self.value} + + my_doodad = Doodad(42) + c = template.Context({"my_doodad": my_doodad}) + + # We can't access ``my_doodad.value`` in the template, because + # ``my_doodad.__call__`` will be invoked first, yielding a dictionary + # without a key ``value``. + t = template.Template('{{ my_doodad.value }}') + self.assertEqual(t.render(c), '') + + # We can confirm that the doodad has been called + self.assertEqual(my_doodad.num_calls, 1) + + # But we can access keys on the dict that's returned + # by ``__call__``, instead. + t = template.Template('{{ my_doodad.the_value }}') + self.assertEqual(t.render(c), '42') + self.assertEqual(my_doodad.num_calls, 2) + + def test_alters_data(self): + + class Doodad(object): + alters_data = True + def __init__(self, value): + self.num_calls = 0 + self.value = value + def __call__(self): + self.num_calls += 1 + return {"the_value": self.value} + + my_doodad = Doodad(42) + c = template.Context({"my_doodad": my_doodad}) + + # Since ``my_doodad.alters_data`` is True, the template system will not + # try to call our doodad but will use TEMPLATE_STRING_IF_INVALID + t = template.Template('{{ my_doodad.value }}') + self.assertEqual(t.render(c), '') + t = template.Template('{{ my_doodad.the_value }}') + self.assertEqual(t.render(c), '') + + # Double-check that the object was really never called during the + # template rendering. + self.assertEqual(my_doodad.num_calls, 0) + + def test_do_not_call(self): + + class Doodad(object): + do_not_call_in_templates = True + def __init__(self, value): + self.num_calls = 0 + self.value = value + def __call__(self): + self.num_calls += 1 + return {"the_value": self.value} + + my_doodad = Doodad(42) + c = template.Context({"my_doodad": my_doodad}) + + # Since ``my_doodad.do_not_call_in_templates`` is True, the template + # system will not try to call our doodad. We can access its attributes + # as normal, and we don't have access to the dict that it returns when + # called. + t = template.Template('{{ my_doodad.value }}') + self.assertEqual(t.render(c), '42') + t = template.Template('{{ my_doodad.the_value }}') + self.assertEqual(t.render(c), '') + + # Double-check that the object was really never called during the + # template rendering. + self.assertEqual(my_doodad.num_calls, 0) + + def test_do_not_call_and_alters_data(self): + # If we combine ``alters_data`` and ``do_not_call_in_templates``, the + # ``alters_data`` attribute will not make any difference in the + # template system's behavior. + + class Doodad(object): + do_not_call_in_templates = True + alters_data = True + def __init__(self, value): + self.num_calls = 0 + self.value = value + def __call__(self): + self.num_calls += 1 + return {"the_value": self.value} + + my_doodad = Doodad(42) + c = template.Context({"my_doodad": my_doodad}) + + t = template.Template('{{ my_doodad.value }}') + self.assertEqual(t.render(c), '42') + t = template.Template('{{ my_doodad.the_value }}') + self.assertEqual(t.render(c), '') + + # Double-check that the object was really never called during the + # template rendering. + self.assertEqual(my_doodad.num_calls, 0) diff --git a/tests/template_tests/test_context.py b/tests/template_tests/test_context.py new file mode 100644 index 0000000000..05c1dd57b9 --- /dev/null +++ b/tests/template_tests/test_context.py @@ -0,0 +1,16 @@ +# coding: utf-8 +from django.template import Context +from django.utils.unittest import TestCase + + +class ContextTests(TestCase): + def test_context(self): + c = Context({"a": 1, "b": "xyzzy"}) + self.assertEqual(c["a"], 1) + self.assertEqual(c.push(), {}) + c["a"] = 2 + self.assertEqual(c["a"], 2) + self.assertEqual(c.get("a"), 2) + self.assertEqual(c.pop(), {"a": 2}) + self.assertEqual(c["a"], 1) + self.assertEqual(c.get("foo", 42), 42) diff --git a/tests/template_tests/test_custom.py b/tests/template_tests/test_custom.py new file mode 100644 index 0000000000..4aea08237d --- /dev/null +++ b/tests/template_tests/test_custom.py @@ -0,0 +1,377 @@ +from __future__ import absolute_import, unicode_literals + +from django import template +from django.utils import six +from django.utils.unittest import TestCase + +from .templatetags import custom + + +class CustomFilterTests(TestCase): + def test_filter(self): + t = template.Template("{% load custom %}{{ string|trim:5 }}") + self.assertEqual( + t.render(template.Context({"string": "abcdefghijklmnopqrstuvwxyz"})), + "abcde" + ) + + +class CustomTagTests(TestCase): + def verify_tag(self, tag, name): + self.assertEqual(tag.__name__, name) + self.assertEqual(tag.__doc__, 'Expected %s __doc__' % name) + self.assertEqual(tag.__dict__['anything'], 'Expected %s __dict__' % name) + + def test_simple_tags(self): + c = template.Context({'value': 42}) + + t = template.Template('{% load custom %}{% no_params %}') + self.assertEqual(t.render(c), 'no_params - Expected result') + + t = template.Template('{% load custom %}{% one_param 37 %}') + self.assertEqual(t.render(c), 'one_param - Expected result: 37') + + t = template.Template('{% load custom %}{% explicit_no_context 37 %}') + self.assertEqual(t.render(c), 'explicit_no_context - Expected result: 37') + + t = template.Template('{% load custom %}{% no_params_with_context %}') + self.assertEqual(t.render(c), 'no_params_with_context - Expected result (context value: 42)') + + t = template.Template('{% load custom %}{% params_and_context 37 %}') + self.assertEqual(t.render(c), 'params_and_context - Expected result (context value: 42): 37') + + t = template.Template('{% load custom %}{% simple_two_params 37 42 %}') + self.assertEqual(t.render(c), 'simple_two_params - Expected result: 37, 42') + + t = template.Template('{% load custom %}{% simple_one_default 37 %}') + self.assertEqual(t.render(c), 'simple_one_default - Expected result: 37, hi') + + t = template.Template('{% load custom %}{% simple_one_default 37 two="hello" %}') + self.assertEqual(t.render(c), 'simple_one_default - Expected result: 37, hello') + + t = template.Template('{% load custom %}{% simple_one_default one=99 two="hello" %}') + self.assertEqual(t.render(c), 'simple_one_default - Expected result: 99, hello') + + six.assertRaisesRegex(self, template.TemplateSyntaxError, + "'simple_one_default' received unexpected keyword argument 'three'", + template.Template, '{% load custom %}{% simple_one_default 99 two="hello" three="foo" %}') + + t = template.Template('{% load custom %}{% simple_one_default 37 42 %}') + self.assertEqual(t.render(c), 'simple_one_default - Expected result: 37, 42') + + t = template.Template('{% load custom %}{% simple_unlimited_args 37 %}') + self.assertEqual(t.render(c), 'simple_unlimited_args - Expected result: 37, hi') + + t = template.Template('{% load custom %}{% simple_unlimited_args 37 42 56 89 %}') + self.assertEqual(t.render(c), 'simple_unlimited_args - Expected result: 37, 42, 56, 89') + + t = template.Template('{% load custom %}{% simple_only_unlimited_args %}') + self.assertEqual(t.render(c), 'simple_only_unlimited_args - Expected result: ') + + t = template.Template('{% load custom %}{% simple_only_unlimited_args 37 42 56 89 %}') + self.assertEqual(t.render(c), 'simple_only_unlimited_args - Expected result: 37, 42, 56, 89') + + six.assertRaisesRegex(self, template.TemplateSyntaxError, + "'simple_two_params' received too many positional arguments", + template.Template, '{% load custom %}{% simple_two_params 37 42 56 %}') + + six.assertRaisesRegex(self, template.TemplateSyntaxError, + "'simple_one_default' received too many positional arguments", + template.Template, '{% load custom %}{% simple_one_default 37 42 56 %}') + + t = template.Template('{% load custom %}{% simple_unlimited_args_kwargs 37 40|add:2 56 eggs="scrambled" four=1|add:3 %}') + self.assertEqual(t.render(c), 'simple_unlimited_args_kwargs - Expected result: 37, 42, 56 / eggs=scrambled, four=4') + + six.assertRaisesRegex(self, template.TemplateSyntaxError, + "'simple_unlimited_args_kwargs' received some positional argument\(s\) after some keyword argument\(s\)", + template.Template, '{% load custom %}{% simple_unlimited_args_kwargs 37 40|add:2 eggs="scrambled" 56 four=1|add:3 %}') + + six.assertRaisesRegex(self, template.TemplateSyntaxError, + "'simple_unlimited_args_kwargs' received multiple values for keyword argument 'eggs'", + template.Template, '{% load custom %}{% simple_unlimited_args_kwargs 37 eggs="scrambled" eggs="scrambled" %}') + + def test_simple_tag_registration(self): + # Test that the decorators preserve the decorated function's docstring, name and attributes. + self.verify_tag(custom.no_params, 'no_params') + self.verify_tag(custom.one_param, 'one_param') + self.verify_tag(custom.explicit_no_context, 'explicit_no_context') + self.verify_tag(custom.no_params_with_context, 'no_params_with_context') + self.verify_tag(custom.params_and_context, 'params_and_context') + self.verify_tag(custom.simple_unlimited_args_kwargs, 'simple_unlimited_args_kwargs') + self.verify_tag(custom.simple_tag_without_context_parameter, 'simple_tag_without_context_parameter') + + def test_simple_tag_missing_context(self): + # The 'context' parameter must be present when takes_context is True + six.assertRaisesRegex(self, template.TemplateSyntaxError, + "'simple_tag_without_context_parameter' is decorated with takes_context=True so it must have a first argument of 'context'", + template.Template, '{% load custom %}{% simple_tag_without_context_parameter 123 %}') + + def test_inclusion_tags(self): + c = template.Context({'value': 42}) + + t = template.Template('{% load custom %}{% inclusion_no_params %}') + self.assertEqual(t.render(c), 'inclusion_no_params - Expected result\n') + + t = template.Template('{% load custom %}{% inclusion_one_param 37 %}') + self.assertEqual(t.render(c), 'inclusion_one_param - Expected result: 37\n') + + t = template.Template('{% load custom %}{% inclusion_explicit_no_context 37 %}') + self.assertEqual(t.render(c), 'inclusion_explicit_no_context - Expected result: 37\n') + + t = template.Template('{% load custom %}{% inclusion_no_params_with_context %}') + self.assertEqual(t.render(c), 'inclusion_no_params_with_context - Expected result (context value: 42)\n') + + t = template.Template('{% load custom %}{% inclusion_params_and_context 37 %}') + self.assertEqual(t.render(c), 'inclusion_params_and_context - Expected result (context value: 42): 37\n') + + t = template.Template('{% load custom %}{% inclusion_two_params 37 42 %}') + self.assertEqual(t.render(c), 'inclusion_two_params - Expected result: 37, 42\n') + + t = template.Template('{% load custom %}{% inclusion_one_default 37 %}') + self.assertEqual(t.render(c), 'inclusion_one_default - Expected result: 37, hi\n') + + t = template.Template('{% load custom %}{% inclusion_one_default 37 two="hello" %}') + self.assertEqual(t.render(c), 'inclusion_one_default - Expected result: 37, hello\n') + + t = template.Template('{% load custom %}{% inclusion_one_default one=99 two="hello" %}') + self.assertEqual(t.render(c), 'inclusion_one_default - Expected result: 99, hello\n') + + six.assertRaisesRegex(self, template.TemplateSyntaxError, + "'inclusion_one_default' received unexpected keyword argument 'three'", + template.Template, '{% load custom %}{% inclusion_one_default 99 two="hello" three="foo" %}') + + t = template.Template('{% load custom %}{% inclusion_one_default 37 42 %}') + self.assertEqual(t.render(c), 'inclusion_one_default - Expected result: 37, 42\n') + + t = template.Template('{% load custom %}{% inclusion_unlimited_args 37 %}') + self.assertEqual(t.render(c), 'inclusion_unlimited_args - Expected result: 37, hi\n') + + t = template.Template('{% load custom %}{% inclusion_unlimited_args 37 42 56 89 %}') + self.assertEqual(t.render(c), 'inclusion_unlimited_args - Expected result: 37, 42, 56, 89\n') + + t = template.Template('{% load custom %}{% inclusion_only_unlimited_args %}') + self.assertEqual(t.render(c), 'inclusion_only_unlimited_args - Expected result: \n') + + t = template.Template('{% load custom %}{% inclusion_only_unlimited_args 37 42 56 89 %}') + self.assertEqual(t.render(c), 'inclusion_only_unlimited_args - Expected result: 37, 42, 56, 89\n') + + six.assertRaisesRegex(self, template.TemplateSyntaxError, + "'inclusion_two_params' received too many positional arguments", + template.Template, '{% load custom %}{% inclusion_two_params 37 42 56 %}') + + six.assertRaisesRegex(self, template.TemplateSyntaxError, + "'inclusion_one_default' received too many positional arguments", + template.Template, '{% load custom %}{% inclusion_one_default 37 42 56 %}') + + six.assertRaisesRegex(self, template.TemplateSyntaxError, + "'inclusion_one_default' did not receive value\(s\) for the argument\(s\): 'one'", + template.Template, '{% load custom %}{% inclusion_one_default %}') + + six.assertRaisesRegex(self, template.TemplateSyntaxError, + "'inclusion_unlimited_args' did not receive value\(s\) for the argument\(s\): 'one'", + template.Template, '{% load custom %}{% inclusion_unlimited_args %}') + + t = template.Template('{% load custom %}{% inclusion_unlimited_args_kwargs 37 40|add:2 56 eggs="scrambled" four=1|add:3 %}') + self.assertEqual(t.render(c), 'inclusion_unlimited_args_kwargs - Expected result: 37, 42, 56 / eggs=scrambled, four=4\n') + + six.assertRaisesRegex(self, template.TemplateSyntaxError, + "'inclusion_unlimited_args_kwargs' received some positional argument\(s\) after some keyword argument\(s\)", + template.Template, '{% load custom %}{% inclusion_unlimited_args_kwargs 37 40|add:2 eggs="scrambled" 56 four=1|add:3 %}') + + six.assertRaisesRegex(self, template.TemplateSyntaxError, + "'inclusion_unlimited_args_kwargs' received multiple values for keyword argument 'eggs'", + template.Template, '{% load custom %}{% inclusion_unlimited_args_kwargs 37 eggs="scrambled" eggs="scrambled" %}') + + def test_include_tag_missing_context(self): + # The 'context' parameter must be present when takes_context is True + six.assertRaisesRegex(self, template.TemplateSyntaxError, + "'inclusion_tag_without_context_parameter' is decorated with takes_context=True so it must have a first argument of 'context'", + template.Template, '{% load custom %}{% inclusion_tag_without_context_parameter 123 %}') + + def test_inclusion_tags_from_template(self): + c = template.Context({'value': 42}) + + t = template.Template('{% load custom %}{% inclusion_no_params_from_template %}') + self.assertEqual(t.render(c), 'inclusion_no_params_from_template - Expected result\n') + + t = template.Template('{% load custom %}{% inclusion_one_param_from_template 37 %}') + self.assertEqual(t.render(c), 'inclusion_one_param_from_template - Expected result: 37\n') + + t = template.Template('{% load custom %}{% inclusion_explicit_no_context_from_template 37 %}') + self.assertEqual(t.render(c), 'inclusion_explicit_no_context_from_template - Expected result: 37\n') + + t = template.Template('{% load custom %}{% inclusion_no_params_with_context_from_template %}') + self.assertEqual(t.render(c), 'inclusion_no_params_with_context_from_template - Expected result (context value: 42)\n') + + t = template.Template('{% load custom %}{% inclusion_params_and_context_from_template 37 %}') + self.assertEqual(t.render(c), 'inclusion_params_and_context_from_template - Expected result (context value: 42): 37\n') + + t = template.Template('{% load custom %}{% inclusion_two_params_from_template 37 42 %}') + self.assertEqual(t.render(c), 'inclusion_two_params_from_template - Expected result: 37, 42\n') + + t = template.Template('{% load custom %}{% inclusion_one_default_from_template 37 %}') + self.assertEqual(t.render(c), 'inclusion_one_default_from_template - Expected result: 37, hi\n') + + t = template.Template('{% load custom %}{% inclusion_one_default_from_template 37 42 %}') + self.assertEqual(t.render(c), 'inclusion_one_default_from_template - Expected result: 37, 42\n') + + t = template.Template('{% load custom %}{% inclusion_unlimited_args_from_template 37 %}') + self.assertEqual(t.render(c), 'inclusion_unlimited_args_from_template - Expected result: 37, hi\n') + + t = template.Template('{% load custom %}{% inclusion_unlimited_args_from_template 37 42 56 89 %}') + self.assertEqual(t.render(c), 'inclusion_unlimited_args_from_template - Expected result: 37, 42, 56, 89\n') + + t = template.Template('{% load custom %}{% inclusion_only_unlimited_args_from_template %}') + self.assertEqual(t.render(c), 'inclusion_only_unlimited_args_from_template - Expected result: \n') + + t = template.Template('{% load custom %}{% inclusion_only_unlimited_args_from_template 37 42 56 89 %}') + self.assertEqual(t.render(c), 'inclusion_only_unlimited_args_from_template - Expected result: 37, 42, 56, 89\n') + + def test_inclusion_tag_registration(self): + # Test that the decorators preserve the decorated function's docstring, name and attributes. + self.verify_tag(custom.inclusion_no_params, 'inclusion_no_params') + self.verify_tag(custom.inclusion_one_param, 'inclusion_one_param') + self.verify_tag(custom.inclusion_explicit_no_context, 'inclusion_explicit_no_context') + self.verify_tag(custom.inclusion_no_params_with_context, 'inclusion_no_params_with_context') + self.verify_tag(custom.inclusion_params_and_context, 'inclusion_params_and_context') + self.verify_tag(custom.inclusion_two_params, 'inclusion_two_params') + self.verify_tag(custom.inclusion_one_default, 'inclusion_one_default') + self.verify_tag(custom.inclusion_unlimited_args, 'inclusion_unlimited_args') + self.verify_tag(custom.inclusion_only_unlimited_args, 'inclusion_only_unlimited_args') + self.verify_tag(custom.inclusion_tag_without_context_parameter, 'inclusion_tag_without_context_parameter') + self.verify_tag(custom.inclusion_tag_use_l10n, 'inclusion_tag_use_l10n') + self.verify_tag(custom.inclusion_tag_current_app, 'inclusion_tag_current_app') + self.verify_tag(custom.inclusion_unlimited_args_kwargs, 'inclusion_unlimited_args_kwargs') + + def test_15070_current_app(self): + """ + Test that inclusion tag passes down `current_app` of context to the + Context of the included/rendered template as well. + """ + c = template.Context({}) + t = template.Template('{% load custom %}{% inclusion_tag_current_app %}') + self.assertEqual(t.render(c).strip(), 'None') + + c.current_app = 'advanced' + self.assertEqual(t.render(c).strip(), 'advanced') + + def test_15070_use_l10n(self): + """ + Test that inclusion tag passes down `use_l10n` of context to the + Context of the included/rendered template as well. + """ + c = template.Context({}) + t = template.Template('{% load custom %}{% inclusion_tag_use_l10n %}') + self.assertEqual(t.render(c).strip(), 'None') + + c.use_l10n = True + self.assertEqual(t.render(c).strip(), 'True') + + def test_assignment_tags(self): + c = template.Context({'value': 42}) + + t = template.Template('{% load custom %}{% assignment_no_params as var %}The result is: {{ var }}') + self.assertEqual(t.render(c), 'The result is: assignment_no_params - Expected result') + + t = template.Template('{% load custom %}{% assignment_one_param 37 as var %}The result is: {{ var }}') + self.assertEqual(t.render(c), 'The result is: assignment_one_param - Expected result: 37') + + t = template.Template('{% load custom %}{% assignment_explicit_no_context 37 as var %}The result is: {{ var }}') + self.assertEqual(t.render(c), 'The result is: assignment_explicit_no_context - Expected result: 37') + + t = template.Template('{% load custom %}{% assignment_no_params_with_context as var %}The result is: {{ var }}') + self.assertEqual(t.render(c), 'The result is: assignment_no_params_with_context - Expected result (context value: 42)') + + t = template.Template('{% load custom %}{% assignment_params_and_context 37 as var %}The result is: {{ var }}') + self.assertEqual(t.render(c), 'The result is: assignment_params_and_context - Expected result (context value: 42): 37') + + t = template.Template('{% load custom %}{% assignment_two_params 37 42 as var %}The result is: {{ var }}') + self.assertEqual(t.render(c), 'The result is: assignment_two_params - Expected result: 37, 42') + + t = template.Template('{% load custom %}{% assignment_one_default 37 as var %}The result is: {{ var }}') + self.assertEqual(t.render(c), 'The result is: assignment_one_default - Expected result: 37, hi') + + t = template.Template('{% load custom %}{% assignment_one_default 37 two="hello" as var %}The result is: {{ var }}') + self.assertEqual(t.render(c), 'The result is: assignment_one_default - Expected result: 37, hello') + + t = template.Template('{% load custom %}{% assignment_one_default one=99 two="hello" as var %}The result is: {{ var }}') + self.assertEqual(t.render(c), 'The result is: assignment_one_default - Expected result: 99, hello') + + six.assertRaisesRegex(self, template.TemplateSyntaxError, + "'assignment_one_default' received unexpected keyword argument 'three'", + template.Template, '{% load custom %}{% assignment_one_default 99 two="hello" three="foo" as var %}') + + t = template.Template('{% load custom %}{% assignment_one_default 37 42 as var %}The result is: {{ var }}') + self.assertEqual(t.render(c), 'The result is: assignment_one_default - Expected result: 37, 42') + + t = template.Template('{% load custom %}{% assignment_unlimited_args 37 as var %}The result is: {{ var }}') + self.assertEqual(t.render(c), 'The result is: assignment_unlimited_args - Expected result: 37, hi') + + t = template.Template('{% load custom %}{% assignment_unlimited_args 37 42 56 89 as var %}The result is: {{ var }}') + self.assertEqual(t.render(c), 'The result is: assignment_unlimited_args - Expected result: 37, 42, 56, 89') + + t = template.Template('{% load custom %}{% assignment_only_unlimited_args as var %}The result is: {{ var }}') + self.assertEqual(t.render(c), 'The result is: assignment_only_unlimited_args - Expected result: ') + + t = template.Template('{% load custom %}{% assignment_only_unlimited_args 37 42 56 89 as var %}The result is: {{ var }}') + self.assertEqual(t.render(c), 'The result is: assignment_only_unlimited_args - Expected result: 37, 42, 56, 89') + + six.assertRaisesRegex(self, template.TemplateSyntaxError, + "'assignment_one_param' tag takes at least 2 arguments and the second last argument must be 'as'", + template.Template, '{% load custom %}{% assignment_one_param 37 %}The result is: {{ var }}') + + six.assertRaisesRegex(self, template.TemplateSyntaxError, + "'assignment_one_param' tag takes at least 2 arguments and the second last argument must be 'as'", + template.Template, '{% load custom %}{% assignment_one_param 37 as %}The result is: {{ var }}') + + six.assertRaisesRegex(self, template.TemplateSyntaxError, + "'assignment_one_param' tag takes at least 2 arguments and the second last argument must be 'as'", + template.Template, '{% load custom %}{% assignment_one_param 37 ass var %}The result is: {{ var }}') + + six.assertRaisesRegex(self, template.TemplateSyntaxError, + "'assignment_two_params' received too many positional arguments", + template.Template, '{% load custom %}{% assignment_two_params 37 42 56 as var %}The result is: {{ var }}') + + six.assertRaisesRegex(self, template.TemplateSyntaxError, + "'assignment_one_default' received too many positional arguments", + template.Template, '{% load custom %}{% assignment_one_default 37 42 56 as var %}The result is: {{ var }}') + + six.assertRaisesRegex(self, template.TemplateSyntaxError, + "'assignment_one_default' did not receive value\(s\) for the argument\(s\): 'one'", + template.Template, '{% load custom %}{% assignment_one_default as var %}The result is: {{ var }}') + + six.assertRaisesRegex(self, template.TemplateSyntaxError, + "'assignment_unlimited_args' did not receive value\(s\) for the argument\(s\): 'one'", + template.Template, '{% load custom %}{% assignment_unlimited_args as var %}The result is: {{ var }}') + + t = template.Template('{% load custom %}{% assignment_unlimited_args_kwargs 37 40|add:2 56 eggs="scrambled" four=1|add:3 as var %}The result is: {{ var }}') + self.assertEqual(t.render(c), 'The result is: assignment_unlimited_args_kwargs - Expected result: 37, 42, 56 / eggs=scrambled, four=4') + + six.assertRaisesRegex(self, template.TemplateSyntaxError, + "'assignment_unlimited_args_kwargs' received some positional argument\(s\) after some keyword argument\(s\)", + template.Template, '{% load custom %}{% assignment_unlimited_args_kwargs 37 40|add:2 eggs="scrambled" 56 four=1|add:3 as var %}The result is: {{ var }}') + + six.assertRaisesRegex(self, template.TemplateSyntaxError, + "'assignment_unlimited_args_kwargs' received multiple values for keyword argument 'eggs'", + template.Template, '{% load custom %}{% assignment_unlimited_args_kwargs 37 eggs="scrambled" eggs="scrambled" as var %}The result is: {{ var }}') + + def test_assignment_tag_registration(self): + # Test that the decorators preserve the decorated function's docstring, name and attributes. + self.verify_tag(custom.assignment_no_params, 'assignment_no_params') + self.verify_tag(custom.assignment_one_param, 'assignment_one_param') + self.verify_tag(custom.assignment_explicit_no_context, 'assignment_explicit_no_context') + self.verify_tag(custom.assignment_no_params_with_context, 'assignment_no_params_with_context') + self.verify_tag(custom.assignment_params_and_context, 'assignment_params_and_context') + self.verify_tag(custom.assignment_one_default, 'assignment_one_default') + self.verify_tag(custom.assignment_two_params, 'assignment_two_params') + self.verify_tag(custom.assignment_unlimited_args, 'assignment_unlimited_args') + self.verify_tag(custom.assignment_only_unlimited_args, 'assignment_only_unlimited_args') + self.verify_tag(custom.assignment_unlimited_args, 'assignment_unlimited_args') + self.verify_tag(custom.assignment_unlimited_args_kwargs, 'assignment_unlimited_args_kwargs') + self.verify_tag(custom.assignment_tag_without_context_parameter, 'assignment_tag_without_context_parameter') + + def test_assignment_tag_missing_context(self): + # The 'context' parameter must be present when takes_context is True + six.assertRaisesRegex(self, template.TemplateSyntaxError, + "'assignment_tag_without_context_parameter' is decorated with takes_context=True so it must have a first argument of 'context'", + template.Template, '{% load custom %}{% assignment_tag_without_context_parameter 123 as var %}') diff --git a/tests/template_tests/test_loaders.py b/tests/template_tests/test_loaders.py new file mode 100644 index 0000000000..b77965203f --- /dev/null +++ b/tests/template_tests/test_loaders.py @@ -0,0 +1,156 @@ +""" +Test cases for the template loaders + +Note: This test requires setuptools! +""" + +from django.conf import settings + +if __name__ == '__main__': + settings.configure() + +import sys +import pkg_resources +import imp +import os.path + +from django.template import TemplateDoesNotExist, Context +from django.template.loaders.eggs import Loader as EggLoader +from django.template import loader +from django.utils import unittest, six +from django.utils._os import upath +from django.utils.six import StringIO + + +# Mock classes and objects for pkg_resources functions. +class MockProvider(pkg_resources.NullProvider): + def __init__(self, module): + pkg_resources.NullProvider.__init__(self, module) + self.module = module + + def _has(self, path): + return path in self.module._resources + + def _isdir(self, path): + return False + + def get_resource_stream(self, manager, resource_name): + return self.module._resources[resource_name] + + def _get(self, path): + return self.module._resources[path].read() + +class MockLoader(object): + pass + +def create_egg(name, resources): + """ + Creates a mock egg with a list of resources. + + name: The name of the module. + resources: A dictionary of resources. Keys are the names and values the data. + """ + egg = imp.new_module(name) + egg.__loader__ = MockLoader() + egg._resources = resources + sys.modules[name] = egg + + +class EggLoaderTest(unittest.TestCase): + def setUp(self): + pkg_resources._provider_factories[MockLoader] = MockProvider + + self.empty_egg = create_egg("egg_empty", {}) + self.egg_1 = create_egg("egg_1", { + os.path.normcase('templates/y.html'): StringIO("y"), + os.path.normcase('templates/x.txt'): StringIO("x"), + }) + self._old_installed_apps = settings.INSTALLED_APPS + settings.INSTALLED_APPS = [] + + def tearDown(self): + settings.INSTALLED_APPS = self._old_installed_apps + + def test_empty(self): + "Loading any template on an empty egg should fail" + settings.INSTALLED_APPS = ['egg_empty'] + egg_loader = EggLoader() + self.assertRaises(TemplateDoesNotExist, egg_loader.load_template_source, "not-existing.html") + + def test_non_existing(self): + "Template loading fails if the template is not in the egg" + settings.INSTALLED_APPS = ['egg_1'] + egg_loader = EggLoader() + self.assertRaises(TemplateDoesNotExist, egg_loader.load_template_source, "not-existing.html") + + def test_existing(self): + "A template can be loaded from an egg" + settings.INSTALLED_APPS = ['egg_1'] + egg_loader = EggLoader() + contents, template_name = egg_loader.load_template_source("y.html") + self.assertEqual(contents, "y") + self.assertEqual(template_name, "egg:egg_1:templates/y.html") + + def test_not_installed(self): + "Loading an existent template from an egg not included in INSTALLED_APPS should fail" + settings.INSTALLED_APPS = [] + egg_loader = EggLoader() + self.assertRaises(TemplateDoesNotExist, egg_loader.load_template_source, "y.html") + +class CachedLoader(unittest.TestCase): + def setUp(self): + self.old_TEMPLATE_LOADERS = settings.TEMPLATE_LOADERS + settings.TEMPLATE_LOADERS = ( + ('django.template.loaders.cached.Loader', ( + 'django.template.loaders.filesystem.Loader', + ) + ), + ) + def tearDown(self): + settings.TEMPLATE_LOADERS = self.old_TEMPLATE_LOADERS + + def test_templatedir_caching(self): + "Check that the template directories form part of the template cache key. Refs #13573" + # Retrive a template specifying a template directory to check + t1, name = loader.find_template('test.html', (os.path.join(os.path.dirname(upath(__file__)), 'templates', 'first'),)) + # Now retrieve the same template name, but from a different directory + t2, name = loader.find_template('test.html', (os.path.join(os.path.dirname(upath(__file__)), 'templates', 'second'),)) + + # The two templates should not have the same content + self.assertNotEqual(t1.render(Context({})), t2.render(Context({}))) + +class RenderToStringTest(unittest.TestCase): + + def setUp(self): + self._old_TEMPLATE_DIRS = settings.TEMPLATE_DIRS + settings.TEMPLATE_DIRS = ( + os.path.join(os.path.dirname(upath(__file__)), 'templates'), + ) + + def tearDown(self): + settings.TEMPLATE_DIRS = self._old_TEMPLATE_DIRS + + def test_basic(self): + self.assertEqual(loader.render_to_string('test_context.html'), 'obj:') + + def test_basic_context(self): + self.assertEqual(loader.render_to_string('test_context.html', + {'obj': 'test'}), 'obj:test') + + def test_existing_context_kept_clean(self): + context = Context({'obj': 'before'}) + output = loader.render_to_string('test_context.html', {'obj': 'after'}, + context_instance=context) + self.assertEqual(output, 'obj:after') + self.assertEqual(context['obj'], 'before') + + def test_empty_list(self): + six.assertRaisesRegex(self, TemplateDoesNotExist, + 'No template names provided$', + loader.render_to_string, []) + + + def test_select_templates_from_empty_list(self): + six.assertRaisesRegex(self, TemplateDoesNotExist, + 'No template names provided$', + loader.select_template, []) diff --git a/tests/template_tests/test_nodelist.py b/tests/template_tests/test_nodelist.py new file mode 100644 index 0000000000..97aa5af6a7 --- /dev/null +++ b/tests/template_tests/test_nodelist.py @@ -0,0 +1,58 @@ +from django.template import VariableNode, Context +from django.template.loader import get_template_from_string +from django.utils.unittest import TestCase +from django.test.utils import override_settings + +class NodelistTest(TestCase): + + def test_for(self): + source = '{% for i in 1 %}{{ a }}{% endfor %}' + template = get_template_from_string(source) + vars = template.nodelist.get_nodes_by_type(VariableNode) + self.assertEqual(len(vars), 1) + + def test_if(self): + source = '{% if x %}{{ a }}{% endif %}' + template = get_template_from_string(source) + vars = template.nodelist.get_nodes_by_type(VariableNode) + self.assertEqual(len(vars), 1) + + def test_ifequal(self): + source = '{% ifequal x y %}{{ a }}{% endifequal %}' + template = get_template_from_string(source) + vars = template.nodelist.get_nodes_by_type(VariableNode) + self.assertEqual(len(vars), 1) + + def test_ifchanged(self): + source = '{% ifchanged x %}{{ a }}{% endifchanged %}' + template = get_template_from_string(source) + vars = template.nodelist.get_nodes_by_type(VariableNode) + self.assertEqual(len(vars), 1) + + +class ErrorIndexTest(TestCase): + """ + Checks whether index of error is calculated correctly in + template debugger in for loops. Refs ticket #5831 + """ + @override_settings(DEBUG=True, TEMPLATE_DEBUG = True) + def test_correct_exception_index(self): + tests = [ + ('{% load bad_tag %}{% for i in range %}{% badsimpletag %}{% endfor %}', (38, 56)), + ('{% load bad_tag %}{% for i in range %}{% for j in range %}{% badsimpletag %}{% endfor %}{% endfor %}', (58, 76)), + ('{% load bad_tag %}{% for i in range %}{% badsimpletag %}{% for j in range %}Hello{% endfor %}{% endfor %}', (38, 56)), + ('{% load bad_tag %}{% for i in range %}{% for j in five %}{% badsimpletag %}{% endfor %}{% endfor %}', (38, 57)), + ('{% load bad_tag %}{% for j in five %}{% badsimpletag %}{% endfor %}', (18, 37)), + ] + context = Context({ + 'range': range(5), + 'five': 5, + }) + for source, expected_error_source_index in tests: + template = get_template_from_string(source) + try: + template.render(context) + except (RuntimeError, TypeError) as e: + error_source_index = e.django_template_source[1] + self.assertEqual(error_source_index, + expected_error_source_index) diff --git a/tests/template_tests/test_parser.py b/tests/template_tests/test_parser.py new file mode 100644 index 0000000000..9422da80d7 --- /dev/null +++ b/tests/template_tests/test_parser.py @@ -0,0 +1,95 @@ +""" +Testing some internals of the template processing. These are *not* examples to be copied in user code. +""" +from __future__ import unicode_literals + +from django.template import (TokenParser, FilterExpression, Parser, Variable, + Template, TemplateSyntaxError) +from django.test.utils import override_settings +from django.utils.unittest import TestCase +from django.utils import six + + +class ParserTests(TestCase): + def test_token_parsing(self): + # Tests for TokenParser behavior in the face of quoted strings with + # spaces. + + p = TokenParser("tag thevar|filter sometag") + self.assertEqual(p.tagname, "tag") + self.assertEqual(p.value(), "thevar|filter") + self.assertTrue(p.more()) + self.assertEqual(p.tag(), "sometag") + self.assertFalse(p.more()) + + p = TokenParser('tag "a value"|filter sometag') + self.assertEqual(p.tagname, "tag") + self.assertEqual(p.value(), '"a value"|filter') + self.assertTrue(p.more()) + self.assertEqual(p.tag(), "sometag") + self.assertFalse(p.more()) + + p = TokenParser("tag 'a value'|filter sometag") + self.assertEqual(p.tagname, "tag") + self.assertEqual(p.value(), "'a value'|filter") + self.assertTrue(p.more()) + self.assertEqual(p.tag(), "sometag") + self.assertFalse(p.more()) + + def test_filter_parsing(self): + c = {"article": {"section": "News"}} + p = Parser("") + + def fe_test(s, val): + self.assertEqual(FilterExpression(s, p).resolve(c), val) + + fe_test("article.section", "News") + fe_test("article.section|upper", "NEWS") + fe_test('"News"', "News") + fe_test("'News'", "News") + fe_test(r'"Some \"Good\" News"', 'Some "Good" News') + fe_test(r'"Some \"Good\" News"', 'Some "Good" News') + fe_test(r"'Some \'Bad\' News'", "Some 'Bad' News") + + fe = FilterExpression(r'"Some \"Good\" News"', p) + self.assertEqual(fe.filters, []) + self.assertEqual(fe.var, 'Some "Good" News') + + # Filtered variables should reject access of attributes beginning with + # underscores. + self.assertRaises(TemplateSyntaxError, + FilterExpression, "article._hidden|upper", p + ) + + def test_variable_parsing(self): + c = {"article": {"section": "News"}} + self.assertEqual(Variable("article.section").resolve(c), "News") + self.assertEqual(Variable('"News"').resolve(c), "News") + self.assertEqual(Variable("'News'").resolve(c), "News") + + # Translated strings are handled correctly. + self.assertEqual(Variable("_(article.section)").resolve(c), "News") + self.assertEqual(Variable('_("Good News")').resolve(c), "Good News") + self.assertEqual(Variable("_('Better News')").resolve(c), "Better News") + + # Escaped quotes work correctly as well. + self.assertEqual( + Variable(r'"Some \"Good\" News"').resolve(c), 'Some "Good" News' + ) + self.assertEqual( + Variable(r"'Some \'Better\' News'").resolve(c), "Some 'Better' News" + ) + + # Variables should reject access of attributes beginning with + # underscores. + self.assertRaises(TemplateSyntaxError, + Variable, "article._hidden" + ) + + @override_settings(DEBUG=True, TEMPLATE_DEBUG=True) + def test_compile_filter_error(self): + # regression test for #19819 + msg = "Could not parse the remainder: '@bar' from 'foo@bar'" + with six.assertRaisesRegex(self, TemplateSyntaxError, msg) as cm: + Template("{% if 1 %}{{ foo@bar }}{% endif %}") + self.assertEqual(cm.exception.django_template_source[1], (10, 23)) diff --git a/tests/template_tests/test_response.py b/tests/template_tests/test_response.py new file mode 100644 index 0000000000..6acc45626f --- /dev/null +++ b/tests/template_tests/test_response.py @@ -0,0 +1,352 @@ +from __future__ import unicode_literals + +import os +import pickle +import time +from datetime import datetime + +from django.test import RequestFactory, TestCase +from django.conf import settings +from django.template import Template, Context +from django.template.response import (TemplateResponse, SimpleTemplateResponse, + ContentNotRenderedError) +from django.test.utils import override_settings +from django.utils._os import upath + +def test_processor(request): + return {'processors': 'yes'} +test_processor_name = 'template_tests.test_response.test_processor' + + +# A test middleware that installs a temporary URLConf +class CustomURLConfMiddleware(object): + def process_request(self, request): + request.urlconf = 'template_tests.alternate_urls' + + +class SimpleTemplateResponseTest(TestCase): + + def _response(self, template='foo', *args, **kwargs): + return SimpleTemplateResponse(Template(template), *args, **kwargs) + + def test_template_resolving(self): + response = SimpleTemplateResponse('first/test.html') + response.render() + self.assertEqual(response.content, b'First template\n') + + templates = ['foo.html', 'second/test.html', 'first/test.html'] + response = SimpleTemplateResponse(templates) + response.render() + self.assertEqual(response.content, b'Second template\n') + + response = self._response() + response.render() + self.assertEqual(response.content, b'foo') + + def test_explicit_baking(self): + # explicit baking + response = self._response() + self.assertFalse(response.is_rendered) + response.render() + self.assertTrue(response.is_rendered) + + def test_render(self): + # response is not re-rendered without the render call + response = self._response().render() + self.assertEqual(response.content, b'foo') + + # rebaking doesn't change the rendered content + response.template_name = Template('bar{{ baz }}') + response.render() + self.assertEqual(response.content, b'foo') + + # but rendered content can be overridden by manually + # setting content + response.content = 'bar' + self.assertEqual(response.content, b'bar') + + def test_iteration_unrendered(self): + # unrendered response raises an exception on iteration + response = self._response() + self.assertFalse(response.is_rendered) + + def iteration(): + for x in response: + pass + self.assertRaises(ContentNotRenderedError, iteration) + self.assertFalse(response.is_rendered) + + def test_iteration_rendered(self): + # iteration works for rendered responses + response = self._response().render() + res = [x for x in response] + self.assertEqual(res, [b'foo']) + + def test_content_access_unrendered(self): + # unrendered response raises an exception when content is accessed + response = self._response() + self.assertFalse(response.is_rendered) + self.assertRaises(ContentNotRenderedError, lambda: response.content) + self.assertFalse(response.is_rendered) + + def test_content_access_rendered(self): + # rendered response content can be accessed + response = self._response().render() + self.assertEqual(response.content, b'foo') + + def test_set_content(self): + # content can be overriden + response = self._response() + self.assertFalse(response.is_rendered) + response.content = 'spam' + self.assertTrue(response.is_rendered) + self.assertEqual(response.content, b'spam') + response.content = 'baz' + self.assertEqual(response.content, b'baz') + + def test_dict_context(self): + response = self._response('{{ foo }}{{ processors }}', + {'foo': 'bar'}) + self.assertEqual(response.context_data, {'foo': 'bar'}) + response.render() + self.assertEqual(response.content, b'bar') + + def test_context_instance(self): + response = self._response('{{ foo }}{{ processors }}', + Context({'foo': 'bar'})) + self.assertEqual(response.context_data.__class__, Context) + response.render() + self.assertEqual(response.content, b'bar') + + def test_kwargs(self): + response = self._response(content_type = 'application/json', status=504) + self.assertEqual(response['content-type'], 'application/json') + self.assertEqual(response.status_code, 504) + + def test_args(self): + response = SimpleTemplateResponse('', {}, 'application/json', 504) + self.assertEqual(response['content-type'], 'application/json') + self.assertEqual(response.status_code, 504) + + def test_post_callbacks(self): + "Rendering a template response triggers the post-render callbacks" + post = [] + + def post1(obj): + post.append('post1') + def post2(obj): + post.append('post2') + + response = SimpleTemplateResponse('first/test.html', {}) + response.add_post_render_callback(post1) + response.add_post_render_callback(post2) + + # When the content is rendered, all the callbacks are invoked, too. + response.render() + self.assertEqual(response.content, b'First template\n') + self.assertEqual(post, ['post1','post2']) + + + def test_pickling(self): + # Create a template response. The context is + # known to be unpickleable (e.g., a function). + response = SimpleTemplateResponse('first/test.html', { + 'value': 123, + 'fn': datetime.now, + }) + self.assertRaises(ContentNotRenderedError, + pickle.dumps, response) + + # But if we render the response, we can pickle it. + response.render() + pickled_response = pickle.dumps(response) + unpickled_response = pickle.loads(pickled_response) + + self.assertEqual(unpickled_response.content, response.content) + self.assertEqual(unpickled_response['content-type'], response['content-type']) + self.assertEqual(unpickled_response.status_code, response.status_code) + + # ...and the unpickled reponse doesn't have the + # template-related attributes, so it can't be re-rendered + template_attrs = ('template_name', 'context_data', '_post_render_callbacks') + for attr in template_attrs: + self.assertFalse(hasattr(unpickled_response, attr)) + + # ...and requesting any of those attributes raises an exception + for attr in template_attrs: + with self.assertRaises(AttributeError): + getattr(unpickled_response, attr) + + def test_repickling(self): + response = SimpleTemplateResponse('first/test.html', { + 'value': 123, + 'fn': datetime.now, + }) + self.assertRaises(ContentNotRenderedError, + pickle.dumps, response) + + response.render() + pickled_response = pickle.dumps(response) + unpickled_response = pickle.loads(pickled_response) + repickled_response = pickle.dumps(unpickled_response) + + def test_pickling_cookie(self): + response = SimpleTemplateResponse('first/test.html', { + 'value': 123, + 'fn': datetime.now, + }) + + response.cookies['key'] = 'value' + + response.render() + pickled_response = pickle.dumps(response, pickle.HIGHEST_PROTOCOL) + unpickled_response = pickle.loads(pickled_response) + + self.assertEqual(unpickled_response.cookies['key'].value, 'value') + + +@override_settings( + TEMPLATE_CONTEXT_PROCESSORS=[test_processor_name], + TEMPLATE_DIRS=(os.path.join(os.path.dirname(upath(__file__)), 'templates')), +) +class TemplateResponseTest(TestCase): + + def setUp(self): + self.factory = RequestFactory() + + def _response(self, template='foo', *args, **kwargs): + return TemplateResponse(self.factory.get('/'), Template(template), + *args, **kwargs) + + def test_render(self): + response = self._response('{{ foo }}{{ processors }}').render() + self.assertEqual(response.content, b'yes') + + def test_render_with_requestcontext(self): + response = self._response('{{ foo }}{{ processors }}', + {'foo': 'bar'}).render() + self.assertEqual(response.content, b'baryes') + + def test_render_with_context(self): + response = self._response('{{ foo }}{{ processors }}', + Context({'foo': 'bar'})).render() + self.assertEqual(response.content, b'bar') + + def test_kwargs(self): + response = self._response(content_type = 'application/json', + status=504) + self.assertEqual(response['content-type'], 'application/json') + self.assertEqual(response.status_code, 504) + + def test_args(self): + response = TemplateResponse(self.factory.get('/'), '', {}, + 'application/json', 504) + self.assertEqual(response['content-type'], 'application/json') + self.assertEqual(response.status_code, 504) + + def test_custom_app(self): + response = self._response('{{ foo }}', current_app="foobar") + + rc = response.resolve_context(response.context_data) + + self.assertEqual(rc.current_app, 'foobar') + + def test_pickling(self): + # Create a template response. The context is + # known to be unpickleable (e.g., a function). + response = TemplateResponse(self.factory.get('/'), + 'first/test.html', { + 'value': 123, + 'fn': datetime.now, + }) + self.assertRaises(ContentNotRenderedError, + pickle.dumps, response) + + # But if we render the response, we can pickle it. + response.render() + pickled_response = pickle.dumps(response) + unpickled_response = pickle.loads(pickled_response) + + self.assertEqual(unpickled_response.content, response.content) + self.assertEqual(unpickled_response['content-type'], response['content-type']) + self.assertEqual(unpickled_response.status_code, response.status_code) + + # ...and the unpickled reponse doesn't have the + # template-related attributes, so it can't be re-rendered + template_attrs = ('template_name', 'context_data', + '_post_render_callbacks', '_request', '_current_app') + for attr in template_attrs: + self.assertFalse(hasattr(unpickled_response, attr)) + + # ...and requesting any of those attributes raises an exception + for attr in template_attrs: + with self.assertRaises(AttributeError): + getattr(unpickled_response, attr) + + def test_repickling(self): + response = SimpleTemplateResponse('first/test.html', { + 'value': 123, + 'fn': datetime.now, + }) + self.assertRaises(ContentNotRenderedError, + pickle.dumps, response) + + response.render() + pickled_response = pickle.dumps(response) + unpickled_response = pickle.loads(pickled_response) + repickled_response = pickle.dumps(unpickled_response) + + +class CustomURLConfTest(TestCase): + urls = 'template_tests.urls' + + def setUp(self): + self.old_MIDDLEWARE_CLASSES = settings.MIDDLEWARE_CLASSES + settings.MIDDLEWARE_CLASSES = list(settings.MIDDLEWARE_CLASSES) + [ + 'template_tests.test_response.CustomURLConfMiddleware' + ] + + def tearDown(self): + settings.MIDDLEWARE_CLASSES = self.old_MIDDLEWARE_CLASSES + + def test_custom_urlconf(self): + response = self.client.get('/template_response_view/') + self.assertEqual(response.status_code, 200) + self.assertContains(response, 'This is where you can find the snark: /snark/') + + +class CacheMiddlewareTest(TestCase): + urls = 'template_tests.alternate_urls' + + def setUp(self): + self.old_MIDDLEWARE_CLASSES = settings.MIDDLEWARE_CLASSES + self.CACHE_MIDDLEWARE_SECONDS = settings.CACHE_MIDDLEWARE_SECONDS + + settings.CACHE_MIDDLEWARE_SECONDS = 2.0 + settings.MIDDLEWARE_CLASSES = list(settings.MIDDLEWARE_CLASSES) + [ + 'django.middleware.cache.FetchFromCacheMiddleware', + 'django.middleware.cache.UpdateCacheMiddleware', + ] + + def tearDown(self): + settings.MIDDLEWARE_CLASSES = self.old_MIDDLEWARE_CLASSES + settings.CACHE_MIDDLEWARE_SECONDS = self.CACHE_MIDDLEWARE_SECONDS + + def test_middleware_caching(self): + response = self.client.get('/template_response_view/') + self.assertEqual(response.status_code, 200) + + time.sleep(1.0) + + response2 = self.client.get('/template_response_view/') + self.assertEqual(response2.status_code, 200) + + self.assertEqual(response.content, response2.content) + + time.sleep(2.0) + + # Let the cache expire and test again + response2 = self.client.get('/template_response_view/') + self.assertEqual(response2.status_code, 200) + + self.assertNotEqual(response.content, response2.content) diff --git a/tests/template_tests/test_smartif.py b/tests/template_tests/test_smartif.py new file mode 100644 index 0000000000..3a705ca663 --- /dev/null +++ b/tests/template_tests/test_smartif.py @@ -0,0 +1,53 @@ +from django.template.smartif import IfParser +from django.utils import unittest + +class SmartIfTests(unittest.TestCase): + + def assertCalcEqual(self, expected, tokens): + self.assertEqual(expected, IfParser(tokens).parse().eval({})) + + # We only test things here that are difficult to test elsewhere + # Many other tests are found in the main tests for builtin template tags + # Test parsing via the printed parse tree + def test_not(self): + var = IfParser(["not", False]).parse() + self.assertEqual("(not (literal False))", repr(var)) + self.assertTrue(var.eval({})) + + self.assertFalse(IfParser(["not", True]).parse().eval({})) + + def test_or(self): + var = IfParser([True, "or", False]).parse() + self.assertEqual("(or (literal True) (literal False))", repr(var)) + self.assertTrue(var.eval({})) + + def test_in(self): + list_ = [1,2,3] + self.assertCalcEqual(True, [1, 'in', list_]) + self.assertCalcEqual(False, [1, 'in', None]) + self.assertCalcEqual(False, [None, 'in', list_]) + + def test_not_in(self): + list_ = [1,2,3] + self.assertCalcEqual(False, [1, 'not', 'in', list_]) + self.assertCalcEqual(True, [4, 'not', 'in', list_]) + self.assertCalcEqual(False, [1, 'not', 'in', None]) + self.assertCalcEqual(True, [None, 'not', 'in', list_]) + + def test_precedence(self): + # (False and False) or True == True <- we want this one, like Python + # False and (False or True) == False + self.assertCalcEqual(True, [False, 'and', False, 'or', True]) + + # True or (False and False) == True <- we want this one, like Python + # (True or False) and False == False + self.assertCalcEqual(True, [True, 'or', False, 'and', False]) + + # (1 or 1) == 2 -> False + # 1 or (1 == 2) -> True <- we want this one + self.assertCalcEqual(True, [1, 'or', 1, '==', 2]) + + self.assertCalcEqual(True, [True, '==', True, 'or', True, '==', False]) + + self.assertEqual("(or (and (== (literal 1) (literal 2)) (literal 3)) (literal 4))", + repr(IfParser([1, '==', 2, 'and', 3, 'or', 4]).parse())) diff --git a/tests/template_tests/test_unicode.py b/tests/template_tests/test_unicode.py new file mode 100644 index 0000000000..7cb2a28d15 --- /dev/null +++ b/tests/template_tests/test_unicode.py @@ -0,0 +1,32 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.template import Template, TemplateEncodingError, Context +from django.utils.safestring import SafeData +from django.utils import six +from django.utils.unittest import TestCase + + +class UnicodeTests(TestCase): + def test_template(self): + # Templates can be created from unicode strings. + t1 = Template('ŠĐĆŽćžšđ {{ var }}') + # Templates can also be created from bytestrings. These are assumed to + # be encoded using UTF-8. + s = b'\xc5\xa0\xc4\x90\xc4\x86\xc5\xbd\xc4\x87\xc5\xbe\xc5\xa1\xc4\x91 {{ var }}' + t2 = Template(s) + s = b'\x80\xc5\xc0' + self.assertRaises(TemplateEncodingError, Template, s) + + # Contexts can be constructed from unicode or UTF-8 bytestrings. + c1 = Context({b"var": b"foo"}) + c2 = Context({"var": b"foo"}) + c3 = Context({b"var": "Đđ"}) + c4 = Context({"var": b"\xc4\x90\xc4\x91"}) + + # Since both templates and all four contexts represent the same thing, + # they all render the same (and are returned as unicode objects and + # "safe" objects as well, for auto-escaping purposes). + self.assertEqual(t1.render(c3), t2.render(c3)) + self.assertIsInstance(t1.render(c3), six.text_type) + self.assertIsInstance(t1.render(c3), SafeData) diff --git a/tests/template_tests/tests.py b/tests/template_tests/tests.py index a9db9edc2f..67839d3ab7 100644 --- a/tests/template_tests/tests.py +++ b/tests/template_tests/tests.py @@ -36,18 +36,18 @@ from django.utils.safestring import mark_safe from django.utils import six from django.utils.tzinfo import LocalTimezone -from .callables import CallableVariablesTests -from .context import ContextTests -from .custom import CustomTagTests, CustomFilterTests -from .parser import ParserTests -from .unicode import UnicodeTests -from .nodelist import NodelistTest, ErrorIndexTest -from .smartif import SmartIfTests -from .response import (TemplateResponseTest, CacheMiddlewareTest, +from .test_callables import CallableVariablesTests +from .test_context import ContextTests +from .test_custom import CustomTagTests, CustomFilterTests +from .test_parser import ParserTests +from .test_unicode import UnicodeTests +from .test_nodelist import NodelistTest, ErrorIndexTest +from .test_smartif import SmartIfTests +from .test_response import (TemplateResponseTest, CacheMiddlewareTest, SimpleTemplateResponseTest, CustomURLConfTest) try: - from .loaders import RenderToStringTest, EggLoaderTest + from .test_loaders import RenderToStringTest, EggLoaderTest except ImportError as e: if "pkg_resources" in e.args[0]: pass # If setuptools isn't installed, that's fine. Just move on. diff --git a/tests/template_tests/unicode.py b/tests/template_tests/unicode.py deleted file mode 100644 index 7cb2a28d15..0000000000 --- a/tests/template_tests/unicode.py +++ /dev/null @@ -1,32 +0,0 @@ -# -*- coding: utf-8 -*- -from __future__ import unicode_literals - -from django.template import Template, TemplateEncodingError, Context -from django.utils.safestring import SafeData -from django.utils import six -from django.utils.unittest import TestCase - - -class UnicodeTests(TestCase): - def test_template(self): - # Templates can be created from unicode strings. - t1 = Template('ŠĐĆŽćžšđ {{ var }}') - # Templates can also be created from bytestrings. These are assumed to - # be encoded using UTF-8. - s = b'\xc5\xa0\xc4\x90\xc4\x86\xc5\xbd\xc4\x87\xc5\xbe\xc5\xa1\xc4\x91 {{ var }}' - t2 = Template(s) - s = b'\x80\xc5\xc0' - self.assertRaises(TemplateEncodingError, Template, s) - - # Contexts can be constructed from unicode or UTF-8 bytestrings. - c1 = Context({b"var": b"foo"}) - c2 = Context({"var": b"foo"}) - c3 = Context({b"var": "Đđ"}) - c4 = Context({"var": b"\xc4\x90\xc4\x91"}) - - # Since both templates and all four contexts represent the same thing, - # they all render the same (and are returned as unicode objects and - # "safe" objects as well, for auto-escaping purposes). - self.assertEqual(t1.render(c3), t2.render(c3)) - self.assertIsInstance(t1.render(c3), six.text_type) - self.assertIsInstance(t1.render(c3), SafeData) -- cgit v1.3