~ubuntu-branches/ubuntu/quantal/python-django/quantal-security

« back to all changes in this revision

Viewing changes to tests/regressiontests/templates/tests.py

  • Committer: Bazaar Package Importer
  • Author(s): Chris Lamb
  • Date: 2010-05-21 07:52:55 UTC
  • mfrom: (1.3.6 upstream)
  • mto: This revision was merged to the branch mainline in revision 28.
  • Revision ID: james.westby@ubuntu.com-20100521075255-ii78v1dyfmyu3uzx
Tags: upstream-1.2
Import upstream version 1.2

Show diffs side-by-side

added added

removed removed

Lines of Context:
7
7
    settings.configure()
8
8
 
9
9
from datetime import datetime, timedelta
 
10
import time
10
11
import os
11
12
import sys
12
13
import traceback
15
16
from django import template
16
17
from django.core import urlresolvers
17
18
from django.template import loader
18
 
from django.template.loaders import app_directories, filesystem
 
19
from django.template.loaders import app_directories, filesystem, cached
19
20
from django.utils.translation import activate, deactivate, ugettext as _
20
21
from django.utils.safestring import mark_safe
21
22
from django.utils.tzinfo import LocalTimezone
22
23
 
23
24
from context import context_tests
24
25
from custom import custom_filters
25
 
from parser import filter_parsing, variable_parsing
 
26
from parser import token_parsing, filter_parsing, variable_parsing
26
27
from unicode import unicode_tests
 
28
from nodelist import NodelistTest
 
29
from smartif import *
27
30
 
28
31
try:
29
32
    from loaders import *
36
39
__test__ = {
37
40
    'unicode': unicode_tests,
38
41
    'context': context_tests,
 
42
    'token_parsing': token_parsing,
39
43
    'filter_parsing': filter_parsing,
 
44
    'variable_parsing': variable_parsing,
40
45
    'custom_filters': custom_filters,
41
46
}
42
47
 
58
63
 
59
64
register.tag("echo", do_echo)
60
65
 
61
 
template.libraries['django.templatetags.testtags'] = register
 
66
template.libraries['testtags'] = register
62
67
 
63
68
#####################################
64
69
# Helper objects for template tests #
93
98
    def method(self):
94
99
        return "OtherClass.method"
95
100
 
 
101
class TestObj(object):
 
102
    def is_true(self):
 
103
        return True
 
104
 
 
105
    def is_false(self):
 
106
        return False
 
107
 
 
108
    def is_bad(self):
 
109
        time.sleep(0.3)
 
110
        return True
 
111
 
 
112
class SilentGetItemClass(object):
 
113
    def __getitem__(self, key):
 
114
        raise SomeException
 
115
 
 
116
class SilentAttrClass(object):
 
117
    def b(self):
 
118
        raise SomeException
 
119
    b = property(b)
 
120
 
96
121
class UTF8Class:
97
122
    "Class whose __str__ returns non-ASCII data"
98
123
    def __str__(self):
100
125
 
101
126
class Templates(unittest.TestCase):
102
127
    def test_loaders_security(self):
 
128
        ad_loader = app_directories.Loader()
 
129
        fs_loader = filesystem.Loader()
103
130
        def test_template_sources(path, template_dirs, expected_sources):
104
131
            if isinstance(expected_sources, list):
105
132
                # Fix expected sources so they are normcased and abspathed
106
133
                expected_sources = [os.path.normcase(os.path.abspath(s)) for s in expected_sources]
107
134
            # Test the two loaders (app_directores and filesystem).
108
 
            func1 = lambda p, t: list(app_directories.get_template_sources(p, t))
109
 
            func2 = lambda p, t: list(filesystem.get_template_sources(p, t))
 
135
            func1 = lambda p, t: list(ad_loader.get_template_sources(p, t))
 
136
            func2 = lambda p, t: list(fs_loader.get_template_sources(p, t))
110
137
            for func in (func1, func2):
111
138
                if isinstance(expected_sources, list):
112
139
                    self.assertEqual(func(path, template_dirs), expected_sources)
150
177
            test_template_sources('/DIR1/index.HTML', template_dirs,
151
178
                                  ['/dir1/index.html'])
152
179
 
 
180
    def test_loader_debug_origin(self):
 
181
        # Turn TEMPLATE_DEBUG on, so that the origin file name will be kept with
 
182
        # the compiled templates.
 
183
        old_td, settings.TEMPLATE_DEBUG = settings.TEMPLATE_DEBUG, True
 
184
        old_loaders = loader.template_source_loaders
 
185
 
 
186
        try:
 
187
            loader.template_source_loaders = (filesystem.Loader(),)
 
188
 
 
189
            # We rely on the fact that runtests.py sets up TEMPLATE_DIRS to
 
190
            # point to a directory containing a 404.html file. Also that
 
191
            # the file system and app directories loaders both inherit the
 
192
            # load_template method from the BaseLoader class, so we only need
 
193
            # to test one of them.
 
194
            load_name = '404.html'
 
195
            template = loader.get_template(load_name)
 
