summaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
authorJustin Bronn <jbronn@gmail.com>2007-12-15 01:38:43 +0000
committerJustin Bronn <jbronn@gmail.com>2007-12-15 01:38:43 +0000
commit34560a01daee3c42a7c5ec462f38a485cccf4df7 (patch)
treec332688943fb10b1503654815a06093c1d52e493 /tests
parent5799c2e048ff829300af88ae839de20e1763ee1d (diff)
gis: Merged revisions 6672,6686-6688,6690,6693,6707-6708,6726,6730,6753,6755-6762,6764,6776-6777,6779,6782-6919 via svnmerge from trunk; reverted oracle backend `base.py` due to ikelly's patch in r6905.
git-svn-id: http://code.djangoproject.com/svn/django/branches/gis@6920 bcc190cf-cafb-0310-a4f2-bffc1f526a37
Diffstat (limited to 'tests')
-rw-r--r--tests/modeltests/empty/models.py2
-rw-r--r--tests/modeltests/field_defaults/models.py5
-rw-r--r--tests/modeltests/generic_relations/models.py30
-rw-r--r--tests/modeltests/get_object_or_404/models.py2
-rw-r--r--tests/modeltests/invalid_models/models.py6
-rw-r--r--tests/modeltests/model_forms/models.py292
-rw-r--r--tests/modeltests/select_related/models.py2
-rw-r--r--tests/modeltests/serializers/models.py40
-rw-r--r--tests/modeltests/test_client/models.py2
-rw-r--r--tests/modeltests/user_commands/models.py4
-rw-r--r--tests/regressiontests/cache/tests.py60
-rw-r--r--tests/regressiontests/defaultfilters/tests.py12
-rw-r--r--tests/regressiontests/forms/localflavor/za.py40
-rw-r--r--tests/regressiontests/forms/tests.py2
-rw-r--r--tests/regressiontests/i18n/tests.py15
-rw-r--r--tests/regressiontests/maxlength/tests.py6
-rw-r--r--tests/regressiontests/middleware/__init__.py0
-rw-r--r--tests/regressiontests/middleware/tests.py93
-rw-r--r--tests/regressiontests/middleware/urls.py7
-rw-r--r--tests/regressiontests/model_regress/models.py10
-rw-r--r--tests/regressiontests/string_lookup/models.py8
-rw-r--r--tests/regressiontests/templates/context.py18
-rw-r--r--tests/regressiontests/templates/tests.py2
-rw-r--r--tests/regressiontests/views/views.py2
-rwxr-xr-xtests/runtests.py3
-rw-r--r--tests/urls.py3
26 files changed, 499 insertions, 167 deletions
diff --git a/tests/modeltests/empty/models.py b/tests/modeltests/empty/models.py
index 2493b53837..d57087134e 100644
--- a/tests/modeltests/empty/models.py
+++ b/tests/modeltests/empty/models.py
@@ -1,5 +1,5 @@
"""
-39. Empty model tests
+40. Empty model tests
These test that things behave sensibly for the rare corner-case of a model with
no fields.
diff --git a/tests/modeltests/field_defaults/models.py b/tests/modeltests/field_defaults/models.py
index 1132f1ca41..fe80cce406 100644
--- a/tests/modeltests/field_defaults/models.py
+++ b/tests/modeltests/field_defaults/models.py
@@ -48,4 +48,9 @@ u'Default headline'
>>> d = now - a.pub_date
>>> d.seconds < 5
True
+
+# make sure that SafeUnicode fields work
+>>> from django.utils.safestring import SafeUnicode
+>>> a.headline = SafeUnicode(u'SafeUnicode Headline')
+>>> a.save()
"""}
diff --git a/tests/modeltests/generic_relations/models.py b/tests/modeltests/generic_relations/models.py
index ce1d824ca8..ff86823d07 100644
--- a/tests/modeltests/generic_relations/models.py
+++ b/tests/modeltests/generic_relations/models.py
@@ -18,42 +18,42 @@ class TaggedItem(models.Model):
tag = models.SlugField()
content_type = models.ForeignKey(ContentType)
object_id = models.PositiveIntegerField()
-
+
content_object = generic.GenericForeignKey()
-
+
class Meta:
ordering = ["tag"]
-
+
def __unicode__(self):
return self.tag
class Animal(models.Model):
common_name = models.CharField(max_length=150)
latin_name = models.CharField(max_length=150)
-
+
tags = generic.GenericRelation(TaggedItem)
def __unicode__(self):
return self.common_name
-
+
class Vegetable(models.Model):
name = models.CharField(max_length=150)
is_yucky = models.BooleanField(default=True)
-
+
tags = generic.GenericRelation(TaggedItem)
-
+
def __unicode__(self):
return self.name
-
+
class Mineral(models.Model):
name = models.CharField(max_length=150)
hardness = models.PositiveSmallIntegerField()
-
+
# note the lack of an explicit GenericRelation here...
-
+
def __unicode__(self):
return self.name
-
+
__test__ = {'API_TESTS':"""
# Create the world in 7 lines of code...
>>> lion = Animal(common_name="Lion", latin_name="Panthera leo")
@@ -117,13 +117,13 @@ __test__ = {'API_TESTS':"""
>>> [(t.tag, t.content_type, t.object_id) for t in TaggedItem.objects.all()]
[(u'clearish', <ContentType: mineral>, 1), (u'fatty', <ContentType: vegetable>, 2), (u'salty', <ContentType: vegetable>, 2), (u'shiny', <ContentType: animal>, 2)]
-# If Generic Relation is not explicitly defined, any related objects
+# If Generic Relation is not explicitly defined, any related objects
# remain after deletion of the source object.
>>> quartz.delete()
>>> [(t.tag, t.content_type, t.object_id) for t in TaggedItem.objects.all()]
[(u'clearish', <ContentType: mineral>, 1), (u'fatty', <ContentType: vegetable>, 2), (u'salty', <ContentType: vegetable>, 2), (u'shiny', <ContentType: animal>, 2)]
-# If you delete a tag, the objects using the tag are unaffected
+# If you delete a tag, the objects using the tag are unaffected
# (other than losing a tag)
>>> tag = TaggedItem.objects.get(id=1)
>>> tag.delete()
@@ -132,4 +132,8 @@ __test__ = {'API_TESTS':"""
>>> [(t.tag, t.content_type, t.object_id) for t in TaggedItem.objects.all()]
[(u'clearish', <ContentType: mineral>, 1), (u'salty', <ContentType: vegetable>, 2), (u'shiny', <ContentType: animal>, 2)]
+>>> ctype = ContentType.objects.get_for_model(lion)
+>>> Animal.objects.filter(tags__content_type=ctype)
+[<Animal: Platypus>]
+
"""}
diff --git a/tests/modeltests/get_object_or_404/models.py b/tests/modeltests/get_object_or_404/models.py
index bd800317d3..d9f276b024 100644
--- a/tests/modeltests/get_object_or_404/models.py
+++ b/tests/modeltests/get_object_or_404/models.py
@@ -78,7 +78,7 @@ Http404: No Article matches the given query.
>>> get_object_or_404(Author.objects.all())
Traceback (most recent call last):
...
-AssertionError: get() returned more than one Author -- it returned ...! Lookup parameters were {}
+MultipleObjectsReturned: get() returned more than one Author -- it returned ...! Lookup parameters were {}
# Using an EmptyQuerySet raises a Http404 error.
>>> get_object_or_404(Article.objects.none(), title__contains="Run")
diff --git a/tests/modeltests/invalid_models/models.py b/tests/modeltests/invalid_models/models.py
index b746af6dba..8a480a2381 100644
--- a/tests/modeltests/invalid_models/models.py
+++ b/tests/modeltests/invalid_models/models.py
@@ -108,6 +108,10 @@ class Car(models.Model):
colour = models.CharField(max_length=5)
model = models.ForeignKey(Model)
+class MissingRelations(models.Model):
+ rel1 = models.ForeignKey("Rel1")
+ rel2 = models.ManyToManyField("Rel2")
+
model_errors = """invalid_models.fielderrors: "charfield": CharFields require a "max_length" attribute.
invalid_models.fielderrors: "decimalfield": DecimalFields require a "decimal_places" attribute.
invalid_models.fielderrors: "decimalfield": DecimalFields require a "max_digits" attribute.
@@ -191,4 +195,6 @@ invalid_models.selfclashm2m: Accessor for m2m field 'm2m_4' clashes with related
invalid_models.selfclashm2m: Accessor for m2m field 'm2m_4' clashes with related m2m field 'SelfClashM2M.selfclashm2m_set'. Add a related_name argument to the definition for 'm2m_4'.
invalid_models.selfclashm2m: Reverse query name for m2m field 'm2m_3' clashes with field 'SelfClashM2M.selfclashm2m'. Add a related_name argument to the definition for 'm2m_3'.
invalid_models.selfclashm2m: Reverse query name for m2m field 'm2m_4' clashes with field 'SelfClashM2M.selfclashm2m'. Add a related_name argument to the definition for 'm2m_4'.
+invalid_models.missingrelations: 'rel2' has m2m relation with model Rel2, which has not been installed
+invalid_models.missingrelations: 'rel1' has relation with model Rel1, which has not been installed
"""
diff --git a/tests/modeltests/model_forms/models.py b/tests/modeltests/model_forms/models.py
index 9b0126ff4f..17c3b3551c 100644
--- a/tests/modeltests/model_forms/models.py
+++ b/tests/modeltests/model_forms/models.py
@@ -1,25 +1,10 @@
"""
-36. Generating HTML forms from models
+XX. Generating HTML forms from models
-Django provides shortcuts for creating Form objects from a model class and a
-model instance.
-
-The function django.newforms.form_for_model() takes a model class and returns
-a Form that is tied to the model. This Form works just like any other Form,
-with one additional method: save(). The save() method creates an instance
-of the model and returns that newly created instance. It saves the instance to
-the database if save(commit=True), which is default. If you pass
-commit=False, then you'll get the object without committing the changes to the
-database.
-
-The function django.newforms.form_for_instance() takes a model instance and
-returns a Form that is tied to the instance. This form works just like any
-other Form, with one additional method: save(). The save()
-method updates the model instance. It also takes a commit=True parameter.
-
-The function django.newforms.save_instance() takes a bound form instance and a
-model instance and saves the form's cleaned_data into the instance. It also takes
-a commit=True parameter.
+This is mostly just a reworking of the form_for_model/form_for_instance tests
+to use ModelForm. As such, the text may not make sense in all cases, and the
+examples are probably a poor fit for the ModelForm syntax. In other words,
+most of these tests should be rewritten.
"""
from django.db import models
@@ -30,23 +15,6 @@ ARTICLE_STATUS = (
(3, 'Live'),
)
-STEERING_TYPE = (
- ('left', 'Left steering wheel'),
- ('right', 'Right steering wheel'),
-)
-
-FUEL_TYPE = (
- ('gas', 'Gasoline'),
- ('diesel', 'Diesel'),
- ('other', 'Other'),
-)
-
-TRANSMISSION_TYPE = (
- ('at', 'Automatic'),
- ('mt', 'Manual'),
- ('cvt', 'CVT'),
-)
-
class Category(models.Model):
name = models.CharField(max_length=20)
slug = models.SlugField(max_length=20)
@@ -87,20 +55,124 @@ class PhoneNumber(models.Model):
def __unicode__(self):
return self.phone
-class Car(models.Model):
- name = models.CharField(max_length=50)
- steering = models.CharField(max_length=5, choices=STEERING_TYPE, default='left')
- fuel = models.CharField(max_length=10, choices=FUEL_TYPE)
- transmission = models.CharField(max_length=3, choices=TRANSMISSION_TYPE, blank=True, help_text='Leave empty if not applicable.')
-
__test__ = {'API_TESTS': """
->>> from django.newforms import form_for_model, form_for_instance, save_instance, BaseForm, Form, CharField
+>>> from django import newforms as forms
+>>> from django.newforms.models import ModelForm
+
+The bare bones, absolutely nothing custom, basic case.
+
+>>> class CategoryForm(ModelForm):
+... class Meta:
+... model = Category
+>>> CategoryForm.base_fields.keys()
+['name', 'slug', 'url']
+
+
+Extra fields.
+
+>>> class CategoryForm(ModelForm):
+... some_extra_field = forms.BooleanField()
+...
+... class Meta:
+... model = Category
+
+>>> CategoryForm.base_fields.keys()
+['name', 'slug', 'url', 'some_extra_field']
+
+
+Replacing a field.
+
+>>> class CategoryForm(ModelForm):
+... url = forms.BooleanField()
+...
+... class Meta:
+... model = Category
+
+>>> CategoryForm.base_fields['url'].__class__
+<class 'django.newforms.fields.BooleanField'>
+
+
+Using 'fields'.
+
+>>> class CategoryForm(ModelForm):
+...
+... class Meta:
+... model = Category
+... fields = ['url']
+
+>>> CategoryForm.base_fields.keys()
+['url']
+
+
+Using 'exclude'
+
+>>> class CategoryForm(ModelForm):
+...
+... class Meta:
+... model = Category
+... exclude = ['url']
+
+>>> CategoryForm.base_fields.keys()
+['name', 'slug']
+
+
+Using 'fields' *and* 'exclude'. Not sure why you'd want to do this, but uh,
+"be liberal in what you accept" and all.
+
+>>> class CategoryForm(ModelForm):
+...
+... class Meta:
+... model = Category
+... fields = ['name', 'url']
+... exclude = ['url']
+
+>>> CategoryForm.base_fields.keys()
+['name']
+
+Don't allow more than one 'model' definition in the inheritance hierarchy.
+Technically, it would generate a valid form, but the fact that the resulting
+save method won't deal with multiple objects is likely to trip up people not
+familiar with the mechanics.
+
+>>> class CategoryForm(ModelForm):
+... class Meta:
+... model = Category
+
+>>> class BadForm(CategoryForm):
+... class Meta:
+... model = Article
+Traceback (most recent call last):
+...
+ImproperlyConfigured: BadForm defines a different model than its parent.
+
+>>> class ArticleForm(ModelForm):
+... class Meta:
+... model = Article
+
+>>> class BadForm(ArticleForm, CategoryForm):
+... pass
+Traceback (most recent call last):
+...
+ImproperlyConfigured: BadForm's base classes define more than one model.
+
+This one is OK since the subclass specifies the same model as the parent.
+
+>>> class SubCategoryForm(CategoryForm):
+... class Meta:
+... model = Category
+
+
+# Old form_for_x tests #######################################################
+
+>>> from django.newforms import ModelForm, CharField
>>> import datetime
>>> Category.objects.all()
[]
->>> CategoryForm = form_for_model(Category)
+>>> class CategoryForm(ModelForm):
+... class Meta:
+... model = Category
>>> f = CategoryForm()
>>> print f
<tr><th><label for="id_name">Name:</label></th><td><input id="id_name" type="text" name="name" maxlength="20" /></td></tr>
@@ -184,7 +256,9 @@ Create a couple of Writers.
ManyToManyFields are represented by a MultipleChoiceField, ForeignKeys and any
fields with the 'choices' attribute are represented by a ChoiceField.
->>> ArticleForm = form_for_model(Article)
+>>> class ArticleForm(ModelForm):
+... class Meta:
+... model = Article
>>> f = ArticleForm(auto_id=False)
>>> print f
<tr><th>Headline:</th><td><input type="text" name="headline" maxlength="50" /></td></tr>
@@ -214,28 +288,23 @@ model created with such a form, you need to ensure that the fields
that are _not_ on the form have default values, or are allowed to have
a value of None. If a field isn't specified on a form, the object created
from the form can't provide a value for that field!
->>> PartialArticleForm = form_for_model(Article, fields=('headline','pub_date'))
+>>> class PartialArticleForm(ModelForm):
+... class Meta:
+... model = Article
+... fields = ('headline','pub_date')
>>> f = PartialArticleForm(auto_id=False)
>>> print f
<tr><th>Headline:</th><td><input type="text" name="headline" maxlength="50" /></td></tr>
<tr><th>Pub date:</th><td><input type="text" name="pub_date" /></td></tr>
-You can pass a custom Form class to form_for_model. Make sure it's a
-subclass of BaseForm, not Form.
->>> class CustomForm(BaseForm):
-... def say_hello(self):
-... print 'hello'
->>> CategoryForm = form_for_model(Category, form=CustomForm)
->>> f = CategoryForm()
->>> f.say_hello()
-hello
-
Use form_for_instance to create a Form from a model instance. The difference
between this Form and one created via form_for_model is that the object's
current values are inserted as 'initial' data in each Field.
>>> w = Writer.objects.get(name='Mike Royko')
->>> RoykoForm = form_for_instance(w)
->>> f = RoykoForm(auto_id=False)
+>>> class RoykoForm(ModelForm):
+... class Meta:
+... model = Writer
+>>> f = RoykoForm(auto_id=False, instance=w)
>>> print f
<tr><th>Name:</th><td><input type="text" name="name" value="Mike Royko" maxlength="50" /><br />Use both first and last names.</td></tr>
@@ -243,8 +312,10 @@ current values are inserted as 'initial' data in each Field.
>>> art.save()
>>> art.id
1
->>> TestArticleForm = form_for_instance(art)
->>> f = TestArticleForm(auto_id=False)
+>>> class TestArticleForm(ModelForm):
+... class Meta:
+... model = Article
+>>> f = TestArticleForm(auto_id=False, instance=art)
>>> print f.as_ul()
<li>Headline: <input type="text" name="headline" value="Test article" maxlength="50" /></li>
<li>Slug: <input type="text" name="slug" value="test-article" maxlength="50" /></li>
@@ -266,7 +337,7 @@ current values are inserted as 'initial' data in each Field.
<option value="2">It&#39;s a test</option>
<option value="3">Third test</option>
</select> Hold down "Control", or "Command" on a Mac, to select more than one.</li>
->>> f = TestArticleForm({'headline': u'Test headline', 'slug': 'test-headline', 'pub_date': u'1984-02-06', 'writer': u'1', 'article': 'Hello.'})
+>>> f = TestArticleForm({'headline': u'Test headline', 'slug': 'test-headline', 'pub_date': u'1984-02-06', 'writer': u'1', 'article': 'Hello.'}, instance=art)
>>> f.is_valid()
True
>>> test_art = f.save()
@@ -278,8 +349,11 @@ u'Test headline'
You can create a form over a subset of the available fields
by specifying a 'fields' argument to form_for_instance.
->>> PartialArticleForm = form_for_instance(art, fields=('headline', 'slug', 'pub_date'))
->>> f = PartialArticleForm({'headline': u'New headline', 'slug': 'new-headline', 'pub_date': u'1988-01-04'}, auto_id=False)
+>>> class PartialArticleForm(ModelForm):
+... class Meta:
+... model = Article
+... fields=('headline', 'slug', 'pub_date')
+>>> f = PartialArticleForm({'headline': u'New headline', 'slug': 'new-headline', 'pub_date': u'1988-01-04'}, auto_id=False, instance=art)
>>> print f.as_ul()
<li>Headline: <input type="text" name="headline" value="New headline" maxlength="50" /></li>
<li>Slug: <input type="text" name="slug" value="new-headline" maxlength="50" /></li>
@@ -299,8 +373,10 @@ Add some categories and test the many-to-many form output.
>>> new_art.categories.add(Category.objects.get(name='Entertainment'))
>>> new_art.categories.all()
[<Category: Entertainment>]
->>> TestArticleForm = form_for_instance(new_art)
->>> f = TestArticleForm(auto_id=False)
+>>> class TestArticleForm(ModelForm):
+... class Meta:
+... model = Article
+>>> f = TestArticleForm(auto_id=False, instance=new_art)
>>> print f.as_ul()
<li>Headline: <input type="text" name="headline" value="New headline" maxlength="50" /></li>
<li>Slug: <input type="text" name="slug" value="new-headline" maxlength="50" /></li>
@@ -324,7 +400,7 @@ Add some categories and test the many-to-many form output.
</select> Hold down "Control", or "Command" on a Mac, to select more than one.</li>
>>> f = TestArticleForm({'headline': u'New headline', 'slug': u'new-headline', 'pub_date': u'1988-01-04',
-... 'writer': u'1', 'article': u'Hello.', 'categories': [u'1', u'2']})
+... 'writer': u'1', 'article': u'Hello.', 'categories': [u'1', u'2']}, instance=new_art)
>>> new_art = f.save()
>>> new_art.id
1
@@ -334,7 +410,7 @@ Add some categories and test the many-to-many form output.
Now, submit form data with no categories. This deletes the existing categories.
>>> f = TestArticleForm({'headline': u'New headline', 'slug': u'new-headline', 'pub_date': u'1988-01-04',
-... 'writer': u'1', 'article': u'Hello.'})
+... 'writer': u'1', 'article': u'Hello.'}, instance=new_art)
>>> new_art = f.save()
>>> new_art.id
1
@@ -343,7 +419,9 @@ Now, submit form data with no categories. This deletes the existing categories.
[]
Create a new article, with categories, via the form.
->>> ArticleForm = form_for_model(Article)
+>>> class ArticleForm(ModelForm):
+... class Meta:
+... model = Article
>>> f = ArticleForm({'headline': u'The walrus was Paul', 'slug': u'walrus-was-paul', 'pub_date': u'1967-11-01',
... 'writer': u'1', 'article': u'Test.', 'categories': [u'1', u'2']})
>>> new_art = f.save()
@@ -354,7 +432,9 @@ Create a new article, with categories, via the form.
[<Category: Entertainment>, <Category: It's a test>]
Create a new article, with no categories, via the form.
->>> ArticleForm = form_for_model(Article)
+>>> class ArticleForm(ModelForm):
+... class Meta:
+... model = Article
>>> f = ArticleForm({'headline': u'The walrus was Paul', 'slug': u'walrus-was-paul', 'pub_date': u'1967-11-01',
... 'writer': u'1', 'article': u'Test.'})
>>> new_art = f.save()
@@ -366,7 +446,9 @@ Create a new article, with no categories, via the form.
Create a new article, with categories, via the form, but use commit=False.
The m2m data won't be saved until save_m2m() is invoked on the form.
->>> ArticleForm = form_for_model(Article)
+>>> class ArticleForm(ModelForm):
+... class Meta:
+... model = Article
>>> f = ArticleForm({'headline': u'The walrus was Paul', 'slug': 'walrus-was-paul', 'pub_date': u'1967-11-01',
... 'writer': u'1', 'article': u'Test.', 'categories': [u'1', u'2']})
>>> new_art = f.save(commit=False)
@@ -386,10 +468,10 @@ The m2m data won't be saved until save_m2m() is invoked on the form.
>>> new_art.categories.order_by('name')
[<Category: Entertainment>, <Category: It's a test>]
-Here, we define a custom Form. Because it happens to have the same fields as
-the Category model, we can use save_instance() to apply its changes to an
+Here, we define a custom ModelForm. Because it happens to have the same fields as
+the Category model, we can just call the form's save() to apply its changes to an
existing Category instance.
->>> class ShortCategory(Form):
+>>> class ShortCategory(ModelForm):
... name = CharField(max_length=5)
... slug = CharField(max_length=5)
... url = CharField(max_length=3)
@@ -398,8 +480,8 @@ existing Category instance.
<Category: Third test>
>>> cat.id
3
->>> sc = ShortCategory({'name': 'Third', 'slug': 'third', 'url': '3rd'})
->>> save_instance(sc, cat)
+>>> form = ShortCategory({'name': 'Third', 'slug': 'third', 'url': '3rd'}, instance=cat)
+>>> form.save()
<Category: Third>
>>> Category.objects.get(id=3)
<Category: Third>
@@ -407,7 +489,9 @@ existing Category instance.
Here, we demonstrate that choices for a ForeignKey ChoiceField are determined
at runtime, based on the data in the database when the form is displayed, not
the data in the database when the form is instantiated.
->>> ArticleForm = form_for_model(Article)
+>>> class ArticleForm(ModelForm):
+... class Meta:
+... model = Article
>>> f = ArticleForm(auto_id=False)
>>> print f.as_ul()
<li>Headline: <input type="text" name="headline" maxlength="50" /></li>
@@ -609,60 +693,12 @@ ValidationError: [u'Select a valid choice. 4 is not one of the available choices
# PhoneNumberField ############################################################
->>> PhoneNumberForm = form_for_model(PhoneNumber)
+>>> class PhoneNumberForm(ModelForm):
+... class Meta:
+... model = PhoneNumber
>>> f = PhoneNumberForm({'phone': '(312) 555-1212', 'description': 'Assistance'})
>>> f.is_valid()
True
>>> f.cleaned_data
{'phone': u'312-555-1212', 'description': u'Assistance'}
-
-# form_for_* blank choices ####################################################
-
-Show the form for a new Car. Note that steering field doesn't include the blank choice,
-because the field is obligatory and has an explicit default.
->>> CarForm = form_for_model(Car)
->>> f = CarForm(auto_id=False)
->>> print f
-<tr><th>Name:</th><td><input type="text" name="name" maxlength="50" /></td></tr>
-<tr><th>Steering:</th><td><select name="steering">
-<option value="left" selected="selected">Left steering wheel</option>
-<option value="right">Right steering wheel</option>
-</select></td></tr>
-<tr><th>Fuel:</th><td><select name="fuel">
-<option value="" selected="selected">---------</option>
-<option value="gas">Gasoline</option>
-<option value="diesel">Diesel</option>
-<option value="other">Other</option>
-</select></td></tr>
-<tr><th>Transmission:</th><td><select name="transmission">
-<option value="" selected="selected">---------</option>
-<option value="at">Automatic</option>
-<option value="mt">Manual</option>
-<option value="cvt">CVT</option>
-</select><br />Leave empty if not applicable.</td></tr>
-
-Create a Car, and display the form for modifying it. Note that now the fuel
-selector doesn't include the blank choice as well, since the field is
-obligatory and can not be changed to be blank.
->>> honda = Car(name='Honda Accord Wagon', steering='right', fuel='gas', transmission='at')
->>> honda.save()
->>> HondaForm = form_for_instance(honda)
->>> f = HondaForm(auto_id=False)
->>> print f
-<tr><th>Name:</th><td><input type="text" name="name" value="Honda Accord Wagon" maxlength="50" /></td></tr>
-<tr><th>Steering:</th><td><select name="steering">
-<option value="left">Left steering wheel</option>
-<option value="right" selected="selected">Right steering wheel</option>
-</select></td></tr>
-<tr><th>Fuel:</th><td><select name="fuel">
-<option value="gas" selected="selected">Gasoline</option>
-<option value="diesel">Diesel</option>
-<option value="other">Other</option>
-</select></td></tr>
-<tr><th>Transmission:</th><td><select name="transmission">
-<option value="">---------</option>
-<option value="at" selected="selected">Automatic</option>
-<option value="mt">Manual</option>
-<option value="cvt">CVT</option>
-</select><br />Leave empty if not applicable.</td></tr>
"""}
diff --git a/tests/modeltests/select_related/models.py b/tests/modeltests/select_related/models.py
index 43efab3a7d..f0fd121665 100644
--- a/tests/modeltests/select_related/models.py
+++ b/tests/modeltests/select_related/models.py
@@ -1,5 +1,5 @@
"""
-40. Tests for select_related()
+41. Tests for select_related()
``select_related()`` follows all relationships and pre-caches any foreign key
values so that complex trees can be fetched in a single query. However, this
diff --git a/tests/modeltests/serializers/models.py b/tests/modeltests/serializers/models.py
index a2388223f0..0ccc19f895 100644
--- a/tests/modeltests/serializers/models.py
+++ b/tests/modeltests/serializers/models.py
@@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
"""
-41. Serialization
+42. Serialization
``django.core.serializers`` provides interfaces to converting Django querysets
to and from "flat" data (i.e. strings).
@@ -218,3 +218,41 @@ None
3.4
"""}
+
+try:
+ import yaml
+ __test__['YAML'] = """
+# Create some data:
+
+>>> articles = Article.objects.all().order_by("id")[:2]
+>>> from django.core import serializers
+
+# test if serial
+
+>>> serialized = serializers.serialize("yaml", articles)
+>>> print serialized
+- fields:
+ author: 2
+ categories: [3, 1]
+ headline: Just kidding; I love TV poker
+ pub_date: 2006-06-16 11:00:00
+ model: serializers.article
+ pk: 1
+- fields:
+ author: 1
+ categories: [2, 3]
+ headline: Time to reform copyright
+ pub_date: 2006-06-16 13:00:11
+ model: serializers.article
+ pk: 2
+<BLANKLINE>
+
+>>> obs = list(serializers.deserialize("yaml", serialized))
+>>> for i in obs:
+... print i
+<DeserializedObject: Just kidding; I love TV poker>
+<DeserializedObject: Time to reform copyright>
+
+"""
+except ImportError: pass
+
diff --git a/tests/modeltests/test_client/models.py b/tests/modeltests/test_client/models.py
index c7aaaff67d..1a6e1bdc18 100644
--- a/tests/modeltests/test_client/models.py
+++ b/tests/modeltests/test_client/models.py
@@ -1,6 +1,6 @@
# coding: utf-8
"""
-38. Testing using the Test Client
+39. Testing using the Test Client
The test client is a class that can act like a simple
browser for testing purposes.
diff --git a/tests/modeltests/user_commands/models.py b/tests/modeltests/user_commands/models.py
index 5f96806dac..6db4b049df 100644
--- a/tests/modeltests/user_commands/models.py
+++ b/tests/modeltests/user_commands/models.py
@@ -1,5 +1,5 @@
"""
-37. User-registered management commands
+38. User-registered management commands
The manage.py utility provides a number of useful commands for managing a
Django project. If you want to add a utility command of your own, you can.
@@ -27,4 +27,4 @@ Traceback (most recent call last):
CommandError: Unknown command: 'explode'
-"""} \ No newline at end of file
+"""}
diff --git a/tests/regressiontests/cache/tests.py b/tests/regressiontests/cache/tests.py
index e94ea33139..f050348c77 100644
--- a/tests/regressiontests/cache/tests.py
+++ b/tests/regressiontests/cache/tests.py
@@ -3,8 +3,8 @@
# Unit tests for cache framework
# Uses whatever cache backend is set in the test settings file.
-import time, unittest
-
+import time
+import unittest
from django.core.cache import cache
from django.utils.cache import patch_vary_headers
from django.http import HttpResponse
@@ -27,7 +27,7 @@ class Cache(unittest.TestCase):
cache.add("addkey1", "value")
cache.add("addkey1", "newvalue")
self.assertEqual(cache.get("addkey1"), "value")
-
+
def test_non_existent(self):
# get with non-existent keys
self.assertEqual(cache.get("does_not_exist"), None)
@@ -72,12 +72,20 @@ class Cache(unittest.TestCase):
'function' : f,
'class' : C,
}
+ cache.set("stuff", stuff)
+ self.assertEqual(cache.get("stuff"), stuff)
def test_expiration(self):
- # expiration
- cache.set('expire', 'very quickly', 1)
- time.sleep(2)
- self.assertEqual(cache.get("expire"), None)
+ cache.set('expire1', 'very quickly', 1)
+ cache.set('expire2', 'very quickly', 1)
+ cache.set('expire3', 'very quickly', 1)
+
+ time.sleep(2)
+ self.assertEqual(cache.get("expire1"), None)
+
+ cache.add("expire2", "newvalue")
+ self.assertEqual(cache.get("expire2"), "newvalue")
+ self.assertEqual(cache.has_key("expire3"), False)
def test_unicode(self):
stuff = {
@@ -90,6 +98,44 @@ class Cache(unittest.TestCase):
cache.set(key, value)
self.assertEqual(cache.get(key), value)
+import os
+import md5
+import shutil
+import tempfile
+from django.core.cache.backends.filebased import CacheClass as FileCache
+
+class FileBasedCacheTests(unittest.TestCase):
+ """
+ Specific test cases for the file-based cache.
+ """
+ def setUp(self):
+ self.dirname = tempfile.mktemp()
+ os.mkdir(self.dirname)
+ self.cache = FileCache(self.dirname, {})
+
+ def tearDown(self):
+ shutil.rmtree(self.dirname)
+
+ def test_hashing(self):
+ """Test that keys are hashed into subdirectories correctly"""
+ self.cache.set("foo", "bar")
+ keyhash = md5.new("foo").hexdigest()
+ keypath = os.path.join(self.dirname, keyhash[:2], keyhash[2:4], keyhash[4:])
+ self.assert_(os.path.exists(keypath))
+
+ def test_subdirectory_removal(self):
+ """
+ Make sure that the created subdirectories are correctly removed when empty.
+ """
+ self.cache.set("foo", "bar")
+ keyhash = md5.new("foo").hexdigest()
+ keypath = os.path.join(self.dirname, keyhash[:2], keyhash[2:4], keyhash[4:])
+ self.assert_(os.path.exists(keypath))
+
+ self.cache.delete("foo")
+ self.assert_(not os.path.exists(keypath))
+ self.assert_(not os.path.exists(os.path.dirname(keypath)))
+ self.assert_(not os.path.exists(os.path.dirname(os.path.dirname(keypath))))
class CacheUtils(unittest.TestCase):
"""TestCase for django.utils.cache functions."""
diff --git a/tests/regressiontests/defaultfilters/tests.py b/tests/regressiontests/defaultfilters/tests.py
index bfa03cd6e1..668ecb9d5a 100644
--- a/tests/regressiontests/defaultfilters/tests.py
+++ b/tests/regressiontests/defaultfilters/tests.py
@@ -49,6 +49,18 @@ u'\\\\ : backslashes, too'
>>> capfirst(u'hello world')
u'Hello world'
+>>> escapejs(u'"double quotes" and \'single quotes\'')
+u'\\"double quotes\\" and \\\'single quotes\\\''
+
+>>> escapejs(ur'\ : backslashes, too')
+u'\\\\ : backslashes, too'
+
+>>> escapejs(u'and lots of whitespace: \r\n\t\v\f\b')
+u'and lots of whitespace: \\r\\n\\t\\v\\f\\b'
+
+>>> escapejs(ur'<script>and this</script>')
+u'<script>and this<\\/script>'
+
>>> fix_ampersands(u'Jack & Jill & Jeroboam')
u'Jack &amp; Jill &amp; Jeroboam'
diff --git a/tests/regressiontests/forms/localflavor/za.py b/tests/regressiontests/forms/localflavor/za.py
new file mode 100644
index 0000000000..a948964b8d
--- /dev/null
+++ b/tests/regressiontests/forms/localflavor/za.py
@@ -0,0 +1,40 @@
+tests = r"""
+# ZAIDField #################################################################
+
+ZAIDField validates that the date is a valid birthdate and that the value
+has a valid checksum. It allows spaces and dashes, and returns a plain
+string of digits.
+>>> from django.contrib.localflavor.za.forms import ZAIDField
+>>> f = ZAIDField()
+>>> f.clean('0002290001003')
+'0002290001003'
+>>> f.clean('000229 0001 003')
+'0002290001003'
+>>> f.clean('0102290001001')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a valid South African ID number']
+>>> f.clean('811208')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a valid South African ID number']
+>>> f.clean('0002290001004')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a valid South African ID number']
+
+# ZAPostCodeField ###########################################################
+>>> from django.contrib.localflavor.za.forms import ZAPostCodeField
+>>> f = ZAPostCodeField()
+>>> f.clean('abcd')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a valid South African postal code']
+>>> f.clean('0000')
+u'0000'
+>>> f.clean(' 7530')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a valid South African postal code']
+
+"""
diff --git a/tests/regressiontests/forms/tests.py b/tests/regressiontests/forms/tests.py
index 6acd4f2e1d..bb0e30b874 100644
--- a/tests/regressiontests/forms/tests.py
+++ b/tests/regressiontests/forms/tests.py
@@ -22,6 +22,7 @@ from localflavor.pl import tests as localflavor_pl_tests
from localflavor.sk import tests as localflavor_sk_tests
from localflavor.uk import tests as localflavor_uk_tests
from localflavor.us import tests as localflavor_us_tests
+from localflavor.za import tests as localflavor_za_tests
from regressions import tests as regression_tests
from util import tests as util_tests
from widgets import tests as widgets_tests
@@ -50,6 +51,7 @@ __test__ = {
'localflavor_sk_tests': localflavor_sk_tests,
'localflavor_uk_tests': localflavor_uk_tests,
'localflavor_us_tests': localflavor_us_tests,
+ 'localflavor_za_tests': localflavor_za_tests,
'regression_tests': regression_tests,
'util_tests': util_tests,
'widgets_tests': widgets_tests,
diff --git a/tests/regressiontests/i18n/tests.py b/tests/regressiontests/i18n/tests.py
index 2ffc62f90d..94e792cf54 100644
--- a/tests/regressiontests/i18n/tests.py
+++ b/tests/regressiontests/i18n/tests.py
@@ -43,7 +43,7 @@ u'django'
Translating a string requiring no auto-escaping shouldn't change the "safe"
status.
->>> from django.utils.safestring import mark_safe
+>>> from django.utils.safestring import mark_safe, SafeString
>>> s = mark_safe('Password')
>>> type(s)
<class 'django.utils.safestring.SafeString'>
@@ -51,6 +51,19 @@ status.
>>> type(ugettext(s))
<class 'django.utils.safestring.SafeUnicode'>
>>> deactivate()
+
+>>> SafeString('a') + s
+'aPassword'
+>>> s + SafeString('a')
+'Passworda'
+>>> s + mark_safe('a')
+'Passworda'
+>>> mark_safe('a') + s
+'aPassword'
+>>> mark_safe('a') + mark_safe('s')
+'as'
+>>> print s
+Password
"""
__test__ = {
diff --git a/tests/regressiontests/maxlength/tests.py b/tests/regressiontests/maxlength/tests.py
index 8a5f874c78..c7ed1f91c0 100644
--- a/tests/regressiontests/maxlength/tests.py
+++ b/tests/regressiontests/maxlength/tests.py
@@ -22,12 +22,12 @@ Don't print out the deprecation warnings during testing.
>>> legacy_maxlength(10, 12)
Traceback (most recent call last):
...
-TypeError: field can not take both the max_length argument and the legacy maxlength argument.
+TypeError: Field cannot take both the max_length argument and the legacy maxlength argument.
>>> legacy_maxlength(0, 10)
Traceback (most recent call last):
...
-TypeError: field can not take both the max_length argument and the legacy maxlength argument.
+TypeError: Field cannot take both the max_length argument and the legacy maxlength argument.
>>> legacy_maxlength(0, None)
0
@@ -48,7 +48,7 @@ TypeError: field can not take both the max_length argument and the legacy maxlen
>>> fields.Field(maxlength=10, max_length=15)
Traceback (most recent call last):
...
-TypeError: field can not take both the max_length argument and the legacy maxlength argument.
+TypeError: Field cannot take both the max_length argument and the legacy maxlength argument.
# Test max_length
>>> new.max_length
diff --git a/tests/regressiontests/middleware/__init__.py b/tests/regressiontests/middleware/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/tests/regressiontests/middleware/__init__.py
diff --git a/tests/regressiontests/middleware/tests.py b/tests/regressiontests/middleware/tests.py
new file mode 100644
index 0000000000..cb5c29abe1
--- /dev/null
+++ b/tests/regressiontests/middleware/tests.py
@@ -0,0 +1,93 @@
+# -*- coding: utf-8 -*-
+
+import unittest
+
+from django.test import TestCase
+from django.http import HttpRequest
+from django.middleware.common import CommonMiddleware
+from django.conf import settings
+
+class CommonMiddlewareTest(TestCase):
+ def _get_request(self, path):
+ request = HttpRequest()
+ request.META = {
+ 'SERVER_NAME': 'testserver',
+ 'SERVER_PORT': 80,
+ }
+ request.path = "/middleware/%s" % path
+ return request
+
+ def test_append_slash_have_slash(self):
+ """
+ tests that urls with slashes go unmolested
+ """
+ settings.APPEND_SLASH = True
+ request = self._get_request('slash/')
+ self.assertEquals(CommonMiddleware().process_request(request), None)
+
+ def test_append_slash_slashless_resource(self):
+ """
+ tests that matches to explicit slashless urls go unmolested
+ """
+ settings.APPEND_SLASH = True
+ request = self._get_request('noslash')
+ self.assertEquals(CommonMiddleware().process_request(request), None)
+
+ def test_append_slash_slashless_unknown(self):
+ """
+ tests that APPEND_SLASH doesn't redirect to unknown resources
+ """
+ settings.APPEND_SLASH = True
+ request = self._get_request('unknown')
+ self.assertEquals(CommonMiddleware().process_request(request), None)
+
+ def test_append_slash_redirect(self):
+ """
+ tests that APPEND_SLASH redirects slashless urls to a valid pattern
+ """
+ settings.APPEND_SLASH = True
+ request = self._get_request('slash')
+ r = CommonMiddleware().process_request(request)
+ self.assertEquals(r.status_code, 301)
+ self.assertEquals(r['Location'], 'http://testserver/middleware/slash/')
+
+ def test_append_slash_no_redirect_on_POST_in_DEBUG(self):
+ """
+ tests that while in debug mode, an exception is raised with a warning
+ when a failed attempt is made to POST to an url which would normally be
+ redirected to a slashed version
+ """
+ settings.APPEND_SLASH = True
+ settings.DEBUG = True
+ request = self._get_request('slash')
+ request.method = 'POST'
+ self.assertRaises(
+ RuntimeError,
+ CommonMiddleware().process_request,
+ request)
+ try:
+ CommonMiddleware().process_request(request)
+ except RuntimeError, e:
+ self.assertTrue('end in a slash' in str(e))
+
+ def test_append_slash_disabled(self):
+ """
+ tests disabling append slash functionality
+ """
+ settings.APPEND_SLASH = False
+ request = self._get_request('slash')
+ self.assertEquals(CommonMiddleware().process_request(request), None)
+
+ def test_append_slash_quoted(self):
+ """
+ tests that urls which require quoting are redirected to their slash
+ version ok
+ """
+ settings.APPEND_SLASH = True
+ request = self._get_request('needsquoting#')
+ r = CommonMiddleware().process_request(request)
+ self.assertEquals(r.status_code, 301)
+ self.assertEquals(
+ r['Location'],
+ 'http://testserver/middleware/needsquoting%23/')
+
diff --git a/tests/regressiontests/middleware/urls.py b/tests/regressiontests/middleware/urls.py
new file mode 100644
index 0000000000..88a4b37ddc
--- /dev/null
+++ b/tests/regressiontests/middleware/urls.py
@@ -0,0 +1,7 @@
+from django.conf.urls.defaults import patterns
+
+urlpatterns = patterns('',
+ (r'^noslash$', 'view'),
+ (r'^slash/$', 'view'),
+ (r'^needsquoting#/$', 'view'),
+)
diff --git a/tests/regressiontests/model_regress/models.py b/tests/regressiontests/model_regress/models.py
index 00c3bc96f0..02e73a5aa9 100644
--- a/tests/regressiontests/model_regress/models.py
+++ b/tests/regressiontests/model_regress/models.py
@@ -11,6 +11,7 @@ class Article(models.Model):
pub_date = models.DateTimeField()
status = models.IntegerField(blank=True, null=True, choices=CHOICES)
misc_data = models.CharField(max_length=100, blank=True)
+ article_text = models.TextField()
class Meta:
ordering = ('pub_date','headline')
@@ -41,5 +42,14 @@ Empty strings should be returned as Unicode
>>> a2 = Article.objects.get(pk=a.id)
>>> a2.misc_data
u''
+
+# TextFields can hold more than 4000 characters (this was broken in Oracle).
+>>> a3 = Article(headline="Really, really big", pub_date=datetime.now())
+>>> a3.article_text = "ABCDE" * 1000
+>>> a3.save()
+>>> a4 = Article.objects.get(pk=a3.id)
+>>> len(a4.article_text)
+5000
+
"""
}
diff --git a/tests/regressiontests/string_lookup/models.py b/tests/regressiontests/string_lookup/models.py
index 12ebd0cf07..9deeb18763 100644
--- a/tests/regressiontests/string_lookup/models.py
+++ b/tests/regressiontests/string_lookup/models.py
@@ -18,26 +18,26 @@ class Bar(models.Model):
return "Bar %s" % self.place.name
class Whiz(models.Model):
- name = models.CharField(max_length = 50)
+ name = models.CharField(max_length=50)
def __unicode__(self):
return "Whiz %s" % self.name
class Child(models.Model):
parent = models.OneToOneField('Base')
- name = models.CharField(max_length = 50)
+ name = models.CharField(max_length=50)
def __unicode__(self):
return "Child %s" % self.name
class Base(models.Model):
- name = models.CharField(max_length = 50)
+ name = models.CharField(max_length=50)
def __unicode__(self):
return "Base %s" % self.name
class Article(models.Model):
- name = models.CharField(maxlength = 50)
+ name = models.CharField(max_length=50)
text = models.TextField()
def __str__(self):
diff --git a/tests/regressiontests/templates/context.py b/tests/regressiontests/templates/context.py
new file mode 100644
index 0000000000..d8b0f39abe
--- /dev/null
+++ b/tests/regressiontests/templates/context.py
@@ -0,0 +1,18 @@
+# coding: utf-8
+
+context_tests = r"""
+>>> from django.template import Context
+>>> c = Context({'a': 1, 'b': 'xyzzy'})
+>>> c['a']
+1
+>>> c.push()
+{}
+>>> c['a'] = 2
+>>> c['a']
+2
+>>> c.pop()
+{'a': 2}
+>>> c['a']
+1
+"""
+
diff --git a/tests/regressiontests/templates/tests.py b/tests/regressiontests/templates/tests.py
index cbbd88b06c..846023afc9 100644
--- a/tests/regressiontests/templates/tests.py
+++ b/tests/regressiontests/templates/tests.py
@@ -18,11 +18,13 @@ from django.utils.safestring import mark_safe
from django.utils.tzinfo import LocalTimezone
from unicode import unicode_tests
+from context import context_tests
import filters
# Some other tests we would like to run
__test__ = {
'unicode': unicode_tests,
+ 'context': context_tests,
}
#################################
diff --git a/tests/regressiontests/views/views.py b/tests/regressiontests/views/views.py
index 9e0bbb2d66..956432e7d5 100644
--- a/tests/regressiontests/views/views.py
+++ b/tests/regressiontests/views/views.py
@@ -1,7 +1,5 @@
from django.http import HttpResponse
-from django.template import RequestContext
def index_page(request):
"""Dummy index page"""
return HttpResponse('<html><body>Dummy page</body></html>')
-
diff --git a/tests/runtests.py b/tests/runtests.py
index 843850074b..2d3b737cec 100755
--- a/tests/runtests.py
+++ b/tests/runtests.py
@@ -107,8 +107,7 @@ def django_tests(verbosity, interactive, test_labels):
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.middleware.common.CommonMiddleware',
)
- if not hasattr(settings, 'SITE_ID'):
- settings.SITE_ID = 1
+ settings.SITE_ID = 1
# Load all the ALWAYS_INSTALLED_APPS.
# (This import statement is intentionally delayed until after we
diff --git a/tests/urls.py b/tests/urls.py
index d7251007c5..174e06969b 100644
--- a/tests/urls.py
+++ b/tests/urls.py
@@ -14,4 +14,7 @@ urlpatterns = patterns('',
# django built-in views
(r'^views/', include('regressiontests.views.urls')),
+
+ # test urlconf for middleware tests
+ (r'^middleware/', include('regressiontests.middleware.urls')),
)