blob: dad63aee31332a777833e56ce6ff102504ae818f [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 *
Raymond Hettinger82417ca2009-02-03 03:54:28 +000033import numbers
Benjamin Petersone549ead2009-03-28 21:42:05 +000034from test.support import run_unittest, run_doctest, 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
Mark Dickinsonece06972010-05-04 14:37:14 +000044# Signals ordered with respect to precedence: when an operation
45# produces multiple signals, signals occurring later in the list
46# should be handled before those occurring earlier in the list.
47OrderedSignals = (Clamped, Rounded, Inexact, Subnormal,
48 Underflow, Overflow, DivisionByZero, InvalidOperation)
49
Thomas Wouters49fd7fa2006-04-21 10:40:58 +000050# Tests are built around these assumed context defaults.
51# test_main() restores the original context.
52def init():
53 global ORIGINAL_CONTEXT
54 ORIGINAL_CONTEXT = getcontext().copy()
Christian Heimes81ee3ef2008-05-04 22:42:01 +000055 DefaultTestContext = Context(
56 prec = 9,
57 rounding = ROUND_HALF_EVEN,
58 traps = dict.fromkeys(Signals, 0)
59 )
60 setcontext(DefaultTestContext)
Raymond Hettinger6ea48452004-07-03 12:26:21 +000061
Raymond Hettinger7c85fa42004-07-01 11:01:35 +000062TESTDATADIR = 'decimaltestdata'
Raymond Hettingerd9c0a7a2004-07-03 10:02:28 +000063if __name__ == '__main__':
64 file = sys.argv[0]
65else:
66 file = __file__
67testdir = os.path.dirname(file) or os.curdir
Raymond Hettinger267b8682005-03-27 10:47:39 +000068directory = testdir + os.sep + TESTDATADIR + os.sep
Raymond Hettinger7c85fa42004-07-01 11:01:35 +000069
Raymond Hettinger267b8682005-03-27 10:47:39 +000070skip_expected = not os.path.isdir(directory)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +000071
Mark Dickinsond08fb832009-10-08 16:33:06 +000072# list of individual .decTest test ids that correspond to tests that
73# we're skipping for one reason or another.
74skipped_test_ids = [
75 'scbx164', # skipping apparently implementation-specific scaleb
76 'scbx165', # tests, pending clarification of scaleb rules.
77]
78
Raymond Hettinger7c85fa42004-07-01 11:01:35 +000079# Make sure it actually raises errors when not expected and caught in flags
80# Slower, since it runs some things several times.
81EXTENDEDERRORTEST = False
82
Raymond Hettinger7c85fa42004-07-01 11:01:35 +000083#Map the test cases' error names to the actual errors
Raymond Hettinger7c85fa42004-07-01 11:01:35 +000084ErrorNames = {'clamped' : Clamped,
Raymond Hettinger5aa478b2004-07-09 10:02:53 +000085 'conversion_syntax' : InvalidOperation,
Raymond Hettinger7c85fa42004-07-01 11:01:35 +000086 'division_by_zero' : DivisionByZero,
Raymond Hettinger5aa478b2004-07-09 10:02:53 +000087 'division_impossible' : InvalidOperation,
88 'division_undefined' : InvalidOperation,
Raymond Hettinger7c85fa42004-07-01 11:01:35 +000089 'inexact' : Inexact,
Raymond Hettinger5aa478b2004-07-09 10:02:53 +000090 'invalid_context' : InvalidOperation,
Raymond Hettinger7c85fa42004-07-01 11:01:35 +000091 'invalid_operation' : InvalidOperation,
92 'overflow' : Overflow,
93 'rounded' : Rounded,
94 'subnormal' : Subnormal,
95 'underflow' : Underflow}
96
97
98def Nonfunction(*args):
99 """Doesn't do anything."""
100 return None
101
102RoundingDict = {'ceiling' : ROUND_CEILING, #Maps test-case names to roundings.
103 'down' : ROUND_DOWN,
104 'floor' : ROUND_FLOOR,
105 'half_down' : ROUND_HALF_DOWN,
106 'half_even' : ROUND_HALF_EVEN,
107 'half_up' : ROUND_HALF_UP,
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000108 'up' : ROUND_UP,
109 '05up' : ROUND_05UP}
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000110
111# Name adapter to be able to change the Decimal and Context
112# interface without changing the test files from Cowlishaw
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000113nameAdapter = {'and':'logical_and',
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000114 'apply':'_apply',
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000115 'class':'number_class',
116 'comparesig':'compare_signal',
117 'comparetotal':'compare_total',
118 'comparetotmag':'compare_total_mag',
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000119 'copy':'copy_decimal',
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000120 'copyabs':'copy_abs',
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000121 'copynegate':'copy_negate',
122 'copysign':'copy_sign',
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000123 'divideint':'divide_int',
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000124 'invert':'logical_invert',
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000125 'iscanonical':'is_canonical',
126 'isfinite':'is_finite',
127 'isinfinite':'is_infinite',
128 'isnan':'is_nan',
129 'isnormal':'is_normal',
130 'isqnan':'is_qnan',
131 'issigned':'is_signed',
132 'issnan':'is_snan',
133 'issubnormal':'is_subnormal',
134 'iszero':'is_zero',
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000135 'maxmag':'max_mag',
136 'minmag':'min_mag',
137 'nextminus':'next_minus',
138 'nextplus':'next_plus',
139 'nexttoward':'next_toward',
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000140 'or':'logical_or',
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000141 'reduce':'normalize',
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000142 'remaindernear':'remainder_near',
143 'samequantum':'same_quantum',
144 'squareroot':'sqrt',
145 'toeng':'to_eng_string',
146 'tointegral':'to_integral_value',
147 'tointegralx':'to_integral_exact',
148 'tosci':'to_sci_string',
149 'xor':'logical_xor',
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000150 }
151
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000152# The following functions return True/False rather than a Decimal instance
153
154LOGICAL_FUNCTIONS = (
155 'is_canonical',
156 'is_finite',
157 'is_infinite',
158 'is_nan',
159 'is_normal',
160 'is_qnan',
161 'is_signed',
162 'is_snan',
163 'is_subnormal',
164 'is_zero',
165 'same_quantum',
166 )
167
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000168# For some operations (currently exp, ln, log10, power), the decNumber
169# reference implementation imposes additional restrictions on the
170# context and operands. These restrictions are not part of the
171# specification; however, the effect of these restrictions does show
172# up in some of the testcases. We skip testcases that violate these
173# restrictions, since Decimal behaves differently from decNumber for
174# these testcases so these testcases would otherwise fail.
175
176decNumberRestricted = ('power', 'ln', 'log10', 'exp')
177DEC_MAX_MATH = 999999
178def outside_decNumber_bounds(v, context):
179 if (context.prec > DEC_MAX_MATH or
180 context.Emax > DEC_MAX_MATH or
181 -context.Emin > DEC_MAX_MATH):
182 return True
183 if not v._is_special and v and (
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000184 v.adjusted() > DEC_MAX_MATH or
185 v.adjusted() < 1-2*DEC_MAX_MATH):
186 return True
187 return False
188
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000189class DecimalTest(unittest.TestCase):
190 """Class which tests the Decimal class against the test cases.
191
192 Changed for unittest.
193 """
194 def setUp(self):
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000195 self.context = Context()
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000196 self.ignore_list = ['#']
197 # Basically, a # means return NaN InvalidOperation.
198 # Different from a sNaN in trim
199
200 self.ChangeDict = {'precision' : self.change_precision,
201 'rounding' : self.change_rounding_method,
202 'maxexponent' : self.change_max_exponent,
203 'minexponent' : self.change_min_exponent,
204 'clamp' : self.change_clamp}
205
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000206 def eval_file(self, file):
207 global skip_expected
208 if skip_expected:
Benjamin Petersone549ead2009-03-28 21:42:05 +0000209 raise unittest.SkipTest
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000210 return
Neal Norwitz70967602006-03-17 08:29:44 +0000211 for line in open(file):
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000212 line = line.replace('\r\n', '').replace('\n', '')
Raymond Hettinger5aa478b2004-07-09 10:02:53 +0000213 #print line
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000214 try:
215 t = self.eval_line(line)
Guido van Rossumb940e112007-01-10 16:19:56 +0000216 except DecimalException as exception:
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000217 #Exception raised where there shoudn't have been one.
218 self.fail('Exception "'+exception.__class__.__name__ + '" raised on line '+line)
219
220 return
221
222 def eval_line(self, s):
223 if s.find(' -> ') >= 0 and s[:2] != '--' and not s.startswith(' --'):
224 s = (s.split('->')[0] + '->' +
225 s.split('->')[1].split('--')[0]).strip()
226 else:
227 s = s.split('--')[0].strip()
228
229 for ignore in self.ignore_list:
230 if s.find(ignore) >= 0:
231 #print s.split()[0], 'NotImplemented--', ignore
232 return
233 if not s:
234 return
235 elif ':' in s:
236 return self.eval_directive(s)
237 else:
238 return self.eval_equation(s)
239
240 def eval_directive(self, s):
Guido van Rossumc1f779c2007-07-03 08:25:58 +0000241 funct, value = (x.strip().lower() for x in s.split(':'))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000242 if funct == 'rounding':
243 value = RoundingDict[value]
244 else:
245 try:
246 value = int(value)
247 except ValueError:
248 pass
249
250 funct = self.ChangeDict.get(funct, Nonfunction)
251 funct(value)
252
253 def eval_equation(self, s):
254 #global DEFAULT_PRECISION
255 #print DEFAULT_PRECISION
Raymond Hettingered20ad82004-09-04 20:09:13 +0000256
257 if not TEST_ALL and random.random() < 0.90:
258 return
259
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000260 try:
261 Sides = s.split('->')
262 L = Sides[0].strip().split()
263 id = L[0]
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000264 if DEBUG:
265 print("Test ", id, end=" ")
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000266 funct = L[1].lower()
267 valstemp = L[2:]
268 L = Sides[1].strip().split()
269 ans = L[0]
270 exceptions = L[1:]
271 except (TypeError, AttributeError, IndexError):
Raymond Hettingerd87ac8f2004-07-09 10:52:54 +0000272 raise InvalidOperation
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000273 def FixQuotes(val):
274 val = val.replace("''", 'SingleQuote').replace('""', 'DoubleQuote')
275 val = val.replace("'", '').replace('"', '')
276 val = val.replace('SingleQuote', "'").replace('DoubleQuote', '"')
277 return val
Mark Dickinsond08fb832009-10-08 16:33:06 +0000278
279 if id in skipped_test_ids:
280 return
281
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000282 fname = nameAdapter.get(funct, funct)
283 if fname == 'rescale':
284 return
285 funct = getattr(self.context, fname)
286 vals = []
287 conglomerate = ''
288 quote = 0
289 theirexceptions = [ErrorNames[x.lower()] for x in exceptions]
290
Raymond Hettingerd9c0a7a2004-07-03 10:02:28 +0000291 for exception in Signals:
Raymond Hettingerbf440692004-07-10 14:14:37 +0000292 self.context.traps[exception] = 1 #Catch these bugs...
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000293 for exception in theirexceptions:
Raymond Hettingerbf440692004-07-10 14:14:37 +0000294 self.context.traps[exception] = 0
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000295 for i, val in enumerate(valstemp):
296 if val.count("'") % 2 == 1:
297 quote = 1 - quote
298 if quote:
299 conglomerate = conglomerate + ' ' + val
300 continue
301 else:
302 val = conglomerate + val
303 conglomerate = ''
304 v = FixQuotes(val)
305 if fname in ('to_sci_string', 'to_eng_string'):
306 if EXTENDEDERRORTEST:
307 for error in theirexceptions:
Raymond Hettingerbf440692004-07-10 14:14:37 +0000308 self.context.traps[error] = 1
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000309 try:
310 funct(self.context.create_decimal(v))
311 except error:
312 pass
Guido van Rossumb940e112007-01-10 16:19:56 +0000313 except Signals as e:
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000314 self.fail("Raised %s in %s when %s disabled" % \
315 (e, s, error))
316 else:
317 self.fail("Did not raise %s in %s" % (error, s))
Raymond Hettingerbf440692004-07-10 14:14:37 +0000318 self.context.traps[error] = 0
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000319 v = self.context.create_decimal(v)
320 else:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000321 v = Decimal(v, self.context)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000322 vals.append(v)
323
324 ans = FixQuotes(ans)
325
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000326 # skip tests that are related to bounds imposed in the decNumber
327 # reference implementation
328 if fname in decNumberRestricted:
329 if fname == 'power':
330 if not (vals[1]._isinteger() and
331 -1999999997 <= vals[1] <= 999999999):
332 if outside_decNumber_bounds(vals[0], self.context) or \
333 outside_decNumber_bounds(vals[1], self.context):
334 #print "Skipping test %s" % s
335 return
336 else:
337 if outside_decNumber_bounds(vals[0], self.context):
338 #print "Skipping test %s" % s
339 return
340
341
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000342 if EXTENDEDERRORTEST and fname not in ('to_sci_string', 'to_eng_string'):
343 for error in theirexceptions:
Raymond Hettingerbf440692004-07-10 14:14:37 +0000344 self.context.traps[error] = 1
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000345 try:
346 funct(*vals)
347 except error:
348 pass
Guido van Rossumb940e112007-01-10 16:19:56 +0000349 except Signals as e:
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000350 self.fail("Raised %s in %s when %s disabled" % \
351 (e, s, error))
352 else:
353 self.fail("Did not raise %s in %s" % (error, s))
Raymond Hettingerbf440692004-07-10 14:14:37 +0000354 self.context.traps[error] = 0
Mark Dickinsonece06972010-05-04 14:37:14 +0000355
356 # as above, but add traps cumulatively, to check precedence
357 ordered_errors = [e for e in OrderedSignals if e in theirexceptions]
358 for error in ordered_errors:
359 self.context.traps[error] = 1
360 try:
361 funct(*vals)
362 except error:
363 pass
364 except Signals as e:
365 self.fail("Raised %s in %s; expected %s" %
366 (type(e), s, error))
367 else:
368 self.fail("Did not raise %s in %s" % (error, s))
369 # reset traps
370 for error in ordered_errors:
371 self.context.traps[error] = 0
372
373
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000374 if DEBUG:
375 print("--", self.context)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000376 try:
377 result = str(funct(*vals))
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000378 if fname in LOGICAL_FUNCTIONS:
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000379 result = str(int(eval(result))) # 'True', 'False' -> '1', '0'
Guido van Rossumb940e112007-01-10 16:19:56 +0000380 except Signals as error:
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000381 self.fail("Raised %s in %s" % (error, s))
382 except: #Catch any error long enough to state the test case.
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000383 print("ERROR:", s)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000384 raise
385
386 myexceptions = self.getexceptions()
Raymond Hettingerbf440692004-07-10 14:14:37 +0000387 self.context.clear_flags()
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000388
Guido van Rossum47b9ff62006-08-24 00:41:19 +0000389 myexceptions.sort(key=repr)
390 theirexceptions.sort(key=repr)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000391
392 self.assertEqual(result, ans,
393 'Incorrect answer for ' + s + ' -- got ' + result)
394 self.assertEqual(myexceptions, theirexceptions,
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000395 'Incorrect flags set in ' + s + ' -- got ' + str(myexceptions))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000396 return
397
398 def getexceptions(self):
Raymond Hettingerf63ba432004-08-17 05:42:09 +0000399 return [e for e in Signals if self.context.flags[e]]
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000400
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000401 def change_precision(self, prec):
402 self.context.prec = prec
403 def change_rounding_method(self, rounding):
404 self.context.rounding = rounding
405 def change_min_exponent(self, exp):
406 self.context.Emin = exp
407 def change_max_exponent(self, exp):
408 self.context.Emax = exp
409 def change_clamp(self, clamp):
410 self.context._clamp = clamp
411
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000412
413
414# The following classes test the behaviour of Decimal according to PEP 327
415
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000416class DecimalExplicitConstructionTest(unittest.TestCase):
417 '''Unit tests for Explicit Construction cases of Decimal.'''
418
419 def test_explicit_empty(self):
420 self.assertEqual(Decimal(), Decimal("0"))
421
422 def test_explicit_from_None(self):
423 self.assertRaises(TypeError, Decimal, None)
424
425 def test_explicit_from_int(self):
426
427 #positive
428 d = Decimal(45)
429 self.assertEqual(str(d), '45')
430
431 #very large positive
432 d = Decimal(500000123)
433 self.assertEqual(str(d), '500000123')
434
435 #negative
436 d = Decimal(-45)
437 self.assertEqual(str(d), '-45')
438
439 #zero
440 d = Decimal(0)
441 self.assertEqual(str(d), '0')
442
443 def test_explicit_from_string(self):
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000444
445 #empty
446 self.assertEqual(str(Decimal('')), 'NaN')
447
448 #int
449 self.assertEqual(str(Decimal('45')), '45')
450
451 #float
452 self.assertEqual(str(Decimal('45.34')), '45.34')
453
454 #engineer notation
455 self.assertEqual(str(Decimal('45e2')), '4.5E+3')
456
457 #just not a number
458 self.assertEqual(str(Decimal('ugly')), 'NaN')
459
Christian Heimesa62da1d2008-01-12 19:39:10 +0000460 #leading and trailing whitespace permitted
461 self.assertEqual(str(Decimal('1.3E4 \n')), '1.3E+4')
462 self.assertEqual(str(Decimal(' -7.89')), '-7.89')
463
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000464 def test_explicit_from_tuples(self):
465
466 #zero
467 d = Decimal( (0, (0,), 0) )
468 self.assertEqual(str(d), '0')
469
470 #int
471 d = Decimal( (1, (4, 5), 0) )
472 self.assertEqual(str(d), '-45')
473
474 #float
475 d = Decimal( (0, (4, 5, 3, 4), -2) )
476 self.assertEqual(str(d), '45.34')
477
478 #weird
479 d = Decimal( (1, (4, 3, 4, 9, 1, 3, 5, 3, 4), -25) )
480 self.assertEqual(str(d), '-4.34913534E-17')
481
482 #wrong number of items
483 self.assertRaises(ValueError, Decimal, (1, (4, 3, 4, 9, 1)) )
484
485 #bad sign
486 self.assertRaises(ValueError, Decimal, (8, (4, 3, 4, 9, 1), 2) )
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000487 self.assertRaises(ValueError, Decimal, (0., (4, 3, 4, 9, 1), 2) )
488 self.assertRaises(ValueError, Decimal, (Decimal(1), (4, 3, 4, 9, 1), 2))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000489
490 #bad exp
491 self.assertRaises(ValueError, Decimal, (1, (4, 3, 4, 9, 1), 'wrong!') )
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000492 self.assertRaises(ValueError, Decimal, (1, (4, 3, 4, 9, 1), 0.) )
493 self.assertRaises(ValueError, Decimal, (1, (4, 3, 4, 9, 1), '1') )
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000494
495 #bad coefficients
496 self.assertRaises(ValueError, Decimal, (1, (4, 3, 4, None, 1), 2) )
497 self.assertRaises(ValueError, Decimal, (1, (4, -3, 4, 9, 1), 2) )
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000498 self.assertRaises(ValueError, Decimal, (1, (4, 10, 4, 9, 1), 2) )
Guido van Rossum0d3fb8a2007-11-26 23:23:18 +0000499 self.assertRaises(ValueError, Decimal, (1, (4, 3, 4, 'a', 1), 2) )
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000500
501 def test_explicit_from_Decimal(self):
502
503 #positive
504 d = Decimal(45)
505 e = Decimal(d)
506 self.assertEqual(str(e), '45')
507 self.assertNotEqual(id(d), id(e))
508
509 #very large positive
510 d = Decimal(500000123)
511 e = Decimal(d)
512 self.assertEqual(str(e), '500000123')
513 self.assertNotEqual(id(d), id(e))
514
515 #negative
516 d = Decimal(-45)
517 e = Decimal(d)
518 self.assertEqual(str(e), '-45')
519 self.assertNotEqual(id(d), id(e))
520
521 #zero
522 d = Decimal(0)
523 e = Decimal(d)
524 self.assertEqual(str(e), '0')
525 self.assertNotEqual(id(d), id(e))
526
527 def test_explicit_context_create_decimal(self):
528
529 nc = copy.copy(getcontext())
530 nc.prec = 3
531
532 # empty
Raymond Hettingerfed52962004-07-14 15:41:57 +0000533 d = Decimal()
534 self.assertEqual(str(d), '0')
535 d = nc.create_decimal()
536 self.assertEqual(str(d), '0')
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000537
538 # from None
539 self.assertRaises(TypeError, nc.create_decimal, None)
540
541 # from int
542 d = nc.create_decimal(456)
Georg Brandlab91fde2009-08-13 08:51:18 +0000543 self.assertTrue(isinstance(d, Decimal))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000544 self.assertEqual(nc.create_decimal(45678),
545 nc.create_decimal('457E+2'))
546
547 # from string
548 d = Decimal('456789')
549 self.assertEqual(str(d), '456789')
550 d = nc.create_decimal('456789')
551 self.assertEqual(str(d), '4.57E+5')
Christian Heimesa62da1d2008-01-12 19:39:10 +0000552 # leading and trailing whitespace should result in a NaN;
553 # spaces are already checked in Cowlishaw's test-suite, so
554 # here we just check that a trailing newline results in a NaN
555 self.assertEqual(str(nc.create_decimal('3.14\n')), 'NaN')
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000556
557 # from tuples
558 d = Decimal( (1, (4, 3, 4, 9, 1, 3, 5, 3, 4), -25) )
559 self.assertEqual(str(d), '-4.34913534E-17')
560 d = nc.create_decimal( (1, (4, 3, 4, 9, 1, 3, 5, 3, 4), -25) )
561 self.assertEqual(str(d), '-4.35E-17')
562
563 # from Decimal
564 prevdec = Decimal(500000123)
565 d = Decimal(prevdec)
566 self.assertEqual(str(d), '500000123')
567 d = nc.create_decimal(prevdec)
568 self.assertEqual(str(d), '5.00E+8')
569
Mark Dickinson8d238292009-08-02 10:16:33 +0000570 def test_unicode_digits(self):
571 test_values = {
572 '\uff11': '1',
573 '\u0660.\u0660\u0663\u0667\u0662e-\u0663' : '0.0000372',
574 '-nan\u0c68\u0c6a\u0c66\u0c66' : '-NaN2400',
575 }
576 for input, expected in test_values.items():
577 self.assertEqual(str(Decimal(input)), expected)
578
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000579
580class DecimalImplicitConstructionTest(unittest.TestCase):
581 '''Unit tests for Implicit Construction cases of Decimal.'''
582
583 def test_implicit_from_None(self):
584 self.assertRaises(TypeError, eval, 'Decimal(5) + None', globals())
585
586 def test_implicit_from_int(self):
587 #normal
588 self.assertEqual(str(Decimal(5) + 45), '50')
589 #exceeding precision
590 self.assertEqual(Decimal(5) + 123456789000, Decimal(123456789000))
591
592 def test_implicit_from_string(self):
593 self.assertRaises(TypeError, eval, 'Decimal(5) + "3"', globals())
594
595 def test_implicit_from_float(self):
596 self.assertRaises(TypeError, eval, 'Decimal(5) + 2.2', globals())
597
598 def test_implicit_from_Decimal(self):
599 self.assertEqual(Decimal(5) + Decimal(45), Decimal(50))
600
Raymond Hettinger267b8682005-03-27 10:47:39 +0000601 def test_rop(self):
602 # Allow other classes to be trained to interact with Decimals
603 class E:
604 def __divmod__(self, other):
605 return 'divmod ' + str(other)
606 def __rdivmod__(self, other):
607 return str(other) + ' rdivmod'
608 def __lt__(self, other):
609 return 'lt ' + str(other)
610 def __gt__(self, other):
611 return 'gt ' + str(other)
612 def __le__(self, other):
613 return 'le ' + str(other)
614 def __ge__(self, other):
615 return 'ge ' + str(other)
616 def __eq__(self, other):
617 return 'eq ' + str(other)
618 def __ne__(self, other):
619 return 'ne ' + str(other)
620
621 self.assertEqual(divmod(E(), Decimal(10)), 'divmod 10')
622 self.assertEqual(divmod(Decimal(10), E()), '10 rdivmod')
623 self.assertEqual(eval('Decimal(10) < E()'), 'gt 10')
624 self.assertEqual(eval('Decimal(10) > E()'), 'lt 10')
625 self.assertEqual(eval('Decimal(10) <= E()'), 'ge 10')
626 self.assertEqual(eval('Decimal(10) >= E()'), 'le 10')
627 self.assertEqual(eval('Decimal(10) == E()'), 'eq 10')
628 self.assertEqual(eval('Decimal(10) != E()'), 'ne 10')
629
630 # insert operator methods and then exercise them
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000631 oplist = [
632 ('+', '__add__', '__radd__'),
633 ('-', '__sub__', '__rsub__'),
634 ('*', '__mul__', '__rmul__'),
Thomas Woutersdcc6d322006-04-21 11:30:52 +0000635 ('/', '__truediv__', '__rtruediv__'),
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000636 ('%', '__mod__', '__rmod__'),
637 ('//', '__floordiv__', '__rfloordiv__'),
638 ('**', '__pow__', '__rpow__')
639 ]
Raymond Hettinger267b8682005-03-27 10:47:39 +0000640
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000641 for sym, lop, rop in oplist:
Raymond Hettinger267b8682005-03-27 10:47:39 +0000642 setattr(E, lop, lambda self, other: 'str' + lop + str(other))
643 setattr(E, rop, lambda self, other: str(other) + rop + 'str')
644 self.assertEqual(eval('E()' + sym + 'Decimal(10)'),
645 'str' + lop + '10')
646 self.assertEqual(eval('Decimal(10)' + sym + 'E()'),
647 '10' + rop + 'str')
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000648
Mark Dickinson79f52032009-03-17 23:12:51 +0000649
Christian Heimesf16baeb2008-02-29 14:57:44 +0000650class DecimalFormatTest(unittest.TestCase):
651 '''Unit tests for the format function.'''
652 def test_formatting(self):
653 # triples giving a format, a Decimal, and the expected result
654 test_values = [
655 ('e', '0E-15', '0e-15'),
656 ('e', '2.3E-15', '2.3e-15'),
657 ('e', '2.30E+2', '2.30e+2'), # preserve significant zeros
658 ('e', '2.30000E-15', '2.30000e-15'),
659 ('e', '1.23456789123456789e40', '1.23456789123456789e+40'),
660 ('e', '1.5', '1.5e+0'),
661 ('e', '0.15', '1.5e-1'),
662 ('e', '0.015', '1.5e-2'),
663 ('e', '0.0000000000015', '1.5e-12'),
664 ('e', '15.0', '1.50e+1'),
665 ('e', '-15', '-1.5e+1'),
666 ('e', '0', '0e+0'),
667 ('e', '0E1', '0e+1'),
668 ('e', '0.0', '0e-1'),
669 ('e', '0.00', '0e-2'),
670 ('.6e', '0E-15', '0.000000e-9'),
671 ('.6e', '0', '0.000000e+6'),
672 ('.6e', '9.999999', '9.999999e+0'),
673 ('.6e', '9.9999999', '1.000000e+1'),
674 ('.6e', '-1.23e5', '-1.230000e+5'),
675 ('.6e', '1.23456789e-3', '1.234568e-3'),
676 ('f', '0', '0'),
677 ('f', '0.0', '0.0'),
678 ('f', '0E-2', '0.00'),
679 ('f', '0.00E-8', '0.0000000000'),
680 ('f', '0E1', '0'), # loses exponent information
681 ('f', '3.2E1', '32'),
682 ('f', '3.2E2', '320'),
683 ('f', '3.20E2', '320'),
684 ('f', '3.200E2', '320.0'),
685 ('f', '3.2E-6', '0.0000032'),
686 ('.6f', '0E-15', '0.000000'), # all zeros treated equally
687 ('.6f', '0E1', '0.000000'),
688 ('.6f', '0', '0.000000'),
689 ('.0f', '0', '0'), # no decimal point
690 ('.0f', '0e-2', '0'),
691 ('.0f', '3.14159265', '3'),
692 ('.1f', '3.14159265', '3.1'),
693 ('.4f', '3.14159265', '3.1416'),
694 ('.6f', '3.14159265', '3.141593'),
695 ('.7f', '3.14159265', '3.1415926'), # round-half-even!
696 ('.8f', '3.14159265', '3.14159265'),
697 ('.9f', '3.14159265', '3.141592650'),
698
699 ('g', '0', '0'),
700 ('g', '0.0', '0.0'),
701 ('g', '0E1', '0e+1'),
702 ('G', '0E1', '0E+1'),
703 ('g', '0E-5', '0.00000'),
704 ('g', '0E-6', '0.000000'),
705 ('g', '0E-7', '0e-7'),
706 ('g', '-0E2', '-0e+2'),
707 ('.0g', '3.14159265', '3'), # 0 sig fig -> 1 sig fig
708 ('.1g', '3.14159265', '3'),
709 ('.2g', '3.14159265', '3.1'),
710 ('.5g', '3.14159265', '3.1416'),
711 ('.7g', '3.14159265', '3.141593'),
712 ('.8g', '3.14159265', '3.1415926'), # round-half-even!
713 ('.9g', '3.14159265', '3.14159265'),
714 ('.10g', '3.14159265', '3.14159265'), # don't pad
715
716 ('%', '0E1', '0%'),
717 ('%', '0E0', '0%'),
718 ('%', '0E-1', '0%'),
719 ('%', '0E-2', '0%'),
720 ('%', '0E-3', '0.0%'),
721 ('%', '0E-4', '0.00%'),
722
723 ('.3%', '0', '0.000%'), # all zeros treated equally
724 ('.3%', '0E10', '0.000%'),
725 ('.3%', '0E-10', '0.000%'),
726 ('.3%', '2.34', '234.000%'),
727 ('.3%', '1.234567', '123.457%'),
728 ('.0%', '1.23', '123%'),
729
730 ('e', 'NaN', 'NaN'),
731 ('f', '-NaN123', '-NaN123'),
732 ('+g', 'NaN456', '+NaN456'),
733 ('.3e', 'Inf', 'Infinity'),
734 ('.16f', '-Inf', '-Infinity'),
735 ('.0g', '-sNaN', '-sNaN'),
736
737 ('', '1.00', '1.00'),
Mark Dickinsonad416342009-03-17 18:10:15 +0000738
Mark Dickinson79f52032009-03-17 23:12:51 +0000739 # test alignment and padding
Mark Dickinsonad416342009-03-17 18:10:15 +0000740 ('<6', '123', '123 '),
741 ('>6', '123', ' 123'),
742 ('^6', '123', ' 123 '),
743 ('=+6', '123', '+ 123'),
Mark Dickinson79f52032009-03-17 23:12:51 +0000744 ('#<10', 'NaN', 'NaN#######'),
745 ('#<10', '-4.3', '-4.3######'),
746 ('#<+10', '0.0130', '+0.0130###'),
747 ('#< 10', '0.0130', ' 0.0130###'),
748 ('@>10', '-Inf', '@-Infinity'),
749 ('#>5', '-Inf', '-Infinity'),
750 ('?^5', '123', '?123?'),
751 ('%^6', '123', '%123%%'),
752 (' ^6', '-45.6', '-45.6 '),
753 ('/=10', '-45.6', '-/////45.6'),
754 ('/=+10', '45.6', '+/////45.6'),
755 ('/= 10', '45.6', ' /////45.6'),
756
757 # thousands separator
758 (',', '1234567', '1,234,567'),
759 (',', '123456', '123,456'),
760 (',', '12345', '12,345'),
761 (',', '1234', '1,234'),
762 (',', '123', '123'),
763 (',', '12', '12'),
764 (',', '1', '1'),
765 (',', '0', '0'),
766 (',', '-1234567', '-1,234,567'),
767 (',', '-123456', '-123,456'),
768 ('7,', '123456', '123,456'),
769 ('8,', '123456', '123,456 '),
770 ('08,', '123456', '0,123,456'), # special case: extra 0 needed
771 ('+08,', '123456', '+123,456'), # but not if there's a sign
772 (' 08,', '123456', ' 123,456'),
773 ('08,', '-123456', '-123,456'),
774 ('+09,', '123456', '+0,123,456'),
775 # ... with fractional part...
776 ('07,', '1234.56', '1,234.56'),
777 ('08,', '1234.56', '1,234.56'),
778 ('09,', '1234.56', '01,234.56'),
779 ('010,', '1234.56', '001,234.56'),
780 ('011,', '1234.56', '0,001,234.56'),
781 ('012,', '1234.56', '0,001,234.56'),
782 ('08,.1f', '1234.5', '01,234.5'),
783 # no thousands separators in fraction part
784 (',', '1.23456789', '1.23456789'),
785 (',%', '123.456789', '12,345.6789%'),
786 (',e', '123456', '1.23456e+5'),
787 (',E', '123456', '1.23456E+5'),
Mark Dickinsond496d302009-09-07 16:23:26 +0000788
789 # issue 6850
790 ('a=-7.0', '0.12345', 'aaaa0.1'),
Christian Heimesf16baeb2008-02-29 14:57:44 +0000791 ]
792 for fmt, d, result in test_values:
793 self.assertEqual(format(Decimal(d), fmt), result)
794
Mark Dickinson79f52032009-03-17 23:12:51 +0000795 def test_n_format(self):
796 try:
797 from locale import CHAR_MAX
798 except ImportError:
799 return
800
801 # Set up some localeconv-like dictionaries
802 en_US = {
803 'decimal_point' : '.',
804 'grouping' : [3, 3, 0],
805 'thousands_sep': ','
806 }
807
808 fr_FR = {
809 'decimal_point' : ',',
810 'grouping' : [CHAR_MAX],
811 'thousands_sep' : ''
812 }
813
814 ru_RU = {
815 'decimal_point' : ',',
816 'grouping' : [3, 3, 0],
817 'thousands_sep' : ' '
818 }
819
820 crazy = {
821 'decimal_point' : '&',
822 'grouping' : [1, 4, 2, CHAR_MAX],
823 'thousands_sep' : '-'
824 }
825
826
827 def get_fmt(x, locale, fmt='n'):
828 return Decimal.__format__(Decimal(x), fmt, _localeconv=locale)
829
830 self.assertEqual(get_fmt(Decimal('12.7'), en_US), '12.7')
831 self.assertEqual(get_fmt(Decimal('12.7'), fr_FR), '12,7')
832 self.assertEqual(get_fmt(Decimal('12.7'), ru_RU), '12,7')
833 self.assertEqual(get_fmt(Decimal('12.7'), crazy), '1-2&7')
834
835 self.assertEqual(get_fmt(123456789, en_US), '123,456,789')
836 self.assertEqual(get_fmt(123456789, fr_FR), '123456789')
837 self.assertEqual(get_fmt(123456789, ru_RU), '123 456 789')
838 self.assertEqual(get_fmt(1234567890123, crazy), '123456-78-9012-3')
839
840 self.assertEqual(get_fmt(123456789, en_US, '.6n'), '1.23457e+8')
841 self.assertEqual(get_fmt(123456789, fr_FR, '.6n'), '1,23457e+8')
842 self.assertEqual(get_fmt(123456789, ru_RU, '.6n'), '1,23457e+8')
843 self.assertEqual(get_fmt(123456789, crazy, '.6n'), '1&23457e+8')
844
Mark Dickinson7303b592009-03-18 08:25:36 +0000845 # zero padding
846 self.assertEqual(get_fmt(1234, fr_FR, '03n'), '1234')
847 self.assertEqual(get_fmt(1234, fr_FR, '04n'), '1234')
848 self.assertEqual(get_fmt(1234, fr_FR, '05n'), '01234')
849 self.assertEqual(get_fmt(1234, fr_FR, '06n'), '001234')
850
851 self.assertEqual(get_fmt(12345, en_US, '05n'), '12,345')
852 self.assertEqual(get_fmt(12345, en_US, '06n'), '12,345')
853 self.assertEqual(get_fmt(12345, en_US, '07n'), '012,345')
854 self.assertEqual(get_fmt(12345, en_US, '08n'), '0,012,345')
855 self.assertEqual(get_fmt(12345, en_US, '09n'), '0,012,345')
856 self.assertEqual(get_fmt(12345, en_US, '010n'), '00,012,345')
857
858 self.assertEqual(get_fmt(123456, crazy, '06n'), '1-2345-6')
859 self.assertEqual(get_fmt(123456, crazy, '07n'), '1-2345-6')
860 self.assertEqual(get_fmt(123456, crazy, '08n'), '1-2345-6')
861 self.assertEqual(get_fmt(123456, crazy, '09n'), '01-2345-6')
862 self.assertEqual(get_fmt(123456, crazy, '010n'), '0-01-2345-6')
863 self.assertEqual(get_fmt(123456, crazy, '011n'), '0-01-2345-6')
864 self.assertEqual(get_fmt(123456, crazy, '012n'), '00-01-2345-6')
865 self.assertEqual(get_fmt(123456, crazy, '013n'), '000-01-2345-6')
866
Mark Dickinson79f52032009-03-17 23:12:51 +0000867
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000868class DecimalArithmeticOperatorsTest(unittest.TestCase):
869 '''Unit tests for all arithmetic operators, binary and unary.'''
870
871 def test_addition(self):
872
873 d1 = Decimal('-11.1')
874 d2 = Decimal('22.2')
875
876 #two Decimals
877 self.assertEqual(d1+d2, Decimal('11.1'))
878 self.assertEqual(d2+d1, Decimal('11.1'))
879
880 #with other type, left
881 c = d1 + 5
882 self.assertEqual(c, Decimal('-6.1'))
883 self.assertEqual(type(c), type(d1))
884
885 #with other type, right
886 c = 5 + d1
887 self.assertEqual(c, Decimal('-6.1'))
888 self.assertEqual(type(c), type(d1))
889
890 #inline with decimal
891 d1 += d2
892 self.assertEqual(d1, Decimal('11.1'))
893
894 #inline with other type
895 d1 += 5
896 self.assertEqual(d1, Decimal('16.1'))
897
898 def test_subtraction(self):
899
900 d1 = Decimal('-11.1')
901 d2 = Decimal('22.2')
902
903 #two Decimals
904 self.assertEqual(d1-d2, Decimal('-33.3'))
905 self.assertEqual(d2-d1, Decimal('33.3'))
906
907 #with other type, left
908 c = d1 - 5
909 self.assertEqual(c, Decimal('-16.1'))
910 self.assertEqual(type(c), type(d1))
911
912 #with other type, right
913 c = 5 - d1
914 self.assertEqual(c, Decimal('16.1'))
915 self.assertEqual(type(c), type(d1))
916
917 #inline with decimal
918 d1 -= d2
919 self.assertEqual(d1, Decimal('-33.3'))
920
921 #inline with other type
922 d1 -= 5
923 self.assertEqual(d1, Decimal('-38.3'))
924
925 def test_multiplication(self):
926
927 d1 = Decimal('-5')
928 d2 = Decimal('3')
929
930 #two Decimals
931 self.assertEqual(d1*d2, Decimal('-15'))
932 self.assertEqual(d2*d1, Decimal('-15'))
933
934 #with other type, left
935 c = d1 * 5
936 self.assertEqual(c, Decimal('-25'))
937 self.assertEqual(type(c), type(d1))
938
939 #with other type, right
940 c = 5 * d1
941 self.assertEqual(c, Decimal('-25'))
942 self.assertEqual(type(c), type(d1))
943
944 #inline with decimal
945 d1 *= d2
946 self.assertEqual(d1, Decimal('-15'))
947
948 #inline with other type
949 d1 *= 5
950 self.assertEqual(d1, Decimal('-75'))
951
952 def test_division(self):
953
954 d1 = Decimal('-5')
955 d2 = Decimal('2')
956
957 #two Decimals
958 self.assertEqual(d1/d2, Decimal('-2.5'))
959 self.assertEqual(d2/d1, Decimal('-0.4'))
960
961 #with other type, left
962 c = d1 / 4
963 self.assertEqual(c, Decimal('-1.25'))
964 self.assertEqual(type(c), type(d1))
965
966 #with other type, right
967 c = 4 / d1
968 self.assertEqual(c, Decimal('-0.8'))
969 self.assertEqual(type(c), type(d1))
970
971 #inline with decimal
972 d1 /= d2
973 self.assertEqual(d1, Decimal('-2.5'))
974
975 #inline with other type
976 d1 /= 4
977 self.assertEqual(d1, Decimal('-0.625'))
978
979 def test_floor_division(self):
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000980
981 d1 = Decimal('5')
982 d2 = Decimal('2')
983
984 #two Decimals
985 self.assertEqual(d1//d2, Decimal('2'))
986 self.assertEqual(d2//d1, Decimal('0'))
987
988 #with other type, left
989 c = d1 // 4
990 self.assertEqual(c, Decimal('1'))
991 self.assertEqual(type(c), type(d1))
992
993 #with other type, right
994 c = 7 // d1
995 self.assertEqual(c, Decimal('1'))
996 self.assertEqual(type(c), type(d1))
997
998 #inline with decimal
999 d1 //= d2
1000 self.assertEqual(d1, Decimal('2'))
1001
1002 #inline with other type
1003 d1 //= 2
1004 self.assertEqual(d1, Decimal('1'))
1005
1006 def test_powering(self):
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001007
1008 d1 = Decimal('5')
1009 d2 = Decimal('2')
1010
1011 #two Decimals
1012 self.assertEqual(d1**d2, Decimal('25'))
1013 self.assertEqual(d2**d1, Decimal('32'))
1014
1015 #with other type, left
1016 c = d1 ** 4
1017 self.assertEqual(c, Decimal('625'))
1018 self.assertEqual(type(c), type(d1))
1019
1020 #with other type, right
1021 c = 7 ** d1
1022 self.assertEqual(c, Decimal('16807'))
1023 self.assertEqual(type(c), type(d1))
1024
1025 #inline with decimal
1026 d1 **= d2
1027 self.assertEqual(d1, Decimal('25'))
1028
1029 #inline with other type
1030 d1 **= 4
1031 self.assertEqual(d1, Decimal('390625'))
1032
1033 def test_module(self):
1034
1035 d1 = Decimal('5')
1036 d2 = Decimal('2')
1037
1038 #two Decimals
1039 self.assertEqual(d1%d2, Decimal('1'))
1040 self.assertEqual(d2%d1, Decimal('2'))
1041
1042 #with other type, left
1043 c = d1 % 4
1044 self.assertEqual(c, Decimal('1'))
1045 self.assertEqual(type(c), type(d1))
1046
1047 #with other type, right
1048 c = 7 % d1
1049 self.assertEqual(c, Decimal('2'))
1050 self.assertEqual(type(c), type(d1))
1051
1052 #inline with decimal
1053 d1 %= d2
1054 self.assertEqual(d1, Decimal('1'))
1055
1056 #inline with other type
1057 d1 %= 4
1058 self.assertEqual(d1, Decimal('1'))
1059
1060 def test_floor_div_module(self):
1061
1062 d1 = Decimal('5')
1063 d2 = Decimal('2')
1064
1065 #two Decimals
1066 (p, q) = divmod(d1, d2)
1067 self.assertEqual(p, Decimal('2'))
1068 self.assertEqual(q, Decimal('1'))
1069 self.assertEqual(type(p), type(d1))
1070 self.assertEqual(type(q), type(d1))
1071
1072 #with other type, left
1073 (p, q) = divmod(d1, 4)
1074 self.assertEqual(p, Decimal('1'))
1075 self.assertEqual(q, Decimal('1'))
1076 self.assertEqual(type(p), type(d1))
1077 self.assertEqual(type(q), type(d1))
1078
1079 #with other type, right
1080 (p, q) = divmod(7, d1)
1081 self.assertEqual(p, Decimal('1'))
1082 self.assertEqual(q, Decimal('2'))
1083 self.assertEqual(type(p), type(d1))
1084 self.assertEqual(type(q), type(d1))
1085
1086 def test_unary_operators(self):
1087 self.assertEqual(+Decimal(45), Decimal(+45)) # +
1088 self.assertEqual(-Decimal(45), Decimal(-45)) # -
1089 self.assertEqual(abs(Decimal(45)), abs(Decimal(-45))) # abs
1090
Christian Heimes77c02eb2008-02-09 02:18:51 +00001091 def test_nan_comparisons(self):
1092 n = Decimal('NaN')
1093 s = Decimal('sNaN')
1094 i = Decimal('Inf')
1095 f = Decimal('2')
1096 for x, y in [(n, n), (n, i), (i, n), (n, f), (f, n),
1097 (s, n), (n, s), (s, i), (i, s), (s, f), (f, s), (s, s)]:
Georg Brandlab91fde2009-08-13 08:51:18 +00001098 self.assertTrue(x != y)
1099 self.assertTrue(not (x == y))
1100 self.assertTrue(not (x < y))
1101 self.assertTrue(not (x <= y))
1102 self.assertTrue(not (x > y))
1103 self.assertTrue(not (x >= y))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001104
1105# The following are two functions used to test threading in the next class
1106
1107def thfunc1(cls):
1108 d1 = Decimal(1)
1109 d3 = Decimal(3)
Christian Heimesfe337bf2008-03-23 21:54:12 +00001110 test1 = d1/d3
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001111 cls.synchro.wait()
Christian Heimesfe337bf2008-03-23 21:54:12 +00001112 test2 = d1/d3
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001113 cls.finish1.set()
Christian Heimesfe337bf2008-03-23 21:54:12 +00001114
Christian Heimes81ee3ef2008-05-04 22:42:01 +00001115 cls.assertEqual(test1, Decimal('0.3333333333333333333333333333'))
1116 cls.assertEqual(test2, Decimal('0.3333333333333333333333333333'))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001117 return
1118
1119def thfunc2(cls):
1120 d1 = Decimal(1)
1121 d3 = Decimal(3)
Christian Heimesfe337bf2008-03-23 21:54:12 +00001122 test1 = d1/d3
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001123 thiscontext = getcontext()
1124 thiscontext.prec = 18
Christian Heimesfe337bf2008-03-23 21:54:12 +00001125 test2 = d1/d3
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001126 cls.synchro.set()
1127 cls.finish2.set()
Christian Heimesfe337bf2008-03-23 21:54:12 +00001128
Christian Heimes81ee3ef2008-05-04 22:42:01 +00001129 cls.assertEqual(test1, Decimal('0.3333333333333333333333333333'))
Christian Heimesfe337bf2008-03-23 21:54:12 +00001130 cls.assertEqual(test2, Decimal('0.333333333333333333'))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001131 return
1132
1133
1134class DecimalUseOfContextTest(unittest.TestCase):
1135 '''Unit tests for Use of Context cases in Decimal.'''
1136
Raymond Hettinger7e71fa52004-12-18 19:07:19 +00001137 try:
1138 import threading
1139 except ImportError:
1140 threading = None
1141
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001142 # Take care executing this test from IDLE, there's an issue in threading
1143 # that hangs IDLE and I couldn't find it
1144
1145 def test_threading(self):
1146 #Test the "threading isolation" of a Context.
1147
1148 self.synchro = threading.Event()
1149 self.finish1 = threading.Event()
1150 self.finish2 = threading.Event()
1151
1152 th1 = threading.Thread(target=thfunc1, args=(self,))
1153 th2 = threading.Thread(target=thfunc2, args=(self,))
1154
1155 th1.start()
1156 th2.start()
1157
1158 self.finish1.wait()
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001159 self.finish2.wait()
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001160 return
1161
Raymond Hettinger7e71fa52004-12-18 19:07:19 +00001162 if threading is None:
1163 del test_threading
1164
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001165
1166class DecimalUsabilityTest(unittest.TestCase):
1167 '''Unit tests for Usability cases of Decimal.'''
1168
1169 def test_comparison_operators(self):
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001170
1171 da = Decimal('23.42')
1172 db = Decimal('23.42')
1173 dc = Decimal('45')
1174
1175 #two Decimals
Georg Brandlab91fde2009-08-13 08:51:18 +00001176 self.assertTrue(dc > da)
1177 self.assertTrue(dc >= da)
1178 self.assertTrue(da < dc)
1179 self.assertTrue(da <= dc)
Guido van Rossume61fd5b2007-07-11 12:20:59 +00001180 self.assertEqual(da, db)
Georg Brandlab91fde2009-08-13 08:51:18 +00001181 self.assertTrue(da != dc)
1182 self.assertTrue(da <= db)
1183 self.assertTrue(da >= db)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001184
1185 #a Decimal and an int
Georg Brandlab91fde2009-08-13 08:51:18 +00001186 self.assertTrue(dc > 23)
1187 self.assertTrue(23 < dc)
Guido van Rossume61fd5b2007-07-11 12:20:59 +00001188 self.assertEqual(dc, 45)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001189
1190 #a Decimal and uncomparable
Raymond Hettinger0aeac102004-07-05 22:53:03 +00001191 self.assertNotEqual(da, 'ugly')
1192 self.assertNotEqual(da, 32.7)
1193 self.assertNotEqual(da, object())
1194 self.assertNotEqual(da, object)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001195
Raymond Hettinger0aeac102004-07-05 22:53:03 +00001196 # sortable
Guido van Rossumc1f779c2007-07-03 08:25:58 +00001197 a = list(map(Decimal, range(100)))
Raymond Hettinger0aeac102004-07-05 22:53:03 +00001198 b = a[:]
1199 random.shuffle(a)
1200 a.sort()
1201 self.assertEqual(a, b)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001202
1203 def test_copy_and_deepcopy_methods(self):
1204 d = Decimal('43.24')
1205 c = copy.copy(d)
1206 self.assertEqual(id(c), id(d))
1207 dc = copy.deepcopy(d)
1208 self.assertEqual(id(dc), id(d))
1209
1210 def test_hash_method(self):
1211 #just that it's hashable
1212 hash(Decimal(23))
Thomas Wouters8ce81f72007-09-20 18:22:40 +00001213
1214 test_values = [Decimal(sign*(2**m + n))
1215 for m in [0, 14, 15, 16, 17, 30, 31,
1216 32, 33, 62, 63, 64, 65, 66]
1217 for n in range(-10, 10)
1218 for sign in [-1, 1]]
1219 test_values.extend([
1220 Decimal("-0"), # zeros
1221 Decimal("0.00"),
1222 Decimal("-0.000"),
1223 Decimal("0E10"),
1224 Decimal("-0E12"),
1225 Decimal("10.0"), # negative exponent
1226 Decimal("-23.00000"),
1227 Decimal("1230E100"), # positive exponent
1228 Decimal("-4.5678E50"),
1229 # a value for which hash(n) != hash(n % (2**64-1))
1230 # in Python pre-2.6
1231 Decimal(2**64 + 2**32 - 1),
1232 # selection of values which fail with the old (before
1233 # version 2.6) long.__hash__
1234 Decimal("1.634E100"),
1235 Decimal("90.697E100"),
1236 Decimal("188.83E100"),
1237 Decimal("1652.9E100"),
1238 Decimal("56531E100"),
1239 ])
1240
1241 # check that hash(d) == hash(int(d)) for integral values
1242 for value in test_values:
1243 self.assertEqual(hash(value), hash(int(value)))
1244
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001245 #the same hash that to an int
1246 self.assertEqual(hash(Decimal(23)), hash(23))
Raymond Hettingerbea3f6f2005-03-15 04:59:17 +00001247 self.assertRaises(TypeError, hash, Decimal('NaN'))
Georg Brandlab91fde2009-08-13 08:51:18 +00001248 self.assertTrue(hash(Decimal('Inf')))
1249 self.assertTrue(hash(Decimal('-Inf')))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001250
Christian Heimes2380ac72008-01-09 00:17:24 +00001251 # check that the value of the hash doesn't depend on the
1252 # current context (issue #1757)
1253 c = getcontext()
1254 old_precision = c.prec
1255 x = Decimal("123456789.1")
1256
1257 c.prec = 6
1258 h1 = hash(x)
1259 c.prec = 10
1260 h2 = hash(x)
1261 c.prec = 16
1262 h3 = hash(x)
1263
1264 self.assertEqual(h1, h2)
1265 self.assertEqual(h1, h3)
1266 c.prec = old_precision
1267
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001268 def test_min_and_max_methods(self):
1269
1270 d1 = Decimal('15.32')
1271 d2 = Decimal('28.5')
1272 l1 = 15
1273 l2 = 28
1274
1275 #between Decimals
Georg Brandlab91fde2009-08-13 08:51:18 +00001276 self.assertTrue(min(d1,d2) is d1)
1277 self.assertTrue(min(d2,d1) is d1)
1278 self.assertTrue(max(d1,d2) is d2)
1279 self.assertTrue(max(d2,d1) is d2)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001280
1281 #between Decimal and long
Georg Brandlab91fde2009-08-13 08:51:18 +00001282 self.assertTrue(min(d1,l2) is d1)
1283 self.assertTrue(min(l2,d1) is d1)
1284 self.assertTrue(max(l1,d2) is d2)
1285 self.assertTrue(max(d2,l1) is d2)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001286
1287 def test_as_nonzero(self):
1288 #as false
Georg Brandlab91fde2009-08-13 08:51:18 +00001289 self.assertFalse(Decimal(0))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001290 #as true
Georg Brandlab91fde2009-08-13 08:51:18 +00001291 self.assertTrue(Decimal('0.372'))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001292
1293 def test_tostring_methods(self):
1294 #Test str and repr methods.
1295
1296 d = Decimal('15.32')
1297 self.assertEqual(str(d), '15.32') # str
Christian Heimes68f5fbe2008-02-14 08:27:37 +00001298 self.assertEqual(repr(d), "Decimal('15.32')") # repr
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001299
1300 def test_tonum_methods(self):
1301 #Test float, int and long methods.
1302
1303 d1 = Decimal('66')
1304 d2 = Decimal('15.32')
1305
1306 #int
1307 self.assertEqual(int(d1), 66)
1308 self.assertEqual(int(d2), 15)
1309
1310 #long
Guido van Rossume2a383d2007-01-15 16:59:06 +00001311 self.assertEqual(int(d1), 66)
1312 self.assertEqual(int(d2), 15)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001313
1314 #float
1315 self.assertEqual(float(d1), 66)
1316 self.assertEqual(float(d2), 15.32)
1317
Mark Dickinsonb27406c2008-05-09 13:42:33 +00001318 #floor
1319 test_pairs = [
1320 ('123.00', 123),
1321 ('3.2', 3),
1322 ('3.54', 3),
1323 ('3.899', 3),
1324 ('-2.3', -3),
1325 ('-11.0', -11),
1326 ('0.0', 0),
1327 ('-0E3', 0),
1328 ]
1329 for d, i in test_pairs:
1330 self.assertEqual(math.floor(Decimal(d)), i)
1331 self.assertRaises(ValueError, math.floor, Decimal('-NaN'))
1332 self.assertRaises(ValueError, math.floor, Decimal('sNaN'))
1333 self.assertRaises(ValueError, math.floor, Decimal('NaN123'))
1334 self.assertRaises(OverflowError, math.floor, Decimal('Inf'))
1335 self.assertRaises(OverflowError, math.floor, Decimal('-Inf'))
1336
1337 #ceiling
1338 test_pairs = [
1339 ('123.00', 123),
1340 ('3.2', 4),
1341 ('3.54', 4),
1342 ('3.899', 4),
1343 ('-2.3', -2),
1344 ('-11.0', -11),
1345 ('0.0', 0),
1346 ('-0E3', 0),
1347 ]
1348 for d, i in test_pairs:
1349 self.assertEqual(math.ceil(Decimal(d)), i)
1350 self.assertRaises(ValueError, math.ceil, Decimal('-NaN'))
1351 self.assertRaises(ValueError, math.ceil, Decimal('sNaN'))
1352 self.assertRaises(ValueError, math.ceil, Decimal('NaN123'))
1353 self.assertRaises(OverflowError, math.ceil, Decimal('Inf'))
1354 self.assertRaises(OverflowError, math.ceil, Decimal('-Inf'))
1355
1356 #round, single argument
1357 test_pairs = [
1358 ('123.00', 123),
1359 ('3.2', 3),
1360 ('3.54', 4),
1361 ('3.899', 4),
1362 ('-2.3', -2),
1363 ('-11.0', -11),
1364 ('0.0', 0),
1365 ('-0E3', 0),
1366 ('-3.5', -4),
1367 ('-2.5', -2),
1368 ('-1.5', -2),
1369 ('-0.5', 0),
1370 ('0.5', 0),
1371 ('1.5', 2),
1372 ('2.5', 2),
1373 ('3.5', 4),
1374 ]
1375 for d, i in test_pairs:
1376 self.assertEqual(round(Decimal(d)), i)
1377 self.assertRaises(ValueError, round, Decimal('-NaN'))
1378 self.assertRaises(ValueError, round, Decimal('sNaN'))
1379 self.assertRaises(ValueError, round, Decimal('NaN123'))
1380 self.assertRaises(OverflowError, round, Decimal('Inf'))
1381 self.assertRaises(OverflowError, round, Decimal('-Inf'))
1382
1383 #round, two arguments; this is essentially equivalent
1384 #to quantize, which is already extensively tested
1385 test_triples = [
1386 ('123.456', -4, '0E+4'),
1387 ('123.456', -3, '0E+3'),
1388 ('123.456', -2, '1E+2'),
1389 ('123.456', -1, '1.2E+2'),
1390 ('123.456', 0, '123'),
1391 ('123.456', 1, '123.5'),
1392 ('123.456', 2, '123.46'),
1393 ('123.456', 3, '123.456'),
1394 ('123.456', 4, '123.4560'),
1395 ('123.455', 2, '123.46'),
1396 ('123.445', 2, '123.44'),
1397 ('Inf', 4, 'NaN'),
1398 ('-Inf', -23, 'NaN'),
1399 ('sNaN314', 3, 'NaN314'),
1400 ]
1401 for d, n, r in test_triples:
1402 self.assertEqual(str(round(Decimal(d), n)), r)
1403
1404
1405
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001406 def test_eval_round_trip(self):
1407
1408 #with zero
1409 d = Decimal( (0, (0,), 0) )
1410 self.assertEqual(d, eval(repr(d)))
1411
1412 #int
1413 d = Decimal( (1, (4, 5), 0) )
1414 self.assertEqual(d, eval(repr(d)))
1415
1416 #float
1417 d = Decimal( (0, (4, 5, 3, 4), -2) )
1418 self.assertEqual(d, eval(repr(d)))
1419
1420 #weird
1421 d = Decimal( (1, (4, 3, 4, 9, 1, 3, 5, 3, 4), -25) )
1422 self.assertEqual(d, eval(repr(d)))
1423
1424 def test_as_tuple(self):
1425
1426 #with zero
1427 d = Decimal(0)
1428 self.assertEqual(d.as_tuple(), (0, (0,), 0) )
1429
1430 #int
1431 d = Decimal(-45)
1432 self.assertEqual(d.as_tuple(), (1, (4, 5), 0) )
1433
1434 #complicated string
1435 d = Decimal("-4.34913534E-17")
1436 self.assertEqual(d.as_tuple(), (1, (4, 3, 4, 9, 1, 3, 5, 3, 4), -25) )
1437
1438 #inf
1439 d = Decimal("Infinity")
1440 self.assertEqual(d.as_tuple(), (0, (0,), 'F') )
1441
Guido van Rossum8ce8a782007-11-01 19:42:39 +00001442 #leading zeros in coefficient should be stripped
1443 d = Decimal( (0, (0, 0, 4, 0, 5, 3, 4), -2) )
1444 self.assertEqual(d.as_tuple(), (0, (4, 0, 5, 3, 4), -2) )
1445 d = Decimal( (1, (0, 0, 0), 37) )
1446 self.assertEqual(d.as_tuple(), (1, (0,), 37))
1447 d = Decimal( (1, (), 37) )
1448 self.assertEqual(d.as_tuple(), (1, (0,), 37))
1449
1450 #leading zeros in NaN diagnostic info should be stripped
1451 d = Decimal( (0, (0, 0, 4, 0, 5, 3, 4), 'n') )
1452 self.assertEqual(d.as_tuple(), (0, (4, 0, 5, 3, 4), 'n') )
1453 d = Decimal( (1, (0, 0, 0), 'N') )
1454 self.assertEqual(d.as_tuple(), (1, (), 'N') )
1455 d = Decimal( (1, (), 'n') )
1456 self.assertEqual(d.as_tuple(), (1, (), 'n') )
1457
1458 #coefficient in infinity should be ignored
1459 d = Decimal( (0, (4, 5, 3, 4), 'F') )
1460 self.assertEqual(d.as_tuple(), (0, (0,), 'F'))
1461 d = Decimal( (1, (0, 2, 7, 1), 'F') )
1462 self.assertEqual(d.as_tuple(), (1, (0,), 'F'))
1463
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001464 def test_immutability_operations(self):
1465 # Do operations and check that it didn't change change internal objects.
1466
1467 d1 = Decimal('-25e55')
1468 b1 = Decimal('-25e55')
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001469 d2 = Decimal('33e+33')
1470 b2 = Decimal('33e+33')
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001471
1472 def checkSameDec(operation, useOther=False):
1473 if useOther:
1474 eval("d1." + operation + "(d2)")
1475 self.assertEqual(d1._sign, b1._sign)
1476 self.assertEqual(d1._int, b1._int)
1477 self.assertEqual(d1._exp, b1._exp)
1478 self.assertEqual(d2._sign, b2._sign)
1479 self.assertEqual(d2._int, b2._int)
1480 self.assertEqual(d2._exp, b2._exp)
1481 else:
1482 eval("d1." + operation + "()")
1483 self.assertEqual(d1._sign, b1._sign)
1484 self.assertEqual(d1._int, b1._int)
1485 self.assertEqual(d1._exp, b1._exp)
1486 return
1487
1488 Decimal(d1)
1489 self.assertEqual(d1._sign, b1._sign)
1490 self.assertEqual(d1._int, b1._int)
1491 self.assertEqual(d1._exp, b1._exp)
1492
1493 checkSameDec("__abs__")
1494 checkSameDec("__add__", True)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001495 checkSameDec("__divmod__", True)
Christian Heimes77c02eb2008-02-09 02:18:51 +00001496 checkSameDec("__eq__", True)
1497 checkSameDec("__ne__", True)
1498 checkSameDec("__le__", True)
1499 checkSameDec("__lt__", True)
1500 checkSameDec("__ge__", True)
1501 checkSameDec("__gt__", True)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001502 checkSameDec("__float__")
1503 checkSameDec("__floordiv__", True)
1504 checkSameDec("__hash__")
1505 checkSameDec("__int__")
Christian Heimes969fe572008-01-25 11:23:10 +00001506 checkSameDec("__trunc__")
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001507 checkSameDec("__mod__", True)
1508 checkSameDec("__mul__", True)
1509 checkSameDec("__neg__")
Jack Diederich4dafcc42006-11-28 19:15:13 +00001510 checkSameDec("__bool__")
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001511 checkSameDec("__pos__")
1512 checkSameDec("__pow__", True)
1513 checkSameDec("__radd__", True)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001514 checkSameDec("__rdivmod__", True)
1515 checkSameDec("__repr__")
1516 checkSameDec("__rfloordiv__", True)
1517 checkSameDec("__rmod__", True)
1518 checkSameDec("__rmul__", True)
1519 checkSameDec("__rpow__", True)
1520 checkSameDec("__rsub__", True)
1521 checkSameDec("__str__")
1522 checkSameDec("__sub__", True)
1523 checkSameDec("__truediv__", True)
1524 checkSameDec("adjusted")
1525 checkSameDec("as_tuple")
1526 checkSameDec("compare", True)
1527 checkSameDec("max", True)
1528 checkSameDec("min", True)
1529 checkSameDec("normalize")
1530 checkSameDec("quantize", True)
1531 checkSameDec("remainder_near", True)
1532 checkSameDec("same_quantum", True)
1533 checkSameDec("sqrt")
1534 checkSameDec("to_eng_string")
1535 checkSameDec("to_integral")
1536
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001537 def test_subclassing(self):
1538 # Different behaviours when subclassing Decimal
1539
1540 class MyDecimal(Decimal):
1541 pass
1542
1543 d1 = MyDecimal(1)
1544 d2 = MyDecimal(2)
1545 d = d1 + d2
1546 self.assertTrue(type(d) is Decimal)
1547
1548 d = d1.max(d2)
1549 self.assertTrue(type(d) is Decimal)
1550
Christian Heimes0348fb62008-03-26 12:55:56 +00001551 def test_implicit_context(self):
1552 # Check results when context given implicitly. (Issue 2478)
1553 c = getcontext()
1554 self.assertEqual(str(Decimal(0).sqrt()),
1555 str(c.sqrt(Decimal(0))))
1556
Mark Dickinson9050bb22009-10-29 12:25:07 +00001557 def test_conversions_from_int(self):
1558 # Check that methods taking a second Decimal argument will
1559 # always accept an integer in place of a Decimal.
1560 self.assertEqual(Decimal(4).compare(3),
1561 Decimal(4).compare(Decimal(3)))
1562 self.assertEqual(Decimal(4).compare_signal(3),
1563 Decimal(4).compare_signal(Decimal(3)))
1564 self.assertEqual(Decimal(4).compare_total(3),
1565 Decimal(4).compare_total(Decimal(3)))
1566 self.assertEqual(Decimal(4).compare_total_mag(3),
1567 Decimal(4).compare_total_mag(Decimal(3)))
1568 self.assertEqual(Decimal(10101).logical_and(1001),
1569 Decimal(10101).logical_and(Decimal(1001)))
1570 self.assertEqual(Decimal(10101).logical_or(1001),
1571 Decimal(10101).logical_or(Decimal(1001)))
1572 self.assertEqual(Decimal(10101).logical_xor(1001),
1573 Decimal(10101).logical_xor(Decimal(1001)))
1574 self.assertEqual(Decimal(567).max(123),
1575 Decimal(567).max(Decimal(123)))
1576 self.assertEqual(Decimal(567).max_mag(123),
1577 Decimal(567).max_mag(Decimal(123)))
1578 self.assertEqual(Decimal(567).min(123),
1579 Decimal(567).min(Decimal(123)))
1580 self.assertEqual(Decimal(567).min_mag(123),
1581 Decimal(567).min_mag(Decimal(123)))
1582 self.assertEqual(Decimal(567).next_toward(123),
1583 Decimal(567).next_toward(Decimal(123)))
1584 self.assertEqual(Decimal(1234).quantize(100),
1585 Decimal(1234).quantize(Decimal(100)))
1586 self.assertEqual(Decimal(768).remainder_near(1234),
1587 Decimal(768).remainder_near(Decimal(1234)))
1588 self.assertEqual(Decimal(123).rotate(1),
1589 Decimal(123).rotate(Decimal(1)))
1590 self.assertEqual(Decimal(1234).same_quantum(1000),
1591 Decimal(1234).same_quantum(Decimal(1000)))
1592 self.assertEqual(Decimal('9.123').scaleb(-100),
1593 Decimal('9.123').scaleb(Decimal(-100)))
1594 self.assertEqual(Decimal(456).shift(-1),
1595 Decimal(456).shift(Decimal(-1)))
1596
1597 self.assertEqual(Decimal(-12).fma(Decimal(45), 67),
1598 Decimal(-12).fma(Decimal(45), Decimal(67)))
1599 self.assertEqual(Decimal(-12).fma(45, 67),
1600 Decimal(-12).fma(Decimal(45), Decimal(67)))
1601 self.assertEqual(Decimal(-12).fma(45, Decimal(67)),
1602 Decimal(-12).fma(Decimal(45), Decimal(67)))
1603
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001604
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001605class DecimalPythonAPItests(unittest.TestCase):
1606
Raymond Hettinger82417ca2009-02-03 03:54:28 +00001607 def test_abc(self):
Georg Brandlab91fde2009-08-13 08:51:18 +00001608 self.assertTrue(issubclass(Decimal, numbers.Number))
1609 self.assertTrue(not issubclass(Decimal, numbers.Real))
1610 self.assertTrue(isinstance(Decimal(0), numbers.Number))
1611 self.assertTrue(not isinstance(Decimal(0), numbers.Real))
Raymond Hettinger82417ca2009-02-03 03:54:28 +00001612
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001613 def test_pickle(self):
1614 d = Decimal('-3.141590000')
1615 p = pickle.dumps(d)
1616 e = pickle.loads(p)
1617 self.assertEqual(d, e)
1618
Raymond Hettinger5548be22004-07-05 18:49:38 +00001619 def test_int(self):
Raymond Hettinger605ed022004-11-24 07:28:48 +00001620 for x in range(-250, 250):
1621 s = '%0.2f' % (x / 100.0)
Raymond Hettinger5548be22004-07-05 18:49:38 +00001622 # should work the same as for floats
1623 self.assertEqual(int(Decimal(s)), int(float(s)))
Raymond Hettinger605ed022004-11-24 07:28:48 +00001624 # should work the same as to_integral in the ROUND_DOWN mode
Raymond Hettinger5548be22004-07-05 18:49:38 +00001625 d = Decimal(s)
Raymond Hettinger605ed022004-11-24 07:28:48 +00001626 r = d.to_integral(ROUND_DOWN)
Raymond Hettinger5548be22004-07-05 18:49:38 +00001627 self.assertEqual(Decimal(int(d)), r)
1628
Mark Dickinson8fde3da2009-09-08 19:23:44 +00001629 self.assertRaises(ValueError, int, Decimal('-nan'))
1630 self.assertRaises(ValueError, int, Decimal('snan'))
1631 self.assertRaises(OverflowError, int, Decimal('inf'))
1632 self.assertRaises(OverflowError, int, Decimal('-inf'))
1633
Christian Heimes969fe572008-01-25 11:23:10 +00001634 def test_trunc(self):
1635 for x in range(-250, 250):
1636 s = '%0.2f' % (x / 100.0)
1637 # should work the same as for floats
1638 self.assertEqual(int(Decimal(s)), int(float(s)))
1639 # should work the same as to_integral in the ROUND_DOWN mode
1640 d = Decimal(s)
1641 r = d.to_integral(ROUND_DOWN)
Christian Heimes400adb02008-02-01 08:12:03 +00001642 self.assertEqual(Decimal(math.trunc(d)), r)
Christian Heimes969fe572008-01-25 11:23:10 +00001643
Raymond Hettinger771ed762009-01-03 19:20:32 +00001644 def test_from_float(self):
1645
1646 class MyDecimal(Decimal):
1647 pass
1648
1649 r = MyDecimal.from_float(0.1)
1650 self.assertEqual(type(r), MyDecimal)
1651 self.assertEqual(str(r),
1652 '0.1000000000000000055511151231257827021181583404541015625')
1653 bigint = 12345678901234567890123456789
1654 self.assertEqual(MyDecimal.from_float(bigint), MyDecimal(bigint))
Georg Brandlab91fde2009-08-13 08:51:18 +00001655 self.assertTrue(MyDecimal.from_float(float('nan')).is_qnan())
1656 self.assertTrue(MyDecimal.from_float(float('inf')).is_infinite())
1657 self.assertTrue(MyDecimal.from_float(float('-inf')).is_infinite())
Raymond Hettinger771ed762009-01-03 19:20:32 +00001658 self.assertEqual(str(MyDecimal.from_float(float('nan'))),
1659 str(Decimal('NaN')))
1660 self.assertEqual(str(MyDecimal.from_float(float('inf'))),
1661 str(Decimal('Infinity')))
1662 self.assertEqual(str(MyDecimal.from_float(float('-inf'))),
1663 str(Decimal('-Infinity')))
1664 self.assertRaises(TypeError, MyDecimal.from_float, 'abc')
1665 for i in range(200):
1666 x = random.expovariate(0.01) * (random.random() * 2.0 - 1.0)
1667 self.assertEqual(x, float(MyDecimal.from_float(x))) # roundtrip
1668
1669 def test_create_decimal_from_float(self):
1670 context = Context(prec=5, rounding=ROUND_DOWN)
1671 self.assertEqual(
1672 context.create_decimal_from_float(math.pi),
1673 Decimal('3.1415')
1674 )
1675 context = Context(prec=5, rounding=ROUND_UP)
1676 self.assertEqual(
1677 context.create_decimal_from_float(math.pi),
1678 Decimal('3.1416')
1679 )
1680 context = Context(prec=5, traps=[Inexact])
1681 self.assertRaises(
1682 Inexact,
1683 context.create_decimal_from_float,
1684 math.pi
1685 )
1686 self.assertEqual(repr(context.create_decimal_from_float(-0.0)),
1687 "Decimal('-0')")
1688 self.assertEqual(repr(context.create_decimal_from_float(1.0)),
1689 "Decimal('1')")
1690 self.assertEqual(repr(context.create_decimal_from_float(10)),
1691 "Decimal('10')")
1692
Raymond Hettingerd9c0a7a2004-07-03 10:02:28 +00001693class ContextAPItests(unittest.TestCase):
1694
1695 def test_pickle(self):
1696 c = Context()
1697 e = pickle.loads(pickle.dumps(c))
1698 for k in vars(c):
1699 v1 = vars(c)[k]
1700 v2 = vars(e)[k]
1701 self.assertEqual(v1, v2)
1702
Raymond Hettinger0aeac102004-07-05 22:53:03 +00001703 def test_equality_with_other_types(self):
Georg Brandlab91fde2009-08-13 08:51:18 +00001704 self.assertTrue(Decimal(10) in ['a', 1.0, Decimal(10), (1,2), {}])
1705 self.assertTrue(Decimal(10) not in ['a', 1.0, (1,2), {}])
Raymond Hettinger0aeac102004-07-05 22:53:03 +00001706
Raymond Hettinger955d2b22004-08-08 20:17:45 +00001707 def test_copy(self):
1708 # All copies should be deep
1709 c = Context()
1710 d = c.copy()
1711 self.assertNotEqual(id(c), id(d))
1712 self.assertNotEqual(id(c.flags), id(d.flags))
1713 self.assertNotEqual(id(c.traps), id(d.traps))
1714
Thomas Wouters89f507f2006-12-13 04:49:30 +00001715class WithStatementTest(unittest.TestCase):
1716 # Can't do these as docstrings until Python 2.6
1717 # as doctest can't handle __future__ statements
1718
1719 def test_localcontext(self):
1720 # Use a copy of the current context in the block
1721 orig_ctx = getcontext()
1722 with localcontext() as enter_ctx:
1723 set_ctx = getcontext()
1724 final_ctx = getcontext()
Georg Brandlab91fde2009-08-13 08:51:18 +00001725 self.assertTrue(orig_ctx is final_ctx, 'did not restore context correctly')
1726 self.assertTrue(orig_ctx is not set_ctx, 'did not copy the context')
1727 self.assertTrue(set_ctx is enter_ctx, '__enter__ returned wrong context')
Thomas Wouters89f507f2006-12-13 04:49:30 +00001728
1729 def test_localcontextarg(self):
1730 # Use a copy of the supplied context in the block
1731 orig_ctx = getcontext()
1732 new_ctx = Context(prec=42)
1733 with localcontext(new_ctx) as enter_ctx:
1734 set_ctx = getcontext()
1735 final_ctx = getcontext()
Georg Brandlab91fde2009-08-13 08:51:18 +00001736 self.assertTrue(orig_ctx is final_ctx, 'did not restore context correctly')
1737 self.assertTrue(set_ctx.prec == new_ctx.prec, 'did not set correct context')
1738 self.assertTrue(new_ctx is not set_ctx, 'did not copy the context')
1739 self.assertTrue(set_ctx is enter_ctx, '__enter__ returned wrong context')
Thomas Wouters89f507f2006-12-13 04:49:30 +00001740
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001741class ContextFlags(unittest.TestCase):
1742 def test_flags_irrelevant(self):
1743 # check that the result (numeric result + flags raised) of an
1744 # arithmetic operation doesn't depend on the current flags
1745
1746 context = Context(prec=9, Emin = -999999999, Emax = 999999999,
1747 rounding=ROUND_HALF_EVEN, traps=[], flags=[])
1748
1749 # operations that raise various flags, in the form (function, arglist)
1750 operations = [
1751 (context._apply, [Decimal("100E-1000000009")]),
1752 (context.sqrt, [Decimal(2)]),
1753 (context.add, [Decimal("1.23456789"), Decimal("9.87654321")]),
1754 (context.multiply, [Decimal("1.23456789"), Decimal("9.87654321")]),
1755 (context.subtract, [Decimal("1.23456789"), Decimal("9.87654321")]),
1756 ]
1757
1758 # try various flags individually, then a whole lot at once
1759 flagsets = [[Inexact], [Rounded], [Underflow], [Clamped], [Subnormal],
1760 [Inexact, Rounded, Underflow, Clamped, Subnormal]]
1761
1762 for fn, args in operations:
1763 # find answer and flags raised using a clean context
1764 context.clear_flags()
1765 ans = fn(*args)
1766 flags = [k for k, v in context.flags.items() if v]
1767
1768 for extra_flags in flagsets:
1769 # set flags, before calling operation
1770 context.clear_flags()
1771 for flag in extra_flags:
1772 context._raise_error(flag)
1773 new_ans = fn(*args)
1774
1775 # flags that we expect to be set after the operation
1776 expected_flags = list(flags)
1777 for flag in extra_flags:
1778 if flag not in expected_flags:
1779 expected_flags.append(flag)
1780 expected_flags.sort(key=id)
1781
1782 # flags we actually got
1783 new_flags = [k for k,v in context.flags.items() if v]
1784 new_flags.sort(key=id)
1785
1786 self.assertEqual(ans, new_ans,
1787 "operation produces different answers depending on flags set: " +
1788 "expected %s, got %s." % (ans, new_ans))
1789 self.assertEqual(new_flags, expected_flags,
1790 "operation raises different flags depending on flags set: " +
1791 "expected %s, got %s" % (expected_flags, new_flags))
1792
1793def test_main(arith=False, verbose=None, todo_tests=None, debug=None):
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001794 """ Execute the tests.
1795
Raymond Hettingered20ad82004-09-04 20:09:13 +00001796 Runs all arithmetic tests if arith is True or if the "decimal" resource
1797 is enabled in regrtest.py
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001798 """
Raymond Hettingered20ad82004-09-04 20:09:13 +00001799
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00001800 init()
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001801 global TEST_ALL, DEBUG
Raymond Hettingered20ad82004-09-04 20:09:13 +00001802 TEST_ALL = arith or is_resource_enabled('decimal')
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001803 DEBUG = debug
Raymond Hettingered20ad82004-09-04 20:09:13 +00001804
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001805 if todo_tests is None:
1806 test_classes = [
1807 DecimalExplicitConstructionTest,
1808 DecimalImplicitConstructionTest,
1809 DecimalArithmeticOperatorsTest,
Christian Heimesf16baeb2008-02-29 14:57:44 +00001810 DecimalFormatTest,
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001811 DecimalUseOfContextTest,
1812 DecimalUsabilityTest,
1813 DecimalPythonAPItests,
1814 ContextAPItests,
1815 DecimalTest,
1816 WithStatementTest,
1817 ContextFlags
1818 ]
1819 else:
1820 test_classes = [DecimalTest]
1821
1822 # Dynamically build custom test definition for each file in the test
1823 # directory and add the definitions to the DecimalTest class. This
1824 # procedure insures that new files do not get skipped.
1825 for filename in os.listdir(directory):
1826 if '.decTest' not in filename or filename.startswith("."):
1827 continue
1828 head, tail = filename.split('.')
1829 if todo_tests is not None and head not in todo_tests:
1830 continue
1831 tester = lambda self, f=filename: self.eval_file(directory + f)
1832 setattr(DecimalTest, 'test_' + head, tester)
1833 del filename, head, tail, tester
1834
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001835
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00001836 try:
1837 run_unittest(*test_classes)
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001838 if todo_tests is None:
1839 import decimal as DecimalModule
1840 run_doctest(DecimalModule, verbose)
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00001841 finally:
1842 setcontext(ORIGINAL_CONTEXT)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001843
1844if __name__ == '__main__':
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001845 import optparse
1846 p = optparse.OptionParser("test_decimal.py [--debug] [{--skip | test1 [test2 [...]]}]")
1847 p.add_option('--debug', '-d', action='store_true', help='shows the test number and context before each test')
1848 p.add_option('--skip', '-s', action='store_true', help='skip over 90% of the arithmetic tests')
1849 (opt, args) = p.parse_args()
1850
1851 if opt.skip:
1852 test_main(arith=False, verbose=True)
1853 elif args:
1854 test_main(arith=True, verbose=True, todo_tests=args, debug=opt.debug)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001855 else:
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001856 test_main(arith=True, verbose=True)