196
            template_name = template.nodelist[0].source[0].name
 
197
            self.assertTrue(template_name.endswith(load_name),
 
198
                'Template loaded by filesystem loader has incorrect name for debug page: %s' % template_name)
 
199
 
 
200
            # Aso test the cached loader, since it overrides load_template
 
201
            cache_loader = cached.Loader(('',))
 
202
            cache_loader._cached_loaders = loader.template_source_loaders
 
203
            loader.template_source_loaders = (cache_loader,)
 
204
 
 
205
            template = loader.get_template(load_name)
 
206
            template_name = template.nodelist[0].source[0].name
 
207
            self.assertTrue(template_name.endswith(load_name),
 
208
                'Template loaded through cached loader has incorrect name for debug page: %s' % template_name)
 
209
 
 
210
            template = loader.get_template(load_name)
 
211
            template_name = template.nodelist[0].source[0].name
 
212
            self.assertTrue(template_name.endswith(load_name),
 
213
                'Cached template loaded through cached loader has incorrect name for debug page: %s' % template_name)
 
214
        finally:
 
215
            loader.template_source_loaders = old_loaders
 
216
            settings.TEMPLATE_DEBUG = old_td
 
217
 
 
218
    def test_extends_include_missing_baseloader(self):
 
219
        """
 
220
        Tests that the correct template is identified as not existing
 
221
        when {% extends %} specifies a template that does exist, but
 
222
        that template has an {% include %} of something that does not
 
223
        exist. See #12787.
 
224
        """
 
225
 
 
226
        # TEMPLATE_DEBUG must be true, otherwise the exception raised
 
227
        # during {% include %} processing will be suppressed.
 
228
        old_td, settings.TEMPLATE_DEBUG = settings.TEMPLATE_DEBUG, True
 
229
        old_loaders = loader.template_source_loaders
 
230
 
 
231
        try:
 
232
            # Test the base loader class via the app loader. load_template
 
233
            # from base is used by all shipped loaders excepting cached,
 
234
            # which has its own test.
 
235
            loader.template_source_loaders = (app_directories.Loader(),)
 
236
 
 
237
            load_name = 'test_extends_error.html'
 
238
            tmpl = loader.get_template(load_name)
 
239
            r = None
 
240
            try:
 
241
                r = tmpl.render(template.Context({}))
 
242
            except template.TemplateSyntaxError, e:
 
243
                settings.TEMPLATE_DEBUG = old_td
 
244
                self.assertEqual(e.args[0], 'Caught TemplateDoesNotExist while rendering: missing.html')
 
245
            self.assertEqual(r, None, 'Template rendering unexpectedly succeeded, produced: ->%r<-' % r)
 
246
        finally:
 
247
            loader.template_source_loaders = old_loaders
 
248
            settings.TEMPLATE_DEBUG = old_td
 
249
 
 
250
    def test_extends_include_missing_cachedloader(self):
 
251
        """
 
252
        Same as test_extends_include_missing_baseloader, only tests
 
253
        behavior of the cached loader instead of BaseLoader.
 
254
        """
 
255
 
 
256
        old_td, settings.TEMPLATE_DEBUG = settings.TEMPLATE_DEBUG, True
 
257
        old_loaders = loader.template_source_loaders
 
258
 
 
259
        try:
 
260
            cache_loader = cached.Loader(('',))
 
261
            cache_loader._cached_loaders = (app_directories.Loader(),)
 
262
            loader.template_source_loaders = (cache_loader,)
 
263
 
 
264
            load_name = 'test_extends_error.html'
 
265
            tmpl = loader.get_template(load_name)
 
266
            r = None
 
267
            try:
 
268
                r = tmpl.render(template.Context({}))
 
269
            except template.TemplateSyntaxError, e:
 
270
                self.assertEqual(e.args[0], 'Caught TemplateDoesNotExist while rendering: missing.html')
 
271
            self.assertEqual(r, None, 'Template rendering unexpectedly succeeded, produced: ->%r<-' % r)
 
272
 
 
273
            # For the cached loader, repeat the test, to ensure the first attempt did not cache a
 
274
            # result that behaves incorrectly on subsequent attempts.
 
275
            tmpl = loader.get_template(load_name)
 
276
            try:
 
277
                tmpl.render(template.Context({}))
 
278
            except template.TemplateSyntaxError, e:
 
279
                self.assertEqual(e.args[0], 'Caught TemplateDoesNotExist while rendering: missing.html')
 
280
            self.assertEqual(r, None, 'Template rendering unexpectedly succeeded, produced: ->%r<-' % r)
 
281
        finally:
 
282
            loader.template_source_loaders = old_loaders
 
283
            settings.TEMPLATE_DEBUG = old_td
 
284
 
153
285
    def test_token_smart_split(self):
154
286
        # Regression test for #7027
155
287
        token = template.Token(template.TOKEN_BLOCK, 'sometag _("Page not found") value|yesno:_("yes,no")')
173
305
        except TemplateSyntaxError, e:
174
306
            # Assert that we are getting the template syntax error and not the
175
307
            # string encoding error.
