blob: 43f2a08e672d4bd60f9c1358b903165ebac52d06 [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
Thomas Wouters49fd7fa2006-04-21 10:40:58 +000044# Tests are built around these assumed context defaults.
45# test_main() restores the original context.
46def init():
47 global ORIGINAL_CONTEXT
48 ORIGINAL_CONTEXT = getcontext().copy()
Christian Heimes81ee3ef2008-05-04 22:42:01 +000049 DefaultTestContext = Context(
50 prec = 9,
51 rounding = ROUND_HALF_EVEN,
52 traps = dict.fromkeys(Signals, 0)
53 )
54 setcontext(DefaultTestContext)
Raymond Hettinger6ea48452004-07-03 12:26:21 +000055
Raymond Hettinger7c85fa42004-07-01 11:01:35 +000056TESTDATADIR = 'decimaltestdata'
Raymond Hettingerd9c0a7a2004-07-03 10:02:28 +000057if __name__ == '__main__':
58 file = sys.argv[0]
59else:
60 file = __file__
61testdir = os.path.dirname(file) or os.curdir
Raymond Hettinger267b8682005-03-27 10:47:39 +000062directory = testdir + os.sep + TESTDATADIR + os.sep
Raymond Hettinger7c85fa42004-07-01 11:01:35 +000063
Raymond Hettinger267b8682005-03-27 10:47:39 +000064skip_expected = not os.path.isdir(directory)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +000065
66# Make sure it actually raises errors when not expected and caught in flags
67# Slower, since it runs some things several times.
68EXTENDEDERRORTEST = False
69
Raymond Hettinger7c85fa42004-07-01 11:01:35 +000070#Map the test cases' error names to the actual errors
Raymond Hettinger7c85fa42004-07-01 11:01:35 +000071ErrorNames = {'clamped' : Clamped,
Raymond Hettinger5aa478b2004-07-09 10:02:53 +000072 'conversion_syntax' : InvalidOperation,
Raymond Hettinger7c85fa42004-07-01 11:01:35 +000073 'division_by_zero' : DivisionByZero,
Raymond Hettinger5aa478b2004-07-09 10:02:53 +000074 'division_impossible' : InvalidOperation,
75 'division_undefined' : InvalidOperation,
Raymond Hettinger7c85fa42004-07-01 11:01:35 +000076 'inexact' : Inexact,
Raymond Hettinger5aa478b2004-07-09 10:02:53 +000077 'invalid_context' : InvalidOperation,
Raymond Hettinger7c85fa42004-07-01 11:01:35 +000078 'invalid_operation' : InvalidOperation,
79 'overflow' : Overflow,
80 'rounded' : Rounded,
81 'subnormal' : Subnormal,
82 'underflow' : Underflow}
83
84
85def Nonfunction(*args):
86 """Doesn't do anything."""
87 return None
88
89RoundingDict = {'ceiling' : ROUND_CEILING, #Maps test-case names to roundings.
90 'down' : ROUND_DOWN,
91 'floor' : ROUND_FLOOR,
92 'half_down' : ROUND_HALF_DOWN,
93 'half_even' : ROUND_HALF_EVEN,
94 'half_up' : ROUND_HALF_UP,
Thomas Wouters1b7f8912007-09-19 03:06:30 +000095 'up' : ROUND_UP,
96 '05up' : ROUND_05UP}
Raymond Hettinger7c85fa42004-07-01 11:01:35 +000097
98# Name adapter to be able to change the Decimal and Context
99# interface without changing the test files from Cowlishaw
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000100nameAdapter = {'and':'logical_and',
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000101 'apply':'_apply',
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000102 'class':'number_class',
103 'comparesig':'compare_signal',
104 'comparetotal':'compare_total',
105 'comparetotmag':'compare_total_mag',
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000106 'copy':'copy_decimal',
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000107 'copyabs':'copy_abs',
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000108 'copynegate':'copy_negate',
109 'copysign':'copy_sign',
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000110 'divideint':'divide_int',
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000111 'invert':'logical_invert',
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000112 'iscanonical':'is_canonical',
113 'isfinite':'is_finite',
114 'isinfinite':'is_infinite',
115 'isnan':'is_nan',
116 'isnormal':'is_normal',
117 'isqnan':'is_qnan',
118 'issigned':'is_signed',
119 'issnan':'is_snan',
120 'issubnormal':'is_subnormal',
121 'iszero':'is_zero',
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000122 'maxmag':'max_mag',
123 'minmag':'min_mag',
124 'nextminus':'next_minus',
125 'nextplus':'next_plus',
126 'nexttoward':'next_toward',
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000127 'or':'logical_or',
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000128 'reduce':'normalize',
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000129 'remaindernear':'remainder_near',
130 'samequantum':'same_quantum',
131 'squareroot':'sqrt',
132 'toeng':'to_eng_string',
133 'tointegral':'to_integral_value',
134 'tointegralx':'to_integral_exact',
135 'tosci':'to_sci_string',
136 'xor':'logical_xor',
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000137 }
138
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000139# The following functions return True/False rather than a Decimal instance
140
141LOGICAL_FUNCTIONS = (
142 'is_canonical',
143 'is_finite',
144 'is_infinite',
145 'is_nan',
146 'is_normal',
147 'is_qnan',
148 'is_signed',
149 'is_snan',
150 'is_subnormal',
151 'is_zero',
152 'same_quantum',
153 )
154
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000155# For some operations (currently exp, ln, log10, power), the decNumber
156# reference implementation imposes additional restrictions on the
157# context and operands. These restrictions are not part of the
158# specification; however, the effect of these restrictions does show
159# up in some of the testcases. We skip testcases that violate these
160# restrictions, since Decimal behaves differently from decNumber for
161# these testcases so these testcases would otherwise fail.
162
163decNumberRestricted = ('power', 'ln', 'log10', 'exp')
164DEC_MAX_MATH = 999999
165def outside_decNumber_bounds(v, context):
166 if (context.prec > DEC_MAX_MATH or
167 context.Emax > DEC_MAX_MATH or
168 -context.Emin > DEC_MAX_MATH):
169 return True
170 if not v._is_special and v and (
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000171 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 Hettinger7c85fa42004-07-01 11:01:35 +0000183 self.ignore_list = ['#']
184 # Basically, a # means return NaN InvalidOperation.
185 # Different from a sNaN in trim
186
187 self.ChangeDict = {'precision' : self.change_precision,
188 'rounding' : self.change_rounding_method,
189 'maxexponent' : self.change_max_exponent,
190 'minexponent' : self.change_min_exponent,
191 'clamp' : self.change_clamp}
192
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000193 def eval_file(self, file):
194 global skip_expected
195 if skip_expected:
Benjamin Petersone549ead2009-03-28 21:42:05 +0000196 raise unittest.SkipTest
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000197 return
Neal Norwitz70967602006-03-17 08:29:44 +0000198 for line in open(file):
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000199 line = line.replace('\r\n', '').replace('\n', '')
Raymond Hettinger5aa478b2004-07-09 10:02:53 +0000200 #print line
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000201 try:
202 t = self.eval_line(line)
Guido van Rossumb940e112007-01-10 16:19:56 +0000203 except DecimalException as exception:
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000204 #Exception raised where there shoudn't have been one.
205 self.fail('Exception "'+exception.__class__.__name__ + '" raised on line '+line)
206
207 return
208
209 def eval_line(self, s):
210 if s.find(' -> ') >= 0 and s[:2] != '--' and not s.startswith(' --'):
211 s = (s.split('->')[0] + '->' +
212 s.split('->')[1].split('--')[0]).strip()
213 else:
214 s = s.split('--')[0].strip()
215
216 for ignore in self.ignore_list:
217 if s.find(ignore) >= 0:
218 #print s.split()[0], 'NotImplemented--', ignore
219 return
220 if not s:
221 return
222 elif ':' in s:
223 return self.eval_directive(s)
224 else:
225 return self.eval_equation(s)
226
227 def eval_directive(self, s):
Guido van Rossumc1f779c2007-07-03 08:25:58 +0000228 funct, value = (x.strip().lower() for x in s.split(':'))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000229 if funct == 'rounding':
230 value = RoundingDict[value]
231 else:
232 try:
233 value = int(value)
234 except ValueError:
235 pass
236
237 funct = self.ChangeDict.get(funct, Nonfunction)
238 funct(value)
239
240 def eval_equation(self, s):
241 #global DEFAULT_PRECISION
242 #print DEFAULT_PRECISION
Raymond Hettingered20ad82004-09-04 20:09:13 +0000243
244 if not TEST_ALL and random.random() < 0.90:
245 return
246
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000247 try:
248 Sides = s.split('->')
249 L = Sides[0].strip().split()
250 id = L[0]
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000251 if DEBUG:
252 print("Test ", id, end=" ")
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000253 funct = L[1].lower()
254 valstemp = L[2:]
255 L = Sides[1].strip().split()
256 ans = L[0]
257 exceptions = L[1:]
258 except (TypeError, AttributeError, IndexError):
Raymond Hettingerd87ac8f2004-07-09 10:52:54 +0000259 raise InvalidOperation
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000260 def FixQuotes(val):
261 val = val.replace("''", 'SingleQuote').replace('""', 'DoubleQuote')
262 val = val.replace("'", '').replace('"', '')
263 val = val.replace('SingleQuote', "'").replace('DoubleQuote', '"')
264 return val
265 fname = nameAdapter.get(funct, funct)
266 if fname == 'rescale':
267 return
268 funct = getattr(self.context, fname)
269 vals = []
270 conglomerate = ''
271 quote = 0
272 theirexceptions = [ErrorNames[x.lower()] for x in exceptions]
273
Raymond Hettingerd9c0a7a2004-07-03 10:02:28 +0000274 for exception in Signals:
Raymond Hettingerbf440692004-07-10 14:14:37 +0000275 self.context.traps[exception] = 1 #Catch these bugs...
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000276 for exception in theirexceptions:
Raymond Hettingerbf440692004-07-10 14:14:37 +0000277 self.context.traps[exception] = 0
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000278 for i, val in enumerate(valstemp):
279 if val.count("'") % 2 == 1:
280 quote = 1 - quote
281 if quote:
282 conglomerate = conglomerate + ' ' + val
283 continue
284 else:
285 val = conglomerate + val
286 conglomerate = ''
287 v = FixQuotes(val)
288 if fname in ('to_sci_string', 'to_eng_string'):
289 if EXTENDEDERRORTEST:
290 for error in theirexceptions:
Raymond Hettingerbf440692004-07-10 14:14:37 +0000291 self.context.traps[error] = 1
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000292 try:
293 funct(self.context.create_decimal(v))
294 except error:
295 pass
Guido van Rossumb940e112007-01-10 16:19:56 +0000296 except Signals as e:
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000297 self.fail("Raised %s in %s when %s disabled" % \
298 (e, s, error))
299 else:
300 self.fail("Did not raise %s in %s" % (error, s))
Raymond Hettingerbf440692004-07-10 14:14:37 +0000301 self.context.traps[error] = 0
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000302 v = self.context.create_decimal(v)
303 else:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000304 v = Decimal(v, self.context)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000305 vals.append(v)
306
307 ans = FixQuotes(ans)
308
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000309 # skip tests that are related to bounds imposed in the decNumber
310 # reference implementation
311 if fname in decNumberRestricted:
312 if fname == 'power':
313 if not (vals[1]._isinteger() and
314 -1999999997 <= vals[1] <= 999999999):
315 if outside_decNumber_bounds(vals[0], self.context) or \
316 outside_decNumber_bounds(vals[1], self.context):
317 #print "Skipping test %s" % s
318 return
319 else:
320 if outside_decNumber_bounds(vals[0], self.context):
321 #print "Skipping test %s" % s
322 return
323
324
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000325 if EXTENDEDERRORTEST and fname not in ('to_sci_string', 'to_eng_string'):
326 for error in theirexceptions:
Raymond Hettingerbf440692004-07-10 14:14:37 +0000327 self.context.traps[error] = 1
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000328 try:
329 funct(*vals)
330 except error:
331 pass
Guido van Rossumb940e112007-01-10 16:19:56 +0000332 except Signals as e:
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000333 self.fail("Raised %s in %s when %s disabled" % \
334 (e, s, error))
335 else:
336 self.fail("Did not raise %s in %s" % (error, s))
Raymond Hettingerbf440692004-07-10 14:14:37 +0000337 self.context.traps[error] = 0
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000338 if DEBUG:
339 print("--", self.context)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000340 try:
341 result = str(funct(*vals))
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000342 if fname in LOGICAL_FUNCTIONS:
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000343 result = str(int(eval(result))) # 'True', 'False' -> '1', '0'
Guido van Rossumb940e112007-01-10 16:19:56 +0000344 except Signals as error:
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000345 self.fail("Raised %s in %s" % (error, s))
346 except: #Catch any error long enough to state the test case.
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000347 print("ERROR:", s)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000348 raise
349
350 myexceptions = self.getexceptions()
Raymond Hettingerbf440692004-07-10 14:14:37 +0000351 self.context.clear_flags()
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000352
Guido van Rossum47b9ff62006-08-24 00:41:19 +0000353 myexceptions.sort(key=repr)
354 theirexceptions.sort(key=repr)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000355
356 self.assertEqual(result, ans,
357 'Incorrect answer for ' + s + ' -- got ' + result)
358 self.assertEqual(myexceptions, theirexceptions,
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000359 'Incorrect flags set in ' + s + ' -- got ' + str(myexceptions))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000360 return
361
362 def getexceptions(self):
Raymond Hettingerf63ba432004-08-17 05:42:09 +0000363 return [e for e in Signals if self.context.flags[e]]
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000364
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000365 def change_precision(self, prec):
366 self.context.prec = prec
367 def change_rounding_method(self, rounding):
368 self.context.rounding = rounding
369 def change_min_exponent(self, exp):
370 self.context.Emin = exp
371 def change_max_exponent(self, exp):
372 self.context.Emax = exp
373 def change_clamp(self, clamp):
374 self.context._clamp = clamp
375
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000376
377
378# The following classes test the behaviour of Decimal according to PEP 327
379
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000380class DecimalExplicitConstructionTest(unittest.TestCase):
381 '''Unit tests for Explicit Construction cases of Decimal.'''
382
383 def test_explicit_empty(self):
384 self.assertEqual(Decimal(), Decimal("0"))
385
386 def test_explicit_from_None(self):
387 self.assertRaises(TypeError, Decimal, None)
388
389 def test_explicit_from_int(self):
390
391 #positive
392 d = Decimal(45)
393 self.assertEqual(str(d), '45')
394
395 #very large positive
396 d = Decimal(500000123)
397 self.assertEqual(str(d), '500000123')
398
399 #negative
400 d = Decimal(-45)
401 self.assertEqual(str(d), '-45')
402
403 #zero
404 d = Decimal(0)
405 self.assertEqual(str(d), '0')
406
407 def test_explicit_from_string(self):
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000408
409 #empty
410 self.assertEqual(str(Decimal('')), 'NaN')
411
412 #int
413 self.assertEqual(str(Decimal('45')), '45')
414
415 #float
416 self.assertEqual(str(Decimal('45.34')), '45.34')
417
418 #engineer notation
419 self.assertEqual(str(Decimal('45e2')), '4.5E+3')
420
421 #just not a number
422 self.assertEqual(str(Decimal('ugly')), 'NaN')
423
Christian Heimesa62da1d2008-01-12 19:39:10 +0000424 #leading and trailing whitespace permitted
425 self.assertEqual(str(Decimal('1.3E4 \n')), '1.3E+4')
426 self.assertEqual(str(Decimal(' -7.89')), '-7.89')
427
Benjamin Peterson41181742008-07-02 20:22:54 +0000428 #but alternate unicode digits should not
429 self.assertEqual(str(Decimal('\uff11')), 'NaN')
430
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000431 def test_explicit_from_tuples(self):
432
433 #zero
434 d = Decimal( (0, (0,), 0) )
435 self.assertEqual(str(d), '0')
436
437 #int
438 d = Decimal( (1, (4, 5), 0) )
439 self.assertEqual(str(d), '-45')
440
441 #float
442 d = Decimal( (0, (4, 5, 3, 4), -2) )
443 self.assertEqual(str(d), '45.34')
444
445 #weird
446 d = Decimal( (1, (4, 3, 4, 9, 1, 3, 5, 3, 4), -25) )
447 self.assertEqual(str(d), '-4.34913534E-17')
448
449 #wrong number of items
450 self.assertRaises(ValueError, Decimal, (1, (4, 3, 4, 9, 1)) )
451
452 #bad sign
453 self.assertRaises(ValueError, Decimal, (8, (4, 3, 4, 9, 1), 2) )
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000454 self.assertRaises(ValueError, Decimal, (0., (4, 3, 4, 9, 1), 2) )
455 self.assertRaises(ValueError, Decimal, (Decimal(1), (4, 3, 4, 9, 1), 2))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000456
457 #bad exp
458 self.assertRaises(ValueError, Decimal, (1, (4, 3, 4, 9, 1), 'wrong!') )
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000459 self.assertRaises(ValueError, Decimal, (1, (4, 3, 4, 9, 1), 0.) )
460 self.assertRaises(ValueError, Decimal, (1, (4, 3, 4, 9, 1), '1') )
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000461
462 #bad coefficients
463 self.assertRaises(ValueError, Decimal, (1, (4, 3, 4, None, 1), 2) )
464 self.assertRaises(ValueError, Decimal, (1, (4, -3, 4, 9, 1), 2) )
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000465 self.assertRaises(ValueError, Decimal, (1, (4, 10, 4, 9, 1), 2) )
Guido van Rossum0d3fb8a2007-11-26 23:23:18 +0000466 self.assertRaises(ValueError, Decimal, (1, (4, 3, 4, 'a', 1), 2) )
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000467
468 def test_explicit_from_Decimal(self):
469
470 #positive
471 d = Decimal(45)
472 e = Decimal(d)
473 self.assertEqual(str(e), '45')
474 self.assertNotEqual(id(d), id(e))
475
476 #very large positive
477 d = Decimal(500000123)
478 e = Decimal(d)
479 self.assertEqual(str(e), '500000123')
480 self.assertNotEqual(id(d), id(e))
481
482 #negative
483 d = Decimal(-45)
484 e = Decimal(d)
485 self.assertEqual(str(e), '-45')
486 self.assertNotEqual(id(d), id(e))
487
488 #zero
489 d = Decimal(0)
490 e = Decimal(d)
491 self.assertEqual(str(e), '0')
492 self.assertNotEqual(id(d), id(e))
493
494 def test_explicit_context_create_decimal(self):
495
496 nc = copy.copy(getcontext())
497 nc.prec = 3
498
499 # empty
Raymond Hettingerfed52962004-07-14 15:41:57 +0000500 d = Decimal()
501 self.assertEqual(str(d), '0')
502 d = nc.create_decimal()
503 self.assertEqual(str(d), '0')
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000504
505 # from None
506 self.assertRaises(TypeError, nc.create_decimal, None)
507
508 # from int
509 d = nc.create_decimal(456)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000510 self.assertTrue(isinstance(d, Decimal))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000511 self.assertEqual(nc.create_decimal(45678),
512 nc.create_decimal('457E+2'))
513
514 # from string
515 d = Decimal('456789')
516 self.assertEqual(str(d), '456789')
517 d = nc.create_decimal('456789')
518 self.assertEqual(str(d), '4.57E+5')
Christian Heimesa62da1d2008-01-12 19:39:10 +0000519 # leading and trailing whitespace should result in a NaN;
520 # spaces are already checked in Cowlishaw's test-suite, so
521 # here we just check that a trailing newline results in a NaN
522 self.assertEqual(str(nc.create_decimal('3.14\n')), 'NaN')
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000523
524 # from tuples
525 d = Decimal( (1, (4, 3, 4, 9, 1, 3, 5, 3, 4), -25) )
526 self.assertEqual(str(d), '-4.34913534E-17')
527 d = nc.create_decimal( (1, (4, 3, 4, 9, 1, 3, 5, 3, 4), -25) )
528 self.assertEqual(str(d), '-4.35E-17')
529
530 # from Decimal
531 prevdec = Decimal(500000123)
532 d = Decimal(prevdec)
533 self.assertEqual(str(d), '500000123')
534 d = nc.create_decimal(prevdec)
535 self.assertEqual(str(d), '5.00E+8')
536
537
538class DecimalImplicitConstructionTest(unittest.TestCase):
539 '''Unit tests for Implicit Construction cases of Decimal.'''
540
541 def test_implicit_from_None(self):
542 self.assertRaises(TypeError, eval, 'Decimal(5) + None', globals())
543
544 def test_implicit_from_int(self):
545 #normal
546 self.assertEqual(str(Decimal(5) + 45), '50')
547 #exceeding precision
548 self.assertEqual(Decimal(5) + 123456789000, Decimal(123456789000))
549
550 def test_implicit_from_string(self):
551 self.assertRaises(TypeError, eval, 'Decimal(5) + "3"', globals())
552
553 def test_implicit_from_float(self):
554 self.assertRaises(TypeError, eval, 'Decimal(5) + 2.2', globals())
555
556 def test_implicit_from_Decimal(self):
557 self.assertEqual(Decimal(5) + Decimal(45), Decimal(50))
558
Raymond Hettinger267b8682005-03-27 10:47:39 +0000559 def test_rop(self):
560 # Allow other classes to be trained to interact with Decimals
561 class E:
562 def __divmod__(self, other):
563 return 'divmod ' + str(other)
564 def __rdivmod__(self, other):
565 return str(other) + ' rdivmod'
566 def __lt__(self, other):
567 return 'lt ' + str(other)
568 def __gt__(self, other):
569 return 'gt ' + str(other)
570 def __le__(self, other):
571 return 'le ' + str(other)
572 def __ge__(self, other):
573 return 'ge ' + str(other)
574 def __eq__(self, other):
575 return 'eq ' + str(other)
576 def __ne__(self, other):
577 return 'ne ' + str(other)
578
579 self.assertEqual(divmod(E(), Decimal(10)), 'divmod 10')
580 self.assertEqual(divmod(Decimal(10), E()), '10 rdivmod')
581 self.assertEqual(eval('Decimal(10) < E()'), 'gt 10')
582 self.assertEqual(eval('Decimal(10) > E()'), 'lt 10')
583 self.assertEqual(eval('Decimal(10) <= E()'), 'ge 10')
584 self.assertEqual(eval('Decimal(10) >= E()'), 'le 10')
585 self.assertEqual(eval('Decimal(10) == E()'), 'eq 10')
586 self.assertEqual(eval('Decimal(10) != E()'), 'ne 10')
587
588 # insert operator methods and then exercise them
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000589 oplist = [
590 ('+', '__add__', '__radd__'),
591 ('-', '__sub__', '__rsub__'),
592 ('*', '__mul__', '__rmul__'),
Thomas Woutersdcc6d322006-04-21 11:30:52 +0000593 ('/', '__truediv__', '__rtruediv__'),
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000594 ('%', '__mod__', '__rmod__'),
595 ('//', '__floordiv__', '__rfloordiv__'),
596 ('**', '__pow__', '__rpow__')
597 ]
Raymond Hettinger267b8682005-03-27 10:47:39 +0000598
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000599 for sym, lop, rop in oplist:
Raymond Hettinger267b8682005-03-27 10:47:39 +0000600 setattr(E, lop, lambda self, other: 'str' + lop + str(other))
601 setattr(E, rop, lambda self, other: str(other) + rop + 'str')
602 self.assertEqual(eval('E()' + sym + 'Decimal(10)'),
603 'str' + lop + '10')
604 self.assertEqual(eval('Decimal(10)' + sym + 'E()'),
605 '10' + rop + 'str')
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000606
Mark Dickinson79f52032009-03-17 23:12:51 +0000607
Christian Heimesf16baeb2008-02-29 14:57:44 +0000608class DecimalFormatTest(unittest.TestCase):
609 '''Unit tests for the format function.'''
610 def test_formatting(self):
611 # triples giving a format, a Decimal, and the expected result
612 test_values = [
613 ('e', '0E-15', '0e-15'),
614 ('e', '2.3E-15', '2.3e-15'),
615 ('e', '2.30E+2', '2.30e+2'), # preserve significant zeros
616 ('e', '2.30000E-15', '2.30000e-15'),
617 ('e', '1.23456789123456789e40', '1.23456789123456789e+40'),
618 ('e', '1.5', '1.5e+0'),
619 ('e', '0.15', '1.5e-1'),
620 ('e', '0.015', '1.5e-2'),
621 ('e', '0.0000000000015', '1.5e-12'),
622 ('e', '15.0', '1.50e+1'),
623 ('e', '-15', '-1.5e+1'),
624 ('e', '0', '0e+0'),
625 ('e', '0E1', '0e+1'),
626 ('e', '0.0', '0e-1'),
627 ('e', '0.00', '0e-2'),
628 ('.6e', '0E-15', '0.000000e-9'),
629 ('.6e', '0', '0.000000e+6'),
630 ('.6e', '9.999999', '9.999999e+0'),
631 ('.6e', '9.9999999', '1.000000e+1'),
632 ('.6e', '-1.23e5', '-1.230000e+5'),
633 ('.6e', '1.23456789e-3', '1.234568e-3'),
634 ('f', '0', '0'),
635 ('f', '0.0', '0.0'),
636 ('f', '0E-2', '0.00'),
637 ('f', '0.00E-8', '0.0000000000'),
638 ('f', '0E1', '0'), # loses exponent information
639 ('f', '3.2E1', '32'),
640 ('f', '3.2E2', '320'),
641 ('f', '3.20E2', '320'),
642 ('f', '3.200E2', '320.0'),
643 ('f', '3.2E-6', '0.0000032'),
644 ('.6f', '0E-15', '0.000000'), # all zeros treated equally
645 ('.6f', '0E1', '0.000000'),
646 ('.6f', '0', '0.000000'),
647 ('.0f', '0', '0'), # no decimal point
648 ('.0f', '0e-2', '0'),
649 ('.0f', '3.14159265', '3'),
650 ('.1f', '3.14159265', '3.1'),
651 ('.4f', '3.14159265', '3.1416'),
652 ('.6f', '3.14159265', '3.141593'),
653 ('.7f', '3.14159265', '3.1415926'), # round-half-even!
654 ('.8f', '3.14159265', '3.14159265'),
655 ('.9f', '3.14159265', '3.141592650'),
656
657 ('g', '0', '0'),
658 ('g', '0.0', '0.0'),
659 ('g', '0E1', '0e+1'),
660 ('G', '0E1', '0E+1'),
661 ('g', '0E-5', '0.00000'),
662 ('g', '0E-6', '0.000000'),
663 ('g', '0E-7', '0e-7'),
664 ('g', '-0E2', '-0e+2'),
665 ('.0g', '3.14159265', '3'), # 0 sig fig -> 1 sig fig
666 ('.1g', '3.14159265', '3'),
667 ('.2g', '3.14159265', '3.1'),
668 ('.5g', '3.14159265', '3.1416'),
669 ('.7g', '3.14159265', '3.141593'),
670 ('.8g', '3.14159265', '3.1415926'), # round-half-even!
671 ('.9g', '3.14159265', '3.14159265'),
672 ('.10g', '3.14159265', '3.14159265'), # don't pad
673
674 ('%', '0E1', '0%'),
675 ('%', '0E0', '0%'),
676 ('%', '0E-1', '0%'),
677 ('%', '0E-2', '0%'),
678 ('%', '0E-3', '0.0%'),
679 ('%', '0E-4', '0.00%'),
680
681 ('.3%', '0', '0.000%'), # all zeros treated equally
682 ('.3%', '0E10', '0.000%'),
683 ('.3%', '0E-10', '0.000%'),
684 ('.3%', '2.34', '234.000%'),
685 ('.3%', '1.234567', '123.457%'),
686 ('.0%', '1.23', '123%'),
687
688 ('e', 'NaN', 'NaN'),
689 ('f', '-NaN123', '-NaN123'),
690 ('+g', 'NaN456', '+NaN456'),
691 ('.3e', 'Inf', 'Infinity'),
692 ('.16f', '-Inf', '-Infinity'),
693 ('.0g', '-sNaN', '-sNaN'),
694
695 ('', '1.00', '1.00'),
Mark Dickinsonad416342009-03-17 18:10:15 +0000696
Mark Dickinson79f52032009-03-17 23:12:51 +0000697 # test alignment and padding
Mark Dickinsonad416342009-03-17 18:10:15 +0000698 ('<6', '123', '123 '),
699 ('>6', '123', ' 123'),
700 ('^6', '123', ' 123 '),
701 ('=+6', '123', '+ 123'),
Mark Dickinson79f52032009-03-17 23:12:51 +0000702 ('#<10', 'NaN', 'NaN#######'),
703 ('#<10', '-4.3', '-4.3######'),
704 ('#<+10', '0.0130', '+0.0130###'),
705 ('#< 10', '0.0130', ' 0.0130###'),
706 ('@>10', '-Inf', '@-Infinity'),
707 ('#>5', '-Inf', '-Infinity'),
708 ('?^5', '123', '?123?'),
709 ('%^6', '123', '%123%%'),
710 (' ^6', '-45.6', '-45.6 '),
711 ('/=10', '-45.6', '-/////45.6'),
712 ('/=+10', '45.6', '+/////45.6'),
713 ('/= 10', '45.6', ' /////45.6'),
714
715 # thousands separator
716 (',', '1234567', '1,234,567'),
717 (',', '123456', '123,456'),
718 (',', '12345', '12,345'),
719 (',', '1234', '1,234'),
720 (',', '123', '123'),
721 (',', '12', '12'),
722 (',', '1', '1'),
723 (',', '0', '0'),
724 (',', '-1234567', '-1,234,567'),
725 (',', '-123456', '-123,456'),
726 ('7,', '123456', '123,456'),
727 ('8,', '123456', '123,456 '),
728 ('08,', '123456', '0,123,456'), # special case: extra 0 needed
729 ('+08,', '123456', '+123,456'), # but not if there's a sign
730 (' 08,', '123456', ' 123,456'),
731 ('08,', '-123456', '-123,456'),
732 ('+09,', '123456', '+0,123,456'),
733 # ... with fractional part...
734 ('07,', '1234.56', '1,234.56'),
735 ('08,', '1234.56', '1,234.56'),
736 ('09,', '1234.56', '01,234.56'),
737 ('010,', '1234.56', '001,234.56'),
738 ('011,', '1234.56', '0,001,234.56'),
739 ('012,', '1234.56', '0,001,234.56'),
740 ('08,.1f', '1234.5', '01,234.5'),
741 # no thousands separators in fraction part
742 (',', '1.23456789', '1.23456789'),
743 (',%', '123.456789', '12,345.6789%'),
744 (',e', '123456', '1.23456e+5'),
745 (',E', '123456', '1.23456E+5'),
Christian Heimesf16baeb2008-02-29 14:57:44 +0000746 ]
747 for fmt, d, result in test_values:
748 self.assertEqual(format(Decimal(d), fmt), result)
749
Mark Dickinson79f52032009-03-17 23:12:51 +0000750 def test_n_format(self):
751 try:
752 from locale import CHAR_MAX
753 except ImportError:
754 return
755
756 # Set up some localeconv-like dictionaries
757 en_US = {
758 'decimal_point' : '.',
759 'grouping' : [3, 3, 0],
760 'thousands_sep': ','
761 }
762
763 fr_FR = {
764 'decimal_point' : ',',
765 'grouping' : [CHAR_MAX],
766 'thousands_sep' : ''
767 }
768
769 ru_RU = {
770 'decimal_point' : ',',
771 'grouping' : [3, 3, 0],
772 'thousands_sep' : ' '
773 }
774
775 crazy = {
776 'decimal_point' : '&',
777 'grouping' : [1, 4, 2, CHAR_MAX],
778 'thousands_sep' : '-'
779 }
780
781
782 def get_fmt(x, locale, fmt='n'):
783 return Decimal.__format__(Decimal(x), fmt, _localeconv=locale)
784
785 self.assertEqual(get_fmt(Decimal('12.7'), en_US), '12.7')
786 self.assertEqual(get_fmt(Decimal('12.7'), fr_FR), '12,7')
787 self.assertEqual(get_fmt(Decimal('12.7'), ru_RU), '12,7')
788 self.assertEqual(get_fmt(Decimal('12.7'), crazy), '1-2&7')
789
790 self.assertEqual(get_fmt(123456789, en_US), '123,456,789')
791 self.assertEqual(get_fmt(123456789, fr_FR), '123456789')
792 self.assertEqual(get_fmt(123456789, ru_RU), '123 456 789')
793 self.assertEqual(get_fmt(1234567890123, crazy), '123456-78-9012-3')
794
795 self.assertEqual(get_fmt(123456789, en_US, '.6n'), '1.23457e+8')
796 self.assertEqual(get_fmt(123456789, fr_FR, '.6n'), '1,23457e+8')
797 self.assertEqual(get_fmt(123456789, ru_RU, '.6n'), '1,23457e+8')
798 self.assertEqual(get_fmt(123456789, crazy, '.6n'), '1&23457e+8')
799
Mark Dickinson7303b592009-03-18 08:25:36 +0000800 # zero padding
801 self.assertEqual(get_fmt(1234, fr_FR, '03n'), '1234')
802 self.assertEqual(get_fmt(1234, fr_FR, '04n'), '1234')
803 self.assertEqual(get_fmt(1234, fr_FR, '05n'), '01234')
804 self.assertEqual(get_fmt(1234, fr_FR, '06n'), '001234')
805
806 self.assertEqual(get_fmt(12345, en_US, '05n'), '12,345')
807 self.assertEqual(get_fmt(12345, en_US, '06n'), '12,345')
808 self.assertEqual(get_fmt(12345, en_US, '07n'), '012,345')
809 self.assertEqual(get_fmt(12345, en_US, '08n'), '0,012,345')
810 self.assertEqual(get_fmt(12345, en_US, '09n'), '0,012,345')
811 self.assertEqual(get_fmt(12345, en_US, '010n'), '00,012,345')
812
813 self.assertEqual(get_fmt(123456, crazy, '06n'), '1-2345-6')
814 self.assertEqual(get_fmt(123456, crazy, '07n'), '1-2345-6')
815 self.assertEqual(get_fmt(123456, crazy, '08n'), '1-2345-6')
816 self.assertEqual(get_fmt(123456, crazy, '09n'), '01-2345-6')
817 self.assertEqual(get_fmt(123456, crazy, '010n'), '0-01-2345-6')
818 self.assertEqual(get_fmt(123456, crazy, '011n'), '0-01-2345-6')
819 self.assertEqual(get_fmt(123456, crazy, '012n'), '00-01-2345-6')
820 self.assertEqual(get_fmt(123456, crazy, '013n'), '000-01-2345-6')
821
Mark Dickinson79f52032009-03-17 23:12:51 +0000822
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000823class DecimalArithmeticOperatorsTest(unittest.TestCase):
824 '''Unit tests for all arithmetic operators, binary and unary.'''
825
826 def test_addition(self):
827
828 d1 = Decimal('-11.1')
829 d2 = Decimal('22.2')
830
831 #two Decimals
832 self.assertEqual(d1+d2, Decimal('11.1'))
833 self.assertEqual(d2+d1, Decimal('11.1'))
834
835 #with other type, left
836 c = d1 + 5
837 self.assertEqual(c, Decimal('-6.1'))
838 self.assertEqual(type(c), type(d1))
839
840 #with other type, right
841 c = 5 + d1
842 self.assertEqual(c, Decimal('-6.1'))
843 self.assertEqual(type(c), type(d1))
844
845 #inline with decimal
846 d1 += d2
847 self.assertEqual(d1, Decimal('11.1'))
848
849 #inline with other type
850 d1 += 5
851 self.assertEqual(d1, Decimal('16.1'))
852
853 def test_subtraction(self):
854
855 d1 = Decimal('-11.1')
856 d2 = Decimal('22.2')
857
858 #two Decimals
859 self.assertEqual(d1-d2, Decimal('-33.3'))
860 self.assertEqual(d2-d1, Decimal('33.3'))
861
862 #with other type, left
863 c = d1 - 5
864 self.assertEqual(c, Decimal('-16.1'))
865 self.assertEqual(type(c), type(d1))
866
867 #with other type, right
868 c = 5 - d1
869 self.assertEqual(c, Decimal('16.1'))
870 self.assertEqual(type(c), type(d1))
871
872 #inline with decimal
873 d1 -= d2
874 self.assertEqual(d1, Decimal('-33.3'))
875
876 #inline with other type
877 d1 -= 5
878 self.assertEqual(d1, Decimal('-38.3'))
879
880 def test_multiplication(self):
881
882 d1 = Decimal('-5')
883 d2 = Decimal('3')
884
885 #two Decimals
886 self.assertEqual(d1*d2, Decimal('-15'))
887 self.assertEqual(d2*d1, Decimal('-15'))
888
889 #with other type, left
890 c = d1 * 5
891 self.assertEqual(c, Decimal('-25'))
892 self.assertEqual(type(c), type(d1))
893
894 #with other type, right
895 c = 5 * d1
896 self.assertEqual(c, Decimal('-25'))
897 self.assertEqual(type(c), type(d1))
898
899 #inline with decimal
900 d1 *= d2
901 self.assertEqual(d1, Decimal('-15'))
902
903 #inline with other type
904 d1 *= 5
905 self.assertEqual(d1, Decimal('-75'))
906
907 def test_division(self):
908
909 d1 = Decimal('-5')
910 d2 = Decimal('2')
911
912 #two Decimals
913 self.assertEqual(d1/d2, Decimal('-2.5'))
914 self.assertEqual(d2/d1, Decimal('-0.4'))
915
916 #with other type, left
917 c = d1 / 4
918 self.assertEqual(c, Decimal('-1.25'))
919 self.assertEqual(type(c), type(d1))
920
921 #with other type, right
922 c = 4 / d1
923 self.assertEqual(c, Decimal('-0.8'))
924 self.assertEqual(type(c), type(d1))
925
926 #inline with decimal
927 d1 /= d2
928 self.assertEqual(d1, Decimal('-2.5'))
929
930 #inline with other type
931 d1 /= 4
932 self.assertEqual(d1, Decimal('-0.625'))
933
934 def test_floor_division(self):
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000935
936 d1 = Decimal('5')
937 d2 = Decimal('2')
938
939 #two Decimals
940 self.assertEqual(d1//d2, Decimal('2'))
941 self.assertEqual(d2//d1, Decimal('0'))
942
943 #with other type, left
944 c = d1 // 4
945 self.assertEqual(c, Decimal('1'))
946 self.assertEqual(type(c), type(d1))
947
948 #with other type, right
949 c = 7 // d1
950 self.assertEqual(c, Decimal('1'))
951 self.assertEqual(type(c), type(d1))
952
953 #inline with decimal
954 d1 //= d2
955 self.assertEqual(d1, Decimal('2'))
956
957 #inline with other type
958 d1 //= 2
959 self.assertEqual(d1, Decimal('1'))
960
961 def test_powering(self):
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000962
963 d1 = Decimal('5')
964 d2 = Decimal('2')
965
966 #two Decimals
967 self.assertEqual(d1**d2, Decimal('25'))
968 self.assertEqual(d2**d1, Decimal('32'))
969
970 #with other type, left
971 c = d1 ** 4
972 self.assertEqual(c, Decimal('625'))
973 self.assertEqual(type(c), type(d1))
974
975 #with other type, right
976 c = 7 ** d1
977 self.assertEqual(c, Decimal('16807'))
978 self.assertEqual(type(c), type(d1))
979
980 #inline with decimal
981 d1 **= d2
982 self.assertEqual(d1, Decimal('25'))
983
984 #inline with other type
985 d1 **= 4
986 self.assertEqual(d1, Decimal('390625'))
987
988 def test_module(self):
989
990 d1 = Decimal('5')
991 d2 = Decimal('2')
992
993 #two Decimals
994 self.assertEqual(d1%d2, Decimal('1'))
995 self.assertEqual(d2%d1, Decimal('2'))
996
997 #with other type, left
998 c = d1 % 4
999 self.assertEqual(c, Decimal('1'))
1000 self.assertEqual(type(c), type(d1))
1001
1002 #with other type, right
1003 c = 7 % d1
1004 self.assertEqual(c, Decimal('2'))
1005 self.assertEqual(type(c), type(d1))
1006
1007 #inline with decimal
1008 d1 %= d2
1009 self.assertEqual(d1, Decimal('1'))
1010
1011 #inline with other type
1012 d1 %= 4
1013 self.assertEqual(d1, Decimal('1'))
1014
1015 def test_floor_div_module(self):
1016
1017 d1 = Decimal('5')
1018 d2 = Decimal('2')
1019
1020 #two Decimals
1021 (p, q) = divmod(d1, d2)
1022 self.assertEqual(p, Decimal('2'))
1023 self.assertEqual(q, Decimal('1'))
1024 self.assertEqual(type(p), type(d1))
1025 self.assertEqual(type(q), type(d1))
1026
1027 #with other type, left
1028 (p, q) = divmod(d1, 4)
1029 self.assertEqual(p, Decimal('1'))
1030 self.assertEqual(q, Decimal('1'))
1031 self.assertEqual(type(p), type(d1))
1032 self.assertEqual(type(q), type(d1))
1033
1034 #with other type, right
1035 (p, q) = divmod(7, d1)
1036 self.assertEqual(p, Decimal('1'))
1037 self.assertEqual(q, Decimal('2'))
1038 self.assertEqual(type(p), type(d1))
1039 self.assertEqual(type(q), type(d1))
1040
1041 def test_unary_operators(self):
1042 self.assertEqual(+Decimal(45), Decimal(+45)) # +
1043 self.assertEqual(-Decimal(45), Decimal(-45)) # -
1044 self.assertEqual(abs(Decimal(45)), abs(Decimal(-45))) # abs
1045
Christian Heimes77c02eb2008-02-09 02:18:51 +00001046 def test_nan_comparisons(self):
1047 n = Decimal('NaN')
1048 s = Decimal('sNaN')
1049 i = Decimal('Inf')
1050 f = Decimal('2')
1051 for x, y in [(n, n), (n, i), (i, n), (n, f), (f, n),
1052 (s, n), (n, s), (s, i), (i, s), (s, f), (f, s), (s, s)]:
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001053 self.assertTrue(x != y)
1054 self.assertTrue(not (x == y))
1055 self.assertTrue(not (x < y))
1056 self.assertTrue(not (x <= y))
1057 self.assertTrue(not (x > y))
1058 self.assertTrue(not (x >= y))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001059
1060# The following are two functions used to test threading in the next class
1061
1062def thfunc1(cls):
1063 d1 = Decimal(1)
1064 d3 = Decimal(3)
Christian Heimesfe337bf2008-03-23 21:54:12 +00001065 test1 = d1/d3
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001066 cls.synchro.wait()
Christian Heimesfe337bf2008-03-23 21:54:12 +00001067 test2 = d1/d3
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001068 cls.finish1.set()
Christian Heimesfe337bf2008-03-23 21:54:12 +00001069
Christian Heimes81ee3ef2008-05-04 22:42:01 +00001070 cls.assertEqual(test1, Decimal('0.3333333333333333333333333333'))
1071 cls.assertEqual(test2, Decimal('0.3333333333333333333333333333'))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001072 return
1073
1074def thfunc2(cls):
1075 d1 = Decimal(1)
1076 d3 = Decimal(3)
Christian Heimesfe337bf2008-03-23 21:54:12 +00001077 test1 = d1/d3
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001078 thiscontext = getcontext()
1079 thiscontext.prec = 18
Christian Heimesfe337bf2008-03-23 21:54:12 +00001080 test2 = d1/d3
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001081 cls.synchro.set()
1082 cls.finish2.set()
Christian Heimesfe337bf2008-03-23 21:54:12 +00001083
Christian Heimes81ee3ef2008-05-04 22:42:01 +00001084 cls.assertEqual(test1, Decimal('0.3333333333333333333333333333'))
Christian Heimesfe337bf2008-03-23 21:54:12 +00001085 cls.assertEqual(test2, Decimal('0.333333333333333333'))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001086 return
1087
1088
1089class DecimalUseOfContextTest(unittest.TestCase):
1090 '''Unit tests for Use of Context cases in Decimal.'''
1091
Raymond Hettinger7e71fa52004-12-18 19:07:19 +00001092 try:
1093 import threading
1094 except ImportError:
1095 threading = None
1096
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001097 # Take care executing this test from IDLE, there's an issue in threading
1098 # that hangs IDLE and I couldn't find it
1099
1100 def test_threading(self):
1101 #Test the "threading isolation" of a Context.
1102
1103 self.synchro = threading.Event()
1104 self.finish1 = threading.Event()
1105 self.finish2 = threading.Event()
1106
1107 th1 = threading.Thread(target=thfunc1, args=(self,))
1108 th2 = threading.Thread(target=thfunc2, args=(self,))
1109
1110 th1.start()
1111 th2.start()
1112
1113 self.finish1.wait()
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001114 self.finish2.wait()
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001115 return
1116
Raymond Hettinger7e71fa52004-12-18 19:07:19 +00001117 if threading is None:
1118 del test_threading
1119
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001120
1121class DecimalUsabilityTest(unittest.TestCase):
1122 '''Unit tests for Usability cases of Decimal.'''
1123
1124 def test_comparison_operators(self):
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001125
1126 da = Decimal('23.42')
1127 db = Decimal('23.42')
1128 dc = Decimal('45')
1129
1130 #two Decimals
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001131 self.assertTrue(dc > da)
1132 self.assertTrue(dc >= da)
1133 self.assertTrue(da < dc)
1134 self.assertTrue(da <= dc)
Guido van Rossume61fd5b2007-07-11 12:20:59 +00001135 self.assertEqual(da, db)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001136 self.assertTrue(da != dc)
1137 self.assertTrue(da <= db)
1138 self.assertTrue(da >= db)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001139
1140 #a Decimal and an int
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001141 self.assertTrue(dc > 23)
1142 self.assertTrue(23 < dc)
Guido van Rossume61fd5b2007-07-11 12:20:59 +00001143 self.assertEqual(dc, 45)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001144
1145 #a Decimal and uncomparable
Raymond Hettinger0aeac102004-07-05 22:53:03 +00001146 self.assertNotEqual(da, 'ugly')
1147 self.assertNotEqual(da, 32.7)
1148 self.assertNotEqual(da, object())
1149 self.assertNotEqual(da, object)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001150
Raymond Hettinger0aeac102004-07-05 22:53:03 +00001151 # sortable
Guido van Rossumc1f779c2007-07-03 08:25:58 +00001152 a = list(map(Decimal, range(100)))
Raymond Hettinger0aeac102004-07-05 22:53:03 +00001153 b = a[:]
1154 random.shuffle(a)
1155 a.sort()
1156 self.assertEqual(a, b)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001157
1158 def test_copy_and_deepcopy_methods(self):
1159 d = Decimal('43.24')
1160 c = copy.copy(d)
1161 self.assertEqual(id(c), id(d))
1162 dc = copy.deepcopy(d)
1163 self.assertEqual(id(dc), id(d))
1164
1165 def test_hash_method(self):
1166 #just that it's hashable
1167 hash(Decimal(23))
Thomas Wouters8ce81f72007-09-20 18:22:40 +00001168
1169 test_values = [Decimal(sign*(2**m + n))
1170 for m in [0, 14, 15, 16, 17, 30, 31,
1171 32, 33, 62, 63, 64, 65, 66]
1172 for n in range(-10, 10)
1173 for sign in [-1, 1]]
1174 test_values.extend([
1175 Decimal("-0"), # zeros
1176 Decimal("0.00"),
1177 Decimal("-0.000"),
1178 Decimal("0E10"),
1179 Decimal("-0E12"),
1180 Decimal("10.0"), # negative exponent
1181 Decimal("-23.00000"),
1182 Decimal("1230E100"), # positive exponent
1183 Decimal("-4.5678E50"),
1184 # a value for which hash(n) != hash(n % (2**64-1))
1185 # in Python pre-2.6
1186 Decimal(2**64 + 2**32 - 1),
1187 # selection of values which fail with the old (before
1188 # version 2.6) long.__hash__
1189 Decimal("1.634E100"),
1190 Decimal("90.697E100"),
1191 Decimal("188.83E100"),
1192 Decimal("1652.9E100"),
1193 Decimal("56531E100"),
1194 ])
1195
1196 # check that hash(d) == hash(int(d)) for integral values
1197 for value in test_values:
1198 self.assertEqual(hash(value), hash(int(value)))
1199
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001200 #the same hash that to an int
1201 self.assertEqual(hash(Decimal(23)), hash(23))
Raymond Hettingerbea3f6f2005-03-15 04:59:17 +00001202 self.assertRaises(TypeError, hash, Decimal('NaN'))
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001203 self.assertTrue(hash(Decimal('Inf')))
1204 self.assertTrue(hash(Decimal('-Inf')))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001205
Christian Heimes2380ac72008-01-09 00:17:24 +00001206 # check that the value of the hash doesn't depend on the
1207 # current context (issue #1757)
1208 c = getcontext()
1209 old_precision = c.prec
1210 x = Decimal("123456789.1")
1211
1212 c.prec = 6
1213 h1 = hash(x)
1214 c.prec = 10
1215 h2 = hash(x)
1216 c.prec = 16
1217 h3 = hash(x)
1218
1219 self.assertEqual(h1, h2)
1220 self.assertEqual(h1, h3)
1221 c.prec = old_precision
1222
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001223 def test_min_and_max_methods(self):
1224
1225 d1 = Decimal('15.32')
1226 d2 = Decimal('28.5')
1227 l1 = 15
1228 l2 = 28
1229
1230 #between Decimals
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001231 self.assertTrue(min(d1,d2) is d1)
1232 self.assertTrue(min(d2,d1) is d1)
1233 self.assertTrue(max(d1,d2) is d2)
1234 self.assertTrue(max(d2,d1) is d2)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001235
1236 #between Decimal and long
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001237 self.assertTrue(min(d1,l2) is d1)
1238 self.assertTrue(min(l2,d1) is d1)
1239 self.assertTrue(max(l1,d2) is d2)
1240 self.assertTrue(max(d2,l1) is d2)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001241
1242 def test_as_nonzero(self):
1243 #as false
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001244 self.assertFalse(Decimal(0))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001245 #as true
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001246 self.assertTrue(Decimal('0.372'))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001247
1248 def test_tostring_methods(self):
1249 #Test str and repr methods.
1250
1251 d = Decimal('15.32')
1252 self.assertEqual(str(d), '15.32') # str
Christian Heimes68f5fbe2008-02-14 08:27:37 +00001253 self.assertEqual(repr(d), "Decimal('15.32')") # repr
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001254
1255 def test_tonum_methods(self):
1256 #Test float, int and long methods.
1257
1258 d1 = Decimal('66')
1259 d2 = Decimal('15.32')
1260
1261 #int
1262 self.assertEqual(int(d1), 66)
1263 self.assertEqual(int(d2), 15)
1264
1265 #long
Guido van Rossume2a383d2007-01-15 16:59:06 +00001266 self.assertEqual(int(d1), 66)
1267 self.assertEqual(int(d2), 15)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001268
1269 #float
1270 self.assertEqual(float(d1), 66)
1271 self.assertEqual(float(d2), 15.32)
1272
Mark Dickinsonb27406c2008-05-09 13:42:33 +00001273 #floor
1274 test_pairs = [
1275 ('123.00', 123),
1276 ('3.2', 3),
1277 ('3.54', 3),
1278 ('3.899', 3),
1279 ('-2.3', -3),
1280 ('-11.0', -11),
1281 ('0.0', 0),
1282 ('-0E3', 0),
1283 ]
1284 for d, i in test_pairs:
1285 self.assertEqual(math.floor(Decimal(d)), i)
1286 self.assertRaises(ValueError, math.floor, Decimal('-NaN'))
1287 self.assertRaises(ValueError, math.floor, Decimal('sNaN'))
1288 self.assertRaises(ValueError, math.floor, Decimal('NaN123'))
1289 self.assertRaises(OverflowError, math.floor, Decimal('Inf'))
1290 self.assertRaises(OverflowError, math.floor, Decimal('-Inf'))
1291
1292 #ceiling
1293 test_pairs = [
1294 ('123.00', 123),
1295 ('3.2', 4),
1296 ('3.54', 4),
1297 ('3.899', 4),
1298 ('-2.3', -2),
1299 ('-11.0', -11),
1300 ('0.0', 0),
1301 ('-0E3', 0),
1302 ]
1303 for d, i in test_pairs:
1304 self.assertEqual(math.ceil(Decimal(d)), i)
1305 self.assertRaises(ValueError, math.ceil, Decimal('-NaN'))
1306 self.assertRaises(ValueError, math.ceil, Decimal('sNaN'))
1307 self.assertRaises(ValueError, math.ceil, Decimal('NaN123'))
1308 self.assertRaises(OverflowError, math.ceil, Decimal('Inf'))
1309 self.assertRaises(OverflowError, math.ceil, Decimal('-Inf'))
1310
1311 #round, single argument
1312 test_pairs = [
1313 ('123.00', 123),
1314 ('3.2', 3),
1315 ('3.54', 4),
1316 ('3.899', 4),
1317 ('-2.3', -2),
1318 ('-11.0', -11),
1319 ('0.0', 0),
1320 ('-0E3', 0),
1321 ('-3.5', -4),
1322 ('-2.5', -2),
1323 ('-1.5', -2),
1324 ('-0.5', 0),
1325 ('0.5', 0),
1326 ('1.5', 2),
1327 ('2.5', 2),
1328 ('3.5', 4),
1329 ]
1330 for d, i in test_pairs:
1331 self.assertEqual(round(Decimal(d)), i)
1332 self.assertRaises(ValueError, round, Decimal('-NaN'))
1333 self.assertRaises(ValueError, round, Decimal('sNaN'))
1334 self.assertRaises(ValueError, round, Decimal('NaN123'))
1335 self.assertRaises(OverflowError, round, Decimal('Inf'))
1336 self.assertRaises(OverflowError, round, Decimal('-Inf'))
1337
1338 #round, two arguments; this is essentially equivalent
1339 #to quantize, which is already extensively tested
1340 test_triples = [
1341 ('123.456', -4, '0E+4'),
1342 ('123.456', -3, '0E+3'),
1343 ('123.456', -2, '1E+2'),
1344 ('123.456', -1, '1.2E+2'),
1345 ('123.456', 0, '123'),
1346 ('123.456', 1, '123.5'),
1347 ('123.456', 2, '123.46'),
1348 ('123.456', 3, '123.456'),
1349 ('123.456', 4, '123.4560'),
1350 ('123.455', 2, '123.46'),
1351 ('123.445', 2, '123.44'),
1352 ('Inf', 4, 'NaN'),
1353 ('-Inf', -23, 'NaN'),
1354 ('sNaN314', 3, 'NaN314'),
1355 ]
1356 for d, n, r in test_triples:
1357 self.assertEqual(str(round(Decimal(d), n)), r)
1358
1359
1360
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001361 def test_eval_round_trip(self):
1362
1363 #with zero
1364 d = Decimal( (0, (0,), 0) )
1365 self.assertEqual(d, eval(repr(d)))
1366
1367 #int
1368 d = Decimal( (1, (4, 5), 0) )
1369 self.assertEqual(d, eval(repr(d)))
1370
1371 #float
1372 d = Decimal( (0, (4, 5, 3, 4), -2) )
1373 self.assertEqual(d, eval(repr(d)))
1374
1375 #weird
1376 d = Decimal( (1, (4, 3, 4, 9, 1, 3, 5, 3, 4), -25) )
1377 self.assertEqual(d, eval(repr(d)))
1378
1379 def test_as_tuple(self):
1380
1381 #with zero
1382 d = Decimal(0)
1383 self.assertEqual(d.as_tuple(), (0, (0,), 0) )
1384
1385 #int
1386 d = Decimal(-45)
1387 self.assertEqual(d.as_tuple(), (1, (4, 5), 0) )
1388
1389 #complicated string
1390 d = Decimal("-4.34913534E-17")
1391 self.assertEqual(d.as_tuple(), (1, (4, 3, 4, 9, 1, 3, 5, 3, 4), -25) )
1392
1393 #inf
1394 d = Decimal("Infinity")
1395 self.assertEqual(d.as_tuple(), (0, (0,), 'F') )
1396
Guido van Rossum8ce8a782007-11-01 19:42:39 +00001397 #leading zeros in coefficient should be stripped
1398 d = Decimal( (0, (0, 0, 4, 0, 5, 3, 4), -2) )
1399 self.assertEqual(d.as_tuple(), (0, (4, 0, 5, 3, 4), -2) )
1400 d = Decimal( (1, (0, 0, 0), 37) )
1401 self.assertEqual(d.as_tuple(), (1, (0,), 37))
1402 d = Decimal( (1, (), 37) )
1403 self.assertEqual(d.as_tuple(), (1, (0,), 37))
1404
1405 #leading zeros in NaN diagnostic info should be stripped
1406 d = Decimal( (0, (0, 0, 4, 0, 5, 3, 4), 'n') )
1407 self.assertEqual(d.as_tuple(), (0, (4, 0, 5, 3, 4), 'n') )
1408 d = Decimal( (1, (0, 0, 0), 'N') )
1409 self.assertEqual(d.as_tuple(), (1, (), 'N') )
1410 d = Decimal( (1, (), 'n') )
1411 self.assertEqual(d.as_tuple(), (1, (), 'n') )
1412
1413 #coefficient in infinity should be ignored
1414 d = Decimal( (0, (4, 5, 3, 4), 'F') )
1415 self.assertEqual(d.as_tuple(), (0, (0,), 'F'))
1416 d = Decimal( (1, (0, 2, 7, 1), 'F') )
1417 self.assertEqual(d.as_tuple(), (1, (0,), 'F'))
1418
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001419 def test_immutability_operations(self):
1420 # Do operations and check that it didn't change change internal objects.
1421
1422 d1 = Decimal('-25e55')
1423 b1 = Decimal('-25e55')
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001424 d2 = Decimal('33e+33')
1425 b2 = Decimal('33e+33')
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001426
1427 def checkSameDec(operation, useOther=False):
1428 if useOther:
1429 eval("d1." + operation + "(d2)")
1430 self.assertEqual(d1._sign, b1._sign)
1431 self.assertEqual(d1._int, b1._int)
1432 self.assertEqual(d1._exp, b1._exp)
1433 self.assertEqual(d2._sign, b2._sign)
1434 self.assertEqual(d2._int, b2._int)
1435 self.assertEqual(d2._exp, b2._exp)
1436 else:
1437 eval("d1." + operation + "()")
1438 self.assertEqual(d1._sign, b1._sign)
1439 self.assertEqual(d1._int, b1._int)
1440 self.assertEqual(d1._exp, b1._exp)
1441 return
1442
1443 Decimal(d1)
1444 self.assertEqual(d1._sign, b1._sign)
1445 self.assertEqual(d1._int, b1._int)
1446 self.assertEqual(d1._exp, b1._exp)
1447
1448 checkSameDec("__abs__")
1449 checkSameDec("__add__", True)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001450 checkSameDec("__divmod__", True)
Christian Heimes77c02eb2008-02-09 02:18:51 +00001451 checkSameDec("__eq__", True)
1452 checkSameDec("__ne__", True)
1453 checkSameDec("__le__", True)
1454 checkSameDec("__lt__", True)
1455 checkSameDec("__ge__", True)
1456 checkSameDec("__gt__", True)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001457 checkSameDec("__float__")
1458 checkSameDec("__floordiv__", True)
1459 checkSameDec("__hash__")
1460 checkSameDec("__int__")
Christian Heimes969fe572008-01-25 11:23:10 +00001461 checkSameDec("__trunc__")
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001462 checkSameDec("__mod__", True)
1463 checkSameDec("__mul__", True)
1464 checkSameDec("__neg__")
Jack Diederich4dafcc42006-11-28 19:15:13 +00001465 checkSameDec("__bool__")
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001466 checkSameDec("__pos__")
1467 checkSameDec("__pow__", True)
1468 checkSameDec("__radd__", True)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001469 checkSameDec("__rdivmod__", True)
1470 checkSameDec("__repr__")
1471 checkSameDec("__rfloordiv__", True)
1472 checkSameDec("__rmod__", True)
1473 checkSameDec("__rmul__", True)
1474 checkSameDec("__rpow__", True)
1475 checkSameDec("__rsub__", True)
1476 checkSameDec("__str__")
1477 checkSameDec("__sub__", True)
1478 checkSameDec("__truediv__", True)
1479 checkSameDec("adjusted")
1480 checkSameDec("as_tuple")
1481 checkSameDec("compare", True)
1482 checkSameDec("max", True)
1483 checkSameDec("min", True)
1484 checkSameDec("normalize")
1485 checkSameDec("quantize", True)
1486 checkSameDec("remainder_near", True)
1487 checkSameDec("same_quantum", True)
1488 checkSameDec("sqrt")
1489 checkSameDec("to_eng_string")
1490 checkSameDec("to_integral")
1491
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001492 def test_subclassing(self):
1493 # Different behaviours when subclassing Decimal
1494
1495 class MyDecimal(Decimal):
1496 pass
1497
1498 d1 = MyDecimal(1)
1499 d2 = MyDecimal(2)
1500 d = d1 + d2
1501 self.assertTrue(type(d) is Decimal)
1502
1503 d = d1.max(d2)
1504 self.assertTrue(type(d) is Decimal)
1505
Christian Heimes0348fb62008-03-26 12:55:56 +00001506 def test_implicit_context(self):
1507 # Check results when context given implicitly. (Issue 2478)
1508 c = getcontext()
1509 self.assertEqual(str(Decimal(0).sqrt()),
1510 str(c.sqrt(Decimal(0))))
1511
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001512
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001513class DecimalPythonAPItests(unittest.TestCase):
1514
Raymond Hettinger82417ca2009-02-03 03:54:28 +00001515 def test_abc(self):
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001516 self.assertTrue(issubclass(Decimal, numbers.Number))
1517 self.assertTrue(not issubclass(Decimal, numbers.Real))
1518 self.assertTrue(isinstance(Decimal(0), numbers.Number))
1519 self.assertTrue(not isinstance(Decimal(0), numbers.Real))
Raymond Hettinger82417ca2009-02-03 03:54:28 +00001520
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001521 def test_pickle(self):
1522 d = Decimal('-3.141590000')
1523 p = pickle.dumps(d)
1524 e = pickle.loads(p)
1525 self.assertEqual(d, e)
1526
Raymond Hettinger5548be22004-07-05 18:49:38 +00001527 def test_int(self):
Raymond Hettinger605ed022004-11-24 07:28:48 +00001528 for x in range(-250, 250):
1529 s = '%0.2f' % (x / 100.0)
Raymond Hettinger5548be22004-07-05 18:49:38 +00001530 # should work the same as for floats
1531 self.assertEqual(int(Decimal(s)), int(float(s)))
Raymond Hettinger605ed022004-11-24 07:28:48 +00001532 # should work the same as to_integral in the ROUND_DOWN mode
Raymond Hettinger5548be22004-07-05 18:49:38 +00001533 d = Decimal(s)
Raymond Hettinger605ed022004-11-24 07:28:48 +00001534 r = d.to_integral(ROUND_DOWN)
Raymond Hettinger5548be22004-07-05 18:49:38 +00001535 self.assertEqual(Decimal(int(d)), r)
1536
Christian Heimes969fe572008-01-25 11:23:10 +00001537 def test_trunc(self):
1538 for x in range(-250, 250):
1539 s = '%0.2f' % (x / 100.0)
1540 # should work the same as for floats
1541 self.assertEqual(int(Decimal(s)), int(float(s)))
1542 # should work the same as to_integral in the ROUND_DOWN mode
1543 d = Decimal(s)
1544 r = d.to_integral(ROUND_DOWN)
Christian Heimes400adb02008-02-01 08:12:03 +00001545 self.assertEqual(Decimal(math.trunc(d)), r)
Christian Heimes969fe572008-01-25 11:23:10 +00001546
Raymond Hettinger771ed762009-01-03 19:20:32 +00001547 def test_from_float(self):
1548
1549 class MyDecimal(Decimal):
1550 pass
1551
1552 r = MyDecimal.from_float(0.1)
1553 self.assertEqual(type(r), MyDecimal)
1554 self.assertEqual(str(r),
1555 '0.1000000000000000055511151231257827021181583404541015625')
1556 bigint = 12345678901234567890123456789
1557 self.assertEqual(MyDecimal.from_float(bigint), MyDecimal(bigint))
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001558 self.assertTrue(MyDecimal.from_float(float('nan')).is_qnan())
1559 self.assertTrue(MyDecimal.from_float(float('inf')).is_infinite())
1560 self.assertTrue(MyDecimal.from_float(float('-inf')).is_infinite())
Raymond Hettinger771ed762009-01-03 19:20:32 +00001561 self.assertEqual(str(MyDecimal.from_float(float('nan'))),
1562 str(Decimal('NaN')))
1563 self.assertEqual(str(MyDecimal.from_float(float('inf'))),
1564 str(Decimal('Infinity')))
1565 self.assertEqual(str(MyDecimal.from_float(float('-inf'))),
1566 str(Decimal('-Infinity')))
1567 self.assertRaises(TypeError, MyDecimal.from_float, 'abc')
1568 for i in range(200):
1569 x = random.expovariate(0.01) * (random.random() * 2.0 - 1.0)
1570 self.assertEqual(x, float(MyDecimal.from_float(x))) # roundtrip
1571
1572 def test_create_decimal_from_float(self):
1573 context = Context(prec=5, rounding=ROUND_DOWN)
1574 self.assertEqual(
1575 context.create_decimal_from_float(math.pi),
1576 Decimal('3.1415')
1577 )
1578 context = Context(prec=5, rounding=ROUND_UP)
1579 self.assertEqual(
1580 context.create_decimal_from_float(math.pi),
1581 Decimal('3.1416')
1582 )
1583 context = Context(prec=5, traps=[Inexact])
1584 self.assertRaises(
1585 Inexact,
1586 context.create_decimal_from_float,
1587 math.pi
1588 )
1589 self.assertEqual(repr(context.create_decimal_from_float(-0.0)),
1590 "Decimal('-0')")
1591 self.assertEqual(repr(context.create_decimal_from_float(1.0)),
1592 "Decimal('1')")
1593 self.assertEqual(repr(context.create_decimal_from_float(10)),
1594 "Decimal('10')")
1595
Raymond Hettingerd9c0a7a2004-07-03 10:02:28 +00001596class ContextAPItests(unittest.TestCase):
1597
1598 def test_pickle(self):
1599 c = Context()
1600 e = pickle.loads(pickle.dumps(c))
1601 for k in vars(c):
1602 v1 = vars(c)[k]
1603 v2 = vars(e)[k]
1604 self.assertEqual(v1, v2)
1605
Raymond Hettinger0aeac102004-07-05 22:53:03 +00001606 def test_equality_with_other_types(self):
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001607 self.assertTrue(Decimal(10) in ['a', 1.0, Decimal(10), (1,2), {}])
1608 self.assertTrue(Decimal(10) not in ['a', 1.0, (1,2), {}])
Raymond Hettinger0aeac102004-07-05 22:53:03 +00001609
Raymond Hettinger955d2b22004-08-08 20:17:45 +00001610 def test_copy(self):
1611 # All copies should be deep
1612 c = Context()
1613 d = c.copy()
1614 self.assertNotEqual(id(c), id(d))
1615 self.assertNotEqual(id(c.flags), id(d.flags))
1616 self.assertNotEqual(id(c.traps), id(d.traps))
1617
Thomas Wouters89f507f2006-12-13 04:49:30 +00001618class WithStatementTest(unittest.TestCase):
1619 # Can't do these as docstrings until Python 2.6
1620 # as doctest can't handle __future__ statements
1621
1622 def test_localcontext(self):
1623 # Use a copy of the current context in the block
1624 orig_ctx = getcontext()
1625 with localcontext() as enter_ctx:
1626 set_ctx = getcontext()
1627 final_ctx = getcontext()
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001628 self.assertTrue(orig_ctx is final_ctx, 'did not restore context correctly')
1629 self.assertTrue(orig_ctx is not set_ctx, 'did not copy the context')
1630 self.assertTrue(set_ctx is enter_ctx, '__enter__ returned wrong context')
Thomas Wouters89f507f2006-12-13 04:49:30 +00001631
1632 def test_localcontextarg(self):
1633 # Use a copy of the supplied context in the block
1634 orig_ctx = getcontext()
1635 new_ctx = Context(prec=42)
1636 with localcontext(new_ctx) as enter_ctx:
1637 set_ctx = getcontext()
1638 final_ctx = getcontext()
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001639 self.assertTrue(orig_ctx is final_ctx, 'did not restore context correctly')
1640 self.assertTrue(set_ctx.prec == new_ctx.prec, 'did not set correct context')
1641 self.assertTrue(new_ctx is not set_ctx, 'did not copy the context')
1642 self.assertTrue(set_ctx is enter_ctx, '__enter__ returned wrong context')
Thomas Wouters89f507f2006-12-13 04:49:30 +00001643
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001644class ContextFlags(unittest.TestCase):
1645 def test_flags_irrelevant(self):
1646 # check that the result (numeric result + flags raised) of an
1647 # arithmetic operation doesn't depend on the current flags
1648
1649 context = Context(prec=9, Emin = -999999999, Emax = 999999999,
1650 rounding=ROUND_HALF_EVEN, traps=[], flags=[])
1651
1652 # operations that raise various flags, in the form (function, arglist)
1653 operations = [
1654 (context._apply, [Decimal("100E-1000000009")]),
1655 (context.sqrt, [Decimal(2)]),
1656 (context.add, [Decimal("1.23456789"), Decimal("9.87654321")]),
1657 (context.multiply, [Decimal("1.23456789"), Decimal("9.87654321")]),
1658 (context.subtract, [Decimal("1.23456789"), Decimal("9.87654321")]),
1659 ]
1660
1661 # try various flags individually, then a whole lot at once
1662 flagsets = [[Inexact], [Rounded], [Underflow], [Clamped], [Subnormal],
1663 [Inexact, Rounded, Underflow, Clamped, Subnormal]]
1664
1665 for fn, args in operations:
1666 # find answer and flags raised using a clean context
1667 context.clear_flags()
1668 ans = fn(*args)
1669 flags = [k for k, v in context.flags.items() if v]
1670
1671 for extra_flags in flagsets:
1672 # set flags, before calling operation
1673 context.clear_flags()
1674 for flag in extra_flags:
1675 context._raise_error(flag)
1676 new_ans = fn(*args)
1677
1678 # flags that we expect to be set after the operation
1679 expected_flags = list(flags)
1680 for flag in extra_flags:
1681 if flag not in expected_flags:
1682 expected_flags.append(flag)
1683 expected_flags.sort(key=id)
1684
1685 # flags we actually got
1686 new_flags = [k for k,v in context.flags.items() if v]
1687 new_flags.sort(key=id)
1688
1689 self.assertEqual(ans, new_ans,
1690 "operation produces different answers depending on flags set: " +
1691 "expected %s, got %s." % (ans, new_ans))
1692 self.assertEqual(new_flags, expected_flags,
1693 "operation raises different flags depending on flags set: " +
1694 "expected %s, got %s" % (expected_flags, new_flags))
1695
1696def test_main(arith=False, verbose=None, todo_tests=None, debug=None):
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001697 """ Execute the tests.
1698
Raymond Hettingered20ad82004-09-04 20:09:13 +00001699 Runs all arithmetic tests if arith is True or if the "decimal" resource
1700 is enabled in regrtest.py
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001701 """
Raymond Hettingered20ad82004-09-04 20:09:13 +00001702
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00001703 init()
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001704 global TEST_ALL, DEBUG
Raymond Hettingered20ad82004-09-04 20:09:13 +00001705 TEST_ALL = arith or is_resource_enabled('decimal')
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001706 DEBUG = debug
Raymond Hettingered20ad82004-09-04 20:09:13 +00001707
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001708 if todo_tests is None:
1709 test_classes = [
1710 DecimalExplicitConstructionTest,
1711 DecimalImplicitConstructionTest,
1712 DecimalArithmeticOperatorsTest,
Christian Heimesf16baeb2008-02-29 14:57:44 +00001713 DecimalFormatTest,
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001714 DecimalUseOfContextTest,
1715 DecimalUsabilityTest,
1716 DecimalPythonAPItests,
1717 ContextAPItests,
1718 DecimalTest,
1719 WithStatementTest,
1720 ContextFlags
1721 ]
1722 else:
1723 test_classes = [DecimalTest]
1724
1725 # Dynamically build custom test definition for each file in the test
1726 # directory and add the definitions to the DecimalTest class. This
1727 # procedure insures that new files do not get skipped.
1728 for filename in os.listdir(directory):
1729 if '.decTest' not in filename or filename.startswith("."):
1730 continue
1731 head, tail = filename.split('.')
1732 if todo_tests is not None and head not in todo_tests:
1733 continue
1734 tester = lambda self, f=filename: self.eval_file(directory + f)
1735 setattr(DecimalTest, 'test_' + head, tester)
1736 del filename, head, tail, tester
1737
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001738
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00001739 try:
1740 run_unittest(*test_classes)
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001741 if todo_tests is None:
1742 import decimal as DecimalModule
1743 run_doctest(DecimalModule, verbose)
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00001744 finally:
1745 setcontext(ORIGINAL_CONTEXT)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001746
1747if __name__ == '__main__':
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001748 import optparse
1749 p = optparse.OptionParser("test_decimal.py [--debug] [{--skip | test1 [test2 [...]]}]")
1750 p.add_option('--debug', '-d', action='store_true', help='shows the test number and context before each test')
1751 p.add_option('--skip', '-s', action='store_true', help='skip over 90% of the arithmetic tests')
1752 (opt, args) = p.parse_args()
1753
1754 if opt.skip:
1755 test_main(arith=False, verbose=True)
1756 elif args:
1757 test_main(arith=True, verbose=True, todo_tests=args, debug=opt.debug)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001758 else:
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001759 test_main(arith=True, verbose=True)