diff --git a/django/contrib/localflavor/se/utils.py b/django/contrib/localflavor/se/utils.py index 7fe2b09812..50d8ac1d8e 100644 --- a/django/contrib/localflavor/se/utils.py +++ b/django/contrib/localflavor/se/utils.py @@ -12,7 +12,7 @@ def id_number_checksum(gd): if tmp > 9: tmp = sum([int(i) for i in str(tmp)]) - + s += tmp n += 1 @@ -28,9 +28,9 @@ def validate_id_birthday(gd, fix_coordination_number_day=True): If the date is an invalid birth day, a ValueError will be raised. """ - + today = datetime.date.today() - + day = int(gd['day']) if fix_coordination_number_day and day > 60: day -= 60 @@ -40,7 +40,7 @@ def validate_id_birthday(gd, fix_coordination_number_day=True): # The century was not specified, and need to be calculated from todays date current_year = today.year year = int(today.strftime('%Y')) - int(today.strftime('%y')) + int(gd['year']) - + if ('%s%s%02d' % (gd['year'], gd['month'], day)) > today.strftime('%y%m%d'): year -= 100 @@ -49,7 +49,7 @@ def validate_id_birthday(gd, fix_coordination_number_day=True): year -= 100 else: year = int(gd['century'] + gd['year']) - + # Make sure the year is valid # There are no swedish personal identity numbers where year < 1800 if year < 1800: @@ -57,11 +57,11 @@ def validate_id_birthday(gd, fix_coordination_number_day=True): # ValueError will be raise for invalid dates birth_day = datetime.date(year, int(gd['month']), day) - + # birth_day must not be in the future if birth_day > today: raise ValueError - + return birth_day def format_personal_id_number(birth_day, gd): diff --git a/tests/regressiontests/forms/localflavor/se.py b/tests/regressiontests/forms/localflavor/se.py index 316a612f85..de476d747e 100644 --- a/tests/regressiontests/forms/localflavor/se.py +++ b/tests/regressiontests/forms/localflavor/se.py @@ -1,331 +1,165 @@ # -*- coding: utf-8 -*- -# Tests for the contrib/localflavor/se form fields. +from django.contrib.localflavor.se.forms import (SECountySelect, + SEOrganisationNumberField, SEPersonalIdentityNumberField, + SEPostalCodeField) +import datetime + +from utils import LocalFlavorTestCase + + +class SELocalFlavorTests(LocalFlavorTestCase): + + def setUp(self): + # Mocking datetime.date to make sure + # localflavor.se.utils.validate_id_birthday works + class MockDate(datetime.date): + def today(cls): + return datetime.date(2008, 5, 14) + today = classmethod(today) + self._olddate = datetime.date + datetime.date = MockDate + + def tearDown(self): + datetime.date = self._olddate + + def test_SECountySelect(self): + f = SECountySelect() + out = u'''''' + self.assertEqual(f.render('swedish_county', 'E'), out) + + def test_SEOrganizationNumberField(self): + error_invalid = [u'Enter a valid Swedish organisation number.'] + valid = { + '870512-1989': '198705121989', + '19870512-1989': '198705121989', + '870512-2128': '198705122128', + '081015-6315': '190810156315', + '081015+6315': '180810156315', + '0810156315': '190810156315', + # Test some different organisation numbers + # IKEA Linköping + '556074-7569': '5560747569', + # Volvo Personvagnar + '556074-3089': '5560743089', + # LJS (organisation) + '822001-5476': '8220015476', + # LJS (organisation) + '8220015476': '8220015476', + # Katedralskolan Linköping (school) + '2120000449': '2120000449', + # Faux organisation number, which tests that the checksum can be 0 + '232518-5060': '2325185060', + } + invalid = { + # Ordinary personal identity numbers for sole proprietors + # The same rules as for SEPersonalIdentityField applies here + '081015 6315': error_invalid, + '950231-4496': error_invalid, + '6914104499': error_invalid, + '950d314496': error_invalid, + 'invalid!!!': error_invalid, + '870514-1111': error_invalid, + # Co-ordination number checking + # Co-ordination numbers are not valid organisation numbers + '870574-1315': error_invalid, + '870573-1311': error_invalid, + # Volvo Personvagnar, bad format + '556074+3089': error_invalid, + # Invalid checksum + '2120000441': error_invalid, + # Valid checksum but invalid organisation type + '1120000441': error_invalid, + } + self.assertFieldOutput(SEOrganisationNumberField, valid, invalid) + + def test_SEPersonalIdentityNumberField(self): + error_invalid = [u'Enter a valid Swedish personal identity number.'] + error_coord = [u'Co-ordination numbers are not allowed.'] + valid = { + '870512-1989': '198705121989', + '870512-2128': '198705122128', + '19870512-1989': '198705121989', + '198705121989': '198705121989', + '081015-6315': '190810156315', + '0810156315': '190810156315', + # This is a "special-case" in the checksum calculation, + # where the sum is divisible by 10 (the checksum digit == 0) + '8705141060': '198705141060', + # + means that the person is older than 100 years + '081015+6315': '180810156315', + # Co-ordination number checking + '870574-1315': '198705741315', + '870574+1315': '188705741315', + '198705741315': '198705741315', + } + invalid = { + '081015 6315': error_invalid, + '950d314496': error_invalid, + 'invalid!!!': error_invalid, + # Invalid dates + # February 31st does not exist + '950231-4496': error_invalid, + # Month 14 does not exist + '6914104499': error_invalid, + # There are no Swedish personal id numbers where year < 1800 + '17430309-7135': error_invalid, + # Invalid checksum + '870514-1111': error_invalid, + # Co-ordination number with bad checksum + '870573-1311': error_invalid, + } + self.assertFieldOutput(SEPersonalIdentityNumberField, valid, invalid) + + valid = {} + invalid = { + # Check valid co-ordination numbers that should not be accepted + # because of coordination_number=False + '870574-1315': error_coord, + '870574+1315': error_coord, + '8705741315': error_coord, + # Invalid co-ordination numbers should be treated as invalid, and not + # as co-ordination numbers + '870573-1311': error_invalid, + } + kwargs = {'coordination_number': False,} + self.assertFieldOutput(SEPersonalIdentityNumberField, valid, invalid, + field_kwargs=kwargs) + + def test_SEPostalCodeField(self): + error_format = [u'Enter a Swedish postal code in the format XXXXX.'] + valid = { + '589 37': '58937', + '58937': '58937', + } + invalid = { + 'abcasfassadf': error_format, + # Only one space is allowed for separation + '589 37': error_format, + # The postal code must not start with 0 + '01234': error_format, + + } + self.assertFieldOutput(SEPostalCodeField, valid, invalid) -tests = r""" -# Monkey-patch datetime.date ->>> import datetime ->>> class MockDate(datetime.date): -... def today(cls): -... return datetime.date(2008, 5, 14) -... today = classmethod(today) -... ->>> olddate = datetime.date ->>> datetime.date = MockDate ->>> datetime.date.today() == olddate(2008, 5, 14) -True - -# SECountySelect ##################################################### ->>> from django.contrib.localflavor.se.forms import SECountySelect - ->>> w = SECountySelect() ->>> w.render('swedish_county', 'E') -u'' - -# SEOrganisationNumberField ####################################### - ->>> from django.contrib.localflavor.se.forms import SEOrganisationNumberField - ->>> f = SEOrganisationNumberField() - -# Ordinary personal identity numbers for sole proprietors -# The same rules as for SEPersonalIdentityField applies here ->>> f.clean('870512-1989') -u'198705121989' ->>> f.clean('19870512-1989') -u'198705121989' ->>> f.clean('870512-2128') -u'198705122128' ->>> f.clean('081015-6315') -u'190810156315' ->>> f.clean('081015+6315') -u'180810156315' ->>> f.clean('0810156315') -u'190810156315' - ->>> f.clean('081015 6315') -Traceback (most recent call last): -... -ValidationError: [u'Enter a valid Swedish organisation number.'] ->>> f.clean('950231-4496') -Traceback (most recent call last): -... -ValidationError: [u'Enter a valid Swedish organisation number.'] ->>> f.clean('6914104499') -Traceback (most recent call last): -... -ValidationError: [u'Enter a valid Swedish organisation number.'] ->>> f.clean('950d314496') -Traceback (most recent call last): -... -ValidationError: [u'Enter a valid Swedish organisation number.'] ->>> f.clean('invalid!!!') -Traceback (most recent call last): -... -ValidationError: [u'Enter a valid Swedish organisation number.'] ->>> f.clean('870514-1111') -Traceback (most recent call last): -... -ValidationError: [u'Enter a valid Swedish organisation number.'] - - -# Empty values ->>> f.clean('') -Traceback (most recent call last): -... -ValidationError: [u'This field is required.'] - ->>> f.clean(None) -Traceback (most recent call last): -... -ValidationError: [u'This field is required.'] - -# Co-ordination number checking -# Co-ordination numbers are not valid organisation numbers ->>> f.clean('870574-1315') -Traceback (most recent call last): -... -ValidationError: [u'Enter a valid Swedish organisation number.'] - ->>> f.clean('870573-1311') -Traceback (most recent call last): -... -ValidationError: [u'Enter a valid Swedish organisation number.'] - -# Test some different organisation numbers ->>> f.clean('556074-7569') # IKEA Linköping -u'5560747569' - ->>> f.clean('556074-3089') # Volvo Personvagnar -u'5560743089' - ->>> f.clean('822001-5476') # LJS (organisation) -u'8220015476' - ->>> f.clean('8220015476') # LJS (organisation) -u'8220015476' - ->>> f.clean('2120000449') # Katedralskolan Linköping (school) -u'2120000449' - -# Faux organisation number, which tests that the checksum can be 0 ->>> f.clean('232518-5060') -u'2325185060' - ->>> f.clean('556074+3089') # Volvo Personvagnar, bad format -Traceback (most recent call last): -... -ValidationError: [u'Enter a valid Swedish organisation number.'] - - -# Invalid checksum ->>> f.clean('2120000441') -Traceback (most recent call last): -... -ValidationError: [u'Enter a valid Swedish organisation number.'] - -# Valid checksum but invalid organisation type -f.clean('1120000441') -Traceback (most recent call last): -... -ValidationError: [u'Enter a valid Swedish organisation number.'] - -# Empty values with required=False ->>> f = SEOrganisationNumberField(required=False) - ->>> f.clean(None) -u'' - ->>> f.clean('') -u'' - - -# SEPersonalIdentityNumberField ####################################### - ->>> from django.contrib.localflavor.se.forms import SEPersonalIdentityNumberField - ->>> f = SEPersonalIdentityNumberField() - -# Valid id numbers ->>> f.clean('870512-1989') -u'198705121989' - ->>> f.clean('870512-2128') -u'198705122128' - ->>> f.clean('19870512-1989') -u'198705121989' - ->>> f.clean('198705121989') -u'198705121989' - ->>> f.clean('081015-6315') -u'190810156315' - ->>> f.clean('0810156315') -u'190810156315' - -# This is a "special-case" in the checksum calculation, -# where the sum is divisible by 10 (the checksum digit == 0) ->>> f.clean('8705141060') -u'198705141060' - -# + means that the person is older than 100 years ->>> f.clean('081015+6315') -u'180810156315' - -# Bogus values ->>> f.clean('081015 6315') -Traceback (most recent call last): -... -ValidationError: [u'Enter a valid Swedish personal identity number.'] - ->>> f.clean('950d314496') -Traceback (most recent call last): -... -ValidationError: [u'Enter a valid Swedish personal identity number.'] - ->>> f.clean('invalid!!!') -Traceback (most recent call last): -... -ValidationError: [u'Enter a valid Swedish personal identity number.'] - - -# Invalid dates - -# February 31st does not exist ->>> f.clean('950231-4496') -Traceback (most recent call last): -... -ValidationError: [u'Enter a valid Swedish personal identity number.'] - -# Month 14 does not exist ->>> f.clean('6914104499') -Traceback (most recent call last): -... -ValidationError: [u'Enter a valid Swedish personal identity number.'] - -# There are no Swedish personal id numbers where year < 1800 ->>> f.clean('17430309-7135') -Traceback (most recent call last): -... -ValidationError: [u'Enter a valid Swedish personal identity number.'] - -# Invalid checksum ->>> f.clean('870514-1111') -Traceback (most recent call last): -... -ValidationError: [u'Enter a valid Swedish personal identity number.'] - -# Empty values ->>> f.clean('') -Traceback (most recent call last): -... -ValidationError: [u'This field is required.'] - ->>> f.clean(None) -Traceback (most recent call last): -... -ValidationError: [u'This field is required.'] - -# Co-ordination number checking ->>> f.clean('870574-1315') -u'198705741315' - ->>> f.clean('870574+1315') -u'188705741315' - ->>> f.clean('198705741315') -u'198705741315' - -# Co-ordination number with bad checksum ->>> f.clean('870573-1311') -Traceback (most recent call last): -... -ValidationError: [u'Enter a valid Swedish personal identity number.'] - - -# Check valid co-ordination numbers, that should not be accepted -# because of coordination_number=False ->>> f = SEPersonalIdentityNumberField(coordination_number=False) - ->>> f.clean('870574-1315') -Traceback (most recent call last): -... -ValidationError: [u'Co-ordination numbers are not allowed.'] - ->>> f.clean('870574+1315') -Traceback (most recent call last): -... -ValidationError: [u'Co-ordination numbers are not allowed.'] - ->>> f.clean('8705741315') -Traceback (most recent call last): -... -ValidationError: [u'Co-ordination numbers are not allowed.'] - -# Invalid co-ordination numbers should be treated as invalid, and not -# as co-ordination numbers ->>> f.clean('870573-1311') -Traceback (most recent call last): -... -ValidationError: [u'Enter a valid Swedish personal identity number.'] - -# Empty values with required=False ->>> f = SEPersonalIdentityNumberField(required=False) - ->>> f.clean(None) -u'' - ->>> f.clean('') -u'' - -# SEPostalCodeField ############################################### ->>> from django.contrib.localflavor.se.forms import SEPostalCodeField ->>> f = SEPostalCodeField() ->>> -Postal codes can have spaces ->>> f.clean('589 37') -u'58937' - -... but the dont have to ->>> f.clean('58937') -u'58937' ->>> f.clean('abcasfassadf') -Traceback (most recent call last): -... -ValidationError: [u'Enter a Swedish postal code in the format XXXXX.'] - -# Only one space is allowed for separation ->>> f.clean('589 37') -Traceback (most recent call last): -... -ValidationError: [u'Enter a Swedish postal code in the format XXXXX.'] - -# The postal code must not start with 0 ->>> f.clean('01234') -Traceback (most recent call last): -... -ValidationError: [u'Enter a Swedish postal code in the format XXXXX.'] - -# Empty values ->>> f.clean('') -Traceback (most recent call last): -... -ValidationError: [u'This field is required.'] - ->>> f.clean(None) -Traceback (most recent call last): -... -ValidationError: [u'This field is required.'] - -# Empty values, required=False ->>> f = SEPostalCodeField(required=False) ->>> f.clean('') -u'' ->>> f.clean(None) -u'' - -# Revert the monkey patching ->>> datetime.date = olddate - -""" diff --git a/tests/regressiontests/forms/localflavor/utils.py b/tests/regressiontests/forms/localflavor/utils.py index 6a47538da0..482f7adeab 100644 --- a/tests/regressiontests/forms/localflavor/utils.py +++ b/tests/regressiontests/forms/localflavor/utils.py @@ -14,8 +14,9 @@ class LocalFlavorTestCase(TestCase): restore_warnings_state(self._warnings_state) def assertFieldOutput(self, fieldclass, valid, invalid, field_args=[], - field_kwargs={}, empty_value=u''): - """Asserts that a field behaves correctly with various inputs. + field_kwargs={}, empty_value=u''): + """ + Asserts that a field behaves correctly with various inputs. Args: fieldclass: the class of the field to be tested. @@ -23,9 +24,10 @@ class LocalFlavorTestCase(TestCase): cleaned values. invalid: a dictionary mapping invalid inputs to one or more raised error messages. - fieldargs: the args passed to instantiate the field - fieldkwargs: the kwargs passed to instantiate the field - emptyvalue: the expected clean output for inputs in EMPTY_VALUES + field_args: the args passed to instantiate the field + field_kwargs: the kwargs passed to instantiate the field + empty_value: the expected clean output for inputs in EMPTY_VALUES + """ required = fieldclass(*field_args, **field_kwargs) optional = fieldclass(*field_args, **dict(field_kwargs, required=False)) diff --git a/tests/regressiontests/forms/localflavortests.py b/tests/regressiontests/forms/localflavortests.py index 66059383d3..befc0a7512 100644 --- a/tests/regressiontests/forms/localflavortests.py +++ b/tests/regressiontests/forms/localflavortests.py @@ -1,5 +1,5 @@ +# -*- coding: utf-8 -*- from localflavor.cz import tests as localflavor_cz_tests -from localflavor.se import tests as localflavor_se_tests from localflavor.ar import ARLocalFlavorTests from localflavor.at import ATLocalFlavorTests @@ -25,6 +25,7 @@ from localflavor.nl import NLLocalFlavorTests from localflavor.pl import PLLocalFlavorTests from localflavor.pt import PTLocalFlavorTests from localflavor.ro import ROLocalFlavorTests +from localflavor.se import SELocalFlavorTests from localflavor.sk import SKLocalFlavorTests from localflavor.tr import TRLocalFlavorTests from localflavor.uk import UKLocalFlavorTests @@ -35,5 +36,4 @@ from localflavor.za import ZALocalFlavorTests __test__ = { 'localflavor_cz_tests': localflavor_cz_tests, - 'localflavor_se_tests': localflavor_se_tests, } diff --git a/tests/regressiontests/forms/tests/__init__.py b/tests/regressiontests/forms/tests/__init__.py index ba34c164f3..4f24f52c6d 100644 --- a/tests/regressiontests/forms/tests/__init__.py +++ b/tests/regressiontests/forms/tests/__init__.py @@ -37,6 +37,7 @@ from regressiontests.forms.localflavortests import ( PLLocalFlavorTests, PTLocalFlavorTests, ROLocalFlavorTests, + SELocalFlavorTests, SKLocalFlavorTests, TRLocalFlavorTests, UKLocalFlavorTests,