blob: 1ef0ad3025b4a4ae4d48568314f7ec223320530a [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
613class DecimalArithmeticOperatorsTest(unittest.TestCase):
614 '''Unit tests for all arithmetic operators, binary and unary.'''
615
616 def test_addition(self):
617
618 d1 = Decimal('-11.1')
619 d2 = Decimal('22.2')
620
621 #two Decimals
622 self.assertEqual(d1+d2, Decimal('11.1'))
623 self.assertEqual(d2+d1, Decimal('11.1'))
624
625 #with other type, left
626 c = d1 + 5
627 self.assertEqual(c, Decimal('-6.1'))
628 self.assertEqual(type(c), type(d1))
629
630 #with other type, right
631 c = 5 + d1
632 self.assertEqual(c, Decimal('-6.1'))
633 self.assertEqual(type(c), type(d1))
634
635 #inline with decimal
636 d1 += d2
637 self.assertEqual(d1, Decimal('11.1'))
638
639 #inline with other type
640 d1 += 5
641 self.assertEqual(d1, Decimal('16.1'))
642
643 def test_subtraction(self):
644
645 d1 = Decimal('-11.1')
646 d2 = Decimal('22.2')
647
648 #two Decimals
649 self.assertEqual(d1-d2, Decimal('-33.3'))
650 self.assertEqual(d2-d1, Decimal('33.3'))
651
652 #with other type, left
653 c = d1 - 5
654 self.assertEqual(c, Decimal('-16.1'))
655 self.assertEqual(type(c), type(d1))
656
657 #with other type, right
658 c = 5 - d1
659 self.assertEqual(c, Decimal('16.1'))
660 self.assertEqual(type(c), type(d1))
661
662 #inline with decimal
663 d1 -= d2
664 self.assertEqual(d1, Decimal('-33.3'))
665
666 #inline with other type
667 d1 -= 5
668 self.assertEqual(d1, Decimal('-38.3'))
669
670 def test_multiplication(self):
671
672 d1 = Decimal('-5')
673 d2 = Decimal('3')
674
675 #two Decimals
676 self.assertEqual(d1*d2, Decimal('-15'))
677 self.assertEqual(d2*d1, Decimal('-15'))
678
679 #with other type, left
680 c = d1 * 5
681 self.assertEqual(c, Decimal('-25'))
682 self.assertEqual(type(c), type(d1))
683
684 #with other type, right
685 c = 5 * d1
686 self.assertEqual(c, Decimal('-25'))
687 self.assertEqual(type(c), type(d1))
688
689 #inline with decimal
690 d1 *= d2
691 self.assertEqual(d1, Decimal('-15'))
692
693 #inline with other type
694 d1 *= 5
695 self.assertEqual(d1, Decimal('-75'))
696
697 def test_division(self):
698
699 d1 = Decimal('-5')
700 d2 = Decimal('2')
701
702 #two Decimals
703 self.assertEqual(d1/d2, Decimal('-2.5'))
704 self.assertEqual(d2/d1, Decimal('-0.4'))
705
706 #with other type, left
707 c = d1 / 4
708 self.assertEqual(c, Decimal('-1.25'))
709 self.assertEqual(type(c), type(d1))
710
711 #with other type, right
712 c = 4 / d1
713 self.assertEqual(c, Decimal('-0.8'))
714 self.assertEqual(type(c), type(d1))
715
716 #inline with decimal
717 d1 /= d2
718 self.assertEqual(d1, Decimal('-2.5'))
719
720 #inline with other type
721 d1 /= 4
722 self.assertEqual(d1, Decimal('-0.625'))
723
724 def test_floor_division(self):
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000725
726 d1 = Decimal('5')
727 d2 = Decimal('2')
728
729 #two Decimals
730 self.assertEqual(d1//d2, Decimal('2'))
731 self.assertEqual(d2//d1, Decimal('0'))
732
733 #with other type, left
734 c = d1 // 4
735 self.assertEqual(c, Decimal('1'))
736 self.assertEqual(type(c), type(d1))
737
738 #with other type, right
739 c = 7 // d1
740 self.assertEqual(c, Decimal('1'))
741 self.assertEqual(type(c), type(d1))
742
743 #inline with decimal
744 d1 //= d2
745 self.assertEqual(d1, Decimal('2'))
746
747 #inline with other type
748 d1 //= 2
749 self.assertEqual(d1, Decimal('1'))
750
751 def test_powering(self):
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000752
753 d1 = Decimal('5')
754 d2 = Decimal('2')
755
756 #two Decimals
757 self.assertEqual(d1**d2, Decimal('25'))
758 self.assertEqual(d2**d1, Decimal('32'))
759
760 #with other type, left
761 c = d1 ** 4
762 self.assertEqual(c, Decimal('625'))
763 self.assertEqual(type(c), type(d1))
764
765 #with other type, right
766 c = 7 ** d1
767 self.assertEqual(c, Decimal('16807'))
768 self.assertEqual(type(c), type(d1))
769
770 #inline with decimal
771 d1 **= d2
772 self.assertEqual(d1, Decimal('25'))
773
774 #inline with other type
775 d1 **= 4
776 self.assertEqual(d1, Decimal('390625'))
777
778 def test_module(self):
779
780 d1 = Decimal('5')
781 d2 = Decimal('2')
782
783 #two Decimals
784 self.assertEqual(d1%d2, Decimal('1'))
785 self.assertEqual(d2%d1, Decimal('2'))
786
787 #with other type, left
788 c = d1 % 4
789 self.assertEqual(c, Decimal('1'))
790 self.assertEqual(type(c), type(d1))
791
792 #with other type, right
793 c = 7 % d1
794 self.assertEqual(c, Decimal('2'))
795 self.assertEqual(type(c), type(d1))
796
797 #inline with decimal
798 d1 %= d2
799 self.assertEqual(d1, Decimal('1'))
800
801 #inline with other type
802 d1 %= 4
803 self.assertEqual(d1, Decimal('1'))
804
805 def test_floor_div_module(self):
806
807 d1 = Decimal('5')
808 d2 = Decimal('2')
809
810 #two Decimals
811 (p, q) = divmod(d1, d2)
812 self.assertEqual(p, Decimal('2'))
813 self.assertEqual(q, Decimal('1'))
814 self.assertEqual(type(p), type(d1))
815 self.assertEqual(type(q), type(d1))
816
817 #with other type, left
818 (p, q) = divmod(d1, 4)
819 self.assertEqual(p, Decimal('1'))
820 self.assertEqual(q, Decimal('1'))
821 self.assertEqual(type(p), type(d1))
822 self.assertEqual(type(q), type(d1))
823
824 #with other type, right
825 (p, q) = divmod(7, d1)
826 self.assertEqual(p, Decimal('1'))
827 self.assertEqual(q, Decimal('2'))
828 self.assertEqual(type(p), type(d1))
829 self.assertEqual(type(q), type(d1))
830
831 def test_unary_operators(self):
832 self.assertEqual(+Decimal(45), Decimal(+45)) # +
833 self.assertEqual(-Decimal(45), Decimal(-45)) # -
834 self.assertEqual(abs(Decimal(45)), abs(Decimal(-45))) # abs
835
Christian Heimes77c02eb2008-02-09 02:18:51 +0000836 def test_nan_comparisons(self):
837 n = Decimal('NaN')
838 s = Decimal('sNaN')
839 i = Decimal('Inf')
840 f = Decimal('2')
841 for x, y in [(n, n), (n, i), (i, n), (n, f), (f, n),
842 (s, n), (n, s), (s, i), (i, s), (s, f), (f, s), (s, s)]:
843 self.assert_(x != y)
844 self.assert_(not (x == y))
845 self.assert_(not (x < y))
846 self.assert_(not (x <= y))
847 self.assert_(not (x > y))
848 self.assert_(not (x >= y))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000849
850# The following are two functions used to test threading in the next class
851
852def thfunc1(cls):
853 d1 = Decimal(1)
854 d3 = Decimal(3)
855 cls.assertEqual(d1/d3, Decimal('0.333333333'))
856 cls.synchro.wait()
857 cls.assertEqual(d1/d3, Decimal('0.333333333'))
858 cls.finish1.set()
859 return
860
861def thfunc2(cls):
862 d1 = Decimal(1)
863 d3 = Decimal(3)
864 cls.assertEqual(d1/d3, Decimal('0.333333333'))
865 thiscontext = getcontext()
866 thiscontext.prec = 18
867 cls.assertEqual(d1/d3, Decimal('0.333333333333333333'))
868 cls.synchro.set()
869 cls.finish2.set()
870 return
871
872
873class DecimalUseOfContextTest(unittest.TestCase):
874 '''Unit tests for Use of Context cases in Decimal.'''
875
Raymond Hettinger7e71fa52004-12-18 19:07:19 +0000876 try:
877 import threading
878 except ImportError:
879 threading = None
880
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000881 # Take care executing this test from IDLE, there's an issue in threading
882 # that hangs IDLE and I couldn't find it
883
884 def test_threading(self):
885 #Test the "threading isolation" of a Context.
886
887 self.synchro = threading.Event()
888 self.finish1 = threading.Event()
889 self.finish2 = threading.Event()
890
891 th1 = threading.Thread(target=thfunc1, args=(self,))
892 th2 = threading.Thread(target=thfunc2, args=(self,))
893
894 th1.start()
895 th2.start()
896
897 self.finish1.wait()
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000898 self.finish2.wait()
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000899 return
900
Raymond Hettinger7e71fa52004-12-18 19:07:19 +0000901 if threading is None:
902 del test_threading
903
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000904
905class DecimalUsabilityTest(unittest.TestCase):
906 '''Unit tests for Usability cases of Decimal.'''
907
908 def test_comparison_operators(self):
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000909
910 da = Decimal('23.42')
911 db = Decimal('23.42')
912 dc = Decimal('45')
913
914 #two Decimals
915 self.failUnless(dc > da)
916 self.failUnless(dc >= da)
917 self.failUnless(da < dc)
918 self.failUnless(da <= dc)
Guido van Rossume61fd5b2007-07-11 12:20:59 +0000919 self.assertEqual(da, db)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000920 self.failUnless(da != dc)
921 self.failUnless(da <= db)
922 self.failUnless(da >= db)
923 self.assertEqual(cmp(dc,da), 1)
924 self.assertEqual(cmp(da,dc), -1)
925 self.assertEqual(cmp(da,db), 0)
926
927 #a Decimal and an int
928 self.failUnless(dc > 23)
929 self.failUnless(23 < dc)
Guido van Rossume61fd5b2007-07-11 12:20:59 +0000930 self.assertEqual(dc, 45)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000931 self.assertEqual(cmp(dc,23), 1)
932 self.assertEqual(cmp(23,dc), -1)
933 self.assertEqual(cmp(dc,45), 0)
934
935 #a Decimal and uncomparable
Raymond Hettinger0aeac102004-07-05 22:53:03 +0000936 self.assertNotEqual(da, 'ugly')
937 self.assertNotEqual(da, 32.7)
938 self.assertNotEqual(da, object())
939 self.assertNotEqual(da, object)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000940
Raymond Hettinger0aeac102004-07-05 22:53:03 +0000941 # sortable
Guido van Rossumc1f779c2007-07-03 08:25:58 +0000942 a = list(map(Decimal, range(100)))
Raymond Hettinger0aeac102004-07-05 22:53:03 +0000943 b = a[:]
944 random.shuffle(a)
945 a.sort()
946 self.assertEqual(a, b)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000947
948 def test_copy_and_deepcopy_methods(self):
949 d = Decimal('43.24')
950 c = copy.copy(d)
951 self.assertEqual(id(c), id(d))
952 dc = copy.deepcopy(d)
953 self.assertEqual(id(dc), id(d))
954
955 def test_hash_method(self):
956 #just that it's hashable
957 hash(Decimal(23))
Thomas Wouters8ce81f72007-09-20 18:22:40 +0000958
959 test_values = [Decimal(sign*(2**m + n))
960 for m in [0, 14, 15, 16, 17, 30, 31,
961 32, 33, 62, 63, 64, 65, 66]
962 for n in range(-10, 10)
963 for sign in [-1, 1]]
964 test_values.extend([
965 Decimal("-0"), # zeros
966 Decimal("0.00"),
967 Decimal("-0.000"),
968 Decimal("0E10"),
969 Decimal("-0E12"),
970 Decimal("10.0"), # negative exponent
971 Decimal("-23.00000"),
972 Decimal("1230E100"), # positive exponent
973 Decimal("-4.5678E50"),
974 # a value for which hash(n) != hash(n % (2**64-1))
975 # in Python pre-2.6
976 Decimal(2**64 + 2**32 - 1),
977 # selection of values which fail with the old (before
978 # version 2.6) long.__hash__
979 Decimal("1.634E100"),
980 Decimal("90.697E100"),
981 Decimal("188.83E100"),
982 Decimal("1652.9E100"),
983 Decimal("56531E100"),
984 ])
985
986 # check that hash(d) == hash(int(d)) for integral values
987 for value in test_values:
988 self.assertEqual(hash(value), hash(int(value)))
989
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000990 #the same hash that to an int
991 self.assertEqual(hash(Decimal(23)), hash(23))
Raymond Hettingerbea3f6f2005-03-15 04:59:17 +0000992 self.assertRaises(TypeError, hash, Decimal('NaN'))
993 self.assert_(hash(Decimal('Inf')))
994 self.assert_(hash(Decimal('-Inf')))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000995
Christian Heimes2380ac72008-01-09 00:17:24 +0000996 # check that the value of the hash doesn't depend on the
997 # current context (issue #1757)
998 c = getcontext()
999 old_precision = c.prec
1000 x = Decimal("123456789.1")
1001
1002 c.prec = 6
1003 h1 = hash(x)
1004 c.prec = 10
1005 h2 = hash(x)
1006 c.prec = 16
1007 h3 = hash(x)
1008
1009 self.assertEqual(h1, h2)
1010 self.assertEqual(h1, h3)
1011 c.prec = old_precision
1012
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001013 def test_min_and_max_methods(self):
1014
1015 d1 = Decimal('15.32')
1016 d2 = Decimal('28.5')
1017 l1 = 15
1018 l2 = 28
1019
1020 #between Decimals
1021 self.failUnless(min(d1,d2) is d1)
1022 self.failUnless(min(d2,d1) is d1)
1023 self.failUnless(max(d1,d2) is d2)
1024 self.failUnless(max(d2,d1) is d2)
1025
1026 #between Decimal and long
1027 self.failUnless(min(d1,l2) is d1)
1028 self.failUnless(min(l2,d1) is d1)
1029 self.failUnless(max(l1,d2) is d2)
1030 self.failUnless(max(d2,l1) is d2)
1031
1032 def test_as_nonzero(self):
1033 #as false
1034 self.failIf(Decimal(0))
1035 #as true
1036 self.failUnless(Decimal('0.372'))
1037
1038 def test_tostring_methods(self):
1039 #Test str and repr methods.
1040
1041 d = Decimal('15.32')
1042 self.assertEqual(str(d), '15.32') # str
1043 self.assertEqual(repr(d), 'Decimal("15.32")') # repr
1044
1045 def test_tonum_methods(self):
1046 #Test float, int and long methods.
1047
1048 d1 = Decimal('66')
1049 d2 = Decimal('15.32')
1050
1051 #int
1052 self.assertEqual(int(d1), 66)
1053 self.assertEqual(int(d2), 15)
1054
1055 #long
Guido van Rossume2a383d2007-01-15 16:59:06 +00001056 self.assertEqual(int(d1), 66)
1057 self.assertEqual(int(d2), 15)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001058
1059 #float
1060 self.assertEqual(float(d1), 66)
1061 self.assertEqual(float(d2), 15.32)
1062
1063 def test_eval_round_trip(self):
1064
1065 #with zero
1066 d = Decimal( (0, (0,), 0) )
1067 self.assertEqual(d, eval(repr(d)))
1068
1069 #int
1070 d = Decimal( (1, (4, 5), 0) )
1071 self.assertEqual(d, eval(repr(d)))
1072
1073 #float
1074 d = Decimal( (0, (4, 5, 3, 4), -2) )
1075 self.assertEqual(d, eval(repr(d)))
1076
1077 #weird
1078 d = Decimal( (1, (4, 3, 4, 9, 1, 3, 5, 3, 4), -25) )
1079 self.assertEqual(d, eval(repr(d)))
1080
1081 def test_as_tuple(self):
1082
1083 #with zero
1084 d = Decimal(0)
1085 self.assertEqual(d.as_tuple(), (0, (0,), 0) )
1086
1087 #int
1088 d = Decimal(-45)
1089 self.assertEqual(d.as_tuple(), (1, (4, 5), 0) )
1090
1091 #complicated string
1092 d = Decimal("-4.34913534E-17")
1093 self.assertEqual(d.as_tuple(), (1, (4, 3, 4, 9, 1, 3, 5, 3, 4), -25) )
1094
1095 #inf
1096 d = Decimal("Infinity")
1097 self.assertEqual(d.as_tuple(), (0, (0,), 'F') )
1098
Guido van Rossum8ce8a782007-11-01 19:42:39 +00001099 #leading zeros in coefficient should be stripped
1100 d = Decimal( (0, (0, 0, 4, 0, 5, 3, 4), -2) )
1101 self.assertEqual(d.as_tuple(), (0, (4, 0, 5, 3, 4), -2) )
1102 d = Decimal( (1, (0, 0, 0), 37) )
1103 self.assertEqual(d.as_tuple(), (1, (0,), 37))
1104 d = Decimal( (1, (), 37) )
1105 self.assertEqual(d.as_tuple(), (1, (0,), 37))
1106
1107 #leading zeros in NaN diagnostic info should be stripped
1108 d = Decimal( (0, (0, 0, 4, 0, 5, 3, 4), 'n') )
1109 self.assertEqual(d.as_tuple(), (0, (4, 0, 5, 3, 4), 'n') )
1110 d = Decimal( (1, (0, 0, 0), 'N') )
1111 self.assertEqual(d.as_tuple(), (1, (), 'N') )
1112 d = Decimal( (1, (), 'n') )
1113 self.assertEqual(d.as_tuple(), (1, (), 'n') )
1114
1115 #coefficient in infinity should be ignored
1116 d = Decimal( (0, (4, 5, 3, 4), 'F') )
1117 self.assertEqual(d.as_tuple(), (0, (0,), 'F'))
1118 d = Decimal( (1, (0, 2, 7, 1), 'F') )
1119 self.assertEqual(d.as_tuple(), (1, (0,), 'F'))
1120
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001121 def test_immutability_operations(self):
1122 # Do operations and check that it didn't change change internal objects.
1123
1124 d1 = Decimal('-25e55')
1125 b1 = Decimal('-25e55')
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001126 d2 = Decimal('33e+33')
1127 b2 = Decimal('33e+33')
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001128
1129 def checkSameDec(operation, useOther=False):
1130 if useOther:
1131 eval("d1." + operation + "(d2)")
1132 self.assertEqual(d1._sign, b1._sign)
1133 self.assertEqual(d1._int, b1._int)
1134 self.assertEqual(d1._exp, b1._exp)
1135 self.assertEqual(d2._sign, b2._sign)
1136 self.assertEqual(d2._int, b2._int)
1137 self.assertEqual(d2._exp, b2._exp)
1138 else:
1139 eval("d1." + operation + "()")
1140 self.assertEqual(d1._sign, b1._sign)
1141 self.assertEqual(d1._int, b1._int)
1142 self.assertEqual(d1._exp, b1._exp)
1143 return
1144
1145 Decimal(d1)
1146 self.assertEqual(d1._sign, b1._sign)
1147 self.assertEqual(d1._int, b1._int)
1148 self.assertEqual(d1._exp, b1._exp)
1149
1150 checkSameDec("__abs__")
1151 checkSameDec("__add__", True)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001152 checkSameDec("__divmod__", True)
Christian Heimes77c02eb2008-02-09 02:18:51 +00001153 checkSameDec("__eq__", True)
1154 checkSameDec("__ne__", True)
1155 checkSameDec("__le__", True)
1156 checkSameDec("__lt__", True)
1157 checkSameDec("__ge__", True)
1158 checkSameDec("__gt__", True)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001159 checkSameDec("__float__")
1160 checkSameDec("__floordiv__", True)
1161 checkSameDec("__hash__")
1162 checkSameDec("__int__")
Christian Heimes969fe572008-01-25 11:23:10 +00001163 checkSameDec("__trunc__")
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001164 checkSameDec("__mod__", True)
1165 checkSameDec("__mul__", True)
1166 checkSameDec("__neg__")
Jack Diederich4dafcc42006-11-28 19:15:13 +00001167 checkSameDec("__bool__")
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001168 checkSameDec("__pos__")
1169 checkSameDec("__pow__", True)
1170 checkSameDec("__radd__", True)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001171 checkSameDec("__rdivmod__", True)
1172 checkSameDec("__repr__")
1173 checkSameDec("__rfloordiv__", True)
1174 checkSameDec("__rmod__", True)
1175 checkSameDec("__rmul__", True)
1176 checkSameDec("__rpow__", True)
1177 checkSameDec("__rsub__", True)
1178 checkSameDec("__str__")
1179 checkSameDec("__sub__", True)
1180 checkSameDec("__truediv__", True)
1181 checkSameDec("adjusted")
1182 checkSameDec("as_tuple")
1183 checkSameDec("compare", True)
1184 checkSameDec("max", True)
1185 checkSameDec("min", True)
1186 checkSameDec("normalize")
1187 checkSameDec("quantize", True)
1188 checkSameDec("remainder_near", True)
1189 checkSameDec("same_quantum", True)
1190 checkSameDec("sqrt")
1191 checkSameDec("to_eng_string")
1192 checkSameDec("to_integral")
1193
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001194 def test_subclassing(self):
1195 # Different behaviours when subclassing Decimal
1196
1197 class MyDecimal(Decimal):
1198 pass
1199
1200 d1 = MyDecimal(1)
1201 d2 = MyDecimal(2)
1202 d = d1 + d2
1203 self.assertTrue(type(d) is Decimal)
1204
1205 d = d1.max(d2)
1206 self.assertTrue(type(d) is Decimal)
1207
1208
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001209class DecimalPythonAPItests(unittest.TestCase):
1210
1211 def test_pickle(self):
1212 d = Decimal('-3.141590000')
1213 p = pickle.dumps(d)
1214 e = pickle.loads(p)
1215 self.assertEqual(d, e)
1216
Raymond Hettinger5548be22004-07-05 18:49:38 +00001217 def test_int(self):
Raymond Hettinger605ed022004-11-24 07:28:48 +00001218 for x in range(-250, 250):
1219 s = '%0.2f' % (x / 100.0)
Raymond Hettinger5548be22004-07-05 18:49:38 +00001220 # should work the same as for floats
1221 self.assertEqual(int(Decimal(s)), int(float(s)))
Raymond Hettinger605ed022004-11-24 07:28:48 +00001222 # should work the same as to_integral in the ROUND_DOWN mode
Raymond Hettinger5548be22004-07-05 18:49:38 +00001223 d = Decimal(s)
Raymond Hettinger605ed022004-11-24 07:28:48 +00001224 r = d.to_integral(ROUND_DOWN)
Raymond Hettinger5548be22004-07-05 18:49:38 +00001225 self.assertEqual(Decimal(int(d)), r)
1226
Christian Heimes969fe572008-01-25 11:23:10 +00001227 def test_trunc(self):
1228 for x in range(-250, 250):
1229 s = '%0.2f' % (x / 100.0)
1230 # should work the same as for floats
1231 self.assertEqual(int(Decimal(s)), int(float(s)))
1232 # should work the same as to_integral in the ROUND_DOWN mode
1233 d = Decimal(s)
1234 r = d.to_integral(ROUND_DOWN)
Christian Heimes400adb02008-02-01 08:12:03 +00001235 self.assertEqual(Decimal(math.trunc(d)), r)
Christian Heimes969fe572008-01-25 11:23:10 +00001236
Raymond Hettingerd9c0a7a2004-07-03 10:02:28 +00001237class ContextAPItests(unittest.TestCase):
1238
1239 def test_pickle(self):
1240 c = Context()
1241 e = pickle.loads(pickle.dumps(c))
1242 for k in vars(c):
1243 v1 = vars(c)[k]
1244 v2 = vars(e)[k]
1245 self.assertEqual(v1, v2)
1246
Raymond Hettinger0aeac102004-07-05 22:53:03 +00001247 def test_equality_with_other_types(self):
1248 self.assert_(Decimal(10) in ['a', 1.0, Decimal(10), (1,2), {}])
1249 self.assert_(Decimal(10) not in ['a', 1.0, (1,2), {}])
1250
Raymond Hettinger955d2b22004-08-08 20:17:45 +00001251 def test_copy(self):
1252 # All copies should be deep
1253 c = Context()
1254 d = c.copy()
1255 self.assertNotEqual(id(c), id(d))
1256 self.assertNotEqual(id(c.flags), id(d.flags))
1257 self.assertNotEqual(id(c.traps), id(d.traps))
1258
Thomas Wouters89f507f2006-12-13 04:49:30 +00001259class WithStatementTest(unittest.TestCase):
1260 # Can't do these as docstrings until Python 2.6
1261 # as doctest can't handle __future__ statements
1262
1263 def test_localcontext(self):
1264 # Use a copy of the current context in the block
1265 orig_ctx = getcontext()
1266 with localcontext() as enter_ctx:
1267 set_ctx = getcontext()
1268 final_ctx = getcontext()
1269 self.assert_(orig_ctx is final_ctx, 'did not restore context correctly')
1270 self.assert_(orig_ctx is not set_ctx, 'did not copy the context')
1271 self.assert_(set_ctx is enter_ctx, '__enter__ returned wrong context')
1272
1273 def test_localcontextarg(self):
1274 # Use a copy of the supplied context in the block
1275 orig_ctx = getcontext()
1276 new_ctx = Context(prec=42)
1277 with localcontext(new_ctx) as enter_ctx:
1278 set_ctx = getcontext()
1279 final_ctx = getcontext()
1280 self.assert_(orig_ctx is final_ctx, 'did not restore context correctly')
1281 self.assert_(set_ctx.prec == new_ctx.prec, 'did not set correct context')
1282 self.assert_(new_ctx is not set_ctx, 'did not copy the context')
1283 self.assert_(set_ctx is enter_ctx, '__enter__ returned wrong context')
1284
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001285class ContextFlags(unittest.TestCase):
1286 def test_flags_irrelevant(self):
1287 # check that the result (numeric result + flags raised) of an
1288 # arithmetic operation doesn't depend on the current flags
1289
1290 context = Context(prec=9, Emin = -999999999, Emax = 999999999,
1291 rounding=ROUND_HALF_EVEN, traps=[], flags=[])
1292
1293 # operations that raise various flags, in the form (function, arglist)
1294 operations = [
1295 (context._apply, [Decimal("100E-1000000009")]),
1296 (context.sqrt, [Decimal(2)]),
1297 (context.add, [Decimal("1.23456789"), Decimal("9.87654321")]),
1298 (context.multiply, [Decimal("1.23456789"), Decimal("9.87654321")]),
1299 (context.subtract, [Decimal("1.23456789"), Decimal("9.87654321")]),
1300 ]
1301
1302 # try various flags individually, then a whole lot at once
1303 flagsets = [[Inexact], [Rounded], [Underflow], [Clamped], [Subnormal],
1304 [Inexact, Rounded, Underflow, Clamped, Subnormal]]
1305
1306 for fn, args in operations:
1307 # find answer and flags raised using a clean context
1308 context.clear_flags()
1309 ans = fn(*args)
1310 flags = [k for k, v in context.flags.items() if v]
1311
1312 for extra_flags in flagsets:
1313 # set flags, before calling operation
1314 context.clear_flags()
1315 for flag in extra_flags:
1316 context._raise_error(flag)
1317 new_ans = fn(*args)
1318
1319 # flags that we expect to be set after the operation
1320 expected_flags = list(flags)
1321 for flag in extra_flags:
1322 if flag not in expected_flags:
1323 expected_flags.append(flag)
1324 expected_flags.sort(key=id)
1325
1326 # flags we actually got
1327 new_flags = [k for k,v in context.flags.items() if v]
1328 new_flags.sort(key=id)
1329
1330 self.assertEqual(ans, new_ans,
1331 "operation produces different answers depending on flags set: " +
1332 "expected %s, got %s." % (ans, new_ans))
1333 self.assertEqual(new_flags, expected_flags,
1334 "operation raises different flags depending on flags set: " +
1335 "expected %s, got %s" % (expected_flags, new_flags))
1336
1337def test_main(arith=False, verbose=None, todo_tests=None, debug=None):
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001338 """ Execute the tests.
1339
Raymond Hettingered20ad82004-09-04 20:09:13 +00001340 Runs all arithmetic tests if arith is True or if the "decimal" resource
1341 is enabled in regrtest.py
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001342 """
Raymond Hettingered20ad82004-09-04 20:09:13 +00001343
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00001344 init()
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001345 global TEST_ALL, DEBUG
Raymond Hettingered20ad82004-09-04 20:09:13 +00001346 TEST_ALL = arith or is_resource_enabled('decimal')
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001347 DEBUG = debug
Raymond Hettingered20ad82004-09-04 20:09:13 +00001348
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001349 if todo_tests is None:
1350 test_classes = [
1351 DecimalExplicitConstructionTest,
1352 DecimalImplicitConstructionTest,
1353 DecimalArithmeticOperatorsTest,
1354 DecimalUseOfContextTest,
1355 DecimalUsabilityTest,
1356 DecimalPythonAPItests,
1357 ContextAPItests,
1358 DecimalTest,
1359 WithStatementTest,
1360 ContextFlags
1361 ]
1362 else:
1363 test_classes = [DecimalTest]
1364
1365 # Dynamically build custom test definition for each file in the test
1366 # directory and add the definitions to the DecimalTest class. This
1367 # procedure insures that new files do not get skipped.
1368 for filename in os.listdir(directory):
1369 if '.decTest' not in filename or filename.startswith("."):
1370 continue
1371 head, tail = filename.split('.')
1372 if todo_tests is not None and head not in todo_tests:
1373 continue
1374 tester = lambda self, f=filename: self.eval_file(directory + f)
1375 setattr(DecimalTest, 'test_' + head, tester)
1376 del filename, head, tail, tester
1377
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001378
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00001379 try:
1380 run_unittest(*test_classes)
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001381 if todo_tests is None:
1382 import decimal as DecimalModule
1383 run_doctest(DecimalModule, verbose)
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00001384 finally:
1385 setcontext(ORIGINAL_CONTEXT)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001386
1387if __name__ == '__main__':
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001388 import optparse
1389 p = optparse.OptionParser("test_decimal.py [--debug] [{--skip | test1 [test2 [...]]}]")
1390 p.add_option('--debug', '-d', action='store_true', help='shows the test number and context before each test')
1391 p.add_option('--skip', '-s', action='store_true', help='skip over 90% of the arithmetic tests')
1392 (opt, args) = p.parse_args()
1393
1394 if opt.skip:
1395 test_main(arith=False, verbose=True)
1396 elif args:
1397 test_main(arith=True, verbose=True, todo_tests=args, debug=opt.debug)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001398 else:
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001399 test_main(arith=True, verbose=True)