2005-11-17 23:55:04 +08:00
import traceback
2005-10-15 04:10:13 +08:00
from django . core import template
from django . core . template import loader
2005-11-17 23:55:04 +08:00
from django . utils . translation import activate , deactivate , install
2005-08-02 03:09:07 +08:00
# Helper objects for template tests
class SomeClass :
def __init__ ( self ) :
self . otherclass = OtherClass ( )
2005-08-30 05:11:41 +08:00
2005-08-02 03:09:07 +08:00
def method ( self ) :
return " SomeClass.method "
2005-08-30 05:11:41 +08:00
2005-08-02 03:09:07 +08:00
def method2 ( self , o ) :
return o
class OtherClass :
def method ( self ) :
return " OtherClass.method "
2005-08-30 05:11:41 +08:00
2005-08-02 03:09:07 +08:00
# SYNTAX --
# 'template_name': ('template contents', 'context dict', 'expected string output' or Exception class)
TEMPLATE_TESTS = {
### BASIC SYNTAX ##########################################################
2005-08-30 05:11:41 +08:00
2005-08-02 03:09:07 +08:00
# Plain text should go through the template parser untouched
' basic-syntax01 ' : ( " something cool " , { } , " something cool " ) ,
2005-08-30 05:11:41 +08:00
2005-08-02 03:09:07 +08:00
# Variables should be replaced with their value in the current context
' basic-syntax02 ' : ( " {{ headline }} " , { ' headline ' : ' Success ' } , " Success " ) ,
# More than one replacement variable is allowed in a template
' basic-syntax03 ' : ( " {{ first }} --- {{ second }} " , { " first " : 1 , " second " : 2 } , " 1 --- 2 " ) ,
2005-08-30 05:11:41 +08:00
2005-08-02 03:09:07 +08:00
# Fail silently when a variable is not found in the current context
' basic-syntax04 ' : ( " as {{ missing }}df " , { } , " asdf " ) ,
2005-08-30 05:11:41 +08:00
2005-08-02 03:09:07 +08:00
# A variable may not contain more than one word
' basic-syntax06 ' : ( " {{ multi word variable }} " , { } , template . TemplateSyntaxError ) ,
2005-08-30 05:11:41 +08:00
2005-08-02 03:09:07 +08:00
# Raise TemplateSyntaxError for empty variable tags
' basic-syntax07 ' : ( " {{ }} " , { } , template . TemplateSyntaxError ) ,
' basic-syntax08 ' : ( " {{ }} " , { } , template . TemplateSyntaxError ) ,
2005-08-30 05:11:41 +08:00
2005-08-02 03:09:07 +08:00
# Attribute syntax allows a template to call an object's attribute
' basic-syntax09 ' : ( " {{ var.method }} " , { " var " : SomeClass ( ) } , " SomeClass.method " ) ,
2005-08-30 05:11:41 +08:00
2005-08-02 03:09:07 +08:00
# Multiple levels of attribute access are allowed
' basic-syntax10 ' : ( " {{ var.otherclass.method }} " , { " var " : SomeClass ( ) } , " OtherClass.method " ) ,
2005-08-30 05:11:41 +08:00
2005-08-02 03:09:07 +08:00
# Fail silently when a variable's attribute isn't found
' basic-syntax11 ' : ( " {{ var.blech }} " , { " var " : SomeClass ( ) } , " " ) ,
2005-08-30 05:11:41 +08:00
2005-08-02 03:09:07 +08:00
# Raise TemplateSyntaxError when trying to access a variable beginning with an underscore
' basic-syntax12 ' : ( " {{ var.__dict__ }} " , { " var " : SomeClass ( ) } , template . TemplateSyntaxError ) ,
2005-08-30 05:11:41 +08:00
2005-08-02 03:09:07 +08:00
# Raise TemplateSyntaxError when trying to access a variable containing an illegal character
' basic-syntax13 ' : ( " {{ va>r }} " , { } , template . TemplateSyntaxError ) ,
' basic-syntax14 ' : ( " {{ (var.r) }} " , { } , template . TemplateSyntaxError ) ,
' basic-syntax15 ' : ( " {{ sp %a m }} " , { } , template . TemplateSyntaxError ) ,
' basic-syntax16 ' : ( " {{ eggs! }} " , { } , template . TemplateSyntaxError ) ,
' basic-syntax17 ' : ( " {{ moo? }} " , { } , template . TemplateSyntaxError ) ,
2005-08-30 05:11:41 +08:00
2005-08-02 03:09:07 +08:00
# Attribute syntax allows a template to call a dictionary key's value
' basic-syntax18 ' : ( " {{ foo.bar }} " , { " foo " : { " bar " : " baz " } } , " baz " ) ,
2005-08-30 05:11:41 +08:00
2005-08-02 03:09:07 +08:00
# Fail silently when a variable's dictionary key isn't found
' basic-syntax19 ' : ( " {{ foo.spam }} " , { " foo " : { " bar " : " baz " } } , " " ) ,
2005-08-30 05:11:41 +08:00
2005-08-02 03:09:07 +08:00
# Fail silently when accessing a non-simple method
' basic-syntax20 ' : ( " {{ var.method2 }} " , { " var " : SomeClass ( ) } , " " ) ,
2005-08-30 05:11:41 +08:00
2005-08-02 03:09:07 +08:00
# Basic filter usage
' basic-syntax21 ' : ( " {{ var|upper }} " , { " var " : " Django is the greatest! " } , " DJANGO IS THE GREATEST! " ) ,
2005-08-30 05:11:41 +08:00
2005-08-02 03:09:07 +08:00
# Chained filters
' basic-syntax22 ' : ( " {{ var|upper|lower }} " , { " var " : " Django is the greatest! " } , " django is the greatest! " ) ,
2005-08-30 05:11:41 +08:00
2005-08-02 03:09:07 +08:00
# Raise TemplateSyntaxError for space between a variable and filter pipe
' basic-syntax23 ' : ( " {{ var |upper }} " , { } , template . TemplateSyntaxError ) ,
2005-08-30 05:11:41 +08:00
2005-08-02 03:09:07 +08:00
# Raise TemplateSyntaxError for space after a filter pipe
' basic-syntax24 ' : ( " {{ var| upper }} " , { } , template . TemplateSyntaxError ) ,
2005-08-30 05:11:41 +08:00
2005-08-02 03:09:07 +08:00
# Raise TemplateSyntaxError for a nonexistent filter
' basic-syntax25 ' : ( " {{ var|does_not_exist }} " , { } , template . TemplateSyntaxError ) ,
2005-08-30 05:11:41 +08:00
2005-08-02 03:09:07 +08:00
# Raise TemplateSyntaxError when trying to access a filter containing an illegal character
' basic-syntax26 ' : ( " {{ var|fil(ter) }} " , { } , template . TemplateSyntaxError ) ,
2005-08-30 05:11:41 +08:00
2005-08-02 03:09:07 +08:00
# Raise TemplateSyntaxError for invalid block tags
' basic-syntax27 ' : ( " { % nothing_to_see_here % } " , { } , template . TemplateSyntaxError ) ,
2005-08-30 05:11:41 +08:00
2005-08-02 03:09:07 +08:00
# Raise TemplateSyntaxError for empty block tags
' basic-syntax28 ' : ( " { % % } " , { } , template . TemplateSyntaxError ) ,
2005-08-30 05:11:41 +08:00
2005-09-11 23:18:04 +08:00
# Chained filters, with an argument to the first one
' basic-syntax29 ' : ( ' {{ var|removetags: " b i " |upper|lower }} ' , { " var " : " <b><i>Yes</i></b> " } , " yes " ) ,
2005-08-30 05:11:41 +08:00
### IF TAG ################################################################
' if-tag01 ' : ( " { % i f foo % }yes { % e lse % }no { % e ndif % } " , { " foo " : True } , " yes " ) ,
' if-tag02 ' : ( " { % i f foo % }yes { % e lse % }no { % e ndif % } " , { " foo " : False } , " no " ) ,
' if-tag03 ' : ( " { % i f foo % }yes { % e lse % }no { % e ndif % } " , { } , " no " ) ,
### COMMENT TAG ###########################################################
' comment-tag01 ' : ( " { % c omment % }this is hidden { % e ndcomment % }hello " , { } , " hello " ) ,
' comment-tag02 ' : ( " { % c omment % }this is hidden { % e ndcomment % }hello { % c omment % }foo { % e ndcomment % } " , { } , " hello " ) ,
### FOR TAG ###############################################################
' for-tag01 ' : ( " { % f or val in values % } {{ val }} { % e ndfor % } " , { " values " : [ 1 , 2 , 3 ] } , " 123 " ) ,
' for-tag02 ' : ( " { % f or val in values reversed % } {{ val }} { % e ndfor % } " , { " values " : [ 1 , 2 , 3 ] } , " 321 " ) ,
2005-09-30 07:34:29 +08:00
' for-tag-vars01 ' : ( " { % f or val in values % } {{ forloop.counter }} { % e ndfor % } " , { " values " : [ 6 , 6 , 6 ] } , " 123 " ) ,
' for-tag-vars02 ' : ( " { % f or val in values % } {{ forloop.counter0 }} { % e ndfor % } " , { " values " : [ 6 , 6 , 6 ] } , " 012 " ) ,
' for-tag-vars03 ' : ( " { % f or val in values % } {{ forloop.revcounter }} { % e ndfor % } " , { " values " : [ 6 , 6 , 6 ] } , " 321 " ) ,
' for-tag-vars04 ' : ( " { % f or val in values % } {{ forloop.revcounter0 }} { % e ndfor % } " , { " values " : [ 6 , 6 , 6 ] } , " 210 " ) ,
2005-08-30 05:11:41 +08:00
### IFEQUAL TAG ###########################################################
' ifequal01 ' : ( " { % i fequal a b % }yes { % e ndifequal % } " , { " a " : 1 , " b " : 2 } , " " ) ,
' ifequal02 ' : ( " { % i fequal a b % }yes { % e ndifequal % } " , { " a " : 1 , " b " : 1 } , " yes " ) ,
' ifequal03 ' : ( " { % i fequal a b % }yes { % e lse % }no { % e ndifequal % } " , { " a " : 1 , " b " : 2 } , " no " ) ,
' ifequal04 ' : ( " { % i fequal a b % }yes { % e lse % }no { % e ndifequal % } " , { " a " : 1 , " b " : 1 } , " yes " ) ,
2005-09-01 10:18:04 +08:00
' ifequal05 ' : ( " { % i fequal a ' test ' % }yes { % e lse % }no { % e ndifequal % } " , { " a " : " test " } , " yes " ) ,
' ifequal06 ' : ( " { % i fequal a ' test ' % }yes { % e lse % }no { % e ndifequal % } " , { " a " : " no " } , " no " ) ,
' ifequal07 ' : ( ' { % i fequal a " test " % }yes { % e lse % }no { % e ndifequal % } ' , { " a " : " test " } , " yes " ) ,
' ifequal08 ' : ( ' { % i fequal a " test " % }yes { % e lse % }no { % e ndifequal % } ' , { " a " : " no " } , " no " ) ,
' ifequal09 ' : ( ' { % i fequal a " test " % }yes { % e lse % }no { % e ndifequal % } ' , { } , " no " ) ,
' ifequal10 ' : ( ' { % i fequal a b % }yes { % e lse % }no { % e ndifequal % } ' , { } , " yes " ) ,
2005-08-30 05:11:41 +08:00
### IFNOTEQUAL TAG ########################################################
' ifnotequal01 ' : ( " { % i fnotequal a b % }yes { % e ndifnotequal % } " , { " a " : 1 , " b " : 2 } , " yes " ) ,
' ifnotequal02 ' : ( " { % i fnotequal a b % }yes { % e ndifnotequal % } " , { " a " : 1 , " b " : 1 } , " " ) ,
' ifnotequal03 ' : ( " { % i fnotequal a b % }yes { % e lse % }no { % e ndifnotequal % } " , { " a " : 1 , " b " : 2 } , " yes " ) ,
' ifnotequal04 ' : ( " { % i fnotequal a b % }yes { % e lse % }no { % e ndifnotequal % } " , { " a " : 1 , " b " : 1 } , " no " ) ,
2005-11-22 13:44:04 +08:00
### INCLUDE TAG ###########################################################
' include01 ' : ( ' { % i nclude " basic-syntax01 " % } ' , { } , " something cool " ) ,
' include02 ' : ( ' { % i nclude " basic-syntax02 " % } ' , { ' headline ' : ' Included ' } , " Included " ) ,
' include03 ' : ( ' { % i nclude template_name % } ' , { ' template_name ' : ' basic-syntax02 ' , ' headline ' : ' Included ' } , " Included " ) ,
' include04 ' : ( ' a { % i nclude " nonexistent " % }b ' , { } , " ab " ) ,
2005-08-30 05:11:41 +08:00
### INHERITANCE ###########################################################
2005-08-02 03:09:07 +08:00
# Standard template with no inheritance
' inheritance01 ' : ( " 1 { % block first % }_ { % e ndblock % }3 { % block second % }_ { % e ndblock % } " , { } , ' 1_3_ ' ) ,
# Standard two-level inheritance
' inheritance02 ' : ( " { % e xtends ' inheritance01 ' % } { % block first % }2 { % e ndblock % } { % block second % }4 { % e ndblock % } " , { } , ' 1234 ' ) ,
# Three-level with no redefinitions on third level
' inheritance03 ' : ( " { % e xtends ' inheritance02 ' % } " , { } , ' 1234 ' ) ,
# Two-level with no redefinitions on second level
' inheritance04 ' : ( " { % e xtends ' inheritance01 ' % } " , { } , ' 1_3_ ' ) ,
# Two-level with double quotes instead of single quotes
' inheritance05 ' : ( ' { % e xtends " inheritance02 " % } ' , { } , ' 1234 ' ) ,
# Three-level with variable parent-template name
' inheritance06 ' : ( " { % e xtends foo % } " , { ' foo ' : ' inheritance02 ' } , ' 1234 ' ) ,
# Two-level with one block defined, one block not defined
' inheritance07 ' : ( " { % e xtends ' inheritance01 ' % } { % block second % }5 { % e ndblock % } " , { } , ' 1_35 ' ) ,
# Three-level with one block defined on this level, two blocks defined next level
' inheritance08 ' : ( " { % e xtends ' inheritance02 ' % } { % block second % }5 { % e ndblock % } " , { } , ' 1235 ' ) ,
# Three-level with second and third levels blank
' inheritance09 ' : ( " { % e xtends ' inheritance04 ' % } " , { } , ' 1_3_ ' ) ,
# Three-level with space NOT in a block -- should be ignored
' inheritance10 ' : ( " { % e xtends ' inheritance04 ' % } " , { } , ' 1_3_ ' ) ,
# Three-level with both blocks defined on this level, but none on second level
' inheritance11 ' : ( " { % e xtends ' inheritance04 ' % } { % block first % }2 { % e ndblock % } { % block second % }4 { % e ndblock % } " , { } , ' 1234 ' ) ,
# Three-level with this level providing one and second level providing the other
' inheritance12 ' : ( " { % e xtends ' inheritance07 ' % } { % block first % }2 { % e ndblock % } " , { } , ' 1235 ' ) ,
# Three-level with this level overriding second level
' inheritance13 ' : ( " { % e xtends ' inheritance02 ' % } { % block first % }a { % e ndblock % } { % block second % }b { % e ndblock % } " , { } , ' 1a3b ' ) ,
# A block defined only in a child template shouldn't be displayed
' inheritance14 ' : ( " { % e xtends ' inheritance01 ' % } { % block newblock % }NO DISPLAY { % e ndblock % } " , { } , ' 1_3_ ' ) ,
# A block within another block
' inheritance15 ' : ( " { % e xtends ' inheritance01 ' % } { % block first % }2 { % block inner % }inner { % e ndblock % } { % e ndblock % } " , { } , ' 12inner3_ ' ) ,
# A block within another block (level 2)
' inheritance16 ' : ( " { % e xtends ' inheritance15 ' % } { % block inner % }out { % e ndblock % } " , { } , ' 12out3_ ' ) ,
# {% load %} tag (parent -- setup for exception04)
' inheritance17 ' : ( " { % lo ad testtags % } { % block first % }1234 { % e ndblock % } " , { } , ' 1234 ' ) ,
# {% load %} tag (standard usage, without inheritance)
' inheritance18 ' : ( " { % lo ad testtags % } { % e cho this that theother % }5678 " , { } , ' this that theother5678 ' ) ,
# {% load %} tag (within a child template)
' inheritance19 ' : ( " { % e xtends ' inheritance01 ' % } { % block first % } { % lo ad testtags % } { % e cho 400 % }5678 { % e ndblock % } " , { } , ' 140056783_ ' ) ,
2005-09-29 12:22:09 +08:00
# Two-level inheritance with {{ block.super }}
' inheritance20 ' : ( " { % e xtends ' inheritance01 ' % } { % block first % } {{ block.super }}a { % e ndblock % } " , { } , ' 1_a3_ ' ) ,
# Three-level inheritance with {{ block.super }} from parent
' inheritance21 ' : ( " { % e xtends ' inheritance02 ' % } { % block first % } {{ block.super }}a { % e ndblock % } " , { } , ' 12a34 ' ) ,
# Three-level inheritance with {{ block.super }} from grandparent
' inheritance22 ' : ( " { % e xtends ' inheritance04 ' % } { % block first % } {{ block.super }}a { % e ndblock % } " , { } , ' 1_a3_ ' ) ,
# Three-level inheritance with {{ block.super }} from parent and grandparent
' inheritance23 ' : ( " { % e xtends ' inheritance20 ' % } { % block first % } {{ block.super }}b { % e ndblock % } " , { } , ' 1_ab3_ ' ) ,
2005-08-30 05:11:41 +08:00
### EXCEPTIONS ############################################################
2005-08-02 03:09:07 +08:00
# Raise exception for invalid template name
' exception01 ' : ( " { % e xtends ' nonexistent ' % } " , { } , template . TemplateSyntaxError ) ,
# Raise exception for invalid template name (in variable)
' exception02 ' : ( " { % e xtends nonexistent % } " , { } , template . TemplateSyntaxError ) ,
# Raise exception for extra {% extends %} tags
' exception03 ' : ( " { % e xtends ' inheritance01 ' % } { % block first % }2 { % e ndblock % } { % e xtends ' inheritance16 ' % } " , { } , template . TemplateSyntaxError ) ,
# Raise exception for custom tags used in child with {% load %} tag in parent, not in child
' exception04 ' : ( " { % e xtends ' inheritance17 ' % } { % block first % } { % e cho 400 % }5678 { % e ndblock % } " , { } , template . TemplateSyntaxError ) ,
2005-11-04 12:59:46 +08:00
# simple translation of a string delimited by '
' i18n01 ' : ( " { % lo ad i18n % } { % trans ' xxxyyyxxx ' % } " , { } , " xxxyyyxxx " ) ,
# simple translation of a string delimited by "
' i18n02 ' : ( ' { % lo ad i18n % } { % trans " xxxyyyxxx " % } ' , { } , " xxxyyyxxx " ) ,
# simple translation of a variable
' i18n03 ' : ( ' { % lo ad i18n % } { % blocktrans % } {{ anton }} { % e ndblocktrans % } ' , { ' anton ' : ' xxxyyyxxx ' } , " xxxyyyxxx " ) ,
# simple translation of a variable and filter
' i18n04 ' : ( ' { % lo ad i18n % } { % blocktrans with anton|lower as berta % } {{ berta }} { % e ndblocktrans % } ' , { ' anton ' : ' XXXYYYXXX ' } , " xxxyyyxxx " ) ,
# simple translation of a string with interpolation
' i18n05 ' : ( ' { % lo ad i18n % } { % blocktrans % }xxx {{ anton }}xxx { % e ndblocktrans % } ' , { ' anton ' : ' yyy ' } , " xxxyyyxxx " ) ,
# simple translation of a string to german
' i18n06 ' : ( ' { % lo ad i18n % } { % trans " Page not found " % } ' , { ' LANGUAGE_CODE ' : ' de ' } , " Seite nicht gefunden " ) ,
# translation of singular form
' i18n07 ' : ( ' { % lo ad i18n % } { % blocktrans count number as counter % }singular { % plural % }plural { % e ndblocktrans % } ' , { ' number ' : 1 } , " singular " ) ,
# translation of plural form
' i18n08 ' : ( ' { % lo ad i18n % } { % blocktrans count number as counter % }singular { % plural % }plural { % e ndblocktrans % } ' , { ' number ' : 2 } , " plural " ) ,
# simple non-translation (only marking) of a string to german
' i18n09 ' : ( ' { % lo ad i18n % } { % trans " Page not found " noop % } ' , { ' LANGUAGE_CODE ' : ' de ' } , " Page not found " ) ,
# translation of a variable with a translated filter
' i18n10 ' : ( ' {{ bool|yesno:_( " ja,nein " ) }} ' , { ' bool ' : True } , ' ja ' ) ,
# translation of a variable with a non-translated filter
' i18n11 ' : ( ' {{ bool|yesno: " ja,nein " }} ' , { ' bool ' : True } , ' ja ' ) ,
# usage of the get_available_languages tag
' i18n12 ' : ( ' { % lo ad i18n % } { % g et_available_languages as langs % } { % f or lang in langs % } { % i fequal lang.0 " de " % } {{ lang.0 }} { % e ndifequal % } { % e ndfor % } ' , { } , ' de ' ) ,
# translation of a constant string
' i18n13 ' : ( ' {{ _( " Page not found " ) }} ' , { ' LANGUAGE_CODE ' : ' de ' } , ' Seite nicht gefunden ' ) ,
2005-08-02 03:09:07 +08:00
}
def test_template_loader ( template_name , template_dirs = None ) :
2005-10-15 06:28:38 +08:00
" A custom template loader that loads the unit-test templates. "
2005-08-02 03:09:07 +08:00
try :
return TEMPLATE_TESTS [ template_name ] [ 0 ]
except KeyError :
raise template . TemplateDoesNotExist , template_name
def run_tests ( verbosity = 0 , standalone = False ) :
2005-10-15 06:28:38 +08:00
# Register our custom template loader.
old_template_loaders = loader . template_source_loaders
loader . template_source_loaders = [ test_template_loader ]
2005-08-02 03:09:07 +08:00
failed_tests = [ ]
tests = TEMPLATE_TESTS . items ( )
tests . sort ( )
for name , vals in tests :
2005-11-17 23:55:04 +08:00
install ( )
2005-11-04 12:59:46 +08:00
if ' LANGUAGE_CODE ' in vals [ 1 ] :
activate ( vals [ 1 ] [ ' LANGUAGE_CODE ' ] )
2005-11-17 23:55:04 +08:00
else :
activate ( ' en-us ' )
2005-08-02 03:09:07 +08:00
try :
2005-10-15 04:10:13 +08:00
output = loader . get_template ( name ) . render ( template . Context ( vals [ 1 ] ) )
2005-08-02 03:09:07 +08:00
except Exception , e :
if e . __class__ == vals [ 2 ] :
if verbosity :
print " Template test: %s -- Passed " % name
else :
if verbosity :
2005-11-17 23:55:04 +08:00
traceback . print_exc ( )
2005-08-02 03:09:07 +08:00
print " Template test: %s -- FAILED. Got %s , exception: %s " % ( name , e . __class__ , e )
failed_tests . append ( name )
continue
2005-11-04 12:59:46 +08:00
if ' LANGUAGE_CODE ' in vals [ 1 ] :
deactivate ( )
2005-08-02 03:09:07 +08:00
if output == vals [ 2 ] :
if verbosity :
print " Template test: %s -- Passed " % name
else :
if verbosity :
print " Template test: %s -- FAILED. Expected %r , got %r " % ( name , vals [ 2 ] , output )
failed_tests . append ( name )
2005-10-15 06:28:38 +08:00
loader . template_source_loaders = old_template_loaders
2005-08-30 05:11:41 +08:00
2005-08-02 03:09:07 +08:00
if failed_tests and not standalone :
msg = " Template tests %s failed. " % failed_tests
if not verbosity :
msg + = " Re-run tests with -v1 to see actual failures "
raise Exception , msg
2005-08-30 05:11:41 +08:00
2005-08-02 03:09:07 +08:00
if __name__ == " __main__ " :
run_tests ( 1 , True )