blob: 39a0ad57ad8b0daaf4d966ea9e712dde1995f3cd [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
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000428 def test_explicit_from_tuples(self):
429
430 #zero
431 d = Decimal( (0, (0,), 0) )
432 self.assertEqual(str(d), '0')
433
434 #int
435 d = Decimal( (1, (4, 5), 0) )
436 self.assertEqual(str(d), '-45')
437
438 #float
439 d = Decimal( (0, (4, 5, 3, 4), -2) )
440 self.assertEqual(str(d), '45.34')
441
442 #weird
443 d = Decimal( (1, (4, 3, 4, 9, 1, 3, 5, 3, 4), -25) )
444 self.assertEqual(str(d), '-4.34913534E-17')
445
446 #wrong number of items
447 self.assertRaises(ValueError, Decimal, (1, (4, 3, 4, 9, 1)) )
448
449 #bad sign
450 self.assertRaises(ValueError, Decimal, (8, (4, 3, 4, 9, 1), 2) )
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000451 self.assertRaises(ValueError, Decimal, (0., (4, 3, 4, 9, 1), 2) )
452 self.assertRaises(ValueError, Decimal, (Decimal(1), (4, 3, 4, 9, 1), 2))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000453
454 #bad exp
455 self.assertRaises(ValueError, Decimal, (1, (4, 3, 4, 9, 1), 'wrong!') )
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000456 self.assertRaises(ValueError, Decimal, (1, (4, 3, 4, 9, 1), 0.) )
457 self.assertRaises(ValueError, Decimal, (1, (4, 3, 4, 9, 1), '1') )
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000458
459 #bad coefficients
460 self.assertRaises(ValueError, Decimal, (1, (4, 3, 4, None, 1), 2) )
461 self.assertRaises(ValueError, Decimal, (1, (4, -3, 4, 9, 1), 2) )
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000462 self.assertRaises(ValueError, Decimal, (1, (4, 10, 4, 9, 1), 2) )
Guido van Rossum0d3fb8a2007-11-26 23:23:18 +0000463 self.assertRaises(ValueError, Decimal, (1, (4, 3, 4, 'a', 1), 2) )
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000464
465 def test_explicit_from_Decimal(self):
466
467 #positive
468 d = Decimal(45)
469 e = Decimal(d)
470 self.assertEqual(str(e), '45')
471 self.assertNotEqual(id(d), id(e))
472
473 #very large positive
474 d = Decimal(500000123)
475 e = Decimal(d)
476 self.assertEqual(str(e), '500000123')
477 self.assertNotEqual(id(d), id(e))
478
479 #negative
480 d = Decimal(-45)
481 e = Decimal(d)
482 self.assertEqual(str(e), '-45')
483 self.assertNotEqual(id(d), id(e))
484
485 #zero
486 d = Decimal(0)
487 e = Decimal(d)
488 self.assertEqual(str(e), '0')
489 self.assertNotEqual(id(d), id(e))
490
491 def test_explicit_context_create_decimal(self):
492
493 nc = copy.copy(getcontext())
494 nc.prec = 3
495
496 # empty
Raymond Hettingerfed52962004-07-14 15:41:57 +0000497 d = Decimal()
498 self.assertEqual(str(d), '0')
499 d = nc.create_decimal()
500 self.assertEqual(str(d), '0')
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000501
502 # from None
503 self.assertRaises(TypeError, nc.create_decimal, None)
504
505 # from int
506 d = nc.create_decimal(456)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000507 self.assertTrue(isinstance(d, Decimal))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000508 self.assertEqual(nc.create_decimal(45678),
509 nc.create_decimal('457E+2'))
510
511 # from string
512 d = Decimal('456789')
513 self.assertEqual(str(d), '456789')
514 d = nc.create_decimal('456789')
515 self.assertEqual(str(d), '4.57E+5')
Christian Heimesa62da1d2008-01-12 19:39:10 +0000516 # leading and trailing whitespace should result in a NaN;
517 # spaces are already checked in Cowlishaw's test-suite, so
518 # here we just check that a trailing newline results in a NaN
519 self.assertEqual(str(nc.create_decimal('3.14\n')), 'NaN')
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000520
521 # from tuples
522 d = Decimal( (1, (4, 3, 4, 9, 1, 3, 5, 3, 4), -25) )
523 self.assertEqual(str(d), '-4.34913534E-17')
524 d = nc.create_decimal( (1, (4, 3, 4, 9, 1, 3, 5, 3, 4), -25) )
525 self.assertEqual(str(d), '-4.35E-17')
526
527 # from Decimal
528 prevdec = Decimal(500000123)
529 d = Decimal(prevdec)
530 self.assertEqual(str(d), '500000123')
531 d = nc.create_decimal(prevdec)
532 self.assertEqual(str(d), '5.00E+8')
533
Mark Dickinson345adc42009-08-02 10:14:23 +0000534 def test_unicode_digits(self):
535 test_values = {
536 '\uff11': '1',
537 '\u0660.\u0660\u0663\u0667\u0662e-\u0663' : '0.0000372',
538 '-nan\u0c68\u0c6a\u0c66\u0c66' : '-NaN2400',
539 }
540 for input, expected in test_values.items():
541 self.assertEqual(str(Decimal(input)), expected)
542
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000543
544class DecimalImplicitConstructionTest(unittest.TestCase):
545 '''Unit tests for Implicit Construction cases of Decimal.'''
546
547 def test_implicit_from_None(self):
548 self.assertRaises(TypeError, eval, 'Decimal(5) + None', globals())
549
550 def test_implicit_from_int(self):
551 #normal
552 self.assertEqual(str(Decimal(5) + 45), '50')
553 #exceeding precision
554 self.assertEqual(Decimal(5) + 123456789000, Decimal(123456789000))
555
556 def test_implicit_from_string(self):
557 self.assertRaises(TypeError, eval, 'Decimal(5) + "3"', globals())
558
559 def test_implicit_from_float(self):
560 self.assertRaises(TypeError, eval, 'Decimal(5) + 2.2', globals())
561
562 def test_implicit_from_Decimal(self):
563 self.assertEqual(Decimal(5) + Decimal(45), Decimal(50))
564
Raymond Hettinger267b8682005-03-27 10:47:39 +0000565 def test_rop(self):
566 # Allow other classes to be trained to interact with Decimals
567 class E:
568 def __divmod__(self, other):
569 return 'divmod ' + str(other)
570 def __rdivmod__(self, other):
571 return str(other) + ' rdivmod'
572 def __lt__(self, other):
573 return 'lt ' + str(other)
574 def __gt__(self, other):
575 return 'gt ' + str(other)
576 def __le__(self, other):
577 return 'le ' + str(other)
578 def __ge__(self, other):
579 return 'ge ' + str(other)
580 def __eq__(self, other):
581 return 'eq ' + str(other)
582 def __ne__(self, other):
583 return 'ne ' + str(other)
584
585 self.assertEqual(divmod(E(), Decimal(10)), 'divmod 10')
586 self.assertEqual(divmod(Decimal(10), E()), '10 rdivmod')
587 self.assertEqual(eval('Decimal(10) < E()'), 'gt 10')
588 self.assertEqual(eval('Decimal(10) > E()'), 'lt 10')
589 self.assertEqual(eval('Decimal(10) <= E()'), 'ge 10')
590 self.assertEqual(eval('Decimal(10) >= E()'), 'le 10')
591 self.assertEqual(eval('Decimal(10) == E()'), 'eq 10')
592 self.assertEqual(eval('Decimal(10) != E()'), 'ne 10')
593
594 # insert operator methods and then exercise them
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000595 oplist = [
596 ('+', '__add__', '__radd__'),
597 ('-', '__sub__', '__rsub__'),
598 ('*', '__mul__', '__rmul__'),
Thomas Woutersdcc6d322006-04-21 11:30:52 +0000599 ('/', '__truediv__', '__rtruediv__'),
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000600 ('%', '__mod__', '__rmod__'),
601 ('//', '__floordiv__', '__rfloordiv__'),
602 ('**', '__pow__', '__rpow__')
603 ]
Raymond Hettinger267b8682005-03-27 10:47:39 +0000604
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000605 for sym, lop, rop in oplist:
Raymond Hettinger267b8682005-03-27 10:47:39 +0000606 setattr(E, lop, lambda self, other: 'str' + lop + str(other))
607 setattr(E, rop, lambda self, other: str(other) + rop + 'str')
608 self.assertEqual(eval('E()' + sym + 'Decimal(10)'),
609 'str' + lop + '10')
610 self.assertEqual(eval('Decimal(10)' + sym + 'E()'),
611 '10' + rop + 'str')
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000612
Mark Dickinson79f52032009-03-17 23:12:51 +0000613
Christian Heimesf16baeb2008-02-29 14:57:44 +0000614class DecimalFormatTest(unittest.TestCase):
615 '''Unit tests for the format function.'''
616 def test_formatting(self):
617 # triples giving a format, a Decimal, and the expected result
618 test_values = [
619 ('e', '0E-15', '0e-15'),
620 ('e', '2.3E-15', '2.3e-15'),
621 ('e', '2.30E+2', '2.30e+2'), # preserve significant zeros
622 ('e', '2.30000E-15', '2.30000e-15'),
623 ('e', '1.23456789123456789e40', '1.23456789123456789e+40'),
624 ('e', '1.5', '1.5e+0'),
625 ('e', '0.15', '1.5e-1'),
626 ('e', '0.015', '1.5e-2'),
627 ('e', '0.0000000000015', '1.5e-12'),
628 ('e', '15.0', '1.50e+1'),
629 ('e', '-15', '-1.5e+1'),
630 ('e', '0', '0e+0'),
631 ('e', '0E1', '0e+1'),
632 ('e', '0.0', '0e-1'),
633 ('e', '0.00', '0e-2'),
634 ('.6e', '0E-15', '0.000000e-9'),
635 ('.6e', '0', '0.000000e+6'),
636 ('.6e', '9.999999', '9.999999e+0'),
637 ('.6e', '9.9999999', '1.000000e+1'),
638 ('.6e', '-1.23e5', '-1.230000e+5'),
639 ('.6e', '1.23456789e-3', '1.234568e-3'),
640 ('f', '0', '0'),
641 ('f', '0.0', '0.0'),
642 ('f', '0E-2', '0.00'),
643 ('f', '0.00E-8', '0.0000000000'),
644 ('f', '0E1', '0'), # loses exponent information
645 ('f', '3.2E1', '32'),
646 ('f', '3.2E2', '320'),
647 ('f', '3.20E2', '320'),
648 ('f', '3.200E2', '320.0'),
649 ('f', '3.2E-6', '0.0000032'),
650 ('.6f', '0E-15', '0.000000'), # all zeros treated equally
651 ('.6f', '0E1', '0.000000'),
652 ('.6f', '0', '0.000000'),
653 ('.0f', '0', '0'), # no decimal point
654 ('.0f', '0e-2', '0'),
655 ('.0f', '3.14159265', '3'),
656 ('.1f', '3.14159265', '3.1'),
657 ('.4f', '3.14159265', '3.1416'),
658 ('.6f', '3.14159265', '3.141593'),
659 ('.7f', '3.14159265', '3.1415926'), # round-half-even!
660 ('.8f', '3.14159265', '3.14159265'),
661 ('.9f', '3.14159265', '3.141592650'),
662
663 ('g', '0', '0'),
664 ('g', '0.0', '0.0'),
665 ('g', '0E1', '0e+1'),
666 ('G', '0E1', '0E+1'),
667 ('g', '0E-5', '0.00000'),
668 ('g', '0E-6', '0.000000'),
669 ('g', '0E-7', '0e-7'),
670 ('g', '-0E2', '-0e+2'),
671 ('.0g', '3.14159265', '3'), # 0 sig fig -> 1 sig fig
672 ('.1g', '3.14159265', '3'),
673 ('.2g', '3.14159265', '3.1'),
674 ('.5g', '3.14159265', '3.1416'),
675 ('.7g', '3.14159265', '3.141593'),
676 ('.8g', '3.14159265', '3.1415926'), # round-half-even!
677 ('.9g', '3.14159265', '3.14159265'),
678 ('.10g', '3.14159265', '3.14159265'), # don't pad
679
680 ('%', '0E1', '0%'),
681 ('%', '0E0', '0%'),
682 ('%', '0E-1', '0%'),
683 ('%', '0E-2', '0%'),
684 ('%', '0E-3', '0.0%'),
685 ('%', '0E-4', '0.00%'),
686
687 ('.3%', '0', '0.000%'), # all zeros treated equally
688 ('.3%', '0E10', '0.000%'),
689 ('.3%', '0E-10', '0.000%'),
690 ('.3%', '2.34', '234.000%'),
691 ('.3%', '1.234567', '123.457%'),
692 ('.0%', '1.23', '123%'),
693
694 ('e', 'NaN', 'NaN'),
695 ('f', '-NaN123', '-NaN123'),
696 ('+g', 'NaN456', '+NaN456'),
697 ('.3e', 'Inf', 'Infinity'),
698 ('.16f', '-Inf', '-Infinity'),
699 ('.0g', '-sNaN', '-sNaN'),
700
701 ('', '1.00', '1.00'),
Mark Dickinsonad416342009-03-17 18:10:15 +0000702
Mark Dickinson79f52032009-03-17 23:12:51 +0000703 # test alignment and padding
Mark Dickinson46ab5d02009-09-08 20:22:46 +0000704 ('6', '123', ' 123'),
Mark Dickinsonad416342009-03-17 18:10:15 +0000705 ('<6', '123', '123 '),
706 ('>6', '123', ' 123'),
707 ('^6', '123', ' 123 '),
708 ('=+6', '123', '+ 123'),
Mark Dickinson79f52032009-03-17 23:12:51 +0000709 ('#<10', 'NaN', 'NaN#######'),
710 ('#<10', '-4.3', '-4.3######'),
711 ('#<+10', '0.0130', '+0.0130###'),
712 ('#< 10', '0.0130', ' 0.0130###'),
713 ('@>10', '-Inf', '@-Infinity'),
714 ('#>5', '-Inf', '-Infinity'),
715 ('?^5', '123', '?123?'),
716 ('%^6', '123', '%123%%'),
717 (' ^6', '-45.6', '-45.6 '),
718 ('/=10', '-45.6', '-/////45.6'),
719 ('/=+10', '45.6', '+/////45.6'),
720 ('/= 10', '45.6', ' /////45.6'),
721
722 # thousands separator
723 (',', '1234567', '1,234,567'),
724 (',', '123456', '123,456'),
725 (',', '12345', '12,345'),
726 (',', '1234', '1,234'),
727 (',', '123', '123'),
728 (',', '12', '12'),
729 (',', '1', '1'),
730 (',', '0', '0'),
731 (',', '-1234567', '-1,234,567'),
732 (',', '-123456', '-123,456'),
733 ('7,', '123456', '123,456'),
Mark Dickinson46ab5d02009-09-08 20:22:46 +0000734 ('8,', '123456', ' 123,456'),
Mark Dickinson79f52032009-03-17 23:12:51 +0000735 ('08,', '123456', '0,123,456'), # special case: extra 0 needed
736 ('+08,', '123456', '+123,456'), # but not if there's a sign
737 (' 08,', '123456', ' 123,456'),
738 ('08,', '-123456', '-123,456'),
739 ('+09,', '123456', '+0,123,456'),
740 # ... with fractional part...
741 ('07,', '1234.56', '1,234.56'),
742 ('08,', '1234.56', '1,234.56'),
743 ('09,', '1234.56', '01,234.56'),
744 ('010,', '1234.56', '001,234.56'),
745 ('011,', '1234.56', '0,001,234.56'),
746 ('012,', '1234.56', '0,001,234.56'),
747 ('08,.1f', '1234.5', '01,234.5'),
748 # no thousands separators in fraction part
749 (',', '1.23456789', '1.23456789'),
750 (',%', '123.456789', '12,345.6789%'),
751 (',e', '123456', '1.23456e+5'),
752 (',E', '123456', '1.23456E+5'),
Mark Dickinson7718d2b2009-09-07 16:21:56 +0000753
754 # issue 6850
755 ('a=-7.0', '0.12345', 'aaaa0.1'),
Christian Heimesf16baeb2008-02-29 14:57:44 +0000756 ]
757 for fmt, d, result in test_values:
758 self.assertEqual(format(Decimal(d), fmt), result)
759
Mark Dickinson79f52032009-03-17 23:12:51 +0000760 def test_n_format(self):
761 try:
762 from locale import CHAR_MAX
763 except ImportError:
764 return
765
766 # Set up some localeconv-like dictionaries
767 en_US = {
768 'decimal_point' : '.',
769 'grouping' : [3, 3, 0],
770 'thousands_sep': ','
771 }
772
773 fr_FR = {
774 'decimal_point' : ',',
775 'grouping' : [CHAR_MAX],
776 'thousands_sep' : ''
777 }
778
779 ru_RU = {
780 'decimal_point' : ',',
781 'grouping' : [3, 3, 0],
782 'thousands_sep' : ' '
783 }
784
785 crazy = {
786 'decimal_point' : '&',
787 'grouping' : [1, 4, 2, CHAR_MAX],
788 'thousands_sep' : '-'
789 }
790
791
792 def get_fmt(x, locale, fmt='n'):
793 return Decimal.__format__(Decimal(x), fmt, _localeconv=locale)
794
795 self.assertEqual(get_fmt(Decimal('12.7'), en_US), '12.7')
796 self.assertEqual(get_fmt(Decimal('12.7'), fr_FR), '12,7')
797 self.assertEqual(get_fmt(Decimal('12.7'), ru_RU), '12,7')
798 self.assertEqual(get_fmt(Decimal('12.7'), crazy), '1-2&7')
799
800 self.assertEqual(get_fmt(123456789, en_US), '123,456,789')
801 self.assertEqual(get_fmt(123456789, fr_FR), '123456789')
802 self.assertEqual(get_fmt(123456789, ru_RU), '123 456 789')
803 self.assertEqual(get_fmt(1234567890123, crazy), '123456-78-9012-3')
804
805 self.assertEqual(get_fmt(123456789, en_US, '.6n'), '1.23457e+8')
806 self.assertEqual(get_fmt(123456789, fr_FR, '.6n'), '1,23457e+8')
807 self.assertEqual(get_fmt(123456789, ru_RU, '.6n'), '1,23457e+8')
808 self.assertEqual(get_fmt(123456789, crazy, '.6n'), '1&23457e+8')
809
Mark Dickinson7303b592009-03-18 08:25:36 +0000810 # zero padding
811 self.assertEqual(get_fmt(1234, fr_FR, '03n'), '1234')
812 self.assertEqual(get_fmt(1234, fr_FR, '04n'), '1234')
813 self.assertEqual(get_fmt(1234, fr_FR, '05n'), '01234')
814 self.assertEqual(get_fmt(1234, fr_FR, '06n'), '001234')
815
816 self.assertEqual(get_fmt(12345, en_US, '05n'), '12,345')
817 self.assertEqual(get_fmt(12345, en_US, '06n'), '12,345')
818 self.assertEqual(get_fmt(12345, en_US, '07n'), '012,345')
819 self.assertEqual(get_fmt(12345, en_US, '08n'), '0,012,345')
820 self.assertEqual(get_fmt(12345, en_US, '09n'), '0,012,345')
821 self.assertEqual(get_fmt(12345, en_US, '010n'), '00,012,345')
822
823 self.assertEqual(get_fmt(123456, crazy, '06n'), '1-2345-6')
824 self.assertEqual(get_fmt(123456, crazy, '07n'), '1-2345-6')
825 self.assertEqual(get_fmt(123456, crazy, '08n'), '1-2345-6')
826 self.assertEqual(get_fmt(123456, crazy, '09n'), '01-2345-6')
827 self.assertEqual(get_fmt(123456, crazy, '010n'), '0-01-2345-6')
828 self.assertEqual(get_fmt(123456, crazy, '011n'), '0-01-2345-6')
829 self.assertEqual(get_fmt(123456, crazy, '012n'), '00-01-2345-6')
830 self.assertEqual(get_fmt(123456, crazy, '013n'), '000-01-2345-6')
831
Mark Dickinson79f52032009-03-17 23:12:51 +0000832
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000833class DecimalArithmeticOperatorsTest(unittest.TestCase):
834 '''Unit tests for all arithmetic operators, binary and unary.'''
835
836 def test_addition(self):
837
838 d1 = Decimal('-11.1')
839 d2 = Decimal('22.2')
840
841 #two Decimals
842 self.assertEqual(d1+d2, Decimal('11.1'))
843 self.assertEqual(d2+d1, Decimal('11.1'))
844
845 #with other type, left
846 c = d1 + 5
847 self.assertEqual(c, Decimal('-6.1'))
848 self.assertEqual(type(c), type(d1))
849
850 #with other type, right
851 c = 5 + d1
852 self.assertEqual(c, Decimal('-6.1'))
853 self.assertEqual(type(c), type(d1))
854
855 #inline with decimal
856 d1 += d2
857 self.assertEqual(d1, Decimal('11.1'))
858
859 #inline with other type
860 d1 += 5
861 self.assertEqual(d1, Decimal('16.1'))
862
863 def test_subtraction(self):
864
865 d1 = Decimal('-11.1')
866 d2 = Decimal('22.2')
867
868 #two Decimals
869 self.assertEqual(d1-d2, Decimal('-33.3'))
870 self.assertEqual(d2-d1, Decimal('33.3'))
871
872 #with other type, left
873 c = d1 - 5
874 self.assertEqual(c, Decimal('-16.1'))
875 self.assertEqual(type(c), type(d1))
876
877 #with other type, right
878 c = 5 - d1
879 self.assertEqual(c, Decimal('16.1'))
880 self.assertEqual(type(c), type(d1))
881
882 #inline with decimal
883 d1 -= d2
884 self.assertEqual(d1, Decimal('-33.3'))
885
886 #inline with other type
887 d1 -= 5
888 self.assertEqual(d1, Decimal('-38.3'))
889
890 def test_multiplication(self):
891
892 d1 = Decimal('-5')
893 d2 = Decimal('3')
894
895 #two Decimals
896 self.assertEqual(d1*d2, Decimal('-15'))
897 self.assertEqual(d2*d1, Decimal('-15'))
898
899 #with other type, left
900 c = d1 * 5
901 self.assertEqual(c, Decimal('-25'))
902 self.assertEqual(type(c), type(d1))
903
904 #with other type, right
905 c = 5 * d1
906 self.assertEqual(c, Decimal('-25'))
907 self.assertEqual(type(c), type(d1))
908
909 #inline with decimal
910 d1 *= d2
911 self.assertEqual(d1, Decimal('-15'))
912
913 #inline with other type
914 d1 *= 5
915 self.assertEqual(d1, Decimal('-75'))
916
917 def test_division(self):
918
919 d1 = Decimal('-5')
920 d2 = Decimal('2')
921
922 #two Decimals
923 self.assertEqual(d1/d2, Decimal('-2.5'))
924 self.assertEqual(d2/d1, Decimal('-0.4'))
925
926 #with other type, left
927 c = d1 / 4
928 self.assertEqual(c, Decimal('-1.25'))
929 self.assertEqual(type(c), type(d1))
930
931 #with other type, right
932 c = 4 / d1
933 self.assertEqual(c, Decimal('-0.8'))
934 self.assertEqual(type(c), type(d1))
935
936 #inline with decimal
937 d1 /= d2
938 self.assertEqual(d1, Decimal('-2.5'))
939
940 #inline with other type
941 d1 /= 4
942 self.assertEqual(d1, Decimal('-0.625'))
943
944 def test_floor_division(self):
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000945
946 d1 = Decimal('5')
947 d2 = Decimal('2')
948
949 #two Decimals
950 self.assertEqual(d1//d2, Decimal('2'))
951 self.assertEqual(d2//d1, Decimal('0'))
952
953 #with other type, left
954 c = d1 // 4
955 self.assertEqual(c, Decimal('1'))
956 self.assertEqual(type(c), type(d1))
957
958 #with other type, right
959 c = 7 // d1
960 self.assertEqual(c, Decimal('1'))
961 self.assertEqual(type(c), type(d1))
962
963 #inline with decimal
964 d1 //= d2
965 self.assertEqual(d1, Decimal('2'))
966
967 #inline with other type
968 d1 //= 2
969 self.assertEqual(d1, Decimal('1'))
970
971 def test_powering(self):
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000972
973 d1 = Decimal('5')
974 d2 = Decimal('2')
975
976 #two Decimals
977 self.assertEqual(d1**d2, Decimal('25'))
978 self.assertEqual(d2**d1, Decimal('32'))
979
980 #with other type, left
981 c = d1 ** 4
982 self.assertEqual(c, Decimal('625'))
983 self.assertEqual(type(c), type(d1))
984
985 #with other type, right
986 c = 7 ** d1
987 self.assertEqual(c, Decimal('16807'))
988 self.assertEqual(type(c), type(d1))
989
990 #inline with decimal
991 d1 **= d2
992 self.assertEqual(d1, Decimal('25'))
993
994 #inline with other type
995 d1 **= 4
996 self.assertEqual(d1, Decimal('390625'))
997
998 def test_module(self):
999
1000 d1 = Decimal('5')
1001 d2 = Decimal('2')
1002
1003 #two Decimals
1004 self.assertEqual(d1%d2, Decimal('1'))
1005 self.assertEqual(d2%d1, Decimal('2'))
1006
1007 #with other type, left
1008 c = d1 % 4
1009 self.assertEqual(c, Decimal('1'))
1010 self.assertEqual(type(c), type(d1))
1011
1012 #with other type, right
1013 c = 7 % d1
1014 self.assertEqual(c, Decimal('2'))
1015 self.assertEqual(type(c), type(d1))
1016
1017 #inline with decimal
1018 d1 %= d2
1019 self.assertEqual(d1, Decimal('1'))
1020
1021 #inline with other type
1022 d1 %= 4
1023 self.assertEqual(d1, Decimal('1'))
1024
1025 def test_floor_div_module(self):
1026
1027 d1 = Decimal('5')
1028 d2 = Decimal('2')
1029
1030 #two Decimals
1031 (p, q) = divmod(d1, d2)
1032 self.assertEqual(p, Decimal('2'))
1033 self.assertEqual(q, Decimal('1'))
1034 self.assertEqual(type(p), type(d1))
1035 self.assertEqual(type(q), type(d1))
1036
1037 #with other type, left
1038 (p, q) = divmod(d1, 4)
1039 self.assertEqual(p, Decimal('1'))
1040 self.assertEqual(q, Decimal('1'))
1041 self.assertEqual(type(p), type(d1))
1042 self.assertEqual(type(q), type(d1))
1043
1044 #with other type, right
1045 (p, q) = divmod(7, d1)
1046 self.assertEqual(p, Decimal('1'))
1047 self.assertEqual(q, Decimal('2'))
1048 self.assertEqual(type(p), type(d1))
1049 self.assertEqual(type(q), type(d1))
1050
1051 def test_unary_operators(self):
1052 self.assertEqual(+Decimal(45), Decimal(+45)) # +
1053 self.assertEqual(-Decimal(45), Decimal(-45)) # -
1054 self.assertEqual(abs(Decimal(45)), abs(Decimal(-45))) # abs
1055
Christian Heimes77c02eb2008-02-09 02:18:51 +00001056 def test_nan_comparisons(self):
1057 n = Decimal('NaN')
1058 s = Decimal('sNaN')
1059 i = Decimal('Inf')
1060 f = Decimal('2')
1061 for x, y in [(n, n), (n, i), (i, n), (n, f), (f, n),
1062 (s, n), (n, s), (s, i), (i, s), (s, f), (f, s), (s, s)]:
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001063 self.assertTrue(x != y)
1064 self.assertTrue(not (x == y))
1065 self.assertTrue(not (x < y))
1066 self.assertTrue(not (x <= y))
1067 self.assertTrue(not (x > y))
1068 self.assertTrue(not (x >= y))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001069
1070# The following are two functions used to test threading in the next class
1071
1072def thfunc1(cls):
1073 d1 = Decimal(1)
1074 d3 = Decimal(3)
Christian Heimesfe337bf2008-03-23 21:54:12 +00001075 test1 = d1/d3
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001076 cls.synchro.wait()
Christian Heimesfe337bf2008-03-23 21:54:12 +00001077 test2 = d1/d3
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001078 cls.finish1.set()
Christian Heimesfe337bf2008-03-23 21:54:12 +00001079
Christian Heimes81ee3ef2008-05-04 22:42:01 +00001080 cls.assertEqual(test1, Decimal('0.3333333333333333333333333333'))
1081 cls.assertEqual(test2, Decimal('0.3333333333333333333333333333'))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001082 return
1083
1084def thfunc2(cls):
1085 d1 = Decimal(1)
1086 d3 = Decimal(3)
Christian Heimesfe337bf2008-03-23 21:54:12 +00001087 test1 = d1/d3
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001088 thiscontext = getcontext()
1089 thiscontext.prec = 18
Christian Heimesfe337bf2008-03-23 21:54:12 +00001090 test2 = d1/d3
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001091 cls.synchro.set()
1092 cls.finish2.set()
Christian Heimesfe337bf2008-03-23 21:54:12 +00001093
Christian Heimes81ee3ef2008-05-04 22:42:01 +00001094 cls.assertEqual(test1, Decimal('0.3333333333333333333333333333'))
Christian Heimesfe337bf2008-03-23 21:54:12 +00001095 cls.assertEqual(test2, Decimal('0.333333333333333333'))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001096 return
1097
1098
1099class DecimalUseOfContextTest(unittest.TestCase):
1100 '''Unit tests for Use of Context cases in Decimal.'''
1101
Raymond Hettinger7e71fa52004-12-18 19:07:19 +00001102 try:
1103 import threading
1104 except ImportError:
1105 threading = None
1106
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001107 # Take care executing this test from IDLE, there's an issue in threading
1108 # that hangs IDLE and I couldn't find it
1109
1110 def test_threading(self):
1111 #Test the "threading isolation" of a Context.
1112
1113 self.synchro = threading.Event()
1114 self.finish1 = threading.Event()
1115 self.finish2 = threading.Event()
1116
1117 th1 = threading.Thread(target=thfunc1, args=(self,))
1118 th2 = threading.Thread(target=thfunc2, args=(self,))
1119
1120 th1.start()
1121 th2.start()
1122
1123 self.finish1.wait()
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001124 self.finish2.wait()
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001125 return
1126
Raymond Hettinger7e71fa52004-12-18 19:07:19 +00001127 if threading is None:
1128 del test_threading
1129
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001130
1131class DecimalUsabilityTest(unittest.TestCase):
1132 '''Unit tests for Usability cases of Decimal.'''
1133
1134 def test_comparison_operators(self):
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001135
1136 da = Decimal('23.42')
1137 db = Decimal('23.42')
1138 dc = Decimal('45')
1139
1140 #two Decimals
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001141 self.assertTrue(dc > da)
1142 self.assertTrue(dc >= da)
1143 self.assertTrue(da < dc)
1144 self.assertTrue(da <= dc)
Guido van Rossume61fd5b2007-07-11 12:20:59 +00001145 self.assertEqual(da, db)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001146 self.assertTrue(da != dc)
1147 self.assertTrue(da <= db)
1148 self.assertTrue(da >= db)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001149
1150 #a Decimal and an int
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001151 self.assertTrue(dc > 23)
1152 self.assertTrue(23 < dc)
Guido van Rossume61fd5b2007-07-11 12:20:59 +00001153 self.assertEqual(dc, 45)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001154
1155 #a Decimal and uncomparable
Raymond Hettinger0aeac102004-07-05 22:53:03 +00001156 self.assertNotEqual(da, 'ugly')
1157 self.assertNotEqual(da, 32.7)
1158 self.assertNotEqual(da, object())
1159 self.assertNotEqual(da, object)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001160
Raymond Hettinger0aeac102004-07-05 22:53:03 +00001161 # sortable
Guido van Rossumc1f779c2007-07-03 08:25:58 +00001162 a = list(map(Decimal, range(100)))
Raymond Hettinger0aeac102004-07-05 22:53:03 +00001163 b = a[:]
1164 random.shuffle(a)
1165 a.sort()
1166 self.assertEqual(a, b)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001167
1168 def test_copy_and_deepcopy_methods(self):
1169 d = Decimal('43.24')
1170 c = copy.copy(d)
1171 self.assertEqual(id(c), id(d))
1172 dc = copy.deepcopy(d)
1173 self.assertEqual(id(dc), id(d))
1174
1175 def test_hash_method(self):
1176 #just that it's hashable
1177 hash(Decimal(23))
Thomas Wouters8ce81f72007-09-20 18:22:40 +00001178
1179 test_values = [Decimal(sign*(2**m + n))
1180 for m in [0, 14, 15, 16, 17, 30, 31,
1181 32, 33, 62, 63, 64, 65, 66]
1182 for n in range(-10, 10)
1183 for sign in [-1, 1]]
1184 test_values.extend([
1185 Decimal("-0"), # zeros
1186 Decimal("0.00"),
1187 Decimal("-0.000"),
1188 Decimal("0E10"),
1189 Decimal("-0E12"),
1190 Decimal("10.0"), # negative exponent
1191 Decimal("-23.00000"),
1192 Decimal("1230E100"), # positive exponent
1193 Decimal("-4.5678E50"),
1194 # a value for which hash(n) != hash(n % (2**64-1))
1195 # in Python pre-2.6
1196 Decimal(2**64 + 2**32 - 1),
1197 # selection of values which fail with the old (before
1198 # version 2.6) long.__hash__
1199 Decimal("1.634E100"),
1200 Decimal("90.697E100"),
1201 Decimal("188.83E100"),
1202 Decimal("1652.9E100"),
1203 Decimal("56531E100"),
1204 ])
1205
1206 # check that hash(d) == hash(int(d)) for integral values
1207 for value in test_values:
1208 self.assertEqual(hash(value), hash(int(value)))
1209
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001210 #the same hash that to an int
1211 self.assertEqual(hash(Decimal(23)), hash(23))
Raymond Hettingerbea3f6f2005-03-15 04:59:17 +00001212 self.assertRaises(TypeError, hash, Decimal('NaN'))
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001213 self.assertTrue(hash(Decimal('Inf')))
1214 self.assertTrue(hash(Decimal('-Inf')))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001215
Christian Heimes2380ac72008-01-09 00:17:24 +00001216 # check that the value of the hash doesn't depend on the
1217 # current context (issue #1757)
1218 c = getcontext()
1219 old_precision = c.prec
1220 x = Decimal("123456789.1")
1221
1222 c.prec = 6
1223 h1 = hash(x)
1224 c.prec = 10
1225 h2 = hash(x)
1226 c.prec = 16
1227 h3 = hash(x)
1228
1229 self.assertEqual(h1, h2)
1230 self.assertEqual(h1, h3)
1231 c.prec = old_precision
1232
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001233 def test_min_and_max_methods(self):
1234
1235 d1 = Decimal('15.32')
1236 d2 = Decimal('28.5')
1237 l1 = 15
1238 l2 = 28
1239
1240 #between Decimals
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001241 self.assertTrue(min(d1,d2) is d1)
1242 self.assertTrue(min(d2,d1) is d1)
1243 self.assertTrue(max(d1,d2) is d2)
1244 self.assertTrue(max(d2,d1) is d2)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001245
1246 #between Decimal and long
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001247 self.assertTrue(min(d1,l2) is d1)
1248 self.assertTrue(min(l2,d1) is d1)
1249 self.assertTrue(max(l1,d2) is d2)
1250 self.assertTrue(max(d2,l1) is d2)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001251
1252 def test_as_nonzero(self):
1253 #as false
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001254 self.assertFalse(Decimal(0))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001255 #as true
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001256 self.assertTrue(Decimal('0.372'))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001257
1258 def test_tostring_methods(self):
1259 #Test str and repr methods.
1260
1261 d = Decimal('15.32')
1262 self.assertEqual(str(d), '15.32') # str
Christian Heimes68f5fbe2008-02-14 08:27:37 +00001263 self.assertEqual(repr(d), "Decimal('15.32')") # repr
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001264
1265 def test_tonum_methods(self):
1266 #Test float, int and long methods.
1267
1268 d1 = Decimal('66')
1269 d2 = Decimal('15.32')
1270
1271 #int
1272 self.assertEqual(int(d1), 66)
1273 self.assertEqual(int(d2), 15)
1274
1275 #long
Guido van Rossume2a383d2007-01-15 16:59:06 +00001276 self.assertEqual(int(d1), 66)
1277 self.assertEqual(int(d2), 15)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001278
1279 #float
1280 self.assertEqual(float(d1), 66)
1281 self.assertEqual(float(d2), 15.32)
1282
Mark Dickinsonb27406c2008-05-09 13:42:33 +00001283 #floor
1284 test_pairs = [
1285 ('123.00', 123),
1286 ('3.2', 3),
1287 ('3.54', 3),
1288 ('3.899', 3),
1289 ('-2.3', -3),
1290 ('-11.0', -11),
1291 ('0.0', 0),
1292 ('-0E3', 0),
1293 ]
1294 for d, i in test_pairs:
1295 self.assertEqual(math.floor(Decimal(d)), i)
1296 self.assertRaises(ValueError, math.floor, Decimal('-NaN'))
1297 self.assertRaises(ValueError, math.floor, Decimal('sNaN'))
1298 self.assertRaises(ValueError, math.floor, Decimal('NaN123'))
1299 self.assertRaises(OverflowError, math.floor, Decimal('Inf'))
1300 self.assertRaises(OverflowError, math.floor, Decimal('-Inf'))
1301
1302 #ceiling
1303 test_pairs = [
1304 ('123.00', 123),
1305 ('3.2', 4),
1306 ('3.54', 4),
1307 ('3.899', 4),
1308 ('-2.3', -2),
1309 ('-11.0', -11),
1310 ('0.0', 0),
1311 ('-0E3', 0),
1312 ]
1313 for d, i in test_pairs:
1314 self.assertEqual(math.ceil(Decimal(d)), i)
1315 self.assertRaises(ValueError, math.ceil, Decimal('-NaN'))
1316 self.assertRaises(ValueError, math.ceil, Decimal('sNaN'))
1317 self.assertRaises(ValueError, math.ceil, Decimal('NaN123'))
1318 self.assertRaises(OverflowError, math.ceil, Decimal('Inf'))
1319 self.assertRaises(OverflowError, math.ceil, Decimal('-Inf'))
1320
1321 #round, single argument
1322 test_pairs = [
1323 ('123.00', 123),
1324 ('3.2', 3),
1325 ('3.54', 4),
1326 ('3.899', 4),
1327 ('-2.3', -2),
1328 ('-11.0', -11),
1329 ('0.0', 0),
1330 ('-0E3', 0),
1331 ('-3.5', -4),
1332 ('-2.5', -2),
1333 ('-1.5', -2),
1334 ('-0.5', 0),
1335 ('0.5', 0),
1336 ('1.5', 2),
1337 ('2.5', 2),
1338 ('3.5', 4),
1339 ]
1340 for d, i in test_pairs:
1341 self.assertEqual(round(Decimal(d)), i)
1342 self.assertRaises(ValueError, round, Decimal('-NaN'))
1343 self.assertRaises(ValueError, round, Decimal('sNaN'))
1344 self.assertRaises(ValueError, round, Decimal('NaN123'))
1345 self.assertRaises(OverflowError, round, Decimal('Inf'))
1346 self.assertRaises(OverflowError, round, Decimal('-Inf'))
1347
1348 #round, two arguments; this is essentially equivalent
1349 #to quantize, which is already extensively tested
1350 test_triples = [
1351 ('123.456', -4, '0E+4'),
1352 ('123.456', -3, '0E+3'),
1353 ('123.456', -2, '1E+2'),
1354 ('123.456', -1, '1.2E+2'),
1355 ('123.456', 0, '123'),
1356 ('123.456', 1, '123.5'),
1357 ('123.456', 2, '123.46'),
1358 ('123.456', 3, '123.456'),
1359 ('123.456', 4, '123.4560'),
1360 ('123.455', 2, '123.46'),
1361 ('123.445', 2, '123.44'),
1362 ('Inf', 4, 'NaN'),
1363 ('-Inf', -23, 'NaN'),
1364 ('sNaN314', 3, 'NaN314'),
1365 ]
1366 for d, n, r in test_triples:
1367 self.assertEqual(str(round(Decimal(d), n)), r)
1368
1369
1370
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001371 def test_eval_round_trip(self):
1372
1373 #with zero
1374 d = Decimal( (0, (0,), 0) )
1375 self.assertEqual(d, eval(repr(d)))
1376
1377 #int
1378 d = Decimal( (1, (4, 5), 0) )
1379 self.assertEqual(d, eval(repr(d)))
1380
1381 #float
1382 d = Decimal( (0, (4, 5, 3, 4), -2) )
1383 self.assertEqual(d, eval(repr(d)))
1384
1385 #weird
1386 d = Decimal( (1, (4, 3, 4, 9, 1, 3, 5, 3, 4), -25) )
1387 self.assertEqual(d, eval(repr(d)))
1388
1389 def test_as_tuple(self):
1390
1391 #with zero
1392 d = Decimal(0)
1393 self.assertEqual(d.as_tuple(), (0, (0,), 0) )
1394
1395 #int
1396 d = Decimal(-45)
1397 self.assertEqual(d.as_tuple(), (1, (4, 5), 0) )
1398
1399 #complicated string
1400 d = Decimal("-4.34913534E-17")
1401 self.assertEqual(d.as_tuple(), (1, (4, 3, 4, 9, 1, 3, 5, 3, 4), -25) )
1402
1403 #inf
1404 d = Decimal("Infinity")
1405 self.assertEqual(d.as_tuple(), (0, (0,), 'F') )
1406
Guido van Rossum8ce8a782007-11-01 19:42:39 +00001407 #leading zeros in coefficient should be stripped
1408 d = Decimal( (0, (0, 0, 4, 0, 5, 3, 4), -2) )
1409 self.assertEqual(d.as_tuple(), (0, (4, 0, 5, 3, 4), -2) )
1410 d = Decimal( (1, (0, 0, 0), 37) )
1411 self.assertEqual(d.as_tuple(), (1, (0,), 37))
1412 d = Decimal( (1, (), 37) )
1413 self.assertEqual(d.as_tuple(), (1, (0,), 37))
1414
1415 #leading zeros in NaN diagnostic info should be stripped
1416 d = Decimal( (0, (0, 0, 4, 0, 5, 3, 4), 'n') )
1417 self.assertEqual(d.as_tuple(), (0, (4, 0, 5, 3, 4), 'n') )
1418 d = Decimal( (1, (0, 0, 0), 'N') )
1419 self.assertEqual(d.as_tuple(), (1, (), 'N') )
1420 d = Decimal( (1, (), 'n') )
1421 self.assertEqual(d.as_tuple(), (1, (), 'n') )
1422
1423 #coefficient in infinity should be ignored
1424 d = Decimal( (0, (4, 5, 3, 4), 'F') )
1425 self.assertEqual(d.as_tuple(), (0, (0,), 'F'))
1426 d = Decimal( (1, (0, 2, 7, 1), 'F') )
1427 self.assertEqual(d.as_tuple(), (1, (0,), 'F'))
1428
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001429 def test_immutability_operations(self):
1430 # Do operations and check that it didn't change change internal objects.
1431
1432 d1 = Decimal('-25e55')
1433 b1 = Decimal('-25e55')
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001434 d2 = Decimal('33e+33')
1435 b2 = Decimal('33e+33')
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001436
1437 def checkSameDec(operation, useOther=False):
1438 if useOther:
1439 eval("d1." + operation + "(d2)")
1440 self.assertEqual(d1._sign, b1._sign)
1441 self.assertEqual(d1._int, b1._int)
1442 self.assertEqual(d1._exp, b1._exp)
1443 self.assertEqual(d2._sign, b2._sign)
1444 self.assertEqual(d2._int, b2._int)
1445 self.assertEqual(d2._exp, b2._exp)
1446 else:
1447 eval("d1." + operation + "()")
1448 self.assertEqual(d1._sign, b1._sign)
1449 self.assertEqual(d1._int, b1._int)
1450 self.assertEqual(d1._exp, b1._exp)
1451 return
1452
1453 Decimal(d1)
1454 self.assertEqual(d1._sign, b1._sign)
1455 self.assertEqual(d1._int, b1._int)
1456 self.assertEqual(d1._exp, b1._exp)
1457
1458 checkSameDec("__abs__")
1459 checkSameDec("__add__", True)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001460 checkSameDec("__divmod__", True)
Christian Heimes77c02eb2008-02-09 02:18:51 +00001461 checkSameDec("__eq__", True)
1462 checkSameDec("__ne__", True)
1463 checkSameDec("__le__", True)
1464 checkSameDec("__lt__", True)
1465 checkSameDec("__ge__", True)
1466 checkSameDec("__gt__", True)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001467 checkSameDec("__float__")
1468 checkSameDec("__floordiv__", True)
1469 checkSameDec("__hash__")
1470 checkSameDec("__int__")
Christian Heimes969fe572008-01-25 11:23:10 +00001471 checkSameDec("__trunc__")
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001472 checkSameDec("__mod__", True)
1473 checkSameDec("__mul__", True)
1474 checkSameDec("__neg__")
Jack Diederich4dafcc42006-11-28 19:15:13 +00001475 checkSameDec("__bool__")
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001476 checkSameDec("__pos__")
1477 checkSameDec("__pow__", True)
1478 checkSameDec("__radd__", True)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001479 checkSameDec("__rdivmod__", True)
1480 checkSameDec("__repr__")
1481 checkSameDec("__rfloordiv__", True)
1482 checkSameDec("__rmod__", True)
1483 checkSameDec("__rmul__", True)
1484 checkSameDec("__rpow__", True)
1485 checkSameDec("__rsub__", True)
1486 checkSameDec("__str__")
1487 checkSameDec("__sub__", True)
1488 checkSameDec("__truediv__", True)
1489 checkSameDec("adjusted")
1490 checkSameDec("as_tuple")
1491 checkSameDec("compare", True)
1492 checkSameDec("max", True)
1493 checkSameDec("min", True)
1494 checkSameDec("normalize")
1495 checkSameDec("quantize", True)
1496 checkSameDec("remainder_near", True)
1497 checkSameDec("same_quantum", True)
1498 checkSameDec("sqrt")
1499 checkSameDec("to_eng_string")
1500 checkSameDec("to_integral")
1501
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001502 def test_subclassing(self):
1503 # Different behaviours when subclassing Decimal
1504
1505 class MyDecimal(Decimal):
1506 pass
1507
1508 d1 = MyDecimal(1)
1509 d2 = MyDecimal(2)
1510 d = d1 + d2
1511 self.assertTrue(type(d) is Decimal)
1512
1513 d = d1.max(d2)
1514 self.assertTrue(type(d) is Decimal)
1515
Christian Heimes0348fb62008-03-26 12:55:56 +00001516 def test_implicit_context(self):
1517 # Check results when context given implicitly. (Issue 2478)
1518 c = getcontext()
1519 self.assertEqual(str(Decimal(0).sqrt()),
1520 str(c.sqrt(Decimal(0))))
1521
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001522
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001523class DecimalPythonAPItests(unittest.TestCase):
1524
Raymond Hettinger82417ca2009-02-03 03:54:28 +00001525 def test_abc(self):
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001526 self.assertTrue(issubclass(Decimal, numbers.Number))
1527 self.assertTrue(not issubclass(Decimal, numbers.Real))
1528 self.assertTrue(isinstance(Decimal(0), numbers.Number))
1529 self.assertTrue(not isinstance(Decimal(0), numbers.Real))
Raymond Hettinger82417ca2009-02-03 03:54:28 +00001530
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001531 def test_pickle(self):
1532 d = Decimal('-3.141590000')
1533 p = pickle.dumps(d)
1534 e = pickle.loads(p)
1535 self.assertEqual(d, e)
1536
Raymond Hettinger5548be22004-07-05 18:49:38 +00001537 def test_int(self):
Raymond Hettinger605ed022004-11-24 07:28:48 +00001538 for x in range(-250, 250):
1539 s = '%0.2f' % (x / 100.0)
Raymond Hettinger5548be22004-07-05 18:49:38 +00001540 # should work the same as for floats
1541 self.assertEqual(int(Decimal(s)), int(float(s)))
Raymond Hettinger605ed022004-11-24 07:28:48 +00001542 # should work the same as to_integral in the ROUND_DOWN mode
Raymond Hettinger5548be22004-07-05 18:49:38 +00001543 d = Decimal(s)
Raymond Hettinger605ed022004-11-24 07:28:48 +00001544 r = d.to_integral(ROUND_DOWN)
Raymond Hettinger5548be22004-07-05 18:49:38 +00001545 self.assertEqual(Decimal(int(d)), r)
1546
Mark Dickinson825fce32009-09-07 18:08:12 +00001547 self.assertRaises(ValueError, int, Decimal('-nan'))
1548 self.assertRaises(ValueError, int, Decimal('snan'))
1549 self.assertRaises(OverflowError, int, Decimal('inf'))
1550 self.assertRaises(OverflowError, int, Decimal('-inf'))
1551
Christian Heimes969fe572008-01-25 11:23:10 +00001552 def test_trunc(self):
1553 for x in range(-250, 250):
1554 s = '%0.2f' % (x / 100.0)
1555 # should work the same as for floats
1556 self.assertEqual(int(Decimal(s)), int(float(s)))
1557 # should work the same as to_integral in the ROUND_DOWN mode
1558 d = Decimal(s)
1559 r = d.to_integral(ROUND_DOWN)
Christian Heimes400adb02008-02-01 08:12:03 +00001560 self.assertEqual(Decimal(math.trunc(d)), r)
Christian Heimes969fe572008-01-25 11:23:10 +00001561
Raymond Hettinger771ed762009-01-03 19:20:32 +00001562 def test_from_float(self):
1563
1564 class MyDecimal(Decimal):
1565 pass
1566
1567 r = MyDecimal.from_float(0.1)
1568 self.assertEqual(type(r), MyDecimal)
1569 self.assertEqual(str(r),
1570 '0.1000000000000000055511151231257827021181583404541015625')
1571 bigint = 12345678901234567890123456789
1572 self.assertEqual(MyDecimal.from_float(bigint), MyDecimal(bigint))
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001573 self.assertTrue(MyDecimal.from_float(float('nan')).is_qnan())
1574 self.assertTrue(MyDecimal.from_float(float('inf')).is_infinite())
1575 self.assertTrue(MyDecimal.from_float(float('-inf')).is_infinite())
Raymond Hettinger771ed762009-01-03 19:20:32 +00001576 self.assertEqual(str(MyDecimal.from_float(float('nan'))),
1577 str(Decimal('NaN')))
1578 self.assertEqual(str(MyDecimal.from_float(float('inf'))),
1579 str(Decimal('Infinity')))
1580 self.assertEqual(str(MyDecimal.from_float(float('-inf'))),
1581 str(Decimal('-Infinity')))
1582 self.assertRaises(TypeError, MyDecimal.from_float, 'abc')
1583 for i in range(200):
1584 x = random.expovariate(0.01) * (random.random() * 2.0 - 1.0)
1585 self.assertEqual(x, float(MyDecimal.from_float(x))) # roundtrip
1586
1587 def test_create_decimal_from_float(self):
1588 context = Context(prec=5, rounding=ROUND_DOWN)
1589 self.assertEqual(
1590 context.create_decimal_from_float(math.pi),
1591 Decimal('3.1415')
1592 )
1593 context = Context(prec=5, rounding=ROUND_UP)
1594 self.assertEqual(
1595 context.create_decimal_from_float(math.pi),
1596 Decimal('3.1416')
1597 )
1598 context = Context(prec=5, traps=[Inexact])
1599 self.assertRaises(
1600 Inexact,
1601 context.create_decimal_from_float,
1602 math.pi
1603 )
1604 self.assertEqual(repr(context.create_decimal_from_float(-0.0)),
1605 "Decimal('-0')")
1606 self.assertEqual(repr(context.create_decimal_from_float(1.0)),
1607 "Decimal('1')")
1608 self.assertEqual(repr(context.create_decimal_from_float(10)),
1609 "Decimal('10')")
1610
Raymond Hettingerd9c0a7a2004-07-03 10:02:28 +00001611class ContextAPItests(unittest.TestCase):
1612
1613 def test_pickle(self):
1614 c = Context()
1615 e = pickle.loads(pickle.dumps(c))
1616 for k in vars(c):
1617 v1 = vars(c)[k]
1618 v2 = vars(e)[k]
1619 self.assertEqual(v1, v2)
1620
Raymond Hettinger0aeac102004-07-05 22:53:03 +00001621 def test_equality_with_other_types(self):
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001622 self.assertTrue(Decimal(10) in ['a', 1.0, Decimal(10), (1,2), {}])
1623 self.assertTrue(Decimal(10) not in ['a', 1.0, (1,2), {}])
Raymond Hettinger0aeac102004-07-05 22:53:03 +00001624
Raymond Hettinger955d2b22004-08-08 20:17:45 +00001625 def test_copy(self):
1626 # All copies should be deep
1627 c = Context()
1628 d = c.copy()
1629 self.assertNotEqual(id(c), id(d))
1630 self.assertNotEqual(id(c.flags), id(d.flags))
1631 self.assertNotEqual(id(c.traps), id(d.traps))
1632
Thomas Wouters89f507f2006-12-13 04:49:30 +00001633class WithStatementTest(unittest.TestCase):
1634 # Can't do these as docstrings until Python 2.6
1635 # as doctest can't handle __future__ statements
1636
1637 def test_localcontext(self):
1638 # Use a copy of the current context in the block
1639 orig_ctx = getcontext()
1640 with localcontext() as enter_ctx:
1641 set_ctx = getcontext()
1642 final_ctx = getcontext()
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001643 self.assertTrue(orig_ctx is final_ctx, 'did not restore context correctly')
1644 self.assertTrue(orig_ctx is not set_ctx, 'did not copy the context')
1645 self.assertTrue(set_ctx is enter_ctx, '__enter__ returned wrong context')
Thomas Wouters89f507f2006-12-13 04:49:30 +00001646
1647 def test_localcontextarg(self):
1648 # Use a copy of the supplied context in the block
1649 orig_ctx = getcontext()
1650 new_ctx = Context(prec=42)
1651 with localcontext(new_ctx) as enter_ctx:
1652 set_ctx = getcontext()
1653 final_ctx = getcontext()
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001654 self.assertTrue(orig_ctx is final_ctx, 'did not restore context correctly')
1655 self.assertTrue(set_ctx.prec == new_ctx.prec, 'did not set correct context')
1656 self.assertTrue(new_ctx is not set_ctx, 'did not copy the context')
1657 self.assertTrue(set_ctx is enter_ctx, '__enter__ returned wrong context')
Thomas Wouters89f507f2006-12-13 04:49:30 +00001658
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001659class ContextFlags(unittest.TestCase):
1660 def test_flags_irrelevant(self):
1661 # check that the result (numeric result + flags raised) of an
1662 # arithmetic operation doesn't depend on the current flags
1663
1664 context = Context(prec=9, Emin = -999999999, Emax = 999999999,
1665 rounding=ROUND_HALF_EVEN, traps=[], flags=[])
1666
1667 # operations that raise various flags, in the form (function, arglist)
1668 operations = [
1669 (context._apply, [Decimal("100E-1000000009")]),
1670 (context.sqrt, [Decimal(2)]),
1671 (context.add, [Decimal("1.23456789"), Decimal("9.87654321")]),
1672 (context.multiply, [Decimal("1.23456789"), Decimal("9.87654321")]),
1673 (context.subtract, [Decimal("1.23456789"), Decimal("9.87654321")]),
1674 ]
1675
1676 # try various flags individually, then a whole lot at once
1677 flagsets = [[Inexact], [Rounded], [Underflow], [Clamped], [Subnormal],
1678 [Inexact, Rounded, Underflow, Clamped, Subnormal]]
1679
1680 for fn, args in operations:
1681 # find answer and flags raised using a clean context
1682 context.clear_flags()
1683 ans = fn(*args)
1684 flags = [k for k, v in context.flags.items() if v]
1685
1686 for extra_flags in flagsets:
1687 # set flags, before calling operation
1688 context.clear_flags()
1689 for flag in extra_flags:
1690 context._raise_error(flag)
1691 new_ans = fn(*args)
1692
1693 # flags that we expect to be set after the operation
1694 expected_flags = list(flags)
1695 for flag in extra_flags:
1696 if flag not in expected_flags:
1697 expected_flags.append(flag)
1698 expected_flags.sort(key=id)
1699
1700 # flags we actually got
1701 new_flags = [k for k,v in context.flags.items() if v]
1702 new_flags.sort(key=id)
1703
1704 self.assertEqual(ans, new_ans,
1705 "operation produces different answers depending on flags set: " +
1706 "expected %s, got %s." % (ans, new_ans))
1707 self.assertEqual(new_flags, expected_flags,
1708 "operation raises different flags depending on flags set: " +
1709 "expected %s, got %s" % (expected_flags, new_flags))
1710
1711def test_main(arith=False, verbose=None, todo_tests=None, debug=None):
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001712 """ Execute the tests.
1713
Raymond Hettingered20ad82004-09-04 20:09:13 +00001714 Runs all arithmetic tests if arith is True or if the "decimal" resource
1715 is enabled in regrtest.py
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001716 """
Raymond Hettingered20ad82004-09-04 20:09:13 +00001717
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00001718 init()
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001719 global TEST_ALL, DEBUG
Raymond Hettingered20ad82004-09-04 20:09:13 +00001720 TEST_ALL = arith or is_resource_enabled('decimal')
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001721 DEBUG = debug
Raymond Hettingered20ad82004-09-04 20:09:13 +00001722
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001723 if todo_tests is None:
1724 test_classes = [
1725 DecimalExplicitConstructionTest,
1726 DecimalImplicitConstructionTest,
1727 DecimalArithmeticOperatorsTest,
Christian Heimesf16baeb2008-02-29 14:57:44 +00001728 DecimalFormatTest,
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001729 DecimalUseOfContextTest,
1730 DecimalUsabilityTest,
1731 DecimalPythonAPItests,
1732 ContextAPItests,
1733 DecimalTest,
1734 WithStatementTest,
1735 ContextFlags
1736 ]
1737 else:
1738 test_classes = [DecimalTest]
1739
1740 # Dynamically build custom test definition for each file in the test
1741 # directory and add the definitions to the DecimalTest class. This
1742 # procedure insures that new files do not get skipped.
1743 for filename in os.listdir(directory):
1744 if '.decTest' not in filename or filename.startswith("."):
1745 continue
1746 head, tail = filename.split('.')
1747 if todo_tests is not None and head not in todo_tests:
1748 continue
1749 tester = lambda self, f=filename: self.eval_file(directory + f)
1750 setattr(DecimalTest, 'test_' + head, tester)
1751 del filename, head, tail, tester
1752
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001753
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00001754 try:
1755 run_unittest(*test_classes)
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001756 if todo_tests is None:
1757 import decimal as DecimalModule
1758 run_doctest(DecimalModule, verbose)
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00001759 finally:
1760 setcontext(ORIGINAL_CONTEXT)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001761
1762if __name__ == '__main__':
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001763 import optparse
1764 p = optparse.OptionParser("test_decimal.py [--debug] [{--skip | test1 [test2 [...]]}]")
1765 p.add_option('--debug', '-d', action='store_true', help='shows the test number and context before each test')
1766 p.add_option('--skip', '-s', action='store_true', help='skip over 90% of the arithmetic tests')
1767 (opt, args) = p.parse_args()
1768
1769 if opt.skip:
1770 test_main(arith=False, verbose=True)
1771 elif args:
1772 test_main(arith=True, verbose=True, todo_tests=args, debug=opt.debug)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001773 else:
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001774 test_main(arith=True, verbose=True)