blob: f3f9215221f4803af13dab42f3dc3fe0d9b7f863 [file] [log] [blame]
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001# Copyright (c) 2004 Python Software Foundation.
2# All rights reserved.
3
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
9
10"""
11These are the test cases for the Decimal module.
12
13There are two groups of tests, Arithmetic and Behaviour. The former test
14the Decimal arithmetic using the tests provided by Mike Cowlishaw. The latter
15test the pythonic behaviour according to PEP 327.
16
17Cowlishaw's tests can be downloaded from:
18
19 www2.hursley.ibm.com/decimal/dectest.zip
20
21This test module can be called from command line with one parameter (Arithmetic
22or Behaviour) to test each part, or without parameter to test both parts. If
23you're working through IDLE, you can import this test module and call test_main()
24with the corresponding argument.
25"""
26
Raymond Hettinger7c85fa42004-07-01 11:01:35 +000027import unittest
28import glob
29import os, sys
30import pickle, copy
31from decimal import *
Tim Peters46cc7022006-03-31 04:11:16 +000032from test.test_support import (TestSkipped, run_unittest, run_doctest,
33 is_resource_enabled)
Raymond Hettinger0aeac102004-07-05 22:53:03 +000034import random
Raymond Hettinger7e71fa52004-12-18 19:07:19 +000035try:
36 import threading
37except ImportError:
38 threading = None
Raymond Hettinger7c85fa42004-07-01 11:01:35 +000039
Raymond Hettingerfed52962004-07-14 15:41:57 +000040# Useful Test Constant
41Signals = getcontext().flags.keys()
42
Tim Peters46cc7022006-03-31 04:11:16 +000043# Tests are built around these assumed context defaults.
44# test_main() restores the original context.
Neal Norwitzce4a9c92006-04-09 08:36:46 +000045def init():
46 global ORIGINAL_CONTEXT
47 ORIGINAL_CONTEXT = getcontext().copy()
48 DefaultContext.prec = 9
49 DefaultContext.rounding = ROUND_HALF_EVEN
50 DefaultContext.traps = dict.fromkeys(Signals, 0)
51 setcontext(DefaultContext)
Raymond Hettinger6ea48452004-07-03 12:26:21 +000052
Raymond Hettinger7c85fa42004-07-01 11:01:35 +000053TESTDATADIR = 'decimaltestdata'
Raymond Hettingerd9c0a7a2004-07-03 10:02:28 +000054if __name__ == '__main__':
55 file = sys.argv[0]
56else:
57 file = __file__
58testdir = os.path.dirname(file) or os.curdir
Raymond Hettinger267b8682005-03-27 10:47:39 +000059directory = testdir + os.sep + TESTDATADIR + os.sep
Raymond Hettinger7c85fa42004-07-01 11:01:35 +000060
Raymond Hettinger267b8682005-03-27 10:47:39 +000061skip_expected = not os.path.isdir(directory)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +000062
63# Make sure it actually raises errors when not expected and caught in flags
64# Slower, since it runs some things several times.
65EXTENDEDERRORTEST = False
66
67
68#Map the test cases' error names to the actual errors
69
70ErrorNames = {'clamped' : Clamped,
Raymond Hettinger5aa478b2004-07-09 10:02:53 +000071 'conversion_syntax' : InvalidOperation,
Raymond Hettinger7c85fa42004-07-01 11:01:35 +000072 'division_by_zero' : DivisionByZero,
Raymond Hettinger5aa478b2004-07-09 10:02:53 +000073 'division_impossible' : InvalidOperation,
74 'division_undefined' : InvalidOperation,
Raymond Hettinger7c85fa42004-07-01 11:01:35 +000075 'inexact' : Inexact,
Raymond Hettinger5aa478b2004-07-09 10:02:53 +000076 'invalid_context' : InvalidOperation,
Raymond Hettinger7c85fa42004-07-01 11:01:35 +000077 'invalid_operation' : InvalidOperation,
78 'overflow' : Overflow,
79 'rounded' : Rounded,
80 'subnormal' : Subnormal,
81 'underflow' : Underflow}
82
83
84def Nonfunction(*args):
85 """Doesn't do anything."""
86 return None
87
88RoundingDict = {'ceiling' : ROUND_CEILING, #Maps test-case names to roundings.
89 'down' : ROUND_DOWN,
90 'floor' : ROUND_FLOOR,
91 'half_down' : ROUND_HALF_DOWN,
92 'half_even' : ROUND_HALF_EVEN,
93 'half_up' : ROUND_HALF_UP,
94 'up' : ROUND_UP}
95
96# Name adapter to be able to change the Decimal and Context
97# interface without changing the test files from Cowlishaw
98nameAdapter = {'toeng':'to_eng_string',
99 'tosci':'to_sci_string',
100 'samequantum':'same_quantum',
101 'tointegral':'to_integral',
102 'remaindernear':'remainder_near',
103 'divideint':'divide_int',
104 'squareroot':'sqrt',
105 'apply':'_apply',
106 }
107
108class DecimalTest(unittest.TestCase):
109 """Class which tests the Decimal class against the test cases.
110
111 Changed for unittest.
112 """
113 def setUp(self):
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000114 self.context = Context()
Raymond Hettingerbf440692004-07-10 14:14:37 +0000115 for key in DefaultContext.traps.keys():
116 DefaultContext.traps[key] = 1
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000117 self.ignore_list = ['#']
118 # Basically, a # means return NaN InvalidOperation.
119 # Different from a sNaN in trim
120
121 self.ChangeDict = {'precision' : self.change_precision,
122 'rounding' : self.change_rounding_method,
123 'maxexponent' : self.change_max_exponent,
124 'minexponent' : self.change_min_exponent,
125 'clamp' : self.change_clamp}
126
127 def tearDown(self):
128 """Cleaning up enviroment."""
129 # leaving context in original state
Raymond Hettingerbf440692004-07-10 14:14:37 +0000130 for key in DefaultContext.traps.keys():
131 DefaultContext.traps[key] = 0
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000132 return
133
134 def eval_file(self, file):
135 global skip_expected
136 if skip_expected:
137 raise TestSkipped
138 return
139 for line in open(file).xreadlines():
140 line = line.replace('\r\n', '').replace('\n', '')
Raymond Hettinger5aa478b2004-07-09 10:02:53 +0000141 #print line
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000142 try:
143 t = self.eval_line(line)
Raymond Hettingerd87ac8f2004-07-09 10:52:54 +0000144 except InvalidOperation:
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000145 print 'Error in test cases:'
146 print line
147 continue
148 except DecimalException, exception:
149 #Exception raised where there shoudn't have been one.
150 self.fail('Exception "'+exception.__class__.__name__ + '" raised on line '+line)
151
152 return
153
154 def eval_line(self, s):
155 if s.find(' -> ') >= 0 and s[:2] != '--' and not s.startswith(' --'):
156 s = (s.split('->')[0] + '->' +
157 s.split('->')[1].split('--')[0]).strip()
158 else:
159 s = s.split('--')[0].strip()
160
161 for ignore in self.ignore_list:
162 if s.find(ignore) >= 0:
163 #print s.split()[0], 'NotImplemented--', ignore
164 return
165 if not s:
166 return
167 elif ':' in s:
168 return self.eval_directive(s)
169 else:
170 return self.eval_equation(s)
171
172 def eval_directive(self, s):
173 funct, value = map(lambda x: x.strip().lower(), s.split(':'))
174 if funct == 'rounding':
175 value = RoundingDict[value]
176 else:
177 try:
178 value = int(value)
179 except ValueError:
180 pass
181
182 funct = self.ChangeDict.get(funct, Nonfunction)
183 funct(value)
184
185 def eval_equation(self, s):
186 #global DEFAULT_PRECISION
187 #print DEFAULT_PRECISION
Raymond Hettingered20ad82004-09-04 20:09:13 +0000188
189 if not TEST_ALL and random.random() < 0.90:
190 return
191
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000192 try:
193 Sides = s.split('->')
194 L = Sides[0].strip().split()
195 id = L[0]
196# print id,
197 funct = L[1].lower()
198 valstemp = L[2:]
199 L = Sides[1].strip().split()
200 ans = L[0]
201 exceptions = L[1:]
202 except (TypeError, AttributeError, IndexError):
Raymond Hettingerd87ac8f2004-07-09 10:52:54 +0000203 raise InvalidOperation
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000204 def FixQuotes(val):
205 val = val.replace("''", 'SingleQuote').replace('""', 'DoubleQuote')
206 val = val.replace("'", '').replace('"', '')
207 val = val.replace('SingleQuote', "'").replace('DoubleQuote', '"')
208 return val
209 fname = nameAdapter.get(funct, funct)
210 if fname == 'rescale':
211 return
212 funct = getattr(self.context, fname)
213 vals = []
214 conglomerate = ''
215 quote = 0
216 theirexceptions = [ErrorNames[x.lower()] for x in exceptions]
217
Raymond Hettingerd9c0a7a2004-07-03 10:02:28 +0000218 for exception in Signals:
Raymond Hettingerbf440692004-07-10 14:14:37 +0000219 self.context.traps[exception] = 1 #Catch these bugs...
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000220 for exception in theirexceptions:
Raymond Hettingerbf440692004-07-10 14:14:37 +0000221 self.context.traps[exception] = 0
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000222 for i, val in enumerate(valstemp):
223 if val.count("'") % 2 == 1:
224 quote = 1 - quote
225 if quote:
226 conglomerate = conglomerate + ' ' + val
227 continue
228 else:
229 val = conglomerate + val
230 conglomerate = ''
231 v = FixQuotes(val)
232 if fname in ('to_sci_string', 'to_eng_string'):
233 if EXTENDEDERRORTEST:
234 for error in theirexceptions:
Raymond Hettingerbf440692004-07-10 14:14:37 +0000235 self.context.traps[error] = 1
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000236 try:
237 funct(self.context.create_decimal(v))
238 except error:
239 pass
Raymond Hettingerd9c0a7a2004-07-03 10:02:28 +0000240 except Signals, e:
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000241 self.fail("Raised %s in %s when %s disabled" % \
242 (e, s, error))
243 else:
244 self.fail("Did not raise %s in %s" % (error, s))
Raymond Hettingerbf440692004-07-10 14:14:37 +0000245 self.context.traps[error] = 0
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000246 v = self.context.create_decimal(v)
247 else:
248 v = Decimal(v)
249 vals.append(v)
250
251 ans = FixQuotes(ans)
252
253 if EXTENDEDERRORTEST and fname not in ('to_sci_string', 'to_eng_string'):
254 for error in theirexceptions:
Raymond Hettingerbf440692004-07-10 14:14:37 +0000255 self.context.traps[error] = 1
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000256 try:
257 funct(*vals)
258 except error:
259 pass
Raymond Hettingerd9c0a7a2004-07-03 10:02:28 +0000260 except Signals, e:
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000261 self.fail("Raised %s in %s when %s disabled" % \
262 (e, s, error))
263 else:
264 self.fail("Did not raise %s in %s" % (error, s))
Raymond Hettingerbf440692004-07-10 14:14:37 +0000265 self.context.traps[error] = 0
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000266 try:
267 result = str(funct(*vals))
268 if fname == 'same_quantum':
269 result = str(int(eval(result))) # 'True', 'False' -> '1', '0'
Raymond Hettingerd9c0a7a2004-07-03 10:02:28 +0000270 except Signals, error:
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000271 self.fail("Raised %s in %s" % (error, s))
272 except: #Catch any error long enough to state the test case.
273 print "ERROR:", s
274 raise
275
276 myexceptions = self.getexceptions()
Raymond Hettingerbf440692004-07-10 14:14:37 +0000277 self.context.clear_flags()
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000278
279 myexceptions.sort()
280 theirexceptions.sort()
281
282 self.assertEqual(result, ans,
283 'Incorrect answer for ' + s + ' -- got ' + result)
284 self.assertEqual(myexceptions, theirexceptions,
285 'Incorrect flags set in ' + s + ' -- got ' \
286 + str(myexceptions))
287 return
288
289 def getexceptions(self):
Raymond Hettingerf63ba432004-08-17 05:42:09 +0000290 return [e for e in Signals if self.context.flags[e]]
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000291
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000292 def change_precision(self, prec):
293 self.context.prec = prec
294 def change_rounding_method(self, rounding):
295 self.context.rounding = rounding
296 def change_min_exponent(self, exp):
297 self.context.Emin = exp
298 def change_max_exponent(self, exp):
299 self.context.Emax = exp
300 def change_clamp(self, clamp):
301 self.context._clamp = clamp
302
Raymond Hettingerf63ba432004-08-17 05:42:09 +0000303# Dynamically build custom test definition for each file in the test
304# directory and add the definitions to the DecimalTest class. This
305# procedure insures that new files do not get skipped.
Raymond Hettinger267b8682005-03-27 10:47:39 +0000306for filename in os.listdir(directory):
Raymond Hettingerf63ba432004-08-17 05:42:09 +0000307 if '.decTest' not in filename:
308 continue
Raymond Hettingerf63ba432004-08-17 05:42:09 +0000309 head, tail = filename.split('.')
Raymond Hettinger267b8682005-03-27 10:47:39 +0000310 tester = lambda self, f=filename: self.eval_file(directory + f)
Raymond Hettingerf63ba432004-08-17 05:42:09 +0000311 setattr(DecimalTest, 'test_' + head, tester)
312 del filename, head, tail, tester
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000313
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000314
315
316# The following classes test the behaviour of Decimal according to PEP 327
317
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000318class DecimalExplicitConstructionTest(unittest.TestCase):
319 '''Unit tests for Explicit Construction cases of Decimal.'''
320
321 def test_explicit_empty(self):
322 self.assertEqual(Decimal(), Decimal("0"))
323
324 def test_explicit_from_None(self):
325 self.assertRaises(TypeError, Decimal, None)
326
327 def test_explicit_from_int(self):
328
329 #positive
330 d = Decimal(45)
331 self.assertEqual(str(d), '45')
332
333 #very large positive
334 d = Decimal(500000123)
335 self.assertEqual(str(d), '500000123')
336
337 #negative
338 d = Decimal(-45)
339 self.assertEqual(str(d), '-45')
340
341 #zero
342 d = Decimal(0)
343 self.assertEqual(str(d), '0')
344
345 def test_explicit_from_string(self):
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000346
347 #empty
348 self.assertEqual(str(Decimal('')), 'NaN')
349
350 #int
351 self.assertEqual(str(Decimal('45')), '45')
352
353 #float
354 self.assertEqual(str(Decimal('45.34')), '45.34')
355
356 #engineer notation
357 self.assertEqual(str(Decimal('45e2')), '4.5E+3')
358
359 #just not a number
360 self.assertEqual(str(Decimal('ugly')), 'NaN')
361
362 def test_explicit_from_tuples(self):
363
364 #zero
365 d = Decimal( (0, (0,), 0) )
366 self.assertEqual(str(d), '0')
367
368 #int
369 d = Decimal( (1, (4, 5), 0) )
370 self.assertEqual(str(d), '-45')
371
372 #float
373 d = Decimal( (0, (4, 5, 3, 4), -2) )
374 self.assertEqual(str(d), '45.34')
375
376 #weird
377 d = Decimal( (1, (4, 3, 4, 9, 1, 3, 5, 3, 4), -25) )
378 self.assertEqual(str(d), '-4.34913534E-17')
379
380 #wrong number of items
381 self.assertRaises(ValueError, Decimal, (1, (4, 3, 4, 9, 1)) )
382
383 #bad sign
384 self.assertRaises(ValueError, Decimal, (8, (4, 3, 4, 9, 1), 2) )
385
386 #bad exp
387 self.assertRaises(ValueError, Decimal, (1, (4, 3, 4, 9, 1), 'wrong!') )
388
389 #bad coefficients
390 self.assertRaises(ValueError, Decimal, (1, (4, 3, 4, None, 1), 2) )
391 self.assertRaises(ValueError, Decimal, (1, (4, -3, 4, 9, 1), 2) )
392
393 def test_explicit_from_Decimal(self):
394
395 #positive
396 d = Decimal(45)
397 e = Decimal(d)
398 self.assertEqual(str(e), '45')
399 self.assertNotEqual(id(d), id(e))
400
401 #very large positive
402 d = Decimal(500000123)
403 e = Decimal(d)
404 self.assertEqual(str(e), '500000123')
405 self.assertNotEqual(id(d), id(e))
406
407 #negative
408 d = Decimal(-45)
409 e = Decimal(d)
410 self.assertEqual(str(e), '-45')
411 self.assertNotEqual(id(d), id(e))
412
413 #zero
414 d = Decimal(0)
415 e = Decimal(d)
416 self.assertEqual(str(e), '0')
417 self.assertNotEqual(id(d), id(e))
418
419 def test_explicit_context_create_decimal(self):
420
421 nc = copy.copy(getcontext())
422 nc.prec = 3
423
424 # empty
Raymond Hettingerfed52962004-07-14 15:41:57 +0000425 d = Decimal()
426 self.assertEqual(str(d), '0')
427 d = nc.create_decimal()
428 self.assertEqual(str(d), '0')
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000429
430 # from None
431 self.assertRaises(TypeError, nc.create_decimal, None)
432
433 # from int
434 d = nc.create_decimal(456)
435 self.failUnless(isinstance(d, Decimal))
436 self.assertEqual(nc.create_decimal(45678),
437 nc.create_decimal('457E+2'))
438
439 # from string
440 d = Decimal('456789')
441 self.assertEqual(str(d), '456789')
442 d = nc.create_decimal('456789')
443 self.assertEqual(str(d), '4.57E+5')
444
445 # from tuples
446 d = Decimal( (1, (4, 3, 4, 9, 1, 3, 5, 3, 4), -25) )
447 self.assertEqual(str(d), '-4.34913534E-17')
448 d = nc.create_decimal( (1, (4, 3, 4, 9, 1, 3, 5, 3, 4), -25) )
449 self.assertEqual(str(d), '-4.35E-17')
450
451 # from Decimal
452 prevdec = Decimal(500000123)
453 d = Decimal(prevdec)
454 self.assertEqual(str(d), '500000123')
455 d = nc.create_decimal(prevdec)
456 self.assertEqual(str(d), '5.00E+8')
457
458
459class DecimalImplicitConstructionTest(unittest.TestCase):
460 '''Unit tests for Implicit Construction cases of Decimal.'''
461
462 def test_implicit_from_None(self):
463 self.assertRaises(TypeError, eval, 'Decimal(5) + None', globals())
464
465 def test_implicit_from_int(self):
466 #normal
467 self.assertEqual(str(Decimal(5) + 45), '50')
468 #exceeding precision
469 self.assertEqual(Decimal(5) + 123456789000, Decimal(123456789000))
470
471 def test_implicit_from_string(self):
472 self.assertRaises(TypeError, eval, 'Decimal(5) + "3"', globals())
473
474 def test_implicit_from_float(self):
475 self.assertRaises(TypeError, eval, 'Decimal(5) + 2.2', globals())
476
477 def test_implicit_from_Decimal(self):
478 self.assertEqual(Decimal(5) + Decimal(45), Decimal(50))
479
Raymond Hettinger267b8682005-03-27 10:47:39 +0000480 def test_rop(self):
481 # Allow other classes to be trained to interact with Decimals
482 class E:
483 def __divmod__(self, other):
484 return 'divmod ' + str(other)
485 def __rdivmod__(self, other):
486 return str(other) + ' rdivmod'
487 def __lt__(self, other):
488 return 'lt ' + str(other)
489 def __gt__(self, other):
490 return 'gt ' + str(other)
491 def __le__(self, other):
492 return 'le ' + str(other)
493 def __ge__(self, other):
494 return 'ge ' + str(other)
495 def __eq__(self, other):
496 return 'eq ' + str(other)
497 def __ne__(self, other):
498 return 'ne ' + str(other)
499
500 self.assertEqual(divmod(E(), Decimal(10)), 'divmod 10')
501 self.assertEqual(divmod(Decimal(10), E()), '10 rdivmod')
502 self.assertEqual(eval('Decimal(10) < E()'), 'gt 10')
503 self.assertEqual(eval('Decimal(10) > E()'), 'lt 10')
504 self.assertEqual(eval('Decimal(10) <= E()'), 'ge 10')
505 self.assertEqual(eval('Decimal(10) >= E()'), 'le 10')
506 self.assertEqual(eval('Decimal(10) == E()'), 'eq 10')
507 self.assertEqual(eval('Decimal(10) != E()'), 'ne 10')
508
509 # insert operator methods and then exercise them
Georg Brandl96c3f7f2006-03-28 08:06:35 +0000510 oplist = [
511 ('+', '__add__', '__radd__'),
512 ('-', '__sub__', '__rsub__'),
513 ('*', '__mul__', '__rmul__'),
514 ('%', '__mod__', '__rmod__'),
515 ('//', '__floordiv__', '__rfloordiv__'),
516 ('**', '__pow__', '__rpow__')
517 ]
518 if 1/2 == 0:
519 # testing with classic division, so add __div__
520 oplist.append(('/', '__div__', '__rdiv__'))
521 else:
522 # testing with -Qnew, so add __truediv__
523 oplist.append(('/', '__truediv__', '__rtruediv__'))
Anthony Baxter4ef3a232006-03-30 12:59:11 +0000524
Georg Brandl96c3f7f2006-03-28 08:06:35 +0000525 for sym, lop, rop in oplist:
Raymond Hettinger267b8682005-03-27 10:47:39 +0000526 setattr(E, lop, lambda self, other: 'str' + lop + str(other))
527 setattr(E, rop, lambda self, other: str(other) + rop + 'str')
528 self.assertEqual(eval('E()' + sym + 'Decimal(10)'),
529 'str' + lop + '10')
530 self.assertEqual(eval('Decimal(10)' + sym + 'E()'),
531 '10' + rop + 'str')
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000532
533class DecimalArithmeticOperatorsTest(unittest.TestCase):
534 '''Unit tests for all arithmetic operators, binary and unary.'''
535
536 def test_addition(self):
537
538 d1 = Decimal('-11.1')
539 d2 = Decimal('22.2')
540
541 #two Decimals
542 self.assertEqual(d1+d2, Decimal('11.1'))
543 self.assertEqual(d2+d1, Decimal('11.1'))
544
545 #with other type, left
546 c = d1 + 5
547 self.assertEqual(c, Decimal('-6.1'))
548 self.assertEqual(type(c), type(d1))
549
550 #with other type, right
551 c = 5 + d1
552 self.assertEqual(c, Decimal('-6.1'))
553 self.assertEqual(type(c), type(d1))
554
555 #inline with decimal
556 d1 += d2
557 self.assertEqual(d1, Decimal('11.1'))
558
559 #inline with other type
560 d1 += 5
561 self.assertEqual(d1, Decimal('16.1'))
562
563 def test_subtraction(self):
564
565 d1 = Decimal('-11.1')
566 d2 = Decimal('22.2')
567
568 #two Decimals
569 self.assertEqual(d1-d2, Decimal('-33.3'))
570 self.assertEqual(d2-d1, Decimal('33.3'))
571
572 #with other type, left
573 c = d1 - 5
574 self.assertEqual(c, Decimal('-16.1'))
575 self.assertEqual(type(c), type(d1))
576
577 #with other type, right
578 c = 5 - d1
579 self.assertEqual(c, Decimal('16.1'))
580 self.assertEqual(type(c), type(d1))
581
582 #inline with decimal
583 d1 -= d2
584 self.assertEqual(d1, Decimal('-33.3'))
585
586 #inline with other type
587 d1 -= 5
588 self.assertEqual(d1, Decimal('-38.3'))
589
590 def test_multiplication(self):
591
592 d1 = Decimal('-5')
593 d2 = Decimal('3')
594
595 #two Decimals
596 self.assertEqual(d1*d2, Decimal('-15'))
597 self.assertEqual(d2*d1, Decimal('-15'))
598
599 #with other type, left
600 c = d1 * 5
601 self.assertEqual(c, Decimal('-25'))
602 self.assertEqual(type(c), type(d1))
603
604 #with other type, right
605 c = 5 * d1
606 self.assertEqual(c, Decimal('-25'))
607 self.assertEqual(type(c), type(d1))
608
609 #inline with decimal
610 d1 *= d2
611 self.assertEqual(d1, Decimal('-15'))
612
613 #inline with other type
614 d1 *= 5
615 self.assertEqual(d1, Decimal('-75'))
616
617 def test_division(self):
618
619 d1 = Decimal('-5')
620 d2 = Decimal('2')
621
622 #two Decimals
623 self.assertEqual(d1/d2, Decimal('-2.5'))
624 self.assertEqual(d2/d1, Decimal('-0.4'))
625
626 #with other type, left
627 c = d1 / 4
628 self.assertEqual(c, Decimal('-1.25'))
629 self.assertEqual(type(c), type(d1))
630
631 #with other type, right
632 c = 4 / d1
633 self.assertEqual(c, Decimal('-0.8'))
634 self.assertEqual(type(c), type(d1))
635
636 #inline with decimal
637 d1 /= d2
638 self.assertEqual(d1, Decimal('-2.5'))
639
640 #inline with other type
641 d1 /= 4
642 self.assertEqual(d1, Decimal('-0.625'))
643
644 def test_floor_division(self):
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000645
646 d1 = Decimal('5')
647 d2 = Decimal('2')
648
649 #two Decimals
650 self.assertEqual(d1//d2, Decimal('2'))
651 self.assertEqual(d2//d1, Decimal('0'))
652
653 #with other type, left
654 c = d1 // 4
655 self.assertEqual(c, Decimal('1'))
656 self.assertEqual(type(c), type(d1))
657
658 #with other type, right
659 c = 7 // d1
660 self.assertEqual(c, Decimal('1'))
661 self.assertEqual(type(c), type(d1))
662
663 #inline with decimal
664 d1 //= d2
665 self.assertEqual(d1, Decimal('2'))
666
667 #inline with other type
668 d1 //= 2
669 self.assertEqual(d1, Decimal('1'))
670
671 def test_powering(self):
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000672
673 d1 = Decimal('5')
674 d2 = Decimal('2')
675
676 #two Decimals
677 self.assertEqual(d1**d2, Decimal('25'))
678 self.assertEqual(d2**d1, Decimal('32'))
679
680 #with other type, left
681 c = d1 ** 4
682 self.assertEqual(c, Decimal('625'))
683 self.assertEqual(type(c), type(d1))
684
685 #with other type, right
686 c = 7 ** d1
687 self.assertEqual(c, Decimal('16807'))
688 self.assertEqual(type(c), type(d1))
689
690 #inline with decimal
691 d1 **= d2
692 self.assertEqual(d1, Decimal('25'))
693
694 #inline with other type
695 d1 **= 4
696 self.assertEqual(d1, Decimal('390625'))
697
698 def test_module(self):
699
700 d1 = Decimal('5')
701 d2 = Decimal('2')
702
703 #two Decimals
704 self.assertEqual(d1%d2, Decimal('1'))
705 self.assertEqual(d2%d1, Decimal('2'))
706
707 #with other type, left
708 c = d1 % 4
709 self.assertEqual(c, Decimal('1'))
710 self.assertEqual(type(c), type(d1))
711
712 #with other type, right
713 c = 7 % d1
714 self.assertEqual(c, Decimal('2'))
715 self.assertEqual(type(c), type(d1))
716
717 #inline with decimal
718 d1 %= d2
719 self.assertEqual(d1, Decimal('1'))
720
721 #inline with other type
722 d1 %= 4
723 self.assertEqual(d1, Decimal('1'))
724
725 def test_floor_div_module(self):
726
727 d1 = Decimal('5')
728 d2 = Decimal('2')
729
730 #two Decimals
731 (p, q) = divmod(d1, d2)
732 self.assertEqual(p, Decimal('2'))
733 self.assertEqual(q, Decimal('1'))
734 self.assertEqual(type(p), type(d1))
735 self.assertEqual(type(q), type(d1))
736
737 #with other type, left
738 (p, q) = divmod(d1, 4)
739 self.assertEqual(p, Decimal('1'))
740 self.assertEqual(q, Decimal('1'))
741 self.assertEqual(type(p), type(d1))
742 self.assertEqual(type(q), type(d1))
743
744 #with other type, right
745 (p, q) = divmod(7, d1)
746 self.assertEqual(p, Decimal('1'))
747 self.assertEqual(q, Decimal('2'))
748 self.assertEqual(type(p), type(d1))
749 self.assertEqual(type(q), type(d1))
750
751 def test_unary_operators(self):
752 self.assertEqual(+Decimal(45), Decimal(+45)) # +
753 self.assertEqual(-Decimal(45), Decimal(-45)) # -
754 self.assertEqual(abs(Decimal(45)), abs(Decimal(-45))) # abs
755
756
757# The following are two functions used to test threading in the next class
758
759def thfunc1(cls):
760 d1 = Decimal(1)
761 d3 = Decimal(3)
762 cls.assertEqual(d1/d3, Decimal('0.333333333'))
763 cls.synchro.wait()
764 cls.assertEqual(d1/d3, Decimal('0.333333333'))
765 cls.finish1.set()
766 return
767
768def thfunc2(cls):
769 d1 = Decimal(1)
770 d3 = Decimal(3)
771 cls.assertEqual(d1/d3, Decimal('0.333333333'))
772 thiscontext = getcontext()
773 thiscontext.prec = 18
774 cls.assertEqual(d1/d3, Decimal('0.333333333333333333'))
775 cls.synchro.set()
776 cls.finish2.set()
777 return
778
779
780class DecimalUseOfContextTest(unittest.TestCase):
781 '''Unit tests for Use of Context cases in Decimal.'''
782
Raymond Hettinger7e71fa52004-12-18 19:07:19 +0000783 try:
784 import threading
785 except ImportError:
786 threading = None
787
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000788 # Take care executing this test from IDLE, there's an issue in threading
789 # that hangs IDLE and I couldn't find it
790
791 def test_threading(self):
792 #Test the "threading isolation" of a Context.
793
794 self.synchro = threading.Event()
795 self.finish1 = threading.Event()
796 self.finish2 = threading.Event()
797
798 th1 = threading.Thread(target=thfunc1, args=(self,))
799 th2 = threading.Thread(target=thfunc2, args=(self,))
800
801 th1.start()
802 th2.start()
803
804 self.finish1.wait()
805 self.finish1.wait()
806 return
807
Raymond Hettinger7e71fa52004-12-18 19:07:19 +0000808 if threading is None:
809 del test_threading
810
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000811
812class DecimalUsabilityTest(unittest.TestCase):
813 '''Unit tests for Usability cases of Decimal.'''
814
815 def test_comparison_operators(self):
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000816
817 da = Decimal('23.42')
818 db = Decimal('23.42')
819 dc = Decimal('45')
820
821 #two Decimals
822 self.failUnless(dc > da)
823 self.failUnless(dc >= da)
824 self.failUnless(da < dc)
825 self.failUnless(da <= dc)
826 self.failUnless(da == db)
827 self.failUnless(da != dc)
828 self.failUnless(da <= db)
829 self.failUnless(da >= db)
830 self.assertEqual(cmp(dc,da), 1)
831 self.assertEqual(cmp(da,dc), -1)
832 self.assertEqual(cmp(da,db), 0)
833
834 #a Decimal and an int
835 self.failUnless(dc > 23)
836 self.failUnless(23 < dc)
837 self.failUnless(dc == 45)
838 self.assertEqual(cmp(dc,23), 1)
839 self.assertEqual(cmp(23,dc), -1)
840 self.assertEqual(cmp(dc,45), 0)
841
842 #a Decimal and uncomparable
Raymond Hettinger0aeac102004-07-05 22:53:03 +0000843 self.assertNotEqual(da, 'ugly')
844 self.assertNotEqual(da, 32.7)
845 self.assertNotEqual(da, object())
846 self.assertNotEqual(da, object)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000847
Raymond Hettinger0aeac102004-07-05 22:53:03 +0000848 # sortable
849 a = map(Decimal, xrange(100))
850 b = a[:]
851 random.shuffle(a)
852 a.sort()
853 self.assertEqual(a, b)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000854
855 def test_copy_and_deepcopy_methods(self):
856 d = Decimal('43.24')
857 c = copy.copy(d)
858 self.assertEqual(id(c), id(d))
859 dc = copy.deepcopy(d)
860 self.assertEqual(id(dc), id(d))
861
862 def test_hash_method(self):
863 #just that it's hashable
864 hash(Decimal(23))
865 #the same hash that to an int
866 self.assertEqual(hash(Decimal(23)), hash(23))
Raymond Hettingerbea3f6f2005-03-15 04:59:17 +0000867 self.assertRaises(TypeError, hash, Decimal('NaN'))
868 self.assert_(hash(Decimal('Inf')))
869 self.assert_(hash(Decimal('-Inf')))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000870
871 def test_min_and_max_methods(self):
872
873 d1 = Decimal('15.32')
874 d2 = Decimal('28.5')
875 l1 = 15
876 l2 = 28
877
878 #between Decimals
879 self.failUnless(min(d1,d2) is d1)
880 self.failUnless(min(d2,d1) is d1)
881 self.failUnless(max(d1,d2) is d2)
882 self.failUnless(max(d2,d1) is d2)
883
884 #between Decimal and long
885 self.failUnless(min(d1,l2) is d1)
886 self.failUnless(min(l2,d1) is d1)
887 self.failUnless(max(l1,d2) is d2)
888 self.failUnless(max(d2,l1) is d2)
889
890 def test_as_nonzero(self):
891 #as false
892 self.failIf(Decimal(0))
893 #as true
894 self.failUnless(Decimal('0.372'))
895
896 def test_tostring_methods(self):
897 #Test str and repr methods.
898
899 d = Decimal('15.32')
900 self.assertEqual(str(d), '15.32') # str
901 self.assertEqual(repr(d), 'Decimal("15.32")') # repr
902
903 def test_tonum_methods(self):
904 #Test float, int and long methods.
905
906 d1 = Decimal('66')
907 d2 = Decimal('15.32')
908
909 #int
910 self.assertEqual(int(d1), 66)
911 self.assertEqual(int(d2), 15)
912
913 #long
914 self.assertEqual(long(d1), 66)
915 self.assertEqual(long(d2), 15)
916
917 #float
918 self.assertEqual(float(d1), 66)
919 self.assertEqual(float(d2), 15.32)
920
921 def test_eval_round_trip(self):
922
923 #with zero
924 d = Decimal( (0, (0,), 0) )
925 self.assertEqual(d, eval(repr(d)))
926
927 #int
928 d = Decimal( (1, (4, 5), 0) )
929 self.assertEqual(d, eval(repr(d)))
930
931 #float
932 d = Decimal( (0, (4, 5, 3, 4), -2) )
933 self.assertEqual(d, eval(repr(d)))
934
935 #weird
936 d = Decimal( (1, (4, 3, 4, 9, 1, 3, 5, 3, 4), -25) )
937 self.assertEqual(d, eval(repr(d)))
938
939 def test_as_tuple(self):
940
941 #with zero
942 d = Decimal(0)
943 self.assertEqual(d.as_tuple(), (0, (0,), 0) )
944
945 #int
946 d = Decimal(-45)
947 self.assertEqual(d.as_tuple(), (1, (4, 5), 0) )
948
949 #complicated string
950 d = Decimal("-4.34913534E-17")
951 self.assertEqual(d.as_tuple(), (1, (4, 3, 4, 9, 1, 3, 5, 3, 4), -25) )
952
953 #inf
954 d = Decimal("Infinity")
955 self.assertEqual(d.as_tuple(), (0, (0,), 'F') )
956
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000957 def test_immutability_operations(self):
958 # Do operations and check that it didn't change change internal objects.
959
960 d1 = Decimal('-25e55')
961 b1 = Decimal('-25e55')
962 d2 = Decimal('33e-33')
963 b2 = Decimal('33e-33')
964
965 def checkSameDec(operation, useOther=False):
966 if useOther:
967 eval("d1." + operation + "(d2)")
968 self.assertEqual(d1._sign, b1._sign)
969 self.assertEqual(d1._int, b1._int)
970 self.assertEqual(d1._exp, b1._exp)
971 self.assertEqual(d2._sign, b2._sign)
972 self.assertEqual(d2._int, b2._int)
973 self.assertEqual(d2._exp, b2._exp)
974 else:
975 eval("d1." + operation + "()")
976 self.assertEqual(d1._sign, b1._sign)
977 self.assertEqual(d1._int, b1._int)
978 self.assertEqual(d1._exp, b1._exp)
979 return
980
981 Decimal(d1)
982 self.assertEqual(d1._sign, b1._sign)
983 self.assertEqual(d1._int, b1._int)
984 self.assertEqual(d1._exp, b1._exp)
985
986 checkSameDec("__abs__")
987 checkSameDec("__add__", True)
988 checkSameDec("__div__", True)
989 checkSameDec("__divmod__", True)
990 checkSameDec("__cmp__", True)
991 checkSameDec("__float__")
992 checkSameDec("__floordiv__", True)
993 checkSameDec("__hash__")
994 checkSameDec("__int__")
995 checkSameDec("__long__")
996 checkSameDec("__mod__", True)
997 checkSameDec("__mul__", True)
998 checkSameDec("__neg__")
999 checkSameDec("__nonzero__")
1000 checkSameDec("__pos__")
1001 checkSameDec("__pow__", True)
1002 checkSameDec("__radd__", True)
1003 checkSameDec("__rdiv__", True)
1004 checkSameDec("__rdivmod__", True)
1005 checkSameDec("__repr__")
1006 checkSameDec("__rfloordiv__", True)
1007 checkSameDec("__rmod__", True)
1008 checkSameDec("__rmul__", True)
1009 checkSameDec("__rpow__", True)
1010 checkSameDec("__rsub__", True)
1011 checkSameDec("__str__")
1012 checkSameDec("__sub__", True)
1013 checkSameDec("__truediv__", True)
1014 checkSameDec("adjusted")
1015 checkSameDec("as_tuple")
1016 checkSameDec("compare", True)
1017 checkSameDec("max", True)
1018 checkSameDec("min", True)
1019 checkSameDec("normalize")
1020 checkSameDec("quantize", True)
1021 checkSameDec("remainder_near", True)
1022 checkSameDec("same_quantum", True)
1023 checkSameDec("sqrt")
1024 checkSameDec("to_eng_string")
1025 checkSameDec("to_integral")
1026
1027class DecimalPythonAPItests(unittest.TestCase):
1028
1029 def test_pickle(self):
1030 d = Decimal('-3.141590000')
1031 p = pickle.dumps(d)
1032 e = pickle.loads(p)
1033 self.assertEqual(d, e)
1034
Raymond Hettinger5548be22004-07-05 18:49:38 +00001035 def test_int(self):
Raymond Hettinger605ed022004-11-24 07:28:48 +00001036 for x in range(-250, 250):
1037 s = '%0.2f' % (x / 100.0)
Raymond Hettinger5548be22004-07-05 18:49:38 +00001038 # should work the same as for floats
1039 self.assertEqual(int(Decimal(s)), int(float(s)))
Raymond Hettinger605ed022004-11-24 07:28:48 +00001040 # should work the same as to_integral in the ROUND_DOWN mode
Raymond Hettinger5548be22004-07-05 18:49:38 +00001041 d = Decimal(s)
Raymond Hettinger605ed022004-11-24 07:28:48 +00001042 r = d.to_integral(ROUND_DOWN)
Raymond Hettinger5548be22004-07-05 18:49:38 +00001043 self.assertEqual(Decimal(int(d)), r)
1044
Raymond Hettingerd9c0a7a2004-07-03 10:02:28 +00001045class ContextAPItests(unittest.TestCase):
1046
1047 def test_pickle(self):
1048 c = Context()
1049 e = pickle.loads(pickle.dumps(c))
1050 for k in vars(c):
1051 v1 = vars(c)[k]
1052 v2 = vars(e)[k]
1053 self.assertEqual(v1, v2)
1054
Raymond Hettinger0aeac102004-07-05 22:53:03 +00001055 def test_equality_with_other_types(self):
1056 self.assert_(Decimal(10) in ['a', 1.0, Decimal(10), (1,2), {}])
1057 self.assert_(Decimal(10) not in ['a', 1.0, (1,2), {}])
1058
Raymond Hettinger955d2b22004-08-08 20:17:45 +00001059 def test_copy(self):
1060 # All copies should be deep
1061 c = Context()
1062 d = c.copy()
1063 self.assertNotEqual(id(c), id(d))
1064 self.assertNotEqual(id(c.flags), id(d.flags))
1065 self.assertNotEqual(id(c.traps), id(d.traps))
1066
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001067def test_main(arith=False, verbose=None):
1068 """ Execute the tests.
1069
Raymond Hettingered20ad82004-09-04 20:09:13 +00001070 Runs all arithmetic tests if arith is True or if the "decimal" resource
1071 is enabled in regrtest.py
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001072 """
Raymond Hettingered20ad82004-09-04 20:09:13 +00001073
Neal Norwitzce4a9c92006-04-09 08:36:46 +00001074 init()
Raymond Hettingered20ad82004-09-04 20:09:13 +00001075 global TEST_ALL
1076 TEST_ALL = arith or is_resource_enabled('decimal')
1077
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001078 test_classes = [
1079 DecimalExplicitConstructionTest,
1080 DecimalImplicitConstructionTest,
1081 DecimalArithmeticOperatorsTest,
1082 DecimalUseOfContextTest,
1083 DecimalUsabilityTest,
1084 DecimalPythonAPItests,
Raymond Hettingerd9c0a7a2004-07-03 10:02:28 +00001085 ContextAPItests,
Raymond Hettingered20ad82004-09-04 20:09:13 +00001086 DecimalTest,
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001087 ]
1088
Tim Peters46cc7022006-03-31 04:11:16 +00001089 try:
1090 run_unittest(*test_classes)
1091 import decimal as DecimalModule
1092 run_doctest(DecimalModule, verbose)
1093 finally:
1094 setcontext(ORIGINAL_CONTEXT)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001095
1096if __name__ == '__main__':
1097 # Calling with no arguments runs all tests.
Raymond Hettingered20ad82004-09-04 20:09:13 +00001098 # Calling with "Skip" will skip over 90% of the arithmetic tests.
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001099 if len(sys.argv) == 1:
1100 test_main(arith=True, verbose=True)
1101 elif len(sys.argv) == 2:
1102 arith = sys.argv[1].lower() != 'skip'
1103 test_main(arith=arith, verbose=True)
1104 else:
1105 raise ValueError("test called with wrong arguments, use test_Decimal [Skip]")