176
 
            self.assertEquals(e.args[0], "Caught an exception while rendering: Reverse for 'will_not_match' with arguments '()' and keyword arguments '{}' not found.")
 
308
            self.assertEquals(e.args[0], "Caught NoReverseMatch while rendering: Reverse for 'will_not_match' with arguments '()' and keyword arguments '{}' not found.")
177
309
 
178
310
        settings.SETTINGS_MODULE = old_settings_module
179
311
        settings.TEMPLATE_DEBUG = old_template_debug
180
312
 
 
313
    def test_invalid_block_suggestion(self):
 
314
        # See #7876
 
315
        from django.template import Template, TemplateSyntaxError
 
316
        try:
 
317
            t = Template("{% if 1 %}lala{% endblock %}{% endif %}")
 
318
        except TemplateSyntaxError, e:
 
319
            self.assertEquals(e.args[0], "Invalid block tag: 'endblock', expected 'else' or 'endif'")
 
320
 
181
321
    def test_templates(self):
182
322
        template_tests = self.get_template_tests()
183
323
        filter_tests = filters.get_filter_tests()
197
337
            except KeyError:
198
338
                raise template.TemplateDoesNotExist, template_name
199
339
 
 
340
        cache_loader = cached.Loader(('test_template_loader',))
 
341
        cache_loader._cached_loaders = (test_template_loader,)
 
342
 
200
343
        old_template_loaders = loader.template_source_loaders
201
 
        loader.template_source_loaders = [test_template_loader]
 
344
        loader.template_source_loaders = [cache_loader]
202
345
 
203
346
        failures = []
204
347
        tests = template_tests.items()
211
354
        old_invalid = settings.TEMPLATE_STRING_IF_INVALID
212
355
        expected_invalid_str = 'INVALID'
213
356
 
 
357
        # Warm the URL reversing cache. This ensures we don't pay the cost
 
358
        # warming the cache during one of the tests.
 
359
        urlresolvers.reverse('regressiontests.templates.views.client_action',
 
360
                             kwargs={'id':0,'action':"update"})
 
361
 
214
362
        for name, vals in tests:
215
363
            if isinstance(vals[2], tuple):
216
364
                normal_string_result = vals[2][0]
217
365
                invalid_string_result = vals[2][1]
218
 
                if '%s' in invalid_string_result:
 
366
                if isinstance(invalid_string_result, basestring) and '%s' in invalid_string_result:
219
367
                    expected_invalid_str = 'INVALID %s'
220
368
                    invalid_string_result = invalid_string_result % vals[2][2]
221
369
                    template.invalid_var_format_string = True
231
379
            for invalid_str, result in [('', normal_string_result),
232
380
                                        (expected_invalid_str, invalid_string_result)]:
233
381
                settings.TEMPLATE_STRING_IF_INVALID = invalid_str
234
 
                try:
235
 
                    test_template = loader.get_template(name)
236
 
                    output = self.render(test_template, vals)
237
 
                except ContextStackException:
238
 
                    failures.append("Template test (TEMPLATE_STRING_IF_INVALID='%s'): %s -- FAILED. Context stack was left imbalanced" % (invalid_str, name))
239
 
                    continue
240
 
                except Exception:
241
 
                    exc_type, exc_value, exc_tb = sys.exc_info()
242
 
                    if exc_type != result:
243
 
                        tb = '\n'.join(traceback.format_exception(exc_type, exc_value, exc_tb))
244
 
                        failures.append("Template test (TEMPLATE_STRING_IF_INVALID='%s'): %s -- FAILED. Got %s, exception: %s\n%s" % (invalid_str, name, exc_type, exc_value, tb))
245
 
                    continue
246
 
                if output != result:
247
 
                    failures.append("Template test (TEMPLATE_STRING_IF_INVALID='%s'): %s -- FAILED. Expected %r, got %r" % (invalid_str, name, result, output))
 
382
                for is_cached in (False, True):
 
383
                    try:
 
384
                        start = datetime.now()
 
385
                        test_template = loader.get_template(name)
 
386
                        end = datetime.now()
 
387
                        if end-start > timedelta(seconds=0.2):
 
388
                            failures.append("Template test (Cached='%s', TEMPLATE_STRING_IF_INVALID='%s'): %s -- FAILED. Took too long to parse test" % (is_cached, invalid_str, name))
 
389
 
 
390
                        start = datetime.now()
 
391
                        output = self.render(test_template, vals)
 
392
                        end = datetime.now()
 
393
                        if end-start > timedelta(seconds=0.2):
 
394
                            failures.append("Template test (Cached='%s', TEMPLATE_STRING_IF_INVALID='%s'): %s -- FAILED. Took too long to render test" % (is_cached, invalid_str, name))
 
395
                    except ContextStackException:
 
396
                        failures.append("Template test (Cached='%s', TEMPLATE_STRING_IF_INVALID='%s'): %s -- FAILED. Context stack was left imbalanced" % (is_cached, invalid_str, name))
 
397
                        continue
 
398
                    except Exception:
 
399
                        exc_type, exc_value, exc_tb = sys.exc_info()
 
