test_floatfield.py 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113
  1. from django.core.exceptions import ValidationError
  2. from django.forms import FloatField, NumberInput
  3. from django.test import SimpleTestCase
  4. from django.test.utils import ignore_warnings, override_settings
  5. from django.utils import formats, translation
  6. from django.utils.deprecation import RemovedInDjango50Warning
  7. from . import FormFieldAssertionsMixin
  8. class FloatFieldTest(FormFieldAssertionsMixin, SimpleTestCase):
  9. def test_floatfield_1(self):
  10. f = FloatField()
  11. self.assertWidgetRendersTo(f, '<input step="any" type="number" name="f" id="id_f" required>')
  12. with self.assertRaisesMessage(ValidationError, "'This field is required.'"):
  13. f.clean('')
  14. with self.assertRaisesMessage(ValidationError, "'This field is required.'"):
  15. f.clean(None)
  16. self.assertEqual(1.0, f.clean('1'))
  17. self.assertIsInstance(f.clean('1'), float)
  18. self.assertEqual(23.0, f.clean('23'))
  19. self.assertEqual(3.1400000000000001, f.clean('3.14'))
  20. self.assertEqual(3.1400000000000001, f.clean(3.14))
  21. self.assertEqual(42.0, f.clean(42))
  22. with self.assertRaisesMessage(ValidationError, "'Enter a number.'"):
  23. f.clean('a')
  24. self.assertEqual(1.0, f.clean('1.0 '))
  25. self.assertEqual(1.0, f.clean(' 1.0'))
  26. self.assertEqual(1.0, f.clean(' 1.0 '))
  27. with self.assertRaisesMessage(ValidationError, "'Enter a number.'"):
  28. f.clean('1.0a')
  29. self.assertIsNone(f.max_value)
  30. self.assertIsNone(f.min_value)
  31. with self.assertRaisesMessage(ValidationError, "'Enter a number.'"):
  32. f.clean('Infinity')
  33. with self.assertRaisesMessage(ValidationError, "'Enter a number.'"):
  34. f.clean('NaN')
  35. with self.assertRaisesMessage(ValidationError, "'Enter a number.'"):
  36. f.clean('-Inf')
  37. def test_floatfield_2(self):
  38. f = FloatField(required=False)
  39. self.assertIsNone(f.clean(''))
  40. self.assertIsNone(f.clean(None))
  41. self.assertEqual(1.0, f.clean('1'))
  42. self.assertIsNone(f.max_value)
  43. self.assertIsNone(f.min_value)
  44. def test_floatfield_3(self):
  45. f = FloatField(max_value=1.5, min_value=0.5)
  46. self.assertWidgetRendersTo(
  47. f,
  48. '<input step="any" name="f" min="0.5" max="1.5" type="number" id="id_f" required>',
  49. )
  50. with self.assertRaisesMessage(ValidationError, "'Ensure this value is less than or equal to 1.5.'"):
  51. f.clean('1.6')
  52. with self.assertRaisesMessage(ValidationError, "'Ensure this value is greater than or equal to 0.5.'"):
  53. f.clean('0.4')
  54. self.assertEqual(1.5, f.clean('1.5'))
  55. self.assertEqual(0.5, f.clean('0.5'))
  56. self.assertEqual(f.max_value, 1.5)
  57. self.assertEqual(f.min_value, 0.5)
  58. def test_floatfield_widget_attrs(self):
  59. f = FloatField(widget=NumberInput(attrs={'step': 0.01, 'max': 1.0, 'min': 0.0}))
  60. self.assertWidgetRendersTo(
  61. f,
  62. '<input step="0.01" name="f" min="0.0" max="1.0" type="number" id="id_f" required>',
  63. )
  64. def test_floatfield_localized(self):
  65. """
  66. A localized FloatField's widget renders to a text input without any
  67. number input specific attributes.
  68. """
  69. f = FloatField(localize=True)
  70. self.assertWidgetRendersTo(f, '<input id="id_f" name="f" type="text" required>')
  71. def test_floatfield_changed(self):
  72. f = FloatField()
  73. n = 4.35
  74. self.assertFalse(f.has_changed(n, '4.3500'))
  75. with translation.override('fr'):
  76. f = FloatField(localize=True)
  77. localized_n = formats.localize_input(n) # -> '4,35' in French
  78. self.assertFalse(f.has_changed(n, localized_n))
  79. # RemovedInDjango50Warning: When the deprecation ends, remove
  80. # @ignore_warnings and USE_L10N=False. The test should remain because
  81. # format-related settings will take precedence over locale-dictated
  82. # formats.
  83. @ignore_warnings(category=RemovedInDjango50Warning)
  84. @override_settings(USE_L10N=False, DECIMAL_SEPARATOR=',')
  85. def test_decimalfield_support_decimal_separator(self):
  86. f = FloatField(localize=True)
  87. self.assertEqual(f.clean('1001,10'), 1001.10)
  88. self.assertEqual(f.clean('1001.10'), 1001.10)
  89. # RemovedInDjango50Warning: When the deprecation ends, remove
  90. # @ignore_warnings and USE_L10N=False. The test should remain because
  91. # format-related settings will take precedence over locale-dictated
  92. # formats.
  93. @ignore_warnings(category=RemovedInDjango50Warning)
  94. @override_settings(USE_L10N=False, DECIMAL_SEPARATOR=',', USE_THOUSAND_SEPARATOR=True,
  95. THOUSAND_SEPARATOR='.')
  96. def test_decimalfield_support_thousands_separator(self):
  97. f = FloatField(localize=True)
  98. self.assertEqual(f.clean('1.001,10'), 1001.10)
  99. msg = "'Enter a number.'"
  100. with self.assertRaisesMessage(ValidationError, msg):
  101. f.clean('1,001.1')