Ticket #2333: revised-tests.patch

File revised-tests.patch, 164.4 KB (added by Russell Keith-Magee, 18 years ago)

Combined version of previous patches to tests directory, with some minor revisions and cleanup

  • tests/modeltests/basic/models.py

     
    1313    def __str__(self):
    1414        return self.headline
    1515
    16 API_TESTS = """
    17 
     16__test__ = {'API_TESTS': """
    1817# No articles are in the system yet.
    1918>>> Article.objects.all()
    2019[]
     
    314313>>> Article.objects.all()
    315314[<Article: Article 6>, <Article: Default headline>, <Article: Article 7>, <Article: Updated article 8>]
    316315
    317 """
     316"""}
    318317
    319318from django.conf import settings
    320319
    321320building_docs = getattr(settings, 'BUILDING_DOCS', False)
    322321
    323322if building_docs or settings.DATABASE_ENGINE == 'postgresql':
    324     API_TESTS += """
     323    __test__['API_TESTS'] += """
    325324# In PostgreSQL, microsecond-level precision is available.
    326325>>> a9 = Article(headline='Article 9', pub_date=datetime(2005, 7, 31, 12, 30, 45, 180))
    327326>>> a9.save()
     
    330329"""
    331330
    332331if building_docs or settings.DATABASE_ENGINE == 'mysql':
    333     API_TESTS += """
     332    __test__['API_TESTS'] += """
    334333# In MySQL, microsecond-level precision isn't available. You'll lose
    335334# microsecond-level precision once the data is saved.
    336335>>> a9 = Article(headline='Article 9', pub_date=datetime(2005, 7, 31, 12, 30, 45, 180))
     
    339338datetime.datetime(2005, 7, 31, 12, 30, 45)
    340339"""
    341340
    342 API_TESTS += """
     341__test__['API_TESTS'] += """
    343342
    344343# You can manually specify the primary key when creating a new object.
    345344>>> a101 = Article(id=101, headline='Article 101', pub_date=datetime(2005, 7, 31, 12, 30, 45))
  • tests/modeltests/m2m_recursive/models.py

     
    2222    def __str__(self):
    2323        return self.name
    2424
    25 API_TESTS = """
     25__test__ = {'API_TESTS':"""
    2626>>> a = Person(name='Anne')
    2727>>> a.save()
    2828>>> b = Person(name='Bill')
     
    189189>>> d.stalkers.all()
    190190[<Person: Chuck>]
    191191
    192 """
     192"""}
  • tests/modeltests/one_to_one/models.py

     
    3030    def __str__(self):
    3131        return "%s the waiter at %s" % (self.name, self.restaurant)
    3232
    33 API_TESTS = """
     33__test__ = {'API_TESTS':"""
    3434# Create a couple of Places.
    3535>>> p1 = Place(name='Demon Dogs', address='944 W. Fullerton')
    3636>>> p1.save()
     
    151151# Delete the restaurant; the waiter should also be removed
    152152>>> r = Restaurant.objects.get(pk=1)
    153153>>> r.delete()
    154 """
     154"""}
  • tests/modeltests/m2o_recursive/models.py

     
    1919    def __str__(self):
    2020        return self.name
    2121
    22 API_TESTS = """
     22__test__ = {'API_TESTS':"""
    2323# Create a few Category objects.
    2424>>> r = Category(id=None, name='Root category', parent=None)
    2525>>> r.save()
     
    3737[]
    3838>>> c.parent
    3939<Category: Root category>
    40 """
     40"""}
  • tests/modeltests/custom_managers/models.py

     
    5858    def __str__(self):
    5959        return self.name
    6060
    61 API_TESTS = """
     61__test__ = {'API_TESTS':"""
    6262>>> p1 = Person(first_name='Bugs', last_name='Bunny', fun=True)
    6363>>> p1.save()
    6464>>> p2 = Person(first_name='Droopy', last_name='Dog', fun=False)
     
    104104# to the first manager defined in the class. In this case, it's "cars".
    105105>>> Car._default_manager.order_by('name')
    106106[<Car: Corvette>, <Car: Neon>]
    107 """
     107"""}
  • tests/modeltests/invalid_models/models.py

     
    7878
    7979
    8080
    81 error_log = """invalid_models.fielderrors: "charfield": CharFields require a "maxlength" attribute.
     81model_errors = """invalid_models.fielderrors: "charfield": CharFields require a "maxlength" attribute.
    8282invalid_models.fielderrors: "floatfield": FloatFields require a "decimal_places" attribute.
    8383invalid_models.fielderrors: "floatfield": FloatFields require a "max_digits" attribute.
    8484invalid_models.fielderrors: "filefield": FileFields require an "upload_to" attribute.
  • tests/modeltests/many_to_many/models.py

     
    2828    class Meta:
    2929        ordering = ('headline',)
    3030
    31 API_TESTS = """
     31__test__ = {'API_TESTS':"""
    3232# Create a couple of Publications.
    3333>>> p1 = Publication(id=None, title='The Python Journal')
    3434>>> p1.save()
     
    231231>>> p1.article_set.all()
    232232[<Article: NASA uses Python>]
    233233
    234 """
     234"""}
  • tests/modeltests/m2m_and_m2o/models.py

     
    2121        ordering = ('num',)
    2222
    2323
    24 API_TESTS = """
     24__test__ = {'API_TESTS':"""
    2525>>> Issue.objects.all()
    2626[]
    2727>>> r = User(username='russell')
     
    6262[<Issue: 1>, <Issue: 2>, <Issue: 3>]
    6363>>> Issue.objects.filter(Q(client=r.id) | Q(cc__id__exact=r.id))
    6464[<Issue: 1>, <Issue: 2>, <Issue: 3>]
    65 """
     65"""}
  • tests/modeltests/validation/models.py

     
    2020    def __str__(self):
    2121        return self.name
    2222
    23 API_TESTS = """
     23__test__ = {'API_TESTS':"""
    2424
    2525>>> import datetime
    2626>>> valid_params = {
     
    146146>>> p.validate()
    147147{'email': ['Enter a valid e-mail address.']}
    148148
    149 """
     149"""}
  • tests/modeltests/or_lookups/models.py

     
    2323    def __str__(self):
    2424        return self.headline
    2525
    26 API_TESTS = """
     26__test__ = {'API_TESTS':"""
    2727>>> from datetime import datetime
    2828>>> from django.db.models import Q
    2929
     
    101101[<Article: Hello>]
    102102>>> Article.objects.complex_filter(Q(pk=1) | Q(pk=2))
    103103[<Article: Hello>, <Article: Goodbye>]
    104 """
     104"""}
  • tests/modeltests/mutually_referential/models.py

     
    1414    name = CharField(maxlength=100)
    1515    parent = ForeignKey(Parent)
    1616
    17 API_TESTS = """
     17__test__ = {'API_TESTS':"""
    1818# Create a Parent
    1919>>> q = Parent(name='Elizabeth')
    2020>>> q.save()
     
    2929
    3030>>> q.delete()
    3131
    32 """
    33  No newline at end of file
     32"""}
     33 No newline at end of file
  • tests/modeltests/custom_methods/models.py

     
    3636        # positional arguments to Article().
    3737        return [self.__class__(*row) for row in cursor.fetchall()]
    3838
    39 API_TESTS = """
     39__test__ = {'API_TESTS':"""
    4040# Create a couple of Articles.
    4141>>> from datetime import date
    4242>>> a = Article(id=None, headline='Area man programs in Python', pub_date=date(2005, 7, 27))
     
    5555[<Article: Area man programs in Python>]
    5656>>> b.articles_from_same_day_2()
    5757[<Article: Area man programs in Python>]
    58 """
     58"""}
  • tests/modeltests/empty/models.py

     
    1010class Empty(models.Model):
    1111    pass
    1212
    13 API_TESTS = """
     13__test__ = {'API_TESTS':"""
    1414>>> m = Empty()
    1515>>> m.id
    1616>>> m.save()
     
    2323>>> existing = Empty(m.id)
    2424>>> existing.save()
    2525
    26 """
     26"""}
  • tests/modeltests/many_to_one_null/models.py

     
    2323    def __str__(self):
    2424        return self.headline
    2525
    26 API_TESTS = """
     26__test__ = {'API_TESTS':"""
    2727# Create a Reporter.
    2828>>> r = Reporter(name='John Smith')
    2929>>> r.save()
     
    121121>>> Article.objects.filter(reporter__isnull=True)
    122122[<Article: First>, <Article: Fourth>]
    123123
    124 """
     124"""}
  • tests/modeltests/get_or_create/models.py

     
    1515    def __str__(self):
    1616        return '%s %s' % (self.first_name, self.last_name)
    1717
    18 API_TESTS = """
     18__test__ = {'API_TESTS':"""
    1919# Acting as a divine being, create an Person.
    2020>>> from datetime import date
    2121>>> p = Person(first_name='John', last_name='Lennon', birthday=date(1940, 10, 9))
     
    4949False
    5050>>> Person.objects.count()
    51512
    52 """
     52"""}
  • tests/modeltests/custom_pk/models.py

     
    2727    def __str__(self):
    2828        return self.name
    2929
    30 API_TESTS = """
     30__test__ = {'API_TESTS':"""
    3131>>> dan = Employee(employee_code='ABC123', first_name='Dan', last_name='Jones')
    3232>>> dan.save()
    3333>>> Employee.objects.all()
     
    8888>>> Business.objects.filter(employees__first_name__startswith='Fran')
    8989[<Business: Sears>]
    9090
    91 """
     91"""}
  • tests/modeltests/reverse_lookup/models.py

     
    2727    def __str(self):
    2828        return self.name
    2929
    30 API_TESTS = """
     30__test__ = {'API_TESTS':"""
    3131>>> john = User(name="John Doe")
    3232>>> john.save()
    3333>>> jim = User(name="Jim Bo")
     
    5656Traceback (most recent call last):
    5757    ...
    5858TypeError: Cannot resolve keyword 'choice' into field
    59 """
     59"""}
  • tests/modeltests/m2o_recursive2/models.py

     
    1717    def __str__(self):
    1818        return self.full_name
    1919
    20 API_TESTS = """
     20__test__ = {'API_TESTS':"""
    2121# Create two Person objects -- the mom and dad in our family.
    2222>>> dad = Person(full_name='John Smith Senior', mother=None, father=None)
    2323>>> dad.save()
     
    4040[]
    4141>>> kid.fathers_child_set.all()
    4242[]
    43 """
     43"""}
  • tests/modeltests/m2m_multiple/models.py

     
    2828    def __str__(self):
    2929        return self.headline
    3030
    31 API_TESTS = """
     31__test__ = {'API_TESTS':"""
    3232>>> from datetime import datetime
    3333
    3434>>> c1 = Category(name='Sports')
     
    7676[]
    7777>>> c4.secondary_article_set.all()
    7878[<Article: Area man steals>, <Article: Area man runs>]
    79 """
     79"""}
  • tests/modeltests/m2m_intermediary/models.py

     
    3434    def __str__(self):
    3535        return '%s (%s)' % (self.reporter, self.position)
    3636
    37 API_TESTS = """
     37__test__ = {'API_TESTS':"""
    3838# Create a few Reporters.
    3939>>> r1 = Reporter(first_name='John', last_name='Smith')
    4040>>> r1.save()
     
    6565<Article: This is a test>
    6666>>> r1.writer_set.all()
    6767[<Writer: John Smith (Main writer)>]
    68 """
     68"""}
  • tests/modeltests/str/models.py

     
    1717    def __str__(self):
    1818        return self.headline
    1919
    20 API_TESTS = """
     20__test__ = {'API_TESTS':"""
    2121# Create an Article.
    2222>>> from datetime import datetime
    2323>>> a = Article(headline='Area man programs in Python', pub_date=datetime(2005, 7, 28))
     
    2828
    2929>>> a
    3030<Article: Area man programs in Python>
    31 """
     31"""}
  • tests/modeltests/transactions/models.py

     
    1717    def __str__(self):
    1818        return "%s %s" % (self.first_name, self.last_name)
    1919
    20 API_TESTS = """
     20__test__ = {'API_TESTS':"""
    2121>>> from django.db import connection, transaction
    22 """
     22"""}
    2323
    2424from django.conf import settings
    2525
    2626building_docs = getattr(settings, 'BUILDING_DOCS', False)
    2727
    2828if building_docs or settings.DATABASE_ENGINE != 'mysql':
    29     API_TESTS += """
     29    __test__['API_TESTS'] += """
    3030# the default behavior is to autocommit after each save() action
    3131>>> def create_a_reporter_then_fail(first, last):
    3232...     a = Reporter(first_name=first, last_name=last)
  • tests/modeltests/model_inheritance/models.py

     
    2626    def __str__(self):
    2727        return "%s the italian restaurant" % self.name
    2828
    29 API_TESTS = """
     29__test__ = {'API_TESTS':"""
    3030# Make sure Restaurant has the right fields in the right order.
    3131>>> [f.name for f in Restaurant._meta.fields]
    3232['id', 'name', 'address', 'serves_hot_dogs', 'serves_pizza']
     
    5050>>> ir.save()
    5151
    5252
    53 """
     53"""}
  • tests/modeltests/lookup/models.py

     
    1515    def __str__(self):
    1616        return self.headline
    1717
    18 API_TESTS = """
     18__test__ = {'API_TESTS':"""
    1919# Create a couple of Articles.
    2020>>> from datetime import datetime
    2121>>> a1 = Article(headline='Article 1', pub_date=datetime(2005, 7, 26))
     
    182182[<Article: Article% with percent sign>, <Article: Article 5>, <Article: Article 6>, <Article: Article 4>, <Article: Article 2>, <Article: Article 3>, <Article: Article 7>, <Article: Article 1>]
    183183>>> Article.objects.exclude(headline="Article 7")
    184184[<Article: Article% with percent sign>, <Article: Article_ with underscore>, <Article: Article 5>, <Article: Article 6>, <Article: Article 4>, <Article: Article 2>, <Article: Article 3>, <Article: Article 1>]
    185 """
     185"""}
  • tests/modeltests/choices/models.py

     
    2323    def __str__(self):
    2424        return self.name
    2525
    26 API_TESTS = """
     26__test__ = {'API_TESTS':"""
    2727>>> a = Person(name='Adrian', gender='M')
    2828>>> a.save()
    2929>>> s = Person(name='Sara', gender='F')
     
    3636'Male'
    3737>>> s.get_gender_display()
    3838'Female'
    39 """
     39"""}
  • tests/modeltests/save_delete_hooks/models.py

     
    2424        super(Person, self).delete() # Call the "real" delete() method
    2525        print "After deletion"
    2626
    27 API_TESTS = """
     27__test__ = {'API_TESTS':"""
    2828>>> p1 = Person(first_name='John', last_name='Smith')
    2929>>> p1.save()
    3030Before save
     
    3939
    4040>>> Person.objects.all()
    4141[]
    42 """
     42"""}
  • tests/modeltests/pagination/models.py

     
    1515    def __str__(self):
    1616        return self.headline
    1717
    18 API_TESTS = """
     18__test__ = {'API_TESTS':"""
    1919# prepare a list of objects for pagination
    2020>>> from datetime import datetime
    2121>>> for x in range(1, 10):
     
    6464>>> paginator.last_on_page(1)
    65659
    6666
    67 """
     67"""}
  • tests/modeltests/get_latest/models.py

     
    2929    def __str__(self):
    3030        return self.name
    3131
    32 API_TESTS = """
     32__test__ = {'API_TESTS':"""
    3333# Because no Articles exist yet, get_latest() raises ArticleDoesNotExist.
    3434>>> Article.objects.latest()
    3535Traceback (most recent call last):
     
    7676
    7777>>> Person.objects.latest('birthday')
    7878<Person: Stephanie>
    79 """
     79"""}
  • tests/modeltests/properties/models.py

     
    2020
    2121    full_name_2 = property(_get_full_name, _set_full_name)
    2222
    23 API_TESTS = """
     23__test__ = {'API_TESTS':"""
    2424>>> a = Person(first_name='John', last_name='Lennon')
    2525>>> a.save()
    2626>>> a.full_name
     
    3737>>> a2.save()
    3838>>> a2.first_name
    3939'Paul'
    40 """
     40"""}
  • tests/modeltests/generic_relations/models.py

     
    5353    def __str__(self):
    5454        return self.name
    5555       
    56 API_TESTS = """
     56__test__ = {'API_TESTS':"""
    5757# Create the world in 7 lines of code...
    5858>>> lion = Animal(common_name="Lion", latin_name="Panthera leo")
    5959>>> platypus = Animal(common_name="Platypus", latin_name="Ornithorhynchus anatinus")
     
    105105[<TaggedItem: shiny>]
    106106>>> TaggedItem.objects.filter(content_type__pk=ctype.id, object_id=quartz.id)
    107107[<TaggedItem: clearish>]
    108 """
     108"""}
  • tests/modeltests/serializers/models.py

     
    3737    def __str__(self):
    3838        return self.headline
    3939
    40 API_TESTS = """
     40__test__ = {'API_TESTS':"""
    4141# Create some data:
    4242>>> from datetime import datetime
    4343>>> sports = Category(name="Sports")
     
    118118>>> Article.objects.all()
    119119[<Article: Just kidding; I love TV poker>, <Article: Time to reform copyright>]
    120120
    121 """
     121"""}
  • tests/modeltests/reserved_names/models.py

     
    2424    def __str__(self):
    2525        return self.when
    2626
    27 API_TESTS = """
     27__test__ = {'API_TESTS':"""
    2828>>> import datetime
    2929>>> day1 = datetime.date(2005, 1, 1)
    3030>>> day2 = datetime.date(2006, 2, 2)
     
    5353
    5454>>> Thing.objects.filter(where__month=1)
    5555[<Thing: a>]
    56 """
     56"""}
  • tests/modeltests/many_to_one/models.py

     
    2525    class Meta:
    2626        ordering = ('headline',)
    2727
    28 API_TESTS = """
     28__test__ = {'API_TESTS':"""
    2929# Create a few Reporters.
    3030>>> r = Reporter(first_name='John', last_name='Smith', email='john@example.com')
    3131>>> r.save()
     
    263263>>> Article.objects.all()
    264264[]
    265265
    266 """
     266"""}
  • tests/modeltests/ordering/models.py

     
    2424    def __str__(self):
    2525        return self.headline
    2626
    27 API_TESTS = """
     27__test__ = {'API_TESTS':"""
    2828# Create a couple of Articles.
    2929>>> from datetime import datetime
    3030>>> a1 = Article(headline='Article 1', pub_date=datetime(2005, 7, 26))
     
    6464# don't know what order the output will be in.
    6565>>> Article.objects.order_by('?')
    6666[...]
    67 """
     67"""}
  • tests/modeltests/custom_columns/models.py

     
    1515    def __str__(self):
    1616        return '%s %s' % (self.first_name, self.last_name)
    1717
    18 API_TESTS = """
     18__test__ = {'API_TESTS':"""
    1919# Create a Person.
    2020>>> p = Person(first_name='John', last_name='Smith')
    2121>>> p.save()
     
    5050Traceback (most recent call last):
    5151    ...
    5252AttributeError: 'Person' object has no attribute 'last'
    53 """
     53"""}
  • tests/modeltests/field_defaults/models.py

     
    1919    def __str__(self):
    2020        return self.headline
    2121
    22 API_TESTS = """
     22__test__ = {'API_TESTS':"""
    2323>>> from datetime import datetime
    2424
    2525# No articles are in the system yet.
     
    4848>>> d = now - a.pub_date
    4949>>> d.seconds < 5
    5050True
    51 """
     51"""}
  • tests/modeltests/manipulators/models.py

     
    2121    def __str__(self):
    2222        return self.name
    2323
    24 API_TESTS = """
     24__test__ = {'API_TESTS':"""
    2525>>> from django.utils.datastructures import MultiValueDict
    2626
    2727# Create a Musician object via the default AddManipulator.
     
    8888<Album: Ultimate Ella>
    8989>>> a2.release_date
    9090datetime.date(2005, 2, 13)
    91 """
     91"""}
  • tests/regressiontests/string_lookup/models.py

     
    3434    def __str__(self):
    3535        return "Base %s" % self.name
    3636
    37 API_TESTS = """
     37__test__ = {'API_TESTS':"""
    3838# Regression test for #1661 and #1662: Check that string form referencing of models works,
    3939# both as pre and post reference, on all RelatedField types.
    4040
     
    6666
    6767>>> child1.parent
    6868<Base: Base Base1>
    69 """
     69"""}
  • tests/regressiontests/markup/tests.py

     
     1# Quick tests for the markup templatetags (django.contrib.markup)
     2
     3from django.template import Template, Context, add_to_builtins
     4import re
     5import unittest
     6
     7add_to_builtins('django.contrib.markup.templatetags.markup')
     8
     9class Templates(unittest.TestCase):
     10    def test_textile(self):
     11        try:
     12            import textile
     13        except ImportError:
     14            textile = None
     15
     16        ### test textile
     17       
     18        textile_content = """Paragraph 1
     19
     20Paragraph 2 with "quotes" and @code@"""
     21       
     22        t = Template("{{ textile_content|textile }}")
     23        rendered = t.render(Context(locals())).strip()
     24        if textile:
     25            self.assertEqual(rendered,"""<p>Paragraph 1</p>
     26
     27<p>Paragraph 2 with &#8220;quotes&#8221; and <code>code</code></p>""")
     28        else:
     29            self.assertEqual(rendered, textile_content)
     30
     31    def test_markdown(self):
     32        try:
     33            import markdown
     34        except ImportError:
     35            markdown = None
     36       
     37        ### test markdown
     38       
     39        markdown_content = """Paragraph 1
     40
     41## An h2"""
     42       
     43        t = Template("{{ markdown_content|markdown }}")
     44        rendered = t.render(Context(locals())).strip()
     45        if markdown:
     46            pattern = re.compile("""<p>Paragraph 1\s*</p>\s*<h2>\s*An h2</h2>""")
     47            self.assert_(pattern.match(rendered))
     48        else:
     49            self.assertEqual(rendered, markdown_content)
     50
     51    def test_rest(self):
     52        try:
     53            import docutils
     54        except ImportError:
     55            docutils = None
     56       
     57        ### test rest
     58       
     59        rest_content = """Paragraph 1
     60
     61Paragraph 2 with a link_
     62
     63.. _link: http://www.example.com/"""
     64       
     65        t = Template("{{ rest_content|restructuredtext }}")
     66        rendered = t.render(Context(locals())).strip()
     67        if docutils:
     68            self.assertEqual(rendered, """<p>Paragraph 1</p>
     69<p>Paragraph 2 with a <a class="reference" href="http://www.example.com/">link</a></p>""")
     70        else:
     71            self.assertEqual(rendered, rest_content)
     72           
     73if __name__ == '__main__':
     74    unittest.main()
  • tests/regressiontests/many_to_one_regress/models.py

     
    1010# created (the field names being lower-cased versions of their opposite
    1111# classes is important here).
    1212
    13 API_TESTS = ""
     13__test__ = {'API_TESTS':""}
  • tests/regressiontests/initial_sql_regress/models.py

     
    77class Simple(models.Model):
    88    name = models.CharField(maxlength = 50)
    99
    10 API_TESTS = ""
     10__test__ = {'API_TESTS':""}
    1111
    1212# NOTE: The format of the included SQL file for this test suite is important.
    1313# It must end with a trailing newline in order to test the fix for #2161.
  • tests/regressiontests/cache/tests.py

     
     1# Unit tests for cache framework
     2# Uses whatever cache backend is set in the test settings file.
     3
     4from django.core.cache import cache
     5import time, unittest
     6
     7# functions/classes for complex data type tests       
     8def f():
     9    return 42
     10class C:
     11    def m(n):
     12        return 24
     13
     14class Cache(unittest.TestCase):
     15    def test_simple(self):
     16        # simple set/get
     17        cache.set("key", "value")
     18        self.assertEqual(cache.get("key"), "value")
     19       
     20    def test_non_existent(self):
     21        # get with non-existent keys
     22        self.assertEqual(cache.get("does not exist"), None)
     23        self.assertEqual(cache.get("does not exist", "bang!"), "bang!")
     24       
     25    def test_get_many(self):
     26        # get_many
     27        cache.set('a', 'a')
     28        cache.set('b', 'b')
     29        cache.set('c', 'c')
     30        cache.set('d', 'd')
     31       
     32        self.assertEqual(cache.get_many(['a', 'c', 'd']), {'a' : 'a', 'c' : 'c', 'd' : 'd'})
     33        self.assertEqual(cache.get_many(['a', 'b', 'e']), {'a' : 'a', 'b' : 'b'})
     34       
     35    def test_delete(self):
     36        # delete
     37        cache.set("key1", "spam")
     38        cache.set("key2", "eggs")
     39        self.assertEqual(cache.get("key1"), "spam")
     40        cache.delete("key1")
     41        self.assertEqual(cache.get("key1"), None)
     42        self.assertEqual(cache.get("key2"), "eggs")
     43       
     44    def test_has_key(self):
     45        # has_key
     46        cache.set("hello", "goodbye")
     47        self.assertEqual(cache.has_key("hello"), True)
     48        self.assertEqual(cache.has_key("goodbye"), False)
     49       
     50    def test_data_types(self):
     51        # test data types
     52        stuff = {
     53            'string'    : 'this is a string',
     54            'int'       : 42,
     55            'list'      : [1, 2, 3, 4],
     56            'tuple'     : (1, 2, 3, 4),
     57            'dict'      : {'A': 1, 'B' : 2},
     58            'function'  : f,
     59            'class'     : C,
     60        }
     61        for (key, value) in stuff.items():
     62            cache.set(key, value)
     63            self.assertEqual(cache.get(key), value)
     64           
     65        # expiration
     66        cache.set('expire', 'very quickly', 1)
     67        time.sleep(2)
     68        self.assertEqual(cache.get("expire"), None)
     69
     70if __name__ == '__main__':
     71    unittest.main()
     72 No newline at end of file
  • tests/regressiontests/httpwrappers/tests.py

     
     1"""
     2###################
     3# Empty QueryDict #
     4###################
     5
     6>>> q = QueryDict('')
     7
     8>>> q['foo']
     9Traceback (most recent call last):
     10...
     11MultiValueDictKeyError: "Key 'foo' not found in <MultiValueDict: {}>"
     12
     13>>> q['something'] = 'bar'
     14Traceback (most recent call last):
     15...
     16AttributeError: This QueryDict instance is immutable
     17
     18>>> q.get('foo', 'default')
     19'default'
     20
     21>>> q.getlist('foo')
     22[]
     23
     24>>> q.setlist('foo', ['bar', 'baz'])
     25Traceback (most recent call last):
     26...
     27AttributeError: This QueryDict instance is immutable
     28
     29>>> q.appendlist('foo', ['bar'])
     30Traceback (most recent call last):
     31...
     32AttributeError: This QueryDict instance is immutable
     33
     34>>> q.has_key('foo')
     35False
     36
     37>>> q.items()
     38[]
     39
     40>>> q.lists()
     41[]
     42
     43>>> q.keys()
     44[]
     45
     46>>> q.values()
     47[]
     48
     49>>> len(q)
     500
     51
     52>>> q.update({'foo': 'bar'})
     53Traceback (most recent call last):
     54...
     55AttributeError: This QueryDict instance is immutable
     56
     57>>> q.pop('foo')
     58Traceback (most recent call last):
     59...
     60AttributeError: This QueryDict instance is immutable
     61
     62>>> q.popitem()
     63Traceback (most recent call last):
     64...
     65AttributeError: This QueryDict instance is immutable
     66
     67>>> q.clear()
     68Traceback (most recent call last):
     69...
     70AttributeError: This QueryDict instance is immutable
     71
     72>>> q.setdefault('foo', 'bar')
     73Traceback (most recent call last):
     74...
     75AttributeError: This QueryDict instance is immutable
     76
     77>>> q.urlencode()
     78''
     79
     80###################################
     81# Mutable copy of empty QueryDict #
     82###################################
     83
     84>>> q = q.copy()
     85
     86>>> q['foo']
     87Traceback (most recent call last):
     88...
     89MultiValueDictKeyError: "Key 'foo' not found in <MultiValueDict: {}>"
     90
     91>>> q['name'] = 'john'
     92
     93>>> q['name']
     94'john'
     95
     96>>> q.get('foo', 'default')
     97'default'
     98
     99>>> q.get('name', 'default')
     100'john'
     101
     102>>> q.getlist('name')
     103['john']
     104
     105>>> q.getlist('foo')
     106[]
     107
     108>>> q.setlist('foo', ['bar', 'baz'])
     109
     110>>> q.get('foo', 'default')
     111'baz'
     112
     113>>> q.getlist('foo')
     114['bar', 'baz']
     115
     116>>> q.appendlist('foo', 'another')
     117
     118>>> q.getlist('foo')
     119['bar', 'baz', 'another']
     120
     121>>> q['foo']
     122'another'
     123
     124>>> q.has_key('foo')
     125True
     126
     127>>> q.items()
     128[('foo', 'another'), ('name', 'john')]
     129
     130>>> q.lists()
     131[('foo', ['bar', 'baz', 'another']), ('name', ['john'])]
     132
     133>>> q.keys()
     134['foo', 'name']
     135
     136>>> q.values()
     137['another', 'john']
     138
     139>>> len(q)
     1402
     141
     142>>> q.update({'foo': 'hello'})
     143
     144# Displays last value
     145>>> q['foo']
     146'hello'
     147
     148>>> q.get('foo', 'not available')
     149'hello'
     150
     151>>> q.getlist('foo')
     152['bar', 'baz', 'another', 'hello']
     153
     154>>> q.pop('foo')
     155['bar', 'baz', 'another', 'hello']
     156
     157>>> q.get('foo', 'not there')
     158'not there'
     159
     160>>> q.setdefault('foo', 'bar')
     161'bar'
     162
     163>>> q['foo']
     164'bar'
     165
     166>>> q.getlist('foo')
     167['bar']
     168
     169>>> q.urlencode()
     170'foo=bar&name=john'
     171
     172>>> q.clear()
     173
     174>>> len(q)
     1750
     176
     177#####################################
     178# QueryDict with one key/value pair #
     179#####################################
     180
     181>>> q = QueryDict('foo=bar')
     182
     183>>> q['foo']
     184'bar'
     185
     186>>> q['bar']
     187Traceback (most recent call last):
     188...
     189MultiValueDictKeyError: "Key 'bar' not found in <MultiValueDict: {'foo': ['bar']}>"
     190
     191>>> q['something'] = 'bar'
     192Traceback (most recent call last):
     193...
     194AttributeError: This QueryDict instance is immutable
     195
     196>>> q.get('foo', 'default')
     197'bar'
     198
     199>>> q.get('bar', 'default')
     200'default'
     201
     202>>> q.getlist('foo')
     203['bar']
     204
     205>>> q.getlist('bar')
     206[]
     207
     208>>> q.setlist('foo', ['bar', 'baz'])
     209Traceback (most recent call last):
     210...
     211AttributeError: This QueryDict instance is immutable
     212
     213>>> q.appendlist('foo', ['bar'])
     214Traceback (most recent call last):
     215...
     216AttributeError: This QueryDict instance is immutable
     217
     218>>> q.has_key('foo')
     219True
     220
     221>>> q.has_key('bar')
     222False
     223
     224>>> q.items()
     225[('foo', 'bar')]
     226
     227>>> q.lists()
     228[('foo', ['bar'])]
     229
     230>>> q.keys()
     231['foo']
     232
     233>>> q.values()
     234['bar']
     235
     236>>> len(q)
     2371
     238
     239>>> q.update({'foo': 'bar'})
     240Traceback (most recent call last):
     241...
     242AttributeError: This QueryDict instance is immutable
     243
     244>>> q.pop('foo')
     245Traceback (most recent call last):
     246...
     247AttributeError: This QueryDict instance is immutable
     248
     249>>> q.popitem()
     250Traceback (most recent call last):
     251...
     252AttributeError: This QueryDict instance is immutable
     253
     254>>> q.clear()
     255Traceback (most recent call last):
     256...
     257AttributeError: This QueryDict instance is immutable
     258
     259>>> q.setdefault('foo', 'bar')
     260Traceback (most recent call last):
     261...
     262AttributeError: This QueryDict instance is immutable
     263
     264>>> q.urlencode()
     265'foo=bar'
     266
     267#####################################################
     268# QueryDict with two key/value pairs with same keys #
     269#####################################################
     270
     271>>> q = QueryDict('vote=yes&vote=no')
     272
     273>>> q['vote']
     274'no'
     275
     276>>> q['something'] = 'bar'
     277Traceback (most recent call last):
     278...
     279AttributeError: This QueryDict instance is immutable
     280
     281>>> q.get('vote', 'default')
     282'no'
     283
     284>>> q.get('foo', 'default')
     285'default'
     286
     287>>> q.getlist('vote')
     288['yes', 'no']
     289
     290>>> q.getlist('foo')
     291[]
     292
     293>>> q.setlist('foo', ['bar', 'baz'])
     294Traceback (most recent call last):
     295...
     296AttributeError: This QueryDict instance is immutable
     297
     298>>> q.appendlist('foo', ['bar'])
     299Traceback (most recent call last):
     300...
     301AttributeError: This QueryDict instance is immutable
     302
     303>>> q.has_key('vote')
     304True
     305
     306>>> q.has_key('foo')
     307False
     308
     309>>> q.items()
     310[('vote', 'no')]
     311
     312>>> q.lists()
     313[('vote', ['yes', 'no'])]
     314
     315>>> q.keys()
     316['vote']
     317
     318>>> q.values()
     319['no']
     320
     321>>> len(q)
     3221
     323
     324>>> q.update({'foo': 'bar'})
     325Traceback (most recent call last):
     326...
     327AttributeError: This QueryDict instance is immutable
     328
     329>>> q.pop('foo')
     330Traceback (most recent call last):
     331...
     332AttributeError: This QueryDict instance is immutable
     333
     334>>> q.popitem()
     335Traceback (most recent call last):
     336...
     337AttributeError: This QueryDict instance is immutable
     338
     339>>> q.clear()
     340Traceback (most recent call last):
     341...
     342AttributeError: This QueryDict instance is immutable
     343
     344>>> q.setdefault('foo', 'bar')
     345Traceback (most recent call last):
     346...
     347AttributeError: This QueryDict instance is immutable
     348
     349>>> q.urlencode()
     350'vote=yes&vote=no'
     351
     352"""
     353
     354from django.http import QueryDict
     355
     356if __name__ == "__main__":
     357    import doctest
     358    doctest.testmod()
  • tests/regressiontests/db_typecasts/tests.py

     
     1# Unit tests for typecast functions in django.db.backends.util
     2
     3from django.db.backends import util as typecasts
     4import datetime, unittest
     5
     6TEST_CASES = {
     7    'typecast_date': (
     8        ('', None),
     9        (None, None),
     10        ('2005-08-11', datetime.date(2005, 8, 11)),
     11        ('1990-01-01', datetime.date(1990, 1, 1)),
     12    ),
     13    'typecast_time': (
     14        ('', None),
     15        (None, None),
     16        ('0:00:00', datetime.time(0, 0)),
     17        ('0:30:00', datetime.time(0, 30)),
     18        ('8:50:00', datetime.time(8, 50)),
     19        ('08:50:00', datetime.time(8, 50)),
     20        ('12:00:00', datetime.time(12, 00)),
     21        ('12:30:00', datetime.time(12, 30)),
     22        ('13:00:00', datetime.time(13, 00)),
     23        ('23:59:00', datetime.time(23, 59)),
     24        ('00:00:12', datetime.time(0, 0, 12)),
     25        ('00:00:12.5', datetime.time(0, 0, 12, 500000)),
     26        ('7:22:13.312', datetime.time(7, 22, 13, 312000)),
     27    ),
     28    'typecast_timestamp': (
     29        ('', None),
     30        (None, None),
     31        ('2005-08-11 0:00:00', datetime.datetime(2005, 8, 11)),
     32        ('2005-08-11 0:30:00', datetime.datetime(2005, 8, 11, 0, 30)),
     33        ('2005-08-11 8:50:30', datetime.datetime(2005, 8, 11, 8, 50, 30)),
     34        ('2005-08-11 8:50:30.123', datetime.datetime(2005, 8, 11, 8, 50, 30, 123000)),
     35        ('2005-08-11 8:50:30.9', datetime.datetime(2005, 8, 11, 8, 50, 30, 900000)),
     36        ('2005-08-11 8:50:30.312-05', datetime.datetime(2005, 8, 11, 8, 50, 30, 312000)),
     37        ('2005-08-11 8:50:30.312+02', datetime.datetime(2005, 8, 11, 8, 50, 30, 312000)),
     38    ),
     39    'typecast_boolean': (
     40        (None, None),
     41        ('', False),
     42        ('t', True),
     43        ('f', False),
     44        ('x', False),
     45    ),
     46}
     47
     48class DBTypeCasts(unittest.TestCase):
     49    def test_typeCasts(self):
     50        for k, v in TEST_CASES.items():
     51            for inpt, expected in v:
     52                got = getattr(typecasts, k)(inpt)
     53                self.assertEqual(got, expected, "In %s: %r doesn't match %r. Got %r instead." % (k, inpt, expected, got))
     54
     55if __name__ == '__main__':
     56    unittest.main()
     57 No newline at end of file
  • tests/regressiontests/dateformat/tests.py

     
     1r"""
     2>>> format(my_birthday, '')
     3''
     4>>> format(my_birthday, 'a')
     5'p.m.'
     6>>> format(my_birthday, 'A')
     7'PM'
     8>>> format(my_birthday, 'd')
     9'08'
     10>>> format(my_birthday, 'j')
     11'8'
     12>>> format(my_birthday, 'l')
     13'Sunday'
     14>>> format(my_birthday, 'L')
     15'False'
     16>>> format(my_birthday, 'm')
     17'07'
     18>>> format(my_birthday, 'M')
     19'Jul'
     20>>> format(my_birthday, 'n')
     21'7'
     22>>> format(my_birthday, 'N')
     23'July'
     24>>> format(my_birthday, 'O')
     25'+0100'
     26>>> format(my_birthday, 'P')
     27'10 p.m.'
     28>>> format(my_birthday, 'r')
     29'Sun, 8 Jul 1979 22:00:00 +0100'
     30>>> format(my_birthday, 's')
     31'00'
     32>>> format(my_birthday, 'S')
     33'th'
     34>>> format(my_birthday, 't')
     35'31'
     36>>> format(my_birthday, 'T')
     37'CET'
     38>>> format(my_birthday, 'U')
     39'300531600'
     40>>> format(my_birthday, 'w')
     41'0'
     42>>> format(my_birthday, 'W')
     43'27'
     44>>> format(my_birthday, 'y')
     45'79'
     46>>> format(my_birthday, 'Y')
     47'1979'
     48>>> format(my_birthday, 'z')
     49'189'
     50>>> format(my_birthday, 'Z')
     51'3600'
     52
     53>>> format(summertime, 'I')
     54'1'
     55>>> format(summertime, 'O')
     56'+0200'
     57>>> format(wintertime, 'I')
     58'0'
     59>>> format(wintertime, 'O')
     60'+0100'
     61
     62>>> format(my_birthday, r'Y z \C\E\T')
     63'1979 189 CET'
     64
     65>>> format(my_birthday, r'jS o\f F')
     66'8th of July'
     67"""
     68
     69from django.utils import dateformat, translation
     70import datetime, os, time
     71
     72format = dateformat.format
     73os.environ['TZ'] = 'Europe/Copenhagen'
     74translation.activate('en-us')
     75
     76#time.tzset()
     77
     78my_birthday = datetime.datetime(1979, 7, 8, 22, 00)
     79summertime = datetime.datetime(2005, 10, 30, 1, 00)
     80wintertime = datetime.datetime(2005, 10, 30, 4, 00)
     81
     82
     83if __name__ == '__main__':
     84    import doctest
     85    doctest.testmod()
  • tests/regressiontests/defaultfilters/tests.py

     
     1r"""
     2>>> floatformat(7.7)
     3'7.7'
     4>>> floatformat(7.0)
     5'7'
     6>>> floatformat(0.7)
     7'0.7'
     8>>> floatformat(0.07)
     9'0.1'
     10>>> floatformat(0.007)
     11'0.0'
     12>>> floatformat(0.0)
     13'0'
     14
     15>>> addslashes('"double quotes" and \'single quotes\'')
     16'\\"double quotes\\" and \\\'single quotes\\\''
     17
     18>>> capfirst('hello world')
     19'Hello world'
     20
     21>>> fix_ampersands('Jack & Jill & Jeroboam')
     22'Jack &amp; Jill &amp; Jeroboam'
     23
     24>>> linenumbers('line 1\nline 2')
     25'1. line 1\n2. line 2'
     26
     27>>> linenumbers('\n'.join(['x'] * 10))
     28'01. x\n02. x\n03. x\n04. x\n05. x\n06. x\n07. x\n08. x\n09. x\n10. x'
     29
     30>>> lower('TEST')
     31'test'
     32
     33>>> lower(u'\xcb') # uppercase E umlaut
     34u'\xeb'
     35
     36>>> make_list('abc')
     37['a', 'b', 'c']
     38
     39>>> make_list(1234)
     40['1', '2', '3', '4']
     41
     42>>> slugify(' Jack & Jill like numbers 1,2,3 and 4 and silly characters ?%.$!/')
     43'jack-jill-like-numbers-123-and-4-and-silly-characters'
     44
     45>>> stringformat(1, '03d')
     46'001'
     47
     48>>> stringformat(1, 'z')
     49''
     50
     51>>> title('a nice title, isn\'t it?')
     52"A Nice Title, Isn't It?"
     53
     54
     55>>> truncatewords('A sentence with a few words in it', 1)
     56'A ...'
     57
     58>>> truncatewords('A sentence with a few words in it', 5)
     59'A sentence with a few ...'
     60
     61>>> truncatewords('A sentence with a few words in it', 100)
     62'A sentence with a few words in it'
     63
     64>>> truncatewords('A sentence with a few words in it', 'not a number')
     65'A sentence with a few words in it'
     66
     67
     68>>> upper('Mixed case input')
     69'MIXED CASE INPUT'
     70
     71>>> upper(u'\xeb') # lowercase e umlaut
     72u'\xcb'
     73
     74
     75>>> urlencode('jack & jill')
     76'jack%20%26%20jill'
     77
     78
     79>>> urlizetrunc('http://short.com/', 20)
     80'<a href="http://short.com/" rel="nofollow">http://short.com/</a>'
     81
     82>>> urlizetrunc('http://www.google.co.uk/search?hl=en&q=some+long+url&btnG=Search&meta=', 20)
     83'<a href="http://www.google.co.uk/search?hl=en&q=some+long+url&btnG=Search&meta=" rel="nofollow">http://www.google.co...</a>'
     84
     85>>> wordcount('')
     860
     87
     88>>> wordcount('oneword')
     891
     90
     91>>> wordcount('lots of words')
     923
     93
     94>>> wordwrap('this is a long paragraph of text that really needs to be wrapped I\'m afraid', 14)
     95"this is a long\nparagraph of\ntext that\nreally needs\nto be wrapped\nI'm afraid"
     96
     97>>> ljust('test', 10)
     98'test      '
     99
     100>>> ljust('test', 3)
     101'test'
     102
     103>>> rjust('test', 10)
     104'      test'
     105
     106>>> rjust('test', 3)
     107'test'
     108
     109>>> center('test', 6)
     110' test '
     111
     112>>> cut('a string to be mangled', 'a')
     113' string to be mngled'
     114
     115>>> cut('a string to be mangled', 'ng')
     116'a stri to be maled'
     117
     118>>> cut('a string to be mangled', 'strings')
     119'a string to be mangled'
     120
     121>>> escape('<some html & special characters > here')
     122'&lt;some html &amp; special characters &gt; here'
     123
     124>>> linebreaks('line 1')
     125'<p>line 1</p>'
     126
     127>>> linebreaks('line 1\nline 2')
     128'<p>line 1<br />line 2</p>'
     129
     130>>> removetags('some <b>html</b> with <script>alert("You smell")</script> disallowed <img /> tags', 'script img')
     131'some <b>html</b> with alert("You smell") disallowed  tags'
     132
     133>>> striptags('some <b>html</b> with <script>alert("You smell")</script> disallowed <img /> tags')
     134'some html with alert("You smell") disallowed  tags'
     135
     136>>> dictsort([{'age': 23, 'name': 'Barbara-Ann'},
     137...           {'age': 63, 'name': 'Ra Ra Rasputin'},
     138...           {'name': 'Jonny B Goode', 'age': 18}], 'age')
     139[{'age': 18, 'name': 'Jonny B Goode'}, {'age': 23, 'name': 'Barbara-Ann'}, {'age': 63, 'name': 'Ra Ra Rasputin'}]
     140
     141>>> dictsortreversed([{'age': 23, 'name': 'Barbara-Ann'},
     142...           {'age': 63, 'name': 'Ra Ra Rasputin'},
     143...           {'name': 'Jonny B Goode', 'age': 18}], 'age')
     144[{'age': 63, 'name': 'Ra Ra Rasputin'}, {'age': 23, 'name': 'Barbara-Ann'}, {'age': 18, 'name': 'Jonny B Goode'}]
     145
     146>>> first([0,1,2])
     1470
     148
     149>>> first('')
     150''
     151
     152>>> first('test')
     153't'
     154
     155>>> join([0,1,2], 'glue')
     156'0glue1glue2'
     157
     158>>> length('1234')
     1594
     160
     161>>> length([1,2,3,4])
     1624
     163
     164>>> length_is([], 0)
     165True
     166
     167>>> length_is([], 1)
     168False
     169
     170>>> length_is('a', 1)
     171True
     172
     173>>> length_is('a', 10)
     174False
     175
     176>>> slice_('abcdefg', '0')
     177''
     178
     179>>> slice_('abcdefg', '1')
     180'a'
     181
     182>>> slice_('abcdefg', '-1')
     183'abcdef'
     184
     185>>> slice_('abcdefg', '1:2')
     186'b'
     187
     188>>> slice_('abcdefg', '1:3')
     189'bc'
     190
     191>>> slice_('abcdefg', '0::2')
     192'aceg'
     193
     194>>> unordered_list(['item 1', []])
     195'\t<li>item 1</li>'
     196
     197>>> unordered_list(['item 1', [['item 1.1', []]]])
     198'\t<li>item 1\n\t<ul>\n\t\t<li>item 1.1</li>\n\t</ul>\n\t</li>'
     199
     200>>> unordered_list(['item 1', [['item 1.1', []], ['item 1.2', []]]])
     201'\t<li>item 1\n\t<ul>\n\t\t<li>item 1.1</li>\n\t\t<li>item 1.2</li>\n\t</ul>\n\t</li>'
     202
     203>>> add('1', '2')
     2043
     205
     206>>> get_digit(123, 1)
     2073
     208
     209>>> get_digit(123, 2)
     2102
     211
     212>>> get_digit(123, 3)
     2131
     214
     215>>> get_digit(123, 4)
     2160
     217
     218>>> get_digit(123, 0)
     219123
     220
     221>>> get_digit('xyz', 0)
     222'xyz'
     223
     224# real testing of date() is in dateformat.py
     225>>> date(datetime.datetime(2005, 12, 29), "d F Y")
     226'29 December 2005'
     227>>> date(datetime.datetime(2005, 12, 29), r'jS o\f F')
     228'29th of December'
     229
     230# real testing of time() is done in dateformat.py
     231>>> time(datetime.time(13), "h")
     232'01'
     233
     234# real testing is done in timesince.py, where we can provide our own 'now'
     235>>> timesince(datetime.datetime.now() - datetime.timedelta(1))
     236'1 day'
     237
     238>>> default("val", "default")
     239'val'
     240
     241>>> default(None, "default")
     242'default'
     243
     244>>> default('', "default")
     245'default'
     246
     247>>> default_if_none("val", "default")
     248'val'
     249
     250>>> default_if_none(None, "default")
     251'default'
     252
     253>>> default_if_none('', "default")
     254''
     255
     256>>> divisibleby(4, 2)
     257True
     258
     259>>> divisibleby(4, 3)
     260False
     261
     262>>> yesno(True)
     263'yes'
     264
     265>>> yesno(False)
     266'no'
     267
     268>>> yesno(None)
     269'maybe'
     270
     271>>> yesno(True, 'certainly,get out of town,perhaps')
     272'certainly'
     273
     274>>> yesno(False, 'certainly,get out of town,perhaps')
     275'get out of town'
     276
     277>>> yesno(None, 'certainly,get out of town,perhaps')
     278'perhaps'
     279
     280>>> yesno(None, 'certainly,get out of town')
     281'get out of town'
     282
     283>>> filesizeformat(1023)
     284'1023 bytes'
     285
     286>>> filesizeformat(1024)
     287'1.0 KB'
     288
     289>>> filesizeformat(10*1024)
     290'10.0 KB'
     291
     292>>> filesizeformat(1024*1024-1)
     293'1024.0 KB'
     294
     295>>> filesizeformat(1024*1024)
     296'1.0 MB'
     297
     298>>> filesizeformat(1024*1024*50)
     299'50.0 MB'
     300
     301>>> filesizeformat(1024*1024*1024-1)
     302'1024.0 MB'
     303
     304>>> filesizeformat(1024*1024*1024)
     305'1.0 GB'
     306
     307>>> pluralize(1)
     308''
     309
     310>>> pluralize(0)
     311's'
     312
     313>>> pluralize(2)
     314's'
     315
     316>>> pluralize([1])
     317''
     318
     319>>> pluralize([])
     320's'
     321
     322>>> pluralize([1,2,3])
     323's'
     324
     325>>> pluralize(1,'es')
     326''
     327
     328>>> pluralize(0,'es')
     329'es'
     330
     331>>> pluralize(2,'es')
     332'es'
     333
     334>>> pluralize(1,'y,ies')
     335'y'
     336
     337>>> pluralize(0,'y,ies')
     338'ies'
     339
     340>>> pluralize(2,'y,ies')
     341'ies'
     342
     343>>> pluralize(0,'y,ies,error')
     344''
     345
     346>>> phone2numeric('0800 flowers')
     347'0800 3569377'
     348
     349
     350
     351"""
     352
     353from django.template.defaultfilters import *
     354import datetime
     355
     356if __name__ == '__main__':
     357    import doctest
     358    doctest.testmod()
  • tests/regressiontests/one_to_one_regress/models.py

     
    2222    def __str__(self):
    2323        return "Favorites for %s" % self.name
    2424
    25 API_TESTS = """
     25__test__ = {'API_TESTS':"""
    2626# Regression test for #1064 and #1506: Check that we create models via the m2m
    2727# relation if the remote model has a OneToOneField.
    2828>>> p1 = Place(name='Demon Dogs', address='944 W. Fullerton')
     
    3434>>> f.restaurants = [r]
    3535>>> f.restaurants.all()
    3636[<Restaurant: Demon Dogs the restaurant>]
    37 """
     37"""}
  • tests/regressiontests/templates/tests.py

     
     1from django.conf import settings
     2
     3if __name__ == '__main__':
     4    # When running this file in isolation, we need to set up the configuration
     5    # before importing 'template'.
     6    settings.configure()
     7
     8from django import template
     9from django.template import loader
     10from django.utils.translation import activate, deactivate, install
     11from django.utils.tzinfo import LocalTimezone
     12from datetime import datetime, timedelta
     13import unittest
     14
     15#################################
     16# Custom template tag for tests #
     17#################################
     18
     19register = template.Library()
     20
     21class EchoNode(template.Node):
     22    def __init__(self, contents):
     23        self.contents = contents
     24
     25    def render(self, context):
     26        return " ".join(self.contents)
     27
     28def do_echo(parser, token):
     29    return EchoNode(token.contents.split()[1:])
     30
     31register.tag("echo", do_echo)
     32
     33template.libraries['django.templatetags.testtags'] = register
     34
     35#####################################
     36# Helper objects for template tests #
     37#####################################
     38
     39class SomeException(Exception):
     40    silent_variable_failure = True
     41
     42class SomeOtherException(Exception):
     43    pass
     44
     45class SomeClass:
     46    def __init__(self):
     47        self.otherclass = OtherClass()
     48
     49    def method(self):
     50        return "SomeClass.method"
     51
     52    def method2(self, o):
     53        return o
     54
     55    def method3(self):
     56        raise SomeException
     57
     58    def method4(self):
     59        raise SomeOtherException
     60
     61class OtherClass:
     62    def method(self):
     63        return "OtherClass.method"
     64
     65class Templates(unittest.TestCase):
     66    def test_templates(self):
     67        # NOW and NOW_tz are used by timesince tag tests.
     68        NOW = datetime.now()
     69        NOW_tz = datetime.now(LocalTimezone(datetime.now()))
     70       
     71        # SYNTAX --
     72        # 'template_name': ('template contents', 'context dict', 'expected string output' or Exception class)
     73        TEMPLATE_TESTS = {
     74
     75            ### BASIC SYNTAX ##########################################################
     76
     77            # Plain text should go through the template parser untouched
     78            'basic-syntax01': ("something cool", {}, "something cool"),
     79
     80            # Variables should be replaced with their value in the current context
     81            'basic-syntax02': ("{{ headline }}", {'headline':'Success'}, "Success"),
     82
     83            # More than one replacement variable is allowed in a template
     84            'basic-syntax03': ("{{ first }} --- {{ second }}", {"first" : 1, "second" : 2}, "1 --- 2"),
     85
     86            # Fail silently when a variable is not found in the current context
     87            'basic-syntax04': ("as{{ missing }}df", {}, "asINVALIDdf"),
     88
     89            # A variable may not contain more than one word
     90            'basic-syntax06': ("{{ multi word variable }}", {}, template.TemplateSyntaxError),
     91
     92            # Raise TemplateSyntaxError for empty variable tags
     93            'basic-syntax07': ("{{ }}",        {}, template.TemplateSyntaxError),
     94            'basic-syntax08': ("{{        }}", {}, template.TemplateSyntaxError),
     95
     96            # Attribute syntax allows a template to call an object's attribute
     97            'basic-syntax09': ("{{ var.method }}", {"var": SomeClass()}, "SomeClass.method"),
     98
     99            # Multiple levels of attribute access are allowed
     100            'basic-syntax10': ("{{ var.otherclass.method }}", {"var": SomeClass()}, "OtherClass.method"),
     101
     102            # Fail silently when a variable's attribute isn't found
     103            'basic-syntax11': ("{{ var.blech }}", {"var": SomeClass()}, "INVALID"),
     104
     105            # Raise TemplateSyntaxError when trying to access a variable beginning with an underscore
     106            'basic-syntax12': ("{{ var.__dict__ }}", {"var": SomeClass()}, template.TemplateSyntaxError),
     107
     108            # Raise TemplateSyntaxError when trying to access a variable containing an illegal character
     109            'basic-syntax13': ("{{ va>r }}", {}, template.TemplateSyntaxError),
     110            'basic-syntax14': ("{{ (var.r) }}", {}, template.TemplateSyntaxError),
     111            'basic-syntax15': ("{{ sp%am }}", {}, template.TemplateSyntaxError),
     112            'basic-syntax16': ("{{ eggs! }}", {}, template.TemplateSyntaxError),
     113            'basic-syntax17': ("{{ moo? }}", {}, template.TemplateSyntaxError),
     114
     115            # Attribute syntax allows a template to call a dictionary key's value
     116            'basic-syntax18': ("{{ foo.bar }}", {"foo" : {"bar" : "baz"}}, "baz"),
     117
     118            # Fail silently when a variable's dictionary key isn't found
     119            'basic-syntax19': ("{{ foo.spam }}", {"foo" : {"bar" : "baz"}}, "INVALID"),
     120
     121            # Fail silently when accessing a non-simple method
     122            'basic-syntax20': ("{{ var.method2 }}", {"var": SomeClass()}, "INVALID"),
     123
     124            # Basic filter usage
     125            'basic-syntax21': ("{{ var|upper }}", {"var": "Django is the greatest!"}, "DJANGO IS THE GREATEST!"),
     126
     127            # Chained filters
     128            'basic-syntax22': ("{{ var|upper|lower }}", {"var": "Django is the greatest!"}, "django is the greatest!"),
     129
     130            # Raise TemplateSyntaxError for space between a variable and filter pipe
     131            'basic-syntax23': ("{{ var |upper }}", {}, template.TemplateSyntaxError),
     132
     133            # Raise TemplateSyntaxError for space after a filter pipe
     134            'basic-syntax24': ("{{ var| upper }}", {}, template.TemplateSyntaxError),
     135
     136            # Raise TemplateSyntaxError for a nonexistent filter
     137            'basic-syntax25': ("{{ var|does_not_exist }}", {}, template.TemplateSyntaxError),
     138
     139            # Raise TemplateSyntaxError when trying to access a filter containing an illegal character
     140            'basic-syntax26': ("{{ var|fil(ter) }}", {}, template.TemplateSyntaxError),
     141
     142            # Raise TemplateSyntaxError for invalid block tags
     143            'basic-syntax27': ("{% nothing_to_see_here %}", {}, template.TemplateSyntaxError),
     144
     145            # Raise TemplateSyntaxError for empty block tags
     146            'basic-syntax28': ("{% %}", {}, template.TemplateSyntaxError),
     147
     148            # Chained filters, with an argument to the first one
     149            'basic-syntax29': ('{{ var|removetags:"b i"|upper|lower }}', {"var": "<b><i>Yes</i></b>"}, "yes"),
     150
     151            # Escaped string as argument
     152            'basic-syntax30': (r'{{ var|default_if_none:" endquote\" hah" }}', {"var": None}, ' endquote" hah'),
     153
     154            # Variable as argument
     155            'basic-syntax31': (r'{{ var|default_if_none:var2 }}', {"var": None, "var2": "happy"}, 'happy'),
     156
     157            # Default argument testing
     158            'basic-syntax32': (r'{{ var|yesno:"yup,nup,mup" }} {{ var|yesno }}', {"var": True}, 'yup yes'),
     159
     160            # Fail silently for methods that raise an exception with a "silent_variable_failure" attribute
     161            'basic-syntax33': (r'1{{ var.method3 }}2', {"var": SomeClass()}, "1INVALID2"),
     162
     163            # In methods that raise an exception without a "silent_variable_attribute" set to True,
     164            # the exception propogates
     165            'basic-syntax34': (r'1{{ var.method4 }}2', {"var": SomeClass()}, SomeOtherException),
     166
     167            # Escaped backslash in argument
     168            'basic-syntax35': (r'{{ var|default_if_none:"foo\bar" }}', {"var": None}, r'foo\bar'),
     169
     170            # Escaped backslash using known escape char
     171            'basic-syntax35': (r'{{ var|default_if_none:"foo\now" }}', {"var": None}, r'foo\now'),
     172
     173            ### COMMENT TAG ###########################################################
     174            'comment-tag01': ("{% comment %}this is hidden{% endcomment %}hello", {}, "hello"),
     175            'comment-tag02': ("{% comment %}this is hidden{% endcomment %}hello{% comment %}foo{% endcomment %}", {}, "hello"),
     176
     177            # Comment tag can contain invalid stuff.
     178            'comment-tag03': ("foo{% comment %} {% if %} {% endcomment %}", {}, "foo"),
     179            'comment-tag04': ("foo{% comment %} {% endblock %} {% endcomment %}", {}, "foo"),
     180            'comment-tag05': ("foo{% comment %} {% somerandomtag %} {% endcomment %}", {}, "foo"),
     181
     182            ### CYCLE TAG #############################################################
     183            'cycle01': ('{% cycle a %}', {}, template.TemplateSyntaxError),
     184            'cycle02': ('{% cycle a,b,c as abc %}{% cycle abc %}', {}, 'ab'),
     185            'cycle03': ('{% cycle a,b,c as abc %}{% cycle abc %}{% cycle abc %}', {}, 'abc'),
     186            'cycle04': ('{% cycle a,b,c as abc %}{% cycle abc %}{% cycle abc %}{% cycle abc %}', {}, 'abca'),
     187            'cycle05': ('{% cycle %}', {}, template.TemplateSyntaxError),
     188            'cycle06': ('{% cycle a %}', {}, template.TemplateSyntaxError),
     189            'cycle07': ('{% cycle a,b,c as foo %}{% cycle bar %}', {}, template.TemplateSyntaxError),
     190
     191            ### EXCEPTIONS ############################################################
     192
     193            # Raise exception for invalid template name
     194            'exception01': ("{% extends 'nonexistent' %}", {}, template.TemplateSyntaxError),
     195
     196            # Raise exception for invalid template name (in variable)
     197            'exception02': ("{% extends nonexistent %}", {}, template.TemplateSyntaxError),
     198
     199            # Raise exception for extra {% extends %} tags
     200            'exception03': ("{% extends 'inheritance01' %}{% block first %}2{% endblock %}{% extends 'inheritance16' %}", {}, template.TemplateSyntaxError),
     201
     202            # Raise exception for custom tags used in child with {% load %} tag in parent, not in child
     203            'exception04': ("{% extends 'inheritance17' %}{% block first %}{% echo 400 %}5678{% endblock %}", {}, template.TemplateSyntaxError),
     204
     205            ### FILTER TAG ############################################################
     206            'filter01': ('{% filter upper %}{% endfilter %}', {}, ''),
     207            'filter02': ('{% filter upper %}django{% endfilter %}', {}, 'DJANGO'),
     208            'filter03': ('{% filter upper|lower %}django{% endfilter %}', {}, 'django'),
     209
     210            ### FIRSTOF TAG ###########################################################
     211            'firstof01': ('{% firstof a b c %}', {'a':0,'b':0,'c':0}, ''),
     212            'firstof02': ('{% firstof a b c %}', {'a':1,'b':0,'c':0}, '1'),
     213            'firstof03': ('{% firstof a b c %}', {'a':0,'b':2,'c':0}, '2'),
     214            'firstof04': ('{% firstof a b c %}', {'a':0,'b':0,'c':3}, '3'),
     215            'firstof05': ('{% firstof a b c %}', {'a':1,'b':2,'c':3}, '1'),
     216            'firstof06': ('{% firstof %}', {}, template.TemplateSyntaxError),
     217
     218            ### FOR TAG ###############################################################
     219            'for-tag01': ("{% for val in values %}{{ val }}{% endfor %}", {"values": [1, 2, 3]}, "123"),
     220            'for-tag02': ("{% for val in values reversed %}{{ val }}{% endfor %}", {"values": [1, 2, 3]}, "321"),
     221            'for-tag-vars01': ("{% for val in values %}{{ forloop.counter }}{% endfor %}", {"values": [6, 6, 6]}, "123"),
     222            'for-tag-vars02': ("{% for val in values %}{{ forloop.counter0 }}{% endfor %}", {"values": [6, 6, 6]}, "012"),
     223            'for-tag-vars03': ("{% for val in values %}{{ forloop.revcounter }}{% endfor %}", {"values": [6, 6, 6]}, "321"),
     224            'for-tag-vars04': ("{% for val in values %}{{ forloop.revcounter0 }}{% endfor %}", {"values": [6, 6, 6]}, "210"),
     225
     226            ### IF TAG ################################################################
     227            'if-tag01': ("{% if foo %}yes{% else %}no{% endif %}", {"foo": True}, "yes"),
     228            'if-tag02': ("{% if foo %}yes{% else %}no{% endif %}", {"foo": False}, "no"),
     229            'if-tag03': ("{% if foo %}yes{% else %}no{% endif %}", {}, "no"),
     230
     231            # AND
     232            'if-tag-and01': ("{% if foo and bar %}yes{% else %}no{% endif %}", {'foo': True, 'bar': True}, 'yes'),
     233            'if-tag-and02': ("{% if foo and bar %}yes{% else %}no{% endif %}", {'foo': True, 'bar': False}, 'no'),
     234            'if-tag-and03': ("{% if foo and bar %}yes{% else %}no{% endif %}", {'foo': False, 'bar': True}, 'no'),
     235            'if-tag-and04': ("{% if foo and bar %}yes{% else %}no{% endif %}", {'foo': False, 'bar': False}, 'no'),
     236            'if-tag-and05': ("{% if foo and bar %}yes{% else %}no{% endif %}", {'foo': False}, 'no'),
     237            'if-tag-and06': ("{% if foo and bar %}yes{% else %}no{% endif %}", {'bar': False}, 'no'),
     238            'if-tag-and07': ("{% if foo and bar %}yes{% else %}no{% endif %}", {'foo': True}, 'no'),
     239            'if-tag-and08': ("{% if foo and bar %}yes{% else %}no{% endif %}", {'bar': True}, 'no'),
     240
     241            # OR
     242            'if-tag-or01': ("{% if foo or bar %}yes{% else %}no{% endif %}", {'foo': True, 'bar': True}, 'yes'),
     243            'if-tag-or02': ("{% if foo or bar %}yes{% else %}no{% endif %}", {'foo': True, 'bar': False}, 'yes'),
     244            'if-tag-or03': ("{% if foo or bar %}yes{% else %}no{% endif %}", {'foo': False, 'bar': True}, 'yes'),
     245            'if-tag-or04': ("{% if foo or bar %}yes{% else %}no{% endif %}", {'foo': False, 'bar': False}, 'no'),
     246            'if-tag-or05': ("{% if foo or bar %}yes{% else %}no{% endif %}", {'foo': False}, 'no'),
     247            'if-tag-or06': ("{% if foo or bar %}yes{% else %}no{% endif %}", {'bar': False}, 'no'),
     248            'if-tag-or07': ("{% if foo or bar %}yes{% else %}no{% endif %}", {'foo': True}, 'yes'),
     249            'if-tag-or08': ("{% if foo or bar %}yes{% else %}no{% endif %}", {'bar': True}, 'yes'),
     250
     251            # TODO: multiple ORs
     252
     253            # NOT
     254            'if-tag-not01': ("{% if not foo %}no{% else %}yes{% endif %}", {'foo': True}, 'yes'),
     255            'if-tag-not02': ("{% if not %}yes{% else %}no{% endif %}", {'foo': True}, 'no'),
     256            'if-tag-not03': ("{% if not %}yes{% else %}no{% endif %}", {'not': True}, 'yes'),
     257            'if-tag-not04': ("{% if not not %}no{% else %}yes{% endif %}", {'not': True}, 'yes'),
     258            'if-tag-not05': ("{% if not not %}no{% else %}yes{% endif %}", {}, 'no'),
     259
     260            'if-tag-not06': ("{% if foo and not bar %}yes{% else %}no{% endif %}", {}, 'no'),
     261            'if-tag-not07': ("{% if foo and not bar %}yes{% else %}no{% endif %}", {'foo': True, 'bar': True}, 'no'),
     262            'if-tag-not08': ("{% if foo and not bar %}yes{% else %}no{% endif %}", {'foo': True, 'bar': False}, 'yes'),
     263            'if-tag-not09': ("{% if foo and not bar %}yes{% else %}no{% endif %}", {'foo': False, 'bar': True}, 'no'),
     264            'if-tag-not10': ("{% if foo and not bar %}yes{% else %}no{% endif %}", {'foo': False, 'bar': False}, 'no'),
     265
     266            'if-tag-not11': ("{% if not foo and bar %}yes{% else %}no{% endif %}", {}, 'no'),
     267            'if-tag-not12': ("{% if not foo and bar %}yes{% else %}no{% endif %}", {'foo': True, 'bar': True}, 'no'),
     268            'if-tag-not13': ("{% if not foo and bar %}yes{% else %}no{% endif %}", {'foo': True, 'bar': False}, 'no'),
     269            'if-tag-not14': ("{% if not foo and bar %}yes{% else %}no{% endif %}", {'foo': False, 'bar': True}, 'yes'),
     270            'if-tag-not15': ("{% if not foo and bar %}yes{% else %}no{% endif %}", {'foo': False, 'bar': False}, 'no'),
     271
     272            'if-tag-not16': ("{% if foo or not bar %}yes{% else %}no{% endif %}", {}, 'yes'),
     273            'if-tag-not17': ("{% if foo or not bar %}yes{% else %}no{% endif %}", {'foo': True, 'bar': True}, 'yes'),
     274            'if-tag-not18': ("{% if foo or not bar %}yes{% else %}no{% endif %}", {'foo': True, 'bar': False}, 'yes'),
     275            'if-tag-not19': ("{% if foo or not bar %}yes{% else %}no{% endif %}", {'foo': False, 'bar': True}, 'no'),
     276            'if-tag-not20': ("{% if foo or not bar %}yes{% else %}no{% endif %}", {'foo': False, 'bar': False}, 'yes'),
     277
     278            'if-tag-not21': ("{% if not foo or bar %}yes{% else %}no{% endif %}", {}, 'yes'),
     279            'if-tag-not22': ("{% if not foo or bar %}yes{% else %}no{% endif %}", {'foo': True, 'bar': True}, 'yes'),
     280            'if-tag-not23': ("{% if not foo or bar %}yes{% else %}no{% endif %}", {'foo': True, 'bar': False}, 'no'),
     281            'if-tag-not24': ("{% if not foo or bar %}yes{% else %}no{% endif %}", {'foo': False, 'bar': True}, 'yes'),
     282            'if-tag-not25': ("{% if not foo or bar %}yes{% else %}no{% endif %}", {'foo': False, 'bar': False}, 'yes'),
     283
     284            'if-tag-not26': ("{% if not foo and not bar %}yes{% else %}no{% endif %}", {}, 'yes'),
     285            'if-tag-not27': ("{% if not foo and not bar %}yes{% else %}no{% endif %}", {'foo': True, 'bar': True}, 'no'),
     286            'if-tag-not28': ("{% if not foo and not bar %}yes{% else %}no{% endif %}", {'foo': True, 'bar': False}, 'no'),
     287            'if-tag-not29': ("{% if not foo and not bar %}yes{% else %}no{% endif %}", {'foo': False, 'bar': True}, 'no'),
     288            'if-tag-not30': ("{% if not foo and not bar %}yes{% else %}no{% endif %}", {'foo': False, 'bar': False}, 'yes'),
     289
     290            'if-tag-not31': ("{% if not foo or not bar %}yes{% else %}no{% endif %}", {}, 'yes'),
     291            'if-tag-not32': ("{% if not foo or not bar %}yes{% else %}no{% endif %}", {'foo': True, 'bar': True}, 'no'),
     292            'if-tag-not33': ("{% if not foo or not bar %}yes{% else %}no{% endif %}", {'foo': True, 'bar': False}, 'yes'),
     293            'if-tag-not34': ("{% if not foo or not bar %}yes{% else %}no{% endif %}", {'foo': False, 'bar': True}, 'yes'),
     294            'if-tag-not35': ("{% if not foo or not bar %}yes{% else %}no{% endif %}", {'foo': False, 'bar': False}, 'yes'),
     295
     296            # AND and OR raises a TemplateSyntaxError
     297            'if-tag-error01': ("{% if foo or bar and baz %}yes{% else %}no{% endif %}", {'foo': False, 'bar': False}, template.TemplateSyntaxError),
     298            'if-tag-error02': ("{% if foo and %}yes{% else %}no{% endif %}", {'foo': True}, template.TemplateSyntaxError),
     299            'if-tag-error03': ("{% if foo or %}yes{% else %}no{% endif %}", {'foo': True}, template.TemplateSyntaxError),
     300            'if-tag-error04': ("{% if not foo and %}yes{% else %}no{% endif %}", {'foo': True}, template.TemplateSyntaxError),
     301            'if-tag-error05': ("{% if not foo or %}yes{% else %}no{% endif %}", {'foo': True}, template.TemplateSyntaxError),
     302
     303            ### IFCHANGED TAG #########################################################
     304            'ifchanged01': ('{% for n in num %}{% ifchanged %}{{ n }}{% endifchanged %}{% endfor %}', { 'num': (1,2,3) }, '123'),
     305            'ifchanged02': ('{% for n in num %}{% ifchanged %}{{ n }}{% endifchanged %}{% endfor %}', { 'num': (1,1,3) }, '13'),
     306            'ifchanged03': ('{% for n in num %}{% ifchanged %}{{ n }}{% endifchanged %}{% endfor %}', { 'num': (1,1,1) }, '1'),
     307
     308            ### IFEQUAL TAG ###########################################################
     309            'ifequal01': ("{% ifequal a b %}yes{% endifequal %}", {"a": 1, "b": 2}, ""),
     310            'ifequal02': ("{% ifequal a b %}yes{% endifequal %}", {"a": 1, "b": 1}, "yes"),
     311            'ifequal03': ("{% ifequal a b %}yes{% else %}no{% endifequal %}", {"a": 1, "b": 2}, "no"),
     312            'ifequal04': ("{% ifequal a b %}yes{% else %}no{% endifequal %}", {"a": 1, "b": 1}, "yes"),
     313            'ifequal05': ("{% ifequal a 'test' %}yes{% else %}no{% endifequal %}", {"a": "test"}, "yes"),
     314            'ifequal06': ("{% ifequal a 'test' %}yes{% else %}no{% endifequal %}", {"a": "no"}, "no"),
     315            'ifequal07': ('{% ifequal a "test" %}yes{% else %}no{% endifequal %}', {"a": "test"}, "yes"),
     316            'ifequal08': ('{% ifequal a "test" %}yes{% else %}no{% endifequal %}', {"a": "no"}, "no"),
     317            'ifequal09': ('{% ifequal a "test" %}yes{% else %}no{% endifequal %}', {}, "no"),
     318            'ifequal10': ('{% ifequal a b %}yes{% else %}no{% endifequal %}', {}, "yes"),
     319
     320            # SMART SPLITTING
     321            'ifequal-split01': ('{% ifequal a "test man" %}yes{% else %}no{% endifequal %}', {}, "no"),
     322            'ifequal-split02': ('{% ifequal a "test man" %}yes{% else %}no{% endifequal %}', {'a': 'foo'}, "no"),
     323            'ifequal-split03': ('{% ifequal a "test man" %}yes{% else %}no{% endifequal %}', {'a': 'test man'}, "yes"),
     324            'ifequal-split04': ("{% ifequal a 'test man' %}yes{% else %}no{% endifequal %}", {'a': 'test man'}, "yes"),
     325            'ifequal-split05': ("{% ifequal a 'i \"love\" you' %}yes{% else %}no{% endifequal %}", {'a': ''}, "no"),
     326            'ifequal-split06': ("{% ifequal a 'i \"love\" you' %}yes{% else %}no{% endifequal %}", {'a': 'i "love" you'}, "yes"),
     327            'ifequal-split07': ("{% ifequal a 'i \"love\" you' %}yes{% else %}no{% endifequal %}", {'a': 'i love you'}, "no"),
     328            'ifequal-split08': (r"{% ifequal a 'I\'m happy' %}yes{% else %}no{% endifequal %}", {'a': "I'm happy"}, "yes"),
     329            'ifequal-split09': (r"{% ifequal a 'slash\man' %}yes{% else %}no{% endifequal %}", {'a': r"slash\man"}, "yes"),
     330            'ifequal-split10': (r"{% ifequal a 'slash\man' %}yes{% else %}no{% endifequal %}", {'a': r"slashman"}, "no"),
     331
     332            ### IFNOTEQUAL TAG ########################################################
     333            'ifnotequal01': ("{% ifnotequal a b %}yes{% endifnotequal %}", {"a": 1, "b": 2}, "yes"),
     334            'ifnotequal02': ("{% ifnotequal a b %}yes{% endifnotequal %}", {"a": 1, "b": 1}, ""),
     335            'ifnotequal03': ("{% ifnotequal a b %}yes{% else %}no{% endifnotequal %}", {"a": 1, "b": 2}, "yes"),
     336            'ifnotequal04': ("{% ifnotequal a b %}yes{% else %}no{% endifnotequal %}", {"a": 1, "b": 1}, "no"),
     337
     338            ### INCLUDE TAG ###########################################################
     339            'include01': ('{% include "basic-syntax01" %}', {}, "something cool"),
     340            'include02': ('{% include "basic-syntax02" %}', {'headline': 'Included'}, "Included"),
     341            'include03': ('{% include template_name %}', {'template_name': 'basic-syntax02', 'headline': 'Included'}, "Included"),
     342            'include04': ('a{% include "nonexistent" %}b', {}, "ab"),
     343
     344            ### INHERITANCE ###########################################################
     345
     346            # Standard template with no inheritance
     347            'inheritance01': ("1{% block first %}_{% endblock %}3{% block second %}_{% endblock %}", {}, '1_3_'),
     348
     349            # Standard two-level inheritance
     350            'inheritance02': ("{% extends 'inheritance01' %}{% block first %}2{% endblock %}{% block second %}4{% endblock %}", {}, '1234'),
     351
     352            # Three-level with no redefinitions on third level
     353            'inheritance03': ("{% extends 'inheritance02' %}", {}, '1234'),
     354
     355            # Two-level with no redefinitions on second level
     356            'inheritance04': ("{% extends 'inheritance01' %}", {}, '1_3_'),
     357
     358            # Two-level with double quotes instead of single quotes
     359            'inheritance05': ('{% extends "inheritance02" %}', {}, '1234'),
     360
     361            # Three-level with variable parent-template name
     362            'inheritance06': ("{% extends foo %}", {'foo': 'inheritance02'}, '1234'),
     363
     364            # Two-level with one block defined, one block not defined
     365            'inheritance07': ("{% extends 'inheritance01' %}{% block second %}5{% endblock %}", {}, '1_35'),
     366
     367            # Three-level with one block defined on this level, two blocks defined next level
     368            'inheritance08': ("{% extends 'inheritance02' %}{% block second %}5{% endblock %}", {}, '1235'),
     369
     370            # Three-level with second and third levels blank
     371            'inheritance09': ("{% extends 'inheritance04' %}", {}, '1_3_'),
     372
     373            # Three-level with space NOT in a block -- should be ignored
     374            'inheritance10': ("{% extends 'inheritance04' %}      ", {}, '1_3_'),
     375
     376            # Three-level with both blocks defined on this level, but none on second level
     377            'inheritance11': ("{% extends 'inheritance04' %}{% block first %}2{% endblock %}{% block second %}4{% endblock %}", {}, '1234'),
     378
     379            # Three-level with this level providing one and second level providing the other
     380            'inheritance12': ("{% extends 'inheritance07' %}{% block first %}2{% endblock %}", {}, '1235'),
     381
     382            # Three-level with this level overriding second level
     383            'inheritance13': ("{% extends 'inheritance02' %}{% block first %}a{% endblock %}{% block second %}b{% endblock %}", {}, '1a3b'),
     384
     385            # A block defined only in a child template shouldn't be displayed
     386            'inheritance14': ("{% extends 'inheritance01' %}{% block newblock %}NO DISPLAY{% endblock %}", {}, '1_3_'),
     387
     388            # A block within another block
     389            'inheritance15': ("{% extends 'inheritance01' %}{% block first %}2{% block inner %}inner{% endblock %}{% endblock %}", {}, '12inner3_'),
     390
     391            # A block within another block (level 2)
     392            'inheritance16': ("{% extends 'inheritance15' %}{% block inner %}out{% endblock %}", {}, '12out3_'),
     393
     394            # {% load %} tag (parent -- setup for exception04)
     395            'inheritance17': ("{% load testtags %}{% block first %}1234{% endblock %}", {}, '1234'),
     396
     397            # {% load %} tag (standard usage, without inheritance)
     398            'inheritance18': ("{% load testtags %}{% echo this that theother %}5678", {}, 'this that theother5678'),
     399
     400            # {% load %} tag (within a child template)
     401            'inheritance19': ("{% extends 'inheritance01' %}{% block first %}{% load testtags %}{% echo 400 %}5678{% endblock %}", {}, '140056783_'),
     402
     403            # Two-level inheritance with {{ block.super }}
     404            'inheritance20': ("{% extends 'inheritance01' %}{% block first %}{{ block.super }}a{% endblock %}", {}, '1_a3_'),
     405
     406            # Three-level inheritance with {{ block.super }} from parent
     407            'inheritance21': ("{% extends 'inheritance02' %}{% block first %}{{ block.super }}a{% endblock %}", {}, '12a34'),
     408
     409            # Three-level inheritance with {{ block.super }} from grandparent
     410            'inheritance22': ("{% extends 'inheritance04' %}{% block first %}{{ block.super }}a{% endblock %}", {}, '1_a3_'),
     411
     412            # Three-level inheritance with {{ block.super }} from parent and grandparent
     413            'inheritance23': ("{% extends 'inheritance20' %}{% block first %}{{ block.super }}b{% endblock %}", {}, '1_ab3_'),
     414
     415            # Inheritance from local context without use of template loader
     416            'inheritance24': ("{% extends context_template %}{% block first %}2{% endblock %}{% block second %}4{% endblock %}", {'context_template': template.Template("1{% block first %}_{% endblock %}3{% block second %}_{% endblock %}")}, '1234'),
     417
     418            # Inheritance from local context with variable parent template
     419            'inheritance25': ("{% extends context_template.1 %}{% block first %}2{% endblock %}{% block second %}4{% endblock %}", {'context_template': [template.Template("Wrong"), template.Template("1{% block first %}_{% endblock %}3{% block second %}_{% endblock %}")]}, '1234'),
     420
     421            ### I18N ##################################################################
     422
     423            # {% spaceless %} tag
     424            'spaceless01': ("{% spaceless %} <b>    <i> text </i>    </b> {% endspaceless %}", {}, "<b> <i> text </i> </b>"),
     425            'spaceless02': ("{% spaceless %} <b> \n <i> text </i> \n </b> {% endspaceless %}", {}, "<b> <i> text </i> </b>"),
     426            'spaceless03': ("{% spaceless %}<b><i>text</i></b>{% endspaceless %}", {}, "<b><i>text</i></b>"),
     427
     428            # simple translation of a string delimited by '
     429            'i18n01': ("{% load i18n %}{% trans 'xxxyyyxxx' %}", {}, "xxxyyyxxx"),
     430
     431            # simple translation of a string delimited by "
     432            'i18n02': ('{% load i18n %}{% trans "xxxyyyxxx" %}', {}, "xxxyyyxxx"),
     433
     434            # simple translation of a variable
     435            'i18n03': ('{% load i18n %}{% blocktrans %}{{ anton }}{% endblocktrans %}', {'anton': 'xxxyyyxxx'}, "xxxyyyxxx"),
     436
     437            # simple translation of a variable and filter
     438            'i18n04': ('{% load i18n %}{% blocktrans with anton|lower as berta %}{{ berta }}{% endblocktrans %}', {'anton': 'XXXYYYXXX'}, "xxxyyyxxx"),
     439
     440            # simple translation of a string with interpolation
     441            'i18n05': ('{% load i18n %}{% blocktrans %}xxx{{ anton }}xxx{% endblocktrans %}', {'anton': 'yyy'}, "xxxyyyxxx"),
     442
     443            # simple translation of a string to german
     444            'i18n06': ('{% load i18n %}{% trans "Page not found" %}', {'LANGUAGE_CODE': 'de'}, "Seite nicht gefunden"),
     445
     446            # translation of singular form
     447            'i18n07': ('{% load i18n %}{% blocktrans count number as counter %}singular{% plural %}plural{% endblocktrans %}', {'number': 1}, "singular"),
     448
     449            # translation of plural form
     450            'i18n08': ('{% load i18n %}{% blocktrans count number as counter %}singular{% plural %}plural{% endblocktrans %}', {'number': 2}, "plural"),
     451
     452            # simple non-translation (only marking) of a string to german
     453            'i18n09': ('{% load i18n %}{% trans "Page not found" noop %}', {'LANGUAGE_CODE': 'de'}, "Page not found"),
     454
     455            # translation of a variable with a translated filter
     456            'i18n10': ('{{ bool|yesno:_("ja,nein") }}', {'bool': True}, 'ja'),
     457
     458            # translation of a variable with a non-translated filter
     459            'i18n11': ('{{ bool|yesno:"ja,nein" }}', {'bool': True}, 'ja'),
     460
     461            # usage of the get_available_languages tag
     462            'i18n12': ('{% load i18n %}{% get_available_languages as langs %}{% for lang in langs %}{% ifequal lang.0 "de" %}{{ lang.0 }}{% endifequal %}{% endfor %}', {}, 'de'),
     463
     464            # translation of a constant string
     465            'i18n13': ('{{ _("Page not found") }}', {'LANGUAGE_CODE': 'de'}, 'Seite nicht gefunden'),
     466
     467            ### MULTILINE #############################################################
     468
     469            'multiline01': ("""
     470                            Hello,
     471                            boys.
     472                            How
     473                            are
     474                            you
     475                            gentlemen.
     476                            """,
     477                            {},
     478                            """
     479                            Hello,
     480                            boys.
     481                            How
     482                            are
     483                            you
     484                            gentlemen.
     485                            """),
     486
     487            ### REGROUP TAG ###########################################################
     488            'regroup01': ('{% regroup data by bar as grouped %}' + \
     489                          '{% for group in grouped %}' + \
     490                          '{{ group.grouper }}:' + \
     491                          '{% for item in group.list %}' + \
     492                          '{{ item.foo }}' + \
     493                          '{% endfor %},' + \
     494                          '{% endfor %}',
     495                          {'data': [ {'foo':'c', 'bar':1},
     496                                     {'foo':'d', 'bar':1},
     497                                     {'foo':'a', 'bar':2},
     498                                     {'foo':'b', 'bar':2},
     499                                     {'foo':'x', 'bar':3}  ]},
     500                          '1:cd,2:ab,3:x,'),
     501
     502            # Test for silent failure when target variable isn't found
     503            'regroup02': ('{% regroup data by bar as grouped %}' + \
     504                          '{% for group in grouped %}' + \
     505                          '{{ group.grouper }}:' + \
     506                          '{% for item in group.list %}' + \
     507                          '{{ item.foo }}' + \
     508                          '{% endfor %},' + \
     509                          '{% endfor %}',
     510                          {}, 'INVALID:INVALIDINVALIDINVALIDINVALIDINVALIDINVALIDINVALID,'),
     511
     512            ### TEMPLATETAG TAG #######################################################
     513            'templatetag01': ('{% templatetag openblock %}', {}, '{%'),
     514            'templatetag02': ('{% templatetag closeblock %}', {}, '%}'),
     515            'templatetag03': ('{% templatetag openvariable %}', {}, '{{'),
     516            'templatetag04': ('{% templatetag closevariable %}', {}, '}}'),
     517            'templatetag05': ('{% templatetag %}', {}, template.TemplateSyntaxError),
     518            'templatetag06': ('{% templatetag foo %}', {}, template.TemplateSyntaxError),
     519            'templatetag07': ('{% templatetag openbrace %}', {}, '{'),
     520            'templatetag08': ('{% templatetag closebrace %}', {}, '}'),
     521            'templatetag09': ('{% templatetag openbrace %}{% templatetag openbrace %}', {}, '{{'),
     522            'templatetag10': ('{% templatetag closebrace %}{% templatetag closebrace %}', {}, '}}'),
     523
     524            ### WIDTHRATIO TAG ########################################################
     525            'widthratio01': ('{% widthratio a b 0 %}', {'a':50,'b':100}, '0'),
     526            'widthratio02': ('{% widthratio a b 100 %}', {'a':0,'b':0}, ''),
     527            'widthratio03': ('{% widthratio a b 100 %}', {'a':0,'b':100}, '0'),
     528            'widthratio04': ('{% widthratio a b 100 %}', {'a':50,'b':100}, '50'),
     529            'widthratio05': ('{% widthratio a b 100 %}', {'a':100,'b':100}, '100'),
     530
     531            # 62.5 should round to 63
     532            'widthratio06': ('{% widthratio a b 100 %}', {'a':50,'b':80}, '63'),
     533
     534            # 71.4 should round to 71
     535            'widthratio07': ('{% widthratio a b 100 %}', {'a':50,'b':70}, '71'),
     536
     537            # Raise exception if we don't have 3 args, last one an integer
     538            'widthratio08': ('{% widthratio %}', {}, template.TemplateSyntaxError),
     539            'widthratio09': ('{% widthratio a b %}', {'a':50,'b':100}, template.TemplateSyntaxError),
     540            'widthratio10': ('{% widthratio a b 100.0 %}', {'a':50,'b':100}, template.TemplateSyntaxError),
     541
     542            ### NOW TAG ########################################################
     543            # Simple case
     544            'now01' : ('{% now "j n Y"%}', {}, str(datetime.now().day) + ' ' + str(datetime.now().month) + ' ' + str(datetime.now().year)),
     545
     546            # Check parsing of escaped and special characters
     547            'now02' : ('{% now "j "n" Y"%}', {}, template.TemplateSyntaxError),
     548        #    'now03' : ('{% now "j \"n\" Y"%}', {}, str(datetime.now().day) + '"' + str(datetime.now().month) + '"' + str(datetime.now().year)),
     549        #    'now04' : ('{% now "j \nn\n Y"%}', {}, str(datetime.now().day) + '\n' + str(datetime.now().month) + '\n' + str(datetime.now().year))
     550
     551            ### TIMESINCE TAG ##################################################
     552            # Default compare with datetime.now()
     553            'timesince01' : ('{{ a|timesince }}', {'a':datetime.now() + timedelta(minutes=-1, seconds = -10)}, '1 minute'),
     554            'timesince02' : ('{{ a|timesince }}', {'a':(datetime.now() - timedelta(days=1, minutes = 1))}, '1 day'),
     555            'timesince03' : ('{{ a|timesince }}', {'a':(datetime.now() -
     556                timedelta(hours=1, minutes=25, seconds = 10))}, '1 hour, 25 minutes'),
     557
     558            # Compare to a given parameter
     559            'timesince04' : ('{{ a|timesince:b }}', {'a':NOW + timedelta(days=2), 'b':NOW + timedelta(days=1)}, '1 day'),
     560            'timesince05' : ('{{ a|timesince:b }}', {'a':NOW + timedelta(days=2, minutes=1), 'b':NOW + timedelta(days=2)}, '1 minute'),
     561
     562            # Check that timezone is respected
     563            'timesince06' : ('{{ a|timesince:b }}', {'a':NOW_tz + timedelta(hours=8), 'b':NOW_tz}, '8 hours'),
     564
     565            ### TIMEUNTIL TAG ##################################################
     566            # Default compare with datetime.now()
     567            'timeuntil01' : ('{{ a|timeuntil }}', {'a':datetime.now() + timedelta(minutes=2, seconds = 10)}, '2 minutes'),
     568            'timeuntil02' : ('{{ a|timeuntil }}', {'a':(datetime.now() + timedelta(days=1, seconds = 10))}, '1 day'),
     569            'timeuntil03' : ('{{ a|timeuntil }}', {'a':(datetime.now() + timedelta(hours=8, minutes=10, seconds = 10))}, '8 hours, 10 minutes'),
     570
     571            # Compare to a given parameter
     572            'timeuntil04' : ('{{ a|timeuntil:b }}', {'a':NOW - timedelta(days=1), 'b':NOW - timedelta(days=2)}, '1 day'),
     573            'timeuntil05' : ('{{ a|timeuntil:b }}', {'a':NOW - timedelta(days=2), 'b':NOW - timedelta(days=2, minutes=1)}, '1 minute'),
     574        }
     575       
     576        # Register our custom template loader.
     577        def test_template_loader(template_name, template_dirs=None):
     578            "A custom template loader that loads the unit-test templates."
     579            try:
     580                return (TEMPLATE_TESTS[template_name][0] , "test:%s" % template_name)
     581            except KeyError:
     582                raise template.TemplateDoesNotExist, template_name
     583       
     584        old_template_loaders = loader.template_source_loaders
     585        loader.template_source_loaders = [test_template_loader]
     586   
     587        failures = []
     588        tests = TEMPLATE_TESTS.items()       
     589        tests.sort()
     590   
     591        # Turn TEMPLATE_DEBUG off, because tests assume that.
     592        old_td, settings.TEMPLATE_DEBUG = settings.TEMPLATE_DEBUG, False
     593       
     594        # Set TEMPLATE_STRING_IF_INVALID to a known string
     595        old_invalid, settings.TEMPLATE_STRING_IF_INVALID = settings.TEMPLATE_STRING_IF_INVALID, 'INVALID'
     596       
     597        for name, vals in tests:
     598            install()
     599            if 'LANGUAGE_CODE' in vals[1]:
     600                activate(vals[1]['LANGUAGE_CODE'])
     601            else:
     602                activate('en-us')
     603            try:
     604                output = loader.get_template(name).render(template.Context(vals[1]))
     605            except Exception, e:               
     606                if e.__class__ != vals[2]:
     607                    failures.append("Template test: %s -- FAILED. Got %s, exception: %s" % (name, e.__class__, e))
     608                continue
     609                               
     610            if 'LANGUAGE_CODE' in vals[1]:
     611                deactivate()
     612            if output != vals[2]:
     613                failures.append("Template test: %s -- FAILED. Expected %r, got %r" % (name, vals[2], output))
     614        loader.template_source_loaders = old_template_loaders
     615        deactivate()
     616        settings.TEMPLATE_DEBUG = old_td
     617        settings.TEMPLATE_STRING_IF_INVALID = old_invalid
     618   
     619        self.assertEqual(failures,[])
     620       
     621if __name__ == '__main__':
     622    unittest.main()
  • tests/regressiontests/urlpatterns_reverse/tests.py

     
     1"Unit tests for reverse URL lookup"
     2
     3from django.core.urlresolvers import reverse_helper, NoReverseMatch
     4import re
     5
     6test_data = (
     7    ('^places/(\d+)/$', 'places/3/', [3], {}),
     8    ('^places/(\d+)/$', 'places/3/', ['3'], {}),
     9    ('^places/(\d+)/$', NoReverseMatch, ['a'], {}),
     10    ('^places/(\d+)/$', NoReverseMatch, [], {}),
     11    ('^places/(?P<id>\d+)/$', 'places/3/', [], {'id': 3}),
     12    ('^people/(?P<name>\w+)/$', 'people/adrian/', ['adrian'], {}),
     13    ('^people/(?P<name>\w+)/$', 'people/adrian/', [], {'name': 'adrian'}),
     14    ('^people/(?P<name>\w+)/$', NoReverseMatch, ['name with spaces'], {}),
     15    ('^people/(?P<name>\w+)/$', NoReverseMatch, [], {'name': 'name with spaces'}),
     16    ('^people/(?P<name>\w+)/$', NoReverseMatch, [], {}),
     17    ('^hardcoded/$', 'hardcoded/', [], {}),
     18    ('^hardcoded/$', 'hardcoded/', ['any arg'], {}),
     19    ('^hardcoded/$', 'hardcoded/', [], {'kwarg': 'foo'}),
     20    ('^people/(?P<state>\w\w)/(?P<name>\w+)/$', 'people/il/adrian/', [], {'state': 'il', 'name': 'adrian'}),
     21    ('^people/(?P<state>\w\w)/(?P<name>\d)/$', NoReverseMatch, [], {'state': 'il', 'name': 'adrian'}),
     22    ('^people/(?P<state>\w\w)/(?P<name>\w+)/$', NoReverseMatch, [], {'state': 'il'}),
     23    ('^people/(?P<state>\w\w)/(?P<name>\w+)/$', NoReverseMatch, [], {'name': 'adrian'}),
     24    ('^people/(?P<state>\w\w)/(\w+)/$', NoReverseMatch, ['il'], {'name': 'adrian'}),
     25    ('^people/(?P<state>\w\w)/(\w+)/$', 'people/il/adrian/', ['adrian'], {'state': 'il'}),
     26)
     27
     28def run_tests(verbosity=0):
     29    for regex, expected, args, kwargs in test_data:
     30        passed = True
     31        try:
     32            got = reverse_helper(re.compile(regex), *args, **kwargs)
     33        except NoReverseMatch, e:
     34            if expected != NoReverseMatch:
     35                passed, got = False, str(e)
     36        else:
     37            if got != expected:
     38                passed, got = False, got
     39        if passed and verbosity:
     40            print "Passed: %s" % regex
     41        elif not passed:
     42            print "REVERSE LOOKUP FAILED: %s" % regex
     43            print "   Got: %s" % got
     44            print "   Expected: %r" % expected
     45
     46if __name__ == "__main__":
     47    run_tests(1)
  • tests/othertests/defaultfilters.py

     
    1 r"""
    2 >>> floatformat(7.7)
    3 '7.7'
    4 >>> floatformat(7.0)
    5 '7'
    6 >>> floatformat(0.7)
    7 '0.7'
    8 >>> floatformat(0.07)
    9 '0.1'
    10 >>> floatformat(0.007)
    11 '0.0'
    12 >>> floatformat(0.0)
    13 '0'
    14 
    15 >>> addslashes('"double quotes" and \'single quotes\'')
    16 '\\"double quotes\\" and \\\'single quotes\\\''
    17 
    18 >>> capfirst('hello world')
    19 'Hello world'
    20 
    21 >>> fix_ampersands('Jack & Jill & Jeroboam')
    22 'Jack &amp; Jill &amp; Jeroboam'
    23 
    24 >>> linenumbers('line 1\nline 2')
    25 '1. line 1\n2. line 2'
    26 
    27 >>> linenumbers('\n'.join(['x'] * 10))
    28 '01. x\n02. x\n03. x\n04. x\n05. x\n06. x\n07. x\n08. x\n09. x\n10. x'
    29 
    30 >>> lower('TEST')
    31 'test'
    32 
    33 >>> lower(u'\xcb') # uppercase E umlaut
    34 u'\xeb'
    35 
    36 >>> make_list('abc')
    37 ['a', 'b', 'c']
    38 
    39 >>> make_list(1234)
    40 ['1', '2', '3', '4']
    41 
    42 >>> slugify(' Jack & Jill like numbers 1,2,3 and 4 and silly characters ?%.$!/')
    43 'jack-jill-like-numbers-123-and-4-and-silly-characters'
    44 
    45 >>> stringformat(1, '03d')
    46 '001'
    47 
    48 >>> stringformat(1, 'z')
    49 ''
    50 
    51 >>> title('a nice title, isn\'t it?')
    52 "A Nice Title, Isn't It?"
    53 
    54 
    55 >>> truncatewords('A sentence with a few words in it', 1)
    56 'A ...'
    57 
    58 >>> truncatewords('A sentence with a few words in it', 5)
    59 'A sentence with a few ...'
    60 
    61 >>> truncatewords('A sentence with a few words in it', 100)
    62 'A sentence with a few words in it'
    63 
    64 >>> truncatewords('A sentence with a few words in it', 'not a number')
    65 'A sentence with a few words in it'
    66 
    67 
    68 >>> upper('Mixed case input')
    69 'MIXED CASE INPUT'
    70 
    71 >>> upper(u'\xeb') # lowercase e umlaut
    72 u'\xcb'
    73 
    74 
    75 >>> urlencode('jack & jill')
    76 'jack%20%26%20jill'
    77 
    78 
    79 >>> urlizetrunc('http://short.com/', 20)
    80 '<a href="http://short.com/" rel="nofollow">http://short.com/</a>'
    81 
    82 >>> urlizetrunc('http://www.google.co.uk/search?hl=en&q=some+long+url&btnG=Search&meta=', 20)
    83 '<a href="http://www.google.co.uk/search?hl=en&q=some+long+url&btnG=Search&meta=" rel="nofollow">http://www.google.co...</a>'
    84 
    85 >>> wordcount('')
    86 0
    87 
    88 >>> wordcount('oneword')
    89 1
    90 
    91 >>> wordcount('lots of words')
    92 3
    93 
    94 >>> wordwrap('this is a long paragraph of text that really needs to be wrapped I\'m afraid', 14)
    95 "this is a long\nparagraph of\ntext that\nreally needs\nto be wrapped\nI'm afraid"
    96 
    97 >>> ljust('test', 10)
    98 'test      '
    99 
    100 >>> ljust('test', 3)
    101 'test'
    102 
    103 >>> rjust('test', 10)
    104 '      test'
    105 
    106 >>> rjust('test', 3)
    107 'test'
    108 
    109 >>> center('test', 6)
    110 ' test '
    111 
    112 >>> cut('a string to be mangled', 'a')
    113 ' string to be mngled'
    114 
    115 >>> cut('a string to be mangled', 'ng')
    116 'a stri to be maled'
    117 
    118 >>> cut('a string to be mangled', 'strings')
    119 'a string to be mangled'
    120 
    121 >>> escape('<some html & special characters > here')
    122 '&lt;some html &amp; special characters &gt; here'
    123 
    124 >>> linebreaks('line 1')
    125 '<p>line 1</p>'
    126 
    127 >>> linebreaks('line 1\nline 2')
    128 '<p>line 1<br />line 2</p>'
    129 
    130 >>> removetags('some <b>html</b> with <script>alert("You smell")</script> disallowed <img /> tags', 'script img')
    131 'some <b>html</b> with alert("You smell") disallowed  tags'
    132 
    133 >>> striptags('some <b>html</b> with <script>alert("You smell")</script> disallowed <img /> tags')
    134 'some html with alert("You smell") disallowed  tags'
    135 
    136 >>> dictsort([{'age': 23, 'name': 'Barbara-Ann'},
    137 ...           {'age': 63, 'name': 'Ra Ra Rasputin'},
    138 ...           {'name': 'Jonny B Goode', 'age': 18}], 'age')
    139 [{'age': 18, 'name': 'Jonny B Goode'}, {'age': 23, 'name': 'Barbara-Ann'}, {'age': 63, 'name': 'Ra Ra Rasputin'}]
    140 
    141 >>> dictsortreversed([{'age': 23, 'name': 'Barbara-Ann'},
    142 ...           {'age': 63, 'name': 'Ra Ra Rasputin'},
    143 ...           {'name': 'Jonny B Goode', 'age': 18}], 'age')
    144 [{'age': 63, 'name': 'Ra Ra Rasputin'}, {'age': 23, 'name': 'Barbara-Ann'}, {'age': 18, 'name': 'Jonny B Goode'}]
    145 
    146 >>> first([0,1,2])
    147 0
    148 
    149 >>> first('')
    150 ''
    151 
    152 >>> first('test')
    153 't'
    154 
    155 >>> join([0,1,2], 'glue')
    156 '0glue1glue2'
    157 
    158 >>> length('1234')
    159 4
    160 
    161 >>> length([1,2,3,4])
    162 4
    163 
    164 >>> length_is([], 0)
    165 True
    166 
    167 >>> length_is([], 1)
    168 False
    169 
    170 >>> length_is('a', 1)
    171 True
    172 
    173 >>> length_is('a', 10)
    174 False
    175 
    176 >>> slice_('abcdefg', '0')
    177 ''
    178 
    179 >>> slice_('abcdefg', '1')
    180 'a'
    181 
    182 >>> slice_('abcdefg', '-1')
    183 'abcdef'
    184 
    185 >>> slice_('abcdefg', '1:2')
    186 'b'
    187 
    188 >>> slice_('abcdefg', '1:3')
    189 'bc'
    190 
    191 >>> slice_('abcdefg', '0::2')
    192 'aceg'
    193 
    194 >>> unordered_list(['item 1', []])
    195 '\t<li>item 1</li>'
    196 
    197 >>> unordered_list(['item 1', [['item 1.1', []]]])
    198 '\t<li>item 1\n\t<ul>\n\t\t<li>item 1.1</li>\n\t</ul>\n\t</li>'
    199 
    200 >>> unordered_list(['item 1', [['item 1.1', []], ['item 1.2', []]]])
    201 '\t<li>item 1\n\t<ul>\n\t\t<li>item 1.1</li>\n\t\t<li>item 1.2</li>\n\t</ul>\n\t</li>'
    202 
    203 >>> add('1', '2')
    204 3
    205 
    206 >>> get_digit(123, 1)
    207 3
    208 
    209 >>> get_digit(123, 2)
    210 2
    211 
    212 >>> get_digit(123, 3)
    213 1
    214 
    215 >>> get_digit(123, 4)
    216 0
    217 
    218 >>> get_digit(123, 0)
    219 123
    220 
    221 >>> get_digit('xyz', 0)
    222 'xyz'
    223 
    224 # real testing of date() is in dateformat.py
    225 >>> date(datetime.datetime(2005, 12, 29), "d F Y")
    226 '29 December 2005'
    227 >>> date(datetime.datetime(2005, 12, 29), r'jS o\f F')
    228 '29th of December'
    229 
    230 # real testing of time() is done in dateformat.py
    231 >>> time(datetime.time(13), "h")
    232 '01'
    233 
    234 # real testing is done in timesince.py, where we can provide our own 'now'
    235 >>> timesince(datetime.datetime.now() - datetime.timedelta(1))
    236 '1 day'
    237 
    238 >>> default("val", "default")
    239 'val'
    240 
    241 >>> default(None, "default")
    242 'default'
    243 
    244 >>> default('', "default")
    245 'default'
    246 
    247 >>> default_if_none("val", "default")
    248 'val'
    249 
    250 >>> default_if_none(None, "default")
    251 'default'
    252 
    253 >>> default_if_none('', "default")
    254 ''
    255 
    256 >>> divisibleby(4, 2)
    257 True
    258 
    259 >>> divisibleby(4, 3)
    260 False
    261 
    262 >>> yesno(True)
    263 'yes'
    264 
    265 >>> yesno(False)
    266 'no'
    267 
    268 >>> yesno(None)
    269 'maybe'
    270 
    271 >>> yesno(True, 'certainly,get out of town,perhaps')
    272 'certainly'
    273 
    274 >>> yesno(False, 'certainly,get out of town,perhaps')
    275 'get out of town'
    276 
    277 >>> yesno(None, 'certainly,get out of town,perhaps')
    278 'perhaps'
    279 
    280 >>> yesno(None, 'certainly,get out of town')
    281 'get out of town'
    282 
    283 >>> filesizeformat(1023)
    284 '1023 bytes'
    285 
    286 >>> filesizeformat(1024)
    287 '1.0 KB'
    288 
    289 >>> filesizeformat(10*1024)
    290 '10.0 KB'
    291 
    292 >>> filesizeformat(1024*1024-1)
    293 '1024.0 KB'
    294 
    295 >>> filesizeformat(1024*1024)
    296 '1.0 MB'
    297 
    298 >>> filesizeformat(1024*1024*50)
    299 '50.0 MB'
    300 
    301 >>> filesizeformat(1024*1024*1024-1)
    302 '1024.0 MB'
    303 
    304 >>> filesizeformat(1024*1024*1024)
    305 '1.0 GB'
    306 
    307 >>> pluralize(1)
    308 ''
    309 
    310 >>> pluralize(0)
    311 's'
    312 
    313 >>> pluralize(2)
    314 's'
    315 
    316 >>> pluralize([1])
    317 ''
    318 
    319 >>> pluralize([])
    320 's'
    321 
    322 >>> pluralize([1,2,3])
    323 's'
    324 
    325 >>> pluralize(1,'es')
    326 ''
    327 
    328 >>> pluralize(0,'es')
    329 'es'
    330 
    331 >>> pluralize(2,'es')
    332 'es'
    333 
    334 >>> pluralize(1,'y,ies')
    335 'y'
    336 
    337 >>> pluralize(0,'y,ies')
    338 'ies'
    339 
    340 >>> pluralize(2,'y,ies')
    341 'ies'
    342 
    343 >>> pluralize(0,'y,ies,error')
    344 ''
    345 
    346 >>> phone2numeric('0800 flowers')
    347 '0800 3569377'
    348 
    349 
    350 
    351 """
    352 
    353 from django.template.defaultfilters import *
    354 import datetime
    355 
    356 if __name__ == '__main__':
    357     import doctest
    358     doctest.testmod()
  • tests/othertests/templates.py

     
    1 from django.conf import settings
    2 
    3 if __name__ == '__main__':
    4     # When running this file in isolation, we need to set up the configuration
    5     # before importing 'template'.
    6     settings.configure()
    7 
    8 from django import template
    9 from django.template import loader
    10 from django.utils.translation import activate, deactivate, install
    11 from django.utils.tzinfo import LocalTimezone
    12 from datetime import datetime, timedelta
    13 import traceback
    14 
    15 #################################
    16 # Custom template tag for tests #
    17 #################################
    18 
    19 register = template.Library()
    20 
    21 class EchoNode(template.Node):
    22     def __init__(self, contents):
    23         self.contents = contents
    24 
    25     def render(self, context):
    26         return " ".join(self.contents)
    27 
    28 def do_echo(parser, token):
    29     return EchoNode(token.contents.split()[1:])
    30 
    31 register.tag("echo", do_echo)
    32 
    33 template.libraries['django.templatetags.testtags'] = register
    34 
    35 #####################################
    36 # Helper objects for template tests #
    37 #####################################
    38 
    39 class SomeException(Exception):
    40     silent_variable_failure = True
    41 
    42 class SomeOtherException(Exception):
    43     pass
    44 
    45 class SomeClass:
    46     def __init__(self):
    47         self.otherclass = OtherClass()
    48 
    49     def method(self):
    50         return "SomeClass.method"
    51 
    52     def method2(self, o):
    53         return o
    54 
    55     def method3(self):
    56         raise SomeException
    57 
    58     def method4(self):
    59         raise SomeOtherException
    60 
    61 class OtherClass:
    62     def method(self):
    63         return "OtherClass.method"
    64 
    65 # NOW and NOW_tz are used by timesince tag tests.
    66 NOW = datetime.now()
    67 NOW_tz = datetime.now(LocalTimezone(datetime.now()))
    68 
    69 # SYNTAX --
    70 # 'template_name': ('template contents', 'context dict', 'expected string output' or Exception class)
    71 TEMPLATE_TESTS = {
    72 
    73     ### BASIC SYNTAX ##########################################################
    74 
    75     # Plain text should go through the template parser untouched
    76     'basic-syntax01': ("something cool", {}, "something cool"),
    77 
    78     # Variables should be replaced with their value in the current context
    79     'basic-syntax02': ("{{ headline }}", {'headline':'Success'}, "Success"),
    80 
    81     # More than one replacement variable is allowed in a template
    82     'basic-syntax03': ("{{ first }} --- {{ second }}", {"first" : 1, "second" : 2}, "1 --- 2"),
    83 
    84     # Fail silently when a variable is not found in the current context
    85     'basic-syntax04': ("as{{ missing }}df", {}, "asINVALIDdf"),
    86 
    87     # A variable may not contain more than one word
    88     'basic-syntax06': ("{{ multi word variable }}", {}, template.TemplateSyntaxError),
    89 
    90     # Raise TemplateSyntaxError for empty variable tags
    91     'basic-syntax07': ("{{ }}",        {}, template.TemplateSyntaxError),
    92     'basic-syntax08': ("{{        }}", {}, template.TemplateSyntaxError),
    93 
    94     # Attribute syntax allows a template to call an object's attribute
    95     'basic-syntax09': ("{{ var.method }}", {"var": SomeClass()}, "SomeClass.method"),
    96 
    97     # Multiple levels of attribute access are allowed
    98     'basic-syntax10': ("{{ var.otherclass.method }}", {"var": SomeClass()}, "OtherClass.method"),
    99 
    100     # Fail silently when a variable's attribute isn't found
    101     'basic-syntax11': ("{{ var.blech }}", {"var": SomeClass()}, "INVALID"),
    102 
    103     # Raise TemplateSyntaxError when trying to access a variable beginning with an underscore
    104     'basic-syntax12': ("{{ var.__dict__ }}", {"var": SomeClass()}, template.TemplateSyntaxError),
    105 
    106     # Raise TemplateSyntaxError when trying to access a variable containing an illegal character
    107     'basic-syntax13': ("{{ va>r }}", {}, template.TemplateSyntaxError),
    108     'basic-syntax14': ("{{ (var.r) }}", {}, template.TemplateSyntaxError),
    109     'basic-syntax15': ("{{ sp%am }}", {}, template.TemplateSyntaxError),
    110     'basic-syntax16': ("{{ eggs! }}", {}, template.TemplateSyntaxError),
    111     'basic-syntax17': ("{{ moo? }}", {}, template.TemplateSyntaxError),
    112 
    113     # Attribute syntax allows a template to call a dictionary key's value
    114     'basic-syntax18': ("{{ foo.bar }}", {"foo" : {"bar" : "baz"}}, "baz"),
    115 
    116     # Fail silently when a variable's dictionary key isn't found
    117     'basic-syntax19': ("{{ foo.spam }}", {"foo" : {"bar" : "baz"}}, "INVALID"),
    118 
    119     # Fail silently when accessing a non-simple method
    120     'basic-syntax20': ("{{ var.method2 }}", {"var": SomeClass()}, "INVALID"),
    121 
    122     # Basic filter usage
    123     'basic-syntax21': ("{{ var|upper }}", {"var": "Django is the greatest!"}, "DJANGO IS THE GREATEST!"),
    124 
    125     # Chained filters
    126     'basic-syntax22': ("{{ var|upper|lower }}", {"var": "Django is the greatest!"}, "django is the greatest!"),
    127 
    128     # Raise TemplateSyntaxError for space between a variable and filter pipe
    129     'basic-syntax23': ("{{ var |upper }}", {}, template.TemplateSyntaxError),
    130 
    131     # Raise TemplateSyntaxError for space after a filter pipe
    132     'basic-syntax24': ("{{ var| upper }}", {}, template.TemplateSyntaxError),
    133 
    134     # Raise TemplateSyntaxError for a nonexistent filter
    135     'basic-syntax25': ("{{ var|does_not_exist }}", {}, template.TemplateSyntaxError),
    136 
    137     # Raise TemplateSyntaxError when trying to access a filter containing an illegal character
    138     'basic-syntax26': ("{{ var|fil(ter) }}", {}, template.TemplateSyntaxError),
    139 
    140     # Raise TemplateSyntaxError for invalid block tags
    141     'basic-syntax27': ("{% nothing_to_see_here %}", {}, template.TemplateSyntaxError),
    142 
    143     # Raise TemplateSyntaxError for empty block tags
    144     'basic-syntax28': ("{% %}", {}, template.TemplateSyntaxError),
    145 
    146     # Chained filters, with an argument to the first one
    147     'basic-syntax29': ('{{ var|removetags:"b i"|upper|lower }}', {"var": "<b><i>Yes</i></b>"}, "yes"),
    148 
    149     # Escaped string as argument
    150     'basic-syntax30': (r'{{ var|default_if_none:" endquote\" hah" }}', {"var": None}, ' endquote" hah'),
    151 
    152     # Variable as argument
    153     'basic-syntax31': (r'{{ var|default_if_none:var2 }}', {"var": None, "var2": "happy"}, 'happy'),
    154 
    155     # Default argument testing
    156     'basic-syntax32': (r'{{ var|yesno:"yup,nup,mup" }} {{ var|yesno }}', {"var": True}, 'yup yes'),
    157 
    158     # Fail silently for methods that raise an exception with a "silent_variable_failure" attribute
    159     'basic-syntax33': (r'1{{ var.method3 }}2', {"var": SomeClass()}, "1INVALID2"),
    160 
    161     # In methods that raise an exception without a "silent_variable_attribute" set to True,
    162     # the exception propogates
    163     'basic-syntax34': (r'1{{ var.method4 }}2', {"var": SomeClass()}, SomeOtherException),
    164 
    165     # Escaped backslash in argument
    166     'basic-syntax35': (r'{{ var|default_if_none:"foo\bar" }}', {"var": None}, r'foo\bar'),
    167 
    168     # Escaped backslash using known escape char
    169     'basic-syntax35': (r'{{ var|default_if_none:"foo\now" }}', {"var": None}, r'foo\now'),
    170 
    171     ### COMMENT TAG ###########################################################
    172     'comment-tag01': ("{% comment %}this is hidden{% endcomment %}hello", {}, "hello"),
    173     'comment-tag02': ("{% comment %}this is hidden{% endcomment %}hello{% comment %}foo{% endcomment %}", {}, "hello"),
    174 
    175     # Comment tag can contain invalid stuff.
    176     'comment-tag03': ("foo{% comment %} {% if %} {% endcomment %}", {}, "foo"),
    177     'comment-tag04': ("foo{% comment %} {% endblock %} {% endcomment %}", {}, "foo"),
    178     'comment-tag05': ("foo{% comment %} {% somerandomtag %} {% endcomment %}", {}, "foo"),
    179 
    180     ### CYCLE TAG #############################################################
    181     'cycle01': ('{% cycle a %}', {}, template.TemplateSyntaxError),
    182     'cycle02': ('{% cycle a,b,c as abc %}{% cycle abc %}', {}, 'ab'),
    183     'cycle03': ('{% cycle a,b,c as abc %}{% cycle abc %}{% cycle abc %}', {}, 'abc'),
    184     'cycle04': ('{% cycle a,b,c as abc %}{% cycle abc %}{% cycle abc %}{% cycle abc %}', {}, 'abca'),
    185     'cycle05': ('{% cycle %}', {}, template.TemplateSyntaxError),
    186     'cycle06': ('{% cycle a %}', {}, template.TemplateSyntaxError),
    187     'cycle07': ('{% cycle a,b,c as foo %}{% cycle bar %}', {}, template.TemplateSyntaxError),
    188 
    189     ### EXCEPTIONS ############################################################
    190 
    191     # Raise exception for invalid template name
    192     'exception01': ("{% extends 'nonexistent' %}", {}, template.TemplateSyntaxError),
    193 
    194     # Raise exception for invalid template name (in variable)
    195     'exception02': ("{% extends nonexistent %}", {}, template.TemplateSyntaxError),
    196 
    197     # Raise exception for extra {% extends %} tags
    198     'exception03': ("{% extends 'inheritance01' %}{% block first %}2{% endblock %}{% extends 'inheritance16' %}", {}, template.TemplateSyntaxError),
    199 
    200     # Raise exception for custom tags used in child with {% load %} tag in parent, not in child
    201     'exception04': ("{% extends 'inheritance17' %}{% block first %}{% echo 400 %}5678{% endblock %}", {}, template.TemplateSyntaxError),
    202 
    203     ### FILTER TAG ############################################################
    204     'filter01': ('{% filter upper %}{% endfilter %}', {}, ''),
    205     'filter02': ('{% filter upper %}django{% endfilter %}', {}, 'DJANGO'),
    206     'filter03': ('{% filter upper|lower %}django{% endfilter %}', {}, 'django'),
    207 
    208     ### FIRSTOF TAG ###########################################################
    209     'firstof01': ('{% firstof a b c %}', {'a':0,'b':0,'c':0}, ''),
    210     'firstof02': ('{% firstof a b c %}', {'a':1,'b':0,'c':0}, '1'),
    211     'firstof03': ('{% firstof a b c %}', {'a':0,'b':2,'c':0}, '2'),
    212     'firstof04': ('{% firstof a b c %}', {'a':0,'b':0,'c':3}, '3'),
    213     'firstof05': ('{% firstof a b c %}', {'a':1,'b':2,'c':3}, '1'),
    214     'firstof06': ('{% firstof %}', {}, template.TemplateSyntaxError),
    215 
    216     ### FOR TAG ###############################################################
    217     'for-tag01': ("{% for val in values %}{{ val }}{% endfor %}", {"values": [1, 2, 3]}, "123"),
    218     'for-tag02': ("{% for val in values reversed %}{{ val }}{% endfor %}", {"values": [1, 2, 3]}, "321"),
    219     'for-tag-vars01': ("{% for val in values %}{{ forloop.counter }}{% endfor %}", {"values": [6, 6, 6]}, "123"),
    220     'for-tag-vars02': ("{% for val in values %}{{ forloop.counter0 }}{% endfor %}", {"values": [6, 6, 6]}, "012"),
    221     'for-tag-vars03': ("{% for val in values %}{{ forloop.revcounter }}{% endfor %}", {"values": [6, 6, 6]}, "321"),
    222     'for-tag-vars04': ("{% for val in values %}{{ forloop.revcounter0 }}{% endfor %}", {"values": [6, 6, 6]}, "210"),
    223 
    224     ### IF TAG ################################################################
    225     'if-tag01': ("{% if foo %}yes{% else %}no{% endif %}", {"foo": True}, "yes"),
    226     'if-tag02': ("{% if foo %}yes{% else %}no{% endif %}", {"foo": False}, "no"),
    227     'if-tag03': ("{% if foo %}yes{% else %}no{% endif %}", {}, "no"),
    228 
    229     # AND
    230     'if-tag-and01': ("{% if foo and bar %}yes{% else %}no{% endif %}", {'foo': True, 'bar': True}, 'yes'),
    231     'if-tag-and02': ("{% if foo and bar %}yes{% else %}no{% endif %}", {'foo': True, 'bar': False}, 'no'),
    232     'if-tag-and03': ("{% if foo and bar %}yes{% else %}no{% endif %}", {'foo': False, 'bar': True}, 'no'),
    233     'if-tag-and04': ("{% if foo and bar %}yes{% else %}no{% endif %}", {'foo': False, 'bar': False}, 'no'),
    234     'if-tag-and05': ("{% if foo and bar %}yes{% else %}no{% endif %}", {'foo': False}, 'no'),
    235     'if-tag-and06': ("{% if foo and bar %}yes{% else %}no{% endif %}", {'bar': False}, 'no'),
    236     'if-tag-and07': ("{% if foo and bar %}yes{% else %}no{% endif %}", {'foo': True}, 'no'),
    237     'if-tag-and08': ("{% if foo and bar %}yes{% else %}no{% endif %}", {'bar': True}, 'no'),
    238 
    239     # OR
    240     'if-tag-or01': ("{% if foo or bar %}yes{% else %}no{% endif %}", {'foo': True, 'bar': True}, 'yes'),
    241     'if-tag-or02': ("{% if foo or bar %}yes{% else %}no{% endif %}", {'foo': True, 'bar': False}, 'yes'),
    242     'if-tag-or03': ("{% if foo or bar %}yes{% else %}no{% endif %}", {'foo': False, 'bar': True}, 'yes'),
    243     'if-tag-or04': ("{% if foo or bar %}yes{% else %}no{% endif %}", {'foo': False, 'bar': False}, 'no'),
    244     'if-tag-or05': ("{% if foo or bar %}yes{% else %}no{% endif %}", {'foo': False}, 'no'),
    245     'if-tag-or06': ("{% if foo or bar %}yes{% else %}no{% endif %}", {'bar': False}, 'no'),
    246     'if-tag-or07': ("{% if foo or bar %}yes{% else %}no{% endif %}", {'foo': True}, 'yes'),
    247     'if-tag-or08': ("{% if foo or bar %}yes{% else %}no{% endif %}", {'bar': True}, 'yes'),
    248 
    249     # TODO: multiple ORs
    250 
    251     # NOT
    252     'if-tag-not01': ("{% if not foo %}no{% else %}yes{% endif %}", {'foo': True}, 'yes'),
    253     'if-tag-not02': ("{% if not %}yes{% else %}no{% endif %}", {'foo': True}, 'no'),
    254     'if-tag-not03': ("{% if not %}yes{% else %}no{% endif %}", {'not': True}, 'yes'),
    255     'if-tag-not04': ("{% if not not %}no{% else %}yes{% endif %}", {'not': True}, 'yes'),
    256     'if-tag-not05': ("{% if not not %}no{% else %}yes{% endif %}", {}, 'no'),
    257 
    258     'if-tag-not06': ("{% if foo and not bar %}yes{% else %}no{% endif %}", {}, 'no'),
    259     'if-tag-not07': ("{% if foo and not bar %}yes{% else %}no{% endif %}", {'foo': True, 'bar': True}, 'no'),
    260     'if-tag-not08': ("{% if foo and not bar %}yes{% else %}no{% endif %}", {'foo': True, 'bar': False}, 'yes'),
    261     'if-tag-not09': ("{% if foo and not bar %}yes{% else %}no{% endif %}", {'foo': False, 'bar': True}, 'no'),
    262     'if-tag-not10': ("{% if foo and not bar %}yes{% else %}no{% endif %}", {'foo': False, 'bar': False}, 'no'),
    263 
    264     'if-tag-not11': ("{% if not foo and bar %}yes{% else %}no{% endif %}", {}, 'no'),
    265     'if-tag-not12': ("{% if not foo and bar %}yes{% else %}no{% endif %}", {'foo': True, 'bar': True}, 'no'),
    266     'if-tag-not13': ("{% if not foo and bar %}yes{% else %}no{% endif %}", {'foo': True, 'bar': False}, 'no'),
    267     'if-tag-not14': ("{% if not foo and bar %}yes{% else %}no{% endif %}", {'foo': False, 'bar': True}, 'yes'),
    268     'if-tag-not15': ("{% if not foo and bar %}yes{% else %}no{% endif %}", {'foo': False, 'bar': False}, 'no'),
    269 
    270     'if-tag-not16': ("{% if foo or not bar %}yes{% else %}no{% endif %}", {}, 'yes'),
    271     'if-tag-not17': ("{% if foo or not bar %}yes{% else %}no{% endif %}", {'foo': True, 'bar': True}, 'yes'),
    272     'if-tag-not18': ("{% if foo or not bar %}yes{% else %}no{% endif %}", {'foo': True, 'bar': False}, 'yes'),
    273     'if-tag-not19': ("{% if foo or not bar %}yes{% else %}no{% endif %}", {'foo': False, 'bar': True}, 'no'),
    274     'if-tag-not20': ("{% if foo or not bar %}yes{% else %}no{% endif %}", {'foo': False, 'bar': False}, 'yes'),
    275 
    276     'if-tag-not21': ("{% if not foo or bar %}yes{% else %}no{% endif %}", {}, 'yes'),
    277     'if-tag-not22': ("{% if not foo or bar %}yes{% else %}no{% endif %}", {'foo': True, 'bar': True}, 'yes'),
    278     'if-tag-not23': ("{% if not foo or bar %}yes{% else %}no{% endif %}", {'foo': True, 'bar': False}, 'no'),
    279     'if-tag-not24': ("{% if not foo or bar %}yes{% else %}no{% endif %}", {'foo': False, 'bar': True}, 'yes'),
    280     'if-tag-not25': ("{% if not foo or bar %}yes{% else %}no{% endif %}", {'foo': False, 'bar': False}, 'yes'),
    281 
    282     'if-tag-not26': ("{% if not foo and not bar %}yes{% else %}no{% endif %}", {}, 'yes'),
    283     'if-tag-not27': ("{% if not foo and not bar %}yes{% else %}no{% endif %}", {'foo': True, 'bar': True}, 'no'),
    284     'if-tag-not28': ("{% if not foo and not bar %}yes{% else %}no{% endif %}", {'foo': True, 'bar': False}, 'no'),
    285     'if-tag-not29': ("{% if not foo and not bar %}yes{% else %}no{% endif %}", {'foo': False, 'bar': True}, 'no'),
    286     'if-tag-not30': ("{% if not foo and not bar %}yes{% else %}no{% endif %}", {'foo': False, 'bar': False}, 'yes'),
    287 
    288     'if-tag-not31': ("{% if not foo or not bar %}yes{% else %}no{% endif %}", {}, 'yes'),
    289     'if-tag-not32': ("{% if not foo or not bar %}yes{% else %}no{% endif %}", {'foo': True, 'bar': True}, 'no'),
    290     'if-tag-not33': ("{% if not foo or not bar %}yes{% else %}no{% endif %}", {'foo': True, 'bar': False}, 'yes'),
    291     'if-tag-not34': ("{% if not foo or not bar %}yes{% else %}no{% endif %}", {'foo': False, 'bar': True}, 'yes'),
    292     'if-tag-not35': ("{% if not foo or not bar %}yes{% else %}no{% endif %}", {'foo': False, 'bar': False}, 'yes'),
    293 
    294     # AND and OR raises a TemplateSyntaxError
    295     'if-tag-error01': ("{% if foo or bar and baz %}yes{% else %}no{% endif %}", {'foo': False, 'bar': False}, template.TemplateSyntaxError),
    296     'if-tag-error02': ("{% if foo and %}yes{% else %}no{% endif %}", {'foo': True}, template.TemplateSyntaxError),
    297     'if-tag-error03': ("{% if foo or %}yes{% else %}no{% endif %}", {'foo': True}, template.TemplateSyntaxError),
    298     'if-tag-error04': ("{% if not foo and %}yes{% else %}no{% endif %}", {'foo': True}, template.TemplateSyntaxError),
    299     'if-tag-error05': ("{% if not foo or %}yes{% else %}no{% endif %}", {'foo': True}, template.TemplateSyntaxError),
    300 
    301     ### IFCHANGED TAG #########################################################
    302     'ifchanged01': ('{% for n in num %}{% ifchanged %}{{ n }}{% endifchanged %}{% endfor %}', { 'num': (1,2,3) }, '123'),
    303     'ifchanged02': ('{% for n in num %}{% ifchanged %}{{ n }}{% endifchanged %}{% endfor %}', { 'num': (1,1,3) }, '13'),
    304     'ifchanged03': ('{% for n in num %}{% ifchanged %}{{ n }}{% endifchanged %}{% endfor %}', { 'num': (1,1,1) }, '1'),
    305 
    306     ### IFEQUAL TAG ###########################################################
    307     'ifequal01': ("{% ifequal a b %}yes{% endifequal %}", {"a": 1, "b": 2}, ""),
    308     'ifequal02': ("{% ifequal a b %}yes{% endifequal %}", {"a": 1, "b": 1}, "yes"),
    309     'ifequal03': ("{% ifequal a b %}yes{% else %}no{% endifequal %}", {"a": 1, "b": 2}, "no"),
    310     'ifequal04': ("{% ifequal a b %}yes{% else %}no{% endifequal %}", {"a": 1, "b": 1}, "yes"),
    311     'ifequal05': ("{% ifequal a 'test' %}yes{% else %}no{% endifequal %}", {"a": "test"}, "yes"),
    312     'ifequal06': ("{% ifequal a 'test' %}yes{% else %}no{% endifequal %}", {"a": "no"}, "no"),
    313     'ifequal07': ('{% ifequal a "test" %}yes{% else %}no{% endifequal %}', {"a": "test"}, "yes"),
    314     'ifequal08': ('{% ifequal a "test" %}yes{% else %}no{% endifequal %}', {"a": "no"}, "no"),
    315     'ifequal09': ('{% ifequal a "test" %}yes{% else %}no{% endifequal %}', {}, "no"),
    316     'ifequal10': ('{% ifequal a b %}yes{% else %}no{% endifequal %}', {}, "yes"),
    317 
    318     # SMART SPLITTING
    319     'ifequal-split01': ('{% ifequal a "test man" %}yes{% else %}no{% endifequal %}', {}, "no"),
    320     'ifequal-split02': ('{% ifequal a "test man" %}yes{% else %}no{% endifequal %}', {'a': 'foo'}, "no"),
    321     'ifequal-split03': ('{% ifequal a "test man" %}yes{% else %}no{% endifequal %}', {'a': 'test man'}, "yes"),
    322     'ifequal-split04': ("{% ifequal a 'test man' %}yes{% else %}no{% endifequal %}", {'a': 'test man'}, "yes"),
    323     'ifequal-split05': ("{% ifequal a 'i \"love\" you' %}yes{% else %}no{% endifequal %}", {'a': ''}, "no"),
    324     'ifequal-split06': ("{% ifequal a 'i \"love\" you' %}yes{% else %}no{% endifequal %}", {'a': 'i "love" you'}, "yes"),
    325     'ifequal-split07': ("{% ifequal a 'i \"love\" you' %}yes{% else %}no{% endifequal %}", {'a': 'i love you'}, "no"),
    326     'ifequal-split08': (r"{% ifequal a 'I\'m happy' %}yes{% else %}no{% endifequal %}", {'a': "I'm happy"}, "yes"),
    327     'ifequal-split09': (r"{% ifequal a 'slash\man' %}yes{% else %}no{% endifequal %}", {'a': r"slash\man"}, "yes"),
    328     'ifequal-split10': (r"{% ifequal a 'slash\man' %}yes{% else %}no{% endifequal %}", {'a': r"slashman"}, "no"),
    329 
    330     ### IFNOTEQUAL TAG ########################################################
    331     'ifnotequal01': ("{% ifnotequal a b %}yes{% endifnotequal %}", {"a": 1, "b": 2}, "yes"),
    332     'ifnotequal02': ("{% ifnotequal a b %}yes{% endifnotequal %}", {"a": 1, "b": 1}, ""),
    333     'ifnotequal03': ("{% ifnotequal a b %}yes{% else %}no{% endifnotequal %}", {"a": 1, "b": 2}, "yes"),
    334     'ifnotequal04': ("{% ifnotequal a b %}yes{% else %}no{% endifnotequal %}", {"a": 1, "b": 1}, "no"),
    335 
    336     ### INCLUDE TAG ###########################################################
    337     'include01': ('{% include "basic-syntax01" %}', {}, "something cool"),
    338     'include02': ('{% include "basic-syntax02" %}', {'headline': 'Included'}, "Included"),
    339     'include03': ('{% include template_name %}', {'template_name': 'basic-syntax02', 'headline': 'Included'}, "Included"),
    340     'include04': ('a{% include "nonexistent" %}b', {}, "ab"),
    341 
    342     ### INHERITANCE ###########################################################
    343 
    344     # Standard template with no inheritance
    345     'inheritance01': ("1{% block first %}_{% endblock %}3{% block second %}_{% endblock %}", {}, '1_3_'),
    346 
    347     # Standard two-level inheritance
    348     'inheritance02': ("{% extends 'inheritance01' %}{% block first %}2{% endblock %}{% block second %}4{% endblock %}", {}, '1234'),
    349 
    350     # Three-level with no redefinitions on third level
    351     'inheritance03': ("{% extends 'inheritance02' %}", {}, '1234'),
    352 
    353     # Two-level with no redefinitions on second level
    354     'inheritance04': ("{% extends 'inheritance01' %}", {}, '1_3_'),
    355 
    356     # Two-level with double quotes instead of single quotes
    357     'inheritance05': ('{% extends "inheritance02" %}', {}, '1234'),
    358 
    359     # Three-level with variable parent-template name
    360     'inheritance06': ("{% extends foo %}", {'foo': 'inheritance02'}, '1234'),
    361 
    362     # Two-level with one block defined, one block not defined
    363     'inheritance07': ("{% extends 'inheritance01' %}{% block second %}5{% endblock %}", {}, '1_35'),
    364 
    365     # Three-level with one block defined on this level, two blocks defined next level
    366     'inheritance08': ("{% extends 'inheritance02' %}{% block second %}5{% endblock %}", {}, '1235'),
    367 
    368     # Three-level with second and third levels blank
    369     'inheritance09': ("{% extends 'inheritance04' %}", {}, '1_3_'),
    370 
    371     # Three-level with space NOT in a block -- should be ignored
    372     'inheritance10': ("{% extends 'inheritance04' %}      ", {}, '1_3_'),
    373 
    374     # Three-level with both blocks defined on this level, but none on second level
    375     'inheritance11': ("{% extends 'inheritance04' %}{% block first %}2{% endblock %}{% block second %}4{% endblock %}", {}, '1234'),
    376 
    377     # Three-level with this level providing one and second level providing the other
    378     'inheritance12': ("{% extends 'inheritance07' %}{% block first %}2{% endblock %}", {}, '1235'),
    379 
    380     # Three-level with this level overriding second level
    381     'inheritance13': ("{% extends 'inheritance02' %}{% block first %}a{% endblock %}{% block second %}b{% endblock %}", {}, '1a3b'),
    382 
    383     # A block defined only in a child template shouldn't be displayed
    384     'inheritance14': ("{% extends 'inheritance01' %}{% block newblock %}NO DISPLAY{% endblock %}", {}, '1_3_'),
    385 
    386     # A block within another block
    387     'inheritance15': ("{% extends 'inheritance01' %}{% block first %}2{% block inner %}inner{% endblock %}{% endblock %}", {}, '12inner3_'),
    388 
    389     # A block within another block (level 2)
    390     'inheritance16': ("{% extends 'inheritance15' %}{% block inner %}out{% endblock %}", {}, '12out3_'),
    391 
    392     # {% load %} tag (parent -- setup for exception04)
    393     'inheritance17': ("{% load testtags %}{% block first %}1234{% endblock %}", {}, '1234'),
    394 
    395     # {% load %} tag (standard usage, without inheritance)
    396     'inheritance18': ("{% load testtags %}{% echo this that theother %}5678", {}, 'this that theother5678'),
    397 
    398     # {% load %} tag (within a child template)
    399     'inheritance19': ("{% extends 'inheritance01' %}{% block first %}{% load testtags %}{% echo 400 %}5678{% endblock %}", {}, '140056783_'),
    400 
    401     # Two-level inheritance with {{ block.super }}
    402     'inheritance20': ("{% extends 'inheritance01' %}{% block first %}{{ block.super }}a{% endblock %}", {}, '1_a3_'),
    403 
    404     # Three-level inheritance with {{ block.super }} from parent
    405     'inheritance21': ("{% extends 'inheritance02' %}{% block first %}{{ block.super }}a{% endblock %}", {}, '12a34'),
    406 
    407     # Three-level inheritance with {{ block.super }} from grandparent
    408     'inheritance22': ("{% extends 'inheritance04' %}{% block first %}{{ block.super }}a{% endblock %}", {}, '1_a3_'),
    409 
    410     # Three-level inheritance with {{ block.super }} from parent and grandparent
    411     'inheritance23': ("{% extends 'inheritance20' %}{% block first %}{{ block.super }}b{% endblock %}", {}, '1_ab3_'),
    412 
    413     # Inheritance from local context without use of template loader
    414     'inheritance24': ("{% extends context_template %}{% block first %}2{% endblock %}{% block second %}4{% endblock %}", {'context_template': template.Template("1{% block first %}_{% endblock %}3{% block second %}_{% endblock %}")}, '1234'),
    415 
    416     # Inheritance from local context with variable parent template
    417     'inheritance25': ("{% extends context_template.1 %}{% block first %}2{% endblock %}{% block second %}4{% endblock %}", {'context_template': [template.Template("Wrong"), template.Template("1{% block first %}_{% endblock %}3{% block second %}_{% endblock %}")]}, '1234'),
    418 
    419     ### I18N ##################################################################
    420 
    421     # {% spaceless %} tag
    422     'spaceless01': ("{% spaceless %} <b>    <i> text </i>    </b> {% endspaceless %}", {}, "<b> <i> text </i> </b>"),
    423     'spaceless02': ("{% spaceless %} <b> \n <i> text </i> \n </b> {% endspaceless %}", {}, "<b> <i> text </i> </b>"),
    424     'spaceless03': ("{% spaceless %}<b><i>text</i></b>{% endspaceless %}", {}, "<b><i>text</i></b>"),
    425 
    426     # simple translation of a string delimited by '
    427     'i18n01': ("{% load i18n %}{% trans 'xxxyyyxxx' %}", {}, "xxxyyyxxx"),
    428 
    429     # simple translation of a string delimited by "
    430     'i18n02': ('{% load i18n %}{% trans "xxxyyyxxx" %}', {}, "xxxyyyxxx"),
    431 
    432     # simple translation of a variable
    433     'i18n03': ('{% load i18n %}{% blocktrans %}{{ anton }}{% endblocktrans %}', {'anton': 'xxxyyyxxx'}, "xxxyyyxxx"),
    434 
    435     # simple translation of a variable and filter
    436     'i18n04': ('{% load i18n %}{% blocktrans with anton|lower as berta %}{{ berta }}{% endblocktrans %}', {'anton': 'XXXYYYXXX'}, "xxxyyyxxx"),
    437 
    438     # simple translation of a string with interpolation
    439     'i18n05': ('{% load i18n %}{% blocktrans %}xxx{{ anton }}xxx{% endblocktrans %}', {'anton': 'yyy'}, "xxxyyyxxx"),
    440 
    441     # simple translation of a string to german
    442     'i18n06': ('{% load i18n %}{% trans "Page not found" %}', {'LANGUAGE_CODE': 'de'}, "Seite nicht gefunden"),
    443 
    444     # translation of singular form
    445     'i18n07': ('{% load i18n %}{% blocktrans count number as counter %}singular{% plural %}plural{% endblocktrans %}', {'number': 1}, "singular"),
    446 
    447     # translation of plural form
    448     'i18n08': ('{% load i18n %}{% blocktrans count number as counter %}singular{% plural %}plural{% endblocktrans %}', {'number': 2}, "plural"),
    449 
    450     # simple non-translation (only marking) of a string to german
    451     'i18n09': ('{% load i18n %}{% trans "Page not found" noop %}', {'LANGUAGE_CODE': 'de'}, "Page not found"),
    452 
    453     # translation of a variable with a translated filter
    454     'i18n10': ('{{ bool|yesno:_("ja,nein") }}', {'bool': True}, 'ja'),
    455 
    456     # translation of a variable with a non-translated filter
    457     'i18n11': ('{{ bool|yesno:"ja,nein" }}', {'bool': True}, 'ja'),
    458 
    459     # usage of the get_available_languages tag
    460     'i18n12': ('{% load i18n %}{% get_available_languages as langs %}{% for lang in langs %}{% ifequal lang.0 "de" %}{{ lang.0 }}{% endifequal %}{% endfor %}', {}, 'de'),
    461 
    462     # translation of a constant string
    463     'i18n13': ('{{ _("Page not found") }}', {'LANGUAGE_CODE': 'de'}, 'Seite nicht gefunden'),
    464 
    465     ### MULTILINE #############################################################
    466 
    467     'multiline01': ("""
    468                     Hello,
    469                     boys.
    470                     How
    471                     are
    472                     you
    473                     gentlemen.
    474                     """,
    475                     {},
    476                     """
    477                     Hello,
    478                     boys.
    479                     How
    480                     are
    481                     you
    482                     gentlemen.
    483                     """),
    484 
    485     ### REGROUP TAG ###########################################################
    486     'regroup01': ('{% regroup data by bar as grouped %}' + \
    487                   '{% for group in grouped %}' + \
    488                   '{{ group.grouper }}:' + \
    489                   '{% for item in group.list %}' + \
    490                   '{{ item.foo }}' + \
    491                   '{% endfor %},' + \
    492                   '{% endfor %}',
    493                   {'data': [ {'foo':'c', 'bar':1},
    494                              {'foo':'d', 'bar':1},
    495                              {'foo':'a', 'bar':2},
    496                              {'foo':'b', 'bar':2},
    497                              {'foo':'x', 'bar':3}  ]},
    498                   '1:cd,2:ab,3:x,'),
    499 
    500     # Test for silent failure when target variable isn't found
    501     'regroup02': ('{% regroup data by bar as grouped %}' + \
    502                   '{% for group in grouped %}' + \
    503                   '{{ group.grouper }}:' + \
    504                   '{% for item in group.list %}' + \
    505                   '{{ item.foo }}' + \
    506                   '{% endfor %},' + \
    507                   '{% endfor %}',
    508                   {}, 'INVALID:INVALIDINVALIDINVALIDINVALIDINVALIDINVALIDINVALID,'),
    509 
    510     ### TEMPLATETAG TAG #######################################################
    511     'templatetag01': ('{% templatetag openblock %}', {}, '{%'),
    512     'templatetag02': ('{% templatetag closeblock %}', {}, '%}'),
    513     'templatetag03': ('{% templatetag openvariable %}', {}, '{{'),
    514     'templatetag04': ('{% templatetag closevariable %}', {}, '}}'),
    515     'templatetag05': ('{% templatetag %}', {}, template.TemplateSyntaxError),
    516     'templatetag06': ('{% templatetag foo %}', {}, template.TemplateSyntaxError),
    517     'templatetag07': ('{% templatetag openbrace %}', {}, '{'),
    518     'templatetag08': ('{% templatetag closebrace %}', {}, '}'),
    519     'templatetag09': ('{% templatetag openbrace %}{% templatetag openbrace %}', {}, '{{'),
    520     'templatetag10': ('{% templatetag closebrace %}{% templatetag closebrace %}', {}, '}}'),
    521 
    522     ### WIDTHRATIO TAG ########################################################
    523     'widthratio01': ('{% widthratio a b 0 %}', {'a':50,'b':100}, '0'),
    524     'widthratio02': ('{% widthratio a b 100 %}', {'a':0,'b':0}, ''),
    525     'widthratio03': ('{% widthratio a b 100 %}', {'a':0,'b':100}, '0'),
    526     'widthratio04': ('{% widthratio a b 100 %}', {'a':50,'b':100}, '50'),
    527     'widthratio05': ('{% widthratio a b 100 %}', {'a':100,'b':100}, '100'),
    528 
    529     # 62.5 should round to 63
    530     'widthratio06': ('{% widthratio a b 100 %}', {'a':50,'b':80}, '63'),
    531 
    532     # 71.4 should round to 71
    533     'widthratio07': ('{% widthratio a b 100 %}', {'a':50,'b':70}, '71'),
    534 
    535     # Raise exception if we don't have 3 args, last one an integer
    536     'widthratio08': ('{% widthratio %}', {}, template.TemplateSyntaxError),
    537     'widthratio09': ('{% widthratio a b %}', {'a':50,'b':100}, template.TemplateSyntaxError),
    538     'widthratio10': ('{% widthratio a b 100.0 %}', {'a':50,'b':100}, template.TemplateSyntaxError),
    539 
    540     ### NOW TAG ########################################################
    541     # Simple case
    542     'now01' : ('{% now "j n Y"%}', {}, str(datetime.now().day) + ' ' + str(datetime.now().month) + ' ' + str(datetime.now().year)),
    543 
    544     # Check parsing of escaped and special characters
    545     'now02' : ('{% now "j "n" Y"%}', {}, template.TemplateSyntaxError),
    546 #    'now03' : ('{% now "j \"n\" Y"%}', {}, str(datetime.now().day) + '"' + str(datetime.now().month) + '"' + str(datetime.now().year)),
    547 #    'now04' : ('{% now "j \nn\n Y"%}', {}, str(datetime.now().day) + '\n' + str(datetime.now().month) + '\n' + str(datetime.now().year))
    548 
    549     ### TIMESINCE TAG ##################################################
    550     # Default compare with datetime.now()
    551     'timesince01' : ('{{ a|timesince }}', {'a':datetime.now() + timedelta(minutes=-1, seconds = -10)}, '1 minute'),
    552     'timesince02' : ('{{ a|timesince }}', {'a':(datetime.now() - timedelta(days=1, minutes = 1))}, '1 day'),
    553     'timesince03' : ('{{ a|timesince }}', {'a':(datetime.now() -
    554         timedelta(hours=1, minutes=25, seconds = 10))}, '1 hour, 25 minutes'),
    555 
    556     # Compare to a given parameter
    557     'timesince04' : ('{{ a|timesince:b }}', {'a':NOW + timedelta(days=2), 'b':NOW + timedelta(days=1)}, '1 day'),
    558     'timesince05' : ('{{ a|timesince:b }}', {'a':NOW + timedelta(days=2, minutes=1), 'b':NOW + timedelta(days=2)}, '1 minute'),
    559 
    560     # Check that timezone is respected
    561     'timesince06' : ('{{ a|timesince:b }}', {'a':NOW_tz + timedelta(hours=8), 'b':NOW_tz}, '8 hours'),
    562 
    563     ### TIMEUNTIL TAG ##################################################
    564     # Default compare with datetime.now()
    565     'timeuntil01' : ('{{ a|timeuntil }}', {'a':datetime.now() + timedelta(minutes=2, seconds = 10)}, '2 minutes'),
    566     'timeuntil02' : ('{{ a|timeuntil }}', {'a':(datetime.now() + timedelta(days=1, seconds = 10))}, '1 day'),
    567     'timeuntil03' : ('{{ a|timeuntil }}', {'a':(datetime.now() + timedelta(hours=8, minutes=10, seconds = 10))}, '8 hours, 10 minutes'),
    568 
    569     # Compare to a given parameter
    570     'timeuntil04' : ('{{ a|timeuntil:b }}', {'a':NOW - timedelta(days=1), 'b':NOW - timedelta(days=2)}, '1 day'),
    571     'timeuntil05' : ('{{ a|timeuntil:b }}', {'a':NOW - timedelta(days=2), 'b':NOW - timedelta(days=2, minutes=1)}, '1 minute'),
    572 }
    573 
    574 def test_template_loader(template_name, template_dirs=None):
    575     "A custom template loader that loads the unit-test templates."
    576     try:
    577         return (TEMPLATE_TESTS[template_name][0] , "test:%s" % template_name)
    578     except KeyError:
    579         raise template.TemplateDoesNotExist, template_name
    580 
    581 def run_tests(verbosity=0, standalone=False):
    582     # Register our custom template loader.
    583     old_template_loaders = loader.template_source_loaders
    584     loader.template_source_loaders = [test_template_loader]
    585 
    586     failed_tests = []
    587     tests = TEMPLATE_TESTS.items()
    588     tests.sort()
    589 
    590     # Turn TEMPLATE_DEBUG off, because tests assume that.
    591     old_td, settings.TEMPLATE_DEBUG = settings.TEMPLATE_DEBUG, False
    592     # Set TEMPLATE_STRING_IF_INVALID to a known string
    593     old_invalid, settings.TEMPLATE_STRING_IF_INVALID = settings.TEMPLATE_STRING_IF_INVALID, 'INVALID'
    594    
    595     for name, vals in tests:
    596         install()
    597         if 'LANGUAGE_CODE' in vals[1]:
    598             activate(vals[1]['LANGUAGE_CODE'])
    599         else:
    600             activate('en-us')
    601         try:
    602             output = loader.get_template(name).render(template.Context(vals[1]))
    603         except Exception, e:
    604             if e.__class__ == vals[2]:
    605                 if verbosity:
    606                     print "Template test: %s -- Passed" % name
    607             else:
    608                 if verbosity:
    609                     traceback.print_exc()
    610                     print "Template test: %s -- FAILED. Got %s, exception: %s" % (name, e.__class__, e)
    611                 failed_tests.append(name)
    612             continue
    613         if 'LANGUAGE_CODE' in vals[1]:
    614             deactivate()
    615         if output == vals[2]:
    616             if verbosity:
    617                 print "Template test: %s -- Passed" % name
    618         else:
    619             if verbosity:
    620                 print "Template test: %s -- FAILED. Expected %r, got %r" % (name, vals[2], output)
    621             failed_tests.append(name)
    622     loader.template_source_loaders = old_template_loaders
    623     deactivate()
    624     settings.TEMPLATE_DEBUG = old_td
    625     settings.TEMPLATE_STRING_IF_INVALID = old_invalid
    626 
    627     if failed_tests and not standalone:
    628         msg = "Template tests %s failed." % failed_tests
    629         if not verbosity:
    630             msg += "  Re-run tests with -v1 to see actual failures"
    631         raise Exception, msg
    632 
    633 if __name__ == "__main__":
    634     run_tests(1, True)
  • tests/othertests/urlpatterns_reverse.py

     
    1 "Unit tests for reverse URL lookup"
    2 
    3 from django.core.urlresolvers import reverse_helper, NoReverseMatch
    4 import re
    5 
    6 test_data = (
    7     ('^places/(\d+)/$', 'places/3/', [3], {}),
    8     ('^places/(\d+)/$', 'places/3/', ['3'], {}),
    9     ('^places/(\d+)/$', NoReverseMatch, ['a'], {}),
    10     ('^places/(\d+)/$', NoReverseMatch, [], {}),
    11     ('^places/(?P<id>\d+)/$', 'places/3/', [], {'id': 3}),
    12     ('^people/(?P<name>\w+)/$', 'people/adrian/', ['adrian'], {}),
    13     ('^people/(?P<name>\w+)/$', 'people/adrian/', [], {'name': 'adrian'}),
    14     ('^people/(?P<name>\w+)/$', NoReverseMatch, ['name with spaces'], {}),
    15     ('^people/(?P<name>\w+)/$', NoReverseMatch, [], {'name': 'name with spaces'}),
    16     ('^people/(?P<name>\w+)/$', NoReverseMatch, [], {}),
    17     ('^hardcoded/$', 'hardcoded/', [], {}),
    18     ('^hardcoded/$', 'hardcoded/', ['any arg'], {}),
    19     ('^hardcoded/$', 'hardcoded/', [], {'kwarg': 'foo'}),
    20     ('^people/(?P<state>\w\w)/(?P<name>\w+)/$', 'people/il/adrian/', [], {'state': 'il', 'name': 'adrian'}),
    21     ('^people/(?P<state>\w\w)/(?P<name>\d)/$', NoReverseMatch, [], {'state': 'il', 'name': 'adrian'}),
    22     ('^people/(?P<state>\w\w)/(?P<name>\w+)/$', NoReverseMatch, [], {'state': 'il'}),
    23     ('^people/(?P<state>\w\w)/(?P<name>\w+)/$', NoReverseMatch, [], {'name': 'adrian'}),
    24     ('^people/(?P<state>\w\w)/(\w+)/$', NoReverseMatch, ['il'], {'name': 'adrian'}),
    25     ('^people/(?P<state>\w\w)/(\w+)/$', 'people/il/adrian/', ['adrian'], {'state': 'il'}),
    26 )
    27 
    28 def run_tests(verbosity=0):
    29     for regex, expected, args, kwargs in test_data:
    30         passed = True
    31         try:
    32             got = reverse_helper(re.compile(regex), *args, **kwargs)
    33         except NoReverseMatch, e:
    34             if expected != NoReverseMatch:
    35                 passed, got = False, str(e)
    36         else:
    37             if got != expected:
    38                 passed, got = False, got
    39         if passed and verbosity:
    40             print "Passed: %s" % regex
    41         elif not passed:
    42             print "REVERSE LOOKUP FAILED: %s" % regex
    43             print "   Got: %s" % got
    44             print "   Expected: %r" % expected
    45 
    46 if __name__ == "__main__":
    47     run_tests(1)
  • tests/othertests/markup.py

     
    1 # Quick tests for the markup templatetags (django.contrib.markup)
    2 
    3 from django.template import Template, Context, add_to_builtins
    4 import re
    5 
    6 add_to_builtins('django.contrib.markup.templatetags.markup')
    7 
    8 # find out if markup modules are installed and tailor the test appropriately
    9 try:
    10     import textile
    11 except ImportError:
    12     textile = None
    13 
    14 try:
    15     import markdown
    16 except ImportError:
    17     markdown = None
    18 
    19 try:
    20     import docutils
    21 except ImportError:
    22     docutils = None
    23 
    24 # simple examples 'cause this isn't actually testing the markup, just
    25 # that the filters work as advertised
    26 
    27 ### test textile
    28 
    29 textile_content = """Paragraph 1
    30 
    31 Paragraph 2 with "quotes" and @code@"""
    32 
    33 t = Template("{{ textile_content|textile }}")
    34 rendered = t.render(Context(locals())).strip()
    35 if textile:
    36     assert rendered == """<p>Paragraph 1</p>
    37 
    38 <p>Paragraph 2 with &#8220;quotes&#8221; and <code>code</code></p>"""
    39 else:
    40     assert rendered == textile_content
    41 
    42 ### test markdown
    43 
    44 markdown_content = """Paragraph 1
    45 
    46 ## An h2"""
    47 
    48 t = Template("{{ markdown_content|markdown }}")
    49 rendered = t.render(Context(locals())).strip()
    50 if markdown:
    51     pattern = re.compile("""<p>Paragraph 1\s*</p>\s*<h2>\s*An h2</h2>""")
    52     assert pattern.match(rendered)
    53 else:
    54     assert rendered == markdown_content
    55 
    56 ### test rest
    57 
    58 rest_content = """Paragraph 1
    59 
    60 Paragraph 2 with a link_
    61 
    62 .. _link: http://www.example.com/"""
    63 
    64 t = Template("{{ rest_content|restructuredtext }}")
    65 rendered = t.render(Context(locals())).strip()
    66 if docutils:
    67     assert rendered =="""<p>Paragraph 1</p>
    68 <p>Paragraph 2 with a <a class="reference" href="http://www.example.com/">link</a></p>"""
    69 else:
    70     assert rendered == rest_content
  • tests/othertests/cache.py

     
    1 # Unit tests for cache framework
    2 # Uses whatever cache backend is set in the test settings file.
    3 
    4 from django.core.cache import cache
    5 import time
    6 
    7 # functions/classes for complex data type tests       
    8 def f():
    9     return 42
    10 class C:
    11     def m(n):
    12         return 24
    13 
    14 # simple set/get
    15 cache.set("key", "value")
    16 assert cache.get("key") == "value"
    17 
    18 # get with non-existent keys
    19 assert cache.get("does not exist") is None
    20 assert cache.get("does not exist", "bang!") == "bang!"
    21 
    22 # get_many
    23 cache.set('a', 'a')
    24 cache.set('b', 'b')
    25 cache.set('c', 'c')
    26 cache.set('d', 'd')
    27 assert cache.get_many(['a', 'c', 'd']) == {'a' : 'a', 'c' : 'c', 'd' : 'd'}
    28 assert cache.get_many(['a', 'b', 'e']) == {'a' : 'a', 'b' : 'b'}
    29 
    30 # delete
    31 cache.set("key1", "spam")
    32 cache.set("key2", "eggs")
    33 assert cache.get("key1") == "spam"
    34 cache.delete("key1")
    35 assert cache.get("key1") is None
    36 assert cache.get("key2") == "eggs"
    37 
    38 # has_key
    39 cache.set("hello", "goodbye")
    40 assert cache.has_key("hello") == True
    41 assert cache.has_key("goodbye") == False
    42 
    43 # test data types
    44 stuff = {
    45     'string'    : 'this is a string',
    46     'int'       : 42,
    47     'list'      : [1, 2, 3, 4],
    48     'tuple'     : (1, 2, 3, 4),
    49     'dict'      : {'A': 1, 'B' : 2},
    50     'function'  : f,
    51     'class'     : C,
    52 }
    53 for (key, value) in stuff.items():
    54     cache.set(key, value)
    55     assert cache.get(key) == value
    56    
    57 # expiration
    58 cache.set('expire', 'very quickly', 1)
    59 time.sleep(2)
    60 assert cache.get("expire") == None
  • tests/othertests/httpwrappers.py

     
    1 """
    2 ###################
    3 # Empty QueryDict #
    4 ###################
    5 
    6 >>> q = QueryDict('')
    7 
    8 >>> q['foo']
    9 Traceback (most recent call last):
    10 ...
    11 MultiValueDictKeyError: "Key 'foo' not found in <MultiValueDict: {}>"
    12 
    13 >>> q['something'] = 'bar'
    14 Traceback (most recent call last):
    15 ...
    16 AttributeError: This QueryDict instance is immutable
    17 
    18 >>> q.get('foo', 'default')
    19 'default'
    20 
    21 >>> q.getlist('foo')
    22 []
    23 
    24 >>> q.setlist('foo', ['bar', 'baz'])
    25 Traceback (most recent call last):
    26 ...
    27 AttributeError: This QueryDict instance is immutable
    28 
    29 >>> q.appendlist('foo', ['bar'])
    30 Traceback (most recent call last):
    31 ...
    32 AttributeError: This QueryDict instance is immutable
    33 
    34 >>> q.has_key('foo')
    35 False
    36 
    37 >>> q.items()
    38 []
    39 
    40 >>> q.lists()
    41 []
    42 
    43 >>> q.keys()
    44 []
    45 
    46 >>> q.values()
    47 []
    48 
    49 >>> len(q)
    50 0
    51 
    52 >>> q.update({'foo': 'bar'})
    53 Traceback (most recent call last):
    54 ...
    55 AttributeError: This QueryDict instance is immutable
    56 
    57 >>> q.pop('foo')
    58 Traceback (most recent call last):
    59 ...
    60 AttributeError: This QueryDict instance is immutable
    61 
    62 >>> q.popitem()
    63 Traceback (most recent call last):
    64 ...
    65 AttributeError: This QueryDict instance is immutable
    66 
    67 >>> q.clear()
    68 Traceback (most recent call last):
    69 ...
    70 AttributeError: This QueryDict instance is immutable
    71 
    72 >>> q.setdefault('foo', 'bar')
    73 Traceback (most recent call last):
    74 ...
    75 AttributeError: This QueryDict instance is immutable
    76 
    77 >>> q.urlencode()
    78 ''
    79 
    80 ###################################
    81 # Mutable copy of empty QueryDict #
    82 ###################################
    83 
    84 >>> q = q.copy()
    85 
    86 >>> q['foo']
    87 Traceback (most recent call last):
    88 ...
    89 MultiValueDictKeyError: "Key 'foo' not found in <MultiValueDict: {}>"
    90 
    91 >>> q['name'] = 'john'
    92 
    93 >>> q['name']
    94 'john'
    95 
    96 >>> q.get('foo', 'default')
    97 'default'
    98 
    99 >>> q.get('name', 'default')
    100 'john'
    101 
    102 >>> q.getlist('name')
    103 ['john']
    104 
    105 >>> q.getlist('foo')
    106 []
    107 
    108 >>> q.setlist('foo', ['bar', 'baz'])
    109 
    110 >>> q.get('foo', 'default')
    111 'baz'
    112 
    113 >>> q.getlist('foo')
    114 ['bar', 'baz']
    115 
    116 >>> q.appendlist('foo', 'another')
    117 
    118 >>> q.getlist('foo')
    119 ['bar', 'baz', 'another']
    120 
    121 >>> q['foo']
    122 'another'
    123 
    124 >>> q.has_key('foo')
    125 True
    126 
    127 >>> q.items()
    128 [('foo', 'another'), ('name', 'john')]
    129 
    130 >>> q.lists()
    131 [('foo', ['bar', 'baz', 'another']), ('name', ['john'])]
    132 
    133 >>> q.keys()
    134 ['foo', 'name']
    135 
    136 >>> q.values()
    137 ['another', 'john']
    138 
    139 >>> len(q)
    140 2
    141 
    142 >>> q.update({'foo': 'hello'})
    143 
    144 # Displays last value
    145 >>> q['foo']
    146 'hello'
    147 
    148 >>> q.get('foo', 'not available')
    149 'hello'
    150 
    151 >>> q.getlist('foo')
    152 ['bar', 'baz', 'another', 'hello']
    153 
    154 >>> q.pop('foo')
    155 ['bar', 'baz', 'another', 'hello']
    156 
    157 >>> q.get('foo', 'not there')
    158 'not there'
    159 
    160 >>> q.setdefault('foo', 'bar')
    161 'bar'
    162 
    163 >>> q['foo']
    164 'bar'
    165 
    166 >>> q.getlist('foo')
    167 ['bar']
    168 
    169 >>> q.urlencode()
    170 'foo=bar&name=john'
    171 
    172 >>> q.clear()
    173 
    174 >>> len(q)
    175 0
    176 
    177 #####################################
    178 # QueryDict with one key/value pair #
    179 #####################################
    180 
    181 >>> q = QueryDict('foo=bar')
    182 
    183 >>> q['foo']
    184 'bar'
    185 
    186 >>> q['bar']
    187 Traceback (most recent call last):
    188 ...
    189 MultiValueDictKeyError: "Key 'bar' not found in <MultiValueDict: {'foo': ['bar']}>"
    190 
    191 >>> q['something'] = 'bar'
    192 Traceback (most recent call last):
    193 ...
    194 AttributeError: This QueryDict instance is immutable
    195 
    196 >>> q.get('foo', 'default')
    197 'bar'
    198 
    199 >>> q.get('bar', 'default')
    200 'default'
    201 
    202 >>> q.getlist('foo')
    203 ['bar']
    204 
    205 >>> q.getlist('bar')
    206 []
    207 
    208 >>> q.setlist('foo', ['bar', 'baz'])
    209 Traceback (most recent call last):
    210 ...
    211 AttributeError: This QueryDict instance is immutable
    212 
    213 >>> q.appendlist('foo', ['bar'])
    214 Traceback (most recent call last):
    215 ...
    216 AttributeError: This QueryDict instance is immutable
    217 
    218 >>> q.has_key('foo')
    219 True
    220 
    221 >>> q.has_key('bar')
    222 False
    223 
    224 >>> q.items()
    225 [('foo', 'bar')]
    226 
    227 >>> q.lists()
    228 [('foo', ['bar'])]
    229 
    230 >>> q.keys()
    231 ['foo']
    232 
    233 >>> q.values()
    234 ['bar']
    235 
    236 >>> len(q)
    237 1
    238 
    239 >>> q.update({'foo': 'bar'})
    240 Traceback (most recent call last):
    241 ...
    242 AttributeError: This QueryDict instance is immutable
    243 
    244 >>> q.pop('foo')
    245 Traceback (most recent call last):
    246 ...
    247 AttributeError: This QueryDict instance is immutable
    248 
    249 >>> q.popitem()
    250 Traceback (most recent call last):
    251 ...
    252 AttributeError: This QueryDict instance is immutable
    253 
    254 >>> q.clear()
    255 Traceback (most recent call last):
    256 ...
    257 AttributeError: This QueryDict instance is immutable
    258 
    259 >>> q.setdefault('foo', 'bar')
    260 Traceback (most recent call last):
    261 ...
    262 AttributeError: This QueryDict instance is immutable
    263 
    264 >>> q.urlencode()
    265 'foo=bar'
    266 
    267 #####################################################
    268 # QueryDict with two key/value pairs with same keys #
    269 #####################################################
    270 
    271 >>> q = QueryDict('vote=yes&vote=no')
    272 
    273 >>> q['vote']
    274 'no'
    275 
    276 >>> q['something'] = 'bar'
    277 Traceback (most recent call last):
    278 ...
    279 AttributeError: This QueryDict instance is immutable
    280 
    281 >>> q.get('vote', 'default')
    282 'no'
    283 
    284 >>> q.get('foo', 'default')
    285 'default'
    286 
    287 >>> q.getlist('vote')
    288 ['yes', 'no']
    289 
    290 >>> q.getlist('foo')
    291 []
    292 
    293 >>> q.setlist('foo', ['bar', 'baz'])
    294 Traceback (most recent call last):
    295 ...
    296 AttributeError: This QueryDict instance is immutable
    297 
    298 >>> q.appendlist('foo', ['bar'])
    299 Traceback (most recent call last):
    300 ...
    301 AttributeError: This QueryDict instance is immutable
    302 
    303 >>> q.has_key('vote')
    304 True
    305 
    306 >>> q.has_key('foo')
    307 False
    308 
    309 >>> q.items()
    310 [('vote', 'no')]
    311 
    312 >>> q.lists()
    313 [('vote', ['yes', 'no'])]
    314 
    315 >>> q.keys()
    316 ['vote']
    317 
    318 >>> q.values()
    319 ['no']
    320 
    321 >>> len(q)
    322 1
    323 
    324 >>> q.update({'foo': 'bar'})
    325 Traceback (most recent call last):
    326 ...
    327 AttributeError: This QueryDict instance is immutable
    328 
    329 >>> q.pop('foo')
    330 Traceback (most recent call last):
    331 ...
    332 AttributeError: This QueryDict instance is immutable
    333 
    334 >>> q.popitem()
    335 Traceback (most recent call last):
    336 ...
    337 AttributeError: This QueryDict instance is immutable
    338 
    339 >>> q.clear()
    340 Traceback (most recent call last):
    341 ...
    342 AttributeError: This QueryDict instance is immutable
    343 
    344 >>> q.setdefault('foo', 'bar')
    345 Traceback (most recent call last):
    346 ...
    347 AttributeError: This QueryDict instance is immutable
    348 
    349 >>> q.urlencode()
    350 'vote=yes&vote=no'
    351 
    352 """
    353 
    354 from django.http import QueryDict
    355 
    356 if __name__ == "__main__":
    357     import doctest
    358     doctest.testmod()
  • tests/othertests/db_typecasts.py

     
    1 # Unit tests for typecast functions in django.db.backends.util
    2 
    3 from django.db.backends import util as typecasts
    4 import datetime
    5 
    6 TEST_CASES = {
    7     'typecast_date': (
    8         ('', None),
    9         (None, None),
    10         ('2005-08-11', datetime.date(2005, 8, 11)),
    11         ('1990-01-01', datetime.date(1990, 1, 1)),
    12     ),
    13     'typecast_time': (
    14         ('', None),
    15         (None, None),
    16         ('0:00:00', datetime.time(0, 0)),
    17         ('0:30:00', datetime.time(0, 30)),
    18         ('8:50:00', datetime.time(8, 50)),
    19         ('08:50:00', datetime.time(8, 50)),
    20         ('12:00:00', datetime.time(12, 00)),
    21         ('12:30:00', datetime.time(12, 30)),
    22         ('13:00:00', datetime.time(13, 00)),
    23         ('23:59:00', datetime.time(23, 59)),
    24         ('00:00:12', datetime.time(0, 0, 12)),
    25         ('00:00:12.5', datetime.time(0, 0, 12, 500000)),
    26         ('7:22:13.312', datetime.time(7, 22, 13, 312000)),
    27     ),
    28     'typecast_timestamp': (
    29         ('', None),
    30         (None, None),
    31         ('2005-08-11 0:00:00', datetime.datetime(2005, 8, 11)),
    32         ('2005-08-11 0:30:00', datetime.datetime(2005, 8, 11, 0, 30)),
    33         ('2005-08-11 8:50:30', datetime.datetime(2005, 8, 11, 8, 50, 30)),
    34         ('2005-08-11 8:50:30.123', datetime.datetime(2005, 8, 11, 8, 50, 30, 123000)),
    35         ('2005-08-11 8:50:30.9', datetime.datetime(2005, 8, 11, 8, 50, 30, 900000)),
    36         ('2005-08-11 8:50:30.312-05', datetime.datetime(2005, 8, 11, 8, 50, 30, 312000)),
    37         ('2005-08-11 8:50:30.312+02', datetime.datetime(2005, 8, 11, 8, 50, 30, 312000)),
    38     ),
    39     'typecast_boolean': (
    40         (None, None),
    41         ('', False),
    42         ('t', True),
    43         ('f', False),
    44         ('x', False),
    45     ),
    46 }
    47 
    48 for k, v in TEST_CASES.items():
    49     for inpt, expected in v:
    50         got = getattr(typecasts, k)(inpt)
    51         assert got == expected, "In %s: %r doesn't match %r. Got %r instead." % (k, inpt, expected, got)
  • tests/othertests/dateformat.py

     
    1 r"""
    2 >>> format(my_birthday, '')
    3 ''
    4 >>> format(my_birthday, 'a')
    5 'p.m.'
    6 >>> format(my_birthday, 'A')
    7 'PM'
    8 >>> format(my_birthday, 'd')
    9 '08'
    10 >>> format(my_birthday, 'j')
    11 '8'
    12 >>> format(my_birthday, 'l')
    13 'Sunday'
    14 >>> format(my_birthday, 'L')
    15 'False'
    16 >>> format(my_birthday, 'm')
    17 '07'
    18 >>> format(my_birthday, 'M')
    19 'Jul'
    20 >>> format(my_birthday, 'n')
    21 '7'
    22 >>> format(my_birthday, 'N')
    23 'July'
    24 >>> format(my_birthday, 'O')
    25 '+0100'
    26 >>> format(my_birthday, 'P')
    27 '10 p.m.'
    28 >>> format(my_birthday, 'r')
    29 'Sun, 8 Jul 1979 22:00:00 +0100'
    30 >>> format(my_birthday, 's')
    31 '00'
    32 >>> format(my_birthday, 'S')
    33 'th'
    34 >>> format(my_birthday, 't')
    35 '31'
    36 >>> format(my_birthday, 'T')
    37 'CET'
    38 >>> format(my_birthday, 'U')
    39 '300531600'
    40 >>> format(my_birthday, 'w')
    41 '0'
    42 >>> format(my_birthday, 'W')
    43 '27'
    44 >>> format(my_birthday, 'y')
    45 '79'
    46 >>> format(my_birthday, 'Y')
    47 '1979'
    48 >>> format(my_birthday, 'z')
    49 '189'
    50 >>> format(my_birthday, 'Z')
    51 '3600'
    52 
    53 >>> format(summertime, 'I')
    54 '1'
    55 >>> format(summertime, 'O')
    56 '+0200'
    57 >>> format(wintertime, 'I')
    58 '0'
    59 >>> format(wintertime, 'O')
    60 '+0100'
    61 
    62 >>> format(my_birthday, r'Y z \C\E\T')
    63 '1979 189 CET'
    64 
    65 >>> format(my_birthday, r'jS o\f F')
    66 '8th of July'
    67 """
    68 
    69 from django.utils import dateformat, translation
    70 import datetime, os, time
    71 
    72 format = dateformat.format
    73 os.environ['TZ'] = 'Europe/Copenhagen'
    74 translation.activate('en-us')
    75 
    76 time.tzset()
    77 
    78 my_birthday = datetime.datetime(1979, 7, 8, 22, 00)
    79 summertime = datetime.datetime(2005, 10, 30, 1, 00)
    80 wintertime = datetime.datetime(2005, 10, 30, 4, 00)
  • tests/runtests.py

     
    11#!/usr/bin/env python
    22
    3 import os, re, sys, time, traceback
     3import os, sys, traceback
     4import unittest
    45
    5 # doctest is included in the same package as this module, because this testing
    6 # framework uses features only available in the Python 2.4 version of doctest,
    7 # and Django aims to work with Python 2.3+.
    8 import doctest
    9 
    106MODEL_TESTS_DIR_NAME = 'modeltests'
    11 OTHER_TESTS_DIR = "othertests"
    127REGRESSION_TESTS_DIR_NAME = 'regressiontests'
    13 TEST_DATABASE_NAME = 'django_test_db'
    148
    15 error_list = []
    16 def log_error(model_name, title, description):
    17     error_list.append({
    18         'title': "%r module: %s" % (model_name, title),
    19         'description': description,
    20     })
    21 
    229MODEL_TEST_DIR = os.path.join(os.path.dirname(__file__), MODEL_TESTS_DIR_NAME)
    2310REGRESSION_TEST_DIR = os.path.join(os.path.dirname(__file__), REGRESSION_TESTS_DIR_NAME)
    2411
     
    3724    models = []
    3825    for loc, dirpath in (MODEL_TESTS_DIR_NAME, MODEL_TEST_DIR), (REGRESSION_TESTS_DIR_NAME, REGRESSION_TEST_DIR):
    3926        for f in os.listdir(dirpath):
    40             if f.startswith('__init__') or f.startswith('.') or f.startswith('sql'):
     27            if f.startswith('__init__') or f.startswith('.') or f.startswith('sql') or f.startswith('invalid'):
    4128                continue
    4229            models.append((loc, f))
    4330    return models
    4431
    45 class DjangoDoctestRunner(doctest.DocTestRunner):
    46     def __init__(self, verbosity_level, *args, **kwargs):
    47         self.verbosity_level = verbosity_level
    48         doctest.DocTestRunner.__init__(self, *args, **kwargs)
    49         self._checker = DjangoDoctestOutputChecker()
    50         self.optionflags = doctest.ELLIPSIS
    51 
    52     def report_start(self, out, test, example):
    53         if self.verbosity_level > 1:
    54             out("  >>> %s\n" % example.source.strip())
    55 
    56     def report_failure(self, out, test, example, got):
    57         log_error(test.name, "API test failed",
    58             "Code: %r\nLine: %s\nExpected: %r\nGot: %r" % (example.source.strip(), example.lineno, example.want, got))
    59 
    60     def report_unexpected_exception(self, out, test, example, exc_info):
    61         from django.db import transaction
    62         tb = ''.join(traceback.format_exception(*exc_info)[1:])
    63         log_error(test.name, "API test raised an exception",
    64             "Code: %r\nLine: %s\nException: %s" % (example.source.strip(), example.lineno, tb))
    65         # Rollback, in case of database errors. Otherwise they'd have
    66         # side effects on other tests.
    67         transaction.rollback_unless_managed()
    68 
    69 normalize_long_ints = lambda s: re.sub(r'(?<![\w])(\d+)L(?![\w])', '\\1', s)
    70 
    71 class DjangoDoctestOutputChecker(doctest.OutputChecker):
    72     def check_output(self, want, got, optionflags):
    73         ok = doctest.OutputChecker.check_output(self, want, got, optionflags)
    74 
    75         # Doctest does an exact string comparison of output, which means long
    76         # integers aren't equal to normal integers ("22L" vs. "22"). The
    77         # following code normalizes long integers so that they equal normal
    78         # integers.
    79         if not ok:
    80             return normalize_long_ints(want) == normalize_long_ints(got)
    81         return ok
    82 
    83 class TestRunner:
    84     def __init__(self, verbosity_level=0, which_tests=None):
    85         self.verbosity_level = verbosity_level
    86         self.which_tests = which_tests
    87 
    88     def output(self, required_level, message):
    89         if self.verbosity_level > required_level - 1:
    90             print message
    91 
    92     def run_tests(self):
    93         from django.conf import settings
    94 
    95         # An empty access of the settings to force the default options to be
    96         # installed prior to assigning to them.
    97         settings.INSTALLED_APPS
    98 
    99         # Manually set INSTALLED_APPS to point to the test models.
    100         settings.INSTALLED_APPS = ALWAYS_INSTALLED_APPS + ['.'.join(a) for a in get_test_models()]
    101 
    102         # Manually set DEBUG and USE_I18N.
    103         settings.DEBUG = False
    104         settings.USE_I18N = True
    105 
    106         from django.db import connection
     32def get_invalid_models():
     33    models = []
     34    for loc, dirpath in (MODEL_TESTS_DIR_NAME, MODEL_TEST_DIR), (REGRESSION_TESTS_DIR_NAME, REGRESSION_TEST_DIR):
     35        for f in os.listdir(dirpath):
     36            if f.startswith('__init__') or f.startswith('.') or f.startswith('sql'):
     37                continue
     38            if f.startswith('invalid'):
     39                models.append((loc, f))
     40    return models
     41               
     42class InvalidModelTestCase(unittest.TestCase):
     43    def __init__(self, model_label):
     44        unittest.TestCase.__init__(self)
     45        self.model_label = model_label
     46       
     47    def runTest(self):
    10748        from django.core import management
    108         import django.db.models
    109 
    110         # Determine which models we're going to test.
    111         test_models = get_test_models()
    112         if 'othertests' in self.which_tests:
    113             self.which_tests.remove('othertests')
    114             run_othertests = True
    115             if not self.which_tests:
    116                 test_models = []
    117         else:
    118             run_othertests = not self.which_tests
    119 
    120         if self.which_tests:
    121             # Only run the specified tests.
    122             bad_models = [m for m in self.which_tests if (MODEL_TESTS_DIR_NAME, m) not in test_models and (REGRESSION_TESTS_DIR_NAME, m) not in test_models]
    123             if bad_models:
    124                 sys.stderr.write("Models not found: %s\n" % bad_models)
    125                 sys.exit(1)
    126             else:
    127                 all_tests = []
    128                 for test in self.which_tests:
    129                     for loc in MODEL_TESTS_DIR_NAME, REGRESSION_TESTS_DIR_NAME:
    130                         if (loc, test) in test_models:
    131                             all_tests.append((loc, test))
    132                 test_models = all_tests
    133 
    134         self.output(0, "Running tests with database %r" % settings.DATABASE_ENGINE)
    135 
    136         # If we're using SQLite, it's more convenient to test against an
    137         # in-memory database.
    138         if settings.DATABASE_ENGINE == "sqlite3":
    139             global TEST_DATABASE_NAME
    140             TEST_DATABASE_NAME = ":memory:"
    141         else:
    142             # Create the test database and connect to it. We need to autocommit
    143             # if the database supports it because PostgreSQL doesn't allow
    144             # CREATE/DROP DATABASE statements within transactions.
    145             cursor = connection.cursor()
    146             self._set_autocommit(connection)
    147             self.output(1, "Creating test database")
    148             try:
    149                 cursor.execute("CREATE DATABASE %s" % TEST_DATABASE_NAME)
    150             except Exception, e:
    151                 sys.stderr.write("Got an error creating the test database: %s\n" % e)
    152                 confirm = raw_input("It appears the test database, %s, already exists. Type 'yes' to delete it, or 'no' to cancel: " % TEST_DATABASE_NAME)
    153                 if confirm == 'yes':
    154                     cursor.execute("DROP DATABASE %s" % TEST_DATABASE_NAME)
    155                     cursor.execute("CREATE DATABASE %s" % TEST_DATABASE_NAME)
    156                 else:
    157                     print "Tests cancelled."
    158                     return
    159         connection.close()
    160         old_database_name = settings.DATABASE_NAME
    161         settings.DATABASE_NAME = TEST_DATABASE_NAME
    162 
    163         # Initialize the test database.
    164         cursor = connection.cursor()
    165 
    16649        from django.db.models.loading import load_app
    167         # Install the core always installed apps
    168         for app in ALWAYS_INSTALLED_APPS:
    169             self.output(1, "Installing contrib app %s" % app)
    170             mod = load_app(app)
    171             management.install(mod)
     50        from cStringIO import StringIO
    17251
    173         # Run the tests for each test model.
    174         self.output(1, "Running app tests")
    175         for model_dir, model_name in test_models:
    176             self.output(1, "%s model: Importing" % model_name)
    177             try:
    178                 mod = load_app(model_dir + '.' + model_name)
    179             except Exception, e:
    180                 log_error(model_name, "Error while importing", ''.join(traceback.format_exception(*sys.exc_info())[1:]))
    181                 continue
     52        try:
     53            module = load_app(self.model_label)
     54        except Exception, e:
     55            self.fail('Unable to load invalid model module')
     56       
     57        s = StringIO()
     58        count = management.get_validation_errors(s, module)
     59        s.seek(0)
     60        error_log = s.read()
     61        actual = error_log.split('\n')
     62        expected = module.model_errors.split('\n')
    18263
    183             if not getattr(mod, 'error_log', None):
    184                 # Model is not marked as an invalid model
    185                 self.output(1, "%s.%s model: Installing" % (model_dir, model_name))
    186                 management.install(mod)
     64        unexpected = [err for err in actual if err not in expected]
     65        missing = [err for err in expected if err not in actual]
    18766
    188                 # Run the API tests.
    189                 p = doctest.DocTestParser()
    190                 test_namespace = dict([(m._meta.object_name, m) \
    191                                         for m in django.db.models.get_models(mod)])
    192                 dtest = p.get_doctest(mod.API_TESTS, test_namespace, model_name, None, None)
    193                 # Manually set verbose=False, because "-v" command-line parameter
    194                 # has side effects on doctest TestRunner class.
    195                 runner = DjangoDoctestRunner(verbosity_level=verbosity_level, verbose=False)
    196                 self.output(1, "%s.%s model: Running tests" % (model_dir, model_name))
    197                 runner.run(dtest, clear_globs=True, out=sys.stdout.write)
    198             else:
    199                 # Check that model known to be invalid is invalid for the right reasons.
    200                 self.output(1, "%s.%s model: Validating" % (model_dir, model_name))
     67        self.assert_(not unexpected, "Unexpected Errors: " + '\n'.join(unexpected))
     68        self.assert_(not missing, "Missing Errors: " + '\n'.join(missing))
    20169
    202                 from cStringIO import StringIO
    203                 s = StringIO()
    204                 count = management.get_validation_errors(s, mod)
    205                 s.seek(0)
    206                 error_log = s.read()
    207                 actual = error_log.split('\n')
    208                 expected = mod.error_log.split('\n')
     70def django_tests(verbosity, tests_to_run):
     71    from django.conf import settings
     72    from django.db.models.loading import get_apps, load_app
     73    old_installed_apps = settings.INSTALLED_APPS
     74   
     75    # load all the ALWAYS_INSTALLED_APPS
     76    settings.INSTALLED_APPS = ALWAYS_INSTALLED_APPS
     77    get_apps()
     78   
     79    test_models = []
     80    # Load all the test model apps
     81    for model_dir, model_name in get_test_models():       
     82        model_label = '.'.join([model_dir, model_name])
     83        try:
     84            # if the model was named on the command line, or
     85            # no models were named (i.e., run all), import
     86            # this model and add it to the list to test.
     87            if not tests_to_run or model_name in tests_to_run:
     88                if verbosity >= 1:
     89                    print "Importing model %s" % model_name
     90                mod = load_app(model_label)
     91                settings.INSTALLED_APPS.append(model_label)       
     92                test_models.append(mod)
     93        except Exception, e:
     94            sys.stderr.write("Error while importing %s:" % model_name + ''.join(traceback.format_exception(*sys.exc_info())[1:]))
     95            continue   
    20996
    210                 unexpected = [err for err in actual if err not in expected]
    211                 missing = [err for err in expected if err not in actual]
    212 
    213                 if unexpected or missing:
    214                     unexpected_log = '\n'.join(unexpected)
    215                     missing_log = '\n'.join(missing)
    216                     log_error(model_name,
    217                         "Validator found %d validation errors, %d expected" % (count, len(expected) - 1),
    218                         "Missing errors:\n%s\n\nUnexpected errors:\n%s" % (missing_log, unexpected_log))
    219 
    220         if run_othertests:
    221             # Run the non-model tests in the other tests dir
    222             self.output(1, "Running other tests")
    223             other_tests_dir = os.path.join(os.path.dirname(__file__), OTHER_TESTS_DIR)
    224             test_modules = [f[:-3] for f in os.listdir(other_tests_dir) if f.endswith('.py') and not f.startswith('__init__')]
    225             for module in test_modules:
    226                 self.output(1, "%s module: Importing" % module)
    227                 try:
    228                     mod = __import__("othertests." + module, '', '', [''])
    229                 except Exception, e:
    230                     log_error(module, "Error while importing", ''.join(traceback.format_exception(*sys.exc_info())[1:]))
    231                     continue
    232                 if mod.__doc__:
    233                     p = doctest.DocTestParser()
    234                     dtest = p.get_doctest(mod.__doc__, mod.__dict__, module, None, None)
    235                     runner = DjangoDoctestRunner(verbosity_level=verbosity_level, verbose=False)
    236                     self.output(1, "%s module: running tests" % module)
    237                     runner.run(dtest, clear_globs=True, out=sys.stdout.write)
    238                 if hasattr(mod, "run_tests") and callable(mod.run_tests):
    239                     self.output(1, "%s module: running tests" % module)
    240                     try:
    241                         mod.run_tests(verbosity_level)
    242                     except Exception, e:
    243                         log_error(module, "Exception running tests", ''.join(traceback.format_exception(*sys.exc_info())[1:]))
    244                         continue
    245 
    246         # Unless we're using SQLite, remove the test database to clean up after
    247         # ourselves. Connect to the previous database (not the test database)
    248         # to do so, because it's not allowed to delete a database while being
    249         # connected to it.
    250         if settings.DATABASE_ENGINE != "sqlite3":
    251             connection.close()
    252             settings.DATABASE_NAME = old_database_name
    253             cursor = connection.cursor()
    254             self.output(1, "Deleting test database")
    255             self._set_autocommit(connection)
    256             time.sleep(1) # To avoid "database is being accessed by other users" errors.
    257             cursor.execute("DROP DATABASE %s" % TEST_DATABASE_NAME)
    258 
    259         # Display output.
    260         if error_list:
    261             for d in error_list:
    262                 print
    263                 print d['title']
    264                 print "=" * len(d['title'])
    265                 print d['description']
    266             print "%s error%s:" % (len(error_list), len(error_list) != 1 and 's' or '')
    267         else:
    268             print "All tests passed."
    269 
    270     def _set_autocommit(self, connection):
    271         """
    272         Make sure a connection is in autocommit mode.
    273         """
    274         if hasattr(connection.connection, "autocommit"):
    275             connection.connection.autocommit(True)
    276         elif hasattr(connection.connection, "set_isolation_level"):
    277             connection.connection.set_isolation_level(0)
    278 
     97    # Add tests for invalid models
     98    extra_tests = []
     99    for model_dir, model_name in get_invalid_models():
     100        model_label = '.'.join([model_dir, model_name])
     101        if not tests_to_run or model_name in tests_to_run:
     102            extra_tests.append(InvalidModelTestCase(model_label))
     103   
     104    # Run the test suite, including the extra validation tests.
     105    from django.test.simple import run_tests
     106    run_tests(test_models, verbosity, extra_tests=extra_tests)
     107 
     108    # Restore the old INSTALLED_APPS setting
     109    settings.INSTALLED_APPS = old_installed_apps
     110     
    279111if __name__ == "__main__":
    280112    from optparse import OptionParser
    281113    usage = "%prog [options] [model model model ...]"
    282114    parser = OptionParser(usage=usage)
    283     parser.add_option('-v', help='How verbose should the output be? Choices are 0, 1 and 2, where 2 is most verbose. Default is 0.',
    284         type='choice', choices=['0', '1', '2'])
     115    parser.add_option('-v','--verbosity', action='store', dest='verbosity', default='0',
     116        type='choice', choices=['0', '1', '2'],
     117        help='Verbosity level; 0=minimal output, 1=normal output, 2=all output')   
    285118    parser.add_option('--settings',
    286119        help='Python path to settings module, e.g. "myproject.settings". If this isn\'t provided, the DJANGO_SETTINGS_MODULE environment variable will be used.')
    287120    options, args = parser.parse_args()
    288     verbosity_level = 0
    289     if options.v:
    290         verbosity_level = int(options.v)
    291121    if options.settings:
    292122        os.environ['DJANGO_SETTINGS_MODULE'] = options.settings
    293     t = TestRunner(verbosity_level, args)
    294     t.run_tests()
     123       
     124    django_tests(int(options.verbosity), args)
Back to Top