400
                        if exc_type != result:
 
401
                            tb = '\n'.join(traceback.format_exception(exc_type, exc_value, exc_tb))
 
402
                            failures.append("Template test (Cached='%s', TEMPLATE_STRING_IF_INVALID='%s'): %s -- FAILED. Got %s, exception: %s\n%s" % (is_cached, invalid_str, name, exc_type, exc_value, tb))
 
403
                        continue
 
404
                    if output != result:
 
405
                        failures.append("Template test (Cached='%s', TEMPLATE_STRING_IF_INVALID='%s'): %s -- FAILED. Expected %r, got %r" % (is_cached, invalid_str, name, result, output))
 
406
                cache_loader.reset()
248
407
 
249
408
            if 'LANGUAGE_CODE' in vals[1]:
250
409
                deactivate()
341
500
            'basic-syntax26': (r'{{ "\"fred\"" }}', {}, "\"fred\""),
342
501
            'basic-syntax27': (r'{{ _("\"fred\"") }}', {}, "\"fred\""),
343
502
 
 
503
            # regression test for ticket #12554
 
504
            # make sure a silent_variable_failure Exception is supressed
 
505
            # on dictionary and attribute lookup
 
506
            'basic-syntax28': ("{{ a.b }}", {'a': SilentGetItemClass()}, ('', 'INVALID')),
 
507
            'basic-syntax29': ("{{ a.b }}", {'a': SilentAttrClass()}, ('', 'INVALID')),
 
508
 
344
509
            # List-index syntax allows a template to access a certain item of a subscriptable object.
345
510
            'list-index01': ("{{ var.1 }}", {"var": ["first item", "second item"]}, "second item"),
346
511
 
474
639
            ### EXCEPTIONS ############################################################
475
640
 
476
641
            # Raise exception for invalid template name
477
 
            'exception01': ("{% extends 'nonexistent' %}", {}, template.TemplateSyntaxError),
 
642
            'exception01': ("{% extends 'nonexistent' %}", {}, template.TemplateDoesNotExist),
478
643
 
479
644
            # Raise exception for invalid template name (in variable)
480
 
            'exception02': ("{% extends nonexistent %}", {}, template.TemplateSyntaxError),
 
645
            'exception02': ("{% extends nonexistent %}", {}, (template.TemplateSyntaxError, template.TemplateDoesNotExist)),
481
646
 
482
647
            # Raise exception for extra {% extends %} tags
483
648
            'exception03': ("{% extends 'inheritance01' %}{% block first %}2{% endblock %}{% extends 'inheritance16' %}", {}, template.TemplateSyntaxError),
534
699
            'if-tag02': ("{% if foo %}yes{% else %}no{% endif %}", {"foo": False}, "no"),
535
700
            'if-tag03': ("{% if foo %}yes{% else %}no{% endif %}", {}, "no"),
536
701
 
 
702
            # Filters
 
703
            'if-tag-filter01': ("{% if foo|length == 5 %}yes{% else %}no{% endif %}", {'foo': 'abcde'}, "yes"),
 
704
            'if-tag-filter02': ("{% if foo|upper == 'ABC' %}yes{% else %}no{% endif %}", {}, "no"),
 
705
 
 
706
            # Equality
 
707
            'if-tag-eq01': ("{% if foo == bar %}yes{% else %}no{% endif %}", {}, "yes"),
 
708
            'if-tag-eq02': ("{% if foo == bar %}yes{% else %}no{% endif %}", {'foo': 1}, "no"),
 
709
            'if-tag-eq03': ("{% if foo == bar %}yes{% else %}no{% endif %}", {'foo': 1, 'bar': 1}, "yes"),
 
710
            'if-tag-eq04': ("{% if foo == bar %}yes{% else %}no{% endif %}", {'foo': 1, 'bar': 2}, "no"),
 
711
            'if-tag-eq05': ("{% if foo == '' %}yes{% else %}no{% endif %}", {}, "no"),
 
712
 
 
713
            # Comparison
 
714
            'if-tag-gt-01': ("{% if 2 > 1 %}yes{% else %}no{% endif %}", {}, "yes"),
 
715
            'if-tag-gt-02': ("{% if 1 > 1 %}yes{% else %}no{% endif %}", {}, "no"),
 
716
            'if-tag-gte-01': ("{% if 1 >= 1 %}yes{% else %}no{% endif %}", {}, "yes"),
 
717
            'if-tag-gte-02': ("{% if 1 >= 2 %}yes{% else %}no{% endif %}", {}, "no"),
 
718
            'if-tag-lt-01': ("{% if 1 < 2 %}yes{% else %}no{% endif %}", {}, "yes"),
 
719
            'if-tag-lt-02': ("{% if 1 < 1 %}yes{% else %}no{% endif %}", {}, "no"),
 
720
            'if-tag-lte-01': ("{% if 1 <= 1 %}yes{% else %}no{% endif %}", {}, "yes"),
 
721
            'if-tag-lte-02': ("{% if 2 <= 1 %}yes{% else %}no{% endif %}", {}, "no"),
 
