Exceptions raised during renaming in rotating file handlers are now passed to handleE...
[python.git] / Lib / test / test_decimal.py
blob34f034b850bc3c8262c945329c4a62168da1db46
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 unittest
28 import glob
29 import os, sys
30 import pickle, copy
31 from decimal import *
32 from test.test_support import TestSkipped, run_unittest, run_doctest, is_resource_enabled
33 import random
34 try:
35 import threading
36 except ImportError:
37 threading = None
39 # Useful Test Constant
40 Signals = getcontext().flags.keys()
42 # Tests are built around these assumed context defaults
43 DefaultContext.prec=9
44 DefaultContext.rounding=ROUND_HALF_EVEN
45 DefaultContext.traps=dict.fromkeys(Signals, 0)
46 setcontext(DefaultContext)
49 TESTDATADIR = 'decimaltestdata'
50 if __name__ == '__main__':
51 file = sys.argv[0]
52 else:
53 file = __file__
54 testdir = os.path.dirname(file) or os.curdir
55 directory = testdir + os.sep + TESTDATADIR + os.sep
57 skip_expected = not os.path.isdir(directory)
59 # Make sure it actually raises errors when not expected and caught in flags
60 # Slower, since it runs some things several times.
61 EXTENDEDERRORTEST = False
64 #Map the test cases' error names to the actual errors
66 ErrorNames = {'clamped' : Clamped,
67 'conversion_syntax' : InvalidOperation,
68 'division_by_zero' : DivisionByZero,
69 'division_impossible' : InvalidOperation,
70 'division_undefined' : InvalidOperation,
71 'inexact' : Inexact,
72 'invalid_context' : InvalidOperation,
73 'invalid_operation' : InvalidOperation,
74 'overflow' : Overflow,
75 'rounded' : Rounded,
76 'subnormal' : Subnormal,
77 'underflow' : Underflow}
80 def Nonfunction(*args):
81 """Doesn't do anything."""
82 return None
84 RoundingDict = {'ceiling' : ROUND_CEILING, #Maps test-case names to roundings.
85 'down' : ROUND_DOWN,
86 'floor' : ROUND_FLOOR,
87 'half_down' : ROUND_HALF_DOWN,
88 'half_even' : ROUND_HALF_EVEN,
89 'half_up' : ROUND_HALF_UP,
90 'up' : ROUND_UP}
92 # Name adapter to be able to change the Decimal and Context
93 # interface without changing the test files from Cowlishaw
94 nameAdapter = {'toeng':'to_eng_string',
95 'tosci':'to_sci_string',
96 'samequantum':'same_quantum',
97 'tointegral':'to_integral',
98 'remaindernear':'remainder_near',
99 'divideint':'divide_int',
100 'squareroot':'sqrt',
101 'apply':'_apply',
104 class DecimalTest(unittest.TestCase):
105 """Class which tests the Decimal class against the test cases.
107 Changed for unittest.
109 def setUp(self):
110 self.context = Context()
111 for key in DefaultContext.traps.keys():
112 DefaultContext.traps[key] = 1
113 self.ignore_list = ['#']
114 # Basically, a # means return NaN InvalidOperation.
115 # Different from a sNaN in trim
117 self.ChangeDict = {'precision' : self.change_precision,
118 'rounding' : self.change_rounding_method,
119 'maxexponent' : self.change_max_exponent,
120 'minexponent' : self.change_min_exponent,
121 'clamp' : self.change_clamp}
123 def tearDown(self):
124 """Cleaning up enviroment."""
125 # leaving context in original state
126 for key in DefaultContext.traps.keys():
127 DefaultContext.traps[key] = 0
128 return
130 def eval_file(self, file):
131 global skip_expected
132 if skip_expected:
133 raise TestSkipped
134 return
135 for line in open(file).xreadlines():
136 line = line.replace('\r\n', '').replace('\n', '')
137 #print line
138 try:
139 t = self.eval_line(line)
140 except InvalidOperation:
141 print 'Error in test cases:'
142 print line
143 continue
144 except DecimalException, exception:
145 #Exception raised where there shoudn't have been one.
146 self.fail('Exception "'+exception.__class__.__name__ + '" raised on line '+line)
148 return
150 def eval_line(self, s):
151 if s.find(' -> ') >= 0 and s[:2] != '--' and not s.startswith(' --'):
152 s = (s.split('->')[0] + '->' +
153 s.split('->')[1].split('--')[0]).strip()
154 else:
155 s = s.split('--')[0].strip()
157 for ignore in self.ignore_list:
158 if s.find(ignore) >= 0:
159 #print s.split()[0], 'NotImplemented--', ignore
160 return
161 if not s:
162 return
163 elif ':' in s:
164 return self.eval_directive(s)
165 else:
166 return self.eval_equation(s)
168 def eval_directive(self, s):
169 funct, value = map(lambda x: x.strip().lower(), s.split(':'))
170 if funct == 'rounding':
171 value = RoundingDict[value]
172 else:
173 try:
174 value = int(value)
175 except ValueError:
176 pass
178 funct = self.ChangeDict.get(funct, Nonfunction)
179 funct(value)
181 def eval_equation(self, s):
182 #global DEFAULT_PRECISION
183 #print DEFAULT_PRECISION
185 if not TEST_ALL and random.random() < 0.90:
186 return
188 try:
189 Sides = s.split('->')
190 L = Sides[0].strip().split()
191 id = L[0]
192 # print id,
193 funct = L[1].lower()
194 valstemp = L[2:]
195 L = Sides[1].strip().split()
196 ans = L[0]
197 exceptions = L[1:]
198 except (TypeError, AttributeError, IndexError):
199 raise InvalidOperation
200 def FixQuotes(val):
201 val = val.replace("''", 'SingleQuote').replace('""', 'DoubleQuote')
202 val = val.replace("'", '').replace('"', '')
203 val = val.replace('SingleQuote', "'").replace('DoubleQuote', '"')
204 return val
205 fname = nameAdapter.get(funct, funct)
206 if fname == 'rescale':
207 return
208 funct = getattr(self.context, fname)
209 vals = []
210 conglomerate = ''
211 quote = 0
212 theirexceptions = [ErrorNames[x.lower()] for x in exceptions]
214 for exception in Signals:
215 self.context.traps[exception] = 1 #Catch these bugs...
216 for exception in theirexceptions:
217 self.context.traps[exception] = 0
218 for i, val in enumerate(valstemp):
219 if val.count("'") % 2 == 1:
220 quote = 1 - quote
221 if quote:
222 conglomerate = conglomerate + ' ' + val
223 continue
224 else:
225 val = conglomerate + val
226 conglomerate = ''
227 v = FixQuotes(val)
228 if fname in ('to_sci_string', 'to_eng_string'):
229 if EXTENDEDERRORTEST:
230 for error in theirexceptions:
231 self.context.traps[error] = 1
232 try:
233 funct(self.context.create_decimal(v))
234 except error:
235 pass
236 except Signals, e:
237 self.fail("Raised %s in %s when %s disabled" % \
238 (e, s, error))
239 else:
240 self.fail("Did not raise %s in %s" % (error, s))
241 self.context.traps[error] = 0
242 v = self.context.create_decimal(v)
243 else:
244 v = Decimal(v)
245 vals.append(v)
247 ans = FixQuotes(ans)
249 if EXTENDEDERRORTEST and fname not in ('to_sci_string', 'to_eng_string'):
250 for error in theirexceptions:
251 self.context.traps[error] = 1
252 try:
253 funct(*vals)
254 except error:
255 pass
256 except Signals, e:
257 self.fail("Raised %s in %s when %s disabled" % \
258 (e, s, error))
259 else:
260 self.fail("Did not raise %s in %s" % (error, s))
261 self.context.traps[error] = 0
262 try:
263 result = str(funct(*vals))
264 if fname == 'same_quantum':
265 result = str(int(eval(result))) # 'True', 'False' -> '1', '0'
266 except Signals, error:
267 self.fail("Raised %s in %s" % (error, s))
268 except: #Catch any error long enough to state the test case.
269 print "ERROR:", s
270 raise
272 myexceptions = self.getexceptions()
273 self.context.clear_flags()
275 myexceptions.sort()
276 theirexceptions.sort()
278 self.assertEqual(result, ans,
279 'Incorrect answer for ' + s + ' -- got ' + result)
280 self.assertEqual(myexceptions, theirexceptions,
281 'Incorrect flags set in ' + s + ' -- got ' \
282 + str(myexceptions))
283 return
285 def getexceptions(self):
286 return [e for e in Signals if self.context.flags[e]]
288 def change_precision(self, prec):
289 self.context.prec = prec
290 def change_rounding_method(self, rounding):
291 self.context.rounding = rounding
292 def change_min_exponent(self, exp):
293 self.context.Emin = exp
294 def change_max_exponent(self, exp):
295 self.context.Emax = exp
296 def change_clamp(self, clamp):
297 self.context._clamp = clamp
299 # Dynamically build custom test definition for each file in the test
300 # directory and add the definitions to the DecimalTest class. This
301 # procedure insures that new files do not get skipped.
302 for filename in os.listdir(directory):
303 if '.decTest' not in filename:
304 continue
305 head, tail = filename.split('.')
306 tester = lambda self, f=filename: self.eval_file(directory + f)
307 setattr(DecimalTest, 'test_' + head, tester)
308 del filename, head, tail, tester
312 # The following classes test the behaviour of Decimal according to PEP 327
314 class DecimalExplicitConstructionTest(unittest.TestCase):
315 '''Unit tests for Explicit Construction cases of Decimal.'''
317 def test_explicit_empty(self):
318 self.assertEqual(Decimal(), Decimal("0"))
320 def test_explicit_from_None(self):
321 self.assertRaises(TypeError, Decimal, None)
323 def test_explicit_from_int(self):
325 #positive
326 d = Decimal(45)
327 self.assertEqual(str(d), '45')
329 #very large positive
330 d = Decimal(500000123)
331 self.assertEqual(str(d), '500000123')
333 #negative
334 d = Decimal(-45)
335 self.assertEqual(str(d), '-45')
337 #zero
338 d = Decimal(0)
339 self.assertEqual(str(d), '0')
341 def test_explicit_from_string(self):
343 #empty
344 self.assertEqual(str(Decimal('')), 'NaN')
346 #int
347 self.assertEqual(str(Decimal('45')), '45')
349 #float
350 self.assertEqual(str(Decimal('45.34')), '45.34')
352 #engineer notation
353 self.assertEqual(str(Decimal('45e2')), '4.5E+3')
355 #just not a number
356 self.assertEqual(str(Decimal('ugly')), 'NaN')
358 def test_explicit_from_tuples(self):
360 #zero
361 d = Decimal( (0, (0,), 0) )
362 self.assertEqual(str(d), '0')
364 #int
365 d = Decimal( (1, (4, 5), 0) )
366 self.assertEqual(str(d), '-45')
368 #float
369 d = Decimal( (0, (4, 5, 3, 4), -2) )
370 self.assertEqual(str(d), '45.34')
372 #weird
373 d = Decimal( (1, (4, 3, 4, 9, 1, 3, 5, 3, 4), -25) )
374 self.assertEqual(str(d), '-4.34913534E-17')
376 #wrong number of items
377 self.assertRaises(ValueError, Decimal, (1, (4, 3, 4, 9, 1)) )
379 #bad sign
380 self.assertRaises(ValueError, Decimal, (8, (4, 3, 4, 9, 1), 2) )
382 #bad exp
383 self.assertRaises(ValueError, Decimal, (1, (4, 3, 4, 9, 1), 'wrong!') )
385 #bad coefficients
386 self.assertRaises(ValueError, Decimal, (1, (4, 3, 4, None, 1), 2) )
387 self.assertRaises(ValueError, Decimal, (1, (4, -3, 4, 9, 1), 2) )
389 def test_explicit_from_Decimal(self):
391 #positive
392 d = Decimal(45)
393 e = Decimal(d)
394 self.assertEqual(str(e), '45')
395 self.assertNotEqual(id(d), id(e))
397 #very large positive
398 d = Decimal(500000123)
399 e = Decimal(d)
400 self.assertEqual(str(e), '500000123')
401 self.assertNotEqual(id(d), id(e))
403 #negative
404 d = Decimal(-45)
405 e = Decimal(d)
406 self.assertEqual(str(e), '-45')
407 self.assertNotEqual(id(d), id(e))
409 #zero
410 d = Decimal(0)
411 e = Decimal(d)
412 self.assertEqual(str(e), '0')
413 self.assertNotEqual(id(d), id(e))
415 def test_explicit_context_create_decimal(self):
417 nc = copy.copy(getcontext())
418 nc.prec = 3
420 # empty
421 d = Decimal()
422 self.assertEqual(str(d), '0')
423 d = nc.create_decimal()
424 self.assertEqual(str(d), '0')
426 # from None
427 self.assertRaises(TypeError, nc.create_decimal, None)
429 # from int
430 d = nc.create_decimal(456)
431 self.failUnless(isinstance(d, Decimal))
432 self.assertEqual(nc.create_decimal(45678),
433 nc.create_decimal('457E+2'))
435 # from string
436 d = Decimal('456789')
437 self.assertEqual(str(d), '456789')
438 d = nc.create_decimal('456789')
439 self.assertEqual(str(d), '4.57E+5')
441 # from tuples
442 d = Decimal( (1, (4, 3, 4, 9, 1, 3, 5, 3, 4), -25) )
443 self.assertEqual(str(d), '-4.34913534E-17')
444 d = nc.create_decimal( (1, (4, 3, 4, 9, 1, 3, 5, 3, 4), -25) )
445 self.assertEqual(str(d), '-4.35E-17')
447 # from Decimal
448 prevdec = Decimal(500000123)
449 d = Decimal(prevdec)
450 self.assertEqual(str(d), '500000123')
451 d = nc.create_decimal(prevdec)
452 self.assertEqual(str(d), '5.00E+8')
455 class DecimalImplicitConstructionTest(unittest.TestCase):
456 '''Unit tests for Implicit Construction cases of Decimal.'''
458 def test_implicit_from_None(self):
459 self.assertRaises(TypeError, eval, 'Decimal(5) + None', globals())
461 def test_implicit_from_int(self):
462 #normal
463 self.assertEqual(str(Decimal(5) + 45), '50')
464 #exceeding precision
465 self.assertEqual(Decimal(5) + 123456789000, Decimal(123456789000))
467 def test_implicit_from_string(self):
468 self.assertRaises(TypeError, eval, 'Decimal(5) + "3"', globals())
470 def test_implicit_from_float(self):
471 self.assertRaises(TypeError, eval, 'Decimal(5) + 2.2', globals())
473 def test_implicit_from_Decimal(self):
474 self.assertEqual(Decimal(5) + Decimal(45), Decimal(50))
476 def test_rop(self):
477 # Allow other classes to be trained to interact with Decimals
478 class E:
479 def __divmod__(self, other):
480 return 'divmod ' + str(other)
481 def __rdivmod__(self, other):
482 return str(other) + ' rdivmod'
483 def __lt__(self, other):
484 return 'lt ' + str(other)
485 def __gt__(self, other):
486 return 'gt ' + str(other)
487 def __le__(self, other):
488 return 'le ' + str(other)
489 def __ge__(self, other):
490 return 'ge ' + str(other)
491 def __eq__(self, other):
492 return 'eq ' + str(other)
493 def __ne__(self, other):
494 return 'ne ' + str(other)
496 self.assertEqual(divmod(E(), Decimal(10)), 'divmod 10')
497 self.assertEqual(divmod(Decimal(10), E()), '10 rdivmod')
498 self.assertEqual(eval('Decimal(10) < E()'), 'gt 10')
499 self.assertEqual(eval('Decimal(10) > E()'), 'lt 10')
500 self.assertEqual(eval('Decimal(10) <= E()'), 'ge 10')
501 self.assertEqual(eval('Decimal(10) >= E()'), 'le 10')
502 self.assertEqual(eval('Decimal(10) == E()'), 'eq 10')
503 self.assertEqual(eval('Decimal(10) != E()'), 'ne 10')
505 # insert operator methods and then exercise them
506 for sym, lop, rop in (
507 ('+', '__add__', '__radd__'),
508 ('-', '__sub__', '__rsub__'),
509 ('*', '__mul__', '__rmul__'),
510 ('/', '__div__', '__rdiv__'),
511 ('%', '__mod__', '__rmod__'),
512 ('//', '__floordiv__', '__rfloordiv__'),
513 ('**', '__pow__', '__rpow__'),
516 setattr(E, lop, lambda self, other: 'str' + lop + str(other))
517 setattr(E, rop, lambda self, other: str(other) + rop + 'str')
518 self.assertEqual(eval('E()' + sym + 'Decimal(10)'),
519 'str' + lop + '10')
520 self.assertEqual(eval('Decimal(10)' + sym + 'E()'),
521 '10' + rop + 'str')
523 class DecimalArithmeticOperatorsTest(unittest.TestCase):
524 '''Unit tests for all arithmetic operators, binary and unary.'''
526 def test_addition(self):
528 d1 = Decimal('-11.1')
529 d2 = Decimal('22.2')
531 #two Decimals
532 self.assertEqual(d1+d2, Decimal('11.1'))
533 self.assertEqual(d2+d1, Decimal('11.1'))
535 #with other type, left
536 c = d1 + 5
537 self.assertEqual(c, Decimal('-6.1'))
538 self.assertEqual(type(c), type(d1))
540 #with other type, right
541 c = 5 + d1
542 self.assertEqual(c, Decimal('-6.1'))
543 self.assertEqual(type(c), type(d1))
545 #inline with decimal
546 d1 += d2
547 self.assertEqual(d1, Decimal('11.1'))
549 #inline with other type
550 d1 += 5
551 self.assertEqual(d1, Decimal('16.1'))
553 def test_subtraction(self):
555 d1 = Decimal('-11.1')
556 d2 = Decimal('22.2')
558 #two Decimals
559 self.assertEqual(d1-d2, Decimal('-33.3'))
560 self.assertEqual(d2-d1, Decimal('33.3'))
562 #with other type, left
563 c = d1 - 5
564 self.assertEqual(c, Decimal('-16.1'))
565 self.assertEqual(type(c), type(d1))
567 #with other type, right
568 c = 5 - d1
569 self.assertEqual(c, Decimal('16.1'))
570 self.assertEqual(type(c), type(d1))
572 #inline with decimal
573 d1 -= d2
574 self.assertEqual(d1, Decimal('-33.3'))
576 #inline with other type
577 d1 -= 5
578 self.assertEqual(d1, Decimal('-38.3'))
580 def test_multiplication(self):
582 d1 = Decimal('-5')
583 d2 = Decimal('3')
585 #two Decimals
586 self.assertEqual(d1*d2, Decimal('-15'))
587 self.assertEqual(d2*d1, Decimal('-15'))
589 #with other type, left
590 c = d1 * 5
591 self.assertEqual(c, Decimal('-25'))
592 self.assertEqual(type(c), type(d1))
594 #with other type, right
595 c = 5 * d1
596 self.assertEqual(c, Decimal('-25'))
597 self.assertEqual(type(c), type(d1))
599 #inline with decimal
600 d1 *= d2
601 self.assertEqual(d1, Decimal('-15'))
603 #inline with other type
604 d1 *= 5
605 self.assertEqual(d1, Decimal('-75'))
607 def test_division(self):
609 d1 = Decimal('-5')
610 d2 = Decimal('2')
612 #two Decimals
613 self.assertEqual(d1/d2, Decimal('-2.5'))
614 self.assertEqual(d2/d1, Decimal('-0.4'))
616 #with other type, left
617 c = d1 / 4
618 self.assertEqual(c, Decimal('-1.25'))
619 self.assertEqual(type(c), type(d1))
621 #with other type, right
622 c = 4 / d1
623 self.assertEqual(c, Decimal('-0.8'))
624 self.assertEqual(type(c), type(d1))
626 #inline with decimal
627 d1 /= d2
628 self.assertEqual(d1, Decimal('-2.5'))
630 #inline with other type
631 d1 /= 4
632 self.assertEqual(d1, Decimal('-0.625'))
634 def test_floor_division(self):
636 d1 = Decimal('5')
637 d2 = Decimal('2')
639 #two Decimals
640 self.assertEqual(d1//d2, Decimal('2'))
641 self.assertEqual(d2//d1, Decimal('0'))
643 #with other type, left
644 c = d1 // 4
645 self.assertEqual(c, Decimal('1'))
646 self.assertEqual(type(c), type(d1))
648 #with other type, right
649 c = 7 // d1
650 self.assertEqual(c, Decimal('1'))
651 self.assertEqual(type(c), type(d1))
653 #inline with decimal
654 d1 //= d2
655 self.assertEqual(d1, Decimal('2'))
657 #inline with other type
658 d1 //= 2
659 self.assertEqual(d1, Decimal('1'))
661 def test_powering(self):
663 d1 = Decimal('5')
664 d2 = Decimal('2')
666 #two Decimals
667 self.assertEqual(d1**d2, Decimal('25'))
668 self.assertEqual(d2**d1, Decimal('32'))
670 #with other type, left
671 c = d1 ** 4
672 self.assertEqual(c, Decimal('625'))
673 self.assertEqual(type(c), type(d1))
675 #with other type, right
676 c = 7 ** d1
677 self.assertEqual(c, Decimal('16807'))
678 self.assertEqual(type(c), type(d1))
680 #inline with decimal
681 d1 **= d2
682 self.assertEqual(d1, Decimal('25'))
684 #inline with other type
685 d1 **= 4
686 self.assertEqual(d1, Decimal('390625'))
688 def test_module(self):
690 d1 = Decimal('5')
691 d2 = Decimal('2')
693 #two Decimals
694 self.assertEqual(d1%d2, Decimal('1'))
695 self.assertEqual(d2%d1, Decimal('2'))
697 #with other type, left
698 c = d1 % 4
699 self.assertEqual(c, Decimal('1'))
700 self.assertEqual(type(c), type(d1))
702 #with other type, right
703 c = 7 % d1
704 self.assertEqual(c, Decimal('2'))
705 self.assertEqual(type(c), type(d1))
707 #inline with decimal
708 d1 %= d2
709 self.assertEqual(d1, Decimal('1'))
711 #inline with other type
712 d1 %= 4
713 self.assertEqual(d1, Decimal('1'))
715 def test_floor_div_module(self):
717 d1 = Decimal('5')
718 d2 = Decimal('2')
720 #two Decimals
721 (p, q) = divmod(d1, d2)
722 self.assertEqual(p, Decimal('2'))
723 self.assertEqual(q, Decimal('1'))
724 self.assertEqual(type(p), type(d1))
725 self.assertEqual(type(q), type(d1))
727 #with other type, left
728 (p, q) = divmod(d1, 4)
729 self.assertEqual(p, Decimal('1'))
730 self.assertEqual(q, Decimal('1'))
731 self.assertEqual(type(p), type(d1))
732 self.assertEqual(type(q), type(d1))
734 #with other type, right
735 (p, q) = divmod(7, d1)
736 self.assertEqual(p, Decimal('1'))
737 self.assertEqual(q, Decimal('2'))
738 self.assertEqual(type(p), type(d1))
739 self.assertEqual(type(q), type(d1))
741 def test_unary_operators(self):
742 self.assertEqual(+Decimal(45), Decimal(+45)) # +
743 self.assertEqual(-Decimal(45), Decimal(-45)) # -
744 self.assertEqual(abs(Decimal(45)), abs(Decimal(-45))) # abs
747 # The following are two functions used to test threading in the next class
749 def thfunc1(cls):
750 d1 = Decimal(1)
751 d3 = Decimal(3)
752 cls.assertEqual(d1/d3, Decimal('0.333333333'))
753 cls.synchro.wait()
754 cls.assertEqual(d1/d3, Decimal('0.333333333'))
755 cls.finish1.set()
756 return
758 def thfunc2(cls):
759 d1 = Decimal(1)
760 d3 = Decimal(3)
761 cls.assertEqual(d1/d3, Decimal('0.333333333'))
762 thiscontext = getcontext()
763 thiscontext.prec = 18
764 cls.assertEqual(d1/d3, Decimal('0.333333333333333333'))
765 cls.synchro.set()
766 cls.finish2.set()
767 return
770 class DecimalUseOfContextTest(unittest.TestCase):
771 '''Unit tests for Use of Context cases in Decimal.'''
773 try:
774 import threading
775 except ImportError:
776 threading = None
778 # Take care executing this test from IDLE, there's an issue in threading
779 # that hangs IDLE and I couldn't find it
781 def test_threading(self):
782 #Test the "threading isolation" of a Context.
784 self.synchro = threading.Event()
785 self.finish1 = threading.Event()
786 self.finish2 = threading.Event()
788 th1 = threading.Thread(target=thfunc1, args=(self,))
789 th2 = threading.Thread(target=thfunc2, args=(self,))
791 th1.start()
792 th2.start()
794 self.finish1.wait()
795 self.finish1.wait()
796 return
798 if threading is None:
799 del test_threading
802 class DecimalUsabilityTest(unittest.TestCase):
803 '''Unit tests for Usability cases of Decimal.'''
805 def test_comparison_operators(self):
807 da = Decimal('23.42')
808 db = Decimal('23.42')
809 dc = Decimal('45')
811 #two Decimals
812 self.failUnless(dc > da)
813 self.failUnless(dc >= da)
814 self.failUnless(da < dc)
815 self.failUnless(da <= dc)
816 self.failUnless(da == db)
817 self.failUnless(da != dc)
818 self.failUnless(da <= db)
819 self.failUnless(da >= db)
820 self.assertEqual(cmp(dc,da), 1)
821 self.assertEqual(cmp(da,dc), -1)
822 self.assertEqual(cmp(da,db), 0)
824 #a Decimal and an int
825 self.failUnless(dc > 23)
826 self.failUnless(23 < dc)
827 self.failUnless(dc == 45)
828 self.assertEqual(cmp(dc,23), 1)
829 self.assertEqual(cmp(23,dc), -1)
830 self.assertEqual(cmp(dc,45), 0)
832 #a Decimal and uncomparable
833 self.assertNotEqual(da, 'ugly')
834 self.assertNotEqual(da, 32.7)
835 self.assertNotEqual(da, object())
836 self.assertNotEqual(da, object)
838 # sortable
839 a = map(Decimal, xrange(100))
840 b = a[:]
841 random.shuffle(a)
842 a.sort()
843 self.assertEqual(a, b)
845 def test_copy_and_deepcopy_methods(self):
846 d = Decimal('43.24')
847 c = copy.copy(d)
848 self.assertEqual(id(c), id(d))
849 dc = copy.deepcopy(d)
850 self.assertEqual(id(dc), id(d))
852 def test_hash_method(self):
853 #just that it's hashable
854 hash(Decimal(23))
855 #the same hash that to an int
856 self.assertEqual(hash(Decimal(23)), hash(23))
857 self.assertRaises(TypeError, hash, Decimal('NaN'))
858 self.assert_(hash(Decimal('Inf')))
859 self.assert_(hash(Decimal('-Inf')))
861 def test_min_and_max_methods(self):
863 d1 = Decimal('15.32')
864 d2 = Decimal('28.5')
865 l1 = 15
866 l2 = 28
868 #between Decimals
869 self.failUnless(min(d1,d2) is d1)
870 self.failUnless(min(d2,d1) is d1)
871 self.failUnless(max(d1,d2) is d2)
872 self.failUnless(max(d2,d1) is d2)
874 #between Decimal and long
875 self.failUnless(min(d1,l2) is d1)
876 self.failUnless(min(l2,d1) is d1)
877 self.failUnless(max(l1,d2) is d2)
878 self.failUnless(max(d2,l1) is d2)
880 def test_as_nonzero(self):
881 #as false
882 self.failIf(Decimal(0))
883 #as true
884 self.failUnless(Decimal('0.372'))
886 def test_tostring_methods(self):
887 #Test str and repr methods.
889 d = Decimal('15.32')
890 self.assertEqual(str(d), '15.32') # str
891 self.assertEqual(repr(d), 'Decimal("15.32")') # repr
893 def test_tonum_methods(self):
894 #Test float, int and long methods.
896 d1 = Decimal('66')
897 d2 = Decimal('15.32')
899 #int
900 self.assertEqual(int(d1), 66)
901 self.assertEqual(int(d2), 15)
903 #long
904 self.assertEqual(long(d1), 66)
905 self.assertEqual(long(d2), 15)
907 #float
908 self.assertEqual(float(d1), 66)
909 self.assertEqual(float(d2), 15.32)
911 def test_eval_round_trip(self):
913 #with zero
914 d = Decimal( (0, (0,), 0) )
915 self.assertEqual(d, eval(repr(d)))
917 #int
918 d = Decimal( (1, (4, 5), 0) )
919 self.assertEqual(d, eval(repr(d)))
921 #float
922 d = Decimal( (0, (4, 5, 3, 4), -2) )
923 self.assertEqual(d, eval(repr(d)))
925 #weird
926 d = Decimal( (1, (4, 3, 4, 9, 1, 3, 5, 3, 4), -25) )
927 self.assertEqual(d, eval(repr(d)))
929 def test_as_tuple(self):
931 #with zero
932 d = Decimal(0)
933 self.assertEqual(d.as_tuple(), (0, (0,), 0) )
935 #int
936 d = Decimal(-45)
937 self.assertEqual(d.as_tuple(), (1, (4, 5), 0) )
939 #complicated string
940 d = Decimal("-4.34913534E-17")
941 self.assertEqual(d.as_tuple(), (1, (4, 3, 4, 9, 1, 3, 5, 3, 4), -25) )
943 #inf
944 d = Decimal("Infinity")
945 self.assertEqual(d.as_tuple(), (0, (0,), 'F') )
947 def test_immutability_operations(self):
948 # Do operations and check that it didn't change change internal objects.
950 d1 = Decimal('-25e55')
951 b1 = Decimal('-25e55')
952 d2 = Decimal('33e-33')
953 b2 = Decimal('33e-33')
955 def checkSameDec(operation, useOther=False):
956 if useOther:
957 eval("d1." + operation + "(d2)")
958 self.assertEqual(d1._sign, b1._sign)
959 self.assertEqual(d1._int, b1._int)
960 self.assertEqual(d1._exp, b1._exp)
961 self.assertEqual(d2._sign, b2._sign)
962 self.assertEqual(d2._int, b2._int)
963 self.assertEqual(d2._exp, b2._exp)
964 else:
965 eval("d1." + operation + "()")
966 self.assertEqual(d1._sign, b1._sign)
967 self.assertEqual(d1._int, b1._int)
968 self.assertEqual(d1._exp, b1._exp)
969 return
971 Decimal(d1)
972 self.assertEqual(d1._sign, b1._sign)
973 self.assertEqual(d1._int, b1._int)
974 self.assertEqual(d1._exp, b1._exp)
976 checkSameDec("__abs__")
977 checkSameDec("__add__", True)
978 checkSameDec("__div__", True)
979 checkSameDec("__divmod__", True)
980 checkSameDec("__cmp__", True)
981 checkSameDec("__float__")
982 checkSameDec("__floordiv__", True)
983 checkSameDec("__hash__")
984 checkSameDec("__int__")
985 checkSameDec("__long__")
986 checkSameDec("__mod__", True)
987 checkSameDec("__mul__", True)
988 checkSameDec("__neg__")
989 checkSameDec("__nonzero__")
990 checkSameDec("__pos__")
991 checkSameDec("__pow__", True)
992 checkSameDec("__radd__", True)
993 checkSameDec("__rdiv__", True)
994 checkSameDec("__rdivmod__", True)
995 checkSameDec("__repr__")
996 checkSameDec("__rfloordiv__", True)
997 checkSameDec("__rmod__", True)
998 checkSameDec("__rmul__", True)
999 checkSameDec("__rpow__", True)
1000 checkSameDec("__rsub__", True)
1001 checkSameDec("__str__")
1002 checkSameDec("__sub__", True)
1003 checkSameDec("__truediv__", True)
1004 checkSameDec("adjusted")
1005 checkSameDec("as_tuple")
1006 checkSameDec("compare", True)
1007 checkSameDec("max", True)
1008 checkSameDec("min", True)
1009 checkSameDec("normalize")
1010 checkSameDec("quantize", True)
1011 checkSameDec("remainder_near", True)
1012 checkSameDec("same_quantum", True)
1013 checkSameDec("sqrt")
1014 checkSameDec("to_eng_string")
1015 checkSameDec("to_integral")
1017 class DecimalPythonAPItests(unittest.TestCase):
1019 def test_pickle(self):
1020 d = Decimal('-3.141590000')
1021 p = pickle.dumps(d)
1022 e = pickle.loads(p)
1023 self.assertEqual(d, e)
1025 def test_int(self):
1026 for x in range(-250, 250):
1027 s = '%0.2f' % (x / 100.0)
1028 # should work the same as for floats
1029 self.assertEqual(int(Decimal(s)), int(float(s)))
1030 # should work the same as to_integral in the ROUND_DOWN mode
1031 d = Decimal(s)
1032 r = d.to_integral(ROUND_DOWN)
1033 self.assertEqual(Decimal(int(d)), r)
1035 class ContextAPItests(unittest.TestCase):
1037 def test_pickle(self):
1038 c = Context()
1039 e = pickle.loads(pickle.dumps(c))
1040 for k in vars(c):
1041 v1 = vars(c)[k]
1042 v2 = vars(e)[k]
1043 self.assertEqual(v1, v2)
1045 def test_equality_with_other_types(self):
1046 self.assert_(Decimal(10) in ['a', 1.0, Decimal(10), (1,2), {}])
1047 self.assert_(Decimal(10) not in ['a', 1.0, (1,2), {}])
1049 def test_copy(self):
1050 # All copies should be deep
1051 c = Context()
1052 d = c.copy()
1053 self.assertNotEqual(id(c), id(d))
1054 self.assertNotEqual(id(c.flags), id(d.flags))
1055 self.assertNotEqual(id(c.traps), id(d.traps))
1057 def test_main(arith=False, verbose=None):
1058 """ Execute the tests.
1060 Runs all arithmetic tests if arith is True or if the "decimal" resource
1061 is enabled in regrtest.py
1064 global TEST_ALL
1065 TEST_ALL = arith or is_resource_enabled('decimal')
1067 test_classes = [
1068 DecimalExplicitConstructionTest,
1069 DecimalImplicitConstructionTest,
1070 DecimalArithmeticOperatorsTest,
1071 DecimalUseOfContextTest,
1072 DecimalUsabilityTest,
1073 DecimalPythonAPItests,
1074 ContextAPItests,
1075 DecimalTest,
1078 run_unittest(*test_classes)
1079 import decimal as DecimalModule
1080 run_doctest(DecimalModule, verbose)
1083 if __name__ == '__main__':
1084 # Calling with no arguments runs all tests.
1085 # Calling with "Skip" will skip over 90% of the arithmetic tests.
1086 if len(sys.argv) == 1:
1087 test_main(arith=True, verbose=True)
1088 elif len(sys.argv) == 2:
1089 arith = sys.argv[1].lower() != 'skip'
1090 test_main(arith=arith, verbose=True)
1091 else:
1092 raise ValueError("test called with wrong arguments, use test_Decimal [Skip]")