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