blob: 79b6a8563d996c0340d47f6a46adb7557fd54274 [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
Jeffrey Yasskinca2b69f2008-02-01 06:22:46 +000028import math
Raymond Hettinger7c85fa42004-07-01 11:01:35 +000029import os, sys
30import pickle, copy
Jeffrey Yasskinca2b69f2008-02-01 06:22:46 +000031import unittest
Raymond Hettinger7c85fa42004-07-01 11:01:35 +000032from decimal import *
Raymond Hettinger45fd4762009-02-03 03:42:07 +000033import numbers
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()
Facundo Batistaee340e52008-05-02 17:39:00 +000050 DefaultTestContext = Context(
51 prec = 9,
52 rounding = ROUND_HALF_EVEN,
53 traps = dict.fromkeys(Signals, 0)
54 )
55 setcontext(DefaultTestContext)
Raymond Hettinger6ea48452004-07-03 12:26:21 +000056
Raymond Hettinger7c85fa42004-07-01 11:01:35 +000057TESTDATADIR = 'decimaltestdata'
Raymond Hettingerd9c0a7a2004-07-03 10:02:28 +000058if __name__ == '__main__':
59 file = sys.argv[0]
60else:
61 file = __file__
62testdir = os.path.dirname(file) or os.curdir
Raymond Hettinger267b8682005-03-27 10:47:39 +000063directory = testdir + os.sep + TESTDATADIR + os.sep
Raymond Hettinger7c85fa42004-07-01 11:01:35 +000064
Raymond Hettinger267b8682005-03-27 10:47:39 +000065skip_expected = not os.path.isdir(directory)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +000066
67# Make sure it actually raises errors when not expected and caught in flags
68# Slower, since it runs some things several times.
69EXTENDEDERRORTEST = False
70
Raymond Hettinger7c85fa42004-07-01 11:01:35 +000071#Map the test cases' error names to the actual errors
Raymond Hettinger7c85fa42004-07-01 11:01:35 +000072ErrorNames = {'clamped' : Clamped,
Raymond Hettinger5aa478b2004-07-09 10:02:53 +000073 'conversion_syntax' : InvalidOperation,
Raymond Hettinger7c85fa42004-07-01 11:01:35 +000074 'division_by_zero' : DivisionByZero,
Raymond Hettinger5aa478b2004-07-09 10:02:53 +000075 'division_impossible' : InvalidOperation,
76 'division_undefined' : InvalidOperation,
Raymond Hettinger7c85fa42004-07-01 11:01:35 +000077 'inexact' : Inexact,
Raymond Hettinger5aa478b2004-07-09 10:02:53 +000078 'invalid_context' : InvalidOperation,
Raymond Hettinger7c85fa42004-07-01 11:01:35 +000079 'invalid_operation' : InvalidOperation,
80 'overflow' : Overflow,
81 'rounded' : Rounded,
82 'subnormal' : Subnormal,
83 'underflow' : Underflow}
84
85
86def Nonfunction(*args):
87 """Doesn't do anything."""
88 return None
89
90RoundingDict = {'ceiling' : ROUND_CEILING, #Maps test-case names to roundings.
91 'down' : ROUND_DOWN,
92 'floor' : ROUND_FLOOR,
93 'half_down' : ROUND_HALF_DOWN,
94 'half_even' : ROUND_HALF_EVEN,
95 'half_up' : ROUND_HALF_UP,
Facundo Batista353750c2007-09-13 18:13:15 +000096 'up' : ROUND_UP,
97 '05up' : ROUND_05UP}
Raymond Hettinger7c85fa42004-07-01 11:01:35 +000098
99# Name adapter to be able to change the Decimal and Context
100# interface without changing the test files from Cowlishaw
Facundo Batista1a191df2007-10-02 17:01:24 +0000101nameAdapter = {'and':'logical_and',
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000102 'apply':'_apply',
Facundo Batista353750c2007-09-13 18:13:15 +0000103 'class':'number_class',
104 'comparesig':'compare_signal',
105 'comparetotal':'compare_total',
106 'comparetotmag':'compare_total_mag',
Facundo Batista353750c2007-09-13 18:13:15 +0000107 'copy':'copy_decimal',
Facundo Batista1a191df2007-10-02 17:01:24 +0000108 'copyabs':'copy_abs',
Facundo Batista353750c2007-09-13 18:13:15 +0000109 'copynegate':'copy_negate',
110 'copysign':'copy_sign',
Facundo Batista1a191df2007-10-02 17:01:24 +0000111 'divideint':'divide_int',
Facundo Batista353750c2007-09-13 18:13:15 +0000112 'invert':'logical_invert',
Facundo Batista1a191df2007-10-02 17:01:24 +0000113 'iscanonical':'is_canonical',
114 'isfinite':'is_finite',
115 'isinfinite':'is_infinite',
116 'isnan':'is_nan',
117 'isnormal':'is_normal',
118 'isqnan':'is_qnan',
119 'issigned':'is_signed',
120 'issnan':'is_snan',
121 'issubnormal':'is_subnormal',
122 'iszero':'is_zero',
Facundo Batista353750c2007-09-13 18:13:15 +0000123 'maxmag':'max_mag',
124 'minmag':'min_mag',
125 'nextminus':'next_minus',
126 'nextplus':'next_plus',
127 'nexttoward':'next_toward',
Facundo Batista1a191df2007-10-02 17:01:24 +0000128 'or':'logical_or',
Facundo Batista353750c2007-09-13 18:13:15 +0000129 'reduce':'normalize',
Facundo Batista1a191df2007-10-02 17:01:24 +0000130 'remaindernear':'remainder_near',
131 'samequantum':'same_quantum',
132 'squareroot':'sqrt',
133 'toeng':'to_eng_string',
134 'tointegral':'to_integral_value',
135 'tointegralx':'to_integral_exact',
136 'tosci':'to_sci_string',
137 'xor':'logical_xor',
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000138 }
139
Facundo Batista1a191df2007-10-02 17:01:24 +0000140# The following functions return True/False rather than a Decimal instance
141
142LOGICAL_FUNCTIONS = (
143 'is_canonical',
144 'is_finite',
145 'is_infinite',
146 'is_nan',
147 'is_normal',
148 'is_qnan',
149 'is_signed',
150 'is_snan',
151 'is_subnormal',
152 'is_zero',
153 'same_quantum',
154 )
155
Facundo Batista353750c2007-09-13 18:13:15 +0000156# For some operations (currently exp, ln, log10, power), the decNumber
157# reference implementation imposes additional restrictions on the
158# context and operands. These restrictions are not part of the
159# specification; however, the effect of these restrictions does show
160# up in some of the testcases. We skip testcases that violate these
161# restrictions, since Decimal behaves differently from decNumber for
162# these testcases so these testcases would otherwise fail.
163
164decNumberRestricted = ('power', 'ln', 'log10', 'exp')
165DEC_MAX_MATH = 999999
166def outside_decNumber_bounds(v, context):
167 if (context.prec > DEC_MAX_MATH or
168 context.Emax > DEC_MAX_MATH or
169 -context.Emin > DEC_MAX_MATH):
170 return True
171 if not v._is_special and v and (
Facundo Batista353750c2007-09-13 18:13:15 +0000172 v.adjusted() > DEC_MAX_MATH or
173 v.adjusted() < 1-2*DEC_MAX_MATH):
174 return True
175 return False
176
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000177class DecimalTest(unittest.TestCase):
178 """Class which tests the Decimal class against the test cases.
179
180 Changed for unittest.
181 """
182 def setUp(self):
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000183 self.context = Context()
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000184 self.ignore_list = ['#']
185 # Basically, a # means return NaN InvalidOperation.
186 # Different from a sNaN in trim
187
188 self.ChangeDict = {'precision' : self.change_precision,
189 'rounding' : self.change_rounding_method,
190 'maxexponent' : self.change_max_exponent,
191 'minexponent' : self.change_min_exponent,
192 'clamp' : self.change_clamp}
193
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000194 def eval_file(self, file):
195 global skip_expected
196 if skip_expected:
197 raise TestSkipped
198 return
199 for line in open(file).xreadlines():
200 line = line.replace('\r\n', '').replace('\n', '')
Raymond Hettinger5aa478b2004-07-09 10:02:53 +0000201 #print line
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000202 try:
203 t = self.eval_line(line)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000204 except DecimalException, exception:
205 #Exception raised where there shoudn't have been one.
206 self.fail('Exception "'+exception.__class__.__name__ + '" raised on line '+line)
207
208 return
209
210 def eval_line(self, s):
211 if s.find(' -> ') >= 0 and s[:2] != '--' and not s.startswith(' --'):
212 s = (s.split('->')[0] + '->' +
213 s.split('->')[1].split('--')[0]).strip()
214 else:
215 s = s.split('--')[0].strip()
216
217 for ignore in self.ignore_list:
218 if s.find(ignore) >= 0:
219 #print s.split()[0], 'NotImplemented--', ignore
220 return
221 if not s:
222 return
223 elif ':' in s:
224 return self.eval_directive(s)
225 else:
226 return self.eval_equation(s)
227
228 def eval_directive(self, s):
229 funct, value = map(lambda x: x.strip().lower(), s.split(':'))
230 if funct == 'rounding':
231 value = RoundingDict[value]
232 else:
233 try:
234 value = int(value)
235 except ValueError:
236 pass
237
238 funct = self.ChangeDict.get(funct, Nonfunction)
239 funct(value)
240
241 def eval_equation(self, s):
242 #global DEFAULT_PRECISION
243 #print DEFAULT_PRECISION
Raymond Hettingered20ad82004-09-04 20:09:13 +0000244
245 if not TEST_ALL and random.random() < 0.90:
246 return
247
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000248 try:
249 Sides = s.split('->')
250 L = Sides[0].strip().split()
251 id = L[0]
Facundo Batista353750c2007-09-13 18:13:15 +0000252 if DEBUG:
253 print "Test ", id,
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000254 funct = L[1].lower()
255 valstemp = L[2:]
256 L = Sides[1].strip().split()
257 ans = L[0]
258 exceptions = L[1:]
259 except (TypeError, AttributeError, IndexError):
Raymond Hettingerd87ac8f2004-07-09 10:52:54 +0000260 raise InvalidOperation
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000261 def FixQuotes(val):
262 val = val.replace("''", 'SingleQuote').replace('""', 'DoubleQuote')
263 val = val.replace("'", '').replace('"', '')
264 val = val.replace('SingleQuote', "'").replace('DoubleQuote', '"')
265 return val
266 fname = nameAdapter.get(funct, funct)
267 if fname == 'rescale':
268 return
269 funct = getattr(self.context, fname)
270 vals = []
271 conglomerate = ''
272 quote = 0
273 theirexceptions = [ErrorNames[x.lower()] for x in exceptions]
274
Raymond Hettingerd9c0a7a2004-07-03 10:02:28 +0000275 for exception in Signals:
Raymond Hettingerbf440692004-07-10 14:14:37 +0000276 self.context.traps[exception] = 1 #Catch these bugs...
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000277 for exception in theirexceptions:
Raymond Hettingerbf440692004-07-10 14:14:37 +0000278 self.context.traps[exception] = 0
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000279 for i, val in enumerate(valstemp):
280 if val.count("'") % 2 == 1:
281 quote = 1 - quote
282 if quote:
283 conglomerate = conglomerate + ' ' + val
284 continue
285 else:
286 val = conglomerate + val
287 conglomerate = ''
288 v = FixQuotes(val)
289 if fname in ('to_sci_string', 'to_eng_string'):
290 if EXTENDEDERRORTEST:
291 for error in theirexceptions:
Raymond Hettingerbf440692004-07-10 14:14:37 +0000292 self.context.traps[error] = 1
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000293 try:
294 funct(self.context.create_decimal(v))
295 except error:
296 pass
Raymond Hettingerd9c0a7a2004-07-03 10:02:28 +0000297 except Signals, e:
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000298 self.fail("Raised %s in %s when %s disabled" % \
299 (e, s, error))
300 else:
301 self.fail("Did not raise %s in %s" % (error, s))
Raymond Hettingerbf440692004-07-10 14:14:37 +0000302 self.context.traps[error] = 0
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000303 v = self.context.create_decimal(v)
304 else:
Facundo Batista353750c2007-09-13 18:13:15 +0000305 v = Decimal(v, self.context)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000306 vals.append(v)
307
308 ans = FixQuotes(ans)
309
Facundo Batista353750c2007-09-13 18:13:15 +0000310 # skip tests that are related to bounds imposed in the decNumber
311 # reference implementation
312 if fname in decNumberRestricted:
313 if fname == 'power':
314 if not (vals[1]._isinteger() and
315 -1999999997 <= vals[1] <= 999999999):
316 if outside_decNumber_bounds(vals[0], self.context) or \
317 outside_decNumber_bounds(vals[1], self.context):
318 #print "Skipping test %s" % s
319 return
320 else:
321 if outside_decNumber_bounds(vals[0], self.context):
322 #print "Skipping test %s" % s
323 return
324
325
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000326 if EXTENDEDERRORTEST and fname not in ('to_sci_string', 'to_eng_string'):
327 for error in theirexceptions:
Raymond Hettingerbf440692004-07-10 14:14:37 +0000328 self.context.traps[error] = 1
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000329 try:
330 funct(*vals)
331 except error:
332 pass
Raymond Hettingerd9c0a7a2004-07-03 10:02:28 +0000333 except Signals, e:
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000334 self.fail("Raised %s in %s when %s disabled" % \
335 (e, s, error))
336 else:
337 self.fail("Did not raise %s in %s" % (error, s))
Raymond Hettingerbf440692004-07-10 14:14:37 +0000338 self.context.traps[error] = 0
Facundo Batista353750c2007-09-13 18:13:15 +0000339 if DEBUG:
340 print "--", self.context
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000341 try:
342 result = str(funct(*vals))
Facundo Batista1a191df2007-10-02 17:01:24 +0000343 if fname in LOGICAL_FUNCTIONS:
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000344 result = str(int(eval(result))) # 'True', 'False' -> '1', '0'
Raymond Hettingerd9c0a7a2004-07-03 10:02:28 +0000345 except Signals, error:
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000346 self.fail("Raised %s in %s" % (error, s))
347 except: #Catch any error long enough to state the test case.
348 print "ERROR:", s
349 raise
350
351 myexceptions = self.getexceptions()
Raymond Hettingerbf440692004-07-10 14:14:37 +0000352 self.context.clear_flags()
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000353
354 myexceptions.sort()
355 theirexceptions.sort()
356
357 self.assertEqual(result, ans,
358 'Incorrect answer for ' + s + ' -- got ' + result)
359 self.assertEqual(myexceptions, theirexceptions,
Facundo Batista353750c2007-09-13 18:13:15 +0000360 'Incorrect flags set in ' + s + ' -- got ' + str(myexceptions))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000361 return
362
363 def getexceptions(self):
Raymond Hettingerf63ba432004-08-17 05:42:09 +0000364 return [e for e in Signals if self.context.flags[e]]
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000365
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000366 def change_precision(self, prec):
367 self.context.prec = prec
368 def change_rounding_method(self, rounding):
369 self.context.rounding = rounding
370 def change_min_exponent(self, exp):
371 self.context.Emin = exp
372 def change_max_exponent(self, exp):
373 self.context.Emax = exp
374 def change_clamp(self, clamp):
375 self.context._clamp = clamp
376
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000377
378
379# The following classes test the behaviour of Decimal according to PEP 327
380
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000381class DecimalExplicitConstructionTest(unittest.TestCase):
382 '''Unit tests for Explicit Construction cases of Decimal.'''
383
384 def test_explicit_empty(self):
385 self.assertEqual(Decimal(), Decimal("0"))
386
387 def test_explicit_from_None(self):
388 self.assertRaises(TypeError, Decimal, None)
389
390 def test_explicit_from_int(self):
391
392 #positive
393 d = Decimal(45)
394 self.assertEqual(str(d), '45')
395
396 #very large positive
397 d = Decimal(500000123)
398 self.assertEqual(str(d), '500000123')
399
400 #negative
401 d = Decimal(-45)
402 self.assertEqual(str(d), '-45')
403
404 #zero
405 d = Decimal(0)
406 self.assertEqual(str(d), '0')
407
408 def test_explicit_from_string(self):
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000409
410 #empty
411 self.assertEqual(str(Decimal('')), 'NaN')
412
413 #int
414 self.assertEqual(str(Decimal('45')), '45')
415
416 #float
417 self.assertEqual(str(Decimal('45.34')), '45.34')
418
419 #engineer notation
420 self.assertEqual(str(Decimal('45e2')), '4.5E+3')
421
422 #just not a number
423 self.assertEqual(str(Decimal('ugly')), 'NaN')
424
Mark Dickinson59bc20b2008-01-12 01:56:00 +0000425 #leading and trailing whitespace permitted
426 self.assertEqual(str(Decimal('1.3E4 \n')), '1.3E+4')
427 self.assertEqual(str(Decimal(' -7.89')), '-7.89')
428
Mark Dickinson8e85ffa2008-03-25 18:47:59 +0000429 #unicode strings should be permitted
430 self.assertEqual(str(Decimal(u'0E-017')), '0E-17')
431 self.assertEqual(str(Decimal(u'45')), '45')
432 self.assertEqual(str(Decimal(u'-Inf')), '-Infinity')
433 self.assertEqual(str(Decimal(u'NaN123')), 'NaN123')
434
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000435 def test_explicit_from_tuples(self):
436
437 #zero
438 d = Decimal( (0, (0,), 0) )
439 self.assertEqual(str(d), '0')
440
441 #int
442 d = Decimal( (1, (4, 5), 0) )
443 self.assertEqual(str(d), '-45')
444
445 #float
446 d = Decimal( (0, (4, 5, 3, 4), -2) )
447 self.assertEqual(str(d), '45.34')
448
449 #weird
450 d = Decimal( (1, (4, 3, 4, 9, 1, 3, 5, 3, 4), -25) )
451 self.assertEqual(str(d), '-4.34913534E-17')
452
453 #wrong number of items
454 self.assertRaises(ValueError, Decimal, (1, (4, 3, 4, 9, 1)) )
455
456 #bad sign
457 self.assertRaises(ValueError, Decimal, (8, (4, 3, 4, 9, 1), 2) )
Facundo Batista9b5e2312007-10-19 19:25:57 +0000458 self.assertRaises(ValueError, Decimal, (0., (4, 3, 4, 9, 1), 2) )
459 self.assertRaises(ValueError, Decimal, (Decimal(1), (4, 3, 4, 9, 1), 2))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000460
461 #bad exp
462 self.assertRaises(ValueError, Decimal, (1, (4, 3, 4, 9, 1), 'wrong!') )
Facundo Batista9b5e2312007-10-19 19:25:57 +0000463 self.assertRaises(ValueError, Decimal, (1, (4, 3, 4, 9, 1), 0.) )
464 self.assertRaises(ValueError, Decimal, (1, (4, 3, 4, 9, 1), '1') )
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000465
466 #bad coefficients
467 self.assertRaises(ValueError, Decimal, (1, (4, 3, 4, None, 1), 2) )
468 self.assertRaises(ValueError, Decimal, (1, (4, -3, 4, 9, 1), 2) )
Facundo Batista9b5e2312007-10-19 19:25:57 +0000469 self.assertRaises(ValueError, Decimal, (1, (4, 10, 4, 9, 1), 2) )
Facundo Batista72bc54f2007-11-23 17:59:00 +0000470 self.assertRaises(ValueError, Decimal, (1, (4, 3, 4, 'a', 1), 2) )
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000471
472 def test_explicit_from_Decimal(self):
473
474 #positive
475 d = Decimal(45)
476 e = Decimal(d)
477 self.assertEqual(str(e), '45')
478 self.assertNotEqual(id(d), id(e))
479
480 #very large positive
481 d = Decimal(500000123)
482 e = Decimal(d)
483 self.assertEqual(str(e), '500000123')
484 self.assertNotEqual(id(d), id(e))
485
486 #negative
487 d = Decimal(-45)
488 e = Decimal(d)
489 self.assertEqual(str(e), '-45')
490 self.assertNotEqual(id(d), id(e))
491
492 #zero
493 d = Decimal(0)
494 e = Decimal(d)
495 self.assertEqual(str(e), '0')
496 self.assertNotEqual(id(d), id(e))
497
498 def test_explicit_context_create_decimal(self):
499
500 nc = copy.copy(getcontext())
501 nc.prec = 3
502
503 # empty
Raymond Hettingerfed52962004-07-14 15:41:57 +0000504 d = Decimal()
505 self.assertEqual(str(d), '0')
506 d = nc.create_decimal()
507 self.assertEqual(str(d), '0')
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000508
509 # from None
510 self.assertRaises(TypeError, nc.create_decimal, None)
511
512 # from int
513 d = nc.create_decimal(456)
514 self.failUnless(isinstance(d, Decimal))
515 self.assertEqual(nc.create_decimal(45678),
516 nc.create_decimal('457E+2'))
517
518 # from string
519 d = Decimal('456789')
520 self.assertEqual(str(d), '456789')
521 d = nc.create_decimal('456789')
522 self.assertEqual(str(d), '4.57E+5')
Mark Dickinson59bc20b2008-01-12 01:56:00 +0000523 # leading and trailing whitespace should result in a NaN;
524 # spaces are already checked in Cowlishaw's test-suite, so
525 # here we just check that a trailing newline results in a NaN
526 self.assertEqual(str(nc.create_decimal('3.14\n')), 'NaN')
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000527
528 # from tuples
529 d = Decimal( (1, (4, 3, 4, 9, 1, 3, 5, 3, 4), -25) )
530 self.assertEqual(str(d), '-4.34913534E-17')
531 d = nc.create_decimal( (1, (4, 3, 4, 9, 1, 3, 5, 3, 4), -25) )
532 self.assertEqual(str(d), '-4.35E-17')
533
534 # from Decimal
535 prevdec = Decimal(500000123)
536 d = Decimal(prevdec)
537 self.assertEqual(str(d), '500000123')
538 d = nc.create_decimal(prevdec)
539 self.assertEqual(str(d), '5.00E+8')
540
Mark Dickinson9a6e6452009-08-02 11:01:01 +0000541 def test_unicode_digits(self):
542 test_values = {
543 u'\uff11': '1',
544 u'\u0660.\u0660\u0663\u0667\u0662e-\u0663' : '0.0000372',
545 u'-nan\u0c68\u0c6a\u0c66\u0c66' : '-NaN2400',
546 }
547 for input, expected in test_values.items():
548 self.assertEqual(str(Decimal(input)), expected)
549
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000550
551class DecimalImplicitConstructionTest(unittest.TestCase):
552 '''Unit tests for Implicit Construction cases of Decimal.'''
553
554 def test_implicit_from_None(self):
555 self.assertRaises(TypeError, eval, 'Decimal(5) + None', globals())
556
557 def test_implicit_from_int(self):
558 #normal
559 self.assertEqual(str(Decimal(5) + 45), '50')
560 #exceeding precision
561 self.assertEqual(Decimal(5) + 123456789000, Decimal(123456789000))
562
563 def test_implicit_from_string(self):
564 self.assertRaises(TypeError, eval, 'Decimal(5) + "3"', globals())
565
566 def test_implicit_from_float(self):
567 self.assertRaises(TypeError, eval, 'Decimal(5) + 2.2', globals())
568
569 def test_implicit_from_Decimal(self):
570 self.assertEqual(Decimal(5) + Decimal(45), Decimal(50))
571
Raymond Hettinger267b8682005-03-27 10:47:39 +0000572 def test_rop(self):
573 # Allow other classes to be trained to interact with Decimals
574 class E:
575 def __divmod__(self, other):
576 return 'divmod ' + str(other)
577 def __rdivmod__(self, other):
578 return str(other) + ' rdivmod'
579 def __lt__(self, other):
580 return 'lt ' + str(other)
581 def __gt__(self, other):
582 return 'gt ' + str(other)
583 def __le__(self, other):
584 return 'le ' + str(other)
585 def __ge__(self, other):
586 return 'ge ' + str(other)
587 def __eq__(self, other):
588 return 'eq ' + str(other)
589 def __ne__(self, other):
590 return 'ne ' + str(other)
591
592 self.assertEqual(divmod(E(), Decimal(10)), 'divmod 10')
593 self.assertEqual(divmod(Decimal(10), E()), '10 rdivmod')
594 self.assertEqual(eval('Decimal(10) < E()'), 'gt 10')
595 self.assertEqual(eval('Decimal(10) > E()'), 'lt 10')
596 self.assertEqual(eval('Decimal(10) <= E()'), 'ge 10')
597 self.assertEqual(eval('Decimal(10) >= E()'), 'le 10')
598 self.assertEqual(eval('Decimal(10) == E()'), 'eq 10')
599 self.assertEqual(eval('Decimal(10) != E()'), 'ne 10')
600
601 # insert operator methods and then exercise them
Georg Brandl96c3f7f2006-03-28 08:06:35 +0000602 oplist = [
603 ('+', '__add__', '__radd__'),
604 ('-', '__sub__', '__rsub__'),
605 ('*', '__mul__', '__rmul__'),
606 ('%', '__mod__', '__rmod__'),
607 ('//', '__floordiv__', '__rfloordiv__'),
608 ('**', '__pow__', '__rpow__')
609 ]
610 if 1/2 == 0:
611 # testing with classic division, so add __div__
612 oplist.append(('/', '__div__', '__rdiv__'))
613 else:
614 # testing with -Qnew, so add __truediv__
615 oplist.append(('/', '__truediv__', '__rtruediv__'))
Anthony Baxter4ef3a232006-03-30 12:59:11 +0000616
Georg Brandl96c3f7f2006-03-28 08:06:35 +0000617 for sym, lop, rop in oplist:
Raymond Hettinger267b8682005-03-27 10:47:39 +0000618 setattr(E, lop, lambda self, other: 'str' + lop + str(other))
619 setattr(E, rop, lambda self, other: str(other) + rop + 'str')
620 self.assertEqual(eval('E()' + sym + 'Decimal(10)'),
621 'str' + lop + '10')
622 self.assertEqual(eval('Decimal(10)' + sym + 'E()'),
623 '10' + rop + 'str')
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000624
Mark Dickinson1ddf1d82008-02-29 02:16:37 +0000625class DecimalFormatTest(unittest.TestCase):
626 '''Unit tests for the format function.'''
627 def test_formatting(self):
628 # triples giving a format, a Decimal, and the expected result
629 test_values = [
630 ('e', '0E-15', '0e-15'),
631 ('e', '2.3E-15', '2.3e-15'),
632 ('e', '2.30E+2', '2.30e+2'), # preserve significant zeros
633 ('e', '2.30000E-15', '2.30000e-15'),
634 ('e', '1.23456789123456789e40', '1.23456789123456789e+40'),
635 ('e', '1.5', '1.5e+0'),
636 ('e', '0.15', '1.5e-1'),
637 ('e', '0.015', '1.5e-2'),
638 ('e', '0.0000000000015', '1.5e-12'),
639 ('e', '15.0', '1.50e+1'),
640 ('e', '-15', '-1.5e+1'),
641 ('e', '0', '0e+0'),
642 ('e', '0E1', '0e+1'),
643 ('e', '0.0', '0e-1'),
644 ('e', '0.00', '0e-2'),
645 ('.6e', '0E-15', '0.000000e-9'),
646 ('.6e', '0', '0.000000e+6'),
647 ('.6e', '9.999999', '9.999999e+0'),
648 ('.6e', '9.9999999', '1.000000e+1'),
649 ('.6e', '-1.23e5', '-1.230000e+5'),
650 ('.6e', '1.23456789e-3', '1.234568e-3'),
651 ('f', '0', '0'),
652 ('f', '0.0', '0.0'),
653 ('f', '0E-2', '0.00'),
654 ('f', '0.00E-8', '0.0000000000'),
655 ('f', '0E1', '0'), # loses exponent information
656 ('f', '3.2E1', '32'),
657 ('f', '3.2E2', '320'),
658 ('f', '3.20E2', '320'),
659 ('f', '3.200E2', '320.0'),
660 ('f', '3.2E-6', '0.0000032'),
661 ('.6f', '0E-15', '0.000000'), # all zeros treated equally
662 ('.6f', '0E1', '0.000000'),
663 ('.6f', '0', '0.000000'),
664 ('.0f', '0', '0'), # no decimal point
665 ('.0f', '0e-2', '0'),
666 ('.0f', '3.14159265', '3'),
667 ('.1f', '3.14159265', '3.1'),
668 ('.4f', '3.14159265', '3.1416'),
669 ('.6f', '3.14159265', '3.141593'),
670 ('.7f', '3.14159265', '3.1415926'), # round-half-even!
671 ('.8f', '3.14159265', '3.14159265'),
672 ('.9f', '3.14159265', '3.141592650'),
673
674 ('g', '0', '0'),
675 ('g', '0.0', '0.0'),
676 ('g', '0E1', '0e+1'),
677 ('G', '0E1', '0E+1'),
678 ('g', '0E-5', '0.00000'),
679 ('g', '0E-6', '0.000000'),
680 ('g', '0E-7', '0e-7'),
681 ('g', '-0E2', '-0e+2'),
682 ('.0g', '3.14159265', '3'), # 0 sig fig -> 1 sig fig
683 ('.1g', '3.14159265', '3'),
684 ('.2g', '3.14159265', '3.1'),
685 ('.5g', '3.14159265', '3.1416'),
686 ('.7g', '3.14159265', '3.141593'),
687 ('.8g', '3.14159265', '3.1415926'), # round-half-even!
688 ('.9g', '3.14159265', '3.14159265'),
689 ('.10g', '3.14159265', '3.14159265'), # don't pad
690
691 ('%', '0E1', '0%'),
692 ('%', '0E0', '0%'),
693 ('%', '0E-1', '0%'),
694 ('%', '0E-2', '0%'),
695 ('%', '0E-3', '0.0%'),
696 ('%', '0E-4', '0.00%'),
697
698 ('.3%', '0', '0.000%'), # all zeros treated equally
699 ('.3%', '0E10', '0.000%'),
700 ('.3%', '0E-10', '0.000%'),
701 ('.3%', '2.34', '234.000%'),
702 ('.3%', '1.234567', '123.457%'),
703 ('.0%', '1.23', '123%'),
704
705 ('e', 'NaN', 'NaN'),
706 ('f', '-NaN123', '-NaN123'),
707 ('+g', 'NaN456', '+NaN456'),
708 ('.3e', 'Inf', 'Infinity'),
709 ('.16f', '-Inf', '-Infinity'),
710 ('.0g', '-sNaN', '-sNaN'),
711
712 ('', '1.00', '1.00'),
Mark Dickinson71416822009-03-17 18:07:41 +0000713
714 # check alignment
715 ('<6', '123', '123 '),
716 ('>6', '123', ' 123'),
717 ('^6', '123', ' 123 '),
718 ('=+6', '123', '+ 123'),
Mark Dickinsonc3c112d2009-09-07 16:19:35 +0000719
720 # issue 6850
721 ('a=-7.0', '0.12345', 'aaaa0.1'),
Mark Dickinson1ddf1d82008-02-29 02:16:37 +0000722 ]
723 for fmt, d, result in test_values:
724 self.assertEqual(format(Decimal(d), fmt), result)
725
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000726class DecimalArithmeticOperatorsTest(unittest.TestCase):
727 '''Unit tests for all arithmetic operators, binary and unary.'''
728
729 def test_addition(self):
730
731 d1 = Decimal('-11.1')
732 d2 = Decimal('22.2')
733
734 #two Decimals
735 self.assertEqual(d1+d2, Decimal('11.1'))
736 self.assertEqual(d2+d1, Decimal('11.1'))
737
738 #with other type, left
739 c = d1 + 5
740 self.assertEqual(c, Decimal('-6.1'))
741 self.assertEqual(type(c), type(d1))
742
743 #with other type, right
744 c = 5 + d1
745 self.assertEqual(c, Decimal('-6.1'))
746 self.assertEqual(type(c), type(d1))
747
748 #inline with decimal
749 d1 += d2
750 self.assertEqual(d1, Decimal('11.1'))
751
752 #inline with other type
753 d1 += 5
754 self.assertEqual(d1, Decimal('16.1'))
755
756 def test_subtraction(self):
757
758 d1 = Decimal('-11.1')
759 d2 = Decimal('22.2')
760
761 #two Decimals
762 self.assertEqual(d1-d2, Decimal('-33.3'))
763 self.assertEqual(d2-d1, Decimal('33.3'))
764
765 #with other type, left
766 c = d1 - 5
767 self.assertEqual(c, Decimal('-16.1'))
768 self.assertEqual(type(c), type(d1))
769
770 #with other type, right
771 c = 5 - d1
772 self.assertEqual(c, Decimal('16.1'))
773 self.assertEqual(type(c), type(d1))
774
775 #inline with decimal
776 d1 -= d2
777 self.assertEqual(d1, Decimal('-33.3'))
778
779 #inline with other type
780 d1 -= 5
781 self.assertEqual(d1, Decimal('-38.3'))
782
783 def test_multiplication(self):
784
785 d1 = Decimal('-5')
786 d2 = Decimal('3')
787
788 #two Decimals
789 self.assertEqual(d1*d2, Decimal('-15'))
790 self.assertEqual(d2*d1, Decimal('-15'))
791
792 #with other type, left
793 c = d1 * 5
794 self.assertEqual(c, Decimal('-25'))
795 self.assertEqual(type(c), type(d1))
796
797 #with other type, right
798 c = 5 * d1
799 self.assertEqual(c, Decimal('-25'))
800 self.assertEqual(type(c), type(d1))
801
802 #inline with decimal
803 d1 *= d2
804 self.assertEqual(d1, Decimal('-15'))
805
806 #inline with other type
807 d1 *= 5
808 self.assertEqual(d1, Decimal('-75'))
809
810 def test_division(self):
811
812 d1 = Decimal('-5')
813 d2 = Decimal('2')
814
815 #two Decimals
816 self.assertEqual(d1/d2, Decimal('-2.5'))
817 self.assertEqual(d2/d1, Decimal('-0.4'))
818
819 #with other type, left
820 c = d1 / 4
821 self.assertEqual(c, Decimal('-1.25'))
822 self.assertEqual(type(c), type(d1))
823
824 #with other type, right
825 c = 4 / d1
826 self.assertEqual(c, Decimal('-0.8'))
827 self.assertEqual(type(c), type(d1))
828
829 #inline with decimal
830 d1 /= d2
831 self.assertEqual(d1, Decimal('-2.5'))
832
833 #inline with other type
834 d1 /= 4
835 self.assertEqual(d1, Decimal('-0.625'))
836
837 def test_floor_division(self):
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000838
839 d1 = Decimal('5')
840 d2 = Decimal('2')
841
842 #two Decimals
843 self.assertEqual(d1//d2, Decimal('2'))
844 self.assertEqual(d2//d1, Decimal('0'))
845
846 #with other type, left
847 c = d1 // 4
848 self.assertEqual(c, Decimal('1'))
849 self.assertEqual(type(c), type(d1))
850
851 #with other type, right
852 c = 7 // d1
853 self.assertEqual(c, Decimal('1'))
854 self.assertEqual(type(c), type(d1))
855
856 #inline with decimal
857 d1 //= d2
858 self.assertEqual(d1, Decimal('2'))
859
860 #inline with other type
861 d1 //= 2
862 self.assertEqual(d1, Decimal('1'))
863
864 def test_powering(self):
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000865
866 d1 = Decimal('5')
867 d2 = Decimal('2')
868
869 #two Decimals
870 self.assertEqual(d1**d2, Decimal('25'))
871 self.assertEqual(d2**d1, Decimal('32'))
872
873 #with other type, left
874 c = d1 ** 4
875 self.assertEqual(c, Decimal('625'))
876 self.assertEqual(type(c), type(d1))
877
878 #with other type, right
879 c = 7 ** d1
880 self.assertEqual(c, Decimal('16807'))
881 self.assertEqual(type(c), type(d1))
882
883 #inline with decimal
884 d1 **= d2
885 self.assertEqual(d1, Decimal('25'))
886
887 #inline with other type
888 d1 **= 4
889 self.assertEqual(d1, Decimal('390625'))
890
891 def test_module(self):
892
893 d1 = Decimal('5')
894 d2 = Decimal('2')
895
896 #two Decimals
897 self.assertEqual(d1%d2, Decimal('1'))
898 self.assertEqual(d2%d1, Decimal('2'))
899
900 #with other type, left
901 c = d1 % 4
902 self.assertEqual(c, Decimal('1'))
903 self.assertEqual(type(c), type(d1))
904
905 #with other type, right
906 c = 7 % d1
907 self.assertEqual(c, Decimal('2'))
908 self.assertEqual(type(c), type(d1))
909
910 #inline with decimal
911 d1 %= d2
912 self.assertEqual(d1, Decimal('1'))
913
914 #inline with other type
915 d1 %= 4
916 self.assertEqual(d1, Decimal('1'))
917
918 def test_floor_div_module(self):
919
920 d1 = Decimal('5')
921 d2 = Decimal('2')
922
923 #two Decimals
924 (p, q) = divmod(d1, d2)
925 self.assertEqual(p, Decimal('2'))
926 self.assertEqual(q, Decimal('1'))
927 self.assertEqual(type(p), type(d1))
928 self.assertEqual(type(q), type(d1))
929
930 #with other type, left
931 (p, q) = divmod(d1, 4)
932 self.assertEqual(p, Decimal('1'))
933 self.assertEqual(q, Decimal('1'))
934 self.assertEqual(type(p), type(d1))
935 self.assertEqual(type(q), type(d1))
936
937 #with other type, right
938 (p, q) = divmod(7, d1)
939 self.assertEqual(p, Decimal('1'))
940 self.assertEqual(q, Decimal('2'))
941 self.assertEqual(type(p), type(d1))
942 self.assertEqual(type(q), type(d1))
943
944 def test_unary_operators(self):
945 self.assertEqual(+Decimal(45), Decimal(+45)) # +
946 self.assertEqual(-Decimal(45), Decimal(-45)) # -
947 self.assertEqual(abs(Decimal(45)), abs(Decimal(-45))) # abs
948
Mark Dickinson2fc92632008-02-06 22:10:50 +0000949 def test_nan_comparisons(self):
950 n = Decimal('NaN')
951 s = Decimal('sNaN')
952 i = Decimal('Inf')
953 f = Decimal('2')
954 for x, y in [(n, n), (n, i), (i, n), (n, f), (f, n),
955 (s, n), (n, s), (s, i), (i, s), (s, f), (f, s), (s, s)]:
956 self.assert_(x != y)
957 self.assert_(not (x == y))
958 self.assert_(not (x < y))
959 self.assert_(not (x <= y))
960 self.assert_(not (x > y))
961 self.assert_(not (x >= y))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000962
963# The following are two functions used to test threading in the next class
964
965def thfunc1(cls):
966 d1 = Decimal(1)
967 d3 = Decimal(3)
Facundo Batista64156672008-03-22 02:45:37 +0000968 test1 = d1/d3
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000969 cls.synchro.wait()
Facundo Batista64156672008-03-22 02:45:37 +0000970 test2 = d1/d3
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000971 cls.finish1.set()
Facundo Batista64156672008-03-22 02:45:37 +0000972
Facundo Batistaee340e52008-05-02 17:39:00 +0000973 cls.assertEqual(test1, Decimal('0.3333333333333333333333333333'))
974 cls.assertEqual(test2, Decimal('0.3333333333333333333333333333'))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000975 return
976
977def thfunc2(cls):
978 d1 = Decimal(1)
979 d3 = Decimal(3)
Facundo Batista64156672008-03-22 02:45:37 +0000980 test1 = d1/d3
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000981 thiscontext = getcontext()
982 thiscontext.prec = 18
Facundo Batista64156672008-03-22 02:45:37 +0000983 test2 = d1/d3
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000984 cls.synchro.set()
985 cls.finish2.set()
Facundo Batista64156672008-03-22 02:45:37 +0000986
Facundo Batistaee340e52008-05-02 17:39:00 +0000987 cls.assertEqual(test1, Decimal('0.3333333333333333333333333333'))
Facundo Batista64156672008-03-22 02:45:37 +0000988 cls.assertEqual(test2, Decimal('0.333333333333333333'))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000989 return
990
991
992class DecimalUseOfContextTest(unittest.TestCase):
993 '''Unit tests for Use of Context cases in Decimal.'''
994
Raymond Hettinger7e71fa52004-12-18 19:07:19 +0000995 try:
996 import threading
997 except ImportError:
998 threading = None
999
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001000 # Take care executing this test from IDLE, there's an issue in threading
1001 # that hangs IDLE and I couldn't find it
1002
1003 def test_threading(self):
1004 #Test the "threading isolation" of a Context.
1005
1006 self.synchro = threading.Event()
1007 self.finish1 = threading.Event()
1008 self.finish2 = threading.Event()
1009
1010 th1 = threading.Thread(target=thfunc1, args=(self,))
1011 th2 = threading.Thread(target=thfunc2, args=(self,))
1012
1013 th1.start()
1014 th2.start()
1015
1016 self.finish1.wait()
Thomas Woutersb3e6e8c2007-09-19 17:27:29 +00001017 self.finish2.wait()
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001018 return
1019
Raymond Hettinger7e71fa52004-12-18 19:07:19 +00001020 if threading is None:
1021 del test_threading
1022
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001023
1024class DecimalUsabilityTest(unittest.TestCase):
1025 '''Unit tests for Usability cases of Decimal.'''
1026
1027 def test_comparison_operators(self):
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001028
1029 da = Decimal('23.42')
1030 db = Decimal('23.42')
1031 dc = Decimal('45')
1032
1033 #two Decimals
1034 self.failUnless(dc > da)
1035 self.failUnless(dc >= da)
1036 self.failUnless(da < dc)
1037 self.failUnless(da <= dc)
1038 self.failUnless(da == db)
1039 self.failUnless(da != dc)
1040 self.failUnless(da <= db)
1041 self.failUnless(da >= db)
1042 self.assertEqual(cmp(dc,da), 1)
1043 self.assertEqual(cmp(da,dc), -1)
1044 self.assertEqual(cmp(da,db), 0)
1045
1046 #a Decimal and an int
1047 self.failUnless(dc > 23)
1048 self.failUnless(23 < dc)
1049 self.failUnless(dc == 45)
1050 self.assertEqual(cmp(dc,23), 1)
1051 self.assertEqual(cmp(23,dc), -1)
1052 self.assertEqual(cmp(dc,45), 0)
1053
1054 #a Decimal and uncomparable
Raymond Hettinger0aeac102004-07-05 22:53:03 +00001055 self.assertNotEqual(da, 'ugly')
1056 self.assertNotEqual(da, 32.7)
1057 self.assertNotEqual(da, object())
1058 self.assertNotEqual(da, object)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001059
Raymond Hettinger0aeac102004-07-05 22:53:03 +00001060 # sortable
1061 a = map(Decimal, xrange(100))
1062 b = a[:]
1063 random.shuffle(a)
1064 a.sort()
1065 self.assertEqual(a, b)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001066
Facundo Batista353750c2007-09-13 18:13:15 +00001067 # with None
1068 self.assertFalse(Decimal(1) < None)
1069 self.assertTrue(Decimal(1) > None)
1070
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001071 def test_copy_and_deepcopy_methods(self):
1072 d = Decimal('43.24')
1073 c = copy.copy(d)
1074 self.assertEqual(id(c), id(d))
1075 dc = copy.deepcopy(d)
1076 self.assertEqual(id(dc), id(d))
1077
1078 def test_hash_method(self):
1079 #just that it's hashable
1080 hash(Decimal(23))
Facundo Batista8c202442007-09-19 17:53:25 +00001081
1082 test_values = [Decimal(sign*(2**m + n))
1083 for m in [0, 14, 15, 16, 17, 30, 31,
1084 32, 33, 62, 63, 64, 65, 66]
1085 for n in range(-10, 10)
1086 for sign in [-1, 1]]
1087 test_values.extend([
1088 Decimal("-0"), # zeros
1089 Decimal("0.00"),
1090 Decimal("-0.000"),
1091 Decimal("0E10"),
1092 Decimal("-0E12"),
1093 Decimal("10.0"), # negative exponent
1094 Decimal("-23.00000"),
1095 Decimal("1230E100"), # positive exponent
1096 Decimal("-4.5678E50"),
1097 # a value for which hash(n) != hash(n % (2**64-1))
1098 # in Python pre-2.6
1099 Decimal(2**64 + 2**32 - 1),
1100 # selection of values which fail with the old (before
1101 # version 2.6) long.__hash__
1102 Decimal("1.634E100"),
1103 Decimal("90.697E100"),
1104 Decimal("188.83E100"),
1105 Decimal("1652.9E100"),
1106 Decimal("56531E100"),
1107 ])
1108
1109 # check that hash(d) == hash(int(d)) for integral values
1110 for value in test_values:
1111 self.assertEqual(hash(value), hash(int(value)))
1112
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001113 #the same hash that to an int
1114 self.assertEqual(hash(Decimal(23)), hash(23))
Raymond Hettingerbea3f6f2005-03-15 04:59:17 +00001115 self.assertRaises(TypeError, hash, Decimal('NaN'))
1116 self.assert_(hash(Decimal('Inf')))
1117 self.assert_(hash(Decimal('-Inf')))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001118
Facundo Batista52b25792008-01-08 12:25:20 +00001119 # check that the value of the hash doesn't depend on the
1120 # current context (issue #1757)
1121 c = getcontext()
1122 old_precision = c.prec
1123 x = Decimal("123456789.1")
1124
1125 c.prec = 6
1126 h1 = hash(x)
1127 c.prec = 10
1128 h2 = hash(x)
1129 c.prec = 16
1130 h3 = hash(x)
1131
1132 self.assertEqual(h1, h2)
1133 self.assertEqual(h1, h3)
1134 c.prec = old_precision
1135
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001136 def test_min_and_max_methods(self):
1137
1138 d1 = Decimal('15.32')
1139 d2 = Decimal('28.5')
1140 l1 = 15
1141 l2 = 28
1142
1143 #between Decimals
1144 self.failUnless(min(d1,d2) is d1)
1145 self.failUnless(min(d2,d1) is d1)
1146 self.failUnless(max(d1,d2) is d2)
1147 self.failUnless(max(d2,d1) is d2)
1148
1149 #between Decimal and long
1150 self.failUnless(min(d1,l2) is d1)
1151 self.failUnless(min(l2,d1) is d1)
1152 self.failUnless(max(l1,d2) is d2)
1153 self.failUnless(max(d2,l1) is d2)
1154
1155 def test_as_nonzero(self):
1156 #as false
1157 self.failIf(Decimal(0))
1158 #as true
1159 self.failUnless(Decimal('0.372'))
1160
1161 def test_tostring_methods(self):
1162 #Test str and repr methods.
1163
1164 d = Decimal('15.32')
1165 self.assertEqual(str(d), '15.32') # str
Raymond Hettingerabe32372008-02-14 02:41:22 +00001166 self.assertEqual(repr(d), "Decimal('15.32')") # repr
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001167
Mark Dickinson8e85ffa2008-03-25 18:47:59 +00001168 # result type of string methods should be str, not unicode
1169 unicode_inputs = [u'123.4', u'0.5E2', u'Infinity', u'sNaN',
1170 u'-0.0E100', u'-NaN001', u'-Inf']
1171
1172 for u in unicode_inputs:
1173 d = Decimal(u)
1174 self.assertEqual(type(str(d)), str)
1175 self.assertEqual(type(repr(d)), str)
1176 self.assertEqual(type(d.to_eng_string()), str)
1177
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001178 def test_tonum_methods(self):
1179 #Test float, int and long methods.
1180
1181 d1 = Decimal('66')
1182 d2 = Decimal('15.32')
1183
1184 #int
1185 self.assertEqual(int(d1), 66)
1186 self.assertEqual(int(d2), 15)
1187
1188 #long
1189 self.assertEqual(long(d1), 66)
1190 self.assertEqual(long(d2), 15)
1191
1192 #float
1193 self.assertEqual(float(d1), 66)
1194 self.assertEqual(float(d2), 15.32)
1195
1196 def test_eval_round_trip(self):
1197
1198 #with zero
1199 d = Decimal( (0, (0,), 0) )
1200 self.assertEqual(d, eval(repr(d)))
1201
1202 #int
1203 d = Decimal( (1, (4, 5), 0) )
1204 self.assertEqual(d, eval(repr(d)))
1205
1206 #float
1207 d = Decimal( (0, (4, 5, 3, 4), -2) )
1208 self.assertEqual(d, eval(repr(d)))
1209
1210 #weird
1211 d = Decimal( (1, (4, 3, 4, 9, 1, 3, 5, 3, 4), -25) )
1212 self.assertEqual(d, eval(repr(d)))
1213
1214 def test_as_tuple(self):
1215
1216 #with zero
1217 d = Decimal(0)
1218 self.assertEqual(d.as_tuple(), (0, (0,), 0) )
1219
1220 #int
1221 d = Decimal(-45)
1222 self.assertEqual(d.as_tuple(), (1, (4, 5), 0) )
1223
1224 #complicated string
1225 d = Decimal("-4.34913534E-17")
1226 self.assertEqual(d.as_tuple(), (1, (4, 3, 4, 9, 1, 3, 5, 3, 4), -25) )
1227
1228 #inf
1229 d = Decimal("Infinity")
1230 self.assertEqual(d.as_tuple(), (0, (0,), 'F') )
1231
Facundo Batista9b5e2312007-10-19 19:25:57 +00001232 #leading zeros in coefficient should be stripped
1233 d = Decimal( (0, (0, 0, 4, 0, 5, 3, 4), -2) )
1234 self.assertEqual(d.as_tuple(), (0, (4, 0, 5, 3, 4), -2) )
1235 d = Decimal( (1, (0, 0, 0), 37) )
1236 self.assertEqual(d.as_tuple(), (1, (0,), 37))
1237 d = Decimal( (1, (), 37) )
1238 self.assertEqual(d.as_tuple(), (1, (0,), 37))
1239
1240 #leading zeros in NaN diagnostic info should be stripped
1241 d = Decimal( (0, (0, 0, 4, 0, 5, 3, 4), 'n') )
1242 self.assertEqual(d.as_tuple(), (0, (4, 0, 5, 3, 4), 'n') )
1243 d = Decimal( (1, (0, 0, 0), 'N') )
1244 self.assertEqual(d.as_tuple(), (1, (), 'N') )
1245 d = Decimal( (1, (), 'n') )
1246 self.assertEqual(d.as_tuple(), (1, (), 'n') )
1247
1248 #coefficient in infinity should be ignored
1249 d = Decimal( (0, (4, 5, 3, 4), 'F') )
1250 self.assertEqual(d.as_tuple(), (0, (0,), 'F'))
1251 d = Decimal( (1, (0, 2, 7, 1), 'F') )
1252 self.assertEqual(d.as_tuple(), (1, (0,), 'F'))
1253
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001254 def test_immutability_operations(self):
1255 # Do operations and check that it didn't change change internal objects.
1256
1257 d1 = Decimal('-25e55')
1258 b1 = Decimal('-25e55')
Facundo Batista353750c2007-09-13 18:13:15 +00001259 d2 = Decimal('33e+33')
1260 b2 = Decimal('33e+33')
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001261
1262 def checkSameDec(operation, useOther=False):
1263 if useOther:
1264 eval("d1." + operation + "(d2)")
1265 self.assertEqual(d1._sign, b1._sign)
1266 self.assertEqual(d1._int, b1._int)
1267 self.assertEqual(d1._exp, b1._exp)
1268 self.assertEqual(d2._sign, b2._sign)
1269 self.assertEqual(d2._int, b2._int)
1270 self.assertEqual(d2._exp, b2._exp)
1271 else:
1272 eval("d1." + operation + "()")
1273 self.assertEqual(d1._sign, b1._sign)
1274 self.assertEqual(d1._int, b1._int)
1275 self.assertEqual(d1._exp, b1._exp)
1276 return
1277
1278 Decimal(d1)
1279 self.assertEqual(d1._sign, b1._sign)
1280 self.assertEqual(d1._int, b1._int)
1281 self.assertEqual(d1._exp, b1._exp)
1282
1283 checkSameDec("__abs__")
1284 checkSameDec("__add__", True)
1285 checkSameDec("__div__", True)
1286 checkSameDec("__divmod__", True)
Mark Dickinson2fc92632008-02-06 22:10:50 +00001287 checkSameDec("__eq__", True)
1288 checkSameDec("__ne__", True)
1289 checkSameDec("__le__", True)
1290 checkSameDec("__lt__", True)
1291 checkSameDec("__ge__", True)
1292 checkSameDec("__gt__", True)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001293 checkSameDec("__float__")
1294 checkSameDec("__floordiv__", True)
1295 checkSameDec("__hash__")
1296 checkSameDec("__int__")
Raymond Hettinger5a053642008-01-24 19:05:29 +00001297 checkSameDec("__trunc__")
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001298 checkSameDec("__long__")
1299 checkSameDec("__mod__", True)
1300 checkSameDec("__mul__", True)
1301 checkSameDec("__neg__")
1302 checkSameDec("__nonzero__")
1303 checkSameDec("__pos__")
1304 checkSameDec("__pow__", True)
1305 checkSameDec("__radd__", True)
1306 checkSameDec("__rdiv__", True)
1307 checkSameDec("__rdivmod__", True)
1308 checkSameDec("__repr__")
1309 checkSameDec("__rfloordiv__", True)
1310 checkSameDec("__rmod__", True)
1311 checkSameDec("__rmul__", True)
1312 checkSameDec("__rpow__", True)
1313 checkSameDec("__rsub__", True)
1314 checkSameDec("__str__")
1315 checkSameDec("__sub__", True)
1316 checkSameDec("__truediv__", True)
1317 checkSameDec("adjusted")
1318 checkSameDec("as_tuple")
1319 checkSameDec("compare", True)
1320 checkSameDec("max", True)
1321 checkSameDec("min", True)
1322 checkSameDec("normalize")
1323 checkSameDec("quantize", True)
1324 checkSameDec("remainder_near", True)
1325 checkSameDec("same_quantum", True)
1326 checkSameDec("sqrt")
1327 checkSameDec("to_eng_string")
1328 checkSameDec("to_integral")
1329
Facundo Batista6c398da2007-09-17 17:30:13 +00001330 def test_subclassing(self):
1331 # Different behaviours when subclassing Decimal
1332
1333 class MyDecimal(Decimal):
1334 pass
1335
1336 d1 = MyDecimal(1)
1337 d2 = MyDecimal(2)
1338 d = d1 + d2
1339 self.assertTrue(type(d) is Decimal)
1340
1341 d = d1.max(d2)
1342 self.assertTrue(type(d) is Decimal)
1343
Mark Dickinson3b24ccb2008-03-25 14:33:23 +00001344 def test_implicit_context(self):
1345 # Check results when context given implicitly. (Issue 2478)
1346 c = getcontext()
1347 self.assertEqual(str(Decimal(0).sqrt()),
1348 str(c.sqrt(Decimal(0))))
1349
Facundo Batista6c398da2007-09-17 17:30:13 +00001350
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001351class DecimalPythonAPItests(unittest.TestCase):
1352
Raymond Hettinger45fd4762009-02-03 03:42:07 +00001353 def test_abc(self):
1354 self.assert_(issubclass(Decimal, numbers.Number))
1355 self.assert_(not issubclass(Decimal, numbers.Real))
1356 self.assert_(isinstance(Decimal(0), numbers.Number))
1357 self.assert_(not isinstance(Decimal(0), numbers.Real))
1358
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001359 def test_pickle(self):
1360 d = Decimal('-3.141590000')
1361 p = pickle.dumps(d)
1362 e = pickle.loads(p)
1363 self.assertEqual(d, e)
1364
Raymond Hettinger5548be22004-07-05 18:49:38 +00001365 def test_int(self):
Raymond Hettinger605ed022004-11-24 07:28:48 +00001366 for x in range(-250, 250):
1367 s = '%0.2f' % (x / 100.0)
Raymond Hettinger5548be22004-07-05 18:49:38 +00001368 # should work the same as for floats
1369 self.assertEqual(int(Decimal(s)), int(float(s)))
Raymond Hettinger605ed022004-11-24 07:28:48 +00001370 # should work the same as to_integral in the ROUND_DOWN mode
Raymond Hettinger5548be22004-07-05 18:49:38 +00001371 d = Decimal(s)
Raymond Hettinger605ed022004-11-24 07:28:48 +00001372 r = d.to_integral(ROUND_DOWN)
Raymond Hettinger5548be22004-07-05 18:49:38 +00001373 self.assertEqual(Decimal(int(d)), r)
1374
Raymond Hettinger5a053642008-01-24 19:05:29 +00001375 def test_trunc(self):
1376 for x in range(-250, 250):
1377 s = '%0.2f' % (x / 100.0)
1378 # should work the same as for floats
1379 self.assertEqual(int(Decimal(s)), int(float(s)))
1380 # should work the same as to_integral in the ROUND_DOWN mode
1381 d = Decimal(s)
1382 r = d.to_integral(ROUND_DOWN)
Jeffrey Yasskinca2b69f2008-02-01 06:22:46 +00001383 self.assertEqual(Decimal(math.trunc(d)), r)
Raymond Hettinger5a053642008-01-24 19:05:29 +00001384
Raymond Hettingerd9c0a7a2004-07-03 10:02:28 +00001385class ContextAPItests(unittest.TestCase):
1386
1387 def test_pickle(self):
1388 c = Context()
1389 e = pickle.loads(pickle.dumps(c))
1390 for k in vars(c):
1391 v1 = vars(c)[k]
1392 v2 = vars(e)[k]
1393 self.assertEqual(v1, v2)
1394
Raymond Hettinger0aeac102004-07-05 22:53:03 +00001395 def test_equality_with_other_types(self):
1396 self.assert_(Decimal(10) in ['a', 1.0, Decimal(10), (1,2), {}])
1397 self.assert_(Decimal(10) not in ['a', 1.0, (1,2), {}])
1398
Raymond Hettinger955d2b22004-08-08 20:17:45 +00001399 def test_copy(self):
1400 # All copies should be deep
1401 c = Context()
1402 d = c.copy()
1403 self.assertNotEqual(id(c), id(d))
1404 self.assertNotEqual(id(c.flags), id(d.flags))
1405 self.assertNotEqual(id(c.traps), id(d.traps))
1406
Nick Coghlan8b6999b2006-08-31 12:00:43 +00001407class WithStatementTest(unittest.TestCase):
1408 # Can't do these as docstrings until Python 2.6
1409 # as doctest can't handle __future__ statements
Nick Coghlan8b6999b2006-08-31 12:00:43 +00001410
1411 def test_localcontext(self):
Nick Coghlanced12182006-09-02 03:54:17 +00001412 # Use a copy of the current context in the block
Nick Coghlan8b6999b2006-08-31 12:00:43 +00001413 orig_ctx = getcontext()
1414 with localcontext() as enter_ctx:
1415 set_ctx = getcontext()
1416 final_ctx = getcontext()
1417 self.assert_(orig_ctx is final_ctx, 'did not restore context correctly')
1418 self.assert_(orig_ctx is not set_ctx, 'did not copy the context')
1419 self.assert_(set_ctx is enter_ctx, '__enter__ returned wrong context')
1420
1421 def test_localcontextarg(self):
Nick Coghlanced12182006-09-02 03:54:17 +00001422 # Use a copy of the supplied context in the block
Nick Coghlan8b6999b2006-08-31 12:00:43 +00001423 orig_ctx = getcontext()
1424 new_ctx = Context(prec=42)
1425 with localcontext(new_ctx) as enter_ctx:
1426 set_ctx = getcontext()
1427 final_ctx = getcontext()
1428 self.assert_(orig_ctx is final_ctx, 'did not restore context correctly')
1429 self.assert_(set_ctx.prec == new_ctx.prec, 'did not set correct context')
1430 self.assert_(new_ctx is not set_ctx, 'did not copy the context')
1431 self.assert_(set_ctx is enter_ctx, '__enter__ returned wrong context')
1432
Facundo Batista353750c2007-09-13 18:13:15 +00001433class ContextFlags(unittest.TestCase):
1434 def test_flags_irrelevant(self):
1435 # check that the result (numeric result + flags raised) of an
1436 # arithmetic operation doesn't depend on the current flags
1437
1438 context = Context(prec=9, Emin = -999999999, Emax = 999999999,
1439 rounding=ROUND_HALF_EVEN, traps=[], flags=[])
1440
1441 # operations that raise various flags, in the form (function, arglist)
1442 operations = [
1443 (context._apply, [Decimal("100E-1000000009")]),
1444 (context.sqrt, [Decimal(2)]),
1445 (context.add, [Decimal("1.23456789"), Decimal("9.87654321")]),
1446 (context.multiply, [Decimal("1.23456789"), Decimal("9.87654321")]),
1447 (context.subtract, [Decimal("1.23456789"), Decimal("9.87654321")]),
1448 ]
1449
1450 # try various flags individually, then a whole lot at once
1451 flagsets = [[Inexact], [Rounded], [Underflow], [Clamped], [Subnormal],
1452 [Inexact, Rounded, Underflow, Clamped, Subnormal]]
1453
1454 for fn, args in operations:
1455 # find answer and flags raised using a clean context
1456 context.clear_flags()
1457 ans = fn(*args)
1458 flags = [k for k, v in context.flags.items() if v]
1459
1460 for extra_flags in flagsets:
1461 # set flags, before calling operation
1462 context.clear_flags()
1463 for flag in extra_flags:
1464 context._raise_error(flag)
1465 new_ans = fn(*args)
1466
1467 # flags that we expect to be set after the operation
1468 expected_flags = list(flags)
1469 for flag in extra_flags:
1470 if flag not in expected_flags:
1471 expected_flags.append(flag)
1472 expected_flags.sort()
1473
1474 # flags we actually got
1475 new_flags = [k for k,v in context.flags.items() if v]
1476 new_flags.sort()
1477
1478 self.assertEqual(ans, new_ans,
1479 "operation produces different answers depending on flags set: " +
1480 "expected %s, got %s." % (ans, new_ans))
1481 self.assertEqual(new_flags, expected_flags,
1482 "operation raises different flags depending on flags set: " +
1483 "expected %s, got %s" % (expected_flags, new_flags))
1484
1485def test_main(arith=False, verbose=None, todo_tests=None, debug=None):
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001486 """ Execute the tests.
1487
Raymond Hettingered20ad82004-09-04 20:09:13 +00001488 Runs all arithmetic tests if arith is True or if the "decimal" resource
1489 is enabled in regrtest.py
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001490 """
Raymond Hettingered20ad82004-09-04 20:09:13 +00001491
Neal Norwitzce4a9c92006-04-09 08:36:46 +00001492 init()
Facundo Batista353750c2007-09-13 18:13:15 +00001493 global TEST_ALL, DEBUG
Raymond Hettingered20ad82004-09-04 20:09:13 +00001494 TEST_ALL = arith or is_resource_enabled('decimal')
Facundo Batista353750c2007-09-13 18:13:15 +00001495 DEBUG = debug
Raymond Hettingered20ad82004-09-04 20:09:13 +00001496
Facundo Batista353750c2007-09-13 18:13:15 +00001497 if todo_tests is None:
1498 test_classes = [
1499 DecimalExplicitConstructionTest,
1500 DecimalImplicitConstructionTest,
1501 DecimalArithmeticOperatorsTest,
Mark Dickinson1ddf1d82008-02-29 02:16:37 +00001502 DecimalFormatTest,
Facundo Batista353750c2007-09-13 18:13:15 +00001503 DecimalUseOfContextTest,
1504 DecimalUsabilityTest,
1505 DecimalPythonAPItests,
1506 ContextAPItests,
1507 DecimalTest,
1508 WithStatementTest,
1509 ContextFlags
1510 ]
1511 else:
1512 test_classes = [DecimalTest]
1513
1514 # Dynamically build custom test definition for each file in the test
1515 # directory and add the definitions to the DecimalTest class. This
1516 # procedure insures that new files do not get skipped.
1517 for filename in os.listdir(directory):
1518 if '.decTest' not in filename or filename.startswith("."):
1519 continue
1520 head, tail = filename.split('.')
1521 if todo_tests is not None and head not in todo_tests:
1522 continue
1523 tester = lambda self, f=filename: self.eval_file(directory + f)
1524 setattr(DecimalTest, 'test_' + head, tester)
1525 del filename, head, tail, tester
1526
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001527
Tim Peters46cc7022006-03-31 04:11:16 +00001528 try:
1529 run_unittest(*test_classes)
Facundo Batista353750c2007-09-13 18:13:15 +00001530 if todo_tests is None:
1531 import decimal as DecimalModule
1532 run_doctest(DecimalModule, verbose)
Tim Peters46cc7022006-03-31 04:11:16 +00001533 finally:
1534 setcontext(ORIGINAL_CONTEXT)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001535
1536if __name__ == '__main__':
Facundo Batista353750c2007-09-13 18:13:15 +00001537 import optparse
1538 p = optparse.OptionParser("test_decimal.py [--debug] [{--skip | test1 [test2 [...]]}]")
1539 p.add_option('--debug', '-d', action='store_true', help='shows the test number and context before each test')
1540 p.add_option('--skip', '-s', action='store_true', help='skip over 90% of the arithmetic tests')
1541 (opt, args) = p.parse_args()
1542
1543 if opt.skip:
1544 test_main(arith=False, verbose=True)
1545 elif args:
1546 test_main(arith=True, verbose=True, todo_tests=args, debug=opt.debug)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001547 else:
Facundo Batista353750c2007-09-13 18:13:15 +00001548 test_main(arith=True, verbose=True)