2014-11-30 16:29:52 +08:00
|
|
|
from decimal import Decimal
|
|
|
|
from sys import float_info
|
|
|
|
|
2018-07-20 04:44:40 +08:00
|
|
|
from django.test import SimpleTestCase
|
2012-09-09 00:29:29 +08:00
|
|
|
from django.utils.numberformat import format as nformat
|
|
|
|
|
|
|
|
|
2018-07-20 04:44:40 +08:00
|
|
|
class TestNumberFormat(SimpleTestCase):
|
2012-09-09 00:29:29 +08:00
|
|
|
|
|
|
|
def test_format_number(self):
|
|
|
|
self.assertEqual(nformat(1234, '.'), '1234')
|
|
|
|
self.assertEqual(nformat(1234.2, '.'), '1234.2')
|
|
|
|
self.assertEqual(nformat(1234, '.', decimal_pos=2), '1234.00')
|
2016-01-29 23:36:58 +08:00
|
|
|
self.assertEqual(nformat(1234, '.', grouping=2, thousand_sep=','), '1234')
|
|
|
|
self.assertEqual(nformat(1234, '.', grouping=2, thousand_sep=',', force_grouping=True), '12,34')
|
2012-09-09 00:29:29 +08:00
|
|
|
self.assertEqual(nformat(-1234.33, '.', decimal_pos=1), '-1234.3')
|
2018-07-20 04:44:40 +08:00
|
|
|
# The use_l10n parameter can force thousand grouping behavior.
|
2021-09-09 13:42:05 +08:00
|
|
|
with self.settings(USE_THOUSAND_SEPARATOR=True):
|
2018-07-20 04:44:40 +08:00
|
|
|
self.assertEqual(nformat(1234, '.', grouping=3, thousand_sep=',', use_l10n=False), '1234')
|
|
|
|
self.assertEqual(nformat(1234, '.', grouping=3, thousand_sep=',', use_l10n=True), '1,234')
|
2012-09-09 00:29:29 +08:00
|
|
|
|
|
|
|
def test_format_string(self):
|
|
|
|
self.assertEqual(nformat('1234', '.'), '1234')
|
|
|
|
self.assertEqual(nformat('1234.2', '.'), '1234.2')
|
|
|
|
self.assertEqual(nformat('1234', '.', decimal_pos=2), '1234.00')
|
2016-01-29 23:36:58 +08:00
|
|
|
self.assertEqual(nformat('1234', '.', grouping=2, thousand_sep=','), '1234')
|
|
|
|
self.assertEqual(nformat('1234', '.', grouping=2, thousand_sep=',', force_grouping=True), '12,34')
|
2012-09-09 00:29:29 +08:00
|
|
|
self.assertEqual(nformat('-1234.33', '.', decimal_pos=1), '-1234.3')
|
2016-01-29 23:36:58 +08:00
|
|
|
self.assertEqual(nformat('10000', '.', grouping=3, thousand_sep='comma', force_grouping=True), '10comma000')
|
2012-09-09 00:29:29 +08:00
|
|
|
|
|
|
|
def test_large_number(self):
|
2016-01-29 23:36:58 +08:00
|
|
|
most_max = (
|
|
|
|
'{}179769313486231570814527423731704356798070567525844996'
|
|
|
|
'598917476803157260780028538760589558632766878171540458953'
|
|
|
|
'514382464234321326889464182768467546703537516986049910576'
|
|
|
|
'551282076245490090389328944075868508455133942304583236903'
|
|
|
|
'222948165808559332123348274797826204144723168738177180919'
|
|
|
|
'29988125040402618412485836{}'
|
|
|
|
)
|
|
|
|
most_max2 = (
|
|
|
|
'{}35953862697246314162905484746340871359614113505168999'
|
|
|
|
'31978349536063145215600570775211791172655337563430809179'
|
|
|
|
'07028764928468642653778928365536935093407075033972099821'
|
|
|
|
'15310256415249098018077865788815173701691026788460916647'
|
|
|
|
'38064458963316171186642466965495956524082894463374763543'
|
|
|
|
'61838599762500808052368249716736'
|
|
|
|
)
|
2012-09-09 00:29:29 +08:00
|
|
|
int_max = int(float_info.max)
|
|
|
|
self.assertEqual(nformat(int_max, '.'), most_max.format('', '8'))
|
|
|
|
self.assertEqual(nformat(int_max + 1, '.'), most_max.format('', '9'))
|
|
|
|
self.assertEqual(nformat(int_max * 2, '.'), most_max2.format(''))
|
|
|
|
self.assertEqual(nformat(0 - int_max, '.'), most_max.format('-', '8'))
|
|
|
|
self.assertEqual(nformat(-1 - int_max, '.'), most_max.format('-', '9'))
|
|
|
|
self.assertEqual(nformat(-2 * int_max, '.'), most_max2.format('-'))
|
2014-11-30 16:29:52 +08:00
|
|
|
|
2017-06-13 22:48:53 +08:00
|
|
|
def test_float_numbers(self):
|
2020-02-23 21:37:02 +08:00
|
|
|
tests = [
|
|
|
|
(9e-10, 10, '0.0000000009'),
|
|
|
|
(9e-19, 2, '0.00'),
|
|
|
|
(.00000000000099, 0, '0'),
|
|
|
|
(.00000000000099, 13, '0.0000000000009'),
|
|
|
|
(1e16, None, '10000000000000000'),
|
|
|
|
(1e16, 2, '10000000000000000.00'),
|
|
|
|
# A float without a fractional part (3.) results in a ".0" when no
|
|
|
|
# decimal_pos is given. Contrast that with the Decimal('3.') case
|
|
|
|
# in test_decimal_numbers which doesn't return a fractional part.
|
|
|
|
(3., None, '3.0'),
|
|
|
|
]
|
|
|
|
for value, decimal_pos, expected_value in tests:
|
|
|
|
with self.subTest(value=value, decimal_pos=decimal_pos):
|
|
|
|
self.assertEqual(nformat(value, '.', decimal_pos), expected_value)
|
|
|
|
# Thousand grouping behavior.
|
|
|
|
self.assertEqual(
|
|
|
|
nformat(1e16, '.', thousand_sep=',', grouping=3, force_grouping=True),
|
|
|
|
'10,000,000,000,000,000',
|
|
|
|
)
|
|
|
|
self.assertEqual(
|
|
|
|
nformat(1e16, '.', decimal_pos=2, thousand_sep=',', grouping=3, force_grouping=True),
|
|
|
|
'10,000,000,000,000,000.00',
|
|
|
|
)
|
2017-06-13 22:48:53 +08:00
|
|
|
|
2014-11-30 16:29:52 +08:00
|
|
|
def test_decimal_numbers(self):
|
|
|
|
self.assertEqual(nformat(Decimal('1234'), '.'), '1234')
|
|
|
|
self.assertEqual(nformat(Decimal('1234.2'), '.'), '1234.2')
|
|
|
|
self.assertEqual(nformat(Decimal('1234'), '.', decimal_pos=2), '1234.00')
|
|
|
|
self.assertEqual(nformat(Decimal('1234'), '.', grouping=2, thousand_sep=','), '1234')
|
|
|
|
self.assertEqual(nformat(Decimal('1234'), '.', grouping=2, thousand_sep=',', force_grouping=True), '12,34')
|
|
|
|
self.assertEqual(nformat(Decimal('-1234.33'), '.', decimal_pos=1), '-1234.3')
|
|
|
|
self.assertEqual(nformat(Decimal('0.00000001'), '.', decimal_pos=8), '0.00000001')
|
2017-06-13 22:48:53 +08:00
|
|
|
self.assertEqual(nformat(Decimal('9e-19'), '.', decimal_pos=2), '0.00')
|
|
|
|
self.assertEqual(nformat(Decimal('.00000000000099'), '.', decimal_pos=0), '0')
|
|
|
|
self.assertEqual(
|
|
|
|
nformat(Decimal('1e16'), '.', thousand_sep=',', grouping=3, force_grouping=True),
|
|
|
|
'10,000,000,000,000,000'
|
|
|
|
)
|
|
|
|
self.assertEqual(
|
|
|
|
nformat(Decimal('1e16'), '.', decimal_pos=2, thousand_sep=',', grouping=3, force_grouping=True),
|
|
|
|
'10,000,000,000,000,000.00'
|
|
|
|
)
|
|
|
|
self.assertEqual(nformat(Decimal('3.'), '.'), '3')
|
|
|
|
self.assertEqual(nformat(Decimal('3.0'), '.'), '3.0')
|
2019-02-11 18:08:45 +08:00
|
|
|
# Very large & small numbers.
|
|
|
|
tests = [
|
|
|
|
('9e9999', None, '9e+9999'),
|
|
|
|
('9e9999', 3, '9.000e+9999'),
|
|
|
|
('9e201', None, '9e+201'),
|
|
|
|
('9e200', None, '9e+200'),
|
|
|
|
('1.2345e999', 2, '1.23e+999'),
|
|
|
|
('9e-999', None, '9e-999'),
|
|
|
|
('1e-7', 8, '0.00000010'),
|
|
|
|
('1e-8', 8, '0.00000001'),
|
|
|
|
('1e-9', 8, '0.00000000'),
|
|
|
|
('1e-10', 8, '0.00000000'),
|
|
|
|
('1e-11', 8, '0.00000000'),
|
|
|
|
('1' + ('0' * 300), 3, '1.000e+300'),
|
2019-04-13 18:11:34 +08:00
|
|
|
('0.{}1234'.format('0' * 299), 3, '0.000'),
|
2019-02-11 18:08:45 +08:00
|
|
|
]
|
|
|
|
for value, decimal_pos, expected_value in tests:
|
|
|
|
with self.subTest(value=value):
|
|
|
|
self.assertEqual(nformat(Decimal(value), '.', decimal_pos), expected_value)
|
2015-03-10 00:56:13 +08:00
|
|
|
|
|
|
|
def test_decimal_subclass(self):
|
|
|
|
class EuroDecimal(Decimal):
|
|
|
|
"""
|
|
|
|
Wrapper for Decimal which prefixes each amount with the € symbol.
|
|
|
|
"""
|
|
|
|
def __format__(self, specifier, **kwargs):
|
2017-01-21 21:13:44 +08:00
|
|
|
amount = super().__format__(specifier, **kwargs)
|
2015-03-10 00:56:13 +08:00
|
|
|
return '€ {}'.format(amount)
|
|
|
|
|
|
|
|
price = EuroDecimal('1.23')
|
|
|
|
self.assertEqual(nformat(price, ','), '€ 1,23')
|