Issue #5788: `datetime.timedelta` objects get a new `total_seconds()` method returning
[python.git] / Lib / test / test_decimal.py
blob69f31a0e54e0890a2f836f4e25d4c5c5642b2a34
1 # Copyright (c) 2004 Python Software Foundation.
2 # All rights reserved.
4 # Written by Eric Price <eprice at tjhsst.edu>
5 # and Facundo Batista <facundo at taniquetil.com.ar>
6 # and Raymond Hettinger <python at rcn.com>
7 # and Aahz (aahz at pobox.com)
8 # and Tim Peters
10 """
11 These are the test cases for the Decimal module.
13 There are two groups of tests, Arithmetic and Behaviour. The former test
14 the Decimal arithmetic using the tests provided by Mike Cowlishaw. The latter
15 test the pythonic behaviour according to PEP 327.
17 Cowlishaw's tests can be downloaded from:
19 www2.hursley.ibm.com/decimal/dectest.zip
21 This test module can be called from command line with one parameter (Arithmetic
22 or Behaviour) to test each part, or without parameter to test both parts. If
23 you're working through IDLE, you can import this test module and call test_main()
24 with the corresponding argument.
25 """
27 import glob
28 import math
29 import os, sys
30 import pickle, copy
31 import unittest
32 from decimal import *
33 import numbers
34 from test.test_support import (run_unittest, run_doctest, is_resource_enabled)
35 import random
36 try:
37 import threading
38 except ImportError:
39 threading = None
41 # Useful Test Constant
42 Signals = getcontext().flags.keys()
44 # Tests are built around these assumed context defaults.
45 # test_main() restores the original context.
46 def init():
47 global ORIGINAL_CONTEXT
48 ORIGINAL_CONTEXT = getcontext().copy()
49 DefaultTestContext = Context(
50 prec = 9,
51 rounding = ROUND_HALF_EVEN,
52 traps = dict.fromkeys(Signals, 0)
54 setcontext(DefaultTestContext)
56 TESTDATADIR = 'decimaltestdata'
57 if __name__ == '__main__':
58 file = sys.argv[0]
59 else:
60 file = __file__
61 testdir = os.path.dirname(file) or os.curdir
62 directory = testdir + os.sep + TESTDATADIR + os.sep
64 skip_expected = not os.path.isdir(directory)
66 # list of individual .decTest test ids that correspond to tests that
67 # we're skipping for one reason or another.
68 skipped_test_ids = [
69 'scbx164', # skipping apparently implementation-specific scaleb
70 'scbx165', # tests, pending clarification of scaleb rules.
73 # Make sure it actually raises errors when not expected and caught in flags
74 # Slower, since it runs some things several times.
75 EXTENDEDERRORTEST = False
77 #Map the test cases' error names to the actual errors
78 ErrorNames = {'clamped' : Clamped,
79 'conversion_syntax' : InvalidOperation,
80 'division_by_zero' : DivisionByZero,
81 'division_impossible' : InvalidOperation,
82 'division_undefined' : InvalidOperation,
83 'inexact' : Inexact,
84 'invalid_context' : InvalidOperation,
85 'invalid_operation' : InvalidOperation,
86 'overflow' : Overflow,
87 'rounded' : Rounded,
88 'subnormal' : Subnormal,
89 'underflow' : Underflow}
92 def Nonfunction(*args):
93 """Doesn't do anything."""
94 return None
96 RoundingDict = {'ceiling' : ROUND_CEILING, #Maps test-case names to roundings.
97 'down' : ROUND_DOWN,
98 'floor' : ROUND_FLOOR,
99 'half_down' : ROUND_HALF_DOWN,
100 'half_even' : ROUND_HALF_EVEN,
101 'half_up' : ROUND_HALF_UP,
102 'up' : ROUND_UP,
103 '05up' : ROUND_05UP}
105 # Name adapter to be able to change the Decimal and Context
106 # interface without changing the test files from Cowlishaw
107 nameAdapter = {'and':'logical_and',
108 'apply':'_apply',
109 'class':'number_class',
110 'comparesig':'compare_signal',
111 'comparetotal':'compare_total',
112 'comparetotmag':'compare_total_mag',
113 'copy':'copy_decimal',
114 'copyabs':'copy_abs',
115 'copynegate':'copy_negate',
116 'copysign':'copy_sign',
117 'divideint':'divide_int',
118 'invert':'logical_invert',
119 'iscanonical':'is_canonical',
120 'isfinite':'is_finite',
121 'isinfinite':'is_infinite',
122 'isnan':'is_nan',
123 'isnormal':'is_normal',
124 'isqnan':'is_qnan',
125 'issigned':'is_signed',
126 'issnan':'is_snan',
127 'issubnormal':'is_subnormal',
128 'iszero':'is_zero',
129 'maxmag':'max_mag',
130 'minmag':'min_mag',
131 'nextminus':'next_minus',
132 'nextplus':'next_plus',
133 'nexttoward':'next_toward',
134 'or':'logical_or',
135 'reduce':'normalize',
136 'remaindernear':'remainder_near',
137 'samequantum':'same_quantum',
138 'squareroot':'sqrt',
139 'toeng':'to_eng_string',
140 'tointegral':'to_integral_value',
141 'tointegralx':'to_integral_exact',
142 'tosci':'to_sci_string',
143 'xor':'logical_xor',
146 # The following functions return True/False rather than a Decimal instance
148 LOGICAL_FUNCTIONS = (
149 'is_canonical',
150 'is_finite',
151 'is_infinite',
152 'is_nan',
153 'is_normal',
154 'is_qnan',
155 'is_signed',
156 'is_snan',
157 'is_subnormal',
158 'is_zero',
159 'same_quantum',
162 # For some operations (currently exp, ln, log10, power), the decNumber
163 # reference implementation imposes additional restrictions on the
164 # context and operands. These restrictions are not part of the
165 # specification; however, the effect of these restrictions does show
166 # up in some of the testcases. We skip testcases that violate these
167 # restrictions, since Decimal behaves differently from decNumber for
168 # these testcases so these testcases would otherwise fail.
170 decNumberRestricted = ('power', 'ln', 'log10', 'exp')
171 DEC_MAX_MATH = 999999
172 def outside_decNumber_bounds(v, context):
173 if (context.prec > DEC_MAX_MATH or
174 context.Emax > DEC_MAX_MATH or
175 -context.Emin > DEC_MAX_MATH):
176 return True
177 if not v._is_special and v and (
178 v.adjusted() > DEC_MAX_MATH or
179 v.adjusted() < 1-2*DEC_MAX_MATH):
180 return True
181 return False
183 class DecimalTest(unittest.TestCase):
184 """Class which tests the Decimal class against the test cases.
186 Changed for unittest.
188 def setUp(self):
189 self.context = Context()
190 self.ignore_list = ['#']
191 # Basically, a # means return NaN InvalidOperation.
192 # Different from a sNaN in trim
194 self.ChangeDict = {'precision' : self.change_precision,
195 'rounding' : self.change_rounding_method,
196 'maxexponent' : self.change_max_exponent,
197 'minexponent' : self.change_min_exponent,
198 'clamp' : self.change_clamp}
200 def eval_file(self, file):
201 global skip_expected
202 if skip_expected:
203 raise unittest.SkipTest
204 return
205 for line in open(file).xreadlines():
206 line = line.replace('\r\n', '').replace('\n', '')
207 #print line
208 try:
209 t = self.eval_line(line)
210 except DecimalException, exception:
211 #Exception raised where there shoudn't have been one.
212 self.fail('Exception "'+exception.__class__.__name__ + '" raised on line '+line)
214 return
216 def eval_line(self, s):
217 if s.find(' -> ') >= 0 and s[:2] != '--' and not s.startswith(' --'):
218 s = (s.split('->')[0] + '->' +
219 s.split('->')[1].split('--')[0]).strip()
220 else:
221 s = s.split('--')[0].strip()
223 for ignore in self.ignore_list:
224 if s.find(ignore) >= 0:
225 #print s.split()[0], 'NotImplemented--', ignore
226 return
227 if not s:
228 return
229 elif ':' in s:
230 return self.eval_directive(s)
231 else:
232 return self.eval_equation(s)
234 def eval_directive(self, s):
235 funct, value = map(lambda x: x.strip().lower(), s.split(':'))
236 if funct == 'rounding':
237 value = RoundingDict[value]
238 else:
239 try:
240 value = int(value)
241 except ValueError:
242 pass
244 funct = self.ChangeDict.get(funct, Nonfunction)
245 funct(value)
247 def eval_equation(self, s):
248 #global DEFAULT_PRECISION
249 #print DEFAULT_PRECISION
251 if not TEST_ALL and random.random() < 0.90:
252 return
254 try:
255 Sides = s.split('->')
256 L = Sides[0].strip().split()
257 id = L[0]
258 if DEBUG:
259 print "Test ", id,
260 funct = L[1].lower()
261 valstemp = L[2:]
262 L = Sides[1].strip().split()
263 ans = L[0]
264 exceptions = L[1:]
265 except (TypeError, AttributeError, IndexError):
266 raise InvalidOperation
267 def FixQuotes(val):
268 val = val.replace("''", 'SingleQuote').replace('""', 'DoubleQuote')
269 val = val.replace("'", '').replace('"', '')
270 val = val.replace('SingleQuote', "'").replace('DoubleQuote', '"')
271 return val
273 if id in skipped_test_ids:
274 return
276 fname = nameAdapter.get(funct, funct)
277 if fname == 'rescale':
278 return
279 funct = getattr(self.context, fname)
280 vals = []
281 conglomerate = ''
282 quote = 0
283 theirexceptions = [ErrorNames[x.lower()] for x in exceptions]
285 for exception in Signals:
286 self.context.traps[exception] = 1 #Catch these bugs...
287 for exception in theirexceptions:
288 self.context.traps[exception] = 0
289 for i, val in enumerate(valstemp):
290 if val.count("'") % 2 == 1:
291 quote = 1 - quote
292 if quote:
293 conglomerate = conglomerate + ' ' + val
294 continue
295 else:
296 val = conglomerate + val
297 conglomerate = ''
298 v = FixQuotes(val)
299 if fname in ('to_sci_string', 'to_eng_string'):
300 if EXTENDEDERRORTEST:
301 for error in theirexceptions:
302 self.context.traps[error] = 1
303 try:
304 funct(self.context.create_decimal(v))
305 except error:
306 pass
307 except Signals, e:
308 self.fail("Raised %s in %s when %s disabled" % \
309 (e, s, error))
310 else:
311 self.fail("Did not raise %s in %s" % (error, s))
312 self.context.traps[error] = 0
313 v = self.context.create_decimal(v)
314 else:
315 v = Decimal(v, self.context)
316 vals.append(v)
318 ans = FixQuotes(ans)
320 # skip tests that are related to bounds imposed in the decNumber
321 # reference implementation
322 if fname in decNumberRestricted:
323 if fname == 'power':
324 if not (vals[1]._isinteger() and
325 -1999999997 <= vals[1] <= 999999999):
326 if outside_decNumber_bounds(vals[0], self.context) or \
327 outside_decNumber_bounds(vals[1], self.context):
328 #print "Skipping test %s" % s
329 return
330 else:
331 if outside_decNumber_bounds(vals[0], self.context):
332 #print "Skipping test %s" % s
333 return
336 if EXTENDEDERRORTEST and fname not in ('to_sci_string', 'to_eng_string'):
337 for error in theirexceptions:
338 self.context.traps[error] = 1
339 try:
340 funct(*vals)
341 except error:
342 pass
343 except Signals, e:
344 self.fail("Raised %s in %s when %s disabled" % \
345 (e, s, error))
346 else:
347 self.fail("Did not raise %s in %s" % (error, s))
348 self.context.traps[error] = 0
349 if DEBUG:
350 print "--", self.context
351 try:
352 result = str(funct(*vals))
353 if fname in LOGICAL_FUNCTIONS:
354 result = str(int(eval(result))) # 'True', 'False' -> '1', '0'
355 except Signals, error:
356 self.fail("Raised %s in %s" % (error, s))
357 except: #Catch any error long enough to state the test case.
358 print "ERROR:", s
359 raise
361 myexceptions = self.getexceptions()
362 self.context.clear_flags()
364 myexceptions.sort()
365 theirexceptions.sort()
367 self.assertEqual(result, ans,
368 'Incorrect answer for ' + s + ' -- got ' + result)
369 self.assertEqual(myexceptions, theirexceptions,
370 'Incorrect flags set in ' + s + ' -- got ' + str(myexceptions))
371 return
373 def getexceptions(self):
374 return [e for e in Signals if self.context.flags[e]]
376 def change_precision(self, prec):
377 self.context.prec = prec
378 def change_rounding_method(self, rounding):
379 self.context.rounding = rounding
380 def change_min_exponent(self, exp):
381 self.context.Emin = exp
382 def change_max_exponent(self, exp):
383 self.context.Emax = exp
384 def change_clamp(self, clamp):
385 self.context._clamp = clamp
389 # The following classes test the behaviour of Decimal according to PEP 327
391 class DecimalExplicitConstructionTest(unittest.TestCase):
392 '''Unit tests for Explicit Construction cases of Decimal.'''
394 def test_explicit_empty(self):
395 self.assertEqual(Decimal(), Decimal("0"))
397 def test_explicit_from_None(self):
398 self.assertRaises(TypeError, Decimal, None)
400 def test_explicit_from_int(self):
402 #positive
403 d = Decimal(45)
404 self.assertEqual(str(d), '45')
406 #very large positive
407 d = Decimal(500000123)
408 self.assertEqual(str(d), '500000123')
410 #negative
411 d = Decimal(-45)
412 self.assertEqual(str(d), '-45')
414 #zero
415 d = Decimal(0)
416 self.assertEqual(str(d), '0')
418 def test_explicit_from_string(self):
420 #empty
421 self.assertEqual(str(Decimal('')), 'NaN')
423 #int
424 self.assertEqual(str(Decimal('45')), '45')
426 #float
427 self.assertEqual(str(Decimal('45.34')), '45.34')
429 #engineer notation
430 self.assertEqual(str(Decimal('45e2')), '4.5E+3')
432 #just not a number
433 self.assertEqual(str(Decimal('ugly')), 'NaN')
435 #leading and trailing whitespace permitted
436 self.assertEqual(str(Decimal('1.3E4 \n')), '1.3E+4')
437 self.assertEqual(str(Decimal(' -7.89')), '-7.89')
439 #unicode strings should be permitted
440 self.assertEqual(str(Decimal(u'0E-017')), '0E-17')
441 self.assertEqual(str(Decimal(u'45')), '45')
442 self.assertEqual(str(Decimal(u'-Inf')), '-Infinity')
443 self.assertEqual(str(Decimal(u'NaN123')), 'NaN123')
445 def test_explicit_from_tuples(self):
447 #zero
448 d = Decimal( (0, (0,), 0) )
449 self.assertEqual(str(d), '0')
451 #int
452 d = Decimal( (1, (4, 5), 0) )
453 self.assertEqual(str(d), '-45')
455 #float
456 d = Decimal( (0, (4, 5, 3, 4), -2) )
457 self.assertEqual(str(d), '45.34')
459 #weird
460 d = Decimal( (1, (4, 3, 4, 9, 1, 3, 5, 3, 4), -25) )
461 self.assertEqual(str(d), '-4.34913534E-17')
463 #wrong number of items
464 self.assertRaises(ValueError, Decimal, (1, (4, 3, 4, 9, 1)) )
466 #bad sign
467 self.assertRaises(ValueError, Decimal, (8, (4, 3, 4, 9, 1), 2) )
468 self.assertRaises(ValueError, Decimal, (0., (4, 3, 4, 9, 1), 2) )
469 self.assertRaises(ValueError, Decimal, (Decimal(1), (4, 3, 4, 9, 1), 2))
471 #bad exp
472 self.assertRaises(ValueError, Decimal, (1, (4, 3, 4, 9, 1), 'wrong!') )
473 self.assertRaises(ValueError, Decimal, (1, (4, 3, 4, 9, 1), 0.) )
474 self.assertRaises(ValueError, Decimal, (1, (4, 3, 4, 9, 1), '1') )
476 #bad coefficients
477 self.assertRaises(ValueError, Decimal, (1, (4, 3, 4, None, 1), 2) )
478 self.assertRaises(ValueError, Decimal, (1, (4, -3, 4, 9, 1), 2) )
479 self.assertRaises(ValueError, Decimal, (1, (4, 10, 4, 9, 1), 2) )
480 self.assertRaises(ValueError, Decimal, (1, (4, 3, 4, 'a', 1), 2) )
482 def test_explicit_from_Decimal(self):
484 #positive
485 d = Decimal(45)
486 e = Decimal(d)
487 self.assertEqual(str(e), '45')
488 self.assertNotEqual(id(d), id(e))
490 #very large positive
491 d = Decimal(500000123)
492 e = Decimal(d)
493 self.assertEqual(str(e), '500000123')
494 self.assertNotEqual(id(d), id(e))
496 #negative
497 d = Decimal(-45)
498 e = Decimal(d)
499 self.assertEqual(str(e), '-45')
500 self.assertNotEqual(id(d), id(e))
502 #zero
503 d = Decimal(0)
504 e = Decimal(d)
505 self.assertEqual(str(e), '0')
506 self.assertNotEqual(id(d), id(e))
508 def test_explicit_context_create_decimal(self):
510 nc = copy.copy(getcontext())
511 nc.prec = 3
513 # empty
514 d = Decimal()
515 self.assertEqual(str(d), '0')
516 d = nc.create_decimal()
517 self.assertEqual(str(d), '0')
519 # from None
520 self.assertRaises(TypeError, nc.create_decimal, None)
522 # from int
523 d = nc.create_decimal(456)
524 self.assertTrue(isinstance(d, Decimal))
525 self.assertEqual(nc.create_decimal(45678),
526 nc.create_decimal('457E+2'))
528 # from string
529 d = Decimal('456789')
530 self.assertEqual(str(d), '456789')
531 d = nc.create_decimal('456789')
532 self.assertEqual(str(d), '4.57E+5')
533 # leading and trailing whitespace should result in a NaN;
534 # spaces are already checked in Cowlishaw's test-suite, so
535 # here we just check that a trailing newline results in a NaN
536 self.assertEqual(str(nc.create_decimal('3.14\n')), 'NaN')
538 # from tuples
539 d = Decimal( (1, (4, 3, 4, 9, 1, 3, 5, 3, 4), -25) )
540 self.assertEqual(str(d), '-4.34913534E-17')
541 d = nc.create_decimal( (1, (4, 3, 4, 9, 1, 3, 5, 3, 4), -25) )
542 self.assertEqual(str(d), '-4.35E-17')
544 # from Decimal
545 prevdec = Decimal(500000123)
546 d = Decimal(prevdec)
547 self.assertEqual(str(d), '500000123')
548 d = nc.create_decimal(prevdec)
549 self.assertEqual(str(d), '5.00E+8')
551 def test_unicode_digits(self):
552 test_values = {
553 u'\uff11': '1',
554 u'\u0660.\u0660\u0663\u0667\u0662e-\u0663' : '0.0000372',
555 u'-nan\u0c68\u0c6a\u0c66\u0c66' : '-NaN2400',
557 for input, expected in test_values.items():
558 self.assertEqual(str(Decimal(input)), expected)
561 class DecimalImplicitConstructionTest(unittest.TestCase):
562 '''Unit tests for Implicit Construction cases of Decimal.'''
564 def test_implicit_from_None(self):
565 self.assertRaises(TypeError, eval, 'Decimal(5) + None', globals())
567 def test_implicit_from_int(self):
568 #normal
569 self.assertEqual(str(Decimal(5) + 45), '50')
570 #exceeding precision
571 self.assertEqual(Decimal(5) + 123456789000, Decimal(123456789000))
573 def test_implicit_from_string(self):
574 self.assertRaises(TypeError, eval, 'Decimal(5) + "3"', globals())
576 def test_implicit_from_float(self):
577 self.assertRaises(TypeError, eval, 'Decimal(5) + 2.2', globals())
579 def test_implicit_from_Decimal(self):
580 self.assertEqual(Decimal(5) + Decimal(45), Decimal(50))
582 def test_rop(self):
583 # Allow other classes to be trained to interact with Decimals
584 class E:
585 def __divmod__(self, other):
586 return 'divmod ' + str(other)
587 def __rdivmod__(self, other):
588 return str(other) + ' rdivmod'
589 def __lt__(self, other):
590 return 'lt ' + str(other)
591 def __gt__(self, other):
592 return 'gt ' + str(other)
593 def __le__(self, other):
594 return 'le ' + str(other)
595 def __ge__(self, other):
596 return 'ge ' + str(other)
597 def __eq__(self, other):
598 return 'eq ' + str(other)
599 def __ne__(self, other):
600 return 'ne ' + str(other)
602 self.assertEqual(divmod(E(), Decimal(10)), 'divmod 10')
603 self.assertEqual(divmod(Decimal(10), E()), '10 rdivmod')
604 self.assertEqual(eval('Decimal(10) < E()'), 'gt 10')
605 self.assertEqual(eval('Decimal(10) > E()'), 'lt 10')
606 self.assertEqual(eval('Decimal(10) <= E()'), 'ge 10')
607 self.assertEqual(eval('Decimal(10) >= E()'), 'le 10')
608 self.assertEqual(eval('Decimal(10) == E()'), 'eq 10')
609 self.assertEqual(eval('Decimal(10) != E()'), 'ne 10')
611 # insert operator methods and then exercise them
612 oplist = [
613 ('+', '__add__', '__radd__'),
614 ('-', '__sub__', '__rsub__'),
615 ('*', '__mul__', '__rmul__'),
616 ('%', '__mod__', '__rmod__'),
617 ('//', '__floordiv__', '__rfloordiv__'),
618 ('**', '__pow__', '__rpow__')
620 if 1/2 == 0:
621 # testing with classic division, so add __div__
622 oplist.append(('/', '__div__', '__rdiv__'))
623 else:
624 # testing with -Qnew, so add __truediv__
625 oplist.append(('/', '__truediv__', '__rtruediv__'))
627 for sym, lop, rop in oplist:
628 setattr(E, lop, lambda self, other: 'str' + lop + str(other))
629 setattr(E, rop, lambda self, other: str(other) + rop + 'str')
630 self.assertEqual(eval('E()' + sym + 'Decimal(10)'),
631 'str' + lop + '10')
632 self.assertEqual(eval('Decimal(10)' + sym + 'E()'),
633 '10' + rop + 'str')
636 class DecimalFormatTest(unittest.TestCase):
637 '''Unit tests for the format function.'''
638 def test_formatting(self):
639 # triples giving a format, a Decimal, and the expected result
640 test_values = [
641 ('e', '0E-15', '0e-15'),
642 ('e', '2.3E-15', '2.3e-15'),
643 ('e', '2.30E+2', '2.30e+2'), # preserve significant zeros
644 ('e', '2.30000E-15', '2.30000e-15'),
645 ('e', '1.23456789123456789e40', '1.23456789123456789e+40'),
646 ('e', '1.5', '1.5e+0'),
647 ('e', '0.15', '1.5e-1'),
648 ('e', '0.015', '1.5e-2'),
649 ('e', '0.0000000000015', '1.5e-12'),
650 ('e', '15.0', '1.50e+1'),
651 ('e', '-15', '-1.5e+1'),
652 ('e', '0', '0e+0'),
653 ('e', '0E1', '0e+1'),
654 ('e', '0.0', '0e-1'),
655 ('e', '0.00', '0e-2'),
656 ('.6e', '0E-15', '0.000000e-9'),
657 ('.6e', '0', '0.000000e+6'),
658 ('.6e', '9.999999', '9.999999e+0'),
659 ('.6e', '9.9999999', '1.000000e+1'),
660 ('.6e', '-1.23e5', '-1.230000e+5'),
661 ('.6e', '1.23456789e-3', '1.234568e-3'),
662 ('f', '0', '0'),
663 ('f', '0.0', '0.0'),
664 ('f', '0E-2', '0.00'),
665 ('f', '0.00E-8', '0.0000000000'),
666 ('f', '0E1', '0'), # loses exponent information
667 ('f', '3.2E1', '32'),
668 ('f', '3.2E2', '320'),
669 ('f', '3.20E2', '320'),
670 ('f', '3.200E2', '320.0'),
671 ('f', '3.2E-6', '0.0000032'),
672 ('.6f', '0E-15', '0.000000'), # all zeros treated equally
673 ('.6f', '0E1', '0.000000'),
674 ('.6f', '0', '0.000000'),
675 ('.0f', '0', '0'), # no decimal point
676 ('.0f', '0e-2', '0'),
677 ('.0f', '3.14159265', '3'),
678 ('.1f', '3.14159265', '3.1'),
679 ('.4f', '3.14159265', '3.1416'),
680 ('.6f', '3.14159265', '3.141593'),
681 ('.7f', '3.14159265', '3.1415926'), # round-half-even!
682 ('.8f', '3.14159265', '3.14159265'),
683 ('.9f', '3.14159265', '3.141592650'),
685 ('g', '0', '0'),
686 ('g', '0.0', '0.0'),
687 ('g', '0E1', '0e+1'),
688 ('G', '0E1', '0E+1'),
689 ('g', '0E-5', '0.00000'),
690 ('g', '0E-6', '0.000000'),
691 ('g', '0E-7', '0e-7'),
692 ('g', '-0E2', '-0e+2'),
693 ('.0g', '3.14159265', '3'), # 0 sig fig -> 1 sig fig
694 ('.1g', '3.14159265', '3'),
695 ('.2g', '3.14159265', '3.1'),
696 ('.5g', '3.14159265', '3.1416'),
697 ('.7g', '3.14159265', '3.141593'),
698 ('.8g', '3.14159265', '3.1415926'), # round-half-even!
699 ('.9g', '3.14159265', '3.14159265'),
700 ('.10g', '3.14159265', '3.14159265'), # don't pad
702 ('%', '0E1', '0%'),
703 ('%', '0E0', '0%'),
704 ('%', '0E-1', '0%'),
705 ('%', '0E-2', '0%'),
706 ('%', '0E-3', '0.0%'),
707 ('%', '0E-4', '0.00%'),
709 ('.3%', '0', '0.000%'), # all zeros treated equally
710 ('.3%', '0E10', '0.000%'),
711 ('.3%', '0E-10', '0.000%'),
712 ('.3%', '2.34', '234.000%'),
713 ('.3%', '1.234567', '123.457%'),
714 ('.0%', '1.23', '123%'),
716 ('e', 'NaN', 'NaN'),
717 ('f', '-NaN123', '-NaN123'),
718 ('+g', 'NaN456', '+NaN456'),
719 ('.3e', 'Inf', 'Infinity'),
720 ('.16f', '-Inf', '-Infinity'),
721 ('.0g', '-sNaN', '-sNaN'),
723 ('', '1.00', '1.00'),
725 # test alignment and padding
726 ('6', '123', ' 123'),
727 ('<6', '123', '123 '),
728 ('>6', '123', ' 123'),
729 ('^6', '123', ' 123 '),
730 ('=+6', '123', '+ 123'),
731 ('#<10', 'NaN', 'NaN#######'),
732 ('#<10', '-4.3', '-4.3######'),
733 ('#<+10', '0.0130', '+0.0130###'),
734 ('#< 10', '0.0130', ' 0.0130###'),
735 ('@>10', '-Inf', '@-Infinity'),
736 ('#>5', '-Inf', '-Infinity'),
737 ('?^5', '123', '?123?'),
738 ('%^6', '123', '%123%%'),
739 (' ^6', '-45.6', '-45.6 '),
740 ('/=10', '-45.6', '-/////45.6'),
741 ('/=+10', '45.6', '+/////45.6'),
742 ('/= 10', '45.6', ' /////45.6'),
744 # thousands separator
745 (',', '1234567', '1,234,567'),
746 (',', '123456', '123,456'),
747 (',', '12345', '12,345'),
748 (',', '1234', '1,234'),
749 (',', '123', '123'),
750 (',', '12', '12'),
751 (',', '1', '1'),
752 (',', '0', '0'),
753 (',', '-1234567', '-1,234,567'),
754 (',', '-123456', '-123,456'),
755 ('7,', '123456', '123,456'),
756 ('8,', '123456', ' 123,456'),
757 ('08,', '123456', '0,123,456'), # special case: extra 0 needed
758 ('+08,', '123456', '+123,456'), # but not if there's a sign
759 (' 08,', '123456', ' 123,456'),
760 ('08,', '-123456', '-123,456'),
761 ('+09,', '123456', '+0,123,456'),
762 # ... with fractional part...
763 ('07,', '1234.56', '1,234.56'),
764 ('08,', '1234.56', '1,234.56'),
765 ('09,', '1234.56', '01,234.56'),
766 ('010,', '1234.56', '001,234.56'),
767 ('011,', '1234.56', '0,001,234.56'),
768 ('012,', '1234.56', '0,001,234.56'),
769 ('08,.1f', '1234.5', '01,234.5'),
770 # no thousands separators in fraction part
771 (',', '1.23456789', '1.23456789'),
772 (',%', '123.456789', '12,345.6789%'),
773 (',e', '123456', '1.23456e+5'),
774 (',E', '123456', '1.23456E+5'),
776 # issue 6850
777 ('a=-7.0', '0.12345', 'aaaa0.1'),
779 for fmt, d, result in test_values:
780 self.assertEqual(format(Decimal(d), fmt), result)
782 def test_n_format(self):
783 try:
784 from locale import CHAR_MAX
785 except ImportError:
786 return
788 # Set up some localeconv-like dictionaries
789 en_US = {
790 'decimal_point' : '.',
791 'grouping' : [3, 3, 0],
792 'thousands_sep': ','
795 fr_FR = {
796 'decimal_point' : ',',
797 'grouping' : [CHAR_MAX],
798 'thousands_sep' : ''
801 ru_RU = {
802 'decimal_point' : ',',
803 'grouping' : [3, 3, 0],
804 'thousands_sep' : ' '
807 crazy = {
808 'decimal_point' : '&',
809 'grouping' : [1, 4, 2, CHAR_MAX],
810 'thousands_sep' : '-'
814 def get_fmt(x, locale, fmt='n'):
815 return Decimal.__format__(Decimal(x), fmt, _localeconv=locale)
817 self.assertEqual(get_fmt(Decimal('12.7'), en_US), '12.7')
818 self.assertEqual(get_fmt(Decimal('12.7'), fr_FR), '12,7')
819 self.assertEqual(get_fmt(Decimal('12.7'), ru_RU), '12,7')
820 self.assertEqual(get_fmt(Decimal('12.7'), crazy), '1-2&7')
822 self.assertEqual(get_fmt(123456789, en_US), '123,456,789')
823 self.assertEqual(get_fmt(123456789, fr_FR), '123456789')
824 self.assertEqual(get_fmt(123456789, ru_RU), '123 456 789')
825 self.assertEqual(get_fmt(1234567890123, crazy), '123456-78-9012-3')
827 self.assertEqual(get_fmt(123456789, en_US, '.6n'), '1.23457e+8')
828 self.assertEqual(get_fmt(123456789, fr_FR, '.6n'), '1,23457e+8')
829 self.assertEqual(get_fmt(123456789, ru_RU, '.6n'), '1,23457e+8')
830 self.assertEqual(get_fmt(123456789, crazy, '.6n'), '1&23457e+8')
832 # zero padding
833 self.assertEqual(get_fmt(1234, fr_FR, '03n'), '1234')
834 self.assertEqual(get_fmt(1234, fr_FR, '04n'), '1234')
835 self.assertEqual(get_fmt(1234, fr_FR, '05n'), '01234')
836 self.assertEqual(get_fmt(1234, fr_FR, '06n'), '001234')
838 self.assertEqual(get_fmt(12345, en_US, '05n'), '12,345')
839 self.assertEqual(get_fmt(12345, en_US, '06n'), '12,345')
840 self.assertEqual(get_fmt(12345, en_US, '07n'), '012,345')
841 self.assertEqual(get_fmt(12345, en_US, '08n'), '0,012,345')
842 self.assertEqual(get_fmt(12345, en_US, '09n'), '0,012,345')
843 self.assertEqual(get_fmt(12345, en_US, '010n'), '00,012,345')
845 self.assertEqual(get_fmt(123456, crazy, '06n'), '1-2345-6')
846 self.assertEqual(get_fmt(123456, crazy, '07n'), '1-2345-6')
847 self.assertEqual(get_fmt(123456, crazy, '08n'), '1-2345-6')
848 self.assertEqual(get_fmt(123456, crazy, '09n'), '01-2345-6')
849 self.assertEqual(get_fmt(123456, crazy, '010n'), '0-01-2345-6')
850 self.assertEqual(get_fmt(123456, crazy, '011n'), '0-01-2345-6')
851 self.assertEqual(get_fmt(123456, crazy, '012n'), '00-01-2345-6')
852 self.assertEqual(get_fmt(123456, crazy, '013n'), '000-01-2345-6')
855 class DecimalArithmeticOperatorsTest(unittest.TestCase):
856 '''Unit tests for all arithmetic operators, binary and unary.'''
858 def test_addition(self):
860 d1 = Decimal('-11.1')
861 d2 = Decimal('22.2')
863 #two Decimals
864 self.assertEqual(d1+d2, Decimal('11.1'))
865 self.assertEqual(d2+d1, Decimal('11.1'))
867 #with other type, left
868 c = d1 + 5
869 self.assertEqual(c, Decimal('-6.1'))
870 self.assertEqual(type(c), type(d1))
872 #with other type, right
873 c = 5 + d1
874 self.assertEqual(c, Decimal('-6.1'))
875 self.assertEqual(type(c), type(d1))
877 #inline with decimal
878 d1 += d2
879 self.assertEqual(d1, Decimal('11.1'))
881 #inline with other type
882 d1 += 5
883 self.assertEqual(d1, Decimal('16.1'))
885 def test_subtraction(self):
887 d1 = Decimal('-11.1')
888 d2 = Decimal('22.2')
890 #two Decimals
891 self.assertEqual(d1-d2, Decimal('-33.3'))
892 self.assertEqual(d2-d1, Decimal('33.3'))
894 #with other type, left
895 c = d1 - 5
896 self.assertEqual(c, Decimal('-16.1'))
897 self.assertEqual(type(c), type(d1))
899 #with other type, right
900 c = 5 - d1
901 self.assertEqual(c, Decimal('16.1'))
902 self.assertEqual(type(c), type(d1))
904 #inline with decimal
905 d1 -= d2
906 self.assertEqual(d1, Decimal('-33.3'))
908 #inline with other type
909 d1 -= 5
910 self.assertEqual(d1, Decimal('-38.3'))
912 def test_multiplication(self):
914 d1 = Decimal('-5')
915 d2 = Decimal('3')
917 #two Decimals
918 self.assertEqual(d1*d2, Decimal('-15'))
919 self.assertEqual(d2*d1, Decimal('-15'))
921 #with other type, left
922 c = d1 * 5
923 self.assertEqual(c, Decimal('-25'))
924 self.assertEqual(type(c), type(d1))
926 #with other type, right
927 c = 5 * d1
928 self.assertEqual(c, Decimal('-25'))
929 self.assertEqual(type(c), type(d1))
931 #inline with decimal
932 d1 *= d2
933 self.assertEqual(d1, Decimal('-15'))
935 #inline with other type
936 d1 *= 5
937 self.assertEqual(d1, Decimal('-75'))
939 def test_division(self):
941 d1 = Decimal('-5')
942 d2 = Decimal('2')
944 #two Decimals
945 self.assertEqual(d1/d2, Decimal('-2.5'))
946 self.assertEqual(d2/d1, Decimal('-0.4'))
948 #with other type, left
949 c = d1 / 4
950 self.assertEqual(c, Decimal('-1.25'))
951 self.assertEqual(type(c), type(d1))
953 #with other type, right
954 c = 4 / d1
955 self.assertEqual(c, Decimal('-0.8'))
956 self.assertEqual(type(c), type(d1))
958 #inline with decimal
959 d1 /= d2
960 self.assertEqual(d1, Decimal('-2.5'))
962 #inline with other type
963 d1 /= 4
964 self.assertEqual(d1, Decimal('-0.625'))
966 def test_floor_division(self):
968 d1 = Decimal('5')
969 d2 = Decimal('2')
971 #two Decimals
972 self.assertEqual(d1//d2, Decimal('2'))
973 self.assertEqual(d2//d1, Decimal('0'))
975 #with other type, left
976 c = d1 // 4
977 self.assertEqual(c, Decimal('1'))
978 self.assertEqual(type(c), type(d1))
980 #with other type, right
981 c = 7 // d1
982 self.assertEqual(c, Decimal('1'))
983 self.assertEqual(type(c), type(d1))
985 #inline with decimal
986 d1 //= d2
987 self.assertEqual(d1, Decimal('2'))
989 #inline with other type
990 d1 //= 2
991 self.assertEqual(d1, Decimal('1'))
993 def test_powering(self):
995 d1 = Decimal('5')
996 d2 = Decimal('2')
998 #two Decimals
999 self.assertEqual(d1**d2, Decimal('25'))
1000 self.assertEqual(d2**d1, Decimal('32'))
1002 #with other type, left
1003 c = d1 ** 4
1004 self.assertEqual(c, Decimal('625'))
1005 self.assertEqual(type(c), type(d1))
1007 #with other type, right
1008 c = 7 ** d1
1009 self.assertEqual(c, Decimal('16807'))
1010 self.assertEqual(type(c), type(d1))
1012 #inline with decimal
1013 d1 **= d2
1014 self.assertEqual(d1, Decimal('25'))
1016 #inline with other type
1017 d1 **= 4
1018 self.assertEqual(d1, Decimal('390625'))
1020 def test_module(self):
1022 d1 = Decimal('5')
1023 d2 = Decimal('2')
1025 #two Decimals
1026 self.assertEqual(d1%d2, Decimal('1'))
1027 self.assertEqual(d2%d1, Decimal('2'))
1029 #with other type, left
1030 c = d1 % 4
1031 self.assertEqual(c, Decimal('1'))
1032 self.assertEqual(type(c), type(d1))
1034 #with other type, right
1035 c = 7 % d1
1036 self.assertEqual(c, Decimal('2'))
1037 self.assertEqual(type(c), type(d1))
1039 #inline with decimal
1040 d1 %= d2
1041 self.assertEqual(d1, Decimal('1'))
1043 #inline with other type
1044 d1 %= 4
1045 self.assertEqual(d1, Decimal('1'))
1047 def test_floor_div_module(self):
1049 d1 = Decimal('5')
1050 d2 = Decimal('2')
1052 #two Decimals
1053 (p, q) = divmod(d1, d2)
1054 self.assertEqual(p, Decimal('2'))
1055 self.assertEqual(q, Decimal('1'))
1056 self.assertEqual(type(p), type(d1))
1057 self.assertEqual(type(q), type(d1))
1059 #with other type, left
1060 (p, q) = divmod(d1, 4)
1061 self.assertEqual(p, Decimal('1'))
1062 self.assertEqual(q, Decimal('1'))
1063 self.assertEqual(type(p), type(d1))
1064 self.assertEqual(type(q), type(d1))
1066 #with other type, right
1067 (p, q) = divmod(7, d1)
1068 self.assertEqual(p, Decimal('1'))
1069 self.assertEqual(q, Decimal('2'))
1070 self.assertEqual(type(p), type(d1))
1071 self.assertEqual(type(q), type(d1))
1073 def test_unary_operators(self):
1074 self.assertEqual(+Decimal(45), Decimal(+45)) # +
1075 self.assertEqual(-Decimal(45), Decimal(-45)) # -
1076 self.assertEqual(abs(Decimal(45)), abs(Decimal(-45))) # abs
1078 def test_nan_comparisons(self):
1079 n = Decimal('NaN')
1080 s = Decimal('sNaN')
1081 i = Decimal('Inf')
1082 f = Decimal('2')
1083 for x, y in [(n, n), (n, i), (i, n), (n, f), (f, n),
1084 (s, n), (n, s), (s, i), (i, s), (s, f), (f, s), (s, s)]:
1085 self.assertTrue(x != y)
1086 self.assertTrue(not (x == y))
1087 self.assertTrue(not (x < y))
1088 self.assertTrue(not (x <= y))
1089 self.assertTrue(not (x > y))
1090 self.assertTrue(not (x >= y))
1092 # The following are two functions used to test threading in the next class
1094 def thfunc1(cls):
1095 d1 = Decimal(1)
1096 d3 = Decimal(3)
1097 test1 = d1/d3
1098 cls.synchro.wait()
1099 test2 = d1/d3
1100 cls.finish1.set()
1102 cls.assertEqual(test1, Decimal('0.3333333333333333333333333333'))
1103 cls.assertEqual(test2, Decimal('0.3333333333333333333333333333'))
1104 return
1106 def thfunc2(cls):
1107 d1 = Decimal(1)
1108 d3 = Decimal(3)
1109 test1 = d1/d3
1110 thiscontext = getcontext()
1111 thiscontext.prec = 18
1112 test2 = d1/d3
1113 cls.synchro.set()
1114 cls.finish2.set()
1116 cls.assertEqual(test1, Decimal('0.3333333333333333333333333333'))
1117 cls.assertEqual(test2, Decimal('0.333333333333333333'))
1118 return
1121 class DecimalUseOfContextTest(unittest.TestCase):
1122 '''Unit tests for Use of Context cases in Decimal.'''
1124 try:
1125 import threading
1126 except ImportError:
1127 threading = None
1129 # Take care executing this test from IDLE, there's an issue in threading
1130 # that hangs IDLE and I couldn't find it
1132 def test_threading(self):
1133 #Test the "threading isolation" of a Context.
1135 self.synchro = threading.Event()
1136 self.finish1 = threading.Event()
1137 self.finish2 = threading.Event()
1139 th1 = threading.Thread(target=thfunc1, args=(self,))
1140 th2 = threading.Thread(target=thfunc2, args=(self,))
1142 th1.start()
1143 th2.start()
1145 self.finish1.wait()
1146 self.finish2.wait()
1147 return
1149 if threading is None:
1150 del test_threading
1153 class DecimalUsabilityTest(unittest.TestCase):
1154 '''Unit tests for Usability cases of Decimal.'''
1156 def test_comparison_operators(self):
1158 da = Decimal('23.42')
1159 db = Decimal('23.42')
1160 dc = Decimal('45')
1162 #two Decimals
1163 self.assertTrue(dc > da)
1164 self.assertTrue(dc >= da)
1165 self.assertTrue(da < dc)
1166 self.assertTrue(da <= dc)
1167 self.assertTrue(da == db)
1168 self.assertTrue(da != dc)
1169 self.assertTrue(da <= db)
1170 self.assertTrue(da >= db)
1171 self.assertEqual(cmp(dc,da), 1)
1172 self.assertEqual(cmp(da,dc), -1)
1173 self.assertEqual(cmp(da,db), 0)
1175 #a Decimal and an int
1176 self.assertTrue(dc > 23)
1177 self.assertTrue(23 < dc)
1178 self.assertTrue(dc == 45)
1179 self.assertEqual(cmp(dc,23), 1)
1180 self.assertEqual(cmp(23,dc), -1)
1181 self.assertEqual(cmp(dc,45), 0)
1183 #a Decimal and uncomparable
1184 self.assertNotEqual(da, 'ugly')
1185 self.assertNotEqual(da, 32.7)
1186 self.assertNotEqual(da, object())
1187 self.assertNotEqual(da, object)
1189 # sortable
1190 a = map(Decimal, xrange(100))
1191 b = a[:]
1192 random.shuffle(a)
1193 a.sort()
1194 self.assertEqual(a, b)
1196 # with None
1197 self.assertFalse(Decimal(1) < None)
1198 self.assertTrue(Decimal(1) > None)
1200 def test_copy_and_deepcopy_methods(self):
1201 d = Decimal('43.24')
1202 c = copy.copy(d)
1203 self.assertEqual(id(c), id(d))
1204 dc = copy.deepcopy(d)
1205 self.assertEqual(id(dc), id(d))
1207 def test_hash_method(self):
1208 #just that it's hashable
1209 hash(Decimal(23))
1211 test_values = [Decimal(sign*(2**m + n))
1212 for m in [0, 14, 15, 16, 17, 30, 31,
1213 32, 33, 62, 63, 64, 65, 66]
1214 for n in range(-10, 10)
1215 for sign in [-1, 1]]
1216 test_values.extend([
1217 Decimal("-0"), # zeros
1218 Decimal("0.00"),
1219 Decimal("-0.000"),
1220 Decimal("0E10"),
1221 Decimal("-0E12"),
1222 Decimal("10.0"), # negative exponent
1223 Decimal("-23.00000"),
1224 Decimal("1230E100"), # positive exponent
1225 Decimal("-4.5678E50"),
1226 # a value for which hash(n) != hash(n % (2**64-1))
1227 # in Python pre-2.6
1228 Decimal(2**64 + 2**32 - 1),
1229 # selection of values which fail with the old (before
1230 # version 2.6) long.__hash__
1231 Decimal("1.634E100"),
1232 Decimal("90.697E100"),
1233 Decimal("188.83E100"),
1234 Decimal("1652.9E100"),
1235 Decimal("56531E100"),
1238 # check that hash(d) == hash(int(d)) for integral values
1239 for value in test_values:
1240 self.assertEqual(hash(value), hash(int(value)))
1242 #the same hash that to an int
1243 self.assertEqual(hash(Decimal(23)), hash(23))
1244 self.assertRaises(TypeError, hash, Decimal('NaN'))
1245 self.assertTrue(hash(Decimal('Inf')))
1246 self.assertTrue(hash(Decimal('-Inf')))
1248 # check that the value of the hash doesn't depend on the
1249 # current context (issue #1757)
1250 c = getcontext()
1251 old_precision = c.prec
1252 x = Decimal("123456789.1")
1254 c.prec = 6
1255 h1 = hash(x)
1256 c.prec = 10
1257 h2 = hash(x)
1258 c.prec = 16
1259 h3 = hash(x)
1261 self.assertEqual(h1, h2)
1262 self.assertEqual(h1, h3)
1263 c.prec = old_precision
1265 def test_min_and_max_methods(self):
1267 d1 = Decimal('15.32')
1268 d2 = Decimal('28.5')
1269 l1 = 15
1270 l2 = 28
1272 #between Decimals
1273 self.assertTrue(min(d1,d2) is d1)
1274 self.assertTrue(min(d2,d1) is d1)
1275 self.assertTrue(max(d1,d2) is d2)
1276 self.assertTrue(max(d2,d1) is d2)
1278 #between Decimal and long
1279 self.assertTrue(min(d1,l2) is d1)
1280 self.assertTrue(min(l2,d1) is d1)
1281 self.assertTrue(max(l1,d2) is d2)
1282 self.assertTrue(max(d2,l1) is d2)
1284 def test_as_nonzero(self):
1285 #as false
1286 self.assertFalse(Decimal(0))
1287 #as true
1288 self.assertTrue(Decimal('0.372'))
1290 def test_tostring_methods(self):
1291 #Test str and repr methods.
1293 d = Decimal('15.32')
1294 self.assertEqual(str(d), '15.32') # str
1295 self.assertEqual(repr(d), "Decimal('15.32')") # repr
1297 # result type of string methods should be str, not unicode
1298 unicode_inputs = [u'123.4', u'0.5E2', u'Infinity', u'sNaN',
1299 u'-0.0E100', u'-NaN001', u'-Inf']
1301 for u in unicode_inputs:
1302 d = Decimal(u)
1303 self.assertEqual(type(str(d)), str)
1304 self.assertEqual(type(repr(d)), str)
1305 self.assertEqual(type(d.to_eng_string()), str)
1307 def test_tonum_methods(self):
1308 #Test float, int and long methods.
1310 d1 = Decimal('66')
1311 d2 = Decimal('15.32')
1313 #int
1314 self.assertEqual(int(d1), 66)
1315 self.assertEqual(int(d2), 15)
1317 #long
1318 self.assertEqual(long(d1), 66)
1319 self.assertEqual(long(d2), 15)
1321 #float
1322 self.assertEqual(float(d1), 66)
1323 self.assertEqual(float(d2), 15.32)
1325 def test_eval_round_trip(self):
1327 #with zero
1328 d = Decimal( (0, (0,), 0) )
1329 self.assertEqual(d, eval(repr(d)))
1331 #int
1332 d = Decimal( (1, (4, 5), 0) )
1333 self.assertEqual(d, eval(repr(d)))
1335 #float
1336 d = Decimal( (0, (4, 5, 3, 4), -2) )
1337 self.assertEqual(d, eval(repr(d)))
1339 #weird
1340 d = Decimal( (1, (4, 3, 4, 9, 1, 3, 5, 3, 4), -25) )
1341 self.assertEqual(d, eval(repr(d)))
1343 def test_as_tuple(self):
1345 #with zero
1346 d = Decimal(0)
1347 self.assertEqual(d.as_tuple(), (0, (0,), 0) )
1349 #int
1350 d = Decimal(-45)
1351 self.assertEqual(d.as_tuple(), (1, (4, 5), 0) )
1353 #complicated string
1354 d = Decimal("-4.34913534E-17")
1355 self.assertEqual(d.as_tuple(), (1, (4, 3, 4, 9, 1, 3, 5, 3, 4), -25) )
1357 #inf
1358 d = Decimal("Infinity")
1359 self.assertEqual(d.as_tuple(), (0, (0,), 'F') )
1361 #leading zeros in coefficient should be stripped
1362 d = Decimal( (0, (0, 0, 4, 0, 5, 3, 4), -2) )
1363 self.assertEqual(d.as_tuple(), (0, (4, 0, 5, 3, 4), -2) )
1364 d = Decimal( (1, (0, 0, 0), 37) )
1365 self.assertEqual(d.as_tuple(), (1, (0,), 37))
1366 d = Decimal( (1, (), 37) )
1367 self.assertEqual(d.as_tuple(), (1, (0,), 37))
1369 #leading zeros in NaN diagnostic info should be stripped
1370 d = Decimal( (0, (0, 0, 4, 0, 5, 3, 4), 'n') )
1371 self.assertEqual(d.as_tuple(), (0, (4, 0, 5, 3, 4), 'n') )
1372 d = Decimal( (1, (0, 0, 0), 'N') )
1373 self.assertEqual(d.as_tuple(), (1, (), 'N') )
1374 d = Decimal( (1, (), 'n') )
1375 self.assertEqual(d.as_tuple(), (1, (), 'n') )
1377 #coefficient in infinity should be ignored
1378 d = Decimal( (0, (4, 5, 3, 4), 'F') )
1379 self.assertEqual(d.as_tuple(), (0, (0,), 'F'))
1380 d = Decimal( (1, (0, 2, 7, 1), 'F') )
1381 self.assertEqual(d.as_tuple(), (1, (0,), 'F'))
1383 def test_immutability_operations(self):
1384 # Do operations and check that it didn't change change internal objects.
1386 d1 = Decimal('-25e55')
1387 b1 = Decimal('-25e55')
1388 d2 = Decimal('33e+33')
1389 b2 = Decimal('33e+33')
1391 def checkSameDec(operation, useOther=False):
1392 if useOther:
1393 eval("d1." + operation + "(d2)")
1394 self.assertEqual(d1._sign, b1._sign)
1395 self.assertEqual(d1._int, b1._int)
1396 self.assertEqual(d1._exp, b1._exp)
1397 self.assertEqual(d2._sign, b2._sign)
1398 self.assertEqual(d2._int, b2._int)
1399 self.assertEqual(d2._exp, b2._exp)
1400 else:
1401 eval("d1." + operation + "()")
1402 self.assertEqual(d1._sign, b1._sign)
1403 self.assertEqual(d1._int, b1._int)
1404 self.assertEqual(d1._exp, b1._exp)
1405 return
1407 Decimal(d1)
1408 self.assertEqual(d1._sign, b1._sign)
1409 self.assertEqual(d1._int, b1._int)
1410 self.assertEqual(d1._exp, b1._exp)
1412 checkSameDec("__abs__")
1413 checkSameDec("__add__", True)
1414 checkSameDec("__div__", True)
1415 checkSameDec("__divmod__", True)
1416 checkSameDec("__eq__", True)
1417 checkSameDec("__ne__", True)
1418 checkSameDec("__le__", True)
1419 checkSameDec("__lt__", True)
1420 checkSameDec("__ge__", True)
1421 checkSameDec("__gt__", True)
1422 checkSameDec("__float__")
1423 checkSameDec("__floordiv__", True)
1424 checkSameDec("__hash__")
1425 checkSameDec("__int__")
1426 checkSameDec("__trunc__")
1427 checkSameDec("__long__")
1428 checkSameDec("__mod__", True)
1429 checkSameDec("__mul__", True)
1430 checkSameDec("__neg__")
1431 checkSameDec("__nonzero__")
1432 checkSameDec("__pos__")
1433 checkSameDec("__pow__", True)
1434 checkSameDec("__radd__", True)
1435 checkSameDec("__rdiv__", True)
1436 checkSameDec("__rdivmod__", True)
1437 checkSameDec("__repr__")
1438 checkSameDec("__rfloordiv__", True)
1439 checkSameDec("__rmod__", True)
1440 checkSameDec("__rmul__", True)
1441 checkSameDec("__rpow__", True)
1442 checkSameDec("__rsub__", True)
1443 checkSameDec("__str__")
1444 checkSameDec("__sub__", True)
1445 checkSameDec("__truediv__", True)
1446 checkSameDec("adjusted")
1447 checkSameDec("as_tuple")
1448 checkSameDec("compare", True)
1449 checkSameDec("max", True)
1450 checkSameDec("min", True)
1451 checkSameDec("normalize")
1452 checkSameDec("quantize", True)
1453 checkSameDec("remainder_near", True)
1454 checkSameDec("same_quantum", True)
1455 checkSameDec("sqrt")
1456 checkSameDec("to_eng_string")
1457 checkSameDec("to_integral")
1459 def test_subclassing(self):
1460 # Different behaviours when subclassing Decimal
1462 class MyDecimal(Decimal):
1463 pass
1465 d1 = MyDecimal(1)
1466 d2 = MyDecimal(2)
1467 d = d1 + d2
1468 self.assertTrue(type(d) is Decimal)
1470 d = d1.max(d2)
1471 self.assertTrue(type(d) is Decimal)
1473 def test_implicit_context(self):
1474 # Check results when context given implicitly. (Issue 2478)
1475 c = getcontext()
1476 self.assertEqual(str(Decimal(0).sqrt()),
1477 str(c.sqrt(Decimal(0))))
1479 def test_conversions_from_int(self):
1480 # Check that methods taking a second Decimal argument will
1481 # always accept an integer in place of a Decimal.
1482 self.assertEqual(Decimal(4).compare(3),
1483 Decimal(4).compare(Decimal(3)))
1484 self.assertEqual(Decimal(4).compare_signal(3),
1485 Decimal(4).compare_signal(Decimal(3)))
1486 self.assertEqual(Decimal(4).compare_total(3),
1487 Decimal(4).compare_total(Decimal(3)))
1488 self.assertEqual(Decimal(4).compare_total_mag(3),
1489 Decimal(4).compare_total_mag(Decimal(3)))
1490 self.assertEqual(Decimal(10101).logical_and(1001),
1491 Decimal(10101).logical_and(Decimal(1001)))
1492 self.assertEqual(Decimal(10101).logical_or(1001),
1493 Decimal(10101).logical_or(Decimal(1001)))
1494 self.assertEqual(Decimal(10101).logical_xor(1001),
1495 Decimal(10101).logical_xor(Decimal(1001)))
1496 self.assertEqual(Decimal(567).max(123),
1497 Decimal(567).max(Decimal(123)))
1498 self.assertEqual(Decimal(567).max_mag(123),
1499 Decimal(567).max_mag(Decimal(123)))
1500 self.assertEqual(Decimal(567).min(123),
1501 Decimal(567).min(Decimal(123)))
1502 self.assertEqual(Decimal(567).min_mag(123),
1503 Decimal(567).min_mag(Decimal(123)))
1504 self.assertEqual(Decimal(567).next_toward(123),
1505 Decimal(567).next_toward(Decimal(123)))
1506 self.assertEqual(Decimal(1234).quantize(100),
1507 Decimal(1234).quantize(Decimal(100)))
1508 self.assertEqual(Decimal(768).remainder_near(1234),
1509 Decimal(768).remainder_near(Decimal(1234)))
1510 self.assertEqual(Decimal(123).rotate(1),
1511 Decimal(123).rotate(Decimal(1)))
1512 self.assertEqual(Decimal(1234).same_quantum(1000),
1513 Decimal(1234).same_quantum(Decimal(1000)))
1514 self.assertEqual(Decimal('9.123').scaleb(-100),
1515 Decimal('9.123').scaleb(Decimal(-100)))
1516 self.assertEqual(Decimal(456).shift(-1),
1517 Decimal(456).shift(Decimal(-1)))
1519 self.assertEqual(Decimal(-12).fma(Decimal(45), 67),
1520 Decimal(-12).fma(Decimal(45), Decimal(67)))
1521 self.assertEqual(Decimal(-12).fma(45, 67),
1522 Decimal(-12).fma(Decimal(45), Decimal(67)))
1523 self.assertEqual(Decimal(-12).fma(45, Decimal(67)),
1524 Decimal(-12).fma(Decimal(45), Decimal(67)))
1527 class DecimalPythonAPItests(unittest.TestCase):
1529 def test_abc(self):
1530 self.assertTrue(issubclass(Decimal, numbers.Number))
1531 self.assertTrue(not issubclass(Decimal, numbers.Real))
1532 self.assertTrue(isinstance(Decimal(0), numbers.Number))
1533 self.assertTrue(not isinstance(Decimal(0), numbers.Real))
1535 def test_pickle(self):
1536 d = Decimal('-3.141590000')
1537 p = pickle.dumps(d)
1538 e = pickle.loads(p)
1539 self.assertEqual(d, e)
1541 def test_int(self):
1542 for x in range(-250, 250):
1543 s = '%0.2f' % (x / 100.0)
1544 # should work the same as for floats
1545 self.assertEqual(int(Decimal(s)), int(float(s)))
1546 # should work the same as to_integral in the ROUND_DOWN mode
1547 d = Decimal(s)
1548 r = d.to_integral(ROUND_DOWN)
1549 self.assertEqual(Decimal(int(d)), r)
1551 self.assertRaises(ValueError, int, Decimal('-nan'))
1552 self.assertRaises(ValueError, int, Decimal('snan'))
1553 self.assertRaises(OverflowError, int, Decimal('inf'))
1554 self.assertRaises(OverflowError, int, Decimal('-inf'))
1556 self.assertRaises(ValueError, long, Decimal('-nan'))
1557 self.assertRaises(ValueError, long, Decimal('snan'))
1558 self.assertRaises(OverflowError, long, Decimal('inf'))
1559 self.assertRaises(OverflowError, long, Decimal('-inf'))
1561 def test_trunc(self):
1562 for x in range(-250, 250):
1563 s = '%0.2f' % (x / 100.0)
1564 # should work the same as for floats
1565 self.assertEqual(int(Decimal(s)), int(float(s)))
1566 # should work the same as to_integral in the ROUND_DOWN mode
1567 d = Decimal(s)
1568 r = d.to_integral(ROUND_DOWN)
1569 self.assertEqual(Decimal(math.trunc(d)), r)
1571 def test_from_float(self):
1573 class MyDecimal(Decimal):
1574 pass
1576 r = MyDecimal.from_float(0.1)
1577 self.assertEqual(type(r), MyDecimal)
1578 self.assertEqual(str(r),
1579 '0.1000000000000000055511151231257827021181583404541015625')
1580 bigint = 12345678901234567890123456789
1581 self.assertEqual(MyDecimal.from_float(bigint), MyDecimal(bigint))
1582 self.assertTrue(MyDecimal.from_float(float('nan')).is_qnan())
1583 self.assertTrue(MyDecimal.from_float(float('inf')).is_infinite())
1584 self.assertTrue(MyDecimal.from_float(float('-inf')).is_infinite())
1585 self.assertEqual(str(MyDecimal.from_float(float('nan'))),
1586 str(Decimal('NaN')))
1587 self.assertEqual(str(MyDecimal.from_float(float('inf'))),
1588 str(Decimal('Infinity')))
1589 self.assertEqual(str(MyDecimal.from_float(float('-inf'))),
1590 str(Decimal('-Infinity')))
1591 self.assertRaises(TypeError, MyDecimal.from_float, 'abc')
1592 for i in range(200):
1593 x = random.expovariate(0.01) * (random.random() * 2.0 - 1.0)
1594 self.assertEqual(x, float(MyDecimal.from_float(x))) # roundtrip
1596 def test_create_decimal_from_float(self):
1597 context = Context(prec=5, rounding=ROUND_DOWN)
1598 self.assertEqual(
1599 context.create_decimal_from_float(math.pi),
1600 Decimal('3.1415')
1602 context = Context(prec=5, rounding=ROUND_UP)
1603 self.assertEqual(
1604 context.create_decimal_from_float(math.pi),
1605 Decimal('3.1416')
1607 context = Context(prec=5, traps=[Inexact])
1608 self.assertRaises(
1609 Inexact,
1610 context.create_decimal_from_float,
1611 math.pi
1613 self.assertEqual(repr(context.create_decimal_from_float(-0.0)),
1614 "Decimal('-0')")
1615 self.assertEqual(repr(context.create_decimal_from_float(1.0)),
1616 "Decimal('1')")
1617 self.assertEqual(repr(context.create_decimal_from_float(10)),
1618 "Decimal('10')")
1620 class ContextAPItests(unittest.TestCase):
1622 def test_pickle(self):
1623 c = Context()
1624 e = pickle.loads(pickle.dumps(c))
1625 for k in vars(c):
1626 v1 = vars(c)[k]
1627 v2 = vars(e)[k]
1628 self.assertEqual(v1, v2)
1630 def test_equality_with_other_types(self):
1631 self.assertTrue(Decimal(10) in ['a', 1.0, Decimal(10), (1,2), {}])
1632 self.assertTrue(Decimal(10) not in ['a', 1.0, (1,2), {}])
1634 def test_copy(self):
1635 # All copies should be deep
1636 c = Context()
1637 d = c.copy()
1638 self.assertNotEqual(id(c), id(d))
1639 self.assertNotEqual(id(c.flags), id(d.flags))
1640 self.assertNotEqual(id(c.traps), id(d.traps))
1642 class WithStatementTest(unittest.TestCase):
1643 # Can't do these as docstrings until Python 2.6
1644 # as doctest can't handle __future__ statements
1646 def test_localcontext(self):
1647 # Use a copy of the current context in the block
1648 orig_ctx = getcontext()
1649 with localcontext() as enter_ctx:
1650 set_ctx = getcontext()
1651 final_ctx = getcontext()
1652 self.assertTrue(orig_ctx is final_ctx, 'did not restore context correctly')
1653 self.assertTrue(orig_ctx is not set_ctx, 'did not copy the context')
1654 self.assertTrue(set_ctx is enter_ctx, '__enter__ returned wrong context')
1656 def test_localcontextarg(self):
1657 # Use a copy of the supplied context in the block
1658 orig_ctx = getcontext()
1659 new_ctx = Context(prec=42)
1660 with localcontext(new_ctx) as enter_ctx:
1661 set_ctx = getcontext()
1662 final_ctx = getcontext()
1663 self.assertTrue(orig_ctx is final_ctx, 'did not restore context correctly')
1664 self.assertTrue(set_ctx.prec == new_ctx.prec, 'did not set correct context')
1665 self.assertTrue(new_ctx is not set_ctx, 'did not copy the context')
1666 self.assertTrue(set_ctx is enter_ctx, '__enter__ returned wrong context')
1668 class ContextFlags(unittest.TestCase):
1669 def test_flags_irrelevant(self):
1670 # check that the result (numeric result + flags raised) of an
1671 # arithmetic operation doesn't depend on the current flags
1673 context = Context(prec=9, Emin = -999999999, Emax = 999999999,
1674 rounding=ROUND_HALF_EVEN, traps=[], flags=[])
1676 # operations that raise various flags, in the form (function, arglist)
1677 operations = [
1678 (context._apply, [Decimal("100E-1000000009")]),
1679 (context.sqrt, [Decimal(2)]),
1680 (context.add, [Decimal("1.23456789"), Decimal("9.87654321")]),
1681 (context.multiply, [Decimal("1.23456789"), Decimal("9.87654321")]),
1682 (context.subtract, [Decimal("1.23456789"), Decimal("9.87654321")]),
1685 # try various flags individually, then a whole lot at once
1686 flagsets = [[Inexact], [Rounded], [Underflow], [Clamped], [Subnormal],
1687 [Inexact, Rounded, Underflow, Clamped, Subnormal]]
1689 for fn, args in operations:
1690 # find answer and flags raised using a clean context
1691 context.clear_flags()
1692 ans = fn(*args)
1693 flags = [k for k, v in context.flags.items() if v]
1695 for extra_flags in flagsets:
1696 # set flags, before calling operation
1697 context.clear_flags()
1698 for flag in extra_flags:
1699 context._raise_error(flag)
1700 new_ans = fn(*args)
1702 # flags that we expect to be set after the operation
1703 expected_flags = list(flags)
1704 for flag in extra_flags:
1705 if flag not in expected_flags:
1706 expected_flags.append(flag)
1707 expected_flags.sort()
1709 # flags we actually got
1710 new_flags = [k for k,v in context.flags.items() if v]
1711 new_flags.sort()
1713 self.assertEqual(ans, new_ans,
1714 "operation produces different answers depending on flags set: " +
1715 "expected %s, got %s." % (ans, new_ans))
1716 self.assertEqual(new_flags, expected_flags,
1717 "operation raises different flags depending on flags set: " +
1718 "expected %s, got %s" % (expected_flags, new_flags))
1720 def test_main(arith=False, verbose=None, todo_tests=None, debug=None):
1721 """ Execute the tests.
1723 Runs all arithmetic tests if arith is True or if the "decimal" resource
1724 is enabled in regrtest.py
1727 init()
1728 global TEST_ALL, DEBUG
1729 TEST_ALL = arith or is_resource_enabled('decimal')
1730 DEBUG = debug
1732 if todo_tests is None:
1733 test_classes = [
1734 DecimalExplicitConstructionTest,
1735 DecimalImplicitConstructionTest,
1736 DecimalArithmeticOperatorsTest,
1737 DecimalFormatTest,
1738 DecimalUseOfContextTest,
1739 DecimalUsabilityTest,
1740 DecimalPythonAPItests,
1741 ContextAPItests,
1742 DecimalTest,
1743 WithStatementTest,
1744 ContextFlags
1746 else:
1747 test_classes = [DecimalTest]
1749 # Dynamically build custom test definition for each file in the test
1750 # directory and add the definitions to the DecimalTest class. This
1751 # procedure insures that new files do not get skipped.
1752 for filename in os.listdir(directory):
1753 if '.decTest' not in filename or filename.startswith("."):
1754 continue
1755 head, tail = filename.split('.')
1756 if todo_tests is not None and head not in todo_tests:
1757 continue
1758 tester = lambda self, f=filename: self.eval_file(directory + f)
1759 setattr(DecimalTest, 'test_' + head, tester)
1760 del filename, head, tail, tester
1763 try:
1764 run_unittest(*test_classes)
1765 if todo_tests is None:
1766 import decimal as DecimalModule
1767 run_doctest(DecimalModule, verbose)
1768 finally:
1769 setcontext(ORIGINAL_CONTEXT)
1771 if __name__ == '__main__':
1772 import optparse
1773 p = optparse.OptionParser("test_decimal.py [--debug] [{--skip | test1 [test2 [...]]}]")
1774 p.add_option('--debug', '-d', action='store_true', help='shows the test number and context before each test')
1775 p.add_option('--skip', '-s', action='store_true', help='skip over 90% of the arithmetic tests')
1776 (opt, args) = p.parse_args()
1778 if opt.skip:
1779 test_main(arith=False, verbose=True)
1780 elif args:
1781 test_main(arith=True, verbose=True, todo_tests=args, debug=opt.debug)
1782 else:
1783 test_main(arith=True, verbose=True)