blob: a76b505bfec73ef55508de7594448b0433b9ddd9 [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"""
Thomas Wouters89f507f2006-12-13 04:49:30 +000026from __future__ import with_statement
Raymond Hettinger7c85fa42004-07-01 11:01:35 +000027
Raymond Hettinger7c85fa42004-07-01 11:01:35 +000028import glob
Christian Heimes400adb02008-02-01 08:12:03 +000029import math
Raymond Hettinger7c85fa42004-07-01 11:01:35 +000030import os, sys
31import pickle, copy
Christian Heimes400adb02008-02-01 08:12:03 +000032import unittest
Raymond Hettinger7c85fa42004-07-01 11:01:35 +000033from decimal import *
Thomas Wouters49fd7fa2006-04-21 10:40:58 +000034from test.test_support import (TestSkipped, run_unittest, run_doctest,
35 is_resource_enabled)
Raymond Hettinger0aeac102004-07-05 22:53:03 +000036import random
Raymond Hettinger7e71fa52004-12-18 19:07:19 +000037try:
38 import threading
39except ImportError:
40 threading = None
Raymond Hettinger7c85fa42004-07-01 11:01:35 +000041
Raymond Hettingerfed52962004-07-14 15:41:57 +000042# Useful Test Constant
Guido van Rossumc1f779c2007-07-03 08:25:58 +000043Signals = tuple(getcontext().flags.keys())
Raymond Hettingerfed52962004-07-14 15:41:57 +000044
Thomas Wouters49fd7fa2006-04-21 10:40:58 +000045# Tests are built around these assumed context defaults.
46# test_main() restores the original context.
47def init():
48 global ORIGINAL_CONTEXT
49 ORIGINAL_CONTEXT = getcontext().copy()
50 DefaultContext.prec = 9
51 DefaultContext.rounding = ROUND_HALF_EVEN
52 DefaultContext.traps = dict.fromkeys(Signals, 0)
53 setcontext(DefaultContext)
Raymond Hettinger6ea48452004-07-03 12:26:21 +000054
Raymond Hettinger7c85fa42004-07-01 11:01:35 +000055TESTDATADIR = 'decimaltestdata'
Raymond Hettingerd9c0a7a2004-07-03 10:02:28 +000056if __name__ == '__main__':
57 file = sys.argv[0]
58else:
59 file = __file__
60testdir = os.path.dirname(file) or os.curdir
Raymond Hettinger267b8682005-03-27 10:47:39 +000061directory = testdir + os.sep + TESTDATADIR + os.sep
Raymond Hettinger7c85fa42004-07-01 11:01:35 +000062
Raymond Hettinger267b8682005-03-27 10:47:39 +000063skip_expected = not os.path.isdir(directory)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +000064
65# Make sure it actually raises errors when not expected and caught in flags
66# Slower, since it runs some things several times.
67EXTENDEDERRORTEST = False
68
Raymond Hettinger7c85fa42004-07-01 11:01:35 +000069#Map the test cases' error names to the actual errors
Raymond Hettinger7c85fa42004-07-01 11:01:35 +000070ErrorNames = {'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,
Thomas Wouters1b7f8912007-09-19 03:06:30 +000094 'up' : ROUND_UP,
95 '05up' : ROUND_05UP}
Raymond Hettinger7c85fa42004-07-01 11:01:35 +000096
97# Name adapter to be able to change the Decimal and Context
98# interface without changing the test files from Cowlishaw
Guido van Rossum8ce8a782007-11-01 19:42:39 +000099nameAdapter = {'and':'logical_and',
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000100 'apply':'_apply',
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000101 'class':'number_class',
102 'comparesig':'compare_signal',
103 'comparetotal':'compare_total',
104 'comparetotmag':'compare_total_mag',
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000105 'copy':'copy_decimal',
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000106 'copyabs':'copy_abs',
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000107 'copynegate':'copy_negate',
108 'copysign':'copy_sign',
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000109 'divideint':'divide_int',
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000110 'invert':'logical_invert',
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000111 'iscanonical':'is_canonical',
112 'isfinite':'is_finite',
113 'isinfinite':'is_infinite',
114 'isnan':'is_nan',
115 'isnormal':'is_normal',
116 'isqnan':'is_qnan',
117 'issigned':'is_signed',
118 'issnan':'is_snan',
119 'issubnormal':'is_subnormal',
120 'iszero':'is_zero',
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000121 'maxmag':'max_mag',
122 'minmag':'min_mag',
123 'nextminus':'next_minus',
124 'nextplus':'next_plus',
125 'nexttoward':'next_toward',
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000126 'or':'logical_or',
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000127 'reduce':'normalize',
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000128 'remaindernear':'remainder_near',
129 'samequantum':'same_quantum',
130 'squareroot':'sqrt',
131 'toeng':'to_eng_string',
132 'tointegral':'to_integral_value',
133 'tointegralx':'to_integral_exact',
134 'tosci':'to_sci_string',
135 'xor':'logical_xor',
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000136 }
137
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000138# The following functions return True/False rather than a Decimal instance
139
140LOGICAL_FUNCTIONS = (
141 'is_canonical',
142 'is_finite',
143 'is_infinite',
144 'is_nan',
145 'is_normal',
146 'is_qnan',
147 'is_signed',
148 'is_snan',
149 'is_subnormal',
150 'is_zero',
151 'same_quantum',
152 )
153
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000154# For some operations (currently exp, ln, log10, power), the decNumber
155# reference implementation imposes additional restrictions on the
156# context and operands. These restrictions are not part of the
157# specification; however, the effect of these restrictions does show
158# up in some of the testcases. We skip testcases that violate these
159# restrictions, since Decimal behaves differently from decNumber for
160# these testcases so these testcases would otherwise fail.
161
162decNumberRestricted = ('power', 'ln', 'log10', 'exp')
163DEC_MAX_MATH = 999999
164def outside_decNumber_bounds(v, context):
165 if (context.prec > DEC_MAX_MATH or
166 context.Emax > DEC_MAX_MATH or
167 -context.Emin > DEC_MAX_MATH):
168 return True
169 if not v._is_special and v and (
170 len(v._int) > DEC_MAX_MATH or
171 v.adjusted() > DEC_MAX_MATH or
172 v.adjusted() < 1-2*DEC_MAX_MATH):
173 return True
174 return False
175
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000176class DecimalTest(unittest.TestCase):
177 """Class which tests the Decimal class against the test cases.
178
179 Changed for unittest.
180 """
181 def setUp(self):
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000182 self.context = Context()
Raymond Hettingerbf440692004-07-10 14:14:37 +0000183 for key in DefaultContext.traps.keys():
184 DefaultContext.traps[key] = 1
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000185 self.ignore_list = ['#']
186 # Basically, a # means return NaN InvalidOperation.
187 # Different from a sNaN in trim
188
189 self.ChangeDict = {'precision' : self.change_precision,
190 'rounding' : self.change_rounding_method,
191 'maxexponent' : self.change_max_exponent,
192 'minexponent' : self.change_min_exponent,
193 'clamp' : self.change_clamp}
194
195 def tearDown(self):
196 """Cleaning up enviroment."""
197 # leaving context in original state
Raymond Hettingerbf440692004-07-10 14:14:37 +0000198 for key in DefaultContext.traps.keys():
199 DefaultContext.traps[key] = 0
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000200 return
201
202 def eval_file(self, file):
203 global skip_expected
204 if skip_expected:
205 raise TestSkipped
206 return
Neal Norwitz70967602006-03-17 08:29:44 +0000207 for line in open(file):
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000208 line = line.replace('\r\n', '').replace('\n', '')
Raymond Hettinger5aa478b2004-07-09 10:02:53 +0000209 #print line
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000210 try:
211 t = self.eval_line(line)
Guido van Rossumb940e112007-01-10 16:19:56 +0000212 except DecimalException as exception:
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000213 #Exception raised where there shoudn't have been one.
214 self.fail('Exception "'+exception.__class__.__name__ + '" raised on line '+line)
215
216 return
217
218 def eval_line(self, s):
219 if s.find(' -> ') >= 0 and s[:2] != '--' and not s.startswith(' --'):
220 s = (s.split('->')[0] + '->' +
221 s.split('->')[1].split('--')[0]).strip()
222 else:
223 s = s.split('--')[0].strip()
224
225 for ignore in self.ignore_list:
226 if s.find(ignore) >= 0:
227 #print s.split()[0], 'NotImplemented--', ignore
228 return
229 if not s:
230 return
231 elif ':' in s:
232 return self.eval_directive(s)
233 else:
234 return self.eval_equation(s)
235
236 def eval_directive(self, s):
Guido van Rossumc1f779c2007-07-03 08:25:58 +0000237 funct, value = (x.strip().lower() for x in s.split(':'))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000238 if funct == 'rounding':
239 value = RoundingDict[value]
240 else:
241 try:
242 value = int(value)
243 except ValueError:
244 pass
245
246 funct = self.ChangeDict.get(funct, Nonfunction)
247 funct(value)
248
249 def eval_equation(self, s):
250 #global DEFAULT_PRECISION
251 #print DEFAULT_PRECISION
Raymond Hettingered20ad82004-09-04 20:09:13 +0000252
253 if not TEST_ALL and random.random() < 0.90:
254 return
255
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000256 try:
257 Sides = s.split('->')
258 L = Sides[0].strip().split()
259 id = L[0]
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000260 if DEBUG:
261 print("Test ", id, end=" ")
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000262 funct = L[1].lower()
263 valstemp = L[2:]
264 L = Sides[1].strip().split()
265 ans = L[0]
266 exceptions = L[1:]
267 except (TypeError, AttributeError, IndexError):
Raymond Hettingerd87ac8f2004-07-09 10:52:54 +0000268 raise InvalidOperation
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000269 def FixQuotes(val):
270 val = val.replace("''", 'SingleQuote').replace('""', 'DoubleQuote')
271 val = val.replace("'", '').replace('"', '')
272 val = val.replace('SingleQuote', "'").replace('DoubleQuote', '"')
273 return val
274 fname = nameAdapter.get(funct, funct)
275 if fname == 'rescale':
276 return
277 funct = getattr(self.context, fname)
278 vals = []
279 conglomerate = ''
280 quote = 0
281 theirexceptions = [ErrorNames[x.lower()] for x in exceptions]
282
Raymond Hettingerd9c0a7a2004-07-03 10:02:28 +0000283 for exception in Signals:
Raymond Hettingerbf440692004-07-10 14:14:37 +0000284 self.context.traps[exception] = 1 #Catch these bugs...
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000285 for exception in theirexceptions:
Raymond Hettingerbf440692004-07-10 14:14:37 +0000286 self.context.traps[exception] = 0
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000287 for i, val in enumerate(valstemp):
288 if val.count("'") % 2 == 1:
289 quote = 1 - quote
290 if quote:
291 conglomerate = conglomerate + ' ' + val
292 continue
293 else:
294 val = conglomerate + val
295 conglomerate = ''
296 v = FixQuotes(val)
297 if fname in ('to_sci_string', 'to_eng_string'):
298 if EXTENDEDERRORTEST:
299 for error in theirexceptions:
Raymond Hettingerbf440692004-07-10 14:14:37 +0000300 self.context.traps[error] = 1
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000301 try:
302 funct(self.context.create_decimal(v))
303 except error:
304 pass
Guido van Rossumb940e112007-01-10 16:19:56 +0000305 except Signals as e:
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000306 self.fail("Raised %s in %s when %s disabled" % \
307 (e, s, error))
308 else:
309 self.fail("Did not raise %s in %s" % (error, s))
Raymond Hettingerbf440692004-07-10 14:14:37 +0000310 self.context.traps[error] = 0
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000311 v = self.context.create_decimal(v)
312 else:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000313 v = Decimal(v, self.context)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000314 vals.append(v)
315
316 ans = FixQuotes(ans)
317
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000318 # skip tests that are related to bounds imposed in the decNumber
319 # reference implementation
320 if fname in decNumberRestricted:
321 if fname == 'power':
322 if not (vals[1]._isinteger() and
323 -1999999997 <= vals[1] <= 999999999):
324 if outside_decNumber_bounds(vals[0], self.context) or \
325 outside_decNumber_bounds(vals[1], self.context):
326 #print "Skipping test %s" % s
327 return
328 else:
329 if outside_decNumber_bounds(vals[0], self.context):
330 #print "Skipping test %s" % s
331 return
332
333
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000334 if EXTENDEDERRORTEST and fname not in ('to_sci_string', 'to_eng_string'):
335 for error in theirexceptions:
Raymond Hettingerbf440692004-07-10 14:14:37 +0000336 self.context.traps[error] = 1
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000337 try:
338 funct(*vals)
339 except error:
340 pass
Guido van Rossumb940e112007-01-10 16:19:56 +0000341 except Signals as e:
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000342 self.fail("Raised %s in %s when %s disabled" % \
343 (e, s, error))
344 else:
345 self.fail("Did not raise %s in %s" % (error, s))
Raymond Hettingerbf440692004-07-10 14:14:37 +0000346 self.context.traps[error] = 0
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000347 if DEBUG:
348 print("--", self.context)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000349 try:
350 result = str(funct(*vals))
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000351 if fname in LOGICAL_FUNCTIONS:
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000352 result = str(int(eval(result))) # 'True', 'False' -> '1', '0'
Guido van Rossumb940e112007-01-10 16:19:56 +0000353 except Signals as error:
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000354 self.fail("Raised %s in %s" % (error, s))
355 except: #Catch any error long enough to state the test case.
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000356 print("ERROR:", s)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000357 raise
358
359 myexceptions = self.getexceptions()
Raymond Hettingerbf440692004-07-10 14:14:37 +0000360 self.context.clear_flags()
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000361
Guido van Rossum47b9ff62006-08-24 00:41:19 +0000362 myexceptions.sort(key=repr)
363 theirexceptions.sort(key=repr)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000364
365 self.assertEqual(result, ans,
366 'Incorrect answer for ' + s + ' -- got ' + result)
367 self.assertEqual(myexceptions, theirexceptions,
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000368 'Incorrect flags set in ' + s + ' -- got ' + str(myexceptions))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000369 return
370
371 def getexceptions(self):
Raymond Hettingerf63ba432004-08-17 05:42:09 +0000372 return [e for e in Signals if self.context.flags[e]]
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000373
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000374 def change_precision(self, prec):
375 self.context.prec = prec
376 def change_rounding_method(self, rounding):
377 self.context.rounding = rounding
378 def change_min_exponent(self, exp):
379 self.context.Emin = exp
380 def change_max_exponent(self, exp):
381 self.context.Emax = exp
382 def change_clamp(self, clamp):
383 self.context._clamp = clamp
384
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000385
386
387# The following classes test the behaviour of Decimal according to PEP 327
388
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000389class DecimalExplicitConstructionTest(unittest.TestCase):
390 '''Unit tests for Explicit Construction cases of Decimal.'''
391
392 def test_explicit_empty(self):
393 self.assertEqual(Decimal(), Decimal("0"))
394
395 def test_explicit_from_None(self):
396 self.assertRaises(TypeError, Decimal, None)
397
398 def test_explicit_from_int(self):
399
400 #positive
401 d = Decimal(45)
402 self.assertEqual(str(d), '45')
403
404 #very large positive
405 d = Decimal(500000123)
406 self.assertEqual(str(d), '500000123')
407
408 #negative
409 d = Decimal(-45)
410 self.assertEqual(str(d), '-45')
411
412 #zero
413 d = Decimal(0)
414 self.assertEqual(str(d), '0')
415
416 def test_explicit_from_string(self):
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000417
418 #empty
419 self.assertEqual(str(Decimal('')), 'NaN')
420
421 #int
422 self.assertEqual(str(Decimal('45')), '45')
423
424 #float
425 self.assertEqual(str(Decimal('45.34')), '45.34')
426
427 #engineer notation
428 self.assertEqual(str(Decimal('45e2')), '4.5E+3')
429
430 #just not a number
431 self.assertEqual(str(Decimal('ugly')), 'NaN')
432
Christian Heimesa62da1d2008-01-12 19:39:10 +0000433 #leading and trailing whitespace permitted
434 self.assertEqual(str(Decimal('1.3E4 \n')), '1.3E+4')
435 self.assertEqual(str(Decimal(' -7.89')), '-7.89')
436
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000437 def test_explicit_from_tuples(self):
438
439 #zero
440 d = Decimal( (0, (0,), 0) )
441 self.assertEqual(str(d), '0')
442
443 #int
444 d = Decimal( (1, (4, 5), 0) )
445 self.assertEqual(str(d), '-45')
446
447 #float
448 d = Decimal( (0, (4, 5, 3, 4), -2) )
449 self.assertEqual(str(d), '45.34')
450
451 #weird
452 d = Decimal( (1, (4, 3, 4, 9, 1, 3, 5, 3, 4), -25) )
453 self.assertEqual(str(d), '-4.34913534E-17')
454
455 #wrong number of items
456 self.assertRaises(ValueError, Decimal, (1, (4, 3, 4, 9, 1)) )
457
458 #bad sign
459 self.assertRaises(ValueError, Decimal, (8, (4, 3, 4, 9, 1), 2) )
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000460 self.assertRaises(ValueError, Decimal, (0., (4, 3, 4, 9, 1), 2) )
461 self.assertRaises(ValueError, Decimal, (Decimal(1), (4, 3, 4, 9, 1), 2))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000462
463 #bad exp
464 self.assertRaises(ValueError, Decimal, (1, (4, 3, 4, 9, 1), 'wrong!') )
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000465 self.assertRaises(ValueError, Decimal, (1, (4, 3, 4, 9, 1), 0.) )
466 self.assertRaises(ValueError, Decimal, (1, (4, 3, 4, 9, 1), '1') )
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000467
468 #bad coefficients
469 self.assertRaises(ValueError, Decimal, (1, (4, 3, 4, None, 1), 2) )
470 self.assertRaises(ValueError, Decimal, (1, (4, -3, 4, 9, 1), 2) )
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000471 self.assertRaises(ValueError, Decimal, (1, (4, 10, 4, 9, 1), 2) )
Guido van Rossum0d3fb8a2007-11-26 23:23:18 +0000472 self.assertRaises(ValueError, Decimal, (1, (4, 3, 4, 'a', 1), 2) )
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000473
474 def test_explicit_from_Decimal(self):
475
476 #positive
477 d = Decimal(45)
478 e = Decimal(d)
479 self.assertEqual(str(e), '45')
480 self.assertNotEqual(id(d), id(e))
481
482 #very large positive
483 d = Decimal(500000123)
484 e = Decimal(d)
485 self.assertEqual(str(e), '500000123')
486 self.assertNotEqual(id(d), id(e))
487
488 #negative
489 d = Decimal(-45)
490 e = Decimal(d)
491 self.assertEqual(str(e), '-45')
492 self.assertNotEqual(id(d), id(e))
493
494 #zero
495 d = Decimal(0)
496 e = Decimal(d)
497 self.assertEqual(str(e), '0')
498 self.assertNotEqual(id(d), id(e))
499
500 def test_explicit_context_create_decimal(self):
501
502 nc = copy.copy(getcontext())
503 nc.prec = 3
504
505 # empty
Raymond Hettingerfed52962004-07-14 15:41:57 +0000506 d = Decimal()
507 self.assertEqual(str(d), '0')
508 d = nc.create_decimal()
509 self.assertEqual(str(d), '0')
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000510
511 # from None
512 self.assertRaises(TypeError, nc.create_decimal, None)
513
514 # from int
515 d = nc.create_decimal(456)
516 self.failUnless(isinstance(d, Decimal))
517 self.assertEqual(nc.create_decimal(45678),
518 nc.create_decimal('457E+2'))
519
520 # from string
521 d = Decimal('456789')
522 self.assertEqual(str(d), '456789')
523 d = nc.create_decimal('456789')
524 self.assertEqual(str(d), '4.57E+5')
Christian Heimesa62da1d2008-01-12 19:39:10 +0000525 # leading and trailing whitespace should result in a NaN;
526 # spaces are already checked in Cowlishaw's test-suite, so
527 # here we just check that a trailing newline results in a NaN
528 self.assertEqual(str(nc.create_decimal('3.14\n')), 'NaN')
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000529
530 # from tuples
531 d = Decimal( (1, (4, 3, 4, 9, 1, 3, 5, 3, 4), -25) )
532 self.assertEqual(str(d), '-4.34913534E-17')
533 d = nc.create_decimal( (1, (4, 3, 4, 9, 1, 3, 5, 3, 4), -25) )
534 self.assertEqual(str(d), '-4.35E-17')
535
536 # from Decimal
537 prevdec = Decimal(500000123)
538 d = Decimal(prevdec)
539 self.assertEqual(str(d), '500000123')
540 d = nc.create_decimal(prevdec)
541 self.assertEqual(str(d), '5.00E+8')
542
543
544class DecimalImplicitConstructionTest(unittest.TestCase):
545 '''Unit tests for Implicit Construction cases of Decimal.'''
546
547 def test_implicit_from_None(self):
548 self.assertRaises(TypeError, eval, 'Decimal(5) + None', globals())
549
550 def test_implicit_from_int(self):
551 #normal
552 self.assertEqual(str(Decimal(5) + 45), '50')
553 #exceeding precision
554 self.assertEqual(Decimal(5) + 123456789000, Decimal(123456789000))
555
556 def test_implicit_from_string(self):
557 self.assertRaises(TypeError, eval, 'Decimal(5) + "3"', globals())
558
559 def test_implicit_from_float(self):
560 self.assertRaises(TypeError, eval, 'Decimal(5) + 2.2', globals())
561
562 def test_implicit_from_Decimal(self):
563 self.assertEqual(Decimal(5) + Decimal(45), Decimal(50))
564
Raymond Hettinger267b8682005-03-27 10:47:39 +0000565 def test_rop(self):
566 # Allow other classes to be trained to interact with Decimals
567 class E:
568 def __divmod__(self, other):
569 return 'divmod ' + str(other)
570 def __rdivmod__(self, other):
571 return str(other) + ' rdivmod'
572 def __lt__(self, other):
573 return 'lt ' + str(other)
574 def __gt__(self, other):
575 return 'gt ' + str(other)
576 def __le__(self, other):
577 return 'le ' + str(other)
578 def __ge__(self, other):
579 return 'ge ' + str(other)
580 def __eq__(self, other):
581 return 'eq ' + str(other)
582 def __ne__(self, other):
583 return 'ne ' + str(other)
584
585 self.assertEqual(divmod(E(), Decimal(10)), 'divmod 10')
586 self.assertEqual(divmod(Decimal(10), E()), '10 rdivmod')
587 self.assertEqual(eval('Decimal(10) < E()'), 'gt 10')
588 self.assertEqual(eval('Decimal(10) > E()'), 'lt 10')
589 self.assertEqual(eval('Decimal(10) <= E()'), 'ge 10')
590 self.assertEqual(eval('Decimal(10) >= E()'), 'le 10')
591 self.assertEqual(eval('Decimal(10) == E()'), 'eq 10')
592 self.assertEqual(eval('Decimal(10) != E()'), 'ne 10')
593
594 # insert operator methods and then exercise them
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000595 oplist = [
596 ('+', '__add__', '__radd__'),
597 ('-', '__sub__', '__rsub__'),
598 ('*', '__mul__', '__rmul__'),
Thomas Woutersdcc6d322006-04-21 11:30:52 +0000599 ('/', '__truediv__', '__rtruediv__'),
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000600 ('%', '__mod__', '__rmod__'),
601 ('//', '__floordiv__', '__rfloordiv__'),
602 ('**', '__pow__', '__rpow__')
603 ]
Raymond Hettinger267b8682005-03-27 10:47:39 +0000604
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000605 for sym, lop, rop in oplist:
Raymond Hettinger267b8682005-03-27 10:47:39 +0000606 setattr(E, lop, lambda self, other: 'str' + lop + str(other))
607 setattr(E, rop, lambda self, other: str(other) + rop + 'str')
608 self.assertEqual(eval('E()' + sym + 'Decimal(10)'),
609 'str' + lop + '10')
610 self.assertEqual(eval('Decimal(10)' + sym + 'E()'),
611 '10' + rop + 'str')
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000612
Christian Heimesf16baeb2008-02-29 14:57:44 +0000613class DecimalFormatTest(unittest.TestCase):
614 '''Unit tests for the format function.'''
615 def test_formatting(self):
616 # triples giving a format, a Decimal, and the expected result
617 test_values = [
618 ('e', '0E-15', '0e-15'),
619 ('e', '2.3E-15', '2.3e-15'),
620 ('e', '2.30E+2', '2.30e+2'), # preserve significant zeros
621 ('e', '2.30000E-15', '2.30000e-15'),
622 ('e', '1.23456789123456789e40', '1.23456789123456789e+40'),
623 ('e', '1.5', '1.5e+0'),
624 ('e', '0.15', '1.5e-1'),
625 ('e', '0.015', '1.5e-2'),
626 ('e', '0.0000000000015', '1.5e-12'),
627 ('e', '15.0', '1.50e+1'),
628 ('e', '-15', '-1.5e+1'),
629 ('e', '0', '0e+0'),
630 ('e', '0E1', '0e+1'),
631 ('e', '0.0', '0e-1'),
632 ('e', '0.00', '0e-2'),
633 ('.6e', '0E-15', '0.000000e-9'),
634 ('.6e', '0', '0.000000e+6'),
635 ('.6e', '9.999999', '9.999999e+0'),
636 ('.6e', '9.9999999', '1.000000e+1'),
637 ('.6e', '-1.23e5', '-1.230000e+5'),
638 ('.6e', '1.23456789e-3', '1.234568e-3'),
639 ('f', '0', '0'),
640 ('f', '0.0', '0.0'),
641 ('f', '0E-2', '0.00'),
642 ('f', '0.00E-8', '0.0000000000'),
643 ('f', '0E1', '0'), # loses exponent information
644 ('f', '3.2E1', '32'),
645 ('f', '3.2E2', '320'),
646 ('f', '3.20E2', '320'),
647 ('f', '3.200E2', '320.0'),
648 ('f', '3.2E-6', '0.0000032'),
649 ('.6f', '0E-15', '0.000000'), # all zeros treated equally
650 ('.6f', '0E1', '0.000000'),
651 ('.6f', '0', '0.000000'),
652 ('.0f', '0', '0'), # no decimal point
653 ('.0f', '0e-2', '0'),
654 ('.0f', '3.14159265', '3'),
655 ('.1f', '3.14159265', '3.1'),
656 ('.4f', '3.14159265', '3.1416'),
657 ('.6f', '3.14159265', '3.141593'),
658 ('.7f', '3.14159265', '3.1415926'), # round-half-even!
659 ('.8f', '3.14159265', '3.14159265'),
660 ('.9f', '3.14159265', '3.141592650'),
661
662 ('g', '0', '0'),
663 ('g', '0.0', '0.0'),
664 ('g', '0E1', '0e+1'),
665 ('G', '0E1', '0E+1'),
666 ('g', '0E-5', '0.00000'),
667 ('g', '0E-6', '0.000000'),
668 ('g', '0E-7', '0e-7'),
669 ('g', '-0E2', '-0e+2'),
670 ('.0g', '3.14159265', '3'), # 0 sig fig -> 1 sig fig
671 ('.1g', '3.14159265', '3'),
672 ('.2g', '3.14159265', '3.1'),
673 ('.5g', '3.14159265', '3.1416'),
674 ('.7g', '3.14159265', '3.141593'),
675 ('.8g', '3.14159265', '3.1415926'), # round-half-even!
676 ('.9g', '3.14159265', '3.14159265'),
677 ('.10g', '3.14159265', '3.14159265'), # don't pad
678
679 ('%', '0E1', '0%'),
680 ('%', '0E0', '0%'),
681 ('%', '0E-1', '0%'),
682 ('%', '0E-2', '0%'),
683 ('%', '0E-3', '0.0%'),
684 ('%', '0E-4', '0.00%'),
685
686 ('.3%', '0', '0.000%'), # all zeros treated equally
687 ('.3%', '0E10', '0.000%'),
688 ('.3%', '0E-10', '0.000%'),
689 ('.3%', '2.34', '234.000%'),
690 ('.3%', '1.234567', '123.457%'),
691 ('.0%', '1.23', '123%'),
692
693 ('e', 'NaN', 'NaN'),
694 ('f', '-NaN123', '-NaN123'),
695 ('+g', 'NaN456', '+NaN456'),
696 ('.3e', 'Inf', 'Infinity'),
697 ('.16f', '-Inf', '-Infinity'),
698 ('.0g', '-sNaN', '-sNaN'),
699
700 ('', '1.00', '1.00'),
701 ]
702 for fmt, d, result in test_values:
703 self.assertEqual(format(Decimal(d), fmt), result)
704
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000705class DecimalArithmeticOperatorsTest(unittest.TestCase):
706 '''Unit tests for all arithmetic operators, binary and unary.'''
707
708 def test_addition(self):
709
710 d1 = Decimal('-11.1')
711 d2 = Decimal('22.2')
712
713 #two Decimals
714 self.assertEqual(d1+d2, Decimal('11.1'))
715 self.assertEqual(d2+d1, Decimal('11.1'))
716
717 #with other type, left
718 c = d1 + 5
719 self.assertEqual(c, Decimal('-6.1'))
720 self.assertEqual(type(c), type(d1))
721
722 #with other type, right
723 c = 5 + d1
724 self.assertEqual(c, Decimal('-6.1'))
725 self.assertEqual(type(c), type(d1))
726
727 #inline with decimal
728 d1 += d2
729 self.assertEqual(d1, Decimal('11.1'))
730
731 #inline with other type
732 d1 += 5
733 self.assertEqual(d1, Decimal('16.1'))
734
735 def test_subtraction(self):
736
737 d1 = Decimal('-11.1')
738 d2 = Decimal('22.2')
739
740 #two Decimals
741 self.assertEqual(d1-d2, Decimal('-33.3'))
742 self.assertEqual(d2-d1, Decimal('33.3'))
743
744 #with other type, left
745 c = d1 - 5
746 self.assertEqual(c, Decimal('-16.1'))
747 self.assertEqual(type(c), type(d1))
748
749 #with other type, right
750 c = 5 - d1
751 self.assertEqual(c, Decimal('16.1'))
752 self.assertEqual(type(c), type(d1))
753
754 #inline with decimal
755 d1 -= d2
756 self.assertEqual(d1, Decimal('-33.3'))
757
758 #inline with other type
759 d1 -= 5
760 self.assertEqual(d1, Decimal('-38.3'))
761
762 def test_multiplication(self):
763
764 d1 = Decimal('-5')
765 d2 = Decimal('3')
766
767 #two Decimals
768 self.assertEqual(d1*d2, Decimal('-15'))
769 self.assertEqual(d2*d1, Decimal('-15'))
770
771 #with other type, left
772 c = d1 * 5
773 self.assertEqual(c, Decimal('-25'))
774 self.assertEqual(type(c), type(d1))
775
776 #with other type, right
777 c = 5 * d1
778 self.assertEqual(c, Decimal('-25'))
779 self.assertEqual(type(c), type(d1))
780
781 #inline with decimal
782 d1 *= d2
783 self.assertEqual(d1, Decimal('-15'))
784
785 #inline with other type
786 d1 *= 5
787 self.assertEqual(d1, Decimal('-75'))
788
789 def test_division(self):
790
791 d1 = Decimal('-5')
792 d2 = Decimal('2')
793
794 #two Decimals
795 self.assertEqual(d1/d2, Decimal('-2.5'))
796 self.assertEqual(d2/d1, Decimal('-0.4'))
797
798 #with other type, left
799 c = d1 / 4
800 self.assertEqual(c, Decimal('-1.25'))
801 self.assertEqual(type(c), type(d1))
802
803 #with other type, right
804 c = 4 / d1
805 self.assertEqual(c, Decimal('-0.8'))
806 self.assertEqual(type(c), type(d1))
807
808 #inline with decimal
809 d1 /= d2
810 self.assertEqual(d1, Decimal('-2.5'))
811
812 #inline with other type
813 d1 /= 4
814 self.assertEqual(d1, Decimal('-0.625'))
815
816 def test_floor_division(self):
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000817
818 d1 = Decimal('5')
819 d2 = Decimal('2')
820
821 #two Decimals
822 self.assertEqual(d1//d2, Decimal('2'))
823 self.assertEqual(d2//d1, Decimal('0'))
824
825 #with other type, left
826 c = d1 // 4
827 self.assertEqual(c, Decimal('1'))
828 self.assertEqual(type(c), type(d1))
829
830 #with other type, right
831 c = 7 // d1
832 self.assertEqual(c, Decimal('1'))
833 self.assertEqual(type(c), type(d1))
834
835 #inline with decimal
836 d1 //= d2
837 self.assertEqual(d1, Decimal('2'))
838
839 #inline with other type
840 d1 //= 2
841 self.assertEqual(d1, Decimal('1'))
842
843 def test_powering(self):
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000844
845 d1 = Decimal('5')
846 d2 = Decimal('2')
847
848 #two Decimals
849 self.assertEqual(d1**d2, Decimal('25'))
850 self.assertEqual(d2**d1, Decimal('32'))
851
852 #with other type, left
853 c = d1 ** 4
854 self.assertEqual(c, Decimal('625'))
855 self.assertEqual(type(c), type(d1))
856
857 #with other type, right
858 c = 7 ** d1
859 self.assertEqual(c, Decimal('16807'))
860 self.assertEqual(type(c), type(d1))
861
862 #inline with decimal
863 d1 **= d2
864 self.assertEqual(d1, Decimal('25'))
865
866 #inline with other type
867 d1 **= 4
868 self.assertEqual(d1, Decimal('390625'))
869
870 def test_module(self):
871
872 d1 = Decimal('5')
873 d2 = Decimal('2')
874
875 #two Decimals
876 self.assertEqual(d1%d2, Decimal('1'))
877 self.assertEqual(d2%d1, Decimal('2'))
878
879 #with other type, left
880 c = d1 % 4
881 self.assertEqual(c, Decimal('1'))
882 self.assertEqual(type(c), type(d1))
883
884 #with other type, right
885 c = 7 % d1
886 self.assertEqual(c, Decimal('2'))
887 self.assertEqual(type(c), type(d1))
888
889 #inline with decimal
890 d1 %= d2
891 self.assertEqual(d1, Decimal('1'))
892
893 #inline with other type
894 d1 %= 4
895 self.assertEqual(d1, Decimal('1'))
896
897 def test_floor_div_module(self):
898
899 d1 = Decimal('5')
900 d2 = Decimal('2')
901
902 #two Decimals
903 (p, q) = divmod(d1, d2)
904 self.assertEqual(p, Decimal('2'))
905 self.assertEqual(q, Decimal('1'))
906 self.assertEqual(type(p), type(d1))
907 self.assertEqual(type(q), type(d1))
908
909 #with other type, left
910 (p, q) = divmod(d1, 4)
911 self.assertEqual(p, Decimal('1'))
912 self.assertEqual(q, Decimal('1'))
913 self.assertEqual(type(p), type(d1))
914 self.assertEqual(type(q), type(d1))
915
916 #with other type, right
917 (p, q) = divmod(7, d1)
918 self.assertEqual(p, Decimal('1'))
919 self.assertEqual(q, Decimal('2'))
920 self.assertEqual(type(p), type(d1))
921 self.assertEqual(type(q), type(d1))
922
923 def test_unary_operators(self):
924 self.assertEqual(+Decimal(45), Decimal(+45)) # +
925 self.assertEqual(-Decimal(45), Decimal(-45)) # -
926 self.assertEqual(abs(Decimal(45)), abs(Decimal(-45))) # abs
927
Christian Heimes77c02eb2008-02-09 02:18:51 +0000928 def test_nan_comparisons(self):
929 n = Decimal('NaN')
930 s = Decimal('sNaN')
931 i = Decimal('Inf')
932 f = Decimal('2')
933 for x, y in [(n, n), (n, i), (i, n), (n, f), (f, n),
934 (s, n), (n, s), (s, i), (i, s), (s, f), (f, s), (s, s)]:
935 self.assert_(x != y)
936 self.assert_(not (x == y))
937 self.assert_(not (x < y))
938 self.assert_(not (x <= y))
939 self.assert_(not (x > y))
940 self.assert_(not (x >= y))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000941
942# The following are two functions used to test threading in the next class
943
944def thfunc1(cls):
945 d1 = Decimal(1)
946 d3 = Decimal(3)
Christian Heimesfe337bf2008-03-23 21:54:12 +0000947 test1 = d1/d3
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000948 cls.synchro.wait()
Christian Heimesfe337bf2008-03-23 21:54:12 +0000949 test2 = d1/d3
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000950 cls.finish1.set()
Christian Heimesfe337bf2008-03-23 21:54:12 +0000951
952 cls.assertEqual(test1, Decimal('0.333333333'))
953 cls.assertEqual(test2, Decimal('0.333333333'))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000954 return
955
956def thfunc2(cls):
957 d1 = Decimal(1)
958 d3 = Decimal(3)
Christian Heimesfe337bf2008-03-23 21:54:12 +0000959 test1 = d1/d3
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000960 thiscontext = getcontext()
961 thiscontext.prec = 18
Christian Heimesfe337bf2008-03-23 21:54:12 +0000962 test2 = d1/d3
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000963 cls.synchro.set()
964 cls.finish2.set()
Christian Heimesfe337bf2008-03-23 21:54:12 +0000965
966 cls.assertEqual(test1, Decimal('0.333333333'))
967 cls.assertEqual(test2, Decimal('0.333333333333333333'))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000968 return
969
970
971class DecimalUseOfContextTest(unittest.TestCase):
972 '''Unit tests for Use of Context cases in Decimal.'''
973
Raymond Hettinger7e71fa52004-12-18 19:07:19 +0000974 try:
975 import threading
976 except ImportError:
977 threading = None
978
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000979 # Take care executing this test from IDLE, there's an issue in threading
980 # that hangs IDLE and I couldn't find it
981
982 def test_threading(self):
983 #Test the "threading isolation" of a Context.
984
985 self.synchro = threading.Event()
986 self.finish1 = threading.Event()
987 self.finish2 = threading.Event()
988
989 th1 = threading.Thread(target=thfunc1, args=(self,))
990 th2 = threading.Thread(target=thfunc2, args=(self,))
991
992 th1.start()
993 th2.start()
994
995 self.finish1.wait()
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000996 self.finish2.wait()
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000997 return
998
Raymond Hettinger7e71fa52004-12-18 19:07:19 +0000999 if threading is None:
1000 del test_threading
1001
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001002
1003class DecimalUsabilityTest(unittest.TestCase):
1004 '''Unit tests for Usability cases of Decimal.'''
1005
1006 def test_comparison_operators(self):
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001007
1008 da = Decimal('23.42')
1009 db = Decimal('23.42')
1010 dc = Decimal('45')
1011
1012 #two Decimals
1013 self.failUnless(dc > da)
1014 self.failUnless(dc >= da)
1015 self.failUnless(da < dc)
1016 self.failUnless(da <= dc)
Guido van Rossume61fd5b2007-07-11 12:20:59 +00001017 self.assertEqual(da, db)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001018 self.failUnless(da != dc)
1019 self.failUnless(da <= db)
1020 self.failUnless(da >= db)
1021 self.assertEqual(cmp(dc,da), 1)
1022 self.assertEqual(cmp(da,dc), -1)
1023 self.assertEqual(cmp(da,db), 0)
1024
1025 #a Decimal and an int
1026 self.failUnless(dc > 23)
1027 self.failUnless(23 < dc)
Guido van Rossume61fd5b2007-07-11 12:20:59 +00001028 self.assertEqual(dc, 45)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001029 self.assertEqual(cmp(dc,23), 1)
1030 self.assertEqual(cmp(23,dc), -1)
1031 self.assertEqual(cmp(dc,45), 0)
1032
1033 #a Decimal and uncomparable
Raymond Hettinger0aeac102004-07-05 22:53:03 +00001034 self.assertNotEqual(da, 'ugly')
1035 self.assertNotEqual(da, 32.7)
1036 self.assertNotEqual(da, object())
1037 self.assertNotEqual(da, object)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001038
Raymond Hettinger0aeac102004-07-05 22:53:03 +00001039 # sortable
Guido van Rossumc1f779c2007-07-03 08:25:58 +00001040 a = list(map(Decimal, range(100)))
Raymond Hettinger0aeac102004-07-05 22:53:03 +00001041 b = a[:]
1042 random.shuffle(a)
1043 a.sort()
1044 self.assertEqual(a, b)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001045
1046 def test_copy_and_deepcopy_methods(self):
1047 d = Decimal('43.24')
1048 c = copy.copy(d)
1049 self.assertEqual(id(c), id(d))
1050 dc = copy.deepcopy(d)
1051 self.assertEqual(id(dc), id(d))
1052
1053 def test_hash_method(self):
1054 #just that it's hashable
1055 hash(Decimal(23))
Thomas Wouters8ce81f72007-09-20 18:22:40 +00001056
1057 test_values = [Decimal(sign*(2**m + n))
1058 for m in [0, 14, 15, 16, 17, 30, 31,
1059 32, 33, 62, 63, 64, 65, 66]
1060 for n in range(-10, 10)
1061 for sign in [-1, 1]]
1062 test_values.extend([
1063 Decimal("-0"), # zeros
1064 Decimal("0.00"),
1065 Decimal("-0.000"),
1066 Decimal("0E10"),
1067 Decimal("-0E12"),
1068 Decimal("10.0"), # negative exponent
1069 Decimal("-23.00000"),
1070 Decimal("1230E100"), # positive exponent
1071 Decimal("-4.5678E50"),
1072 # a value for which hash(n) != hash(n % (2**64-1))
1073 # in Python pre-2.6
1074 Decimal(2**64 + 2**32 - 1),
1075 # selection of values which fail with the old (before
1076 # version 2.6) long.__hash__
1077 Decimal("1.634E100"),
1078 Decimal("90.697E100"),
1079 Decimal("188.83E100"),
1080 Decimal("1652.9E100"),
1081 Decimal("56531E100"),
1082 ])
1083
1084 # check that hash(d) == hash(int(d)) for integral values
1085 for value in test_values:
1086 self.assertEqual(hash(value), hash(int(value)))
1087
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001088 #the same hash that to an int
1089 self.assertEqual(hash(Decimal(23)), hash(23))
Raymond Hettingerbea3f6f2005-03-15 04:59:17 +00001090 self.assertRaises(TypeError, hash, Decimal('NaN'))
1091 self.assert_(hash(Decimal('Inf')))
1092 self.assert_(hash(Decimal('-Inf')))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001093
Christian Heimes2380ac72008-01-09 00:17:24 +00001094 # check that the value of the hash doesn't depend on the
1095 # current context (issue #1757)
1096 c = getcontext()
1097 old_precision = c.prec
1098 x = Decimal("123456789.1")
1099
1100 c.prec = 6
1101 h1 = hash(x)
1102 c.prec = 10
1103 h2 = hash(x)
1104 c.prec = 16
1105 h3 = hash(x)
1106
1107 self.assertEqual(h1, h2)
1108 self.assertEqual(h1, h3)
1109 c.prec = old_precision
1110
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001111 def test_min_and_max_methods(self):
1112
1113 d1 = Decimal('15.32')
1114 d2 = Decimal('28.5')
1115 l1 = 15
1116 l2 = 28
1117
1118 #between Decimals
1119 self.failUnless(min(d1,d2) is d1)
1120 self.failUnless(min(d2,d1) is d1)
1121 self.failUnless(max(d1,d2) is d2)
1122 self.failUnless(max(d2,d1) is d2)
1123
1124 #between Decimal and long
1125 self.failUnless(min(d1,l2) is d1)
1126 self.failUnless(min(l2,d1) is d1)
1127 self.failUnless(max(l1,d2) is d2)
1128 self.failUnless(max(d2,l1) is d2)
1129
1130 def test_as_nonzero(self):
1131 #as false
1132 self.failIf(Decimal(0))
1133 #as true
1134 self.failUnless(Decimal('0.372'))
1135
1136 def test_tostring_methods(self):
1137 #Test str and repr methods.
1138
1139 d = Decimal('15.32')
1140 self.assertEqual(str(d), '15.32') # str
Christian Heimes68f5fbe2008-02-14 08:27:37 +00001141 self.assertEqual(repr(d), "Decimal('15.32')") # repr
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001142
1143 def test_tonum_methods(self):
1144 #Test float, int and long methods.
1145
1146 d1 = Decimal('66')
1147 d2 = Decimal('15.32')
1148
1149 #int
1150 self.assertEqual(int(d1), 66)
1151 self.assertEqual(int(d2), 15)
1152
1153 #long
Guido van Rossume2a383d2007-01-15 16:59:06 +00001154 self.assertEqual(int(d1), 66)
1155 self.assertEqual(int(d2), 15)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001156
1157 #float
1158 self.assertEqual(float(d1), 66)
1159 self.assertEqual(float(d2), 15.32)
1160
1161 def test_eval_round_trip(self):
1162
1163 #with zero
1164 d = Decimal( (0, (0,), 0) )
1165 self.assertEqual(d, eval(repr(d)))
1166
1167 #int
1168 d = Decimal( (1, (4, 5), 0) )
1169 self.assertEqual(d, eval(repr(d)))
1170
1171 #float
1172 d = Decimal( (0, (4, 5, 3, 4), -2) )
1173 self.assertEqual(d, eval(repr(d)))
1174
1175 #weird
1176 d = Decimal( (1, (4, 3, 4, 9, 1, 3, 5, 3, 4), -25) )
1177 self.assertEqual(d, eval(repr(d)))
1178
1179 def test_as_tuple(self):
1180
1181 #with zero
1182 d = Decimal(0)
1183 self.assertEqual(d.as_tuple(), (0, (0,), 0) )
1184
1185 #int
1186 d = Decimal(-45)
1187 self.assertEqual(d.as_tuple(), (1, (4, 5), 0) )
1188
1189 #complicated string
1190 d = Decimal("-4.34913534E-17")
1191 self.assertEqual(d.as_tuple(), (1, (4, 3, 4, 9, 1, 3, 5, 3, 4), -25) )
1192
1193 #inf
1194 d = Decimal("Infinity")
1195 self.assertEqual(d.as_tuple(), (0, (0,), 'F') )
1196
Guido van Rossum8ce8a782007-11-01 19:42:39 +00001197 #leading zeros in coefficient should be stripped
1198 d = Decimal( (0, (0, 0, 4, 0, 5, 3, 4), -2) )
1199 self.assertEqual(d.as_tuple(), (0, (4, 0, 5, 3, 4), -2) )
1200 d = Decimal( (1, (0, 0, 0), 37) )
1201 self.assertEqual(d.as_tuple(), (1, (0,), 37))
1202 d = Decimal( (1, (), 37) )
1203 self.assertEqual(d.as_tuple(), (1, (0,), 37))
1204
1205 #leading zeros in NaN diagnostic info should be stripped
1206 d = Decimal( (0, (0, 0, 4, 0, 5, 3, 4), 'n') )
1207 self.assertEqual(d.as_tuple(), (0, (4, 0, 5, 3, 4), 'n') )
1208 d = Decimal( (1, (0, 0, 0), 'N') )
1209 self.assertEqual(d.as_tuple(), (1, (), 'N') )
1210 d = Decimal( (1, (), 'n') )
1211 self.assertEqual(d.as_tuple(), (1, (), 'n') )
1212
1213 #coefficient in infinity should be ignored
1214 d = Decimal( (0, (4, 5, 3, 4), 'F') )
1215 self.assertEqual(d.as_tuple(), (0, (0,), 'F'))
1216 d = Decimal( (1, (0, 2, 7, 1), 'F') )
1217 self.assertEqual(d.as_tuple(), (1, (0,), 'F'))
1218
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001219 def test_immutability_operations(self):
1220 # Do operations and check that it didn't change change internal objects.
1221
1222 d1 = Decimal('-25e55')
1223 b1 = Decimal('-25e55')
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001224 d2 = Decimal('33e+33')
1225 b2 = Decimal('33e+33')
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001226
1227 def checkSameDec(operation, useOther=False):
1228 if useOther:
1229 eval("d1." + operation + "(d2)")
1230 self.assertEqual(d1._sign, b1._sign)
1231 self.assertEqual(d1._int, b1._int)
1232 self.assertEqual(d1._exp, b1._exp)
1233 self.assertEqual(d2._sign, b2._sign)
1234 self.assertEqual(d2._int, b2._int)
1235 self.assertEqual(d2._exp, b2._exp)
1236 else:
1237 eval("d1." + operation + "()")
1238 self.assertEqual(d1._sign, b1._sign)
1239 self.assertEqual(d1._int, b1._int)
1240 self.assertEqual(d1._exp, b1._exp)
1241 return
1242
1243 Decimal(d1)
1244 self.assertEqual(d1._sign, b1._sign)
1245 self.assertEqual(d1._int, b1._int)
1246 self.assertEqual(d1._exp, b1._exp)
1247
1248 checkSameDec("__abs__")
1249 checkSameDec("__add__", True)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001250 checkSameDec("__divmod__", True)
Christian Heimes77c02eb2008-02-09 02:18:51 +00001251 checkSameDec("__eq__", True)
1252 checkSameDec("__ne__", True)
1253 checkSameDec("__le__", True)
1254 checkSameDec("__lt__", True)
1255 checkSameDec("__ge__", True)
1256 checkSameDec("__gt__", True)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001257 checkSameDec("__float__")
1258 checkSameDec("__floordiv__", True)
1259 checkSameDec("__hash__")
1260 checkSameDec("__int__")
Christian Heimes969fe572008-01-25 11:23:10 +00001261 checkSameDec("__trunc__")
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001262 checkSameDec("__mod__", True)
1263 checkSameDec("__mul__", True)
1264 checkSameDec("__neg__")
Jack Diederich4dafcc42006-11-28 19:15:13 +00001265 checkSameDec("__bool__")
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001266 checkSameDec("__pos__")
1267 checkSameDec("__pow__", True)
1268 checkSameDec("__radd__", True)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001269 checkSameDec("__rdivmod__", True)
1270 checkSameDec("__repr__")
1271 checkSameDec("__rfloordiv__", True)
1272 checkSameDec("__rmod__", True)
1273 checkSameDec("__rmul__", True)
1274 checkSameDec("__rpow__", True)
1275 checkSameDec("__rsub__", True)
1276 checkSameDec("__str__")
1277 checkSameDec("__sub__", True)
1278 checkSameDec("__truediv__", True)
1279 checkSameDec("adjusted")
1280 checkSameDec("as_tuple")
1281 checkSameDec("compare", True)
1282 checkSameDec("max", True)
1283 checkSameDec("min", True)
1284 checkSameDec("normalize")
1285 checkSameDec("quantize", True)
1286 checkSameDec("remainder_near", True)
1287 checkSameDec("same_quantum", True)
1288 checkSameDec("sqrt")
1289 checkSameDec("to_eng_string")
1290 checkSameDec("to_integral")
1291
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001292 def test_subclassing(self):
1293 # Different behaviours when subclassing Decimal
1294
1295 class MyDecimal(Decimal):
1296 pass
1297
1298 d1 = MyDecimal(1)
1299 d2 = MyDecimal(2)
1300 d = d1 + d2
1301 self.assertTrue(type(d) is Decimal)
1302
1303 d = d1.max(d2)
1304 self.assertTrue(type(d) is Decimal)
1305
Christian Heimes0348fb62008-03-26 12:55:56 +00001306 def test_implicit_context(self):
1307 # Check results when context given implicitly. (Issue 2478)
1308 c = getcontext()
1309 self.assertEqual(str(Decimal(0).sqrt()),
1310 str(c.sqrt(Decimal(0))))
1311
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001312
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001313class DecimalPythonAPItests(unittest.TestCase):
1314
1315 def test_pickle(self):
1316 d = Decimal('-3.141590000')
1317 p = pickle.dumps(d)
1318 e = pickle.loads(p)
1319 self.assertEqual(d, e)
1320
Raymond Hettinger5548be22004-07-05 18:49:38 +00001321 def test_int(self):
Raymond Hettinger605ed022004-11-24 07:28:48 +00001322 for x in range(-250, 250):
1323 s = '%0.2f' % (x / 100.0)
Raymond Hettinger5548be22004-07-05 18:49:38 +00001324 # should work the same as for floats
1325 self.assertEqual(int(Decimal(s)), int(float(s)))
Raymond Hettinger605ed022004-11-24 07:28:48 +00001326 # should work the same as to_integral in the ROUND_DOWN mode
Raymond Hettinger5548be22004-07-05 18:49:38 +00001327 d = Decimal(s)
Raymond Hettinger605ed022004-11-24 07:28:48 +00001328 r = d.to_integral(ROUND_DOWN)
Raymond Hettinger5548be22004-07-05 18:49:38 +00001329 self.assertEqual(Decimal(int(d)), r)
1330
Christian Heimes969fe572008-01-25 11:23:10 +00001331 def test_trunc(self):
1332 for x in range(-250, 250):
1333 s = '%0.2f' % (x / 100.0)
1334 # should work the same as for floats
1335 self.assertEqual(int(Decimal(s)), int(float(s)))
1336 # should work the same as to_integral in the ROUND_DOWN mode
1337 d = Decimal(s)
1338 r = d.to_integral(ROUND_DOWN)
Christian Heimes400adb02008-02-01 08:12:03 +00001339 self.assertEqual(Decimal(math.trunc(d)), r)
Christian Heimes969fe572008-01-25 11:23:10 +00001340
Raymond Hettingerd9c0a7a2004-07-03 10:02:28 +00001341class ContextAPItests(unittest.TestCase):
1342
1343 def test_pickle(self):
1344 c = Context()
1345 e = pickle.loads(pickle.dumps(c))
1346 for k in vars(c):
1347 v1 = vars(c)[k]
1348 v2 = vars(e)[k]
1349 self.assertEqual(v1, v2)
1350
Raymond Hettinger0aeac102004-07-05 22:53:03 +00001351 def test_equality_with_other_types(self):
1352 self.assert_(Decimal(10) in ['a', 1.0, Decimal(10), (1,2), {}])
1353 self.assert_(Decimal(10) not in ['a', 1.0, (1,2), {}])
1354
Raymond Hettinger955d2b22004-08-08 20:17:45 +00001355 def test_copy(self):
1356 # All copies should be deep
1357 c = Context()
1358 d = c.copy()
1359 self.assertNotEqual(id(c), id(d))
1360 self.assertNotEqual(id(c.flags), id(d.flags))
1361 self.assertNotEqual(id(c.traps), id(d.traps))
1362
Thomas Wouters89f507f2006-12-13 04:49:30 +00001363class WithStatementTest(unittest.TestCase):
1364 # Can't do these as docstrings until Python 2.6
1365 # as doctest can't handle __future__ statements
1366
1367 def test_localcontext(self):
1368 # Use a copy of the current context in the block
1369 orig_ctx = getcontext()
1370 with localcontext() as enter_ctx:
1371 set_ctx = getcontext()
1372 final_ctx = getcontext()
1373 self.assert_(orig_ctx is final_ctx, 'did not restore context correctly')
1374 self.assert_(orig_ctx is not set_ctx, 'did not copy the context')
1375 self.assert_(set_ctx is enter_ctx, '__enter__ returned wrong context')
1376
1377 def test_localcontextarg(self):
1378 # Use a copy of the supplied context in the block
1379 orig_ctx = getcontext()
1380 new_ctx = Context(prec=42)
1381 with localcontext(new_ctx) as enter_ctx:
1382 set_ctx = getcontext()
1383 final_ctx = getcontext()
1384 self.assert_(orig_ctx is final_ctx, 'did not restore context correctly')
1385 self.assert_(set_ctx.prec == new_ctx.prec, 'did not set correct context')
1386 self.assert_(new_ctx is not set_ctx, 'did not copy the context')
1387 self.assert_(set_ctx is enter_ctx, '__enter__ returned wrong context')
1388
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001389class ContextFlags(unittest.TestCase):
1390 def test_flags_irrelevant(self):
1391 # check that the result (numeric result + flags raised) of an
1392 # arithmetic operation doesn't depend on the current flags
1393
1394 context = Context(prec=9, Emin = -999999999, Emax = 999999999,
1395 rounding=ROUND_HALF_EVEN, traps=[], flags=[])
1396
1397 # operations that raise various flags, in the form (function, arglist)
1398 operations = [
1399 (context._apply, [Decimal("100E-1000000009")]),
1400 (context.sqrt, [Decimal(2)]),
1401 (context.add, [Decimal("1.23456789"), Decimal("9.87654321")]),
1402 (context.multiply, [Decimal("1.23456789"), Decimal("9.87654321")]),
1403 (context.subtract, [Decimal("1.23456789"), Decimal("9.87654321")]),
1404 ]
1405
1406 # try various flags individually, then a whole lot at once
1407 flagsets = [[Inexact], [Rounded], [Underflow], [Clamped], [Subnormal],
1408 [Inexact, Rounded, Underflow, Clamped, Subnormal]]
1409
1410 for fn, args in operations:
1411 # find answer and flags raised using a clean context
1412 context.clear_flags()
1413 ans = fn(*args)
1414 flags = [k for k, v in context.flags.items() if v]
1415
1416 for extra_flags in flagsets:
1417 # set flags, before calling operation
1418 context.clear_flags()
1419 for flag in extra_flags:
1420 context._raise_error(flag)
1421 new_ans = fn(*args)
1422
1423 # flags that we expect to be set after the operation
1424 expected_flags = list(flags)
1425 for flag in extra_flags:
1426 if flag not in expected_flags:
1427 expected_flags.append(flag)
1428 expected_flags.sort(key=id)
1429
1430 # flags we actually got
1431 new_flags = [k for k,v in context.flags.items() if v]
1432 new_flags.sort(key=id)
1433
1434 self.assertEqual(ans, new_ans,
1435 "operation produces different answers depending on flags set: " +
1436 "expected %s, got %s." % (ans, new_ans))
1437 self.assertEqual(new_flags, expected_flags,
1438 "operation raises different flags depending on flags set: " +
1439 "expected %s, got %s" % (expected_flags, new_flags))
1440
1441def test_main(arith=False, verbose=None, todo_tests=None, debug=None):
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001442 """ Execute the tests.
1443
Raymond Hettingered20ad82004-09-04 20:09:13 +00001444 Runs all arithmetic tests if arith is True or if the "decimal" resource
1445 is enabled in regrtest.py
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001446 """
Raymond Hettingered20ad82004-09-04 20:09:13 +00001447
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00001448 init()
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001449 global TEST_ALL, DEBUG
Raymond Hettingered20ad82004-09-04 20:09:13 +00001450 TEST_ALL = arith or is_resource_enabled('decimal')
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001451 DEBUG = debug
Raymond Hettingered20ad82004-09-04 20:09:13 +00001452
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001453 if todo_tests is None:
1454 test_classes = [
1455 DecimalExplicitConstructionTest,
1456 DecimalImplicitConstructionTest,
1457 DecimalArithmeticOperatorsTest,
Christian Heimesf16baeb2008-02-29 14:57:44 +00001458 DecimalFormatTest,
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001459 DecimalUseOfContextTest,
1460 DecimalUsabilityTest,
1461 DecimalPythonAPItests,
1462 ContextAPItests,
1463 DecimalTest,
1464 WithStatementTest,
1465 ContextFlags
1466 ]
1467 else:
1468 test_classes = [DecimalTest]
1469
1470 # Dynamically build custom test definition for each file in the test
1471 # directory and add the definitions to the DecimalTest class. This
1472 # procedure insures that new files do not get skipped.
1473 for filename in os.listdir(directory):
1474 if '.decTest' not in filename or filename.startswith("."):
1475 continue
1476 head, tail = filename.split('.')
1477 if todo_tests is not None and head not in todo_tests:
1478 continue
1479 tester = lambda self, f=filename: self.eval_file(directory + f)
1480 setattr(DecimalTest, 'test_' + head, tester)
1481 del filename, head, tail, tester
1482
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001483
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00001484 try:
1485 run_unittest(*test_classes)
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001486 if todo_tests is None:
1487 import decimal as DecimalModule
1488 run_doctest(DecimalModule, verbose)
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00001489 finally:
1490 setcontext(ORIGINAL_CONTEXT)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001491
1492if __name__ == '__main__':
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001493 import optparse
1494 p = optparse.OptionParser("test_decimal.py [--debug] [{--skip | test1 [test2 [...]]}]")
1495 p.add_option('--debug', '-d', action='store_true', help='shows the test number and context before each test')
1496 p.add_option('--skip', '-s', action='store_true', help='skip over 90% of the arithmetic tests')
1497 (opt, args) = p.parse_args()
1498
1499 if opt.skip:
1500 test_main(arith=False, verbose=True)
1501 elif args:
1502 test_main(arith=True, verbose=True, todo_tests=args, debug=opt.debug)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001503 else:
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001504 test_main(arith=True, verbose=True)