722
 
 
723
            # Contains
 
724
            'if-tag-in-01': ("{% if 1 in x %}yes{% else %}no{% endif %}", {'x':[1]}, "yes"),
 
725
            'if-tag-in-02': ("{% if 2 in x %}yes{% else %}no{% endif %}", {'x':[1]}, "no"),
 
726
            'if-tag-not-in-01': ("{% if 1 not in x %}yes{% else %}no{% endif %}", {'x':[1]}, "no"),
 
727
            'if-tag-not-in-02': ("{% if 2 not in x %}yes{% else %}no{% endif %}", {'x':[1]}, "yes"),
 
728
 
537
729
            # AND
538
730
            'if-tag-and01': ("{% if foo and bar %}yes{% else %}no{% endif %}", {'foo': True, 'bar': True}, 'yes'),
539
731
            'if-tag-and02': ("{% if foo and bar %}yes{% else %}no{% endif %}", {'foo': True, 'bar': False}, 'no'),
554
746
            'if-tag-or07': ("{% if foo or bar %}yes{% else %}no{% endif %}", {'foo': True}, 'yes'),
555
747
            'if-tag-or08': ("{% if foo or bar %}yes{% else %}no{% endif %}", {'bar': True}, 'yes'),
556
748
 
557
 
            # TODO: multiple ORs
 
749
            # multiple ORs
 
750
            'if-tag-or09': ("{% if foo or bar or baz %}yes{% else %}no{% endif %}", {'baz': True}, 'yes'),
558
751
 
559
752
            # NOT
560
753
            'if-tag-not01': ("{% if not foo %}no{% else %}yes{% endif %}", {'foo': True}, 'yes'),
561
 
            'if-tag-not02': ("{% if not %}yes{% else %}no{% endif %}", {'foo': True}, 'no'),
562
 
            'if-tag-not03': ("{% if not %}yes{% else %}no{% endif %}", {'not': True}, 'yes'),
563
 
            'if-tag-not04': ("{% if not not %}no{% else %}yes{% endif %}", {'not': True}, 'yes'),
564
 
            'if-tag-not05': ("{% if not not %}no{% else %}yes{% endif %}", {}, 'no'),
 
754
            'if-tag-not02': ("{% if not not foo %}no{% else %}yes{% endif %}", {'foo': True}, 'no'),
 
755
            # not03 to not05 removed, now TemplateSyntaxErrors
565
756
 
566
757
            'if-tag-not06': ("{% if foo and not bar %}yes{% else %}no{% endif %}", {}, 'no'),
567
758
            'if-tag-not07': ("{% if foo and not bar %}yes{% else %}no{% endif %}", {'foo': True, 'bar': True}, 'no'),
599
790
            'if-tag-not34': ("{% if not foo or not bar %}yes{% else %}no{% endif %}", {'foo': False, 'bar': True}, 'yes'),
600
791
            'if-tag-not35': ("{% if not foo or not bar %}yes{% else %}no{% endif %}", {'foo': False, 'bar': False}, 'yes'),
601
792
 
602
 
            # AND and OR raises a TemplateSyntaxError
603
 
            'if-tag-error01': ("{% if foo or bar and baz %}yes{% else %}no{% endif %}", {'foo': False, 'bar': False}, template.TemplateSyntaxError),
 
793
            # Various syntax errors
 
794
            'if-tag-error01': ("{% if %}yes{% endif %}", {}, template.TemplateSyntaxError),
604
795
            'if-tag-error02': ("{% if foo and %}yes{% else %}no{% endif %}", {'foo': True}, template.TemplateSyntaxError),
605
796
            'if-tag-error03': ("{% if foo or %}yes{% else %}no{% endif %}", {'foo': True}, template.TemplateSyntaxError),
606
797
            'if-tag-error04': ("{% if not foo and %}yes{% else %}no{% endif %}", {'foo': True}, template.TemplateSyntaxError),
607
798
            'if-tag-error05': ("{% if not foo or %}yes{% else %}no{% endif %}", {'foo': True}, template.TemplateSyntaxError),
 
799
            'if-tag-error06': ("{% if abc def %}yes{% endif %}", {}, template.TemplateSyntaxError),
 
800
            'if-tag-error07': ("{% if not %}yes{% endif %}", {}, template.TemplateSyntaxError),
 
801
            'if-tag-error08': ("{% if and %}yes{% endif %}", {}, template.TemplateSyntaxError),
 
802
            'if-tag-error09': ("{% if or %}yes{% endif %}", {}, template.TemplateSyntaxError),
 
803
            'if-tag-error10': ("{% if == %}yes{% endif %}", {}, template.TemplateSyntaxError),
 
804
            'if-tag-error11': ("{% if 1 == %}yes{% endif %}", {}, template.TemplateSyntaxError),
 
805
            'if-tag-error12': ("{% if a not b %}yes{% endif %}", {}, template.TemplateSyntaxError),
 
806
 
 
807
            # If evaluations are shortcircuited where possible
 
808
            # These tests will fail by taking too long to run. When the if clause
 
