diff options
| author | Justin Bronn <jbronn@gmail.com> | 2008-03-23 17:18:58 +0000 |
|---|---|---|
| committer | Justin Bronn <jbronn@gmail.com> | 2008-03-23 17:18:58 +0000 |
| commit | 2efc34dc5e65da792700af6594c537104cbee9dc (patch) | |
| tree | d78d906a2d7ea692b5c2f100f792cf1c1991e669 /tests | |
| parent | b0a895f9e891bb1fc653724691e6d85612de2708 (diff) | |
gis: Merged revisions 7280-7353 via svnmerge from trunk.
git-svn-id: http://code.djangoproject.com/svn/django/branches/gis@7354 bcc190cf-cafb-0310-a4f2-bffc1f526a37
Diffstat (limited to 'tests')
| -rw-r--r-- | tests/modeltests/custom_pk/models.py | 5 | ||||
| -rw-r--r-- | tests/modeltests/lookup/models.py | 7 | ||||
| -rw-r--r-- | tests/modeltests/manipulators/models.py | 28 | ||||
| -rw-r--r-- | tests/modeltests/model_forms/models.py | 73 | ||||
| -rw-r--r-- | tests/modeltests/pagination/models.py | 199 | ||||
| -rw-r--r-- | tests/modeltests/validation/models.py | 24 | ||||
| -rw-r--r-- | tests/regressiontests/forms/extra.py | 83 | ||||
| -rw-r--r-- | tests/regressiontests/forms/fields.py | 27 | ||||
| -rw-r--r-- | tests/regressiontests/forms/forms.py | 159 | ||||
| -rw-r--r-- | tests/regressiontests/model_fields/models.py | 24 | ||||
| -rw-r--r-- | tests/regressiontests/syndication/__init__.py | 0 | ||||
| -rw-r--r-- | tests/regressiontests/syndication/models.py | 0 | ||||
| -rw-r--r-- | tests/regressiontests/syndication/tests.py | 14 | ||||
| -rw-r--r-- | tests/regressiontests/syndication/urls.py | 18 | ||||
| -rw-r--r-- | tests/regressiontests/test_client_regress/models.py | 30 | ||||
| -rw-r--r-- | tests/regressiontests/test_client_regress/urls.py | 1 | ||||
| -rw-r--r-- | tests/regressiontests/test_client_regress/views.py | 16 | ||||
| -rw-r--r-- | tests/urls.py | 3 |
18 files changed, 580 insertions, 131 deletions
diff --git a/tests/modeltests/custom_pk/models.py b/tests/modeltests/custom_pk/models.py index 381d81b987..e3edf3187e 100644 --- a/tests/modeltests/custom_pk/models.py +++ b/tests/modeltests/custom_pk/models.py @@ -71,8 +71,9 @@ u'ABC123' >>> fran.save() >>> Employee.objects.filter(last_name__exact='Jones') [<Employee: Dan Jones>, <Employee: Fran Jones>] ->>> Employee.objects.in_bulk(['ABC123', 'XYZ456']) -{u'XYZ456': <Employee: Fran Jones>, u'ABC123': <Employee: Dan Jones>} +>>> emps = Employee.objects.in_bulk(['ABC123', 'XYZ456']) +>>> emps['ABC123'] +<Employee: Dan Jones> >>> b = Business(name='Sears') >>> b.save() diff --git a/tests/modeltests/lookup/models.py b/tests/modeltests/lookup/models.py index aa90d1e5ec..f31857e0fe 100644 --- a/tests/modeltests/lookup/models.py +++ b/tests/modeltests/lookup/models.py @@ -76,8 +76,11 @@ Article 4 # in_bulk() takes a list of IDs and returns a dictionary mapping IDs # to objects. ->>> Article.objects.in_bulk([1, 2]) -{1: <Article: Article 1>, 2: <Article: Article 2>} +>>> arts = Article.objects.in_bulk([1, 2]) +>>> arts[1] +<Article: Article 1> +>>> arts[2] +<Article: Article 2> >>> Article.objects.in_bulk([3]) {3: <Article: Article 3>} >>> Article.objects.in_bulk([1000]) diff --git a/tests/modeltests/manipulators/models.py b/tests/modeltests/manipulators/models.py index c9b9848235..3e52e33bbb 100644 --- a/tests/modeltests/manipulators/models.py +++ b/tests/modeltests/manipulators/models.py @@ -41,25 +41,33 @@ __test__ = {'API_TESTS':u""" True # Attempt to add a Musician without a first_name. ->>> man.get_validation_errors(MultiValueDict({'last_name': ['Blakey']})) -{'first_name': [u'This field is required.']} +>>> man.get_validation_errors(MultiValueDict({'last_name': ['Blakey']}))['first_name'] +[u'This field is required.'] # Attempt to add a Musician without a first_name and last_name. ->>> man.get_validation_errors(MultiValueDict({})) -{'first_name': [u'This field is required.'], 'last_name': [u'This field is required.']} +>>> errors = man.get_validation_errors(MultiValueDict({})) +>>> errors['first_name'] +[u'This field is required.'] +>>> errors['last_name'] +[u'This field is required.'] # Attempt to create an Album without a name or musician. >>> man = Album.AddManipulator() ->>> man.get_validation_errors(MultiValueDict({})) -{'musician': [u'This field is required.'], 'name': [u'This field is required.']} +>>> errors = man.get_validation_errors(MultiValueDict({})) +>>> errors['musician'] +[u'This field is required.'] +>>> errors['name'] +[u'This field is required.'] # Attempt to create an Album with an invalid musician. ->>> man.get_validation_errors(MultiValueDict({'name': ['Sallies Fforth'], 'musician': ['foo']})) -{'musician': [u"Select a valid choice; 'foo' is not in [u'', u'1']."]} +>>> errors = man.get_validation_errors(MultiValueDict({'name': ['Sallies Fforth'], 'musician': ['foo']})) +>>> errors['musician'] +[u"Select a valid choice; 'foo' is not in [u'', u'1']."] # Attempt to create an Album with an invalid release_date. ->>> man.get_validation_errors(MultiValueDict({'name': ['Sallies Fforth'], 'musician': ['1'], 'release_date': 'today'})) -{'release_date': [u'Enter a valid date in YYYY-MM-DD format.']} +>>> errors = man.get_validation_errors(MultiValueDict({'name': ['Sallies Fforth'], 'musician': ['1'], 'release_date': 'today'})) +>>> errors['release_date'] +[u'Enter a valid date in YYYY-MM-DD format.'] # Create an Album without a release_date (because it's optional). >>> data = MultiValueDict({'name': ['Ella and Basie'], 'musician': ['1']}) diff --git a/tests/modeltests/model_forms/models.py b/tests/modeltests/model_forms/models.py index c480899f84..470312f5ca 100644 --- a/tests/modeltests/model_forms/models.py +++ b/tests/modeltests/model_forms/models.py @@ -234,8 +234,12 @@ We can also subclass the Meta inner class to change the fields list. >>> f = CategoryForm({'name': 'Entertainment', 'slug': 'entertainment', 'url': 'entertainment'}) >>> f.is_valid() True ->>> f.cleaned_data -{'url': u'entertainment', 'name': u'Entertainment', 'slug': u'entertainment'} +>>> f.cleaned_data['url'] +u'entertainment' +>>> f.cleaned_data['name'] +u'Entertainment' +>>> f.cleaned_data['slug'] +u'entertainment' >>> obj = f.save() >>> obj <Category: Entertainment> @@ -245,8 +249,12 @@ True >>> f = CategoryForm({'name': "It's a test", 'slug': 'its-test', 'url': 'test'}) >>> f.is_valid() True ->>> f.cleaned_data -{'url': u'test', 'name': u"It's a test", 'slug': u'its-test'} +>>> f.cleaned_data['url'] +u'test' +>>> f.cleaned_data['name'] +u"It's a test" +>>> f.cleaned_data['slug'] +u'its-test' >>> obj = f.save() >>> obj <Category: It's a test> @@ -259,8 +267,12 @@ save() on the resulting model instance. >>> f = CategoryForm({'name': 'Third test', 'slug': 'third-test', 'url': 'third'}) >>> f.is_valid() True ->>> f.cleaned_data -{'url': u'third', 'name': u'Third test', 'slug': u'third-test'} +>>> f.cleaned_data['url'] +u'third' +>>> f.cleaned_data['name'] +u'Third test' +>>> f.cleaned_data['slug'] +u'third-test' >>> obj = f.save(commit=False) >>> obj <Category: Third test> @@ -272,8 +284,10 @@ True If you call save() with invalid data, you'll get a ValueError. >>> f = CategoryForm({'name': '', 'slug': '', 'url': 'foo'}) ->>> f.errors -{'name': [u'This field is required.'], 'slug': [u'This field is required.']} +>>> f.errors['name'] +[u'This field is required.'] +>>> f.errors['slug'] +[u'This field is required.'] >>> f.cleaned_data Traceback (most recent call last): ... @@ -645,6 +659,19 @@ Traceback (most recent call last): ... ValidationError: [u'Select a valid choice. That choice is not one of the available choices.'] +# check that we can safely iterate choices repeatedly +>>> gen_one = list(f.choices) +>>> gen_two = f.choices +>>> gen_one[2] +(2L, u"It's a test") +>>> list(gen_two) +[(u'', u'---------'), (1L, u'Entertainment'), (2L, u"It's a test"), (3L, u'Third')] + +# check that we can override the label_from_instance method to print custom labels (#4620) +>>> f.queryset = Category.objects.all() +>>> f.label_from_instance = lambda obj: "category " + str(obj) +>>> list(f.choices) +[(u'', u'---------'), (1L, 'category Entertainment'), (2L, "category It's a test"), (3L, 'category Third'), (4L, 'category Fourth')] # ModelMultipleChoiceField #################################################### @@ -730,6 +757,10 @@ Traceback (most recent call last): ... ValidationError: [u'Select a valid choice. 4 is not one of the available choices.'] +>>> f.queryset = Category.objects.all() +>>> f.label_from_instance = lambda obj: "multicategory " + str(obj) +>>> list(f.choices) +[(1L, 'multicategory Entertainment'), (2L, "multicategory It's a test"), (3L, 'multicategory Third'), (4L, 'multicategory Fourth')] # PhoneNumberField ############################################################ @@ -739,8 +770,10 @@ ValidationError: [u'Select a valid choice. 4 is not one of the available choices >>> f = PhoneNumberForm({'phone': '(312) 555-1212', 'description': 'Assistance'}) >>> f.is_valid() True ->>> f.cleaned_data -{'phone': u'312-555-1212', 'description': u'Assistance'} +>>> f.cleaned_data['phone'] +u'312-555-1212' +>>> f.cleaned_data['description'] +u'Assistance' # FileField ################################################################### @@ -766,7 +799,7 @@ True <class 'django.newforms.fields.UploadedFile'> >>> instance = f.save() >>> instance.file -u'.../test1.txt' +u'...test1.txt' # Edit an instance that already has the file defined in the model. This will not # save the file again, but leave it exactly as it is. @@ -775,10 +808,10 @@ u'.../test1.txt' >>> f.is_valid() True >>> f.cleaned_data['file'] -u'.../test1.txt' +u'...test1.txt' >>> instance = f.save() >>> instance.file -u'.../test1.txt' +u'...test1.txt' # Delete the current file since this is not done by Django. @@ -791,7 +824,7 @@ u'.../test1.txt' True >>> instance = f.save() >>> instance.file -u'.../test2.txt' +u'...test2.txt' >>> instance.delete() @@ -810,7 +843,7 @@ True True >>> instance = f.save() >>> instance.file -u'.../test3.txt' +u'...test3.txt' >>> instance.delete() # ImageField ################################################################### @@ -832,7 +865,7 @@ True <class 'django.newforms.fields.UploadedFile'> >>> instance = f.save() >>> instance.image -u'.../test.png' +u'...test.png' # Edit an instance that already has the image defined in the model. This will not # save the image again, but leave it exactly as it is. @@ -841,10 +874,10 @@ u'.../test.png' >>> f.is_valid() True >>> f.cleaned_data['image'] -u'.../test.png' +u'...test.png' >>> instance = f.save() >>> instance.image -u'.../test.png' +u'...test.png' # Delete the current image since this is not done by Django. @@ -857,7 +890,7 @@ u'.../test.png' True >>> instance = f.save() >>> instance.image -u'.../test2.png' +u'...test2.png' >>> instance.delete() @@ -876,7 +909,7 @@ True True >>> instance = f.save() >>> instance.image -u'.../test3.png' +u'...test3.png' >>> instance.delete() """} diff --git a/tests/modeltests/pagination/models.py b/tests/modeltests/pagination/models.py index f44c67a139..277c5961e3 100644 --- a/tests/modeltests/pagination/models.py +++ b/tests/modeltests/pagination/models.py @@ -4,6 +4,11 @@ Django provides a framework for paginating a list of objects in a few lines of code. This is often useful for dividing search results or long lists of objects into easily readable pages. + +In Django 0.96 and earlier, a single ObjectPaginator class implemented this +functionality. In the Django development version, the behavior is split across +two classes -- Paginator and Page -- that are more easier to use. The legacy +ObjectPaginator class is deprecated. """ from django.db import models @@ -16,70 +21,210 @@ class Article(models.Model): return self.headline __test__ = {'API_TESTS':""" -# prepare a list of objects for pagination +# Prepare a list of objects for pagination. >>> from datetime import datetime >>> for x in range(1, 10): ... a = Article(headline='Article %s' % x, pub_date=datetime(2005, 7, 29)) ... a.save() -# create a basic paginator, 5 articles per page +#################################### +# New/current API (Paginator/Page) # +#################################### + +>>> from django.core.paginator import Paginator, InvalidPage +>>> paginator = Paginator(Article.objects.all(), 5) +>>> paginator.count +9 +>>> paginator.num_pages +2 +>>> paginator.page_range +[1, 2] + +# Get the first page. +>>> p = paginator.page(1) +>>> p +<Page 1 of 2> +>>> p.object_list +[<Article: Article 1>, <Article: Article 2>, <Article: Article 3>, <Article: Article 4>, <Article: Article 5>] +>>> p.has_next() +True +>>> p.has_previous() +False +>>> p.has_other_pages() +True +>>> p.next_page_number() +2 +>>> p.previous_page_number() +0 +>>> p.start_index() +1 +>>> p.end_index() +5 + +# Get the second page. +>>> p = paginator.page(2) +>>> p +<Page 2 of 2> +>>> p.object_list +[<Article: Article 6>, <Article: Article 7>, <Article: Article 8>, <Article: Article 9>] +>>> p.has_next() +False +>>> p.has_previous() +True +>>> p.has_other_pages() +True +>>> p.next_page_number() +3 +>>> p.previous_page_number() +1 +>>> p.start_index() +6 +>>> p.end_index() +9 + +# Invalid pages raise InvalidPage. +>>> paginator.page(0) +Traceback (most recent call last): +... +InvalidPage: ... +>>> paginator.page(3) +Traceback (most recent call last): +... +InvalidPage: ... + +# Empty paginators with allow_empty_first_page=True. +>>> paginator = Paginator(Article.objects.filter(id=0), 5, allow_empty_first_page=True) +>>> paginator.count +0 +>>> paginator.num_pages +1 +>>> paginator.page_range +[1] + +# Empty paginators with allow_empty_first_page=False. +>>> paginator = Paginator(Article.objects.filter(id=0), 5, allow_empty_first_page=False) +>>> paginator.count +0 +>>> paginator.num_pages +0 +>>> paginator.page_range +[] + +# Paginators work with regular lists/tuples, too -- not just with QuerySets. +>>> paginator = Paginator([1, 2, 3, 4, 5, 6, 7, 8, 9], 5) +>>> paginator.count +9 +>>> paginator.num_pages +2 +>>> paginator.page_range +[1, 2] + +# Get the first page. +>>> p = paginator.page(1) +>>> p +<Page 1 of 2> +>>> p.object_list +[1, 2, 3, 4, 5] +>>> p.has_next() +True +>>> p.has_previous() +False +>>> p.has_other_pages() +True +>>> p.next_page_number() +2 +>>> p.previous_page_number() +0 +>>> p.start_index() +1 +>>> p.end_index() +5 + +################################ +# Legacy API (ObjectPaginator) # +################################ + +# Don't print out the deprecation warnings during testing. +>>> from warnings import filterwarnings +>>> filterwarnings("ignore") + >>> from django.core.paginator import ObjectPaginator, InvalidPage >>> paginator = ObjectPaginator(Article.objects.all(), 5) - -# the paginator knows how many hits and pages it contains >>> paginator.hits 9 - >>> paginator.pages 2 +>>> paginator.page_range +[1, 2] -# get the first page (zero-based) +# Get the first page. >>> paginator.get_page(0) [<Article: Article 1>, <Article: Article 2>, <Article: Article 3>, <Article: Article 4>, <Article: Article 5>] - -# get the second page ->>> paginator.get_page(1) -[<Article: Article 6>, <Article: Article 7>, <Article: Article 8>, <Article: Article 9>] - -# does the first page have a next or previous page? >>> paginator.has_next_page(0) True - >>> paginator.has_previous_page(0) False +>>> paginator.first_on_page(0) +1 +>>> paginator.last_on_page(0) +5 -# check the second page +# Get the second page. +>>> paginator.get_page(1) +[<Article: Article 6>, <Article: Article 7>, <Article: Article 8>, <Article: Article 9>] >>> paginator.has_next_page(1) False - >>> paginator.has_previous_page(1) True - ->>> paginator.first_on_page(0) -1 >>> paginator.first_on_page(1) 6 ->>> paginator.last_on_page(0) -5 >>> paginator.last_on_page(1) 9 +# Invalid pages raise InvalidPage. +>>> paginator.get_page(-1) +Traceback (most recent call last): +... +InvalidPage: ... +>>> paginator.get_page(2) +Traceback (most recent call last): +... +InvalidPage: ... + +# Empty paginators with allow_empty_first_page=True. +>>> paginator = ObjectPaginator(Article.objects.filter(id=0), 5) +>>> paginator.count +0 +>>> paginator.num_pages +1 +>>> paginator.page_range +[1] + +################## +# Orphan support # +################## + # Add a few more records to test out the orphans feature. >>> for x in range(10, 13): ... Article(headline="Article %s" % x, pub_date=datetime(2006, 10, 6)).save() -# With orphans set to 3 and 10 items per page, we should get all 12 items on a single page: +# With orphans set to 3 and 10 items per page, we should get all 12 items on a single page. +>>> paginator = Paginator(Article.objects.all(), 10, orphans=3) +>>> paginator.num_pages +1 + +# With orphans only set to 1, we should get two pages. +>>> paginator = ObjectPaginator(Article.objects.all(), 10, orphans=1) +>>> paginator.num_pages +2 + +# LEGACY: With orphans set to 3 and 10 items per page, we should get all 12 items on a single page. >>> paginator = ObjectPaginator(Article.objects.all(), 10, orphans=3) >>> paginator.pages 1 -# With orphans only set to 1, we should get two pages: +# LEGACY: With orphans only set to 1, we should get two pages. >>> paginator = ObjectPaginator(Article.objects.all(), 10, orphans=1) >>> paginator.pages 2 - -# The paginator can provide a list of all available pages. ->>> paginator = ObjectPaginator(Article.objects.all(), 10) ->>> paginator.page_range -[1, 2] """} diff --git a/tests/modeltests/validation/models.py b/tests/modeltests/validation/models.py index aacd041678..63f9f7a361 100644 --- a/tests/modeltests/validation/models.py +++ b/tests/modeltests/validation/models.py @@ -41,8 +41,8 @@ __test__ = {'API_TESTS':""" 23 >>> p = Person(**dict(valid_params, id='foo')) ->>> p.validate() -{'id': [u'This value must be an integer.']} +>>> p.validate()['id'] +[u'This value must be an integer.'] >>> p = Person(**dict(valid_params, id=None)) >>> p.validate() @@ -75,8 +75,8 @@ True False >>> p = Person(**dict(valid_params, is_child='foo')) ->>> p.validate() -{'is_child': [u'This value must be either True or False.']} +>>> p.validate()['is_child'] +[u'This value must be either True or False.'] >>> p = Person(**dict(valid_params, name=u'Jose')) >>> p.validate() @@ -115,8 +115,8 @@ datetime.date(2000, 5, 3) datetime.date(2000, 5, 3) >>> p = Person(**dict(valid_params, birthdate='foo')) ->>> p.validate() -{'birthdate': [u'Enter a valid date in YYYY-MM-DD format.']} +>>> p.validate()['birthdate'] +[u'Enter a valid date in YYYY-MM-DD format.'] >>> p = Person(**dict(valid_params, favorite_moment=datetime.datetime(2002, 4, 3, 13, 23))) >>> p.validate() @@ -143,11 +143,15 @@ datetime.datetime(2002, 4, 3, 0, 0) u'john@example.com' >>> p = Person(**dict(valid_params, email=22)) ->>> p.validate() -{'email': [u'Enter a valid e-mail address.']} +>>> p.validate()['email'] +[u'Enter a valid e-mail address.'] # Make sure that Date and DateTime return validation errors and don't raise Python errors. ->>> Person(name='John Doe', is_child=True, email='abc@def.com').validate() -{'favorite_moment': [u'This field is required.'], 'birthdate': [u'This field is required.']} +>>> p = Person(name='John Doe', is_child=True, email='abc@def.com') +>>> errors = p.validate() +>>> errors['favorite_moment'] +[u'This field is required.'] +>>> errors['birthdate'] +[u'This field is required.'] """} diff --git a/tests/regressiontests/forms/extra.py b/tests/regressiontests/forms/extra.py index 9dff4071f1..a8b369715d 100644 --- a/tests/regressiontests/forms/extra.py +++ b/tests/regressiontests/forms/extra.py @@ -22,7 +22,7 @@ classes that demonstrate some of the library's abilities. >>> from django.newforms.extras import SelectDateWidget >>> w = SelectDateWidget(years=('2007','2008','2009','2010','2011','2012','2013','2014','2015','2016')) >>> print w.render('mydate', '') -<select name="mydate_month"> +<select name="mydate_month" id="id_mydate_month"> <option value="1">January</option> <option value="2">February</option> <option value="3">March</option> @@ -36,7 +36,7 @@ classes that demonstrate some of the library's abilities. <option value="11">November</option> <option value="12">December</option> </select> -<select name="mydate_day"> +<select name="mydate_day" id="id_mydate_day"> <option value="1">1</option> <option value="2">2</option> <option value="3">3</option> @@ -69,7 +69,7 @@ classes that demonstrate some of the library's abilities. <option value="30">30</option> <option value="31">31</option> </select> -<select name="mydate_year"> +<select name="mydate_year" id="id_mydate_year"> <option value="2007">2007</option> <option value="2008">2008</option> <option value="2009">2009</option> @@ -84,7 +84,7 @@ classes that demonstrate some of the library's abilities. >>> w.render('mydate', None) == w.render('mydate', '') True >>> print w.render('mydate', '2010-04-15') -<select name="mydate_month"> +<select name="mydate_month" id="id_mydate_month"> <option value="1">January</option> <option value="2">February</option> <option value="3">March</option> @@ -98,7 +98,7 @@ True <option value="11">November</option> <option value="12">December</option> </select> -<select name="mydate_day"> +<select name="mydate_day" id="id_mydate_day"> <option value="1">1</option> <option value="2">2</option> <option value="3">3</option> @@ -131,7 +131,74 @@ True <option value="30">30</option> <option value="31">31</option> </select> -<select name="mydate_year"> +<select name="mydate_year" id="id_mydate_year"> +<option value="2007">2007</option> +<option value="2008">2008</option> +<option value="2009">2009</option> +<option value="2010" selected="selected">2010</option> +<option value="2011">2011</option> +<option value="2012">2012</option> +<option value="2013">2013</option> +<option value="2014">2014</option> +<option value="2015">2015</option> +<option value="2016">2016</option> +</select> + +Accepts a datetime or a string: + +>>> w.render('mydate', datetime.date(2010, 4, 15)) == w.render('mydate', '2010-04-15') +True + +Invalid dates still render the failed date: +>>> print w.render('mydate', '2010-02-31') +<select name="mydate_month" id="id_mydate_month"> +<option value="1">January</option> +<option value="2" selected="selected">February</option> +<option value="3">March</option> +<option value="4">April</option> +<option value="5">May</option> +<option value="6">June</option> +<option value="7">July</option> +<option value="8">August</option> +<option value="9">September</option> +<option value="10">October</option> +<option value="11">November</option> +<option value="12">December</option> +</select> +<select name="mydate_day" id="id_mydate_day"> +<option value="1">1</option> +<option value="2">2</option> +<option value="3">3</option> +<option value="4">4</option> +<option value="5">5</option> +<option value="6">6</option> +<option value="7">7</option> +<option value="8">8</option> +<option value="9">9</option> +<option value="10">10</option> +<option value="11">11</option> +<option value="12">12</option> +<option value="13">13</option> +<option value="14">14</option> +<option value="15">15</option> +<option value="16">16</option> +<option value="17">17</option> +<option value="18">18</option> +<option value="19">19</option> +<option value="20">20</option> +<option value="21">21</option> +<option value="22">22</option> +<option value="23">23</option> +<option value="24">24</option> +<option value="25">25</option> +<option value="26">26</option> +<option value="27">27</option> +<option value="28">28</option> +<option value="29">29</option> +<option value="30">30</option> +<option value="31" selected="selected">31</option> +</select> +<select name="mydate_year" id="id_mydate_year"> <option value="2007">2007</option> <option value="2008">2008</option> <option value="2009">2009</option> @@ -252,8 +319,8 @@ ValidationError: [u'This field is required.'] </select> <input type="text" name="field1_2_0" value="2007-04-25" id="id_field1_2_0" /><input type="text" name="field1_2_1" value="06:24:00" id="id_field1_2_1" /></td></tr> ->>> f.cleaned_data -{'field1': u'some text,JP,2007-04-25 06:24:00'} +>>> f.cleaned_data['field1'] +u'some text,JP,2007-04-25 06:24:00' # IPAddressField ################################################################## diff --git a/tests/regressiontests/forms/fields.py b/tests/regressiontests/forms/fields.py index 9216210e09..9421d8c005 100644 --- a/tests/regressiontests/forms/fields.py +++ b/tests/regressiontests/forms/fields.py @@ -1133,6 +1133,33 @@ u'' >>> f.clean(None) u'' +# FilePathField ############################################################### + +>>> import os +>>> from django import newforms as forms +>>> path = forms.__file__ +>>> path = os.path.dirname(path) + '/' +>>> path +'.../django/newforms/' +>>> f = forms.FilePathField(path=path) +>>> f.choices.sort() +>>> f.choices +[('.../django/newforms/__init__.py', '__init__.py'), ('.../django/newforms/__init__.pyc', '__init__.pyc'), ('.../django/newforms/fields.py', 'fields.py'), ('.../django/newforms/fields.pyc', 'fields.pyc'), ('.../django/newforms/forms.py', 'forms.py'), ('.../django/newforms/forms.pyc', 'forms.pyc'), ('.../django/newforms/models.py', 'models.py'), ('.../django/newforms/models.pyc', 'models.pyc'), ('.../django/newforms/util.py', 'util.py'), ('.../django/newforms/util.pyc', 'util.pyc'), ('.../django/newforms/widgets.py', 'widgets.py'), ('.../django/newforms/widgets.pyc', 'widgets.pyc')] +>>> f.clean('fields.py') +Traceback (most recent call last): +... +ValidationError: [u'Select a valid choice. That choice is not one of the available choices.'] +>>> f.clean(path + 'fields.py') +u'.../django/newforms/fields.py' +>>> f = forms.FilePathField(path=path, match='^.*?\.py$') +>>> f.choices.sort() +>>> f.choices +[('.../django/newforms/__init__.py', '__init__.py'), ('.../django/newforms/fields.py', 'fields.py'), ('.../django/newforms/forms.py', 'forms.py'), ('.../django/newforms/models.py', 'models.py'), ('.../django/newforms/util.py', 'util.py'), ('.../django/newforms/widgets.py', 'widgets.py')] +>>> f = forms.FilePathField(path=path, recursive=True, match='^.*?\.py$') +>>> f.choices.sort() +>>> f.choices +[('.../django/newforms/__init__.py', '__init__.py'), ('.../django/newforms/extras/__init__.py', 'extras/__init__.py'), ('.../django/newforms/extras/widgets.py', 'extras/widgets.py'), ('.../django/newforms/fields.py', 'fields.py'), ('.../django/newforms/forms.py', 'forms.py'), ('.../django/newforms/models.py', 'models.py'), ('.../django/newforms/util.py', 'util.py'), ('.../django/newforms/widgets.py', 'widgets.py')] + # SplitDateTimeField ########################################################## >>> f = SplitDateTimeField() diff --git a/tests/regressiontests/forms/forms.py b/tests/regressiontests/forms/forms.py index 7c0cf8abf3..d7fa1780f5 100644 --- a/tests/regressiontests/forms/forms.py +++ b/tests/regressiontests/forms/forms.py @@ -36,8 +36,8 @@ True u'' >>> p.errors.as_text() u'' ->>> p.cleaned_data -{'first_name': u'John', 'last_name': u'Lennon', 'birthday': datetime.date(1940, 10, 9)} +>>> p.cleaned_data["first_name"], p.cleaned_data["last_name"], p.cleaned_data["birthday"] +(u'John', u'Lennon', datetime.date(1940, 10, 9)) >>> print p['first_name'] <input type="text" name="first_name" value="John" id="id_first_name" /> >>> print p['last_name'] @@ -68,8 +68,12 @@ Empty dictionaries are valid, too. >>> p = Person({}) >>> p.is_bound True ->>> p.errors -{'first_name': [u'This field is required.'], 'last_name': [u'This field is required.'], 'birthday': [u'This field is required.']} +>>> p.errors['first_name'] +[u'This field is required.'] +>>> p.errors['last_name'] +[u'This field is required.'] +>>> p.errors['birthday'] +[u'This field is required.'] >>> p.is_valid() False >>> p.cleaned_data @@ -137,8 +141,10 @@ u'<li><label for="id_first_name">First name:</label> <input type="text" name="fi u'<p><label for="id_first_name">First name:</label> <input type="text" name="first_name" value="John" id="id_first_name" /></p>\n<p><label for="id_last_name">Last name:</label> <input type="text" name="last_name" value="\u0160\u0110\u0106\u017d\u0107\u017e\u0161\u0111" id="id_last_name" /></p>\n<p><label for="id_birthday">Birthday:</label> <input type="text" name="birthday" value="1940-10-9" id="id_birthday" /></p>' >>> p = Person({'last_name': u'Lennon'}) ->>> p.errors -{'first_name': [u'This field is required.'], 'birthday': [u'This field is required.']} +>>> p.errors['first_name'] +[u'This field is required.'] +>>> p.errors['birthday'] +[u'This field is required.'] >>> p.is_valid() False >>> p.errors.as_ul() @@ -175,8 +181,13 @@ but cleaned_data contains only the form's fields. >>> p = Person(data) >>> p.is_valid() True ->>> p.cleaned_data -{'first_name': u'John', 'last_name': u'Lennon', 'birthday': datetime.date(1940, 10, 9)} +>>> p.cleaned_data['first_name'] +u'John' +>>> p.cleaned_data['last_name'] +u'Lennon' +>>> p.cleaned_data['birthday'] +datetime.date(1940, 10, 9) + cleaned_data will include a key and value for *all* fields defined in the Form, even if the Form's data didn't include a value for fields that are not @@ -191,8 +202,12 @@ empty string. >>> f = OptionalPersonForm(data) >>> f.is_valid() True ->>> f.cleaned_data -{'nick_name': u'', 'first_name': u'John', 'last_name': u'Lennon'} +>>> f.cleaned_data['nick_name'] +u'' +>>> f.cleaned_data['first_name'] +u'John' +>>> f.cleaned_data['last_name'] +u'Lennon' For DateFields, it's set to None. >>> class OptionalPersonForm(Form): @@ -203,8 +218,12 @@ For DateFields, it's set to None. >>> f = OptionalPersonForm(data) >>> f.is_valid() True ->>> f.cleaned_data -{'birth_date': None, 'first_name': u'John', 'last_name': u'Lennon'} +>>> print f.cleaned_data['birth_date'] +None +>>> f.cleaned_data['first_name'] +u'John' +>>> f.cleaned_data['last_name'] +u'Lennon' "auto_id" tells the Form to add an "id" attribute to each form element. If it's a string that contains '%s', Django will use that as a format string @@ -549,18 +568,22 @@ The MultipleHiddenInput widget renders multiple values as hidden fields. When using CheckboxSelectMultiple, the framework expects a list of input and returns a list of input. >>> f = SongForm({'name': 'Yesterday'}, auto_id=False) ->>> f.errors -{'composers': [u'This field is required.']} +>>> f.errors['composers'] +[u'This field is required.'] >>> f = SongForm({'name': 'Yesterday', 'composers': ['J']}, auto_id=False) >>> f.errors {} ->>> f.cleaned_data -{'composers': [u'J'], 'name': u'Yesterday'} +>>> f.cleaned_data['composers'] +[u'J'] +>>> f.cleaned_data['name'] +u'Yesterday' >>> f = SongForm({'name': 'Yesterday', 'composers': ['J', 'P']}, auto_id=False) >>> f.errors {} ->>> f.cleaned_data -{'composers': [u'J', u'P'], 'name': u'Yesterday'} +>>> f.cleaned_data['composers'] +[u'J', u'P'] +>>> f.cleaned_data['name'] +u'Yesterday' Validation errors are HTML-escaped when output as HTML. >>> class EscapingForm(Form): @@ -598,16 +621,24 @@ including the current field (e.g., the field XXX if you're in clean_XXX()). >>> f.errors {} >>> f = UserRegistration({}, auto_id=False) ->>> f.errors -{'username': [u'This field is required.'], 'password1': [u'This field is required.'], 'password2': [u'This field is required.']} +>>> f.errors['username'] +[u'This field is required.'] +>>> f.errors['password1'] +[u'This field is required.'] +>>> f.errors['password2'] +[u'This field is required.'] >>> f = UserRegistration({'username': 'adrian', 'password1': 'foo', 'password2': 'bar'}, auto_id=False) ->>> f.errors -{'password2': [u'Please make sure your passwords match.']} +>>> f.errors['password2'] +[u'Please make sure your passwords match.'] >>> f = UserRegistration({'username': 'adrian', 'password1': 'foo', 'password2': 'foo'}, auto_id=False) >>> f.errors {} ->>> f.cleaned_data -{'username': u'adrian', 'password1': u'foo', 'password2': u'foo'} +>>> f.cleaned_data['username'] +u'adrian' +>>> f.cleaned_data['password1'] +u'foo' +>>> f.cleaned_data['password2'] +u'foo' Another way of doing multiple-field validation is by implementing the Form's clean() method. If you do this, any ValidationError raised by that @@ -632,11 +663,15 @@ Form.clean() is required to return a dictionary of all clean data. <tr><th>Username:</th><td><ul class="errorlist"><li>This field is required.</li></ul><input type="text" name="username" maxlength="10" /></td></tr> <tr><th>Password1:</th><td><ul class="errorlist"><li>This field is required.</li></ul><input type="password" name="password1" /></td></tr> <tr><th>Password2:</th><td><ul class="errorlist"><li>This field is required.</li></ul><input type="password" name="password2" /></td></tr> ->>> f.errors -{'username': [u'This field is required.'], 'password1': [u'This field is required.'], 'password2': [u'This field is required.']} +>>> f.errors['username'] +[u'This field is required.'] +>>> f.errors['password1'] +[u'This field is required.'] +>>> f.errors['password2'] +[u'This field is required.'] >>> f = UserRegistration({'username': 'adrian', 'password1': 'foo', 'password2': 'bar'}, auto_id=False) ->>> f.errors -{'__all__': [u'Please make sure your passwords match.']} +>>> f.errors['__all__'] +[u'Please make sure your passwords match.'] >>> print f.as_table() <tr><td colspan="2"><ul class="errorlist"><li>Please make sure your passwords match.</li></ul></td></tr> <tr><th>Username:</th><td><input type="text" name="username" value="adrian" maxlength="10" /></td></tr> @@ -650,8 +685,12 @@ Form.clean() is required to return a dictionary of all clean data. >>> f = UserRegistration({'username': 'adrian', 'password1': 'foo', 'password2': 'foo'}, auto_id=False) >>> f.errors {} ->>> f.cleaned_data -{'username': u'adrian', 'password1': u'foo', 'password2': u'foo'} +>>> f.cleaned_data['username'] +u'adrian' +>>> f.cleaned_data['password1'] +u'foo' +>>> f.cleaned_data['password2'] +u'foo' # Dynamic construction ######################################################## @@ -1024,8 +1063,8 @@ An 'initial' value is *not* used as a fallback if data is not provided. In this example, we don't provide a value for 'username', and the form raises a validation error rather than using the initial value for 'username'. >>> p = UserRegistration({'password': 'secret'}) ->>> p.errors -{'username': [u'This field is required.']} +>>> p.errors['username'] +[u'This field is required.'] >>> p.is_valid() False @@ -1069,8 +1108,8 @@ A dynamic 'initial' value is *not* used as a fallback if data is not provided. In this example, we don't provide a value for 'username', and the form raises a validation error rather than using the initial value for 'username'. >>> p = UserRegistration({'password': 'secret'}, initial={'username': 'django'}) ->>> p.errors -{'username': [u'This field is required.']} +>>> p.errors['username'] +[u'This field is required.'] >>> p.is_valid() False @@ -1123,8 +1162,8 @@ A callable 'initial' value is *not* used as a fallback if data is not provided. In this example, we don't provide a value for 'username', and the form raises a validation error rather than using the initial value for 'username'. >>> p = UserRegistration({'password': 'secret'}, initial={'username': initial_django}) ->>> p.errors -{'username': [u'This field is required.']} +>>> p.errors['username'] +[u'This field is required.'] >>> p.is_valid() False @@ -1258,8 +1297,12 @@ actual field name. {} >>> p.is_valid() True ->>> p.cleaned_data -{'first_name': u'John', 'last_name': u'Lennon', 'birthday': datetime.date(1940, 10, 9)} +>>> p.cleaned_data['first_name'] +u'John' +>>> p.cleaned_data['last_name'] +u'Lennon' +>>> p.cleaned_data['birthday'] +datetime.date(1940, 10, 9) Let's try submitting some bad data to make sure form.errors and field.errors work as expected. @@ -1269,8 +1312,12 @@ work as expected. ... 'person1-birthday': u'' ... } >>> p = Person(data, prefix='person1') ->>> p.errors -{'first_name': [u'This field is required.'], 'last_name': [u'This field is required.'], 'birthday': [u'This field is required.']} +>>> p.errors['first_name'] +[u'This field is required.'] +>>> p.errors['last_name'] +[u'This field is required.'] +>>> p.errors['birthday'] +[u'This field is required.'] >>> p['first_name'].errors [u'This field is required.'] >>> p['person1-first_name'].errors @@ -1286,8 +1333,12 @@ the form doesn't "see" the fields. ... 'birthday': u'1940-10-9' ... } >>> p = Person(data, prefix='person1') ->>> p.errors -{'first_name': [u'This field is required.'], 'last_name': [u'This field is required.'], 'birthday': [u'This field is required.']} +>>> p.errors['first_name'] +[u'This field is required.'] +>>> p.errors['last_name'] +[u'This field is required.'] +>>> p.errors['birthday'] +[u'This field is required.'] With prefixes, a single data dictionary can hold data for multiple instances of the same form. @@ -1302,13 +1353,21 @@ of the same form. >>> p1 = Person(data, prefix='person1') >>> p1.is_valid() True ->>> p1.cleaned_data -{'first_name': u'John', 'last_name': u'Lennon', 'birthday': datetime.date(1940, 10, 9)} +>>> p1.cleaned_data['first_name'] +u'John' +>>> p1.cleaned_data['last_name'] +u'Lennon' +>>> p1.cleaned_data['birthday'] +datetime.date(1940, 10, 9) >>> p2 = Person(data, prefix='person2') >>> p2.is_valid() True ->>> p2.cleaned_data -{'first_name': u'Jim', 'last_name': u'Morrison', 'birthday': datetime.date(1943, 12, 8)} +>>> p2.cleaned_data['first_name'] +u'Jim' +>>> p2.cleaned_data['last_name'] +u'Morrison' +>>> p2.cleaned_data['birthday'] +datetime.date(1943, 12, 8) By default, forms append a hyphen between the prefix and the field name, but a form can alter that behavior by implementing the add_prefix() method. This @@ -1333,8 +1392,12 @@ self.prefix. >>> p = Person(data, prefix='foo') >>> p.is_valid() True ->>> p.cleaned_data -{'first_name': u'John', 'last_name': u'Lennon', 'birthday': datetime.date(1940, 10, 9)} +>>> p.cleaned_data['first_name'] +u'John' +>>> p.cleaned_data['last_name'] +u'Lennon' +>>> p.cleaned_data['birthday'] +datetime.date(1940, 10, 9) # Forms with NullBooleanFields ################################################ diff --git a/tests/regressiontests/model_fields/models.py b/tests/regressiontests/model_fields/models.py index e69de29bb2..7e07227961 100644 --- a/tests/regressiontests/model_fields/models.py +++ b/tests/regressiontests/model_fields/models.py @@ -0,0 +1,24 @@ + +from django.db import models + +class Foo(models.Model): + a = models.CharField(max_length=10) + +def get_foo(): + return Foo.objects.get(id=1) + +class Bar(models.Model): + b = models.CharField(max_length=10) + a = models.ForeignKey(Foo, default=get_foo) + +__test__ = {'API_TESTS':""" +# Create a couple of Places. +>>> f = Foo.objects.create(a='abc') +>>> f.id +1 +>>> b = Bar(b = "bcd") +>>> b.a +<Foo: Foo object> +>>> b.save() + +"""} diff --git a/tests/regressiontests/syndication/__init__.py b/tests/regressiontests/syndication/__init__.py new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/regressiontests/syndication/__init__.py diff --git a/tests/regressiontests/syndication/models.py b/tests/regressiontests/syndication/models.py new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/regressiontests/syndication/models.py diff --git a/tests/regressiontests/syndication/tests.py b/tests/regressiontests/syndication/tests.py new file mode 100644 index 0000000000..6a9dd643d7 --- /dev/null +++ b/tests/regressiontests/syndication/tests.py @@ -0,0 +1,14 @@ +# -*- coding: utf-8 -*- + +from django.test import TestCase +from django.test.client import Client + +class SyndicationFeedTest(TestCase): + def test_complex_base_url(self): + """ + Tests that that the base url for a complex feed doesn't raise a 500 + exception. + """ + c = Client() + response = c.get('/syndication/feeds/complex/') + self.assertEquals(response.status_code, 404) diff --git a/tests/regressiontests/syndication/urls.py b/tests/regressiontests/syndication/urls.py new file mode 100644 index 0000000000..24644ffd53 --- /dev/null +++ b/tests/regressiontests/syndication/urls.py @@ -0,0 +1,18 @@ +from django.conf.urls.defaults import patterns +from django.core.exceptions import ObjectDoesNotExist +from django.contrib.syndication import feeds + + +class ComplexFeed(feeds.Feed): + def get_object(self, bits): + if len(bits) != 1: + raise ObjectDoesNotExist + return None + + +urlpatterns = patterns('', + (r'^feeds/(?P<url>.*)/$', 'django.contrib.syndication.views.feed', { + 'feed_dict': dict( + complex = ComplexFeed, + )}), +) diff --git a/tests/regressiontests/test_client_regress/models.py b/tests/regressiontests/test_client_regress/models.py index b5d9ae63b9..305ccc9aa3 100644 --- a/tests/regressiontests/test_client_regress/models.py +++ b/tests/regressiontests/test_client_regress/models.py @@ -3,7 +3,7 @@ Regression tests for the Test Client, especially the customized assertions. """ from django.test import Client, TestCase -from django.core import mail +from django.core.urlresolvers import reverse import os class AssertContainsTests(TestCase): @@ -261,3 +261,31 @@ class LoginTests(TestCase): # Check that assertRedirects uses the original client, not the # default client. self.assertRedirects(response, "http://testserver/test_client_regress/get_view/") + + +class URLEscapingTests(TestCase): + def test_simple_argument_get(self): + "Get a view that has a simple string argument" + response = self.client.get(reverse('arg_view', args=['Slartibartfast'])) + self.assertEqual(response.status_code, 200) + self.assertEqual(response.content, 'Howdy, Slartibartfast') + + def test_argument_with_space_get(self): + "Get a view that has a string argument that requires escaping" + response = self.client.get(reverse('arg_view', args=['Arthur Dent'])) + self.assertEqual(response.status_code, 200) + self.assertEqual(response.content, 'Hi, Arthur') + + def test_simple_argument_post(self): + "Post for a view that has a simple string argument" + response = self.client.post(reverse('arg_view', args=['Slartibartfast'])) + self.assertEqual(response.status_code, 200) + self.assertEqual(response.content, 'Howdy, Slartibartfast') + + def test_argument_with_space_post(self): + "Post for a view that has a string argument that requires escaping" + response = self.client.post(reverse('arg_view', args=['Arthur Dent'])) + self.assertEqual(response.status_code, 200) + self.assertEqual(response.content, 'Hi, Arthur') + + diff --git a/tests/regressiontests/test_client_regress/urls.py b/tests/regressiontests/test_client_regress/urls.py index e771707f61..d3304caef0 100644 --- a/tests/regressiontests/test_client_regress/urls.py +++ b/tests/regressiontests/test_client_regress/urls.py @@ -5,5 +5,6 @@ urlpatterns = patterns('', (r'^no_template_view/$', views.no_template_view), (r'^file_upload/$', views.file_upload_view), (r'^get_view/$', views.get_view), + url(r'^arg_view/(?P<name>.+)/$', views.view_with_argument, name='arg_view'), (r'^login_protected_redirect_view/$', views.login_protected_redirect_view) ) diff --git a/tests/regressiontests/test_client_regress/views.py b/tests/regressiontests/test_client_regress/views.py index 75efd212e1..f44757dc10 100644 --- a/tests/regressiontests/test_client_regress/views.py +++ b/tests/regressiontests/test_client_regress/views.py @@ -1,7 +1,5 @@ from django.contrib.auth.decorators import login_required -from django.core.mail import EmailMessage, SMTPConnection from django.http import HttpResponse, HttpResponseRedirect, HttpResponseServerError -from django.shortcuts import render_to_response def no_template_view(request): "A simple view that expects a GET request, and returns a rendered template" @@ -20,10 +18,22 @@ def file_upload_view(request): return HttpResponseServerError() def get_view(request): - "A simple login protected view" + "A simple login protected view" return HttpResponse("Hello world") get_view = login_required(get_view) +def view_with_argument(request, name): + """A view that takes a string argument + + The purpose of this view is to check that if a space is provided in + the argument, the test framework unescapes the %20 before passing + the value to the view. + """ + if name == 'Arthur Dent': + return HttpResponse('Hi, Arthur') + else: + return HttpResponse('Howdy, %s' % name) + def login_protected_redirect_view(request): "A view that redirects all requests to the GET view" return HttpResponseRedirect('/test_client_regress/get_view/') diff --git a/tests/urls.py b/tests/urls.py index 41b4aaf6d3..dbdf9a8064 100644 --- a/tests/urls.py +++ b/tests/urls.py @@ -19,4 +19,7 @@ urlpatterns = patterns('', (r'^middleware/', include('regressiontests.middleware.urls')), (r'^utils/', include('regressiontests.utils.urls')), + + # test urlconf for syndication tests + (r'^syndication/', include('regressiontests.syndication.urls')), ) |
