summaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
authorMalcolm Tredinnick <malcolm.tredinnick@gmail.com>2007-05-21 01:29:58 +0000
committerMalcolm Tredinnick <malcolm.tredinnick@gmail.com>2007-05-21 01:29:58 +0000
commit92c35a0617836b09aef3b6909579ee368004969b (patch)
treecd5a12f945bf105a53a0346f84c7d5ca6fc7f11f /tests
parent03966f077b8f87d6a59366dedc80fcf1f935e2d3 (diff)
Fixed #2365, #3324 -- Renamed FloatField to DecimalField and changed the code
to return Decimal instances in Python for this field. Backwards incompatible change. Added a real FloatField (stores floats in the database) and support for FloatField and DecimalField in newforms (analogous to IntegerField). Included decimal.py module (as django.utils._decimal) from Python 2.4. This is license compatible with Django and included for Python 2.3 compatibility only. Large portions of this work are based on patches from Andy Durdin and Jorge Gajon. git-svn-id: http://code.djangoproject.com/svn/django/trunk@5302 bcc190cf-cafb-0310-a4f2-bffc1f526a37
Diffstat (limited to 'tests')
-rw-r--r--tests/modeltests/invalid_models/models.py10
-rw-r--r--tests/regressiontests/forms/tests.py131
-rw-r--r--tests/regressiontests/serializers_regress/models.py16
-rw-r--r--tests/regressiontests/serializers_regress/tests.py71
4 files changed, 188 insertions, 40 deletions
diff --git a/tests/modeltests/invalid_models/models.py b/tests/modeltests/invalid_models/models.py
index af54ec3d35..90f2f54632 100644
--- a/tests/modeltests/invalid_models/models.py
+++ b/tests/modeltests/invalid_models/models.py
@@ -8,7 +8,7 @@ from django.db import models
class FieldErrors(models.Model):
charfield = models.CharField()
- floatfield = models.FloatField()
+ decimalfield = models.DecimalField()
filefield = models.FileField()
prepopulate = models.CharField(maxlength=10, prepopulate_from='bad')
choices = models.CharField(maxlength=10, choices='bad')
@@ -87,10 +87,10 @@ class SelfClashM2M(models.Model):
src_safe = models.CharField(maxlength=10)
selfclashm2m = models.CharField(maxlength=10)
- # Non-symmetrical M2M fields _do_ have related accessors, so
+ # Non-symmetrical M2M fields _do_ have related accessors, so
# there is potential for clashes.
selfclashm2m_set = models.ManyToManyField("SelfClashM2M", symmetrical=False)
-
+
m2m_1 = models.ManyToManyField("SelfClashM2M", related_name='id', symmetrical=False)
m2m_2 = models.ManyToManyField("SelfClashM2M", related_name='src_safe', symmetrical=False)
@@ -108,8 +108,8 @@ class Car(models.Model):
model = models.ForeignKey(Model)
model_errors = """invalid_models.fielderrors: "charfield": CharFields require a "maxlength" attribute.
-invalid_models.fielderrors: "floatfield": FloatFields require a "decimal_places" attribute.
-invalid_models.fielderrors: "floatfield": FloatFields require a "max_digits" attribute.
+invalid_models.fielderrors: "decimalfield": DecimalFields require a "decimal_places" attribute.
+invalid_models.fielderrors: "decimalfield": DecimalFields require a "max_digits" attribute.
invalid_models.fielderrors: "filefield": FileFields require an "upload_to" attribute.
invalid_models.fielderrors: "prepopulate": prepopulate_from should be a list or tuple.
invalid_models.fielderrors: "choices": "choices" should be iterable (e.g., a tuple or list).
diff --git a/tests/regressiontests/forms/tests.py b/tests/regressiontests/forms/tests.py
index 5939f7806c..ba5beed5e5 100644
--- a/tests/regressiontests/forms/tests.py
+++ b/tests/regressiontests/forms/tests.py
@@ -7,6 +7,10 @@ form_tests = r"""
>>> import datetime
>>> import time
>>> import re
+>>> try:
+... from decimal import Decimal
+... except ImportError:
+... from django.utils._decimal import Decimal
###########
# Widgets #
@@ -1046,6 +1050,133 @@ Traceback (most recent call last):
...
ValidationError: [u'Ensure this value is less than or equal to 20.']
+# FloatField ##################################################################
+
+>>> f = FloatField()
+>>> 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.']
+>>> f.clean('1')
+1.0
+>>> isinstance(f.clean('1'), float)
+True
+>>> f.clean('23')
+23.0
+>>> f.clean('3.14')
+3.1400000000000001
+>>> f.clean('a')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a number.']
+>>> f.clean('1.0 ')
+1.0
+>>> f.clean(' 1.0')
+1.0
+>>> f.clean(' 1.0 ')
+1.0
+>>> f.clean('1.0a')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a number.']
+
+>>> f = FloatField(required=False)
+>>> f.clean('')
+
+>>> f.clean(None)
+
+>>> f.clean('1')
+1.0
+
+FloatField accepts min_value and max_value just like IntegerField:
+>>> f = FloatField(max_value=1.5, min_value=0.5)
+
+>>> f.clean('1.6')
+Traceback (most recent call last):
+...
+ValidationError: [u'Ensure this value is less than or equal to 1.5.']
+>>> f.clean('0.4')
+Traceback (most recent call last):
+...
+ValidationError: [u'Ensure this value is greater than or equal to 0.5.']
+>>> f.clean('1.5')
+1.5
+>>> f.clean('0.5')
+0.5
+
+# DecimalField ################################################################
+
+>>> f = DecimalField(max_digits=4, decimal_places=2)
+>>> 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.']
+>>> f.clean('1')
+Decimal("1")
+>>> isinstance(f.clean('1'), Decimal)
+True
+>>> f.clean('23')
+Decimal("23")
+>>> f.clean('3.14')
+Decimal("3.14")
+>>> f.clean('a')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a number.']
+>>> f.clean('1.0 ')
+Decimal("1.0")
+>>> f.clean(' 1.0')
+Decimal("1.0")
+>>> f.clean(' 1.0 ')
+Decimal("1.0")
+>>> f.clean('1.0a')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a number.']
+>>> f.clean('123.45')
+Traceback (most recent call last):
+...
+ValidationError: [u'Ensure that there are no more than 4 digits in total.']
+>>> f.clean('1.234')
+Traceback (most recent call last):
+...
+ValidationError: [u'Ensure that there are no more than 2 decimal places.']
+>>> f.clean('123.4')
+Traceback (most recent call last):
+...
+ValidationError: [u'Ensure that there are no more than 2 digits before the decimal point.']
+>>> f = DecimalField(max_digits=4, decimal_places=2, required=False)
+>>> f.clean('')
+
+>>> f.clean(None)
+
+>>> f.clean('1')
+Decimal("1")
+
+DecimalField accepts min_value and max_value just like IntegerField:
+>>> f = DecimalField(max_digits=4, decimal_places=2, max_value=Decimal('1.5'), min_value=Decimal('0.5'))
+
+>>> f.clean('1.6')
+Traceback (most recent call last):
+...
+ValidationError: [u'Ensure this value is less than or equal to 1.5.']
+>>> f.clean('0.4')
+Traceback (most recent call last):
+...
+ValidationError: [u'Ensure this value is greater than or equal to 0.5.']
+>>> f.clean('1.5')
+Decimal("1.5")
+>>> f.clean('0.5')
+Decimal("0.5")
+
# DateField ###################################################################
>>> import datetime
diff --git a/tests/regressiontests/serializers_regress/models.py b/tests/regressiontests/serializers_regress/models.py
index fea5c94cab..999b79ccaf 100644
--- a/tests/regressiontests/serializers_regress/models.py
+++ b/tests/regressiontests/serializers_regress/models.py
@@ -1,7 +1,7 @@
"""
A test spanning all the capabilities of all the serializers.
-This class sets up a model for each model field type
+This class sets up a model for each model field type
(except for image types, because of the PIL dependency).
"""
@@ -9,12 +9,12 @@ from django.db import models
from django.contrib.contenttypes import generic
from django.contrib.contenttypes.models import ContentType
-# The following classes are for testing basic data
+# The following classes are for testing basic data
# marshalling, including NULL values.
class BooleanData(models.Model):
data = models.BooleanField(null=True)
-
+
class CharData(models.Model):
data = models.CharField(maxlength=30, null=True)
@@ -24,6 +24,9 @@ class DateData(models.Model):
class DateTimeData(models.Model):
data = models.DateTimeField(null=True)
+class DecimalData(models.Model):
+ data = models.DecimalField(null=True, decimal_places=3, max_digits=5)
+
class EmailData(models.Model):
data = models.EmailField(null=True)
@@ -34,7 +37,7 @@ class FilePathData(models.Model):
data = models.FilePathField(null=True)
class FloatData(models.Model):
- data = models.FloatField(null=True, decimal_places=3, max_digits=5)
+ data = models.FloatField(null=True)
class IntegerData(models.Model):
data = models.IntegerField(null=True)
@@ -145,6 +148,9 @@ class CharPKData(models.Model):
# class DateTimePKData(models.Model):
# data = models.DateTimeField(primary_key=True)
+class DecimalPKData(models.Model):
+ data = models.DecimalField(primary_key=True, decimal_places=3, max_digits=5)
+
class EmailPKData(models.Model):
data = models.EmailField(primary_key=True)
@@ -155,7 +161,7 @@ class FilePathPKData(models.Model):
data = models.FilePathField(primary_key=True)
class FloatPKData(models.Model):
- data = models.FloatField(primary_key=True, decimal_places=3, max_digits=5)
+ data = models.FloatField(primary_key=True)
class IntegerPKData(models.Model):
data = models.IntegerField(primary_key=True)
diff --git a/tests/regressiontests/serializers_regress/tests.py b/tests/regressiontests/serializers_regress/tests.py
index 317739dac4..5df4c6818a 100644
--- a/tests/regressiontests/serializers_regress/tests.py
+++ b/tests/regressiontests/serializers_regress/tests.py
@@ -2,7 +2,7 @@
A test spanning all the capabilities of all the serializers.
This class defines sample data and a dynamically generated
-test case that is capable of testing the capabilities of
+test case that is capable of testing the capabilities of
the serializers. This includes all valid data values, plus
forward, backwards and self references.
"""
@@ -16,13 +16,17 @@ from django.db import transaction
from django.core import management
from models import *
+try:
+ import decimal
+except ImportError:
+ from django.utils import _decimal as decimal
# A set of functions that can be used to recreate
# test data objects of various kinds
def data_create(pk, klass, data):
instance = klass(id=pk)
instance.data = data
- instance.save()
+ instance.save()
return instance
def generic_create(pk, klass, data):
@@ -32,13 +36,13 @@ def generic_create(pk, klass, data):
for tag in data[1:]:
instance.tags.create(data=tag)
return instance
-
+
def fk_create(pk, klass, data):
instance = klass(id=pk)
setattr(instance, 'data_id', data)
instance.save()
return instance
-
+
def m2m_create(pk, klass, data):
instance = klass(id=pk)
instance.save()
@@ -61,14 +65,14 @@ def pk_create(pk, klass, data):
# test data objects of various kinds
def data_compare(testcase, pk, klass, data):
instance = klass.objects.get(id=pk)
- testcase.assertEqual(data, instance.data,
+ testcase.assertEqual(data, instance.data,
"Objects with PK=%d not equal; expected '%s' (%s), got '%s' (%s)" % (pk,data, type(data), instance.data, type(instance.data)))
def generic_compare(testcase, pk, klass, data):
instance = klass.objects.get(id=pk)
testcase.assertEqual(data[0], instance.data)
testcase.assertEqual(data[1:], [t.data for t in instance.tags.all()])
-
+
def fk_compare(testcase, pk, klass, data):
instance = klass.objects.get(id=pk)
testcase.assertEqual(data, instance.data_id)
@@ -84,7 +88,7 @@ def o2o_compare(testcase, pk, klass, data):
def pk_compare(testcase, pk, klass, data):
instance = klass.objects.get(data=data)
testcase.assertEqual(data, instance.data)
-
+
# Define some data types. Each data type is
# actually a pair of functions; one to create
# and one to compare objects of that type
@@ -96,7 +100,7 @@ o2o_obj = (o2o_create, o2o_compare)
pk_obj = (pk_create, pk_compare)
test_data = [
- # Format: (data type, PK value, Model Class, data)
+ # Format: (data type, PK value, Model Class, data)
(data_obj, 1, BooleanData, True),
(data_obj, 2, BooleanData, False),
(data_obj, 10, CharData, "Test Char Data"),
@@ -115,10 +119,14 @@ test_data = [
(data_obj, 51, FileData, None),
(data_obj, 60, FilePathData, "/foo/bar/whiz.txt"),
(data_obj, 61, FilePathData, None),
- (data_obj, 70, FloatData, 12.345),
- (data_obj, 71, FloatData, -12.345),
- (data_obj, 72, FloatData, 0.0),
- (data_obj, 73, FloatData, None),
+ (data_obj, 70, DecimalData, decimal.Decimal('12.345')),
+ (data_obj, 71, DecimalData, decimal.Decimal('-12.345')),
+ (data_obj, 72, DecimalData, decimal.Decimal('0.0')),
+ (data_obj, 73, DecimalData, None),
+ (data_obj, 74, FloatData, 12.345),
+ (data_obj, 75, FloatData, -12.345),
+ (data_obj, 76, FloatData, 0.0),
+ (data_obj, 77, FloatData, None),
(data_obj, 80, IntegerData, 123456789),
(data_obj, 81, IntegerData, -123456789),
(data_obj, 82, IntegerData, 0),
@@ -137,10 +145,10 @@ test_data = [
(data_obj, 131, PositiveSmallIntegerData, None),
(data_obj, 140, SlugData, "this-is-a-slug"),
(data_obj, 141, SlugData, None),
- (data_obj, 150, SmallData, 12),
- (data_obj, 151, SmallData, -12),
- (data_obj, 152, SmallData, 0),
- (data_obj, 153, SmallData, None),
+ (data_obj, 150, SmallData, 12),
+ (data_obj, 151, SmallData, -12),
+ (data_obj, 152, SmallData, 0),
+ (data_obj, 153, SmallData, None),
(data_obj, 160, TextData, """This is a long piece of text.
It contains line breaks.
Several of them.
@@ -188,7 +196,7 @@ The end."""),
(fk_obj, 450, FKDataToField, "UAnchor 1"),
(fk_obj, 451, FKDataToField, "UAnchor 2"),
(fk_obj, 452, FKDataToField, None),
-
+
(data_obj, 500, Anchor, "Anchor 3"),
(data_obj, 501, Anchor, "Anchor 4"),
(data_obj, 502, UniqueAnchor, "UAnchor 2"),
@@ -201,9 +209,12 @@ The end."""),
(pk_obj, 640, EmailPKData, "hovercraft@example.com"),
(pk_obj, 650, FilePKData, 'file:///foo/bar/whiz.txt'),
(pk_obj, 660, FilePathPKData, "/foo/bar/whiz.txt"),
- (pk_obj, 670, FloatPKData, 12.345),
- (pk_obj, 671, FloatPKData, -12.345),
- (pk_obj, 672, FloatPKData, 0.0),
+ (pk_obj, 670, DecimalPKData, decimal.Decimal('12.345')),
+ (pk_obj, 671, DecimalPKData, decimal.Decimal('-12.345')),
+ (pk_obj, 672, DecimalPKData, decimal.Decimal('0.0')),
+ (pk_obj, 673, FloatPKData, 12.345),
+ (pk_obj, 674, FloatPKData, -12.345),
+ (pk_obj, 675, FloatPKData, 0.0),
(pk_obj, 680, IntegerPKData, 123456789),
(pk_obj, 681, IntegerPKData, -123456789),
(pk_obj, 682, IntegerPKData, 0),
@@ -215,9 +226,9 @@ The end."""),
(pk_obj, 720, PositiveIntegerPKData, 123456789),
(pk_obj, 730, PositiveSmallIntegerPKData, 12),
(pk_obj, 740, SlugPKData, "this-is-a-slug"),
- (pk_obj, 750, SmallPKData, 12),
- (pk_obj, 751, SmallPKData, -12),
- (pk_obj, 752, SmallPKData, 0),
+ (pk_obj, 750, SmallPKData, 12),
+ (pk_obj, 751, SmallPKData, -12),
+ (pk_obj, 752, SmallPKData, 0),
# (pk_obj, 760, TextPKData, """This is a long piece of text.
# It contains line breaks.
# Several of them.
@@ -226,7 +237,7 @@ The end."""),
(pk_obj, 780, USStatePKData, "MA"),
# (pk_obj, 790, XMLPKData, "<foo></foo>"),
]
-
+
# Dynamically create serializer tests to ensure that all
# registered serializers are automatically tested.
class SerializerTests(unittest.TestCase):
@@ -234,7 +245,7 @@ class SerializerTests(unittest.TestCase):
def serializerTest(format, self):
# Clear the database first
- management.flush(verbosity=0, interactive=False)
+ management.flush(verbosity=0, interactive=False)
# Create all the objects defined in the test data
objects = []
@@ -245,14 +256,14 @@ def serializerTest(format, self):
transaction.commit()
transaction.leave_transaction_management()
- # Add the generic tagged objects to the object list
+ # Add the generic tagged objects to the object list
objects.extend(Tag.objects.all())
-
+
# Serialize the test database
serialized_data = serializers.serialize(format, objects, indent=2)
# Flush the database and recreate from the serialized data
- management.flush(verbosity=0, interactive=False)
+ management.flush(verbosity=0, interactive=False)
transaction.enter_transaction_management()
transaction.managed(True)
for obj in serializers.deserialize(format, serialized_data):
@@ -260,10 +271,10 @@ def serializerTest(format, self):
transaction.commit()
transaction.leave_transaction_management()
- # Assert that the deserialized data is the same
+ # Assert that the deserialized data is the same
# as the original source
for (func, pk, klass, datum) in test_data:
func[1](self, pk, klass, datum)
-
+
for format in serializers.get_serializer_formats():
setattr(SerializerTests, 'test_'+format+'_serializer', curry(serializerTest, format))