2006-12-06 03:48:46 +08:00
# -*- coding: utf-8 -*-
2013-07-30 01:19:04 +08:00
from __future__ import unicode_literals
2011-09-16 09:16:25 +08:00
2007-07-23 12:45:01 +08:00
import os
2009-03-31 15:23:50 +08:00
import sys
2009-03-30 07:33:01 +08:00
import traceback
2013-07-01 20:22:27 +08:00
import unittest
2013-02-24 17:28:05 +08:00
import warnings
2007-07-23 12:45:01 +08:00
2006-08-27 21:59:47 +08:00
from django import template
2014-07-22 01:38:34 +08:00
from django . contrib . auth . models import Group
2008-08-05 22:16:13 +08:00
from django . core import urlresolvers
2014-11-23 01:52:55 +08:00
from django . template import loader , Context , RequestContext , Template , TemplateSyntaxError
2014-11-20 06:23:58 +08:00
from django . template . engine import Engine
2014-11-16 03:58:26 +08:00
from django . template . loaders import app_directories , filesystem
2012-11-25 05:03:12 +08:00
from django . test import RequestFactory , TestCase
2014-11-16 03:41:30 +08:00
from django . test . utils import override_settings , extend_sys_path
2014-03-28 04:24:19 +08:00
from django . utils . deprecation import RemovedInDjango19Warning , RemovedInDjango20Warning
2012-12-08 18:13:52 +08:00
from django . utils . _os import upath
2012-07-21 03:14:27 +08:00
from django . utils import six
2014-01-26 21:29:04 +08:00
from django . utils import translation
2007-07-23 12:45:01 +08:00
2011-10-14 05:34:56 +08:00
from . import filters
2014-11-12 09:32:44 +08:00
from . syntax_tests . utils import register_test_tags , ShouldNotExecuteException
2009-06-18 23:03:17 +08:00
2013-11-03 05:34:05 +08:00
2009-04-08 06:02:34 +08:00
class ContextStackException ( Exception ) :
pass
2006-08-27 21:59:47 +08:00
2013-11-03 05:34:05 +08:00
2013-06-06 20:27:00 +08:00
class TemplateLoaderTests ( TestCase ) :
2010-11-17 23:36:26 +08:00
2007-07-23 12:45:01 +08:00
def test_loaders_security ( self ) :
2014-11-20 06:23:58 +08:00
ad_loader = app_directories . Loader ( Engine . get_default ( ) )
fs_loader = filesystem . Loader ( Engine . get_default ( ) )
2013-10-22 18:21:07 +08:00
2007-07-23 12:45:01 +08:00
def test_template_sources ( path , template_dirs , expected_sources ) :
2008-10-06 14:34:54 +08:00
if isinstance ( expected_sources , list ) :
2011-05-23 07:56:42 +08:00
# Fix expected sources so they are abspathed
expected_sources = [ os . path . abspath ( s ) for s in expected_sources ]
2008-10-06 14:34:54 +08:00
# Test the two loaders (app_directores and filesystem).
2009-12-14 20:08:23 +08:00
func1 = lambda p , t : list ( ad_loader . get_template_sources ( p , t ) )
func2 = lambda p , t : list ( fs_loader . get_template_sources ( p , t ) )
2008-10-06 14:34:54 +08:00
for func in ( func1 , func2 ) :
if isinstance ( expected_sources , list ) :
self . assertEqual ( func ( path , template_dirs ) , expected_sources )
else :
self . assertRaises ( expected_sources , func , path , template_dirs )
2007-07-23 12:45:01 +08:00
template_dirs = [ ' /dir1 ' , ' /dir2 ' ]
test_template_sources ( ' index.html ' , template_dirs ,
[ ' /dir1/index.html ' , ' /dir2/index.html ' ] )
2008-10-06 14:34:54 +08:00
test_template_sources ( ' /etc/passwd ' , template_dirs , [ ] )
2007-07-23 12:45:01 +08:00
test_template_sources ( ' etc/passwd ' , template_dirs ,
[ ' /dir1/etc/passwd ' , ' /dir2/etc/passwd ' ] )
2008-10-06 14:34:54 +08:00
test_template_sources ( ' ../etc/passwd ' , template_dirs , [ ] )
test_template_sources ( ' ../../../etc/passwd ' , template_dirs , [ ] )
2007-07-23 12:45:01 +08:00
test_template_sources ( ' /dir1/index.html ' , template_dirs ,
[ ' /dir1/index.html ' ] )
test_template_sources ( ' ../dir2/index.html ' , template_dirs ,
[ ' /dir2/index.html ' ] )
2008-10-06 14:34:54 +08:00
test_template_sources ( ' /dir1blah ' , template_dirs , [ ] )
test_template_sources ( ' ../dir1blah ' , template_dirs , [ ] )
# UTF-8 bytestrings are permitted.
2012-05-19 23:43:34 +08:00
test_template_sources ( b ' \xc3 \x85 ngstr \xc3 \xb6 m ' , template_dirs ,
2012-06-08 00:08:47 +08:00
[ ' /dir1/Ångström ' , ' /dir2/Ångström ' ] )
2008-10-06 14:34:54 +08:00
# Unicode strings are permitted.
2012-06-08 00:08:47 +08:00
test_template_sources ( ' Ångström ' , template_dirs ,
[ ' /dir1/Ångström ' , ' /dir2/Ångström ' ] )
test_template_sources ( ' Ångström ' , [ b ' /Stra \xc3 \x9f e ' ] , [ ' /Straße/Ångström ' ] )
2012-05-19 23:43:34 +08:00
test_template_sources ( b ' \xc3 \x85 ngstr \xc3 \xb6 m ' , [ b ' /Stra \xc3 \x9f e ' ] ,
2012-06-08 00:08:47 +08:00
[ ' /Straße/Ångström ' ] )
2008-10-06 14:34:54 +08:00
# Invalid UTF-8 encoding in bytestrings is not. Should raise a
# semi-useful error message.
2012-05-19 23:43:34 +08:00
test_template_sources ( b ' \xc3 \xc3 ' , template_dirs , UnicodeDecodeError )
2007-07-23 12:45:01 +08:00
# Case insensitive tests (for win32). Not run unless we're on
# a case insensitive operating system.
if os . path . normcase ( ' /TEST ' ) == os . path . normpath ( ' /test ' ) :
template_dirs = [ ' /dir1 ' , ' /DIR2 ' ]
test_template_sources ( ' index.html ' , template_dirs ,
2011-05-23 07:56:42 +08:00
[ ' /dir1/index.html ' , ' /DIR2/index.html ' ] )
2007-07-23 12:45:01 +08:00
test_template_sources ( ' /DIR1/index.HTML ' , template_dirs ,
2011-05-23 07:56:42 +08:00
[ ' /DIR1/index.HTML ' ] )
2007-07-23 12:45:01 +08:00
2014-11-16 03:41:30 +08:00
@override_settings ( TEMPLATE_LOADERS = [ ' django.template.loaders.filesystem.Loader ' ] )
2013-10-14 21:14:17 +08:00
# Turn TEMPLATE_DEBUG on, so that the origin file name will be kept with
# the compiled templates.
@override_settings ( TEMPLATE_DEBUG = True )
2010-03-02 07:05:35 +08:00
def test_loader_debug_origin ( self ) :
2013-12-12 17:59:05 +08:00
# We rely on the fact that runtests.py sets up TEMPLATE_DIRS to
2014-11-16 03:58:26 +08:00
# point to a directory containing a login.html file.
2013-12-12 17:59:05 +08:00
load_name = ' login.html '
2014-11-16 03:58:26 +08:00
# We also rely on the fact the file system and app directories loaders
# both inherit the load_template method from the base Loader class, so
# we only need to test one of them.
2013-12-12 17:59:05 +08:00
template = loader . get_template ( load_name )
template_name = template . nodelist [ 0 ] . source [ 0 ] . name
self . assertTrue ( template_name . endswith ( load_name ) ,
' Template loaded by filesystem loader has incorrect name for debug page: %s ' % template_name )
2014-11-16 03:58:26 +08:00
@override_settings ( TEMPLATE_LOADERS = [
( ' django.template.loaders.cached.Loader ' ,
[ ' django.template.loaders.filesystem.Loader ' ] ) ,
] )
@override_settings ( TEMPLATE_DEBUG = True )
def test_cached_loader_debug_origin ( self ) :
# Same comment as in test_loader_debug_origin.
load_name = ' login.html '
2013-12-12 17:59:05 +08:00
2014-11-16 03:58:26 +08:00
# Test the cached loader separately since it overrides load_template.
2013-12-12 17:59:05 +08:00
template = loader . get_template ( load_name )
template_name = template . nodelist [ 0 ] . source [ 0 ] . name
self . assertTrue ( template_name . endswith ( load_name ) ,
' Template loaded through cached loader has incorrect name for debug page: %s ' % template_name )
template = loader . get_template ( load_name )
template_name = template . nodelist [ 0 ] . source [ 0 ] . name
self . assertTrue ( template_name . endswith ( load_name ) ,
' Cached template loaded through cached loader has incorrect name for debug page: %s ' % template_name )
2010-03-16 22:34:57 +08:00
2014-11-16 03:58:26 +08:00
@override_settings ( TEMPLATE_DEBUG = True )
2013-08-31 03:08:40 +08:00
def test_loader_origin ( self ) :
2014-11-16 03:58:26 +08:00
template = loader . get_template ( ' login.html ' )
self . assertEqual ( template . origin . loadname , ' login.html ' )
2013-08-31 03:08:40 +08:00
2014-11-16 03:58:26 +08:00
@override_settings ( TEMPLATE_DEBUG = True )
2013-08-31 03:08:40 +08:00
def test_string_origin ( self ) :
2014-11-16 03:58:26 +08:00
template = Template ( ' string template ' )
self . assertEqual ( template . origin . source , ' string template ' )
2013-08-31 03:08:40 +08:00
def test_debug_false_origin ( self ) :
template = loader . get_template ( ' login.html ' )
self . assertEqual ( template . origin , None )
2011-03-03 08:41:40 +08:00
2013-10-14 21:14:17 +08:00
# TEMPLATE_DEBUG must be true, otherwise the exception raised
# during {% include %} processing will be suppressed.
@override_settings ( TEMPLATE_DEBUG = True )
2013-12-12 17:59:05 +08:00
# Test the base loader class via the app loader. load_template
# from base is used by all shipped loaders excepting cached,
# which has its own test.
2014-11-16 03:41:30 +08:00
@override_settings ( TEMPLATE_LOADERS = [ ' django.template.loaders.app_directories.Loader ' ] )
2011-03-03 08:41:40 +08:00
def test_include_missing_template ( self ) :
"""
Tests that the correct template is identified as not existing
when { % include % } specifies a template that does not exist .
"""
2013-12-12 17:59:05 +08:00
load_name = ' test_include_error.html '
r = None
2011-03-03 08:41:40 +08:00
try :
2013-12-12 17:59:05 +08:00
tmpl = loader . select_template ( [ load_name ] )
r = tmpl . render ( template . Context ( { } ) )
except template . TemplateDoesNotExist as e :
self . assertEqual ( e . args [ 0 ] , ' missing.html ' )
self . assertEqual ( r , None , ' Template rendering unexpectedly succeeded, produced: -> %r <- ' % r )
2011-03-03 08:41:40 +08:00
2013-10-14 21:14:17 +08:00
# TEMPLATE_DEBUG must be true, otherwise the exception raised
# during {% include %} processing will be suppressed.
@override_settings ( TEMPLATE_DEBUG = True )
2013-12-12 17:59:05 +08:00
# Test the base loader class via the app loader. load_template
# from base is used by all shipped loaders excepting cached,
# which has its own test.
2014-11-16 03:41:30 +08:00
@override_settings ( TEMPLATE_LOADERS = [ ' django.template.loaders.app_directories.Loader ' ] )
2010-03-16 22:34:57 +08:00
def test_extends_include_missing_baseloader ( self ) :
"""
2010-03-30 20:44:30 +08:00
Tests that the correct template is identified as not existing
when { % extends % } specifies a template that does exist , but
2010-03-16 22:34:57 +08:00
that template has an { % include % } of something that does not
exist . See #12787.
"""
2013-12-12 17:59:05 +08:00
load_name = ' test_extends_error.html '
tmpl = loader . get_template ( load_name )
r = None
2010-03-16 22:34:57 +08:00
try :
2013-12-12 17:59:05 +08:00
r = tmpl . render ( template . Context ( { } ) )
except template . TemplateDoesNotExist as e :
self . assertEqual ( e . args [ 0 ] , ' missing.html ' )
self . assertEqual ( r , None , ' Template rendering unexpectedly succeeded, produced: -> %r <- ' % r )
2010-03-16 22:34:57 +08:00
2013-10-14 21:14:17 +08:00
@override_settings ( TEMPLATE_DEBUG = True )
2010-03-16 22:34:57 +08:00
def test_extends_include_missing_cachedloader ( self ) :
"""
2010-03-30 20:44:30 +08:00
Same as test_extends_include_missing_baseloader , only tests
2014-11-16 01:35:02 +08:00
behavior of the cached loader instead of base loader .
2010-03-16 22:34:57 +08:00
"""
2014-11-16 03:41:30 +08:00
with override_settings ( TEMPLATE_LOADERS = [
( ' django.template.loaders.cached.Loader ' , [
' django.template.loaders.app_directories.Loader ' ,
] ) ,
] ) :
2010-03-16 22:34:57 +08:00
load_name = ' test_extends_error.html '
tmpl = loader . get_template ( load_name )
r = None
try :
r = tmpl . render ( template . Context ( { } ) )
2012-04-29 00:09:37 +08:00
except template . TemplateDoesNotExist as e :
2011-09-16 09:16:25 +08:00
self . assertEqual ( e . args [ 0 ] , ' missing.html ' )
2010-03-16 22:34:57 +08:00
self . assertEqual ( r , None , ' Template rendering unexpectedly succeeded, produced: -> %r <- ' % r )
# For the cached loader, repeat the test, to ensure the first attempt did not cache a
# result that behaves incorrectly on subsequent attempts.
tmpl = loader . get_template ( load_name )
try :
tmpl . render ( template . Context ( { } ) )
2012-04-29 00:09:37 +08:00
except template . TemplateDoesNotExist as e :
2011-09-16 09:16:25 +08:00
self . assertEqual ( e . args [ 0 ] , ' missing.html ' )
2010-03-16 22:34:57 +08:00
self . assertEqual ( r , None , ' Template rendering unexpectedly succeeded, produced: -> %r <- ' % r )
2010-03-02 07:05:35 +08:00
2013-08-28 20:17:20 +08:00
def test_include_template_argument ( self ) :
"""
Support any render ( ) supporting object
"""
ctx = Context ( {
' tmpl ' : Template ( ' This worked! ' ) ,
} )
outer_tmpl = Template ( ' { % i nclude tmpl % } ' )
output = outer_tmpl . render ( ctx )
self . assertEqual ( output , ' This worked! ' )
2013-08-29 16:58:56 +08:00
@override_settings ( TEMPLATE_DEBUG = True )
def test_include_immediate_missing ( self ) :
"""
Regression test for #16417 -- {% include %} tag raises TemplateDoesNotExist at compile time if TEMPLATE_DEBUG is True
Test that an { % include % } tag with a literal string referencing a
template that does not exist does not raise an exception at parse
time .
"""
tmpl = Template ( ' { % i nclude " this_does_not_exist.html " % } ' )
self . assertIsInstance ( tmpl , Template )
@override_settings ( TEMPLATE_DEBUG = True )
def test_include_recursive ( self ) :
comments = [
{
' comment ' : ' A1 ' ,
' children ' : [
{ ' comment ' : ' B1 ' , ' children ' : [ ] } ,
{ ' comment ' : ' B2 ' , ' children ' : [ ] } ,
{ ' comment ' : ' B3 ' , ' children ' : [
{ ' comment ' : ' C1 ' , ' children ' : [ ] }
] } ,
]
}
]
t = loader . get_template ( ' recursive_include.html ' )
self . assertEqual (
" Recursion! A1 Recursion! B1 B2 B3 Recursion! C1 " ,
t . render ( Context ( { ' comments ' : comments } ) ) . replace ( ' ' , ' ' ) . replace ( ' \n ' , ' ' ) . strip ( ) ,
)
2013-06-06 20:27:00 +08:00
class TemplateRegressionTests ( TestCase ) :
2008-09-01 02:28:06 +08:00
def test_token_smart_split ( self ) :
# Regression test for #7027
token = template . Token ( template . TOKEN_BLOCK , ' sometag _( " Page not found " ) value|yesno:_( " yes,no " ) ' )
split = token . split_contents ( )
self . assertEqual ( split , [ " sometag " , ' _( " Page not found " ) ' , ' value|yesno:_( " yes,no " ) ' ] )
2011-09-16 09:16:25 +08:00
@override_settings ( SETTINGS_MODULE = None , TEMPLATE_DEBUG = True )
2009-04-02 06:46:46 +08:00
def test_url_reverse_no_settings_module ( self ) :
2009-04-05 03:34:52 +08:00
# Regression test for #9005
2009-04-02 06:46:46 +08:00
t = Template ( ' { % u rl will_not_match % } ' )
c = Context ( )
2011-09-16 09:16:25 +08:00
with self . assertRaises ( urlresolvers . NoReverseMatch ) :
t . render ( c )
2013-02-24 00:41:30 +08:00
@override_settings ( TEMPLATE_STRING_IF_INVALID = ' %s is invalid ' , SETTINGS_MODULE = ' also_something ' )
def test_url_reverse_view_name ( self ) :
# Regression test for #19827
t = Template ( ' { % u rl will_not_match % } ' )
c = Context ( )
try :
t . render ( c )
except urlresolvers . NoReverseMatch :
tb = sys . exc_info ( ) [ 2 ]
depth = 0
while tb . tb_next is not None :
tb = tb . tb_next
depth + = 1
2014-10-28 18:02:56 +08:00
self . assertGreater ( depth , 5 ,
2013-02-24 00:41:30 +08:00
" The traceback context was lost when reraising the traceback. See #19827 " )
2012-04-11 04:49:45 +08:00
@override_settings ( DEBUG = True , TEMPLATE_DEBUG = True )
2011-09-16 09:16:25 +08:00
def test_no_wrapped_exception ( self ) :
"""
The template system doesn ' t wrap exceptions, but annotates them.
Refs #16770
"""
c = Context ( { " coconuts " : lambda : 42 / 0 } )
t = Template ( " {{ coconuts }} " )
with self . assertRaises ( ZeroDivisionError ) as cm :
t . render ( c )
self . assertEqual ( cm . exception . django_template_source [ 1 ] , ( 0 , 14 ) )
2009-04-05 03:34:52 +08:00
2010-02-22 07:38:33 +08:00
def test_invalid_block_suggestion ( self ) :
# See #7876
try :
2013-10-19 20:31:38 +08:00
Template ( " { % i f 1 % }lala { % e ndblock % } { % e ndif % } " )
2012-04-29 00:09:37 +08:00
except TemplateSyntaxError as e :
2011-12-10 06:13:27 +08:00
self . assertEqual ( e . args [ 0 ] , " Invalid block tag: ' endblock ' , expected ' elif ' , ' else ' or ' endif ' " )
2010-02-22 07:38:33 +08:00
2013-02-23 20:13:44 +08:00
def test_ifchanged_concurrency ( self ) :
# Tests for #15849
template = Template ( ' [0 { % f or x in foo % }, { % with var=get_value % } { % i fchanged % } {{ var }} { % e ndifchanged % } { % e ndwith % } { % e ndfor % }] ' )
# Using generator to mimic concurrency.
# The generator is not passed to the 'for' loop, because it does a list(values)
# instead, call gen.next() in the template to control the generator.
def gen ( ) :
yield 1
yield 2
# Simulate that another thread is now rendering.
# When the IfChangeNode stores state at 'self' it stays at '3' and skip the last yielded value below.
iter2 = iter ( [ 1 , 2 , 3 ] )
output2 = template . render ( Context ( { ' foo ' : range ( 3 ) , ' get_value ' : lambda : next ( iter2 ) } ) )
2014-11-27 08:41:27 +08:00
self . assertEqual ( output2 , ' [0,1,2,3] ' , ' Expected [0,1,2,3] in second parallel template, got {} ' . format ( output2 ) )
2013-02-23 20:13:44 +08:00
yield 3
gen1 = gen ( )
output1 = template . render ( Context ( { ' foo ' : range ( 3 ) , ' get_value ' : lambda : next ( gen1 ) } ) )
2014-11-27 08:41:27 +08:00
self . assertEqual ( output1 , ' [0,1,2,3] ' , ' Expected [0,1,2,3] in first template, got {} ' . format ( output1 ) )
2013-02-23 20:13:44 +08:00
2013-03-25 16:10:32 +08:00
def test_cache_regression_20130 ( self ) :
t = Template ( ' { % lo ad cache % } { % c ache 1 regression_20130 % }foo { % e ndcache % } ' )
cachenode = t . nodelist [ 1 ]
self . assertEqual ( cachenode . fragment_name , ' regression_20130 ' )
2013-10-04 05:36:21 +08:00
@override_settings ( CACHES = {
' default ' : {
' BACKEND ' : ' django.core.cache.backends.locmem.LocMemCache ' ,
' LOCATION ' : ' default ' ,
} ,
' template_fragments ' : {
' BACKEND ' : ' django.core.cache.backends.locmem.LocMemCache ' ,
' LOCATION ' : ' fragments ' ,
} ,
} )
def test_cache_fragment_cache ( self ) :
"""
When a cache called " template_fragments " is present , the cache tag
will use it in preference to ' default '
"""
t1 = Template ( ' { % lo ad cache % } { % c ache 1 fragment % }foo { % e ndcache % } ' )
t2 = Template ( ' { % lo ad cache % } { % c ache 1 fragment using= " default " % }bar { % e ndcache % } ' )
ctx = Context ( )
o1 = t1 . render ( ctx )
o2 = t2 . render ( ctx )
self . assertEqual ( o1 , ' foo ' )
2013-10-19 06:49:24 +08:00
self . assertEqual ( o2 , ' bar ' )
2013-10-04 05:36:21 +08:00
def test_cache_missing_backend ( self ) :
"""
When a cache that doesn ' t exist is specified, the cache tag will
raise a TemplateSyntaxError
' " " "
t = Template ( ' { % lo ad cache % } { % c ache 1 backend using= " unknown " % }bar { % e ndcache % } ' )
ctx = Context ( )
with self . assertRaises ( TemplateSyntaxError ) :
t . render ( ctx )
2013-02-24 23:49:28 +08:00
def test_ifchanged_render_once ( self ) :
""" Test for ticket #19890. The content of ifchanged template tag was
rendered twice . """
2014-03-28 04:24:19 +08:00
template = Template ( ' { % i fchanged % } { % c ycle " 1st time " " 2nd time " % } { % e ndifchanged % } ' )
2013-02-25 05:47:14 +08:00
output = template . render ( Context ( { } ) )
self . assertEqual ( output , ' 1st time ' )
2013-02-24 23:49:28 +08:00
2013-05-30 15:25:58 +08:00
def test_super_errors ( self ) :
"""
Test behavior of the raise errors into included blocks .
See #18169
"""
t = loader . get_template ( ' included_content.html ' )
with self . assertRaises ( urlresolvers . NoReverseMatch ) :
t . render ( Context ( { } ) )
2014-07-22 01:38:34 +08:00
def test_debug_tag_non_ascii ( self ) :
"""
Test non - ASCII model representation in debug output ( #23060).
"""
Group . objects . create ( name = " 清風 " )
c1 = Context ( { " objs " : Group . objects . all ( ) } )
t1 = Template ( ' { % d ebug % } ' )
self . assertIn ( " 清風 " , t1 . render ( c1 ) )
2013-06-06 20:27:00 +08:00
2013-11-28 21:22:07 +08:00
# Set ALLOWED_INCLUDE_ROOTS so that ssi works.
2014-11-12 09:32:44 +08:00
@override_settings ( TEMPLATE_DEBUG = False , ROOT_URLCONF = ' template_tests.urls ' )
2014-01-26 21:29:04 +08:00
class TemplateTests ( TestCase ) :
2014-01-14 23:43:27 +08:00
2014-11-12 09:32:44 +08:00
@register_test_tags
2006-08-27 21:59:47 +08:00
def test_templates ( self ) :
2014-11-12 09:32:44 +08:00
template_tests = filters . get_filter_tests ( )
2007-11-14 20:58:53 +08:00
2013-12-12 17:59:05 +08:00
templates = dict ( ( name , t [ 0 ] ) for name , t in six . iteritems ( template_tests ) )
2014-11-16 03:41:30 +08:00
with override_settings ( TEMPLATE_LOADERS = [
( ' django.template.loaders.cached.Loader ' , [
( ' django.template.loaders.locmem.Loader ' , templates ) ,
] ) ,
] ) :
2013-12-12 17:59:05 +08:00
failures = [ ]
tests = sorted ( template_tests . items ( ) )
2007-11-14 20:58:53 +08:00
2013-12-12 17:59:05 +08:00
# Warm the URL reversing cache. This ensures we don't pay the cost
# warming the cache during one of the tests.
2014-06-03 19:30:14 +08:00
urlresolvers . reverse ( ' named.client ' , args = ( 0 , ) )
2013-12-12 17:59:05 +08:00
for name , vals in tests :
2014-11-23 01:52:55 +08:00
# Set TEMPLATE_STRING_IF_INVALID to a known string.
expected_invalid_str = ' INVALID '
2013-12-12 17:59:05 +08:00
if isinstance ( vals [ 2 ] , tuple ) :
normal_string_result = vals [ 2 ] [ 0 ]
invalid_string_result = vals [ 2 ] [ 1 ]
2014-01-26 21:29:04 +08:00
2013-12-12 17:59:05 +08:00
if isinstance ( invalid_string_result , tuple ) :
expected_invalid_str = ' INVALID %s '
invalid_string_result = invalid_string_result [ 0 ] % invalid_string_result [ 1 ]
try :
template_debug_result = vals [ 2 ] [ 2 ]
except IndexError :
template_debug_result = normal_string_result
else :
normal_string_result = vals [ 2 ]
invalid_string_result = vals [ 2 ]
template_debug_result = vals [ 2 ]
with translation . override ( vals [ 1 ] . get ( ' LANGUAGE_CODE ' , ' en-us ' ) ) :
for invalid_str , template_debug , result in [
( ' ' , False , normal_string_result ) ,
( expected_invalid_str , False , invalid_string_result ) ,
( ' ' , True , template_debug_result )
] :
with override_settings ( TEMPLATE_STRING_IF_INVALID = invalid_str ,
TEMPLATE_DEBUG = template_debug ) :
for is_cached in ( False , True ) :
2014-01-26 21:29:04 +08:00
try :
2013-12-12 17:59:05 +08:00
try :
with warnings . catch_warnings ( ) :
# Ignore pending deprecations of loading 'ssi' and 'url' tags from future.
warnings . filterwarnings ( " ignore " , category = RemovedInDjango19Warning , module = ' django.templatetags.future ' )
# Ignore deprecations of loading 'cycle' and 'firstof' tags from future.
warnings . filterwarnings ( " ignore " , category = RemovedInDjango20Warning , module = " django.templatetags.future " )
test_template = loader . get_template ( name )
except ShouldNotExecuteException :
failures . append ( " Template test (Cached= ' %s ' , TEMPLATE_STRING_IF_INVALID= ' %s ' , TEMPLATE_DEBUG= %s ): %s -- FAILED. Template loading invoked method that shouldn ' t have been invoked. " % ( is_cached , invalid_str , template_debug , name ) )
try :
with warnings . catch_warnings ( ) :
# Ignore deprecations of using the wrong number of variables with the 'for' tag.
2014-06-03 19:30:14 +08:00
# and warnings for {% url %} reversing by dotted path
2013-12-12 17:59:05 +08:00
warnings . filterwarnings ( " ignore " , category = RemovedInDjango20Warning , module = " django.template.defaulttags " )
2014-08-11 19:24:51 +08:00
# Ignore deprecations of old style unordered_list
# and removetags.
2014-08-11 15:51:52 +08:00
warnings . filterwarnings ( " ignore " , category = RemovedInDjango20Warning , module = " django.template.defaultfilters " )
2014-11-25 22:09:13 +08:00
# Ignore numpy deprecation warnings (#23890)
warnings . filterwarnings (
" ignore " ,
" Using a non-integer number instead of an "
" integer will result in an error in the future " ,
DeprecationWarning
)
2013-12-12 17:59:05 +08:00
output = self . render ( test_template , vals )
except ShouldNotExecuteException :
failures . append ( " Template test (Cached= ' %s ' , TEMPLATE_STRING_IF_INVALID= ' %s ' , TEMPLATE_DEBUG= %s ): %s -- FAILED. Template rendering invoked method that shouldn ' t have been invoked. " % ( is_cached , invalid_str , template_debug , name ) )
except ContextStackException :
failures . append ( " Template test (Cached= ' %s ' , TEMPLATE_STRING_IF_INVALID= ' %s ' , TEMPLATE_DEBUG= %s ): %s -- FAILED. Context stack was left imbalanced " % ( is_cached , invalid_str , template_debug , name ) )
continue
except Exception :
exc_type , exc_value , exc_tb = sys . exc_info ( )
if exc_type != result :
tb = ' \n ' . join ( traceback . format_exception ( exc_type , exc_value , exc_tb ) )
failures . append ( " Template test (Cached= ' %s ' , TEMPLATE_STRING_IF_INVALID= ' %s ' , TEMPLATE_DEBUG= %s ): %s -- FAILED. Got %s , exception: %s \n %s " % ( is_cached , invalid_str , template_debug , name , exc_type , exc_value , tb ) )
continue
if output != result :
failures . append ( " Template test (Cached= ' %s ' , TEMPLATE_STRING_IF_INVALID= ' %s ' , TEMPLATE_DEBUG= %s ): %s -- FAILED. Expected %r , got %r " % ( is_cached , invalid_str , template_debug , name , result , output ) )
2014-11-16 03:41:30 +08:00
2014-11-20 06:23:58 +08:00
Engine . get_default ( ) . template_loaders [ 0 ] . reset ( )
2014-01-26 21:29:04 +08:00
2009-03-31 00:05:57 +08:00
self . assertEqual ( failures , [ ] , " Tests failed: \n %s \n %s " %
2013-11-03 05:34:05 +08:00
( ' - ' * 70 , ( " \n %s \n " % ( ' - ' * 70 ) ) . join ( failures ) ) )
2007-11-14 20:58:53 +08:00
def render ( self , test_template , vals ) :
2009-04-08 06:02:34 +08:00
context = template . Context ( vals [ 1 ] )
before_stack_size = len ( context . dicts )
output = test_template . render ( context )
if len ( context . dicts ) != before_stack_size :
raise ContextStackException
return output
2007-11-14 20:58:53 +08:00
2013-10-18 07:58:02 +08:00
2013-10-14 21:14:17 +08:00
class TemplateTagLoading ( TestCase ) :
2010-04-16 03:57:09 +08:00
def setUp ( self ) :
2012-12-08 18:13:52 +08:00
self . egg_dir = ' %s /eggs ' % os . path . dirname ( upath ( __file__ ) )
2010-04-16 03:57:09 +08:00
def test_load_error ( self ) :
ttext = " { % lo ad broken_tag % } "
self . assertRaises ( template . TemplateSyntaxError , template . Template , ttext )
try :
template . Template ( ttext )
2012-04-29 00:09:37 +08:00
except template . TemplateSyntaxError as e :
2014-10-28 18:02:56 +08:00
self . assertIn ( ' ImportError ' , e . args [ 0 ] )
self . assertIn ( ' Xtemplate ' , e . args [ 0 ] )
2010-04-16 03:57:09 +08:00
def test_load_error_egg ( self ) :
ttext = " { % lo ad broken_egg % } "
egg_name = ' %s /tagsegg.egg ' % self . egg_dir
2014-01-26 13:50:40 +08:00
with extend_sys_path ( egg_name ) :
with self . assertRaises ( template . TemplateSyntaxError ) :
with self . settings ( INSTALLED_APPS = [ ' tagsegg ' ] ) :
template . Template ( ttext )
try :
with self . settings ( INSTALLED_APPS = [ ' tagsegg ' ] ) :
template . Template ( ttext )
except template . TemplateSyntaxError as e :
2014-10-28 18:02:56 +08:00
self . assertIn ( ' ImportError ' , e . args [ 0 ] )
self . assertIn ( ' Xtemplate ' , e . args [ 0 ] )
2010-04-16 03:57:09 +08:00
def test_load_working_egg ( self ) :
ttext = " { % lo ad working_egg % } "
egg_name = ' %s /tagsegg.egg ' % self . egg_dir
2014-01-26 13:50:40 +08:00
with extend_sys_path ( egg_name ) :
with self . settings ( INSTALLED_APPS = [ ' tagsegg ' ] ) :
template . Template ( ttext )
2010-04-16 03:57:09 +08:00
2011-04-17 12:52:31 +08:00
2012-04-09 21:24:57 +08:00
class RequestContextTests ( unittest . TestCase ) :
2011-04-17 12:52:31 +08:00
def setUp ( self ) :
self . fake_request = RequestFactory ( ) . get ( ' / ' )
2014-11-16 03:41:30 +08:00
@override_settings ( TEMPLATE_LOADERS = [
( ' django.template.loaders.locmem.Loader ' , {
' child ' : ' {{ var|default: " none " }} ' ,
} ) ,
] )
2011-04-17 12:52:31 +08:00
def test_include_only ( self ) :
"""
Regression test for #15721, ``{% include %}`` and ``RequestContext``
not playing together nicely .
"""
ctx = RequestContext ( self . fake_request , { ' var ' : ' parent ' } )
self . assertEqual (
template . Template ( ' { % i nclude " child " % } ' ) . render ( ctx ) ,
' parent '
)
self . assertEqual (
template . Template ( ' { % i nclude " child " only % } ' ) . render ( ctx ) ,
' none '
)
2013-08-29 12:08:01 +08:00
def test_stack_size ( self ) :
"""
Regression test for #7116, Optimize RequetsContext construction
"""
ctx = RequestContext ( self . fake_request , { } )
# The stack should now contain 3 items:
# [builtins, supplied context, context processor]
self . assertEqual ( len ( ctx . dicts ) , 3 )
2013-08-28 06:50:11 +08:00
2014-02-15 20:45:52 +08:00
@override_settings ( TEMPLATE_CONTEXT_PROCESSORS = ( ) )
def test_context_comparable ( self ) :
test_data = { ' x ' : ' y ' , ' v ' : ' z ' , ' d ' : { ' o ' : object , ' a ' : ' b ' } }
# test comparing RequestContext to prevent problems if somebody
# adds __eq__ in the future
request = RequestFactory ( ) . get ( ' / ' )
2014-02-17 11:54:36 +08:00
self . assertEqual (
2014-02-15 20:45:52 +08:00
RequestContext ( request , dict_ = test_data ) ,
RequestContext ( request , dict_ = test_data )
)
2013-08-28 06:50:11 +08:00
class SSITests ( TestCase ) :
def setUp ( self ) :
self . this_dir = os . path . dirname ( os . path . abspath ( upath ( __file__ ) ) )
self . ssi_dir = os . path . join ( self . this_dir , " templates " , " first " )
def render_ssi ( self , path ) :
# the path must exist for the test to be reliable
self . assertTrue ( os . path . exists ( path ) )
return template . Template ( ' { %% ssi " %s " %% } ' % path ) . render ( Context ( ) )
def test_allowed_paths ( self ) :
acceptable_path = os . path . join ( self . ssi_dir , " .. " , " first " , " test.html " )
with override_settings ( ALLOWED_INCLUDE_ROOTS = ( self . ssi_dir , ) ) :
self . assertEqual ( self . render_ssi ( acceptable_path ) , ' First template \n ' )
def test_relative_include_exploit ( self ) :
"""
May not bypass ALLOWED_INCLUDE_ROOTS with relative paths
e . g . if ALLOWED_INCLUDE_ROOTS = ( " /var/www " , ) , it should not be
possible to do { % ssi " /var/www/../../etc/passwd " % }
"""
disallowed_paths = [
os . path . join ( self . ssi_dir , " .. " , " ssi_include.html " ) ,
os . path . join ( self . ssi_dir , " .. " , " second " , " test.html " ) ,
]
with override_settings ( ALLOWED_INCLUDE_ROOTS = ( self . ssi_dir , ) ) :
for path in disallowed_paths :
self . assertEqual ( self . render_ssi ( path ) , ' ' )