blob: bb27eec3e8d2a807d386056c29e39b6748d0931c [file] [log] [blame]
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001# Copyright (c) 2004 Python Software Foundation.
2# All rights reserved.
3
4# Written by Eric Price <eprice at tjhsst.edu>
5# and Facundo Batista <facundo at taniquetil.com.ar>
6# and Raymond Hettinger <python at rcn.com>
7# and Aahz (aahz at pobox.com)
8# and Tim Peters
9
10"""
11These are the test cases for the Decimal module.
12
13There are two groups of tests, Arithmetic and Behaviour. The former test
14the Decimal arithmetic using the tests provided by Mike Cowlishaw. The latter
15test the pythonic behaviour according to PEP 327.
16
17Cowlishaw's tests can be downloaded from:
18
19 www2.hursley.ibm.com/decimal/dectest.zip
20
21This test module can be called from command line with one parameter (Arithmetic
22or Behaviour) to test each part, or without parameter to test both parts. If
23you're working through IDLE, you can import this test module and call test_main()
24with the corresponding argument.
25"""
26
Raymond Hettinger7c85fa42004-07-01 11:01:35 +000027import glob
Christian Heimes400adb02008-02-01 08:12:03 +000028import math
Raymond Hettinger7c85fa42004-07-01 11:01:35 +000029import os, sys
30import pickle, copy
Christian Heimes400adb02008-02-01 08:12:03 +000031import unittest
Raymond Hettinger7c85fa42004-07-01 11:01:35 +000032from decimal import *
Thomas Wouters49fd7fa2006-04-21 10:40:58 +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
Guido van Rossumc1f779c2007-07-03 08:25:58 +000042Signals = tuple(getcontext().flags.keys())
Raymond Hettingerfed52962004-07-14 15:41:57 +000043
Thomas Wouters49fd7fa2006-04-21 10:40:58 +000044# Tests are built around these assumed context defaults.
45# test_main() restores the original context.
46def init():
47 global ORIGINAL_CONTEXT
48 ORIGINAL_CONTEXT = getcontext().copy()
Christian Heimes81ee3ef2008-05-04 22:42:01 +000049 DefaultTestContext = Context(
50 prec = 9,
51 rounding = ROUND_HALF_EVEN,
52 traps = dict.fromkeys(Signals, 0)
53 )
54 setcontext(DefaultTestContext)
Raymond Hettinger6ea48452004-07-03 12:26:21 +000055
Raymond Hettinger7c85fa42004-07-01 11:01:35 +000056TESTDATADIR = 'decimaltestdata'
Raymond Hettingerd9c0a7a2004-07-03 10:02:28 +000057if __name__ == '__main__':
58 file = sys.argv[0]
59else:
60 file = __file__
61testdir = os.path.dirname(file) or os.curdir
Raymond Hettinger267b8682005-03-27 10:47:39 +000062directory = testdir + os.sep + TESTDATADIR + os.sep
Raymond Hettinger7c85fa42004-07-01 11:01:35 +000063
Raymond Hettinger267b8682005-03-27 10:47:39 +000064skip_expected = not os.path.isdir(directory)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +000065
66# Make sure it actually raises errors when not expected and caught in flags
67# Slower, since it runs some things several times.
68EXTENDEDERRORTEST = False
69
Raymond Hettinger7c85fa42004-07-01 11:01:35 +000070#Map the test cases' error names to the actual errors
Raymond Hettinger7c85fa42004-07-01 11:01:35 +000071ErrorNames = {'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,
Thomas Wouters1b7f8912007-09-19 03:06:30 +000095 'up' : ROUND_UP,
96 '05up' : ROUND_05UP}
Raymond Hettinger7c85fa42004-07-01 11:01:35 +000097
98# Name adapter to be able to change the Decimal and Context
99# interface without changing the test files from Cowlishaw
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000100nameAdapter = {'and':'logical_and',
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000101 'apply':'_apply',
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000102 'class':'number_class',
103 'comparesig':'compare_signal',
104 'comparetotal':'compare_total',
105 'comparetotmag':'compare_total_mag',
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000106 'copy':'copy_decimal',
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000107 'copyabs':'copy_abs',
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000108 'copynegate':'copy_negate',
109 'copysign':'copy_sign',
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000110 'divideint':'divide_int',
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000111 'invert':'logical_invert',
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000112 'iscanonical':'is_canonical',
113 'isfinite':'is_finite',
114 'isinfinite':'is_infinite',
115 'isnan':'is_nan',
116 'isnormal':'is_normal',
117 'isqnan':'is_qnan',
118 'issigned':'is_signed',
119 'issnan':'is_snan',
120 'issubnormal':'is_subnormal',
121 'iszero':'is_zero',
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000122 'maxmag':'max_mag',
123 'minmag':'min_mag',
124 'nextminus':'next_minus',
125 'nextplus':'next_plus',
126 'nexttoward':'next_toward',
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000127 'or':'logical_or',
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000128 'reduce':'normalize',
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000129 'remaindernear':'remainder_near',
130 'samequantum':'same_quantum',
131 'squareroot':'sqrt',
132 'toeng':'to_eng_string',
133 'tointegral':'to_integral_value',
134 'tointegralx':'to_integral_exact',
135 'tosci':'to_sci_string',
136 'xor':'logical_xor',
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000137 }
138
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000139# The following functions return True/False rather than a Decimal instance
140
141LOGICAL_FUNCTIONS = (
142 'is_canonical',
143 'is_finite',
144 'is_infinite',
145 'is_nan',
146 'is_normal',
147 'is_qnan',
148 'is_signed',
149 'is_snan',
150 'is_subnormal',
151 'is_zero',
152 'same_quantum',
153 )
154
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000155# For some operations (currently exp, ln, log10, power), the decNumber
156# reference implementation imposes additional restrictions on the
157# context and operands. These restrictions are not part of the
158# specification; however, the effect of these restrictions does show
159# up in some of the testcases. We skip testcases that violate these
160# restrictions, since Decimal behaves differently from decNumber for
161# these testcases so these testcases would otherwise fail.
162
163decNumberRestricted = ('power', 'ln', 'log10', 'exp')
164DEC_MAX_MATH = 999999
165def outside_decNumber_bounds(v, context):
166 if (context.prec > DEC_MAX_MATH or
167 context.Emax > DEC_MAX_MATH or
168 -context.Emin > DEC_MAX_MATH):
169 return True
170 if not v._is_special and v and (
171 len(v._int) > DEC_MAX_MATH or
172 v.adjusted() > DEC_MAX_MATH or
173 v.adjusted() < 1-2*DEC_MAX_MATH):
174 return True
175 return False
176
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000177class DecimalTest(unittest.TestCase):
178 """Class which tests the Decimal class against the test cases.
179
180 Changed for unittest.
181 """
182 def setUp(self):
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000183 self.context = Context()
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000184 self.ignore_list = ['#']
185 # Basically, a # means return NaN InvalidOperation.
186 # Different from a sNaN in trim
187
188 self.ChangeDict = {'precision' : self.change_precision,
189 'rounding' : self.change_rounding_method,
190 'maxexponent' : self.change_max_exponent,
191 'minexponent' : self.change_min_exponent,
192 'clamp' : self.change_clamp}
193
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000194 def eval_file(self, file):
195 global skip_expected
196 if skip_expected:
197 raise TestSkipped
198 return
Neal Norwitz70967602006-03-17 08:29:44 +0000199 for line in open(file):
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000200 line = line.replace('\r\n', '').replace('\n', '')
Raymond Hettinger5aa478b2004-07-09 10:02:53 +0000201 #print line
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000202 try:
203 t = self.eval_line(line)
Guido van Rossumb940e112007-01-10 16:19:56 +0000204 except DecimalException as exception:
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000205 #Exception raised where there shoudn't have been one.
206 self.fail('Exception "'+exception.__class__.__name__ + '" raised on line '+line)
207
208 return
209
210 def eval_line(self, s):
211 if s.find(' -> ') >= 0 and s[:2] != '--' and not s.startswith(' --'):
212 s = (s.split('->')[0] + '->' +
213 s.split('->')[1].split('--')[0]).strip()
214 else:
215 s = s.split('--')[0].strip()
216
217 for ignore in self.ignore_list:
218 if s.find(ignore) >= 0:
219 #print s.split()[0], 'NotImplemented--', ignore
220 return
221 if not s:
222 return
223 elif ':' in s:
224 return self.eval_directive(s)
225 else:
226 return self.eval_equation(s)
227
228 def eval_directive(self, s):
Guido van Rossumc1f779c2007-07-03 08:25:58 +0000229 funct, value = (x.strip().lower() for x in s.split(':'))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000230 if funct == 'rounding':
231 value = RoundingDict[value]
232 else:
233 try:
234 value = int(value)
235 except ValueError:
236 pass
237
238 funct = self.ChangeDict.get(funct, Nonfunction)
239 funct(value)
240
241 def eval_equation(self, s):
242 #global DEFAULT_PRECISION
243 #print DEFAULT_PRECISION
Raymond Hettingered20ad82004-09-04 20:09:13 +0000244
245 if not TEST_ALL and random.random() < 0.90:
246 return
247
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000248 try:
249 Sides = s.split('->')
250 L = Sides[0].strip().split()
251 id = L[0]
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000252 if DEBUG:
253 print("Test ", id, end=" ")
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000254 funct = L[1].lower()
255 valstemp = L[2:]
256 L = Sides[1].strip().split()
257 ans = L[0]
258 exceptions = L[1:]
259 except (TypeError, AttributeError, IndexError):
Raymond Hettingerd87ac8f2004-07-09 10:52:54 +0000260 raise InvalidOperation
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000261 def FixQuotes(val):
262 val = val.replace("''", 'SingleQuote').replace('""', 'DoubleQuote')
263 val = val.replace("'", '').replace('"', '')
264 val = val.replace('SingleQuote', "'").replace('DoubleQuote', '"')
265 return val
266 fname = nameAdapter.get(funct, funct)
267 if fname == 'rescale':
268 return
269 funct = getattr(self.context, fname)
270 vals = []
271 conglomerate = ''
272 quote = 0
273 theirexceptions = [ErrorNames[x.lower()] for x in exceptions]
274
Raymond Hettingerd9c0a7a2004-07-03 10:02:28 +0000275 for exception in Signals:
Raymond Hettingerbf440692004-07-10 14:14:37 +0000276 self.context.traps[exception] = 1 #Catch these bugs...
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000277 for exception in theirexceptions:
Raymond Hettingerbf440692004-07-10 14:14:37 +0000278 self.context.traps[exception] = 0
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000279 for i, val in enumerate(valstemp):
280 if val.count("'") % 2 == 1:
281 quote = 1 - quote
282 if quote:
283 conglomerate = conglomerate + ' ' + val
284 continue
285 else:
286 val = conglomerate + val
287 conglomerate = ''
288 v = FixQuotes(val)
289 if fname in ('to_sci_string', 'to_eng_string'):
290 if EXTENDEDERRORTEST:
291 for error in theirexceptions:
Raymond Hettingerbf440692004-07-10 14:14:37 +0000292 self.context.traps[error] = 1
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000293 try:
294 funct(self.context.create_decimal(v))
295 except error:
296 pass
Guido van Rossumb940e112007-01-10 16:19:56 +0000297 except Signals as e:
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000298 self.fail("Raised %s in %s when %s disabled" % \
299 (e, s, error))
300 else:
301 self.fail("Did not raise %s in %s" % (error, s))
Raymond Hettingerbf440692004-07-10 14:14:37 +0000302 self.context.traps[error] = 0
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000303 v = self.context.create_decimal(v)
304 else:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000305 v = Decimal(v, self.context)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000306 vals.append(v)
307
308 ans = FixQuotes(ans)
309
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000310 # skip tests that are related to bounds imposed in the decNumber
311 # reference implementation
312 if fname in decNumberRestricted:
313 if fname == 'power':
314 if not (vals[1]._isinteger() and
315 -1999999997 <= vals[1] <= 999999999):
316 if outside_decNumber_bounds(vals[0], self.context) or \
317 outside_decNumber_bounds(vals[1], self.context):
318 #print "Skipping test %s" % s
319 return
320 else:
321 if outside_decNumber_bounds(vals[0], self.context):
322 #print "Skipping test %s" % s
323 return
324
325
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000326 if EXTENDEDERRORTEST and fname not in ('to_sci_string', 'to_eng_string'):
327 for error in theirexceptions:
Raymond Hettingerbf440692004-07-10 14:14:37 +0000328 self.context.traps[error] = 1
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000329 try:
330 funct(*vals)
331 except error:
332 pass
Guido van Rossumb940e112007-01-10 16:19:56 +0000333 except Signals as e:
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000334 self.fail("Raised %s in %s when %s disabled" % \
335 (e, s, error))
336 else:
337 self.fail("Did not raise %s in %s" % (error, s))
Raymond Hettingerbf440692004-07-10 14:14:37 +0000338 self.context.traps[error] = 0
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000339 if DEBUG:
340 print("--", self.context)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000341 try:
342 result = str(funct(*vals))
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000343 if fname in LOGICAL_FUNCTIONS:
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000344 result = str(int(eval(result))) # 'True', 'False' -> '1', '0'
Guido van Rossumb940e112007-01-10 16:19:56 +0000345 except Signals as error:
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000346 self.fail("Raised %s in %s" % (error, s))
347 except: #Catch any error long enough to state the test case.
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000348 print("ERROR:", s)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000349 raise
350
351 myexceptions = self.getexceptions()
Raymond Hettingerbf440692004-07-10 14:14:37 +0000352 self.context.clear_flags()
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000353
Guido van Rossum47b9ff62006-08-24 00:41:19 +0000354 myexceptions.sort(key=repr)
355 theirexceptions.sort(key=repr)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000356
357 self.assertEqual(result, ans,
358 'Incorrect answer for ' + s + ' -- got ' + result)
359 self.assertEqual(myexceptions, theirexceptions,
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000360 'Incorrect flags set in ' + s + ' -- got ' + str(myexceptions))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000361 return
362
363 def getexceptions(self):
Raymond Hettingerf63ba432004-08-17 05:42:09 +0000364 return [e for e in Signals if self.context.flags[e]]
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000365
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000366 def change_precision(self, prec):
367 self.context.prec = prec
368 def change_rounding_method(self, rounding):
369 self.context.rounding = rounding
370 def change_min_exponent(self, exp):
371 self.context.Emin = exp
372 def change_max_exponent(self, exp):
373 self.context.Emax = exp
374 def change_clamp(self, clamp):
375 self.context._clamp = clamp
376
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000377
378
379# The following classes test the behaviour of Decimal according to PEP 327
380
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000381class DecimalExplicitConstructionTest(unittest.TestCase):
382 '''Unit tests for Explicit Construction cases of Decimal.'''
383
384 def test_explicit_empty(self):
385 self.assertEqual(Decimal(), Decimal("0"))
386
387 def test_explicit_from_None(self):
388 self.assertRaises(TypeError, Decimal, None)
389
390 def test_explicit_from_int(self):
391
392 #positive
393 d = Decimal(45)
394 self.assertEqual(str(d), '45')
395
396 #very large positive
397 d = Decimal(500000123)
398 self.assertEqual(str(d), '500000123')
399
400 #negative
401 d = Decimal(-45)
402 self.assertEqual(str(d), '-45')
403
404 #zero
405 d = Decimal(0)
406 self.assertEqual(str(d), '0')
407
408 def test_explicit_from_string(self):
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000409
410 #empty
411 self.assertEqual(str(Decimal('')), 'NaN')
412
413 #int
414 self.assertEqual(str(Decimal('45')), '45')
415
416 #float
417 self.assertEqual(str(Decimal('45.34')), '45.34')
418
419 #engineer notation
420 self.assertEqual(str(Decimal('45e2')), '4.5E+3')
421
422 #just not a number
423 self.assertEqual(str(Decimal('ugly')), 'NaN')
424
Christian Heimesa62da1d2008-01-12 19:39:10 +0000425 #leading and trailing whitespace permitted
426 self.assertEqual(str(Decimal('1.3E4 \n')), '1.3E+4')
427 self.assertEqual(str(Decimal(' -7.89')), '-7.89')
428
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000429 def test_explicit_from_tuples(self):
430
431 #zero
432 d = Decimal( (0, (0,), 0) )
433 self.assertEqual(str(d), '0')
434
435 #int
436 d = Decimal( (1, (4, 5), 0) )
437 self.assertEqual(str(d), '-45')
438
439 #float
440 d = Decimal( (0, (4, 5, 3, 4), -2) )
441 self.assertEqual(str(d), '45.34')
442
443 #weird
444 d = Decimal( (1, (4, 3, 4, 9, 1, 3, 5, 3, 4), -25) )
445 self.assertEqual(str(d), '-4.34913534E-17')
446
447 #wrong number of items
448 self.assertRaises(ValueError, Decimal, (1, (4, 3, 4, 9, 1)) )
449
450 #bad sign
451 self.assertRaises(ValueError, Decimal, (8, (4, 3, 4, 9, 1), 2) )
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000452 self.assertRaises(ValueError, Decimal, (0., (4, 3, 4, 9, 1), 2) )
453 self.assertRaises(ValueError, Decimal, (Decimal(1), (4, 3, 4, 9, 1), 2))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000454
455 #bad exp
456 self.assertRaises(ValueError, Decimal, (1, (4, 3, 4, 9, 1), 'wrong!') )
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000457 self.assertRaises(ValueError, Decimal, (1, (4, 3, 4, 9, 1), 0.) )
458 self.assertRaises(ValueError, Decimal, (1, (4, 3, 4, 9, 1), '1') )
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000459
460 #bad coefficients
461 self.assertRaises(ValueError, Decimal, (1, (4, 3, 4, None, 1), 2) )
462 self.assertRaises(ValueError, Decimal, (1, (4, -3, 4, 9, 1), 2) )
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000463 self.assertRaises(ValueError, Decimal, (1, (4, 10, 4, 9, 1), 2) )
Guido van Rossum0d3fb8a2007-11-26 23:23:18 +0000464 self.assertRaises(ValueError, Decimal, (1, (4, 3, 4, 'a', 1), 2) )
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000465
466 def test_explicit_from_Decimal(self):
467
468 #positive
469 d = Decimal(45)
470 e = Decimal(d)
471 self.assertEqual(str(e), '45')
472 self.assertNotEqual(id(d), id(e))
473
474 #very large positive
475 d = Decimal(500000123)
476 e = Decimal(d)
477 self.assertEqual(str(e), '500000123')
478 self.assertNotEqual(id(d), id(e))
479
480 #negative
481 d = Decimal(-45)
482 e = Decimal(d)
483 self.assertEqual(str(e), '-45')
484 self.assertNotEqual(id(d), id(e))
485
486 #zero
487 d = Decimal(0)
488 e = Decimal(d)
489 self.assertEqual(str(e), '0')
490 self.assertNotEqual(id(d), id(e))
491
492 def test_explicit_context_create_decimal(self):
493
494 nc = copy.copy(getcontext())
495 nc.prec = 3
496
497 # empty
Raymond Hettingerfed52962004-07-14 15:41:57 +0000498 d = Decimal()
499 self.assertEqual(str(d), '0')
500 d = nc.create_decimal()
501 self.assertEqual(str(d), '0')
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000502
503 # from None
504 self.assertRaises(TypeError, nc.create_decimal, None)
505
506 # from int
507 d = nc.create_decimal(456)
508 self.failUnless(isinstance(d, Decimal))
509 self.assertEqual(nc.create_decimal(45678),
510 nc.create_decimal('457E+2'))
511
512 # from string
513 d = Decimal('456789')
514 self.assertEqual(str(d), '456789')
515 d = nc.create_decimal('456789')
516 self.assertEqual(str(d), '4.57E+5')
Christian Heimesa62da1d2008-01-12 19:39:10 +0000517 # leading and trailing whitespace should result in a NaN;
518 # spaces are already checked in Cowlishaw's test-suite, so
519 # here we just check that a trailing newline results in a NaN
520 self.assertEqual(str(nc.create_decimal('3.14\n')), 'NaN')
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000521
522 # from tuples
523 d = Decimal( (1, (4, 3, 4, 9, 1, 3, 5, 3, 4), -25) )
524 self.assertEqual(str(d), '-4.34913534E-17')
525 d = nc.create_decimal( (1, (4, 3, 4, 9, 1, 3, 5, 3, 4), -25) )
526 self.assertEqual(str(d), '-4.35E-17')
527
528 # from Decimal
529 prevdec = Decimal(500000123)
530 d = Decimal(prevdec)
531 self.assertEqual(str(d), '500000123')
532 d = nc.create_decimal(prevdec)
533 self.assertEqual(str(d), '5.00E+8')
534
535
536class DecimalImplicitConstructionTest(unittest.TestCase):
537 '''Unit tests for Implicit Construction cases of Decimal.'''
538
539 def test_implicit_from_None(self):
540 self.assertRaises(TypeError, eval, 'Decimal(5) + None', globals())
541
542 def test_implicit_from_int(self):
543 #normal
544 self.assertEqual(str(Decimal(5) + 45), '50')
545 #exceeding precision
546 self.assertEqual(Decimal(5) + 123456789000, Decimal(123456789000))
547
548 def test_implicit_from_string(self):
549 self.assertRaises(TypeError, eval, 'Decimal(5) + "3"', globals())
550
551 def test_implicit_from_float(self):
552 self.assertRaises(TypeError, eval, 'Decimal(5) + 2.2', globals())
553
554 def test_implicit_from_Decimal(self):
555 self.assertEqual(Decimal(5) + Decimal(45), Decimal(50))
556
Raymond Hettinger267b8682005-03-27 10:47:39 +0000557 def test_rop(self):
558 # Allow other classes to be trained to interact with Decimals
559 class E:
560 def __divmod__(self, other):
561 return 'divmod ' + str(other)
562 def __rdivmod__(self, other):
563 return str(other) + ' rdivmod'
564 def __lt__(self, other):
565 return 'lt ' + str(other)
566 def __gt__(self, other):
567 return 'gt ' + str(other)
568 def __le__(self, other):
569 return 'le ' + str(other)
570 def __ge__(self, other):
571 return 'ge ' + str(other)
572 def __eq__(self, other):
573 return 'eq ' + str(other)
574 def __ne__(self, other):
575 return 'ne ' + str(other)
576
577 self.assertEqual(divmod(E(), Decimal(10)), 'divmod 10')
578 self.assertEqual(divmod(Decimal(10), E()), '10 rdivmod')
579 self.assertEqual(eval('Decimal(10) < E()'), 'gt 10')
580 self.assertEqual(eval('Decimal(10) > E()'), 'lt 10')
581 self.assertEqual(eval('Decimal(10) <= E()'), 'ge 10')
582 self.assertEqual(eval('Decimal(10) >= E()'), 'le 10')
583 self.assertEqual(eval('Decimal(10) == E()'), 'eq 10')
584 self.assertEqual(eval('Decimal(10) != E()'), 'ne 10')
585
586 # insert operator methods and then exercise them
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000587 oplist = [
588 ('+', '__add__', '__radd__'),
589 ('-', '__sub__', '__rsub__'),
590 ('*', '__mul__', '__rmul__'),
Thomas Woutersdcc6d322006-04-21 11:30:52 +0000591 ('/', '__truediv__', '__rtruediv__'),
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000592 ('%', '__mod__', '__rmod__'),
593 ('//', '__floordiv__', '__rfloordiv__'),
594 ('**', '__pow__', '__rpow__')
595 ]
Raymond Hettinger267b8682005-03-27 10:47:39 +0000596
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000597 for sym, lop, rop in oplist:
Raymond Hettinger267b8682005-03-27 10:47:39 +0000598 setattr(E, lop, lambda self, other: 'str' + lop + str(other))
599 setattr(E, rop, lambda self, other: str(other) + rop + 'str')
600 self.assertEqual(eval('E()' + sym + 'Decimal(10)'),
601 'str' + lop + '10')
602 self.assertEqual(eval('Decimal(10)' + sym + 'E()'),
603 '10' + rop + 'str')
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000604
Christian Heimesf16baeb2008-02-29 14:57:44 +0000605class DecimalFormatTest(unittest.TestCase):
606 '''Unit tests for the format function.'''
607 def test_formatting(self):
608 # triples giving a format, a Decimal, and the expected result
609 test_values = [
610 ('e', '0E-15', '0e-15'),
611 ('e', '2.3E-15', '2.3e-15'),
612 ('e', '2.30E+2', '2.30e+2'), # preserve significant zeros
613 ('e', '2.30000E-15', '2.30000e-15'),
614 ('e', '1.23456789123456789e40', '1.23456789123456789e+40'),
615 ('e', '1.5', '1.5e+0'),
616 ('e', '0.15', '1.5e-1'),
617 ('e', '0.015', '1.5e-2'),
618 ('e', '0.0000000000015', '1.5e-12'),
619 ('e', '15.0', '1.50e+1'),
620 ('e', '-15', '-1.5e+1'),
621 ('e', '0', '0e+0'),
622 ('e', '0E1', '0e+1'),
623 ('e', '0.0', '0e-1'),
624 ('e', '0.00', '0e-2'),
625 ('.6e', '0E-15', '0.000000e-9'),
626 ('.6e', '0', '0.000000e+6'),
627 ('.6e', '9.999999', '9.999999e+0'),
628 ('.6e', '9.9999999', '1.000000e+1'),
629 ('.6e', '-1.23e5', '-1.230000e+5'),
630 ('.6e', '1.23456789e-3', '1.234568e-3'),
631 ('f', '0', '0'),
632 ('f', '0.0', '0.0'),
633 ('f', '0E-2', '0.00'),
634 ('f', '0.00E-8', '0.0000000000'),
635 ('f', '0E1', '0'), # loses exponent information
636 ('f', '3.2E1', '32'),
637 ('f', '3.2E2', '320'),
638 ('f', '3.20E2', '320'),
639 ('f', '3.200E2', '320.0'),
640 ('f', '3.2E-6', '0.0000032'),
641 ('.6f', '0E-15', '0.000000'), # all zeros treated equally
642 ('.6f', '0E1', '0.000000'),
643 ('.6f', '0', '0.000000'),
644 ('.0f', '0', '0'), # no decimal point
645 ('.0f', '0e-2', '0'),
646 ('.0f', '3.14159265', '3'),
647 ('.1f', '3.14159265', '3.1'),
648 ('.4f', '3.14159265', '3.1416'),
649 ('.6f', '3.14159265', '3.141593'),
650 ('.7f', '3.14159265', '3.1415926'), # round-half-even!
651 ('.8f', '3.14159265', '3.14159265'),
652 ('.9f', '3.14159265', '3.141592650'),
653
654 ('g', '0', '0'),
655 ('g', '0.0', '0.0'),
656 ('g', '0E1', '0e+1'),
657 ('G', '0E1', '0E+1'),
658 ('g', '0E-5', '0.00000'),
659 ('g', '0E-6', '0.000000'),
660 ('g', '0E-7', '0e-7'),
661 ('g', '-0E2', '-0e+2'),
662 ('.0g', '3.14159265', '3'), # 0 sig fig -> 1 sig fig
663 ('.1g', '3.14159265', '3'),
664 ('.2g', '3.14159265', '3.1'),
665 ('.5g', '3.14159265', '3.1416'),
666 ('.7g', '3.14159265', '3.141593'),
667 ('.8g', '3.14159265', '3.1415926'), # round-half-even!
668 ('.9g', '3.14159265', '3.14159265'),
669 ('.10g', '3.14159265', '3.14159265'), # don't pad
670
671 ('%', '0E1', '0%'),
672 ('%', '0E0', '0%'),
673 ('%', '0E-1', '0%'),
674 ('%', '0E-2', '0%'),
675 ('%', '0E-3', '0.0%'),
676 ('%', '0E-4', '0.00%'),
677
678 ('.3%', '0', '0.000%'), # all zeros treated equally
679 ('.3%', '0E10', '0.000%'),
680 ('.3%', '0E-10', '0.000%'),
681 ('.3%', '2.34', '234.000%'),
682 ('.3%', '1.234567', '123.457%'),
683 ('.0%', '1.23', '123%'),
684
685 ('e', 'NaN', 'NaN'),
686 ('f', '-NaN123', '-NaN123'),
687 ('+g', 'NaN456', '+NaN456'),
688 ('.3e', 'Inf', 'Infinity'),
689 ('.16f', '-Inf', '-Infinity'),
690 ('.0g', '-sNaN', '-sNaN'),
691
692 ('', '1.00', '1.00'),
693 ]
694 for fmt, d, result in test_values:
695 self.assertEqual(format(Decimal(d), fmt), result)
696
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000697class DecimalArithmeticOperatorsTest(unittest.TestCase):
698 '''Unit tests for all arithmetic operators, binary and unary.'''
699
700 def test_addition(self):
701
702 d1 = Decimal('-11.1')
703 d2 = Decimal('22.2')
704
705 #two Decimals
706 self.assertEqual(d1+d2, Decimal('11.1'))
707 self.assertEqual(d2+d1, Decimal('11.1'))
708
709 #with other type, left
710 c = d1 + 5
711 self.assertEqual(c, Decimal('-6.1'))
712 self.assertEqual(type(c), type(d1))
713
714 #with other type, right
715 c = 5 + d1
716 self.assertEqual(c, Decimal('-6.1'))
717 self.assertEqual(type(c), type(d1))
718
719 #inline with decimal
720 d1 += d2
721 self.assertEqual(d1, Decimal('11.1'))
722
723 #inline with other type
724 d1 += 5
725 self.assertEqual(d1, Decimal('16.1'))
726
727 def test_subtraction(self):
728
729 d1 = Decimal('-11.1')
730 d2 = Decimal('22.2')
731
732 #two Decimals
733 self.assertEqual(d1-d2, Decimal('-33.3'))
734 self.assertEqual(d2-d1, Decimal('33.3'))
735
736 #with other type, left
737 c = d1 - 5
738 self.assertEqual(c, Decimal('-16.1'))
739 self.assertEqual(type(c), type(d1))
740
741 #with other type, right
742 c = 5 - d1
743 self.assertEqual(c, Decimal('16.1'))
744 self.assertEqual(type(c), type(d1))
745
746 #inline with decimal
747 d1 -= d2
748 self.assertEqual(d1, Decimal('-33.3'))
749
750 #inline with other type
751 d1 -= 5
752 self.assertEqual(d1, Decimal('-38.3'))
753
754 def test_multiplication(self):
755
756 d1 = Decimal('-5')
757 d2 = Decimal('3')
758
759 #two Decimals
760 self.assertEqual(d1*d2, Decimal('-15'))
761 self.assertEqual(d2*d1, Decimal('-15'))
762
763 #with other type, left
764 c = d1 * 5
765 self.assertEqual(c, Decimal('-25'))
766 self.assertEqual(type(c), type(d1))
767
768 #with other type, right
769 c = 5 * d1
770 self.assertEqual(c, Decimal('-25'))
771 self.assertEqual(type(c), type(d1))
772
773 #inline with decimal
774 d1 *= d2
775 self.assertEqual(d1, Decimal('-15'))
776
777 #inline with other type
778 d1 *= 5
779 self.assertEqual(d1, Decimal('-75'))
780
781 def test_division(self):
782
783 d1 = Decimal('-5')
784 d2 = Decimal('2')
785
786 #two Decimals
787 self.assertEqual(d1/d2, Decimal('-2.5'))
788 self.assertEqual(d2/d1, Decimal('-0.4'))
789
790 #with other type, left
791 c = d1 / 4
792 self.assertEqual(c, Decimal('-1.25'))
793 self.assertEqual(type(c), type(d1))
794
795 #with other type, right
796 c = 4 / d1
797 self.assertEqual(c, Decimal('-0.8'))
798 self.assertEqual(type(c), type(d1))
799
800 #inline with decimal
801 d1 /= d2
802 self.assertEqual(d1, Decimal('-2.5'))
803
804 #inline with other type
805 d1 /= 4
806 self.assertEqual(d1, Decimal('-0.625'))
807
808 def test_floor_division(self):
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000809
810 d1 = Decimal('5')
811 d2 = Decimal('2')
812
813 #two Decimals
814 self.assertEqual(d1//d2, Decimal('2'))
815 self.assertEqual(d2//d1, Decimal('0'))
816
817 #with other type, left
818 c = d1 // 4
819 self.assertEqual(c, Decimal('1'))
820 self.assertEqual(type(c), type(d1))
821
822 #with other type, right
823 c = 7 // d1
824 self.assertEqual(c, Decimal('1'))
825 self.assertEqual(type(c), type(d1))
826
827 #inline with decimal
828 d1 //= d2
829 self.assertEqual(d1, Decimal('2'))
830
831 #inline with other type
832 d1 //= 2
833 self.assertEqual(d1, Decimal('1'))
834
835 def test_powering(self):
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000836
837 d1 = Decimal('5')
838 d2 = Decimal('2')
839
840 #two Decimals
841 self.assertEqual(d1**d2, Decimal('25'))
842 self.assertEqual(d2**d1, Decimal('32'))
843
844 #with other type, left
845 c = d1 ** 4
846 self.assertEqual(c, Decimal('625'))
847 self.assertEqual(type(c), type(d1))
848
849 #with other type, right
850 c = 7 ** d1
851 self.assertEqual(c, Decimal('16807'))
852 self.assertEqual(type(c), type(d1))
853
854 #inline with decimal
855 d1 **= d2
856 self.assertEqual(d1, Decimal('25'))
857
858 #inline with other type
859 d1 **= 4
860 self.assertEqual(d1, Decimal('390625'))
861
862 def test_module(self):
863
864 d1 = Decimal('5')
865 d2 = Decimal('2')
866
867 #two Decimals
868 self.assertEqual(d1%d2, Decimal('1'))
869 self.assertEqual(d2%d1, Decimal('2'))
870
871 #with other type, left
872 c = d1 % 4
873 self.assertEqual(c, Decimal('1'))
874 self.assertEqual(type(c), type(d1))
875
876 #with other type, right
877 c = 7 % d1
878 self.assertEqual(c, Decimal('2'))
879 self.assertEqual(type(c), type(d1))
880
881 #inline with decimal
882 d1 %= d2
883 self.assertEqual(d1, Decimal('1'))
884
885 #inline with other type
886 d1 %= 4
887 self.assertEqual(d1, Decimal('1'))
888
889 def test_floor_div_module(self):
890
891 d1 = Decimal('5')
892 d2 = Decimal('2')
893
894 #two Decimals
895 (p, q) = divmod(d1, d2)
896 self.assertEqual(p, Decimal('2'))
897 self.assertEqual(q, Decimal('1'))
898 self.assertEqual(type(p), type(d1))
899 self.assertEqual(type(q), type(d1))
900
901 #with other type, left
902 (p, q) = divmod(d1, 4)
903 self.assertEqual(p, Decimal('1'))
904 self.assertEqual(q, Decimal('1'))
905 self.assertEqual(type(p), type(d1))
906 self.assertEqual(type(q), type(d1))
907
908 #with other type, right
909 (p, q) = divmod(7, d1)
910 self.assertEqual(p, Decimal('1'))
911 self.assertEqual(q, Decimal('2'))
912 self.assertEqual(type(p), type(d1))
913 self.assertEqual(type(q), type(d1))
914
915 def test_unary_operators(self):
916 self.assertEqual(+Decimal(45), Decimal(+45)) # +
917 self.assertEqual(-Decimal(45), Decimal(-45)) # -
918 self.assertEqual(abs(Decimal(45)), abs(Decimal(-45))) # abs
919
Christian Heimes77c02eb2008-02-09 02:18:51 +0000920 def test_nan_comparisons(self):
921 n = Decimal('NaN')
922 s = Decimal('sNaN')
923 i = Decimal('Inf')
924 f = Decimal('2')
925 for x, y in [(n, n), (n, i), (i, n), (n, f), (f, n),
926 (s, n), (n, s), (s, i), (i, s), (s, f), (f, s), (s, s)]:
927 self.assert_(x != y)
928 self.assert_(not (x == y))
929 self.assert_(not (x < y))
930 self.assert_(not (x <= y))
931 self.assert_(not (x > y))
932 self.assert_(not (x >= y))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000933
934# The following are two functions used to test threading in the next class
935
936def thfunc1(cls):
937 d1 = Decimal(1)
938 d3 = Decimal(3)
Christian Heimesfe337bf2008-03-23 21:54:12 +0000939 test1 = d1/d3
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000940 cls.synchro.wait()
Christian Heimesfe337bf2008-03-23 21:54:12 +0000941 test2 = d1/d3
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000942 cls.finish1.set()
Christian Heimesfe337bf2008-03-23 21:54:12 +0000943
Christian Heimes81ee3ef2008-05-04 22:42:01 +0000944 cls.assertEqual(test1, Decimal('0.3333333333333333333333333333'))
945 cls.assertEqual(test2, Decimal('0.3333333333333333333333333333'))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000946 return
947
948def thfunc2(cls):
949 d1 = Decimal(1)
950 d3 = Decimal(3)
Christian Heimesfe337bf2008-03-23 21:54:12 +0000951 test1 = d1/d3
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000952 thiscontext = getcontext()
953 thiscontext.prec = 18
Christian Heimesfe337bf2008-03-23 21:54:12 +0000954 test2 = d1/d3
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000955 cls.synchro.set()
956 cls.finish2.set()
Christian Heimesfe337bf2008-03-23 21:54:12 +0000957
Christian Heimes81ee3ef2008-05-04 22:42:01 +0000958 cls.assertEqual(test1, Decimal('0.3333333333333333333333333333'))
Christian Heimesfe337bf2008-03-23 21:54:12 +0000959 cls.assertEqual(test2, Decimal('0.333333333333333333'))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000960 return
961
962
963class DecimalUseOfContextTest(unittest.TestCase):
964 '''Unit tests for Use of Context cases in Decimal.'''
965
Raymond Hettinger7e71fa52004-12-18 19:07:19 +0000966 try:
967 import threading
968 except ImportError:
969 threading = None
970
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000971 # Take care executing this test from IDLE, there's an issue in threading
972 # that hangs IDLE and I couldn't find it
973
974 def test_threading(self):
975 #Test the "threading isolation" of a Context.
976
977 self.synchro = threading.Event()
978 self.finish1 = threading.Event()
979 self.finish2 = threading.Event()
980
981 th1 = threading.Thread(target=thfunc1, args=(self,))
982 th2 = threading.Thread(target=thfunc2, args=(self,))
983
984 th1.start()
985 th2.start()
986
987 self.finish1.wait()
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000988 self.finish2.wait()
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000989 return
990
Raymond Hettinger7e71fa52004-12-18 19:07:19 +0000991 if threading is None:
992 del test_threading
993
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000994
995class DecimalUsabilityTest(unittest.TestCase):
996 '''Unit tests for Usability cases of Decimal.'''
997
998 def test_comparison_operators(self):
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000999
1000 da = Decimal('23.42')
1001 db = Decimal('23.42')
1002 dc = Decimal('45')
1003
1004 #two Decimals
1005 self.failUnless(dc > da)
1006 self.failUnless(dc >= da)
1007 self.failUnless(da < dc)
1008 self.failUnless(da <= dc)
Guido van Rossume61fd5b2007-07-11 12:20:59 +00001009 self.assertEqual(da, db)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001010 self.failUnless(da != dc)
1011 self.failUnless(da <= db)
1012 self.failUnless(da >= db)
1013 self.assertEqual(cmp(dc,da), 1)
1014 self.assertEqual(cmp(da,dc), -1)
1015 self.assertEqual(cmp(da,db), 0)
1016
1017 #a Decimal and an int
1018 self.failUnless(dc > 23)
1019 self.failUnless(23 < dc)
Guido van Rossume61fd5b2007-07-11 12:20:59 +00001020 self.assertEqual(dc, 45)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001021 self.assertEqual(cmp(dc,23), 1)
1022 self.assertEqual(cmp(23,dc), -1)
1023 self.assertEqual(cmp(dc,45), 0)
1024
1025 #a Decimal and uncomparable
Raymond Hettinger0aeac102004-07-05 22:53:03 +00001026 self.assertNotEqual(da, 'ugly')
1027 self.assertNotEqual(da, 32.7)
1028 self.assertNotEqual(da, object())
1029 self.assertNotEqual(da, object)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001030
Raymond Hettinger0aeac102004-07-05 22:53:03 +00001031 # sortable
Guido van Rossumc1f779c2007-07-03 08:25:58 +00001032 a = list(map(Decimal, range(100)))
Raymond Hettinger0aeac102004-07-05 22:53:03 +00001033 b = a[:]
1034 random.shuffle(a)
1035 a.sort()
1036 self.assertEqual(a, b)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001037
1038 def test_copy_and_deepcopy_methods(self):
1039 d = Decimal('43.24')
1040 c = copy.copy(d)
1041 self.assertEqual(id(c), id(d))
1042 dc = copy.deepcopy(d)
1043 self.assertEqual(id(dc), id(d))
1044
1045 def test_hash_method(self):
1046 #just that it's hashable
1047 hash(Decimal(23))
Thomas Wouters8ce81f72007-09-20 18:22:40 +00001048
1049 test_values = [Decimal(sign*(2**m + n))
1050 for m in [0, 14, 15, 16, 17, 30, 31,
1051 32, 33, 62, 63, 64, 65, 66]
1052 for n in range(-10, 10)
1053 for sign in [-1, 1]]
1054 test_values.extend([
1055 Decimal("-0"), # zeros
1056 Decimal("0.00"),
1057 Decimal("-0.000"),
1058 Decimal("0E10"),
1059 Decimal("-0E12"),
1060 Decimal("10.0"), # negative exponent
1061 Decimal("-23.00000"),
1062 Decimal("1230E100"), # positive exponent
1063 Decimal("-4.5678E50"),
1064 # a value for which hash(n) != hash(n % (2**64-1))
1065 # in Python pre-2.6
1066 Decimal(2**64 + 2**32 - 1),
1067 # selection of values which fail with the old (before
1068 # version 2.6) long.__hash__
1069 Decimal("1.634E100"),
1070 Decimal("90.697E100"),
1071 Decimal("188.83E100"),
1072 Decimal("1652.9E100"),
1073 Decimal("56531E100"),
1074 ])
1075
1076 # check that hash(d) == hash(int(d)) for integral values
1077 for value in test_values:
1078 self.assertEqual(hash(value), hash(int(value)))
1079
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001080 #the same hash that to an int
1081 self.assertEqual(hash(Decimal(23)), hash(23))
Raymond Hettingerbea3f6f2005-03-15 04:59:17 +00001082 self.assertRaises(TypeError, hash, Decimal('NaN'))
1083 self.assert_(hash(Decimal('Inf')))
1084 self.assert_(hash(Decimal('-Inf')))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001085
Christian Heimes2380ac72008-01-09 00:17:24 +00001086 # check that the value of the hash doesn't depend on the
1087 # current context (issue #1757)
1088 c = getcontext()
1089 old_precision = c.prec
1090 x = Decimal("123456789.1")
1091
1092 c.prec = 6
1093 h1 = hash(x)
1094 c.prec = 10
1095 h2 = hash(x)
1096 c.prec = 16
1097 h3 = hash(x)
1098
1099 self.assertEqual(h1, h2)
1100 self.assertEqual(h1, h3)
1101 c.prec = old_precision
1102
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001103 def test_min_and_max_methods(self):
1104
1105 d1 = Decimal('15.32')
1106 d2 = Decimal('28.5')
1107 l1 = 15
1108 l2 = 28
1109
1110 #between Decimals
1111 self.failUnless(min(d1,d2) is d1)
1112 self.failUnless(min(d2,d1) is d1)
1113 self.failUnless(max(d1,d2) is d2)
1114 self.failUnless(max(d2,d1) is d2)
1115
1116 #between Decimal and long
1117 self.failUnless(min(d1,l2) is d1)
1118 self.failUnless(min(l2,d1) is d1)
1119 self.failUnless(max(l1,d2) is d2)
1120 self.failUnless(max(d2,l1) is d2)
1121
1122 def test_as_nonzero(self):
1123 #as false
1124 self.failIf(Decimal(0))
1125 #as true
1126 self.failUnless(Decimal('0.372'))
1127
1128 def test_tostring_methods(self):
1129 #Test str and repr methods.
1130
1131 d = Decimal('15.32')
1132 self.assertEqual(str(d), '15.32') # str
Christian Heimes68f5fbe2008-02-14 08:27:37 +00001133 self.assertEqual(repr(d), "Decimal('15.32')") # repr
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001134
1135 def test_tonum_methods(self):
1136 #Test float, int and long methods.
1137
1138 d1 = Decimal('66')
1139 d2 = Decimal('15.32')
1140
1141 #int
1142 self.assertEqual(int(d1), 66)
1143 self.assertEqual(int(d2), 15)
1144
1145 #long
Guido van Rossume2a383d2007-01-15 16:59:06 +00001146 self.assertEqual(int(d1), 66)
1147 self.assertEqual(int(d2), 15)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001148
1149 #float
1150 self.assertEqual(float(d1), 66)
1151 self.assertEqual(float(d2), 15.32)
1152
1153 def test_eval_round_trip(self):
1154
1155 #with zero
1156 d = Decimal( (0, (0,), 0) )
1157 self.assertEqual(d, eval(repr(d)))
1158
1159 #int
1160 d = Decimal( (1, (4, 5), 0) )
1161 self.assertEqual(d, eval(repr(d)))
1162
1163 #float
1164 d = Decimal( (0, (4, 5, 3, 4), -2) )
1165 self.assertEqual(d, eval(repr(d)))
1166
1167 #weird
1168 d = Decimal( (1, (4, 3, 4, 9, 1, 3, 5, 3, 4), -25) )
1169 self.assertEqual(d, eval(repr(d)))
1170
1171 def test_as_tuple(self):
1172
1173 #with zero
1174 d = Decimal(0)
1175 self.assertEqual(d.as_tuple(), (0, (0,), 0) )
1176
1177 #int
1178 d = Decimal(-45)
1179 self.assertEqual(d.as_tuple(), (1, (4, 5), 0) )
1180
1181 #complicated string
1182 d = Decimal("-4.34913534E-17")
1183 self.assertEqual(d.as_tuple(), (1, (4, 3, 4, 9, 1, 3, 5, 3, 4), -25) )
1184
1185 #inf
1186 d = Decimal("Infinity")
1187 self.assertEqual(d.as_tuple(), (0, (0,), 'F') )
1188
Guido van Rossum8ce8a782007-11-01 19:42:39 +00001189 #leading zeros in coefficient should be stripped
1190 d = Decimal( (0, (0, 0, 4, 0, 5, 3, 4), -2) )
1191 self.assertEqual(d.as_tuple(), (0, (4, 0, 5, 3, 4), -2) )
1192 d = Decimal( (1, (0, 0, 0), 37) )
1193 self.assertEqual(d.as_tuple(), (1, (0,), 37))
1194 d = Decimal( (1, (), 37) )
1195 self.assertEqual(d.as_tuple(), (1, (0,), 37))
1196
1197 #leading zeros in NaN diagnostic info should be stripped
1198 d = Decimal( (0, (0, 0, 4, 0, 5, 3, 4), 'n') )
1199 self.assertEqual(d.as_tuple(), (0, (4, 0, 5, 3, 4), 'n') )
1200 d = Decimal( (1, (0, 0, 0), 'N') )
1201 self.assertEqual(d.as_tuple(), (1, (), 'N') )
1202 d = Decimal( (1, (), 'n') )
1203 self.assertEqual(d.as_tuple(), (1, (), 'n') )
1204
1205 #coefficient in infinity should be ignored
1206 d = Decimal( (0, (4, 5, 3, 4), 'F') )
1207 self.assertEqual(d.as_tuple(), (0, (0,), 'F'))
1208 d = Decimal( (1, (0, 2, 7, 1), 'F') )
1209 self.assertEqual(d.as_tuple(), (1, (0,), 'F'))
1210
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001211 def test_immutability_operations(self):
1212 # Do operations and check that it didn't change change internal objects.
1213
1214 d1 = Decimal('-25e55')
1215 b1 = Decimal('-25e55')
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001216 d2 = Decimal('33e+33')
1217 b2 = Decimal('33e+33')
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001218
1219 def checkSameDec(operation, useOther=False):
1220 if useOther:
1221 eval("d1." + operation + "(d2)")
1222 self.assertEqual(d1._sign, b1._sign)
1223 self.assertEqual(d1._int, b1._int)
1224 self.assertEqual(d1._exp, b1._exp)
1225 self.assertEqual(d2._sign, b2._sign)
1226 self.assertEqual(d2._int, b2._int)
1227 self.assertEqual(d2._exp, b2._exp)
1228 else:
1229 eval("d1." + operation + "()")
1230 self.assertEqual(d1._sign, b1._sign)
1231 self.assertEqual(d1._int, b1._int)
1232 self.assertEqual(d1._exp, b1._exp)
1233 return
1234
1235 Decimal(d1)
1236 self.assertEqual(d1._sign, b1._sign)
1237 self.assertEqual(d1._int, b1._int)
1238 self.assertEqual(d1._exp, b1._exp)
1239
1240 checkSameDec("__abs__")
1241 checkSameDec("__add__", True)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001242 checkSameDec("__divmod__", True)
Christian Heimes77c02eb2008-02-09 02:18:51 +00001243 checkSameDec("__eq__", True)
1244 checkSameDec("__ne__", True)
1245 checkSameDec("__le__", True)
1246 checkSameDec("__lt__", True)
1247 checkSameDec("__ge__", True)
1248 checkSameDec("__gt__", True)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001249 checkSameDec("__float__")
1250 checkSameDec("__floordiv__", True)
1251 checkSameDec("__hash__")
1252 checkSameDec("__int__")
Christian Heimes969fe572008-01-25 11:23:10 +00001253 checkSameDec("__trunc__")
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001254 checkSameDec("__mod__", True)
1255 checkSameDec("__mul__", True)
1256 checkSameDec("__neg__")
Jack Diederich4dafcc42006-11-28 19:15:13 +00001257 checkSameDec("__bool__")
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001258 checkSameDec("__pos__")
1259 checkSameDec("__pow__", True)
1260 checkSameDec("__radd__", True)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001261 checkSameDec("__rdivmod__", True)
1262 checkSameDec("__repr__")
1263 checkSameDec("__rfloordiv__", True)
1264 checkSameDec("__rmod__", True)
1265 checkSameDec("__rmul__", True)
1266 checkSameDec("__rpow__", True)
1267 checkSameDec("__rsub__", True)
1268 checkSameDec("__str__")
1269 checkSameDec("__sub__", True)
1270 checkSameDec("__truediv__", True)
1271 checkSameDec("adjusted")
1272 checkSameDec("as_tuple")
1273 checkSameDec("compare", True)
1274 checkSameDec("max", True)
1275 checkSameDec("min", True)
1276 checkSameDec("normalize")
1277 checkSameDec("quantize", True)
1278 checkSameDec("remainder_near", True)
1279 checkSameDec("same_quantum", True)
1280 checkSameDec("sqrt")
1281 checkSameDec("to_eng_string")
1282 checkSameDec("to_integral")
1283
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001284 def test_subclassing(self):
1285 # Different behaviours when subclassing Decimal
1286
1287 class MyDecimal(Decimal):
1288 pass
1289
1290 d1 = MyDecimal(1)
1291 d2 = MyDecimal(2)
1292 d = d1 + d2
1293 self.assertTrue(type(d) is Decimal)
1294
1295 d = d1.max(d2)
1296 self.assertTrue(type(d) is Decimal)
1297
Christian Heimes0348fb62008-03-26 12:55:56 +00001298 def test_implicit_context(self):
1299 # Check results when context given implicitly. (Issue 2478)
1300 c = getcontext()
1301 self.assertEqual(str(Decimal(0).sqrt()),
1302 str(c.sqrt(Decimal(0))))
1303
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001304
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001305class DecimalPythonAPItests(unittest.TestCase):
1306
1307 def test_pickle(self):
1308 d = Decimal('-3.141590000')
1309 p = pickle.dumps(d)
1310 e = pickle.loads(p)
1311 self.assertEqual(d, e)
1312
Raymond Hettinger5548be22004-07-05 18:49:38 +00001313 def test_int(self):
Raymond Hettinger605ed022004-11-24 07:28:48 +00001314 for x in range(-250, 250):
1315 s = '%0.2f' % (x / 100.0)
Raymond Hettinger5548be22004-07-05 18:49:38 +00001316 # should work the same as for floats
1317 self.assertEqual(int(Decimal(s)), int(float(s)))
Raymond Hettinger605ed022004-11-24 07:28:48 +00001318 # should work the same as to_integral in the ROUND_DOWN mode
Raymond Hettinger5548be22004-07-05 18:49:38 +00001319 d = Decimal(s)
Raymond Hettinger605ed022004-11-24 07:28:48 +00001320 r = d.to_integral(ROUND_DOWN)
Raymond Hettinger5548be22004-07-05 18:49:38 +00001321 self.assertEqual(Decimal(int(d)), r)
1322
Christian Heimes969fe572008-01-25 11:23:10 +00001323 def test_trunc(self):
1324 for x in range(-250, 250):
1325 s = '%0.2f' % (x / 100.0)
1326 # should work the same as for floats
1327 self.assertEqual(int(Decimal(s)), int(float(s)))
1328 # should work the same as to_integral in the ROUND_DOWN mode
1329 d = Decimal(s)
1330 r = d.to_integral(ROUND_DOWN)
Christian Heimes400adb02008-02-01 08:12:03 +00001331 self.assertEqual(Decimal(math.trunc(d)), r)
Christian Heimes969fe572008-01-25 11:23:10 +00001332
Raymond Hettingerd9c0a7a2004-07-03 10:02:28 +00001333class ContextAPItests(unittest.TestCase):
1334
1335 def test_pickle(self):
1336 c = Context()
1337 e = pickle.loads(pickle.dumps(c))
1338 for k in vars(c):
1339 v1 = vars(c)[k]
1340 v2 = vars(e)[k]
1341 self.assertEqual(v1, v2)
1342
Raymond Hettinger0aeac102004-07-05 22:53:03 +00001343 def test_equality_with_other_types(self):
1344 self.assert_(Decimal(10) in ['a', 1.0, Decimal(10), (1,2), {}])
1345 self.assert_(Decimal(10) not in ['a', 1.0, (1,2), {}])
1346
Raymond Hettinger955d2b22004-08-08 20:17:45 +00001347 def test_copy(self):
1348 # All copies should be deep
1349 c = Context()
1350 d = c.copy()
1351 self.assertNotEqual(id(c), id(d))
1352 self.assertNotEqual(id(c.flags), id(d.flags))
1353 self.assertNotEqual(id(c.traps), id(d.traps))
1354
Thomas Wouters89f507f2006-12-13 04:49:30 +00001355class WithStatementTest(unittest.TestCase):
1356 # Can't do these as docstrings until Python 2.6
1357 # as doctest can't handle __future__ statements
1358
1359 def test_localcontext(self):
1360 # Use a copy of the current context in the block
1361 orig_ctx = getcontext()
1362 with localcontext() as enter_ctx:
1363 set_ctx = getcontext()
1364 final_ctx = getcontext()
1365 self.assert_(orig_ctx is final_ctx, 'did not restore context correctly')
1366 self.assert_(orig_ctx is not set_ctx, 'did not copy the context')
1367 self.assert_(set_ctx is enter_ctx, '__enter__ returned wrong context')
1368
1369 def test_localcontextarg(self):
1370 # Use a copy of the supplied context in the block
1371 orig_ctx = getcontext()
1372 new_ctx = Context(prec=42)
1373 with localcontext(new_ctx) as enter_ctx:
1374 set_ctx = getcontext()
1375 final_ctx = getcontext()
1376 self.assert_(orig_ctx is final_ctx, 'did not restore context correctly')
1377 self.assert_(set_ctx.prec == new_ctx.prec, 'did not set correct context')
1378 self.assert_(new_ctx is not set_ctx, 'did not copy the context')
1379 self.assert_(set_ctx is enter_ctx, '__enter__ returned wrong context')
1380
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001381class ContextFlags(unittest.TestCase):
1382 def test_flags_irrelevant(self):
1383 # check that the result (numeric result + flags raised) of an
1384 # arithmetic operation doesn't depend on the current flags
1385
1386 context = Context(prec=9, Emin = -999999999, Emax = 999999999,
1387 rounding=ROUND_HALF_EVEN, traps=[], flags=[])
1388
1389 # operations that raise various flags, in the form (function, arglist)
1390 operations = [
1391 (context._apply, [Decimal("100E-1000000009")]),
1392 (context.sqrt, [Decimal(2)]),
1393 (context.add, [Decimal("1.23456789"), Decimal("9.87654321")]),
1394 (context.multiply, [Decimal("1.23456789"), Decimal("9.87654321")]),
1395 (context.subtract, [Decimal("1.23456789"), Decimal("9.87654321")]),
1396 ]
1397
1398 # try various flags individually, then a whole lot at once
1399 flagsets = [[Inexact], [Rounded], [Underflow], [Clamped], [Subnormal],
1400 [Inexact, Rounded, Underflow, Clamped, Subnormal]]
1401
1402 for fn, args in operations:
1403 # find answer and flags raised using a clean context
1404 context.clear_flags()
1405 ans = fn(*args)
1406 flags = [k for k, v in context.flags.items() if v]
1407
1408 for extra_flags in flagsets:
1409 # set flags, before calling operation
1410 context.clear_flags()
1411 for flag in extra_flags:
1412 context._raise_error(flag)
1413 new_ans = fn(*args)
1414
1415 # flags that we expect to be set after the operation
1416 expected_flags = list(flags)
1417 for flag in extra_flags:
1418 if flag not in expected_flags:
1419 expected_flags.append(flag)
1420 expected_flags.sort(key=id)
1421
1422 # flags we actually got
1423 new_flags = [k for k,v in context.flags.items() if v]
1424 new_flags.sort(key=id)
1425
1426 self.assertEqual(ans, new_ans,
1427 "operation produces different answers depending on flags set: " +
1428 "expected %s, got %s." % (ans, new_ans))
1429 self.assertEqual(new_flags, expected_flags,
1430 "operation raises different flags depending on flags set: " +
1431 "expected %s, got %s" % (expected_flags, new_flags))
1432
1433def test_main(arith=False, verbose=None, todo_tests=None, debug=None):
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001434 """ Execute the tests.
1435
Raymond Hettingered20ad82004-09-04 20:09:13 +00001436 Runs all arithmetic tests if arith is True or if the "decimal" resource
1437 is enabled in regrtest.py
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001438 """
Raymond Hettingered20ad82004-09-04 20:09:13 +00001439
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00001440 init()
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001441 global TEST_ALL, DEBUG
Raymond Hettingered20ad82004-09-04 20:09:13 +00001442 TEST_ALL = arith or is_resource_enabled('decimal')
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001443 DEBUG = debug
Raymond Hettingered20ad82004-09-04 20:09:13 +00001444
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001445 if todo_tests is None:
1446 test_classes = [
1447 DecimalExplicitConstructionTest,
1448 DecimalImplicitConstructionTest,
1449 DecimalArithmeticOperatorsTest,
Christian Heimesf16baeb2008-02-29 14:57:44 +00001450 DecimalFormatTest,
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001451 DecimalUseOfContextTest,
1452 DecimalUsabilityTest,
1453 DecimalPythonAPItests,
1454 ContextAPItests,
1455 DecimalTest,
1456 WithStatementTest,
1457 ContextFlags
1458 ]
1459 else:
1460 test_classes = [DecimalTest]
1461
1462 # Dynamically build custom test definition for each file in the test
1463 # directory and add the definitions to the DecimalTest class. This
1464 # procedure insures that new files do not get skipped.
1465 for filename in os.listdir(directory):
1466 if '.decTest' not in filename or filename.startswith("."):
1467 continue
1468 head, tail = filename.split('.')
1469 if todo_tests is not None and head not in todo_tests:
1470 continue
1471 tester = lambda self, f=filename: self.eval_file(directory + f)
1472 setattr(DecimalTest, 'test_' + head, tester)
1473 del filename, head, tail, tester
1474
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001475
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00001476 try:
1477 run_unittest(*test_classes)
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001478 if todo_tests is None:
1479 import decimal as DecimalModule
1480 run_doctest(DecimalModule, verbose)
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00001481 finally:
1482 setcontext(ORIGINAL_CONTEXT)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001483
1484if __name__ == '__main__':
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001485 import optparse
1486 p = optparse.OptionParser("test_decimal.py [--debug] [{--skip | test1 [test2 [...]]}]")
1487 p.add_option('--debug', '-d', action='store_true', help='shows the test number and context before each test')
1488 p.add_option('--skip', '-s', action='store_true', help='skip over 90% of the arithmetic tests')
1489 (opt, args) = p.parse_args()
1490
1491 if opt.skip:
1492 test_main(arith=False, verbose=True)
1493 elif args:
1494 test_main(arith=True, verbose=True, todo_tests=args, debug=opt.debug)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001495 else:
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001496 test_main(arith=True, verbose=True)