summaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
authorJoseph Kocherhans <joseph@jkocherhans.com>2010-01-05 03:56:19 +0000
committerJoseph Kocherhans <joseph@jkocherhans.com>2010-01-05 03:56:19 +0000
commit471596fc1afcb9c6258d317c619eaf5fd394e797 (patch)
tree193767161be3cc23dc2e6be5e4f16d8fd21a2925 /tests
parent4e89105d64bb9e04c409139a41e9c7aac263df4c (diff)
Merged soc2009/model-validation to trunk. Thanks, Honza!
git-svn-id: http://code.djangoproject.com/svn/django/trunk@12098 bcc190cf-cafb-0310-a4f2-bffc1f526a37
Diffstat (limited to 'tests')
-rw-r--r--tests/modeltests/model_forms/models.py83
-rw-r--r--tests/modeltests/model_formsets/models.py17
-rw-r--r--tests/modeltests/validation/__init__.py21
-rw-r--r--tests/modeltests/validation/models.py53
-rw-r--r--tests/modeltests/validation/test_custom_messages.py13
-rw-r--r--tests/modeltests/validation/test_unique.py58
-rw-r--r--tests/modeltests/validation/tests.py58
-rw-r--r--tests/modeltests/validation/validators.py18
-rw-r--r--tests/modeltests/validators/tests.py146
-rw-r--r--tests/regressiontests/forms/error_messages.py24
-rw-r--r--tests/regressiontests/forms/fields.py6
-rw-r--r--tests/regressiontests/forms/localflavor/ar.py8
-rw-r--r--tests/regressiontests/forms/localflavor/is_.py10
-rw-r--r--tests/regressiontests/forms/tests.py1
-rw-r--r--tests/regressiontests/forms/util.py17
-rw-r--r--tests/regressiontests/forms/validators.py17
-rw-r--r--tests/regressiontests/inline_formsets/tests.py10
-rw-r--r--tests/regressiontests/model_fields/tests.py52
-rw-r--r--tests/regressiontests/views/views.py2
19 files changed, 526 insertions, 88 deletions
diff --git a/tests/modeltests/model_forms/models.py b/tests/modeltests/model_forms/models.py
index c94e6d3e95..ba59f9ae36 100644
--- a/tests/modeltests/model_forms/models.py
+++ b/tests/modeltests/model_forms/models.py
@@ -68,7 +68,7 @@ class ImprovedArticleWithParentLink(models.Model):
article = models.OneToOneField(Article, parent_link=True)
class BetterWriter(Writer):
- pass
+ score = models.IntegerField()
class WriterProfile(models.Model):
writer = models.OneToOneField(Writer, primary_key=True)
@@ -555,6 +555,8 @@ inserted as 'initial' data in each Field.
<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.'}, instance=art)
+>>> f.errors
+{}
>>> f.is_valid()
True
>>> test_art = f.save()
@@ -967,10 +969,20 @@ ValidationError: [u'Select a valid choice. 4 is not one of the available choices
>>> ImprovedArticleWithParentLinkForm.base_fields.keys()
[]
->>> bw = BetterWriter(name=u'Joe Better')
+>>> bw = BetterWriter(name=u'Joe Better', score=10)
>>> bw.save()
>>> sorted(model_to_dict(bw).keys())
-['id', 'name', 'writer_ptr']
+['id', 'name', 'score', 'writer_ptr']
+
+>>> class BetterWriterForm(ModelForm):
+... class Meta:
+... model = BetterWriter
+>>> form = BetterWriterForm({'name': 'Some Name', 'score': 12})
+>>> form.is_valid()
+True
+>>> bw2 = form.save()
+>>> bw2.delete()
+
>>> class WriterProfileForm(ModelForm):
... class Meta:
@@ -1102,16 +1114,6 @@ True
>>> instance.delete()
-# Test the non-required FileField
-
->>> f = TextFileForm(data={'description': u'Assistance'})
->>> f.fields['file'].required = False
->>> f.is_valid()
-True
->>> instance = f.save()
->>> instance.file
-<FieldFile: None>
-
>>> f = TextFileForm(data={'description': u'Assistance'}, files={'file': SimpleUploadedFile('test3.txt', 'hello world')}, instance=instance)
>>> f.is_valid()
True
@@ -1358,27 +1360,35 @@ __test__['API_TESTS'] += """
... class Meta:
... model = CommaSeparatedInteger
->>> f = CommaSeparatedIntegerForm().fields['field']
->>> f.clean('1,2,3')
-u'1,2,3'
->>> f.clean('1a,2')
-Traceback (most recent call last):
-...
-ValidationError: [u'Enter only digits separated by commas.']
->>> f.clean(',,,,')
-u',,,,'
->>> f.clean('1.2')
-Traceback (most recent call last):
-...
-ValidationError: [u'Enter only digits separated by commas.']
->>> f.clean('1,a,2')
-Traceback (most recent call last):
-...
-ValidationError: [u'Enter only digits separated by commas.']
->>> f.clean('1,,2')
-u'1,,2'
->>> f.clean('1')
-u'1'
+>>> f = CommaSeparatedIntegerForm({'field': '1,2,3'})
+>>> f.is_valid()
+True
+>>> f.cleaned_data
+{'field': u'1,2,3'}
+>>> f = CommaSeparatedIntegerForm({'field': '1a,2'})
+>>> f.errors
+{'field': [u'Enter only digits separated by commas.']}
+>>> f = CommaSeparatedIntegerForm({'field': ',,,,'})
+>>> f.is_valid()
+True
+>>> f.cleaned_data
+{'field': u',,,,'}
+>>> f = CommaSeparatedIntegerForm({'field': '1.2'})
+>>> f.errors
+{'field': [u'Enter only digits separated by commas.']}
+>>> f = CommaSeparatedIntegerForm({'field': '1,a,2'})
+>>> f.errors
+{'field': [u'Enter only digits separated by commas.']}
+>>> f = CommaSeparatedIntegerForm({'field': '1,,2'})
+>>> f.is_valid()
+True
+>>> f.cleaned_data
+{'field': u'1,,2'}
+>>> f = CommaSeparatedIntegerForm({'field': '1'})
+>>> f.is_valid()
+True
+>>> f.cleaned_data
+{'field': u'1'}
# unique/unique_together validation
@@ -1415,13 +1425,16 @@ False
>>> form._errors
{'__all__': [u'Price with this Price and Quantity already exists.']}
+# This form is never valid because quantity is blank=False.
>>> class PriceForm(ModelForm):
... class Meta:
... model = Price
... exclude = ('quantity',)
>>> form = PriceForm({'price': '6.00'})
>>> form.is_valid()
-True
+Traceback (most recent call last):
+ ...
+UnresolvableValidationError: {'quantity': [u'This field cannot be null.']}
# Unique & unique together with null values
>>> class BookForm(ModelForm):
diff --git a/tests/modeltests/model_formsets/models.py b/tests/modeltests/model_formsets/models.py
index 1644ddf37b..5eab202962 100644
--- a/tests/modeltests/model_formsets/models.py
+++ b/tests/modeltests/model_formsets/models.py
@@ -543,10 +543,6 @@ This is used in the admin for save_as functionality.
... 'book_set-2-title': '',
... }
->>> formset = AuthorBooksFormSet(data, instance=Author(), save_as_new=True)
->>> formset.is_valid()
-True
-
>>> new_author = Author.objects.create(name='Charles Baudelaire')
>>> formset = AuthorBooksFormSet(data, instance=new_author, save_as_new=True)
>>> [book for book in formset.save() if book.author.pk == new_author.pk]
@@ -1035,19 +1031,6 @@ False
>>> formset._non_form_errors
[u'Please correct the duplicate data for price and quantity, which must be unique.']
-# only the price field is specified, this should skip any unique checks since the unique_together is not fulfilled.
-# this will fail with a KeyError if broken.
->>> FormSet = modelformset_factory(Price, fields=("price",), extra=2)
->>> data = {
-... 'form-TOTAL_FORMS': '2',
-... 'form-INITIAL_FORMS': '0',
-... 'form-0-price': '24',
-... 'form-1-price': '24',
-... }
->>> formset = FormSet(data)
->>> formset.is_valid()
-True
-
>>> FormSet = inlineformset_factory(Author, Book, extra=0)
>>> author = Author.objects.order_by('id')[0]
>>> book_ids = author.book_set.values_list('id', flat=True)
diff --git a/tests/modeltests/validation/__init__.py b/tests/modeltests/validation/__init__.py
new file mode 100644
index 0000000000..d0a7d19d49
--- /dev/null
+++ b/tests/modeltests/validation/__init__.py
@@ -0,0 +1,21 @@
+import unittest
+
+from django.core.exceptions import ValidationError
+
+class ValidationTestCase(unittest.TestCase):
+ def assertFailsValidation(self, clean, failed_fields):
+ self.assertRaises(ValidationError, clean)
+ try:
+ clean()
+ except ValidationError, e:
+ self.assertEquals(sorted(failed_fields), sorted(e.message_dict.keys()))
+
+ def assertFieldFailsValidationWithMessage(self, clean, field_name, message):
+ self.assertRaises(ValidationError, clean)
+ try:
+ clean()
+ except ValidationError, e:
+ self.assertTrue(field_name in e.message_dict)
+ self.assertEquals(message, e.message_dict[field_name])
+
+
diff --git a/tests/modeltests/validation/models.py b/tests/modeltests/validation/models.py
new file mode 100644
index 0000000000..f1b0c5188c
--- /dev/null
+++ b/tests/modeltests/validation/models.py
@@ -0,0 +1,53 @@
+from datetime import datetime
+from django.core.exceptions import ValidationError
+from django.db import models
+from django.test import TestCase
+
+
+def validate_answer_to_universe(value):
+ if value != 42:
+ raise ValidationError('This is not the answer to life, universe and everything!', code='not42')
+
+class ModelToValidate(models.Model):
+ name = models.CharField(max_length=100)
+ created = models.DateTimeField(default=datetime.now)
+ number = models.IntegerField()
+ parent = models.ForeignKey('self', blank=True, null=True)
+ email = models.EmailField(blank=True)
+ url = models.URLField(blank=True)
+ f_with_custom_validator = models.IntegerField(blank=True, null=True, validators=[validate_answer_to_universe])
+
+ def validate(self):
+ super(ModelToValidate, self).validate()
+ if self.number == 11:
+ raise ValidationError('Invalid number supplied!')
+
+class UniqueFieldsModel(models.Model):
+ unique_charfield = models.CharField(max_length=100, unique=True)
+ unique_integerfield = models.IntegerField(unique=True)
+ non_unique_field = models.IntegerField()
+
+class CustomPKModel(models.Model):
+ my_pk_field = models.CharField(max_length=100, primary_key=True)
+
+class UniqueTogetherModel(models.Model):
+ cfield = models.CharField(max_length=100)
+ ifield = models.IntegerField()
+ efield = models.EmailField()
+
+ class Meta:
+ unique_together = (('ifield', 'cfield',),('ifield', 'efield'), )
+
+class UniqueForDateModel(models.Model):
+ start_date = models.DateField()
+ end_date = models.DateTimeField()
+ count = models.IntegerField(unique_for_date="start_date", unique_for_year="end_date")
+ order = models.IntegerField(unique_for_month="end_date")
+ name = models.CharField(max_length=100)
+
+class CustomMessagesModel(models.Model):
+ other = models.IntegerField(blank=True, null=True)
+ number = models.IntegerField(
+ error_messages={'null': 'NULL', 'not42': 'AAARGH', 'not_equal': '%s != me'},
+ validators=[validate_answer_to_universe]
+ )
diff --git a/tests/modeltests/validation/test_custom_messages.py b/tests/modeltests/validation/test_custom_messages.py
new file mode 100644
index 0000000000..9a958a0a3f
--- /dev/null
+++ b/tests/modeltests/validation/test_custom_messages.py
@@ -0,0 +1,13 @@
+from modeltests.validation import ValidationTestCase
+from models import CustomMessagesModel
+
+
+class CustomMessagesTest(ValidationTestCase):
+ def test_custom_simple_validator_message(self):
+ cmm = CustomMessagesModel(number=12)
+ self.assertFieldFailsValidationWithMessage(cmm.full_validate, 'number', ['AAARGH'])
+
+ def test_custom_null_message(self):
+ cmm = CustomMessagesModel()
+ self.assertFieldFailsValidationWithMessage(cmm.full_validate, 'number', ['NULL'])
+
diff --git a/tests/modeltests/validation/test_unique.py b/tests/modeltests/validation/test_unique.py
new file mode 100644
index 0000000000..cbb56aa8f5
--- /dev/null
+++ b/tests/modeltests/validation/test_unique.py
@@ -0,0 +1,58 @@
+import unittest
+from django.conf import settings
+from django.db import connection
+from models import CustomPKModel, UniqueTogetherModel, UniqueFieldsModel, UniqueForDateModel, ModelToValidate
+
+
+class GetUniqueCheckTests(unittest.TestCase):
+ def test_unique_fields_get_collected(self):
+ m = UniqueFieldsModel()
+ self.assertEqual(
+ ([('id',), ('unique_charfield',), ('unique_integerfield',)], []),
+ m._get_unique_checks()
+ )
+
+ def test_unique_together_gets_picked_up(self):
+ m = UniqueTogetherModel()
+ self.assertEqual(
+ ([('ifield', 'cfield',),('ifield', 'efield'), ('id',), ], []),
+ m._get_unique_checks()
+ )
+
+ def test_primary_key_is_considered_unique(self):
+ m = CustomPKModel()
+ self.assertEqual(([('my_pk_field',)], []), m._get_unique_checks())
+
+ def test_unique_for_date_gets_picked_up(self):
+ m = UniqueForDateModel()
+ self.assertEqual((
+ [('id',)],
+ [('date', 'count', 'start_date'), ('year', 'count', 'end_date'), ('month', 'order', 'end_date')]
+ ), m._get_unique_checks()
+ )
+
+class PerformUniqueChecksTest(unittest.TestCase):
+ def setUp(self):
+ # Set debug to True to gain access to connection.queries.
+ self._old_debug, settings.DEBUG = settings.DEBUG, True
+ super(PerformUniqueChecksTest, self).setUp()
+
+ def tearDown(self):
+ # Restore old debug value.
+ settings.DEBUG = self._old_debug
+ super(PerformUniqueChecksTest, self).tearDown()
+
+ def test_primary_key_unique_check_performed_when_adding(self):
+ """Regression test for #12132"""
+ l = len(connection.queries)
+ mtv = ModelToValidate(number=10, name='Some Name')
+ setattr(mtv, '_adding', True)
+ mtv.full_validate()
+ self.assertEqual(l+1, len(connection.queries))
+
+ def test_primary_key_unique_check_not_performed_when_not_adding(self):
+ """Regression test for #12132"""
+ l = len(connection.queries)
+ mtv = ModelToValidate(number=10, name='Some Name')
+ mtv.full_validate()
+ self.assertEqual(l, len(connection.queries))
diff --git a/tests/modeltests/validation/tests.py b/tests/modeltests/validation/tests.py
new file mode 100644
index 0000000000..c00070b2ab
--- /dev/null
+++ b/tests/modeltests/validation/tests.py
@@ -0,0 +1,58 @@
+from django.core.exceptions import ValidationError, NON_FIELD_ERRORS
+from django.db import models
+
+from modeltests.validation import ValidationTestCase
+from models import *
+
+from validators import TestModelsWithValidators
+from test_unique import GetUniqueCheckTests, PerformUniqueChecksTest
+from test_custom_messages import CustomMessagesTest
+
+
+class BaseModelValidationTests(ValidationTestCase):
+
+ def test_missing_required_field_raises_error(self):
+ mtv = ModelToValidate(f_with_custom_validator=42)
+ self.assertFailsValidation(mtv.full_validate, ['name', 'number'])
+
+ def test_with_correct_value_model_validates(self):
+ mtv = ModelToValidate(number=10, name='Some Name')
+ self.assertEqual(None, mtv.full_validate())
+
+ def test_custom_validate_method_is_called(self):
+ mtv = ModelToValidate(number=11)
+ self.assertFailsValidation(mtv.full_validate, [NON_FIELD_ERRORS, 'name'])
+
+ def test_wrong_FK_value_raises_error(self):
+ mtv=ModelToValidate(number=10, name='Some Name', parent_id=3)
+ self.assertFailsValidation(mtv.full_validate, ['parent'])
+
+ def test_correct_FK_value_validates(self):
+ parent = ModelToValidate.objects.create(number=10, name='Some Name')
+ mtv=ModelToValidate(number=10, name='Some Name', parent_id=parent.pk)
+ self.assertEqual(None, mtv.full_validate())
+
+ def test_wrong_email_value_raises_error(self):
+ mtv = ModelToValidate(number=10, name='Some Name', email='not-an-email')
+ self.assertFailsValidation(mtv.full_validate, ['email'])
+
+ def test_correct_email_value_passes(self):
+ mtv = ModelToValidate(number=10, name='Some Name', email='valid@email.com')
+ self.assertEqual(None, mtv.full_validate())
+
+ def test_wrong_url_value_raises_error(self):
+ mtv = ModelToValidate(number=10, name='Some Name', url='not a url')
+ self.assertFieldFailsValidationWithMessage(mtv.full_validate, 'url', [u'Enter a valid value.'])
+
+ def test_correct_url_but_nonexisting_gives_404(self):
+ mtv = ModelToValidate(number=10, name='Some Name', url='http://google.com/we-love-microsoft.html')
+ self.assertFieldFailsValidationWithMessage(mtv.full_validate, 'url', [u'This URL appears to be a broken link.'])
+
+ def test_correct_url_value_passes(self):
+ mtv = ModelToValidate(number=10, name='Some Name', url='http://www.djangoproject.com/')
+ self.assertEqual(None, mtv.full_validate()) # This will fail if there's no Internet connection
+
+ def test_text_greater_that_charfields_max_length_eaises_erros(self):
+ mtv = ModelToValidate(number=10, name='Some Name'*100)
+ self.assertFailsValidation(mtv.full_validate, ['name',])
+
diff --git a/tests/modeltests/validation/validators.py b/tests/modeltests/validation/validators.py
new file mode 100644
index 0000000000..dc4cd4eba1
--- /dev/null
+++ b/tests/modeltests/validation/validators.py
@@ -0,0 +1,18 @@
+from unittest import TestCase
+from modeltests.validation import ValidationTestCase
+from models import *
+
+
+class TestModelsWithValidators(ValidationTestCase):
+ def test_custom_validator_passes_for_correct_value(self):
+ mtv = ModelToValidate(number=10, name='Some Name', f_with_custom_validator=42)
+ self.assertEqual(None, mtv.full_validate())
+
+ def test_custom_validator_raises_error_for_incorrect_value(self):
+ mtv = ModelToValidate(number=10, name='Some Name', f_with_custom_validator=12)
+ self.assertFailsValidation(mtv.full_validate, ['f_with_custom_validator'])
+ self.assertFieldFailsValidationWithMessage(
+ mtv.full_validate,
+ 'f_with_custom_validator',
+ [u'This is not the answer to life, universe and everything!']
+ )
diff --git a/tests/modeltests/validators/tests.py b/tests/modeltests/validators/tests.py
new file mode 100644
index 0000000000..f36d8c4713
--- /dev/null
+++ b/tests/modeltests/validators/tests.py
@@ -0,0 +1,146 @@
+# -*- coding: utf-8 -*-
+import re
+import types
+from unittest import TestCase
+from datetime import datetime, timedelta
+from django.core.exceptions import ValidationError
+from django.core.validators import *
+
+NOW = datetime.now()
+
+TEST_DATA = (
+ # (validator, value, expected),
+ (validate_integer, '42', None),
+ (validate_integer, '-42', None),
+ (validate_integer, -42, None),
+ (validate_integer, -42.5, None),
+
+ (validate_integer, None, ValidationError),
+ (validate_integer, 'a', ValidationError),
+
+ (validate_email, 'email@here.com', None),
+ (validate_email, 'weirder-email@here.and.there.com', None),
+
+ (validate_email, None, ValidationError),
+ (validate_email, '', ValidationError),
+ (validate_email, 'abc', ValidationError),
+ (validate_email, 'a @x.cz', ValidationError),
+ (validate_email, 'something@@somewhere.com', ValidationError),
+
+ (validate_slug, 'slug-ok', None),
+ (validate_slug, 'longer-slug-still-ok', None),
+ (validate_slug, '--------', None),
+ (validate_slug, 'nohyphensoranything', None),
+
+ (validate_slug, '', ValidationError),
+ (validate_slug, ' text ', ValidationError),
+ (validate_slug, ' ', ValidationError),
+ (validate_slug, 'some@mail.com', ValidationError),
+ (validate_slug, '你好', ValidationError),
+ (validate_slug, '\n', ValidationError),
+
+ (validate_ipv4_address, '1.1.1.1', None),
+ (validate_ipv4_address, '255.0.0.0', None),
+ (validate_ipv4_address, '0.0.0.0', None),
+
+ (validate_ipv4_address, '256.1.1.1', ValidationError),
+ (validate_ipv4_address, '25.1.1.', ValidationError),
+ (validate_ipv4_address, '25,1,1,1', ValidationError),
+ (validate_ipv4_address, '25.1 .1.1', ValidationError),
+
+ (validate_comma_separated_integer_list, '1', None),
+ (validate_comma_separated_integer_list, '1,2,3', None),
+ (validate_comma_separated_integer_list, '1,2,3,', None),
+
+ (validate_comma_separated_integer_list, '', ValidationError),
+ (validate_comma_separated_integer_list, 'a,b,c', ValidationError),
+ (validate_comma_separated_integer_list, '1, 2, 3', ValidationError),
+
+ (MaxValueValidator(10), 10, None),
+ (MaxValueValidator(10), -10, None),
+ (MaxValueValidator(10), 0, None),
+ (MaxValueValidator(NOW), NOW, None),
+ (MaxValueValidator(NOW), NOW - timedelta(days=1), None),
+
+ (MaxValueValidator(0), 1, ValidationError),
+ (MaxValueValidator(NOW), NOW + timedelta(days=1), ValidationError),
+
+ (MinValueValidator(-10), -10, None),
+ (MinValueValidator(-10), 10, None),
+ (MinValueValidator(-10), 0, None),
+ (MinValueValidator(NOW), NOW, None),
+ (MinValueValidator(NOW), NOW + timedelta(days=1), None),
+
+ (MinValueValidator(0), -1, ValidationError),
+ (MinValueValidator(NOW), NOW - timedelta(days=1), ValidationError),
+
+ (MaxLengthValidator(10), '', None),
+ (MaxLengthValidator(10), 10*'x', None),
+
+ (MaxLengthValidator(10), 15*'x', ValidationError),
+
+ (MinLengthValidator(10), 15*'x', None),
+ (MinLengthValidator(10), 10*'x', None),
+
+ (MinLengthValidator(10), '', ValidationError),
+
+ (URLValidator(), 'http://www.djangoproject.com/', None),
+ (URLValidator(), 'http://localhost/', None),
+ (URLValidator(), 'http://example.com/', None),
+ (URLValidator(), 'http://www.example.com/', None),
+ (URLValidator(), 'http://www.example.com:8000/test', None),
+ (URLValidator(), 'http://valid-with-hyphens.com/', None),
+ (URLValidator(), 'http://subdomain.domain.com/', None),
+ (URLValidator(), 'http://200.8.9.10/', None),
+ (URLValidator(), 'http://200.8.9.10:8000/test', None),
+ (URLValidator(), 'http://valid-----hyphens.com/', None),
+ (URLValidator(), 'http://example.com?something=value', None),
+ (URLValidator(), 'http://example.com/index.php?something=value&another=value2', None),
+
+ (URLValidator(), 'foo', ValidationError),
+ (URLValidator(), 'http://', ValidationError),
+ (URLValidator(), 'http://example', ValidationError),
+ (URLValidator(), 'http://example.', ValidationError),
+ (URLValidator(), 'http://.com', ValidationError),
+ (URLValidator(), 'http://invalid-.com', ValidationError),
+ (URLValidator(), 'http://-invalid.com', ValidationError),
+ (URLValidator(), 'http://inv-.alid-.com', ValidationError),
+ (URLValidator(), 'http://inv-.-alid.com', ValidationError),
+
+ (BaseValidator(True), True, None),
+ (BaseValidator(True), False, ValidationError),
+
+ (RegexValidator('.*'), '', None),
+ (RegexValidator(re.compile('.*')), '', None),
+ (RegexValidator('.*'), 'xxxxx', None),
+
+ (RegexValidator('x'), 'y', ValidationError),
+ (RegexValidator(re.compile('x')), 'y', ValidationError),
+)
+
+def create_simple_test_method(validator, expected, value, num):
+ if isinstance(expected, type) and issubclass(expected, Exception):
+ test_mask = 'test_%s_raises_error_%d'
+ def test_func(self):
+ self.assertRaises(expected, validator, value)
+ else:
+ test_mask = 'test_%s_%d'
+ def test_func(self):
+ self.assertEqual(expected, validator(value))
+ if isinstance(validator, types.FunctionType):
+ val_name = validator.__name__
+ else:
+ val_name = validator.__class__.__name__
+ test_name = test_mask % (val_name, num)
+ return test_name, test_func
+
+# Dynamically assemble a test class with the contents of TEST_DATA
+
+class TestSimpleValidators(TestCase):
+ pass
+
+test_counter = 0
+for validator, value, expected in TEST_DATA:
+ name, method = create_simple_test_method(validator, expected, value, test_counter)
+ setattr(TestSimpleValidators, name, method)
+ test_counter += 1
diff --git a/tests/regressiontests/forms/error_messages.py b/tests/regressiontests/forms/error_messages.py
index b7224dbde0..038fa39f6b 100644
--- a/tests/regressiontests/forms/error_messages.py
+++ b/tests/regressiontests/forms/error_messages.py
@@ -6,8 +6,8 @@ tests = r"""
# CharField ###################################################################
>>> e = {'required': 'REQUIRED'}
->>> e['min_length'] = 'LENGTH %(length)s, MIN LENGTH %(min)s'
->>> e['max_length'] = 'LENGTH %(length)s, MAX LENGTH %(max)s'
+>>> e['min_length'] = 'LENGTH %(show_value)s, MIN LENGTH %(limit_value)s'
+>>> e['max_length'] = 'LENGTH %(show_value)s, MAX LENGTH %(limit_value)s'
>>> f = CharField(min_length=5, max_length=10, error_messages=e)
>>> f.clean('')
Traceback (most recent call last):
@@ -26,8 +26,8 @@ ValidationError: [u'LENGTH 11, MAX LENGTH 10']
>>> e = {'required': 'REQUIRED'}
>>> e['invalid'] = 'INVALID'
->>> e['min_value'] = 'MIN VALUE IS %s'
->>> e['max_value'] = 'MAX VALUE IS %s'
+>>> e['min_value'] = 'MIN VALUE IS %(limit_value)s'
+>>> e['max_value'] = 'MAX VALUE IS %(limit_value)s'
>>> f = IntegerField(min_value=5, max_value=10, error_messages=e)
>>> f.clean('')
Traceback (most recent call last):
@@ -50,8 +50,8 @@ ValidationError: [u'MAX VALUE IS 10']
>>> e = {'required': 'REQUIRED'}
>>> e['invalid'] = 'INVALID'
->>> e['min_value'] = 'MIN VALUE IS %s'
->>> e['max_value'] = 'MAX VALUE IS %s'
+>>> e['min_value'] = 'MIN VALUE IS %(limit_value)s'
+>>> e['max_value'] = 'MAX VALUE IS %(limit_value)s'
>>> f = FloatField(min_value=5, max_value=10, error_messages=e)
>>> f.clean('')
Traceback (most recent call last):
@@ -74,8 +74,8 @@ ValidationError: [u'MAX VALUE IS 10']
>>> e = {'required': 'REQUIRED'}
>>> e['invalid'] = 'INVALID'
->>> e['min_value'] = 'MIN VALUE IS %s'
->>> e['max_value'] = 'MAX VALUE IS %s'
+>>> e['min_value'] = 'MIN VALUE IS %(limit_value)s'
+>>> e['max_value'] = 'MAX VALUE IS %(limit_value)s'
>>> e['max_digits'] = 'MAX DIGITS IS %s'
>>> e['max_decimal_places'] = 'MAX DP IS %s'
>>> e['max_whole_digits'] = 'MAX DIGITS BEFORE DP IS %s'
@@ -156,8 +156,8 @@ ValidationError: [u'INVALID']
>>> e = {'required': 'REQUIRED'}
>>> e['invalid'] = 'INVALID'
->>> e['min_length'] = 'LENGTH %(length)s, MIN LENGTH %(min)s'
->>> e['max_length'] = 'LENGTH %(length)s, MAX LENGTH %(max)s'
+>>> e['min_length'] = 'LENGTH %(show_value)s, MIN LENGTH %(limit_value)s'
+>>> e['max_length'] = 'LENGTH %(show_value)s, MAX LENGTH %(limit_value)s'
>>> f = RegexField(r'^\d+$', min_length=5, max_length=10, error_messages=e)
>>> f.clean('')
Traceback (most recent call last):
@@ -180,8 +180,8 @@ ValidationError: [u'LENGTH 11, MAX LENGTH 10']
>>> e = {'required': 'REQUIRED'}
>>> e['invalid'] = 'INVALID'
->>> e['min_length'] = 'LENGTH %(length)s, MIN LENGTH %(min)s'
->>> e['max_length'] = 'LENGTH %(length)s, MAX LENGTH %(max)s'
+>>> e['min_length'] = 'LENGTH %(show_value)s, MIN LENGTH %(limit_value)s'
+>>> e['max_length'] = 'LENGTH %(show_value)s, MAX LENGTH %(limit_value)s'
>>> f = EmailField(min_length=8, max_length=10, error_messages=e)
>>> f.clean('')
Traceback (most recent call last):
diff --git a/tests/regressiontests/forms/fields.py b/tests/regressiontests/forms/fields.py
index c9736d38e1..87330904df 100644
--- a/tests/regressiontests/forms/fields.py
+++ b/tests/regressiontests/forms/fields.py
@@ -386,7 +386,7 @@ class FieldsTests(TestCase):
def test_regexfield_31(self):
f = RegexField('^\d+$', min_length=5, max_length=10)
self.assertRaisesErrorWithMessage(ValidationError, "[u'Ensure this value has at least 5 characters (it has 3).']", f.clean, '123')
- self.assertRaisesErrorWithMessage(ValidationError, "[u'Ensure this value has at least 5 characters (it has 3).']", f.clean, 'abc')
+ self.assertRaisesErrorWithMessage(ValidationError, "[u'Ensure this value has at least 5 characters (it has 3).', u'Enter a valid value.']", f.clean, 'abc')
self.assertEqual(u'12345', f.clean('12345'))
self.assertEqual(u'1234567890', f.clean('1234567890'))
self.assertRaisesErrorWithMessage(ValidationError, "[u'Ensure this value has at most 10 characters (it has 11).']", f.clean, '12345678901')
@@ -548,6 +548,10 @@ class FieldsTests(TestCase):
self.assertEqual(u'http://example.com/', f.clean('http://example.com'))
self.assertEqual(u'http://example.com/test', f.clean('http://example.com/test'))
+ def test_urlfield_ticket11826(self):
+ f = URLField()
+ self.assertEqual(u'http://example.com/?some_param=some_value', f.clean('http://example.com?some_param=some_value'))
+
# BooleanField ################################################################
def test_booleanfield_44(self):
diff --git a/tests/regressiontests/forms/localflavor/ar.py b/tests/regressiontests/forms/localflavor/ar.py
index e1c827c4a0..c7967c84da 100644
--- a/tests/regressiontests/forms/localflavor/ar.py
+++ b/tests/regressiontests/forms/localflavor/ar.py
@@ -28,7 +28,7 @@ u'C1064AAB'
>>> f.clean('C1064AABB')
Traceback (most recent call last):
...
-ValidationError: [u'Ensure this value has at most 8 characters (it has 9).']
+ValidationError: [u'Ensure this value has at most 8 characters (it has 9).', u'Enter a postal code in the format NNNN or ANNNNAAA.']
>>> f.clean('C1064AA')
Traceback (most recent call last):
...
@@ -44,7 +44,7 @@ ValidationError: [u'Enter a postal code in the format NNNN or ANNNNAAA.']
>>> f.clean('500')
Traceback (most recent call last):
...
-ValidationError: [u'Ensure this value has at least 4 characters (it has 3).']
+ValidationError: [u'Ensure this value has at least 4 characters (it has 3).', u'Enter a postal code in the format NNNN or ANNNNAAA.']
>>> f.clean('5PPP')
Traceback (most recent call last):
...
@@ -78,7 +78,7 @@ u'C1064AAB'
>>> f.clean('C1064AABB')
Traceback (most recent call last):
...
-ValidationError: [u'Ensure this value has at most 8 characters (it has 9).']
+ValidationError: [u'Ensure this value has at most 8 characters (it has 9).', u'Enter a postal code in the format NNNN or ANNNNAAA.']
>>> f.clean('C1064AA')
Traceback (most recent call last):
...
@@ -94,7 +94,7 @@ ValidationError: [u'Enter a postal code in the format NNNN or ANNNNAAA.']
>>> f.clean('500')
Traceback (most recent call last):
...
-ValidationError: [u'Ensure this value has at least 4 characters (it has 3).']
+ValidationError: [u'Ensure this value has at least 4 characters (it has 3).', u'Enter a postal code in the format NNNN or ANNNNAAA.']
>>> f.clean('5PPP')
Traceback (most recent call last):
...
diff --git a/tests/regressiontests/forms/localflavor/is_.py b/tests/regressiontests/forms/localflavor/is_.py
index 6851441a79..e71c2dd8de 100644
--- a/tests/regressiontests/forms/localflavor/is_.py
+++ b/tests/regressiontests/forms/localflavor/is_.py
@@ -15,11 +15,11 @@ u'230880-3449'
>>> f.clean('230880343')
Traceback (most recent call last):
...
-ValidationError: [u'Ensure this value has at least 10 characters (it has 9).']
+ValidationError: [u'Ensure this value has at least 10 characters (it has 9).', u'Enter a valid Icelandic identification number. The format is XXXXXX-XXXX.']
>>> f.clean('230880343234')
Traceback (most recent call last):
...
-ValidationError: [u'Ensure this value has at most 11 characters (it has 12).']
+ValidationError: [u'Ensure this value has at most 11 characters (it has 12).', u'Enter a valid Icelandic identification number. The format is XXXXXX-XXXX.']
>>> f.clean('abcdefghijk')
Traceback (most recent call last):
...
@@ -61,18 +61,18 @@ ValidationError: [u'Enter a valid value.']
>>> f.clean('123456')
Traceback (most recent call last):
...
-ValidationError: [u'Ensure this value has at least 7 characters (it has 6).']
+ValidationError: [u'Ensure this value has at least 7 characters (it has 6).', u'Enter a valid value.']
>>> f.clean('123456555')
Traceback (most recent call last):
...
-ValidationError: [u'Ensure this value has at most 8 characters (it has 9).']
+ValidationError: [u'Ensure this value has at most 8 characters (it has 9).', u'Enter a valid value.']
>>> f.clean('abcdefg')
Traceback (most recent call last):
ValidationError: [u'Enter a valid value.']
>>> f.clean(' 1234567 ')
Traceback (most recent call last):
...
-ValidationError: [u'Ensure this value has at most 8 characters (it has 9).']
+ValidationError: [u'Ensure this value has at most 8 characters (it has 9).', u'Enter a valid value.']
>>> f.clean(' 12367 ')
Traceback (most recent call last):
...
diff --git a/tests/regressiontests/forms/tests.py b/tests/regressiontests/forms/tests.py
index 89140f04b1..db70500909 100644
--- a/tests/regressiontests/forms/tests.py
+++ b/tests/regressiontests/forms/tests.py
@@ -38,6 +38,7 @@ from formsets import tests as formset_tests
from media import media_tests
from fields import FieldsTests
+from validators import TestFieldWithValidators
__test__ = {
'extra_tests': extra_tests,
diff --git a/tests/regressiontests/forms/util.py b/tests/regressiontests/forms/util.py
index 845ddeaadb..f365c8c1ae 100644
--- a/tests/regressiontests/forms/util.py
+++ b/tests/regressiontests/forms/util.py
@@ -5,6 +5,7 @@ Tests for forms/util.py module.
tests = r"""
>>> from django.forms.util import *
+>>> from django.core.exceptions import ValidationError
>>> from django.utils.translation import ugettext_lazy
###########
@@ -24,36 +25,36 @@ u''
###################
# Can take a string.
->>> print ValidationError("There was an error.").messages
+>>> print ErrorList(ValidationError("There was an error.").messages)
<ul class="errorlist"><li>There was an error.</li></ul>
# Can take a unicode string.
->>> print ValidationError(u"Not \u03C0.").messages
+>>> print ErrorList(ValidationError(u"Not \u03C0.").messages)
<ul class="errorlist"><li>Not π.</li></ul>
# Can take a lazy string.
->>> print ValidationError(ugettext_lazy("Error.")).messages
+>>> print ErrorList(ValidationError(ugettext_lazy("Error.")).messages)
<ul class="errorlist"><li>Error.</li></ul>
# Can take a list.
->>> print ValidationError(["Error one.", "Error two."]).messages
+>>> print ErrorList(ValidationError(["Error one.", "Error two."]).messages)
<ul class="errorlist"><li>Error one.</li><li>Error two.</li></ul>
# Can take a mixture in a list.
->>> print ValidationError(["First error.", u"Not \u03C0.", ugettext_lazy("Error.")]).messages
+>>> print ErrorList(ValidationError(["First error.", u"Not \u03C0.", ugettext_lazy("Error.")]).messages)
<ul class="errorlist"><li>First error.</li><li>Not π.</li><li>Error.</li></ul>
>>> class VeryBadError:
... def __unicode__(self): return u"A very bad error."
# Can take a non-string.
->>> print ValidationError(VeryBadError()).messages
+>>> print ErrorList(ValidationError(VeryBadError()).messages)
<ul class="errorlist"><li>A very bad error.</li></ul>
# Escapes non-safe input but not input marked safe.
>>> example = 'Example of link: <a href="http://www.example.com/">example</a>'
->>> print ValidationError(example).messages
+>>> print ErrorList([example])
<ul class="errorlist"><li>Example of link: &lt;a href=&quot;http://www.example.com/&quot;&gt;example&lt;/a&gt;</li></ul>
->>> print ValidationError(mark_safe(example)).messages
+>>> print ErrorList([mark_safe(example)])
<ul class="errorlist"><li>Example of link: <a href="http://www.example.com/">example</a></li></ul>
"""
diff --git a/tests/regressiontests/forms/validators.py b/tests/regressiontests/forms/validators.py
new file mode 100644
index 0000000000..ed8e8fbd9a
--- /dev/null
+++ b/tests/regressiontests/forms/validators.py
@@ -0,0 +1,17 @@
+from unittest import TestCase
+
+from django import forms
+from django.core import validators
+from django.core.exceptions import ValidationError
+
+
+class TestFieldWithValidators(TestCase):
+ def test_all_errors_get_reported(self):
+ field = forms.CharField(
+ validators=[validators.validate_integer, validators.validate_email]
+ )
+ self.assertRaises(ValidationError, field.clean, 'not int nor mail')
+ try:
+ field.clean('not int nor mail')
+ except ValidationError, e:
+ self.assertEqual(2, len(e.messages))
diff --git a/tests/regressiontests/inline_formsets/tests.py b/tests/regressiontests/inline_formsets/tests.py
index aef6b3f10a..be313f3bf6 100644
--- a/tests/regressiontests/inline_formsets/tests.py
+++ b/tests/regressiontests/inline_formsets/tests.py
@@ -81,7 +81,7 @@ class DeletionTests(TestCase):
regression for #10750
"""
# exclude some required field from the forms
- ChildFormSet = inlineformset_factory(School, Child, exclude=['father', 'mother'])
+ ChildFormSet = inlineformset_factory(School, Child)
school = School.objects.create(name=u'test')
mother = Parent.objects.create(name=u'mother')
father = Parent.objects.create(name=u'father')
@@ -89,13 +89,13 @@ class DeletionTests(TestCase):
'child_set-TOTAL_FORMS': u'1',
'child_set-INITIAL_FORMS': u'0',
'child_set-0-name': u'child',
+ 'child_set-0-mother': unicode(mother.pk),
+ 'child_set-0-father': unicode(father.pk),
}
formset = ChildFormSet(data, instance=school)
self.assertEqual(formset.is_valid(), True)
objects = formset.save(commit=False)
- for obj in objects:
- obj.mother = mother
- obj.father = father
- obj.save()
+ self.assertEqual(school.child_set.count(), 0)
+ objects[0].save()
self.assertEqual(school.child_set.count(), 1)
diff --git a/tests/regressiontests/model_fields/tests.py b/tests/regressiontests/model_fields/tests.py
index f31193e269..ea7b49ab7e 100644
--- a/tests/regressiontests/model_fields/tests.py
+++ b/tests/regressiontests/model_fields/tests.py
@@ -147,6 +147,58 @@ class SlugFieldTests(django.test.TestCase):
bs = BigS.objects.get(pk=bs.pk)
self.assertEqual(bs.s, 'slug'*50)
+
+class ValidationTest(django.test.TestCase):
+ def test_charfield_raises_error_on_empty_string(self):
+ f = models.CharField()
+ self.assertRaises(ValidationError, f.clean, "", None)
+
+ def test_charfield_cleans_empty_string_when_blank_true(self):
+ f = models.CharField(blank=True)
+ self.assertEqual('', f.clean('', None))
+
+ def test_integerfield_cleans_valid_string(self):
+ f = models.IntegerField()
+ self.assertEqual(2, f.clean('2', None))
+
+ def test_integerfield_raises_error_on_invalid_intput(self):
+ f = models.IntegerField()
+ self.assertRaises(ValidationError, f.clean, "a", None)
+
+ def test_charfield_with_choices_cleans_valid_choice(self):
+ f = models.CharField(max_length=1, choices=[('a','A'), ('b','B')])
+ self.assertEqual('a', f.clean('a', None))
+
+ def test_charfield_with_choices_raises_error_on_invalid_choice(self):
+ f = models.CharField(choices=[('a','A'), ('b','B')])
+ self.assertRaises(ValidationError, f.clean, "not a", None)
+
+ def test_nullable_integerfield_raises_error_with_blank_false(self):
+ f = models.IntegerField(null=True, blank=False)
+ self.assertRaises(ValidationError, f.clean, None, None)
+
+ def test_nullable_integerfield_cleans_none_on_null_and_blank_true(self):
+ f = models.IntegerField(null=True, blank=True)
+ self.assertEqual(None, f.clean(None, None))
+
+ def test_integerfield_raises_error_on_empty_input(self):
+ f = models.IntegerField(null=False)
+ self.assertRaises(ValidationError, f.clean, None, None)
+ self.assertRaises(ValidationError, f.clean, '', None)
+
+ def test_charfield_raises_error_on_empty_input(self):
+ f = models.CharField(null=False)
+ self.assertRaises(ValidationError, f.clean, None, None)
+
+ def test_datefield_cleans_date(self):
+ f = models.DateField()
+ self.assertEqual(datetime.date(2008, 10, 10), f.clean('2008-10-10', None))
+
+ def test_boolean_field_doesnt_accept_empty_input(self):
+ f = models.BooleanField()
+ self.assertRaises(ValidationError, f.clean, None, None)
+
+
class BigIntegerFieldTests(django.test.TestCase):
def test_limits(self):
# Ensure that values that are right at the limits can be saved
diff --git a/tests/regressiontests/views/views.py b/tests/regressiontests/views/views.py
index 3447cbfdfd..20ee56f985 100644
--- a/tests/regressiontests/views/views.py
+++ b/tests/regressiontests/views/views.py
@@ -24,7 +24,7 @@ def custom_create(request):
model = Article
def save(self, *args, **kwargs):
- self.cleaned_data['slug'] = 'some-other-slug'
+ self.instance.slug = 'some-other-slug'
return super(SlugChangingArticleForm, self).save(*args, **kwargs)
return create_object(request,