blob: ce6acb677d76ad7e17b0700843e4d3c538a3a80e [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"""
Nick Coghlan8b6999b2006-08-31 12:00:43 +000026from __future__ import with_statement
Raymond Hettinger7c85fa42004-07-01 11:01:35 +000027
Raymond Hettinger7c85fa42004-07-01 11:01:35 +000028import glob
Jeffrey Yasskinca2b69f2008-02-01 06:22:46 +000029import math
Raymond Hettinger7c85fa42004-07-01 11:01:35 +000030import os, sys
31import pickle, copy
Jeffrey Yasskinca2b69f2008-02-01 06:22:46 +000032import unittest
Raymond Hettinger7c85fa42004-07-01 11:01:35 +000033from decimal import *
Tim Peters46cc7022006-03-31 04:11:16 +000034from test.test_support import (TestSkipped, run_unittest, run_doctest,
35 is_resource_enabled)
Raymond Hettinger0aeac102004-07-05 22:53:03 +000036import random
Raymond Hettinger7e71fa52004-12-18 19:07:19 +000037try:
38 import threading
39except ImportError:
40 threading = None
Raymond Hettinger7c85fa42004-07-01 11:01:35 +000041
Raymond Hettingerfed52962004-07-14 15:41:57 +000042# Useful Test Constant
43Signals = getcontext().flags.keys()
44
Tim Peters46cc7022006-03-31 04:11:16 +000045# Tests are built around these assumed context defaults.
46# test_main() restores the original context.
Neal Norwitzce4a9c92006-04-09 08:36:46 +000047def init():
48 global ORIGINAL_CONTEXT
49 ORIGINAL_CONTEXT = getcontext().copy()
50 DefaultContext.prec = 9
51 DefaultContext.rounding = ROUND_HALF_EVEN
52 DefaultContext.traps = dict.fromkeys(Signals, 0)
53 setcontext(DefaultContext)
Raymond Hettinger6ea48452004-07-03 12:26:21 +000054
Raymond Hettinger7c85fa42004-07-01 11:01:35 +000055TESTDATADIR = 'decimaltestdata'
Raymond Hettingerd9c0a7a2004-07-03 10:02:28 +000056if __name__ == '__main__':
57 file = sys.argv[0]
58else:
59 file = __file__
60testdir = os.path.dirname(file) or os.curdir
Raymond Hettinger267b8682005-03-27 10:47:39 +000061directory = testdir + os.sep + TESTDATADIR + os.sep
Raymond Hettinger7c85fa42004-07-01 11:01:35 +000062
Raymond Hettinger267b8682005-03-27 10:47:39 +000063skip_expected = not os.path.isdir(directory)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +000064
65# Make sure it actually raises errors when not expected and caught in flags
66# Slower, since it runs some things several times.
67EXTENDEDERRORTEST = False
68
Raymond Hettinger7c85fa42004-07-01 11:01:35 +000069#Map the test cases' error names to the actual errors
Raymond Hettinger7c85fa42004-07-01 11:01:35 +000070ErrorNames = {'clamped' : Clamped,
Raymond Hettinger5aa478b2004-07-09 10:02:53 +000071 'conversion_syntax' : InvalidOperation,
Raymond Hettinger7c85fa42004-07-01 11:01:35 +000072 'division_by_zero' : DivisionByZero,
Raymond Hettinger5aa478b2004-07-09 10:02:53 +000073 'division_impossible' : InvalidOperation,
74 'division_undefined' : InvalidOperation,
Raymond Hettinger7c85fa42004-07-01 11:01:35 +000075 'inexact' : Inexact,
Raymond Hettinger5aa478b2004-07-09 10:02:53 +000076 'invalid_context' : InvalidOperation,
Raymond Hettinger7c85fa42004-07-01 11:01:35 +000077 'invalid_operation' : InvalidOperation,
78 'overflow' : Overflow,
79 'rounded' : Rounded,
80 'subnormal' : Subnormal,
81 'underflow' : Underflow}
82
83
84def Nonfunction(*args):
85 """Doesn't do anything."""
86 return None
87
88RoundingDict = {'ceiling' : ROUND_CEILING, #Maps test-case names to roundings.
89 'down' : ROUND_DOWN,
90 'floor' : ROUND_FLOOR,
91 'half_down' : ROUND_HALF_DOWN,
92 'half_even' : ROUND_HALF_EVEN,
93 'half_up' : ROUND_HALF_UP,
Facundo Batista353750c2007-09-13 18:13:15 +000094 'up' : ROUND_UP,
95 '05up' : ROUND_05UP}
Raymond Hettinger7c85fa42004-07-01 11:01:35 +000096
97# Name adapter to be able to change the Decimal and Context
98# interface without changing the test files from Cowlishaw
Facundo Batista1a191df2007-10-02 17:01:24 +000099nameAdapter = {'and':'logical_and',
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000100 'apply':'_apply',
Facundo Batista353750c2007-09-13 18:13:15 +0000101 'class':'number_class',
102 'comparesig':'compare_signal',
103 'comparetotal':'compare_total',
104 'comparetotmag':'compare_total_mag',
Facundo Batista353750c2007-09-13 18:13:15 +0000105 'copy':'copy_decimal',
Facundo Batista1a191df2007-10-02 17:01:24 +0000106 'copyabs':'copy_abs',
Facundo Batista353750c2007-09-13 18:13:15 +0000107 'copynegate':'copy_negate',
108 'copysign':'copy_sign',
Facundo Batista1a191df2007-10-02 17:01:24 +0000109 'divideint':'divide_int',
Facundo Batista353750c2007-09-13 18:13:15 +0000110 'invert':'logical_invert',
Facundo Batista1a191df2007-10-02 17:01:24 +0000111 'iscanonical':'is_canonical',
112 'isfinite':'is_finite',
113 'isinfinite':'is_infinite',
114 'isnan':'is_nan',
115 'isnormal':'is_normal',
116 'isqnan':'is_qnan',
117 'issigned':'is_signed',
118 'issnan':'is_snan',
119 'issubnormal':'is_subnormal',
120 'iszero':'is_zero',
Facundo Batista353750c2007-09-13 18:13:15 +0000121 'maxmag':'max_mag',
122 'minmag':'min_mag',
123 'nextminus':'next_minus',
124 'nextplus':'next_plus',
125 'nexttoward':'next_toward',
Facundo Batista1a191df2007-10-02 17:01:24 +0000126 'or':'logical_or',
Facundo Batista353750c2007-09-13 18:13:15 +0000127 'reduce':'normalize',
Facundo Batista1a191df2007-10-02 17:01:24 +0000128 'remaindernear':'remainder_near',
129 'samequantum':'same_quantum',
130 'squareroot':'sqrt',
131 'toeng':'to_eng_string',
132 'tointegral':'to_integral_value',
133 'tointegralx':'to_integral_exact',
134 'tosci':'to_sci_string',
135 'xor':'logical_xor',
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000136 }
137
Facundo Batista1a191df2007-10-02 17:01:24 +0000138# The following functions return True/False rather than a Decimal instance
139
140LOGICAL_FUNCTIONS = (
141 'is_canonical',
142 'is_finite',
143 'is_infinite',
144 'is_nan',
145 'is_normal',
146 'is_qnan',
147 'is_signed',
148 'is_snan',
149 'is_subnormal',
150 'is_zero',
151 'same_quantum',
152 )
153
Facundo Batista353750c2007-09-13 18:13:15 +0000154# For some operations (currently exp, ln, log10, power), the decNumber
155# reference implementation imposes additional restrictions on the
156# context and operands. These restrictions are not part of the
157# specification; however, the effect of these restrictions does show
158# up in some of the testcases. We skip testcases that violate these
159# restrictions, since Decimal behaves differently from decNumber for
160# these testcases so these testcases would otherwise fail.
161
162decNumberRestricted = ('power', 'ln', 'log10', 'exp')
163DEC_MAX_MATH = 999999
164def outside_decNumber_bounds(v, context):
165 if (context.prec > DEC_MAX_MATH or
166 context.Emax > DEC_MAX_MATH or
167 -context.Emin > DEC_MAX_MATH):
168 return True
169 if not v._is_special and v and (
170 len(v._int) > DEC_MAX_MATH or
171 v.adjusted() > DEC_MAX_MATH or
172 v.adjusted() < 1-2*DEC_MAX_MATH):
173 return True
174 return False
175
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000176class DecimalTest(unittest.TestCase):
177 """Class which tests the Decimal class against the test cases.
178
179 Changed for unittest.
180 """
181 def setUp(self):
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000182 self.context = Context()
Raymond Hettingerbf440692004-07-10 14:14:37 +0000183 for key in DefaultContext.traps.keys():
184 DefaultContext.traps[key] = 1
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000185 self.ignore_list = ['#']
186 # Basically, a # means return NaN InvalidOperation.
187 # Different from a sNaN in trim
188
189 self.ChangeDict = {'precision' : self.change_precision,
190 'rounding' : self.change_rounding_method,
191 'maxexponent' : self.change_max_exponent,
192 'minexponent' : self.change_min_exponent,
193 'clamp' : self.change_clamp}
194
195 def tearDown(self):
196 """Cleaning up enviroment."""
197 # leaving context in original state
Raymond Hettingerbf440692004-07-10 14:14:37 +0000198 for key in DefaultContext.traps.keys():
199 DefaultContext.traps[key] = 0
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000200 return
201
202 def eval_file(self, file):
203 global skip_expected
204 if skip_expected:
205 raise TestSkipped
206 return
207 for line in open(file).xreadlines():
208 line = line.replace('\r\n', '').replace('\n', '')
Raymond Hettinger5aa478b2004-07-09 10:02:53 +0000209 #print line
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000210 try:
211 t = self.eval_line(line)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000212 except DecimalException, exception:
213 #Exception raised where there shoudn't have been one.
214 self.fail('Exception "'+exception.__class__.__name__ + '" raised on line '+line)
215
216 return
217
218 def eval_line(self, s):
219 if s.find(' -> ') >= 0 and s[:2] != '--' and not s.startswith(' --'):
220 s = (s.split('->')[0] + '->' +
221 s.split('->')[1].split('--')[0]).strip()
222 else:
223 s = s.split('--')[0].strip()
224
225 for ignore in self.ignore_list:
226 if s.find(ignore) >= 0:
227 #print s.split()[0], 'NotImplemented--', ignore
228 return
229 if not s:
230 return
231 elif ':' in s:
232 return self.eval_directive(s)
233 else:
234 return self.eval_equation(s)
235
236 def eval_directive(self, s):
237 funct, value = map(lambda x: x.strip().lower(), s.split(':'))
238 if funct == 'rounding':
239 value = RoundingDict[value]
240 else:
241 try:
242 value = int(value)
243 except ValueError:
244 pass
245
246 funct = self.ChangeDict.get(funct, Nonfunction)
247 funct(value)
248
249 def eval_equation(self, s):
250 #global DEFAULT_PRECISION
251 #print DEFAULT_PRECISION
Raymond Hettingered20ad82004-09-04 20:09:13 +0000252
253 if not TEST_ALL and random.random() < 0.90:
254 return
255
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000256 try:
257 Sides = s.split('->')
258 L = Sides[0].strip().split()
259 id = L[0]
Facundo Batista353750c2007-09-13 18:13:15 +0000260 if DEBUG:
261 print "Test ", id,
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000262 funct = L[1].lower()
263 valstemp = L[2:]
264 L = Sides[1].strip().split()
265 ans = L[0]
266 exceptions = L[1:]
267 except (TypeError, AttributeError, IndexError):
Raymond Hettingerd87ac8f2004-07-09 10:52:54 +0000268 raise InvalidOperation
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000269 def FixQuotes(val):
270 val = val.replace("''", 'SingleQuote').replace('""', 'DoubleQuote')
271 val = val.replace("'", '').replace('"', '')
272 val = val.replace('SingleQuote', "'").replace('DoubleQuote', '"')
273 return val
274 fname = nameAdapter.get(funct, funct)
275 if fname == 'rescale':
276 return
277 funct = getattr(self.context, fname)
278 vals = []
279 conglomerate = ''
280 quote = 0
281 theirexceptions = [ErrorNames[x.lower()] for x in exceptions]
282
Raymond Hettingerd9c0a7a2004-07-03 10:02:28 +0000283 for exception in Signals:
Raymond Hettingerbf440692004-07-10 14:14:37 +0000284 self.context.traps[exception] = 1 #Catch these bugs...
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000285 for exception in theirexceptions:
Raymond Hettingerbf440692004-07-10 14:14:37 +0000286 self.context.traps[exception] = 0
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000287 for i, val in enumerate(valstemp):
288 if val.count("'") % 2 == 1:
289 quote = 1 - quote
290 if quote:
291 conglomerate = conglomerate + ' ' + val
292 continue
293 else:
294 val = conglomerate + val
295 conglomerate = ''
296 v = FixQuotes(val)
297 if fname in ('to_sci_string', 'to_eng_string'):
298 if EXTENDEDERRORTEST:
299 for error in theirexceptions:
Raymond Hettingerbf440692004-07-10 14:14:37 +0000300 self.context.traps[error] = 1
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000301 try:
302 funct(self.context.create_decimal(v))
303 except error:
304 pass
Raymond Hettingerd9c0a7a2004-07-03 10:02:28 +0000305 except Signals, e:
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000306 self.fail("Raised %s in %s when %s disabled" % \
307 (e, s, error))
308 else:
309 self.fail("Did not raise %s in %s" % (error, s))
Raymond Hettingerbf440692004-07-10 14:14:37 +0000310 self.context.traps[error] = 0
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000311 v = self.context.create_decimal(v)
312 else:
Facundo Batista353750c2007-09-13 18:13:15 +0000313 v = Decimal(v, self.context)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000314 vals.append(v)
315
316 ans = FixQuotes(ans)
317
Facundo Batista353750c2007-09-13 18:13:15 +0000318 # skip tests that are related to bounds imposed in the decNumber
319 # reference implementation
320 if fname in decNumberRestricted:
321 if fname == 'power':
322 if not (vals[1]._isinteger() and
323 -1999999997 <= vals[1] <= 999999999):
324 if outside_decNumber_bounds(vals[0], self.context) or \
325 outside_decNumber_bounds(vals[1], self.context):
326 #print "Skipping test %s" % s
327 return
328 else:
329 if outside_decNumber_bounds(vals[0], self.context):
330 #print "Skipping test %s" % s
331 return
332
333
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000334 if EXTENDEDERRORTEST and fname not in ('to_sci_string', 'to_eng_string'):
335 for error in theirexceptions:
Raymond Hettingerbf440692004-07-10 14:14:37 +0000336 self.context.traps[error] = 1
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000337 try:
338 funct(*vals)
339 except error:
340 pass
Raymond Hettingerd9c0a7a2004-07-03 10:02:28 +0000341 except Signals, e:
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000342 self.fail("Raised %s in %s when %s disabled" % \
343 (e, s, error))
344 else:
345 self.fail("Did not raise %s in %s" % (error, s))
Raymond Hettingerbf440692004-07-10 14:14:37 +0000346 self.context.traps[error] = 0
Facundo Batista353750c2007-09-13 18:13:15 +0000347 if DEBUG:
348 print "--", self.context
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000349 try:
350 result = str(funct(*vals))
Facundo Batista1a191df2007-10-02 17:01:24 +0000351 if fname in LOGICAL_FUNCTIONS:
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000352 result = str(int(eval(result))) # 'True', 'False' -> '1', '0'
Raymond Hettingerd9c0a7a2004-07-03 10:02:28 +0000353 except Signals, error:
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000354 self.fail("Raised %s in %s" % (error, s))
355 except: #Catch any error long enough to state the test case.
356 print "ERROR:", s
357 raise
358
359 myexceptions = self.getexceptions()
Raymond Hettingerbf440692004-07-10 14:14:37 +0000360 self.context.clear_flags()
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000361
362 myexceptions.sort()
363 theirexceptions.sort()
364
365 self.assertEqual(result, ans,
366 'Incorrect answer for ' + s + ' -- got ' + result)
367 self.assertEqual(myexceptions, theirexceptions,
Facundo Batista353750c2007-09-13 18:13:15 +0000368 'Incorrect flags set in ' + s + ' -- got ' + str(myexceptions))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000369 return
370
371 def getexceptions(self):
Raymond Hettingerf63ba432004-08-17 05:42:09 +0000372 return [e for e in Signals if self.context.flags[e]]
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000373
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000374 def change_precision(self, prec):
375 self.context.prec = prec
376 def change_rounding_method(self, rounding):
377 self.context.rounding = rounding
378 def change_min_exponent(self, exp):
379 self.context.Emin = exp
380 def change_max_exponent(self, exp):
381 self.context.Emax = exp
382 def change_clamp(self, clamp):
383 self.context._clamp = clamp
384
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000385
386
387# The following classes test the behaviour of Decimal according to PEP 327
388
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000389class DecimalExplicitConstructionTest(unittest.TestCase):
390 '''Unit tests for Explicit Construction cases of Decimal.'''
391
392 def test_explicit_empty(self):
393 self.assertEqual(Decimal(), Decimal("0"))
394
395 def test_explicit_from_None(self):
396 self.assertRaises(TypeError, Decimal, None)
397
398 def test_explicit_from_int(self):
399
400 #positive
401 d = Decimal(45)
402 self.assertEqual(str(d), '45')
403
404 #very large positive
405 d = Decimal(500000123)
406 self.assertEqual(str(d), '500000123')
407
408 #negative
409 d = Decimal(-45)
410 self.assertEqual(str(d), '-45')
411
412 #zero
413 d = Decimal(0)
414 self.assertEqual(str(d), '0')
415
416 def test_explicit_from_string(self):
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000417
418 #empty
419 self.assertEqual(str(Decimal('')), 'NaN')
420
421 #int
422 self.assertEqual(str(Decimal('45')), '45')
423
424 #float
425 self.assertEqual(str(Decimal('45.34')), '45.34')
426
427 #engineer notation
428 self.assertEqual(str(Decimal('45e2')), '4.5E+3')
429
430 #just not a number
431 self.assertEqual(str(Decimal('ugly')), 'NaN')
432
Mark Dickinson59bc20b2008-01-12 01:56:00 +0000433 #leading and trailing whitespace permitted
434 self.assertEqual(str(Decimal('1.3E4 \n')), '1.3E+4')
435 self.assertEqual(str(Decimal(' -7.89')), '-7.89')
436
Mark Dickinson8e85ffa2008-03-25 18:47:59 +0000437 #unicode strings should be permitted
438 self.assertEqual(str(Decimal(u'0E-017')), '0E-17')
439 self.assertEqual(str(Decimal(u'45')), '45')
440 self.assertEqual(str(Decimal(u'-Inf')), '-Infinity')
441 self.assertEqual(str(Decimal(u'NaN123')), 'NaN123')
442
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000443 def test_explicit_from_tuples(self):
444
445 #zero
446 d = Decimal( (0, (0,), 0) )
447 self.assertEqual(str(d), '0')
448
449 #int
450 d = Decimal( (1, (4, 5), 0) )
451 self.assertEqual(str(d), '-45')
452
453 #float
454 d = Decimal( (0, (4, 5, 3, 4), -2) )
455 self.assertEqual(str(d), '45.34')
456
457 #weird
458 d = Decimal( (1, (4, 3, 4, 9, 1, 3, 5, 3, 4), -25) )
459 self.assertEqual(str(d), '-4.34913534E-17')
460
461 #wrong number of items
462 self.assertRaises(ValueError, Decimal, (1, (4, 3, 4, 9, 1)) )
463
464 #bad sign
465 self.assertRaises(ValueError, Decimal, (8, (4, 3, 4, 9, 1), 2) )
Facundo Batista9b5e2312007-10-19 19:25:57 +0000466 self.assertRaises(ValueError, Decimal, (0., (4, 3, 4, 9, 1), 2) )
467 self.assertRaises(ValueError, Decimal, (Decimal(1), (4, 3, 4, 9, 1), 2))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000468
469 #bad exp
470 self.assertRaises(ValueError, Decimal, (1, (4, 3, 4, 9, 1), 'wrong!') )
Facundo Batista9b5e2312007-10-19 19:25:57 +0000471 self.assertRaises(ValueError, Decimal, (1, (4, 3, 4, 9, 1), 0.) )
472 self.assertRaises(ValueError, Decimal, (1, (4, 3, 4, 9, 1), '1') )
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000473
474 #bad coefficients
475 self.assertRaises(ValueError, Decimal, (1, (4, 3, 4, None, 1), 2) )
476 self.assertRaises(ValueError, Decimal, (1, (4, -3, 4, 9, 1), 2) )
Facundo Batista9b5e2312007-10-19 19:25:57 +0000477 self.assertRaises(ValueError, Decimal, (1, (4, 10, 4, 9, 1), 2) )
Facundo Batista72bc54f2007-11-23 17:59:00 +0000478 self.assertRaises(ValueError, Decimal, (1, (4, 3, 4, 'a', 1), 2) )
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000479
480 def test_explicit_from_Decimal(self):
481
482 #positive
483 d = Decimal(45)
484 e = Decimal(d)
485 self.assertEqual(str(e), '45')
486 self.assertNotEqual(id(d), id(e))
487
488 #very large positive
489 d = Decimal(500000123)
490 e = Decimal(d)
491 self.assertEqual(str(e), '500000123')
492 self.assertNotEqual(id(d), id(e))
493
494 #negative
495 d = Decimal(-45)
496 e = Decimal(d)
497 self.assertEqual(str(e), '-45')
498 self.assertNotEqual(id(d), id(e))
499
500 #zero
501 d = Decimal(0)
502 e = Decimal(d)
503 self.assertEqual(str(e), '0')
504 self.assertNotEqual(id(d), id(e))
505
506 def test_explicit_context_create_decimal(self):
507
508 nc = copy.copy(getcontext())
509 nc.prec = 3
510
511 # empty
Raymond Hettingerfed52962004-07-14 15:41:57 +0000512 d = Decimal()
513 self.assertEqual(str(d), '0')
514 d = nc.create_decimal()
515 self.assertEqual(str(d), '0')
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000516
517 # from None
518 self.assertRaises(TypeError, nc.create_decimal, None)
519
520 # from int
521 d = nc.create_decimal(456)
522 self.failUnless(isinstance(d, Decimal))
523 self.assertEqual(nc.create_decimal(45678),
524 nc.create_decimal('457E+2'))
525
526 # from string
527 d = Decimal('456789')
528 self.assertEqual(str(d), '456789')
529 d = nc.create_decimal('456789')
530 self.assertEqual(str(d), '4.57E+5')
Mark Dickinson59bc20b2008-01-12 01:56:00 +0000531 # leading and trailing whitespace should result in a NaN;
532 # spaces are already checked in Cowlishaw's test-suite, so
533 # here we just check that a trailing newline results in a NaN
534 self.assertEqual(str(nc.create_decimal('3.14\n')), 'NaN')
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000535
536 # from tuples
537 d = Decimal( (1, (4, 3, 4, 9, 1, 3, 5, 3, 4), -25) )
538 self.assertEqual(str(d), '-4.34913534E-17')
539 d = nc.create_decimal( (1, (4, 3, 4, 9, 1, 3, 5, 3, 4), -25) )
540 self.assertEqual(str(d), '-4.35E-17')
541
542 # from Decimal
543 prevdec = Decimal(500000123)
544 d = Decimal(prevdec)
545 self.assertEqual(str(d), '500000123')
546 d = nc.create_decimal(prevdec)
547 self.assertEqual(str(d), '5.00E+8')
548
549
550class DecimalImplicitConstructionTest(unittest.TestCase):
551 '''Unit tests for Implicit Construction cases of Decimal.'''
552
553 def test_implicit_from_None(self):
554 self.assertRaises(TypeError, eval, 'Decimal(5) + None', globals())
555
556 def test_implicit_from_int(self):
557 #normal
558 self.assertEqual(str(Decimal(5) + 45), '50')
559 #exceeding precision
560 self.assertEqual(Decimal(5) + 123456789000, Decimal(123456789000))
561
562 def test_implicit_from_string(self):
563 self.assertRaises(TypeError, eval, 'Decimal(5) + "3"', globals())
564
565 def test_implicit_from_float(self):
566 self.assertRaises(TypeError, eval, 'Decimal(5) + 2.2', globals())
567
568 def test_implicit_from_Decimal(self):
569 self.assertEqual(Decimal(5) + Decimal(45), Decimal(50))
570
Raymond Hettinger267b8682005-03-27 10:47:39 +0000571 def test_rop(self):
572 # Allow other classes to be trained to interact with Decimals
573 class E:
574 def __divmod__(self, other):
575 return 'divmod ' + str(other)
576 def __rdivmod__(self, other):
577 return str(other) + ' rdivmod'
578 def __lt__(self, other):
579 return 'lt ' + str(other)
580 def __gt__(self, other):
581 return 'gt ' + str(other)
582 def __le__(self, other):
583 return 'le ' + str(other)
584 def __ge__(self, other):
585 return 'ge ' + str(other)
586 def __eq__(self, other):
587 return 'eq ' + str(other)
588 def __ne__(self, other):
589 return 'ne ' + str(other)
590
591 self.assertEqual(divmod(E(), Decimal(10)), 'divmod 10')
592 self.assertEqual(divmod(Decimal(10), E()), '10 rdivmod')
593 self.assertEqual(eval('Decimal(10) < E()'), 'gt 10')
594 self.assertEqual(eval('Decimal(10) > E()'), 'lt 10')
595 self.assertEqual(eval('Decimal(10) <= E()'), 'ge 10')
596 self.assertEqual(eval('Decimal(10) >= E()'), 'le 10')
597 self.assertEqual(eval('Decimal(10) == E()'), 'eq 10')
598 self.assertEqual(eval('Decimal(10) != E()'), 'ne 10')
599
600 # insert operator methods and then exercise them
Georg Brandl96c3f7f2006-03-28 08:06:35 +0000601 oplist = [
602 ('+', '__add__', '__radd__'),
603 ('-', '__sub__', '__rsub__'),
604 ('*', '__mul__', '__rmul__'),
605 ('%', '__mod__', '__rmod__'),
606 ('//', '__floordiv__', '__rfloordiv__'),
607 ('**', '__pow__', '__rpow__')
608 ]
609 if 1/2 == 0:
610 # testing with classic division, so add __div__
611 oplist.append(('/', '__div__', '__rdiv__'))
612 else:
613 # testing with -Qnew, so add __truediv__
614 oplist.append(('/', '__truediv__', '__rtruediv__'))
Anthony Baxter4ef3a232006-03-30 12:59:11 +0000615
Georg Brandl96c3f7f2006-03-28 08:06:35 +0000616 for sym, lop, rop in oplist:
Raymond Hettinger267b8682005-03-27 10:47:39 +0000617 setattr(E, lop, lambda self, other: 'str' + lop + str(other))
618 setattr(E, rop, lambda self, other: str(other) + rop + 'str')
619 self.assertEqual(eval('E()' + sym + 'Decimal(10)'),
620 'str' + lop + '10')
621 self.assertEqual(eval('Decimal(10)' + sym + 'E()'),
622 '10' + rop + 'str')
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000623
Mark Dickinson1ddf1d82008-02-29 02:16:37 +0000624class DecimalFormatTest(unittest.TestCase):
625 '''Unit tests for the format function.'''
626 def test_formatting(self):
627 # triples giving a format, a Decimal, and the expected result
628 test_values = [
629 ('e', '0E-15', '0e-15'),
630 ('e', '2.3E-15', '2.3e-15'),
631 ('e', '2.30E+2', '2.30e+2'), # preserve significant zeros
632 ('e', '2.30000E-15', '2.30000e-15'),
633 ('e', '1.23456789123456789e40', '1.23456789123456789e+40'),
634 ('e', '1.5', '1.5e+0'),
635 ('e', '0.15', '1.5e-1'),
636 ('e', '0.015', '1.5e-2'),
637 ('e', '0.0000000000015', '1.5e-12'),
638 ('e', '15.0', '1.50e+1'),
639 ('e', '-15', '-1.5e+1'),
640 ('e', '0', '0e+0'),
641 ('e', '0E1', '0e+1'),
642 ('e', '0.0', '0e-1'),
643 ('e', '0.00', '0e-2'),
644 ('.6e', '0E-15', '0.000000e-9'),
645 ('.6e', '0', '0.000000e+6'),
646 ('.6e', '9.999999', '9.999999e+0'),
647 ('.6e', '9.9999999', '1.000000e+1'),
648 ('.6e', '-1.23e5', '-1.230000e+5'),
649 ('.6e', '1.23456789e-3', '1.234568e-3'),
650 ('f', '0', '0'),
651 ('f', '0.0', '0.0'),
652 ('f', '0E-2', '0.00'),
653 ('f', '0.00E-8', '0.0000000000'),
654 ('f', '0E1', '0'), # loses exponent information
655 ('f', '3.2E1', '32'),
656 ('f', '3.2E2', '320'),
657 ('f', '3.20E2', '320'),
658 ('f', '3.200E2', '320.0'),
659 ('f', '3.2E-6', '0.0000032'),
660 ('.6f', '0E-15', '0.000000'), # all zeros treated equally
661 ('.6f', '0E1', '0.000000'),
662 ('.6f', '0', '0.000000'),
663 ('.0f', '0', '0'), # no decimal point
664 ('.0f', '0e-2', '0'),
665 ('.0f', '3.14159265', '3'),
666 ('.1f', '3.14159265', '3.1'),
667 ('.4f', '3.14159265', '3.1416'),
668 ('.6f', '3.14159265', '3.141593'),
669 ('.7f', '3.14159265', '3.1415926'), # round-half-even!
670 ('.8f', '3.14159265', '3.14159265'),
671 ('.9f', '3.14159265', '3.141592650'),
672
673 ('g', '0', '0'),
674 ('g', '0.0', '0.0'),
675 ('g', '0E1', '0e+1'),
676 ('G', '0E1', '0E+1'),
677 ('g', '0E-5', '0.00000'),
678 ('g', '0E-6', '0.000000'),
679 ('g', '0E-7', '0e-7'),
680 ('g', '-0E2', '-0e+2'),
681 ('.0g', '3.14159265', '3'), # 0 sig fig -> 1 sig fig
682 ('.1g', '3.14159265', '3'),
683 ('.2g', '3.14159265', '3.1'),
684 ('.5g', '3.14159265', '3.1416'),
685 ('.7g', '3.14159265', '3.141593'),
686 ('.8g', '3.14159265', '3.1415926'), # round-half-even!
687 ('.9g', '3.14159265', '3.14159265'),
688 ('.10g', '3.14159265', '3.14159265'), # don't pad
689
690 ('%', '0E1', '0%'),
691 ('%', '0E0', '0%'),
692 ('%', '0E-1', '0%'),
693 ('%', '0E-2', '0%'),
694 ('%', '0E-3', '0.0%'),
695 ('%', '0E-4', '0.00%'),
696
697 ('.3%', '0', '0.000%'), # all zeros treated equally
698 ('.3%', '0E10', '0.000%'),
699 ('.3%', '0E-10', '0.000%'),
700 ('.3%', '2.34', '234.000%'),
701 ('.3%', '1.234567', '123.457%'),
702 ('.0%', '1.23', '123%'),
703
704 ('e', 'NaN', 'NaN'),
705 ('f', '-NaN123', '-NaN123'),
706 ('+g', 'NaN456', '+NaN456'),
707 ('.3e', 'Inf', 'Infinity'),
708 ('.16f', '-Inf', '-Infinity'),
709 ('.0g', '-sNaN', '-sNaN'),
710
711 ('', '1.00', '1.00'),
712 ]
713 for fmt, d, result in test_values:
714 self.assertEqual(format(Decimal(d), fmt), result)
715
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000716class DecimalArithmeticOperatorsTest(unittest.TestCase):
717 '''Unit tests for all arithmetic operators, binary and unary.'''
718
719 def test_addition(self):
720
721 d1 = Decimal('-11.1')
722 d2 = Decimal('22.2')
723
724 #two Decimals
725 self.assertEqual(d1+d2, Decimal('11.1'))
726 self.assertEqual(d2+d1, Decimal('11.1'))
727
728 #with other type, left
729 c = d1 + 5
730 self.assertEqual(c, Decimal('-6.1'))
731 self.assertEqual(type(c), type(d1))
732
733 #with other type, right
734 c = 5 + d1
735 self.assertEqual(c, Decimal('-6.1'))
736 self.assertEqual(type(c), type(d1))
737
738 #inline with decimal
739 d1 += d2
740 self.assertEqual(d1, Decimal('11.1'))
741
742 #inline with other type
743 d1 += 5
744 self.assertEqual(d1, Decimal('16.1'))
745
746 def test_subtraction(self):
747
748 d1 = Decimal('-11.1')
749 d2 = Decimal('22.2')
750
751 #two Decimals
752 self.assertEqual(d1-d2, Decimal('-33.3'))
753 self.assertEqual(d2-d1, Decimal('33.3'))
754
755 #with other type, left
756 c = d1 - 5
757 self.assertEqual(c, Decimal('-16.1'))
758 self.assertEqual(type(c), type(d1))
759
760 #with other type, right
761 c = 5 - d1
762 self.assertEqual(c, Decimal('16.1'))
763 self.assertEqual(type(c), type(d1))
764
765 #inline with decimal
766 d1 -= d2
767 self.assertEqual(d1, Decimal('-33.3'))
768
769 #inline with other type
770 d1 -= 5
771 self.assertEqual(d1, Decimal('-38.3'))
772
773 def test_multiplication(self):
774
775 d1 = Decimal('-5')
776 d2 = Decimal('3')
777
778 #two Decimals
779 self.assertEqual(d1*d2, Decimal('-15'))
780 self.assertEqual(d2*d1, Decimal('-15'))
781
782 #with other type, left
783 c = d1 * 5
784 self.assertEqual(c, Decimal('-25'))
785 self.assertEqual(type(c), type(d1))
786
787 #with other type, right
788 c = 5 * d1
789 self.assertEqual(c, Decimal('-25'))
790 self.assertEqual(type(c), type(d1))
791
792 #inline with decimal
793 d1 *= d2
794 self.assertEqual(d1, Decimal('-15'))
795
796 #inline with other type
797 d1 *= 5
798 self.assertEqual(d1, Decimal('-75'))
799
800 def test_division(self):
801
802 d1 = Decimal('-5')
803 d2 = Decimal('2')
804
805 #two Decimals
806 self.assertEqual(d1/d2, Decimal('-2.5'))
807 self.assertEqual(d2/d1, Decimal('-0.4'))
808
809 #with other type, left
810 c = d1 / 4
811 self.assertEqual(c, Decimal('-1.25'))
812 self.assertEqual(type(c), type(d1))
813
814 #with other type, right
815 c = 4 / d1
816 self.assertEqual(c, Decimal('-0.8'))
817 self.assertEqual(type(c), type(d1))
818
819 #inline with decimal
820 d1 /= d2
821 self.assertEqual(d1, Decimal('-2.5'))
822
823 #inline with other type
824 d1 /= 4
825 self.assertEqual(d1, Decimal('-0.625'))
826
827 def test_floor_division(self):
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000828
829 d1 = Decimal('5')
830 d2 = Decimal('2')
831
832 #two Decimals
833 self.assertEqual(d1//d2, Decimal('2'))
834 self.assertEqual(d2//d1, Decimal('0'))
835
836 #with other type, left
837 c = d1 // 4
838 self.assertEqual(c, Decimal('1'))
839 self.assertEqual(type(c), type(d1))
840
841 #with other type, right
842 c = 7 // d1
843 self.assertEqual(c, Decimal('1'))
844 self.assertEqual(type(c), type(d1))
845
846 #inline with decimal
847 d1 //= d2
848 self.assertEqual(d1, Decimal('2'))
849
850 #inline with other type
851 d1 //= 2
852 self.assertEqual(d1, Decimal('1'))
853
854 def test_powering(self):
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000855
856 d1 = Decimal('5')
857 d2 = Decimal('2')
858
859 #two Decimals
860 self.assertEqual(d1**d2, Decimal('25'))
861 self.assertEqual(d2**d1, Decimal('32'))
862
863 #with other type, left
864 c = d1 ** 4
865 self.assertEqual(c, Decimal('625'))
866 self.assertEqual(type(c), type(d1))
867
868 #with other type, right
869 c = 7 ** d1
870 self.assertEqual(c, Decimal('16807'))
871 self.assertEqual(type(c), type(d1))
872
873 #inline with decimal
874 d1 **= d2
875 self.assertEqual(d1, Decimal('25'))
876
877 #inline with other type
878 d1 **= 4
879 self.assertEqual(d1, Decimal('390625'))
880
881 def test_module(self):
882
883 d1 = Decimal('5')
884 d2 = Decimal('2')
885
886 #two Decimals
887 self.assertEqual(d1%d2, Decimal('1'))
888 self.assertEqual(d2%d1, Decimal('2'))
889
890 #with other type, left
891 c = d1 % 4
892 self.assertEqual(c, Decimal('1'))
893 self.assertEqual(type(c), type(d1))
894
895 #with other type, right
896 c = 7 % d1
897 self.assertEqual(c, Decimal('2'))
898 self.assertEqual(type(c), type(d1))
899
900 #inline with decimal
901 d1 %= d2
902 self.assertEqual(d1, Decimal('1'))
903
904 #inline with other type
905 d1 %= 4
906 self.assertEqual(d1, Decimal('1'))
907
908 def test_floor_div_module(self):
909
910 d1 = Decimal('5')
911 d2 = Decimal('2')
912
913 #two Decimals
914 (p, q) = divmod(d1, d2)
915 self.assertEqual(p, Decimal('2'))
916 self.assertEqual(q, Decimal('1'))
917 self.assertEqual(type(p), type(d1))
918 self.assertEqual(type(q), type(d1))
919
920 #with other type, left
921 (p, q) = divmod(d1, 4)
922 self.assertEqual(p, Decimal('1'))
923 self.assertEqual(q, Decimal('1'))
924 self.assertEqual(type(p), type(d1))
925 self.assertEqual(type(q), type(d1))
926
927 #with other type, right
928 (p, q) = divmod(7, d1)
929 self.assertEqual(p, Decimal('1'))
930 self.assertEqual(q, Decimal('2'))
931 self.assertEqual(type(p), type(d1))
932 self.assertEqual(type(q), type(d1))
933
934 def test_unary_operators(self):
935 self.assertEqual(+Decimal(45), Decimal(+45)) # +
936 self.assertEqual(-Decimal(45), Decimal(-45)) # -
937 self.assertEqual(abs(Decimal(45)), abs(Decimal(-45))) # abs
938
Mark Dickinson2fc92632008-02-06 22:10:50 +0000939 def test_nan_comparisons(self):
940 n = Decimal('NaN')
941 s = Decimal('sNaN')
942 i = Decimal('Inf')
943 f = Decimal('2')
944 for x, y in [(n, n), (n, i), (i, n), (n, f), (f, n),
945 (s, n), (n, s), (s, i), (i, s), (s, f), (f, s), (s, s)]:
946 self.assert_(x != y)
947 self.assert_(not (x == y))
948 self.assert_(not (x < y))
949 self.assert_(not (x <= y))
950 self.assert_(not (x > y))
951 self.assert_(not (x >= y))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000952
953# The following are two functions used to test threading in the next class
954
955def thfunc1(cls):
956 d1 = Decimal(1)
957 d3 = Decimal(3)
Facundo Batista64156672008-03-22 02:45:37 +0000958 test1 = d1/d3
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000959 cls.synchro.wait()
Facundo Batista64156672008-03-22 02:45:37 +0000960 test2 = d1/d3
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000961 cls.finish1.set()
Facundo Batista64156672008-03-22 02:45:37 +0000962
963 cls.assertEqual(test1, Decimal('0.333333333'))
964 cls.assertEqual(test2, Decimal('0.333333333'))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000965 return
966
967def thfunc2(cls):
968 d1 = Decimal(1)
969 d3 = Decimal(3)
Facundo Batista64156672008-03-22 02:45:37 +0000970 test1 = d1/d3
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000971 thiscontext = getcontext()
972 thiscontext.prec = 18
Facundo Batista64156672008-03-22 02:45:37 +0000973 test2 = d1/d3
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000974 cls.synchro.set()
975 cls.finish2.set()
Facundo Batista64156672008-03-22 02:45:37 +0000976
977 cls.assertEqual(test1, Decimal('0.333333333'))
978 cls.assertEqual(test2, Decimal('0.333333333333333333'))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000979 return
980
981
982class DecimalUseOfContextTest(unittest.TestCase):
983 '''Unit tests for Use of Context cases in Decimal.'''
984
Raymond Hettinger7e71fa52004-12-18 19:07:19 +0000985 try:
986 import threading
987 except ImportError:
988 threading = None
989
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000990 # Take care executing this test from IDLE, there's an issue in threading
991 # that hangs IDLE and I couldn't find it
992
993 def test_threading(self):
994 #Test the "threading isolation" of a Context.
995
996 self.synchro = threading.Event()
997 self.finish1 = threading.Event()
998 self.finish2 = threading.Event()
999
1000 th1 = threading.Thread(target=thfunc1, args=(self,))
1001 th2 = threading.Thread(target=thfunc2, args=(self,))
1002
1003 th1.start()
1004 th2.start()
1005
1006 self.finish1.wait()
Thomas Woutersb3e6e8c2007-09-19 17:27:29 +00001007 self.finish2.wait()
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001008 return
1009
Raymond Hettinger7e71fa52004-12-18 19:07:19 +00001010 if threading is None:
1011 del test_threading
1012
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001013
1014class DecimalUsabilityTest(unittest.TestCase):
1015 '''Unit tests for Usability cases of Decimal.'''
1016
1017 def test_comparison_operators(self):
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001018
1019 da = Decimal('23.42')
1020 db = Decimal('23.42')
1021 dc = Decimal('45')
1022
1023 #two Decimals
1024 self.failUnless(dc > da)
1025 self.failUnless(dc >= da)
1026 self.failUnless(da < dc)
1027 self.failUnless(da <= dc)
1028 self.failUnless(da == db)
1029 self.failUnless(da != dc)
1030 self.failUnless(da <= db)
1031 self.failUnless(da >= db)
1032 self.assertEqual(cmp(dc,da), 1)
1033 self.assertEqual(cmp(da,dc), -1)
1034 self.assertEqual(cmp(da,db), 0)
1035
1036 #a Decimal and an int
1037 self.failUnless(dc > 23)
1038 self.failUnless(23 < dc)
1039 self.failUnless(dc == 45)
1040 self.assertEqual(cmp(dc,23), 1)
1041 self.assertEqual(cmp(23,dc), -1)
1042 self.assertEqual(cmp(dc,45), 0)
1043
1044 #a Decimal and uncomparable
Raymond Hettinger0aeac102004-07-05 22:53:03 +00001045 self.assertNotEqual(da, 'ugly')
1046 self.assertNotEqual(da, 32.7)
1047 self.assertNotEqual(da, object())
1048 self.assertNotEqual(da, object)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001049
Raymond Hettinger0aeac102004-07-05 22:53:03 +00001050 # sortable
1051 a = map(Decimal, xrange(100))
1052 b = a[:]
1053 random.shuffle(a)
1054 a.sort()
1055 self.assertEqual(a, b)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001056
Facundo Batista353750c2007-09-13 18:13:15 +00001057 # with None
1058 self.assertFalse(Decimal(1) < None)
1059 self.assertTrue(Decimal(1) > None)
1060
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001061 def test_copy_and_deepcopy_methods(self):
1062 d = Decimal('43.24')
1063 c = copy.copy(d)
1064 self.assertEqual(id(c), id(d))
1065 dc = copy.deepcopy(d)
1066 self.assertEqual(id(dc), id(d))
1067
1068 def test_hash_method(self):
1069 #just that it's hashable
1070 hash(Decimal(23))
Facundo Batista8c202442007-09-19 17:53:25 +00001071
1072 test_values = [Decimal(sign*(2**m + n))
1073 for m in [0, 14, 15, 16, 17, 30, 31,
1074 32, 33, 62, 63, 64, 65, 66]
1075 for n in range(-10, 10)
1076 for sign in [-1, 1]]
1077 test_values.extend([
1078 Decimal("-0"), # zeros
1079 Decimal("0.00"),
1080 Decimal("-0.000"),
1081 Decimal("0E10"),
1082 Decimal("-0E12"),
1083 Decimal("10.0"), # negative exponent
1084 Decimal("-23.00000"),
1085 Decimal("1230E100"), # positive exponent
1086 Decimal("-4.5678E50"),
1087 # a value for which hash(n) != hash(n % (2**64-1))
1088 # in Python pre-2.6
1089 Decimal(2**64 + 2**32 - 1),
1090 # selection of values which fail with the old (before
1091 # version 2.6) long.__hash__
1092 Decimal("1.634E100"),
1093 Decimal("90.697E100"),
1094 Decimal("188.83E100"),
1095 Decimal("1652.9E100"),
1096 Decimal("56531E100"),
1097 ])
1098
1099 # check that hash(d) == hash(int(d)) for integral values
1100 for value in test_values:
1101 self.assertEqual(hash(value), hash(int(value)))
1102
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001103 #the same hash that to an int
1104 self.assertEqual(hash(Decimal(23)), hash(23))
Raymond Hettingerbea3f6f2005-03-15 04:59:17 +00001105 self.assertRaises(TypeError, hash, Decimal('NaN'))
1106 self.assert_(hash(Decimal('Inf')))
1107 self.assert_(hash(Decimal('-Inf')))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001108
Facundo Batista52b25792008-01-08 12:25:20 +00001109 # check that the value of the hash doesn't depend on the
1110 # current context (issue #1757)
1111 c = getcontext()
1112 old_precision = c.prec
1113 x = Decimal("123456789.1")
1114
1115 c.prec = 6
1116 h1 = hash(x)
1117 c.prec = 10
1118 h2 = hash(x)
1119 c.prec = 16
1120 h3 = hash(x)
1121
1122 self.assertEqual(h1, h2)
1123 self.assertEqual(h1, h3)
1124 c.prec = old_precision
1125
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001126 def test_min_and_max_methods(self):
1127
1128 d1 = Decimal('15.32')
1129 d2 = Decimal('28.5')
1130 l1 = 15
1131 l2 = 28
1132
1133 #between Decimals
1134 self.failUnless(min(d1,d2) is d1)
1135 self.failUnless(min(d2,d1) is d1)
1136 self.failUnless(max(d1,d2) is d2)
1137 self.failUnless(max(d2,d1) is d2)
1138
1139 #between Decimal and long
1140 self.failUnless(min(d1,l2) is d1)
1141 self.failUnless(min(l2,d1) is d1)
1142 self.failUnless(max(l1,d2) is d2)
1143 self.failUnless(max(d2,l1) is d2)
1144
1145 def test_as_nonzero(self):
1146 #as false
1147 self.failIf(Decimal(0))
1148 #as true
1149 self.failUnless(Decimal('0.372'))
1150
1151 def test_tostring_methods(self):
1152 #Test str and repr methods.
1153
1154 d = Decimal('15.32')
1155 self.assertEqual(str(d), '15.32') # str
Raymond Hettingerabe32372008-02-14 02:41:22 +00001156 self.assertEqual(repr(d), "Decimal('15.32')") # repr
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001157
Mark Dickinson8e85ffa2008-03-25 18:47:59 +00001158 # result type of string methods should be str, not unicode
1159 unicode_inputs = [u'123.4', u'0.5E2', u'Infinity', u'sNaN',
1160 u'-0.0E100', u'-NaN001', u'-Inf']
1161
1162 for u in unicode_inputs:
1163 d = Decimal(u)
1164 self.assertEqual(type(str(d)), str)
1165 self.assertEqual(type(repr(d)), str)
1166 self.assertEqual(type(d.to_eng_string()), str)
1167
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001168 def test_tonum_methods(self):
1169 #Test float, int and long methods.
1170
1171 d1 = Decimal('66')
1172 d2 = Decimal('15.32')
1173
1174 #int
1175 self.assertEqual(int(d1), 66)
1176 self.assertEqual(int(d2), 15)
1177
1178 #long
1179 self.assertEqual(long(d1), 66)
1180 self.assertEqual(long(d2), 15)
1181
1182 #float
1183 self.assertEqual(float(d1), 66)
1184 self.assertEqual(float(d2), 15.32)
1185
1186 def test_eval_round_trip(self):
1187
1188 #with zero
1189 d = Decimal( (0, (0,), 0) )
1190 self.assertEqual(d, eval(repr(d)))
1191
1192 #int
1193 d = Decimal( (1, (4, 5), 0) )
1194 self.assertEqual(d, eval(repr(d)))
1195
1196 #float
1197 d = Decimal( (0, (4, 5, 3, 4), -2) )
1198 self.assertEqual(d, eval(repr(d)))
1199
1200 #weird
1201 d = Decimal( (1, (4, 3, 4, 9, 1, 3, 5, 3, 4), -25) )
1202 self.assertEqual(d, eval(repr(d)))
1203
1204 def test_as_tuple(self):
1205
1206 #with zero
1207 d = Decimal(0)
1208 self.assertEqual(d.as_tuple(), (0, (0,), 0) )
1209
1210 #int
1211 d = Decimal(-45)
1212 self.assertEqual(d.as_tuple(), (1, (4, 5), 0) )
1213
1214 #complicated string
1215 d = Decimal("-4.34913534E-17")
1216 self.assertEqual(d.as_tuple(), (1, (4, 3, 4, 9, 1, 3, 5, 3, 4), -25) )
1217
1218 #inf
1219 d = Decimal("Infinity")
1220 self.assertEqual(d.as_tuple(), (0, (0,), 'F') )
1221
Facundo Batista9b5e2312007-10-19 19:25:57 +00001222 #leading zeros in coefficient should be stripped
1223 d = Decimal( (0, (0, 0, 4, 0, 5, 3, 4), -2) )
1224 self.assertEqual(d.as_tuple(), (0, (4, 0, 5, 3, 4), -2) )
1225 d = Decimal( (1, (0, 0, 0), 37) )
1226 self.assertEqual(d.as_tuple(), (1, (0,), 37))
1227 d = Decimal( (1, (), 37) )
1228 self.assertEqual(d.as_tuple(), (1, (0,), 37))
1229
1230 #leading zeros in NaN diagnostic info should be stripped
1231 d = Decimal( (0, (0, 0, 4, 0, 5, 3, 4), 'n') )
1232 self.assertEqual(d.as_tuple(), (0, (4, 0, 5, 3, 4), 'n') )
1233 d = Decimal( (1, (0, 0, 0), 'N') )
1234 self.assertEqual(d.as_tuple(), (1, (), 'N') )
1235 d = Decimal( (1, (), 'n') )
1236 self.assertEqual(d.as_tuple(), (1, (), 'n') )
1237
1238 #coefficient in infinity should be ignored
1239 d = Decimal( (0, (4, 5, 3, 4), 'F') )
1240 self.assertEqual(d.as_tuple(), (0, (0,), 'F'))
1241 d = Decimal( (1, (0, 2, 7, 1), 'F') )
1242 self.assertEqual(d.as_tuple(), (1, (0,), 'F'))
1243
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001244 def test_immutability_operations(self):
1245 # Do operations and check that it didn't change change internal objects.
1246
1247 d1 = Decimal('-25e55')
1248 b1 = Decimal('-25e55')
Facundo Batista353750c2007-09-13 18:13:15 +00001249 d2 = Decimal('33e+33')
1250 b2 = Decimal('33e+33')
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001251
1252 def checkSameDec(operation, useOther=False):
1253 if useOther:
1254 eval("d1." + operation + "(d2)")
1255 self.assertEqual(d1._sign, b1._sign)
1256 self.assertEqual(d1._int, b1._int)
1257 self.assertEqual(d1._exp, b1._exp)
1258 self.assertEqual(d2._sign, b2._sign)
1259 self.assertEqual(d2._int, b2._int)
1260 self.assertEqual(d2._exp, b2._exp)
1261 else:
1262 eval("d1." + operation + "()")
1263 self.assertEqual(d1._sign, b1._sign)
1264 self.assertEqual(d1._int, b1._int)
1265 self.assertEqual(d1._exp, b1._exp)
1266 return
1267
1268 Decimal(d1)
1269 self.assertEqual(d1._sign, b1._sign)
1270 self.assertEqual(d1._int, b1._int)
1271 self.assertEqual(d1._exp, b1._exp)
1272
1273 checkSameDec("__abs__")
1274 checkSameDec("__add__", True)
1275 checkSameDec("__div__", True)
1276 checkSameDec("__divmod__", True)
Mark Dickinson2fc92632008-02-06 22:10:50 +00001277 checkSameDec("__eq__", True)
1278 checkSameDec("__ne__", True)
1279 checkSameDec("__le__", True)
1280 checkSameDec("__lt__", True)
1281 checkSameDec("__ge__", True)
1282 checkSameDec("__gt__", True)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001283 checkSameDec("__float__")
1284 checkSameDec("__floordiv__", True)
1285 checkSameDec("__hash__")
1286 checkSameDec("__int__")
Raymond Hettinger5a053642008-01-24 19:05:29 +00001287 checkSameDec("__trunc__")
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001288 checkSameDec("__long__")
1289 checkSameDec("__mod__", True)
1290 checkSameDec("__mul__", True)
1291 checkSameDec("__neg__")
1292 checkSameDec("__nonzero__")
1293 checkSameDec("__pos__")
1294 checkSameDec("__pow__", True)
1295 checkSameDec("__radd__", True)
1296 checkSameDec("__rdiv__", True)
1297 checkSameDec("__rdivmod__", True)
1298 checkSameDec("__repr__")
1299 checkSameDec("__rfloordiv__", True)
1300 checkSameDec("__rmod__", True)
1301 checkSameDec("__rmul__", True)
1302 checkSameDec("__rpow__", True)
1303 checkSameDec("__rsub__", True)
1304 checkSameDec("__str__")
1305 checkSameDec("__sub__", True)
1306 checkSameDec("__truediv__", True)
1307 checkSameDec("adjusted")
1308 checkSameDec("as_tuple")
1309 checkSameDec("compare", True)
1310 checkSameDec("max", True)
1311 checkSameDec("min", True)
1312 checkSameDec("normalize")
1313 checkSameDec("quantize", True)
1314 checkSameDec("remainder_near", True)
1315 checkSameDec("same_quantum", True)
1316 checkSameDec("sqrt")
1317 checkSameDec("to_eng_string")
1318 checkSameDec("to_integral")
1319
Facundo Batista6c398da2007-09-17 17:30:13 +00001320 def test_subclassing(self):
1321 # Different behaviours when subclassing Decimal
1322
1323 class MyDecimal(Decimal):
1324 pass
1325
1326 d1 = MyDecimal(1)
1327 d2 = MyDecimal(2)
1328 d = d1 + d2
1329 self.assertTrue(type(d) is Decimal)
1330
1331 d = d1.max(d2)
1332 self.assertTrue(type(d) is Decimal)
1333
Mark Dickinson3b24ccb2008-03-25 14:33:23 +00001334 def test_implicit_context(self):
1335 # Check results when context given implicitly. (Issue 2478)
1336 c = getcontext()
1337 self.assertEqual(str(Decimal(0).sqrt()),
1338 str(c.sqrt(Decimal(0))))
1339
Facundo Batista6c398da2007-09-17 17:30:13 +00001340
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001341class DecimalPythonAPItests(unittest.TestCase):
1342
1343 def test_pickle(self):
1344 d = Decimal('-3.141590000')
1345 p = pickle.dumps(d)
1346 e = pickle.loads(p)
1347 self.assertEqual(d, e)
1348
Raymond Hettinger5548be22004-07-05 18:49:38 +00001349 def test_int(self):
Raymond Hettinger605ed022004-11-24 07:28:48 +00001350 for x in range(-250, 250):
1351 s = '%0.2f' % (x / 100.0)
Raymond Hettinger5548be22004-07-05 18:49:38 +00001352 # should work the same as for floats
1353 self.assertEqual(int(Decimal(s)), int(float(s)))
Raymond Hettinger605ed022004-11-24 07:28:48 +00001354 # should work the same as to_integral in the ROUND_DOWN mode
Raymond Hettinger5548be22004-07-05 18:49:38 +00001355 d = Decimal(s)
Raymond Hettinger605ed022004-11-24 07:28:48 +00001356 r = d.to_integral(ROUND_DOWN)
Raymond Hettinger5548be22004-07-05 18:49:38 +00001357 self.assertEqual(Decimal(int(d)), r)
1358
Raymond Hettinger5a053642008-01-24 19:05:29 +00001359 def test_trunc(self):
1360 for x in range(-250, 250):
1361 s = '%0.2f' % (x / 100.0)
1362 # should work the same as for floats
1363 self.assertEqual(int(Decimal(s)), int(float(s)))
1364 # should work the same as to_integral in the ROUND_DOWN mode
1365 d = Decimal(s)
1366 r = d.to_integral(ROUND_DOWN)
Jeffrey Yasskinca2b69f2008-02-01 06:22:46 +00001367 self.assertEqual(Decimal(math.trunc(d)), r)
Raymond Hettinger5a053642008-01-24 19:05:29 +00001368
Raymond Hettingerd9c0a7a2004-07-03 10:02:28 +00001369class ContextAPItests(unittest.TestCase):
1370
1371 def test_pickle(self):
1372 c = Context()
1373 e = pickle.loads(pickle.dumps(c))
1374 for k in vars(c):
1375 v1 = vars(c)[k]
1376 v2 = vars(e)[k]
1377 self.assertEqual(v1, v2)
1378
Raymond Hettinger0aeac102004-07-05 22:53:03 +00001379 def test_equality_with_other_types(self):
1380 self.assert_(Decimal(10) in ['a', 1.0, Decimal(10), (1,2), {}])
1381 self.assert_(Decimal(10) not in ['a', 1.0, (1,2), {}])
1382
Raymond Hettinger955d2b22004-08-08 20:17:45 +00001383 def test_copy(self):
1384 # All copies should be deep
1385 c = Context()
1386 d = c.copy()
1387 self.assertNotEqual(id(c), id(d))
1388 self.assertNotEqual(id(c.flags), id(d.flags))
1389 self.assertNotEqual(id(c.traps), id(d.traps))
1390
Nick Coghlan8b6999b2006-08-31 12:00:43 +00001391class WithStatementTest(unittest.TestCase):
1392 # Can't do these as docstrings until Python 2.6
1393 # as doctest can't handle __future__ statements
Nick Coghlan8b6999b2006-08-31 12:00:43 +00001394
1395 def test_localcontext(self):
Nick Coghlanced12182006-09-02 03:54:17 +00001396 # Use a copy of the current context in the block
Nick Coghlan8b6999b2006-08-31 12:00:43 +00001397 orig_ctx = getcontext()
1398 with localcontext() as enter_ctx:
1399 set_ctx = getcontext()
1400 final_ctx = getcontext()
1401 self.assert_(orig_ctx is final_ctx, 'did not restore context correctly')
1402 self.assert_(orig_ctx is not set_ctx, 'did not copy the context')
1403 self.assert_(set_ctx is enter_ctx, '__enter__ returned wrong context')
1404
1405 def test_localcontextarg(self):
Nick Coghlanced12182006-09-02 03:54:17 +00001406 # Use a copy of the supplied context in the block
Nick Coghlan8b6999b2006-08-31 12:00:43 +00001407 orig_ctx = getcontext()
1408 new_ctx = Context(prec=42)
1409 with localcontext(new_ctx) as enter_ctx:
1410 set_ctx = getcontext()
1411 final_ctx = getcontext()
1412 self.assert_(orig_ctx is final_ctx, 'did not restore context correctly')
1413 self.assert_(set_ctx.prec == new_ctx.prec, 'did not set correct context')
1414 self.assert_(new_ctx is not set_ctx, 'did not copy the context')
1415 self.assert_(set_ctx is enter_ctx, '__enter__ returned wrong context')
1416
Facundo Batista353750c2007-09-13 18:13:15 +00001417class ContextFlags(unittest.TestCase):
1418 def test_flags_irrelevant(self):
1419 # check that the result (numeric result + flags raised) of an
1420 # arithmetic operation doesn't depend on the current flags
1421
1422 context = Context(prec=9, Emin = -999999999, Emax = 999999999,
1423 rounding=ROUND_HALF_EVEN, traps=[], flags=[])
1424
1425 # operations that raise various flags, in the form (function, arglist)
1426 operations = [
1427 (context._apply, [Decimal("100E-1000000009")]),
1428 (context.sqrt, [Decimal(2)]),
1429 (context.add, [Decimal("1.23456789"), Decimal("9.87654321")]),
1430 (context.multiply, [Decimal("1.23456789"), Decimal("9.87654321")]),
1431 (context.subtract, [Decimal("1.23456789"), Decimal("9.87654321")]),
1432 ]
1433
1434 # try various flags individually, then a whole lot at once
1435 flagsets = [[Inexact], [Rounded], [Underflow], [Clamped], [Subnormal],
1436 [Inexact, Rounded, Underflow, Clamped, Subnormal]]
1437
1438 for fn, args in operations:
1439 # find answer and flags raised using a clean context
1440 context.clear_flags()
1441 ans = fn(*args)
1442 flags = [k for k, v in context.flags.items() if v]
1443
1444 for extra_flags in flagsets:
1445 # set flags, before calling operation
1446 context.clear_flags()
1447 for flag in extra_flags:
1448 context._raise_error(flag)
1449 new_ans = fn(*args)
1450
1451 # flags that we expect to be set after the operation
1452 expected_flags = list(flags)
1453 for flag in extra_flags:
1454 if flag not in expected_flags:
1455 expected_flags.append(flag)
1456 expected_flags.sort()
1457
1458 # flags we actually got
1459 new_flags = [k for k,v in context.flags.items() if v]
1460 new_flags.sort()
1461
1462 self.assertEqual(ans, new_ans,
1463 "operation produces different answers depending on flags set: " +
1464 "expected %s, got %s." % (ans, new_ans))
1465 self.assertEqual(new_flags, expected_flags,
1466 "operation raises different flags depending on flags set: " +
1467 "expected %s, got %s" % (expected_flags, new_flags))
1468
1469def test_main(arith=False, verbose=None, todo_tests=None, debug=None):
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001470 """ Execute the tests.
1471
Raymond Hettingered20ad82004-09-04 20:09:13 +00001472 Runs all arithmetic tests if arith is True or if the "decimal" resource
1473 is enabled in regrtest.py
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001474 """
Raymond Hettingered20ad82004-09-04 20:09:13 +00001475
Neal Norwitzce4a9c92006-04-09 08:36:46 +00001476 init()
Facundo Batista353750c2007-09-13 18:13:15 +00001477 global TEST_ALL, DEBUG
Raymond Hettingered20ad82004-09-04 20:09:13 +00001478 TEST_ALL = arith or is_resource_enabled('decimal')
Facundo Batista353750c2007-09-13 18:13:15 +00001479 DEBUG = debug
Raymond Hettingered20ad82004-09-04 20:09:13 +00001480
Facundo Batista353750c2007-09-13 18:13:15 +00001481 if todo_tests is None:
1482 test_classes = [
1483 DecimalExplicitConstructionTest,
1484 DecimalImplicitConstructionTest,
1485 DecimalArithmeticOperatorsTest,
Mark Dickinson1ddf1d82008-02-29 02:16:37 +00001486 DecimalFormatTest,
Facundo Batista353750c2007-09-13 18:13:15 +00001487 DecimalUseOfContextTest,
1488 DecimalUsabilityTest,
1489 DecimalPythonAPItests,
1490 ContextAPItests,
1491 DecimalTest,
1492 WithStatementTest,
1493 ContextFlags
1494 ]
1495 else:
1496 test_classes = [DecimalTest]
1497
1498 # Dynamically build custom test definition for each file in the test
1499 # directory and add the definitions to the DecimalTest class. This
1500 # procedure insures that new files do not get skipped.
1501 for filename in os.listdir(directory):
1502 if '.decTest' not in filename or filename.startswith("."):
1503 continue
1504 head, tail = filename.split('.')
1505 if todo_tests is not None and head not in todo_tests:
1506 continue
1507 tester = lambda self, f=filename: self.eval_file(directory + f)
1508 setattr(DecimalTest, 'test_' + head, tester)
1509 del filename, head, tail, tester
1510
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001511
Tim Peters46cc7022006-03-31 04:11:16 +00001512 try:
1513 run_unittest(*test_classes)
Facundo Batista353750c2007-09-13 18:13:15 +00001514 if todo_tests is None:
1515 import decimal as DecimalModule
1516 run_doctest(DecimalModule, verbose)
Tim Peters46cc7022006-03-31 04:11:16 +00001517 finally:
1518 setcontext(ORIGINAL_CONTEXT)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001519
1520if __name__ == '__main__':
Facundo Batista353750c2007-09-13 18:13:15 +00001521 import optparse
1522 p = optparse.OptionParser("test_decimal.py [--debug] [{--skip | test1 [test2 [...]]}]")
1523 p.add_option('--debug', '-d', action='store_true', help='shows the test number and context before each test')
1524 p.add_option('--skip', '-s', action='store_true', help='skip over 90% of the arithmetic tests')
1525 (opt, args) = p.parse_args()
1526
1527 if opt.skip:
1528 test_main(arith=False, verbose=True)
1529 elif args:
1530 test_main(arith=True, verbose=True, todo_tests=args, debug=opt.debug)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001531 else:
Facundo Batista353750c2007-09-13 18:13:15 +00001532 test_main(arith=True, verbose=True)