809
            # is shortcircuiting correctly, the is_bad() function shouldn't be
 
810
            # evaluated, and the deliberate sleep won't happen.
 
811
            'if-tag-shortcircuit01': ('{% if x.is_true or x.is_bad %}yes{% else %}no{% endif %}', {'x': TestObj()}, "yes"),
 
812
            'if-tag-shortcircuit02': ('{% if x.is_false and x.is_bad %}yes{% else %}no{% endif %}', {'x': TestObj()}, "no"),
 
813
 
 
814
            # Non-existent args
 
815
            'if-tag-badarg01':("{% if x|default_if_none:y %}yes{% endif %}", {}, ''),
 
816
            'if-tag-badarg02':("{% if x|default_if_none:y %}yes{% endif %}", {'y': 0}, ''),
 
817
            'if-tag-badarg03':("{% if x|default_if_none:y %}yes{% endif %}", {'y': 1}, 'yes'),
 
818
            'if-tag-badarg04':("{% if x|default_if_none:y %}yes{% else %}no{% endif %}", {}, 'no'),
 
819
 
 
820
            # Additional, more precise parsing tests are in SmartIfTests
608
821
 
609
822
            ### IFCHANGED TAG #########################################################
610
823
            'ifchanged01': ('{% for n in num %}{% ifchanged %}{{ n }}{% endifchanged %}{% endfor %}', {'num': (1,2,3)}, '123'),
802
1015
            # Inheritance from a template with a space in its name should work.
803
1016
            'inheritance29': ("{% extends 'inheritance 28' %}", {}, '!'),
804
1017
 
 
1018
            # Base template, putting block in a conditional {% if %} tag
 
1019
            'inheritance30': ("1{% if optional %}{% block opt %}2{% endblock %}{% endif %}3", {'optional': True}, '123'),
 
1020
 
 
1021
            # Inherit from a template with block wrapped in an {% if %} tag (in parent), still gets overridden
 
1022
            'inheritance31': ("{% extends 'inheritance30' %}{% block opt %}two{% endblock %}", {'optional': True}, '1two3'),
 
1023
            'inheritance32': ("{% extends 'inheritance30' %}{% block opt %}two{% endblock %}", {}, '13'),
 
1024
 
 
1025
            # Base template, putting block in a conditional {% ifequal %} tag
 
1026
            'inheritance33': ("1{% ifequal optional 1 %}{% block opt %}2{% endblock %}{% endifequal %}3", {'optional': 1}, '123'),
 
1027
 
 
1028
            # Inherit from a template with block wrapped in an {% ifequal %} tag (in parent), still gets overridden
 
1029
            'inheritance34': ("{% extends 'inheritance33' %}{% block opt %}two{% endblock %}", {'optional': 1}, '1two3'),
 
1030
            'inheritance35': ("{% extends 'inheritance33' %}{% block opt %}two{% endblock %}", {'optional': 2}, '13'),
 
1031
 
 
1032
            # Base template, putting block in a {% for %} tag
 
1033
            'inheritance36': ("{% for n in numbers %}_{% block opt %}{{ n }}{% endblock %}{% endfor %}_", {'numbers': '123'}, '_1_2_3_'),
 
1034
 
 
1035
            # Inherit from a template with block wrapped in an {% for %} tag (in parent), still gets overridden
 
1036
            'inheritance37': ("{% extends 'inheritance36' %}{% block opt %}X{% endblock %}", {'numbers': '123'}, '_X_X_X_'),
 
1037
            'inheritance38': ("{% extends 'inheritance36' %}{% block opt %}X{% endblock %}", {}, '_'),
 
1038
 
 
1039
            # The super block will still be found.
 
1040
            'inheritance39': ("{% extends 'inheritance30' %}{% block opt %}new{{ block.super }}{% endblock %}", {'optional': True}, '1new23'),
 
1041
            'inheritance40': ("{% extends 'inheritance33' %}{% block opt %}new{{ block.super }}{% endblock %}", {'optional': 1}, '1new23'),
 
1042
            'inheritance41': ("{% extends 'inheritance36' %}{% block opt %}new{{ block.super }}{% endblock %}", {'numbers': '123'}, '_new1_new2_new3_'),
 
1043
 
805
1044
            ### I18N ##################################################################
806
1045
 
807
1046
            # {% spaceless %} tag
860
1099
            'i18n21': ('{% load i18n %}{% blocktrans %}{{ andrew }}{% endblocktrans %}', {'andrew': mark_safe('a & b')}, u'a & b'),
861
1100
            'i18n22': ('{% load i18n %}{% trans andrew %}', {'andrew': mark_safe('a & b')}, u'a & b'),
862
1101
 
 
1102
            # Use filters with the {% trans %} tag, #5972
 
1103
            'i18n23': ('{% load i18n %}{% trans "Page not found"|capfirst|slice:"6:" %}', {'LANGUAGE_CODE': 'de'}, u'nicht gefunden'),
 
1104
            'i18n24': ("{% load i18n %}{% trans 'Page not found'|upper %}", {'LANGUAGE_CODE': 'de'}, u'SEITE NICHT GEFUNDEN'),
 
1105
            'i18n25': ('{% load i18n %}{% trans somevar|upper %}', {'somevar': 'Page not found', 'LANGUAGE_CODE': 'de'}, u'SEITE NICHT GEFUNDEN'),
 
1106
 
863
1107
            ### HANDLING OF TEMPLATE_STRING_IF_INVALID ###################################
864
1108
 
865
1109
            'invalidstr01': ('{{ var|default:"Foo" }}', {}, ('Foo','INVALID')),
968
1212
 
969
1213
            ### URL TAG ########################################################
970
1214
            # Successes
 
1215
            'legacyurl02': ('{% url regressiontests.templates.views.client_action id=client.id,action="update" %}', {'client': {'id': 1}}, '/url_tag/client/1/update/'),
 
1216
            'legacyurl02a': ('{% url regressiontests.templates.views.client_action client.id,"update" %}', {'client': {'id': 1}}, '/url_tag/client/1/update/'),
 
1217
            'legacyurl02b': ("{% url regressiontests.templates.views.client_action id=client.id,action='update' %}", {'client': {'id': 1}}, '/url_tag/client/1/update/'),
 
1218
            'legacyurl02c': ("{% url regressiontests.templates.views.client_action client.id,'update' %}", {'client': {'id': 1}}, '/url_tag/client/1/update/'),
 
1219
            'legacyurl10': ('{% url regressiontests.templates.views.client_action id=client.id,action="two words" %}', {'client': {'id': 1}}, '/url_tag/client/1/two%20words/'),
 
1220
            'legacyurl13': ('{% url regressiontests.templates.views.client_action id=client.id, action=arg|join:"-" %}', {'client': {'id': 1}, 'arg':['a','b']}, '/url_tag/client/1/a-b/'),
 
1221
            'legacyurl14': ('{% url regressiontests.templates.views.client_action client.id, arg|join:"-" %}', {'client': {'id': 1}, 'arg':['a','b']}, '/url_tag/client/1/a-b/'),
 
1222
            'legacyurl16': ('{% url regressiontests.templates.views.client_action action="update",id="1" %}', {}, '/url_tag/client/1/update/'),
 
1223
            'legacyurl16a': ("{% url regressiontests.templates.views.client_action action='update',id='1' %}", {}, '/url_tag/client/1/update/'),
 
1224
            'legacyurl17': ('{% url regressiontests.templates.views.client_action client_id=client.my_id,action=action %}', {'client': {'my_id': 1}, 'action': 'update'}, '/url_tag/client/1/update/'),
 
1225
 
971
1226
            'url01': ('{% url regressiontests.templates.views.client client.id %}', {'client': {'id': 1}}, '/url_tag/client/1/'),
972
 
            'url02': ('{% url regressiontests.templates.views.client_action id=client.id,action="update" %}', {'client': {'id': 1}}, '/url_tag/client/1/update/'),
973
 
            'url02a': ('{% url regressiontests.templates.views.client_action client.id,"update" %}', {'client': {'id': 1}}, '/url_tag/client/1/update/'),
 
1227
            'url02': ('{% url regressiontests.templates.views.client_action id=client.id action="update" %}', {'client': {'id': 1}}, '/url_tag/client/1/update/'),
 
1228
            'url02a': ('{% url regressiontests.templates.views.client_action client.id "update" %}', {'client': {'id': 1}}, '/url_tag/client/1/update/'),
 
1229
            'url02b': ("{% url regressiontests.templates.views.client_action id=client.id action='update' %}", {'client': {'id': 1}}, '/url_tag/client/1/update/'),
 
1230
            'url02c': ("{% url regressiontests.templates.views.client_action client.id 'update' %}", {'client': {'id': 1}}, '/url_tag/client/1/update/'),
974
1231
            'url03': ('{% url regressiontests.templates.views.index %}', {}, '/url_tag/'),
975
1232
            'url04': ('{% url named.client client.id %}', {'client': {'id': 1}}, '/url_tag/named-client/1/'),
976
1233
            'url05': (u'{% url метка_оператора v %}', {'v': u'Ω'}, '/url_tag/%D0%AE%D0%BD%D0%B8%D0%BA%D0%BE%D0%B4/%CE%A9/'),
978
1235
            'url07': (u'{% url regressiontests.templates.views.client2 tag=v %}', {'v': u'Ω'}, '/url_tag/%D0%AE%D0%BD%D0%B8%D0%BA%D0%BE%D0%B4/%CE%A9/'),
979
1236
            'url08': (u'{% url метка_оператора v %}', {'v': 'Ω'}, '/url_tag/%D0%AE%D0%BD%D0%B8%D0%BA%D0%BE%D0%B4/%CE%A9/'),
980
1237
            'url09': (u'{% url метка_оператора_2 tag=v %}', {'v': 'Ω'}, '/url_tag/%D0%AE%D0%BD%D0%B8%D0%BA%D0%BE%D0%B4/%CE%A9/'),
981
 
            'url10': ('{% url regressiontests.templates.views.client_action id=client.id,action="two words" %}', {'client': {'id': 1}}, '/url_tag/client/1/two%20words/'),
 
1238
            'url10': ('{% url regressiontests.templates.views.client_action id=client.id action="two words" %}', {'client': {'id': 1}}, '/url_tag/client/1/two%20words/'),
 
1239
            'url11': ('{% url regressiontests.templates.views.client_action id=client.id action="==" %}', {'client': {'id': 1}}, '/url_tag/client/1/==/'),
 
1240
            'url12': ('{% url regressiontests.templates.views.client_action id=client.id action="," %}', {'client': {'id': 1}}, '/url_tag/client/1/,/'),
 
1241
            'url13': ('{% url regressiontests.templates.views.client_action id=client.id action=arg|join:"-" %}', {'client': {'id': 1}, 'arg':['a','b']}, '/url_tag/client/1/a-b/'),
 
1242
            'url14': ('{% url regressiontests.templates.views.client_action client.id arg|join:"-" %}', {'client': {'id': 1}, 'arg':['a','b']}, '/url_tag/client/1/a-b/'),
 
1243
            'url15': ('{% url regressiontests.templates.views.client_action 12 "test" %}', {}, '/url_tag/client/12/test/'),
 
1244
            'url18': ('{% url regressiontests.templates.views.client "1,2" %}', {}, '/url_tag/client/1,2/'),
982
1245
 
983
1246
            # Failures
984
1247
            'url-fail01': ('{% url %}', {}, template.TemplateSyntaxError),
985
1248
            'url-fail02': ('{% url no_such_view %}', {}, urlresolvers.NoReverseMatch),
986
1249
            'url-fail03': ('{% url regressiontests.templates.views.client %}', {}, urlresolvers.NoReverseMatch),
 
1250
            'url-fail04': ('{% url view id, %}', {}, template.TemplateSyntaxError),
 
1251
            'url-fail05': ('{% url view id= %}', {}, template.TemplateSyntaxError),
 
1252
            'url-fail06': ('{% url view a.id=id %}', {}, template.TemplateSyntaxError),
 
1253
            'url-fail07': ('{% url view a.id!id %}', {}, template.TemplateSyntaxError),
 
1254
            'url-fail08': ('{% url view id="unterminatedstring %}', {}, template.TemplateSyntaxError),
 
1255
            'url-fail09': ('{% url view id=", %}', {}, template.TemplateSyntaxError),
987
1256
 
988
1257
            # {% url ... as var %}
989
1258
            'url-asvar01': ('{% url regressiontests.templates.views.index as url %}', {}, ''),
1047
1316
            'autoescape-filtertag01': ("{{ first }}{% filter safe %}{{ first }} x<y{% endfilter %}", {"first": "<a>"}, template.TemplateSyntaxError),
1048
1317
        }
1049
1318
 
 
1319
 
 
1320
class TemplateTagLoading(unittest.TestCase):
 
1321
 
 
1322
    def setUp(self):
 
1323
        self.old_path = sys.path
 
1324
        self.old_apps = settings.INSTALLED_APPS
 
1325
        self.egg_dir = '%s/eggs' % os.path.dirname(__file__)
 
1326
        self.old_tag_modules = template.templatetags_modules
 
1327
        template.templatetags_modules = []
 
1328
 
 
1329
    def tearDown(self):
 
1330
        settings.INSTALLED_APPS = self.old_apps
 
1331
        sys.path = self.old_path
 
1332
        template.templatetags_modules = self.old_tag_modules
 
1333
 
 
1334
    def test_load_error(self):
 
1335
        ttext = "{% load broken_tag %}"
 
1336
        self.assertRaises(template.TemplateSyntaxError, template.Template, ttext)
 
1337
        try:
 
1338
            template.Template(ttext)
 
1339
        except template.TemplateSyntaxError, e:
 
1340
            self.assertTrue('ImportError' in e.args[0])
 
1341
            self.assertTrue('Xtemplate' in e.args[0])
 
1342
 
 
1343
    def test_load_error_egg(self):
 
1344
        ttext = "{% load broken_egg %}"
 
1345
        egg_name = '%s/tagsegg.egg' % self.egg_dir
 
1346
        sys.path.append(egg_name)
 
1347
        settings.INSTALLED_APPS = ('tagsegg',)
 
1348
        self.assertRaises(template.TemplateSyntaxError, template.Template, ttext)
 
1349
        try:
 
1350
            template.Template(ttext)
 
1351
        except template.TemplateSyntaxError, e:
 
1352
            self.assertTrue('ImportError' in e.args[0])
 
1353
            self.assertTrue('Xtemplate' in e.args[0])
 
1354
 
 
1355
    def test_load_working_egg(self):
 
1356
        ttext = "{% load working_egg %}"
 
1357
        egg_name = '%s/tagsegg.egg' % self.egg_dir
 
1358
        sys.path.append(egg_name)
 
1359
        settings.INSTALLED_APPS = ('tagsegg',)
 
1360
        t = template.Template(ttext)
 
1361
 
1050
1362
if __name__ == "__main__":
1051
1363
    unittest.main()