blob: 92b029e8edc786b3a7d13c8db6c73274e180e8f6 [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
Mark Dickinson70c32892008-07-02 09:37:01 +0000435 #but alternate unicode digits should not
436 self.assertEqual(str(Decimal(u'\uff11')), 'NaN')
437
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000438 def test_explicit_from_tuples(self):
439
440 #zero
441 d = Decimal( (0, (0,), 0) )
442 self.assertEqual(str(d), '0')
443
444 #int
445 d = Decimal( (1, (4, 5), 0) )
446 self.assertEqual(str(d), '-45')
447
448 #float
449 d = Decimal( (0, (4, 5, 3, 4), -2) )
450 self.assertEqual(str(d), '45.34')
451
452 #weird
453 d = Decimal( (1, (4, 3, 4, 9, 1, 3, 5, 3, 4), -25) )
454 self.assertEqual(str(d), '-4.34913534E-17')
455
456 #wrong number of items
457 self.assertRaises(ValueError, Decimal, (1, (4, 3, 4, 9, 1)) )
458
459 #bad sign
460 self.assertRaises(ValueError, Decimal, (8, (4, 3, 4, 9, 1), 2) )
Facundo Batista9b5e2312007-10-19 19:25:57 +0000461 self.assertRaises(ValueError, Decimal, (0., (4, 3, 4, 9, 1), 2) )
462 self.assertRaises(ValueError, Decimal, (Decimal(1), (4, 3, 4, 9, 1), 2))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000463
464 #bad exp
465 self.assertRaises(ValueError, Decimal, (1, (4, 3, 4, 9, 1), 'wrong!') )
Facundo Batista9b5e2312007-10-19 19:25:57 +0000466 self.assertRaises(ValueError, Decimal, (1, (4, 3, 4, 9, 1), 0.) )
467 self.assertRaises(ValueError, Decimal, (1, (4, 3, 4, 9, 1), '1') )
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000468
469 #bad coefficients
470 self.assertRaises(ValueError, Decimal, (1, (4, 3, 4, None, 1), 2) )
471 self.assertRaises(ValueError, Decimal, (1, (4, -3, 4, 9, 1), 2) )
Facundo Batista9b5e2312007-10-19 19:25:57 +0000472 self.assertRaises(ValueError, Decimal, (1, (4, 10, 4, 9, 1), 2) )
Facundo Batista72bc54f2007-11-23 17:59:00 +0000473 self.assertRaises(ValueError, Decimal, (1, (4, 3, 4, 'a', 1), 2) )
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000474
475 def test_explicit_from_Decimal(self):
476
477 #positive
478 d = Decimal(45)
479 e = Decimal(d)
480 self.assertEqual(str(e), '45')
481 self.assertNotEqual(id(d), id(e))
482
483 #very large positive
484 d = Decimal(500000123)
485 e = Decimal(d)
486 self.assertEqual(str(e), '500000123')
487 self.assertNotEqual(id(d), id(e))
488
489 #negative
490 d = Decimal(-45)
491 e = Decimal(d)
492 self.assertEqual(str(e), '-45')
493 self.assertNotEqual(id(d), id(e))
494
495 #zero
496 d = Decimal(0)
497 e = Decimal(d)
498 self.assertEqual(str(e), '0')
499 self.assertNotEqual(id(d), id(e))
500
501 def test_explicit_context_create_decimal(self):
502
503 nc = copy.copy(getcontext())
504 nc.prec = 3
505
506 # empty
Raymond Hettingerfed52962004-07-14 15:41:57 +0000507 d = Decimal()
508 self.assertEqual(str(d), '0')
509 d = nc.create_decimal()
510 self.assertEqual(str(d), '0')
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000511
512 # from None
513 self.assertRaises(TypeError, nc.create_decimal, None)
514
515 # from int
516 d = nc.create_decimal(456)
517 self.failUnless(isinstance(d, Decimal))
518 self.assertEqual(nc.create_decimal(45678),
519 nc.create_decimal('457E+2'))
520
521 # from string
522 d = Decimal('456789')
523 self.assertEqual(str(d), '456789')
524 d = nc.create_decimal('456789')
525 self.assertEqual(str(d), '4.57E+5')
Mark Dickinson59bc20b2008-01-12 01:56:00 +0000526 # leading and trailing whitespace should result in a NaN;
527 # spaces are already checked in Cowlishaw's test-suite, so
528 # here we just check that a trailing newline results in a NaN
529 self.assertEqual(str(nc.create_decimal('3.14\n')), 'NaN')
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000530
531 # from tuples
532 d = Decimal( (1, (4, 3, 4, 9, 1, 3, 5, 3, 4), -25) )
533 self.assertEqual(str(d), '-4.34913534E-17')
534 d = nc.create_decimal( (1, (4, 3, 4, 9, 1, 3, 5, 3, 4), -25) )
535 self.assertEqual(str(d), '-4.35E-17')
536
537 # from Decimal
538 prevdec = Decimal(500000123)
539 d = Decimal(prevdec)
540 self.assertEqual(str(d), '500000123')
541 d = nc.create_decimal(prevdec)
542 self.assertEqual(str(d), '5.00E+8')
543
544
545class DecimalImplicitConstructionTest(unittest.TestCase):
546 '''Unit tests for Implicit Construction cases of Decimal.'''
547
548 def test_implicit_from_None(self):
549 self.assertRaises(TypeError, eval, 'Decimal(5) + None', globals())
550
551 def test_implicit_from_int(self):
552 #normal
553 self.assertEqual(str(Decimal(5) + 45), '50')
554 #exceeding precision
555 self.assertEqual(Decimal(5) + 123456789000, Decimal(123456789000))
556
557 def test_implicit_from_string(self):
558 self.assertRaises(TypeError, eval, 'Decimal(5) + "3"', globals())
559
560 def test_implicit_from_float(self):
561 self.assertRaises(TypeError, eval, 'Decimal(5) + 2.2', globals())
562
563 def test_implicit_from_Decimal(self):
564 self.assertEqual(Decimal(5) + Decimal(45), Decimal(50))
565
Raymond Hettinger267b8682005-03-27 10:47:39 +0000566 def test_rop(self):
567 # Allow other classes to be trained to interact with Decimals
568 class E:
569 def __divmod__(self, other):
570 return 'divmod ' + str(other)
571 def __rdivmod__(self, other):
572 return str(other) + ' rdivmod'
573 def __lt__(self, other):
574 return 'lt ' + str(other)
575 def __gt__(self, other):
576 return 'gt ' + str(other)
577 def __le__(self, other):
578 return 'le ' + str(other)
579 def __ge__(self, other):
580 return 'ge ' + str(other)
581 def __eq__(self, other):
582 return 'eq ' + str(other)
583 def __ne__(self, other):
584 return 'ne ' + str(other)
585
586 self.assertEqual(divmod(E(), Decimal(10)), 'divmod 10')
587 self.assertEqual(divmod(Decimal(10), E()), '10 rdivmod')
588 self.assertEqual(eval('Decimal(10) < E()'), 'gt 10')
589 self.assertEqual(eval('Decimal(10) > E()'), 'lt 10')
590 self.assertEqual(eval('Decimal(10) <= E()'), 'ge 10')
591 self.assertEqual(eval('Decimal(10) >= E()'), 'le 10')
592 self.assertEqual(eval('Decimal(10) == E()'), 'eq 10')
593 self.assertEqual(eval('Decimal(10) != E()'), 'ne 10')
594
595 # insert operator methods and then exercise them
Georg Brandl96c3f7f2006-03-28 08:06:35 +0000596 oplist = [
597 ('+', '__add__', '__radd__'),
598 ('-', '__sub__', '__rsub__'),
599 ('*', '__mul__', '__rmul__'),
600 ('%', '__mod__', '__rmod__'),
601 ('//', '__floordiv__', '__rfloordiv__'),
602 ('**', '__pow__', '__rpow__')
603 ]
604 if 1/2 == 0:
605 # testing with classic division, so add __div__
606 oplist.append(('/', '__div__', '__rdiv__'))
607 else:
608 # testing with -Qnew, so add __truediv__
609 oplist.append(('/', '__truediv__', '__rtruediv__'))
Anthony Baxter4ef3a232006-03-30 12:59:11 +0000610
Georg Brandl96c3f7f2006-03-28 08:06:35 +0000611 for sym, lop, rop in oplist:
Raymond Hettinger267b8682005-03-27 10:47:39 +0000612 setattr(E, lop, lambda self, other: 'str' + lop + str(other))
613 setattr(E, rop, lambda self, other: str(other) + rop + 'str')
614 self.assertEqual(eval('E()' + sym + 'Decimal(10)'),
615 'str' + lop + '10')
616 self.assertEqual(eval('Decimal(10)' + sym + 'E()'),
617 '10' + rop + 'str')
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000618
Mark Dickinson1ddf1d82008-02-29 02:16:37 +0000619class DecimalFormatTest(unittest.TestCase):
620 '''Unit tests for the format function.'''
621 def test_formatting(self):
622 # triples giving a format, a Decimal, and the expected result
623 test_values = [
624 ('e', '0E-15', '0e-15'),
625 ('e', '2.3E-15', '2.3e-15'),
626 ('e', '2.30E+2', '2.30e+2'), # preserve significant zeros
627 ('e', '2.30000E-15', '2.30000e-15'),
628 ('e', '1.23456789123456789e40', '1.23456789123456789e+40'),
629 ('e', '1.5', '1.5e+0'),
630 ('e', '0.15', '1.5e-1'),
631 ('e', '0.015', '1.5e-2'),
632 ('e', '0.0000000000015', '1.5e-12'),
633 ('e', '15.0', '1.50e+1'),
634 ('e', '-15', '-1.5e+1'),
635 ('e', '0', '0e+0'),
636 ('e', '0E1', '0e+1'),
637 ('e', '0.0', '0e-1'),
638 ('e', '0.00', '0e-2'),
639 ('.6e', '0E-15', '0.000000e-9'),
640 ('.6e', '0', '0.000000e+6'),
641 ('.6e', '9.999999', '9.999999e+0'),
642 ('.6e', '9.9999999', '1.000000e+1'),
643 ('.6e', '-1.23e5', '-1.230000e+5'),
644 ('.6e', '1.23456789e-3', '1.234568e-3'),
645 ('f', '0', '0'),
646 ('f', '0.0', '0.0'),
647 ('f', '0E-2', '0.00'),
648 ('f', '0.00E-8', '0.0000000000'),
649 ('f', '0E1', '0'), # loses exponent information
650 ('f', '3.2E1', '32'),
651 ('f', '3.2E2', '320'),
652 ('f', '3.20E2', '320'),
653 ('f', '3.200E2', '320.0'),
654 ('f', '3.2E-6', '0.0000032'),
655 ('.6f', '0E-15', '0.000000'), # all zeros treated equally
656 ('.6f', '0E1', '0.000000'),
657 ('.6f', '0', '0.000000'),
658 ('.0f', '0', '0'), # no decimal point
659 ('.0f', '0e-2', '0'),
660 ('.0f', '3.14159265', '3'),
661 ('.1f', '3.14159265', '3.1'),
662 ('.4f', '3.14159265', '3.1416'),
663 ('.6f', '3.14159265', '3.141593'),
664 ('.7f', '3.14159265', '3.1415926'), # round-half-even!
665 ('.8f', '3.14159265', '3.14159265'),
666 ('.9f', '3.14159265', '3.141592650'),
667
668 ('g', '0', '0'),
669 ('g', '0.0', '0.0'),
670 ('g', '0E1', '0e+1'),
671 ('G', '0E1', '0E+1'),
672 ('g', '0E-5', '0.00000'),
673 ('g', '0E-6', '0.000000'),
674 ('g', '0E-7', '0e-7'),
675 ('g', '-0E2', '-0e+2'),
676 ('.0g', '3.14159265', '3'), # 0 sig fig -> 1 sig fig
677 ('.1g', '3.14159265', '3'),
678 ('.2g', '3.14159265', '3.1'),
679 ('.5g', '3.14159265', '3.1416'),
680 ('.7g', '3.14159265', '3.141593'),
681 ('.8g', '3.14159265', '3.1415926'), # round-half-even!
682 ('.9g', '3.14159265', '3.14159265'),
683 ('.10g', '3.14159265', '3.14159265'), # don't pad
684
685 ('%', '0E1', '0%'),
686 ('%', '0E0', '0%'),
687 ('%', '0E-1', '0%'),
688 ('%', '0E-2', '0%'),
689 ('%', '0E-3', '0.0%'),
690 ('%', '0E-4', '0.00%'),
691
692 ('.3%', '0', '0.000%'), # all zeros treated equally
693 ('.3%', '0E10', '0.000%'),
694 ('.3%', '0E-10', '0.000%'),
695 ('.3%', '2.34', '234.000%'),
696 ('.3%', '1.234567', '123.457%'),
697 ('.0%', '1.23', '123%'),
698
699 ('e', 'NaN', 'NaN'),
700 ('f', '-NaN123', '-NaN123'),
701 ('+g', 'NaN456', '+NaN456'),
702 ('.3e', 'Inf', 'Infinity'),
703 ('.16f', '-Inf', '-Infinity'),
704 ('.0g', '-sNaN', '-sNaN'),
705
706 ('', '1.00', '1.00'),
Mark Dickinson71416822009-03-17 18:07:41 +0000707
708 # check alignment
709 ('<6', '123', '123 '),
710 ('>6', '123', ' 123'),
711 ('^6', '123', ' 123 '),
712 ('=+6', '123', '+ 123'),
Mark Dickinson1ddf1d82008-02-29 02:16:37 +0000713 ]
714 for fmt, d, result in test_values:
715 self.assertEqual(format(Decimal(d), fmt), result)
716
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000717class DecimalArithmeticOperatorsTest(unittest.TestCase):
718 '''Unit tests for all arithmetic operators, binary and unary.'''
719
720 def test_addition(self):
721
722 d1 = Decimal('-11.1')
723 d2 = Decimal('22.2')
724
725 #two Decimals
726 self.assertEqual(d1+d2, Decimal('11.1'))
727 self.assertEqual(d2+d1, Decimal('11.1'))
728
729 #with other type, left
730 c = d1 + 5
731 self.assertEqual(c, Decimal('-6.1'))
732 self.assertEqual(type(c), type(d1))
733
734 #with other type, right
735 c = 5 + d1
736 self.assertEqual(c, Decimal('-6.1'))
737 self.assertEqual(type(c), type(d1))
738
739 #inline with decimal
740 d1 += d2
741 self.assertEqual(d1, Decimal('11.1'))
742
743 #inline with other type
744 d1 += 5
745 self.assertEqual(d1, Decimal('16.1'))
746
747 def test_subtraction(self):
748
749 d1 = Decimal('-11.1')
750 d2 = Decimal('22.2')
751
752 #two Decimals
753 self.assertEqual(d1-d2, Decimal('-33.3'))
754 self.assertEqual(d2-d1, Decimal('33.3'))
755
756 #with other type, left
757 c = d1 - 5
758 self.assertEqual(c, Decimal('-16.1'))
759 self.assertEqual(type(c), type(d1))
760
761 #with other type, right
762 c = 5 - d1
763 self.assertEqual(c, Decimal('16.1'))
764 self.assertEqual(type(c), type(d1))
765
766 #inline with decimal
767 d1 -= d2
768 self.assertEqual(d1, Decimal('-33.3'))
769
770 #inline with other type
771 d1 -= 5
772 self.assertEqual(d1, Decimal('-38.3'))
773
774 def test_multiplication(self):
775
776 d1 = Decimal('-5')
777 d2 = Decimal('3')
778
779 #two Decimals
780 self.assertEqual(d1*d2, Decimal('-15'))
781 self.assertEqual(d2*d1, Decimal('-15'))
782
783 #with other type, left
784 c = d1 * 5
785 self.assertEqual(c, Decimal('-25'))
786 self.assertEqual(type(c), type(d1))
787
788 #with other type, right
789 c = 5 * d1
790 self.assertEqual(c, Decimal('-25'))
791 self.assertEqual(type(c), type(d1))
792
793 #inline with decimal
794 d1 *= d2
795 self.assertEqual(d1, Decimal('-15'))
796
797 #inline with other type
798 d1 *= 5
799 self.assertEqual(d1, Decimal('-75'))
800
801 def test_division(self):
802
803 d1 = Decimal('-5')
804 d2 = Decimal('2')
805
806 #two Decimals
807 self.assertEqual(d1/d2, Decimal('-2.5'))
808 self.assertEqual(d2/d1, Decimal('-0.4'))
809
810 #with other type, left
811 c = d1 / 4
812 self.assertEqual(c, Decimal('-1.25'))
813 self.assertEqual(type(c), type(d1))
814
815 #with other type, right
816 c = 4 / d1
817 self.assertEqual(c, Decimal('-0.8'))
818 self.assertEqual(type(c), type(d1))
819
820 #inline with decimal
821 d1 /= d2
822 self.assertEqual(d1, Decimal('-2.5'))
823
824 #inline with other type
825 d1 /= 4
826 self.assertEqual(d1, Decimal('-0.625'))
827
828 def test_floor_division(self):
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000829
830 d1 = Decimal('5')
831 d2 = Decimal('2')
832
833 #two Decimals
834 self.assertEqual(d1//d2, Decimal('2'))
835 self.assertEqual(d2//d1, Decimal('0'))
836
837 #with other type, left
838 c = d1 // 4
839 self.assertEqual(c, Decimal('1'))
840 self.assertEqual(type(c), type(d1))
841
842 #with other type, right
843 c = 7 // d1
844 self.assertEqual(c, Decimal('1'))
845 self.assertEqual(type(c), type(d1))
846
847 #inline with decimal
848 d1 //= d2
849 self.assertEqual(d1, Decimal('2'))
850
851 #inline with other type
852 d1 //= 2
853 self.assertEqual(d1, Decimal('1'))
854
855 def test_powering(self):
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000856
857 d1 = Decimal('5')
858 d2 = Decimal('2')
859
860 #two Decimals
861 self.assertEqual(d1**d2, Decimal('25'))
862 self.assertEqual(d2**d1, Decimal('32'))
863
864 #with other type, left
865 c = d1 ** 4
866 self.assertEqual(c, Decimal('625'))
867 self.assertEqual(type(c), type(d1))
868
869 #with other type, right
870 c = 7 ** d1
871 self.assertEqual(c, Decimal('16807'))
872 self.assertEqual(type(c), type(d1))
873
874 #inline with decimal
875 d1 **= d2
876 self.assertEqual(d1, Decimal('25'))
877
878 #inline with other type
879 d1 **= 4
880 self.assertEqual(d1, Decimal('390625'))
881
882 def test_module(self):
883
884 d1 = Decimal('5')
885 d2 = Decimal('2')
886
887 #two Decimals
888 self.assertEqual(d1%d2, Decimal('1'))
889 self.assertEqual(d2%d1, Decimal('2'))
890
891 #with other type, left
892 c = d1 % 4
893 self.assertEqual(c, Decimal('1'))
894 self.assertEqual(type(c), type(d1))
895
896 #with other type, right
897 c = 7 % d1
898 self.assertEqual(c, Decimal('2'))
899 self.assertEqual(type(c), type(d1))
900
901 #inline with decimal
902 d1 %= d2
903 self.assertEqual(d1, Decimal('1'))
904
905 #inline with other type
906 d1 %= 4
907 self.assertEqual(d1, Decimal('1'))
908
909 def test_floor_div_module(self):
910
911 d1 = Decimal('5')
912 d2 = Decimal('2')
913
914 #two Decimals
915 (p, q) = divmod(d1, d2)
916 self.assertEqual(p, Decimal('2'))
917 self.assertEqual(q, Decimal('1'))
918 self.assertEqual(type(p), type(d1))
919 self.assertEqual(type(q), type(d1))
920
921 #with other type, left
922 (p, q) = divmod(d1, 4)
923 self.assertEqual(p, Decimal('1'))
924 self.assertEqual(q, Decimal('1'))
925 self.assertEqual(type(p), type(d1))
926 self.assertEqual(type(q), type(d1))
927
928 #with other type, right
929 (p, q) = divmod(7, d1)
930 self.assertEqual(p, Decimal('1'))
931 self.assertEqual(q, Decimal('2'))
932 self.assertEqual(type(p), type(d1))
933 self.assertEqual(type(q), type(d1))
934
935 def test_unary_operators(self):
936 self.assertEqual(+Decimal(45), Decimal(+45)) # +
937 self.assertEqual(-Decimal(45), Decimal(-45)) # -
938 self.assertEqual(abs(Decimal(45)), abs(Decimal(-45))) # abs
939
Mark Dickinson2fc92632008-02-06 22:10:50 +0000940 def test_nan_comparisons(self):
941 n = Decimal('NaN')
942 s = Decimal('sNaN')
943 i = Decimal('Inf')
944 f = Decimal('2')
945 for x, y in [(n, n), (n, i), (i, n), (n, f), (f, n),
946 (s, n), (n, s), (s, i), (i, s), (s, f), (f, s), (s, s)]:
947 self.assert_(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))
952 self.assert_(not (x >= y))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000953
954# The following are two functions used to test threading in the next class
955
956def thfunc1(cls):
957 d1 = Decimal(1)
958 d3 = Decimal(3)
Facundo Batista64156672008-03-22 02:45:37 +0000959 test1 = d1/d3
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000960 cls.synchro.wait()
Facundo Batista64156672008-03-22 02:45:37 +0000961 test2 = d1/d3
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000962 cls.finish1.set()
Facundo Batista64156672008-03-22 02:45:37 +0000963
Facundo Batistaee340e52008-05-02 17:39:00 +0000964 cls.assertEqual(test1, Decimal('0.3333333333333333333333333333'))
965 cls.assertEqual(test2, Decimal('0.3333333333333333333333333333'))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000966 return
967
968def thfunc2(cls):
969 d1 = Decimal(1)
970 d3 = Decimal(3)
Facundo Batista64156672008-03-22 02:45:37 +0000971 test1 = d1/d3
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000972 thiscontext = getcontext()
973 thiscontext.prec = 18
Facundo Batista64156672008-03-22 02:45:37 +0000974 test2 = d1/d3
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000975 cls.synchro.set()
976 cls.finish2.set()
Facundo Batista64156672008-03-22 02:45:37 +0000977
Facundo Batistaee340e52008-05-02 17:39:00 +0000978 cls.assertEqual(test1, Decimal('0.3333333333333333333333333333'))
Facundo Batista64156672008-03-22 02:45:37 +0000979 cls.assertEqual(test2, Decimal('0.333333333333333333'))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000980 return
981
982
983class DecimalUseOfContextTest(unittest.TestCase):
984 '''Unit tests for Use of Context cases in Decimal.'''
985
Raymond Hettinger7e71fa52004-12-18 19:07:19 +0000986 try:
987 import threading
988 except ImportError:
989 threading = None
990
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000991 # Take care executing this test from IDLE, there's an issue in threading
992 # that hangs IDLE and I couldn't find it
993
994 def test_threading(self):
995 #Test the "threading isolation" of a Context.
996
997 self.synchro = threading.Event()
998 self.finish1 = threading.Event()
999 self.finish2 = threading.Event()
1000
1001 th1 = threading.Thread(target=thfunc1, args=(self,))
1002 th2 = threading.Thread(target=thfunc2, args=(self,))
1003
1004 th1.start()
1005 th2.start()
1006
1007 self.finish1.wait()
Thomas Woutersb3e6e8c2007-09-19 17:27:29 +00001008 self.finish2.wait()
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001009 return
1010
Raymond Hettinger7e71fa52004-12-18 19:07:19 +00001011 if threading is None:
1012 del test_threading
1013
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001014
1015class DecimalUsabilityTest(unittest.TestCase):
1016 '''Unit tests for Usability cases of Decimal.'''
1017
1018 def test_comparison_operators(self):
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001019
1020 da = Decimal('23.42')
1021 db = Decimal('23.42')
1022 dc = Decimal('45')
1023
1024 #two Decimals
1025 self.failUnless(dc > da)
1026 self.failUnless(dc >= da)
1027 self.failUnless(da < dc)
1028 self.failUnless(da <= dc)
1029 self.failUnless(da == db)
1030 self.failUnless(da != dc)
1031 self.failUnless(da <= db)
1032 self.failUnless(da >= db)
1033 self.assertEqual(cmp(dc,da), 1)
1034 self.assertEqual(cmp(da,dc), -1)
1035 self.assertEqual(cmp(da,db), 0)
1036
1037 #a Decimal and an int
1038 self.failUnless(dc > 23)
1039 self.failUnless(23 < dc)
1040 self.failUnless(dc == 45)
1041 self.assertEqual(cmp(dc,23), 1)
1042 self.assertEqual(cmp(23,dc), -1)
1043 self.assertEqual(cmp(dc,45), 0)
1044
1045 #a Decimal and uncomparable
Raymond Hettinger0aeac102004-07-05 22:53:03 +00001046 self.assertNotEqual(da, 'ugly')
1047 self.assertNotEqual(da, 32.7)
1048 self.assertNotEqual(da, object())
1049 self.assertNotEqual(da, object)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001050
Raymond Hettinger0aeac102004-07-05 22:53:03 +00001051 # sortable
1052 a = map(Decimal, xrange(100))
1053 b = a[:]
1054 random.shuffle(a)
1055 a.sort()
1056 self.assertEqual(a, b)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001057
Facundo Batista353750c2007-09-13 18:13:15 +00001058 # with None
1059 self.assertFalse(Decimal(1) < None)
1060 self.assertTrue(Decimal(1) > None)
1061
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001062 def test_copy_and_deepcopy_methods(self):
1063 d = Decimal('43.24')
1064 c = copy.copy(d)
1065 self.assertEqual(id(c), id(d))
1066 dc = copy.deepcopy(d)
1067 self.assertEqual(id(dc), id(d))
1068
1069 def test_hash_method(self):
1070 #just that it's hashable
1071 hash(Decimal(23))
Facundo Batista8c202442007-09-19 17:53:25 +00001072
1073 test_values = [Decimal(sign*(2**m + n))
1074 for m in [0, 14, 15, 16, 17, 30, 31,
1075 32, 33, 62, 63, 64, 65, 66]
1076 for n in range(-10, 10)
1077 for sign in [-1, 1]]
1078 test_values.extend([
1079 Decimal("-0"), # zeros
1080 Decimal("0.00"),
1081 Decimal("-0.000"),
1082 Decimal("0E10"),
1083 Decimal("-0E12"),
1084 Decimal("10.0"), # negative exponent
1085 Decimal("-23.00000"),
1086 Decimal("1230E100"), # positive exponent
1087 Decimal("-4.5678E50"),
1088 # a value for which hash(n) != hash(n % (2**64-1))
1089 # in Python pre-2.6
1090 Decimal(2**64 + 2**32 - 1),
1091 # selection of values which fail with the old (before
1092 # version 2.6) long.__hash__
1093 Decimal("1.634E100"),
1094 Decimal("90.697E100"),
1095 Decimal("188.83E100"),
1096 Decimal("1652.9E100"),
1097 Decimal("56531E100"),
1098 ])
1099
1100 # check that hash(d) == hash(int(d)) for integral values
1101 for value in test_values:
1102 self.assertEqual(hash(value), hash(int(value)))
1103
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001104 #the same hash that to an int
1105 self.assertEqual(hash(Decimal(23)), hash(23))
Raymond Hettingerbea3f6f2005-03-15 04:59:17 +00001106 self.assertRaises(TypeError, hash, Decimal('NaN'))
1107 self.assert_(hash(Decimal('Inf')))
1108 self.assert_(hash(Decimal('-Inf')))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001109
Facundo Batista52b25792008-01-08 12:25:20 +00001110 # check that the value of the hash doesn't depend on the
1111 # current context (issue #1757)
1112 c = getcontext()
1113 old_precision = c.prec
1114 x = Decimal("123456789.1")
1115
1116 c.prec = 6
1117 h1 = hash(x)
1118 c.prec = 10
1119 h2 = hash(x)
1120 c.prec = 16
1121 h3 = hash(x)
1122
1123 self.assertEqual(h1, h2)
1124 self.assertEqual(h1, h3)
1125 c.prec = old_precision
1126
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001127 def test_min_and_max_methods(self):
1128
1129 d1 = Decimal('15.32')
1130 d2 = Decimal('28.5')
1131 l1 = 15
1132 l2 = 28
1133
1134 #between Decimals
1135 self.failUnless(min(d1,d2) is d1)
1136 self.failUnless(min(d2,d1) is d1)
1137 self.failUnless(max(d1,d2) is d2)
1138 self.failUnless(max(d2,d1) is d2)
1139
1140 #between Decimal and long
1141 self.failUnless(min(d1,l2) is d1)
1142 self.failUnless(min(l2,d1) is d1)
1143 self.failUnless(max(l1,d2) is d2)
1144 self.failUnless(max(d2,l1) is d2)
1145
1146 def test_as_nonzero(self):
1147 #as false
1148 self.failIf(Decimal(0))
1149 #as true
1150 self.failUnless(Decimal('0.372'))
1151
1152 def test_tostring_methods(self):
1153 #Test str and repr methods.
1154
1155 d = Decimal('15.32')
1156 self.assertEqual(str(d), '15.32') # str
Raymond Hettingerabe32372008-02-14 02:41:22 +00001157 self.assertEqual(repr(d), "Decimal('15.32')") # repr
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001158
Mark Dickinson8e85ffa2008-03-25 18:47:59 +00001159 # result type of string methods should be str, not unicode
1160 unicode_inputs = [u'123.4', u'0.5E2', u'Infinity', u'sNaN',
1161 u'-0.0E100', u'-NaN001', u'-Inf']
1162
1163 for u in unicode_inputs:
1164 d = Decimal(u)
1165 self.assertEqual(type(str(d)), str)
1166 self.assertEqual(type(repr(d)), str)
1167 self.assertEqual(type(d.to_eng_string()), str)
1168
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001169 def test_tonum_methods(self):
1170 #Test float, int and long methods.
1171
1172 d1 = Decimal('66')
1173 d2 = Decimal('15.32')
1174
1175 #int
1176 self.assertEqual(int(d1), 66)
1177 self.assertEqual(int(d2), 15)
1178
1179 #long
1180 self.assertEqual(long(d1), 66)
1181 self.assertEqual(long(d2), 15)
1182
1183 #float
1184 self.assertEqual(float(d1), 66)
1185 self.assertEqual(float(d2), 15.32)
1186
1187 def test_eval_round_trip(self):
1188
1189 #with zero
1190 d = Decimal( (0, (0,), 0) )
1191 self.assertEqual(d, eval(repr(d)))
1192
1193 #int
1194 d = Decimal( (1, (4, 5), 0) )
1195 self.assertEqual(d, eval(repr(d)))
1196
1197 #float
1198 d = Decimal( (0, (4, 5, 3, 4), -2) )
1199 self.assertEqual(d, eval(repr(d)))
1200
1201 #weird
1202 d = Decimal( (1, (4, 3, 4, 9, 1, 3, 5, 3, 4), -25) )
1203 self.assertEqual(d, eval(repr(d)))
1204
1205 def test_as_tuple(self):
1206
1207 #with zero
1208 d = Decimal(0)
1209 self.assertEqual(d.as_tuple(), (0, (0,), 0) )
1210
1211 #int
1212 d = Decimal(-45)
1213 self.assertEqual(d.as_tuple(), (1, (4, 5), 0) )
1214
1215 #complicated string
1216 d = Decimal("-4.34913534E-17")
1217 self.assertEqual(d.as_tuple(), (1, (4, 3, 4, 9, 1, 3, 5, 3, 4), -25) )
1218
1219 #inf
1220 d = Decimal("Infinity")
1221 self.assertEqual(d.as_tuple(), (0, (0,), 'F') )
1222
Facundo Batista9b5e2312007-10-19 19:25:57 +00001223 #leading zeros in coefficient should be stripped
1224 d = Decimal( (0, (0, 0, 4, 0, 5, 3, 4), -2) )
1225 self.assertEqual(d.as_tuple(), (0, (4, 0, 5, 3, 4), -2) )
1226 d = Decimal( (1, (0, 0, 0), 37) )
1227 self.assertEqual(d.as_tuple(), (1, (0,), 37))
1228 d = Decimal( (1, (), 37) )
1229 self.assertEqual(d.as_tuple(), (1, (0,), 37))
1230
1231 #leading zeros in NaN diagnostic info should be stripped
1232 d = Decimal( (0, (0, 0, 4, 0, 5, 3, 4), 'n') )
1233 self.assertEqual(d.as_tuple(), (0, (4, 0, 5, 3, 4), 'n') )
1234 d = Decimal( (1, (0, 0, 0), 'N') )
1235 self.assertEqual(d.as_tuple(), (1, (), 'N') )
1236 d = Decimal( (1, (), 'n') )
1237 self.assertEqual(d.as_tuple(), (1, (), 'n') )
1238
1239 #coefficient in infinity should be ignored
1240 d = Decimal( (0, (4, 5, 3, 4), 'F') )
1241 self.assertEqual(d.as_tuple(), (0, (0,), 'F'))
1242 d = Decimal( (1, (0, 2, 7, 1), 'F') )
1243 self.assertEqual(d.as_tuple(), (1, (0,), 'F'))
1244
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001245 def test_immutability_operations(self):
1246 # Do operations and check that it didn't change change internal objects.
1247
1248 d1 = Decimal('-25e55')
1249 b1 = Decimal('-25e55')
Facundo Batista353750c2007-09-13 18:13:15 +00001250 d2 = Decimal('33e+33')
1251 b2 = Decimal('33e+33')
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001252
1253 def checkSameDec(operation, useOther=False):
1254 if useOther:
1255 eval("d1." + operation + "(d2)")
1256 self.assertEqual(d1._sign, b1._sign)
1257 self.assertEqual(d1._int, b1._int)
1258 self.assertEqual(d1._exp, b1._exp)
1259 self.assertEqual(d2._sign, b2._sign)
1260 self.assertEqual(d2._int, b2._int)
1261 self.assertEqual(d2._exp, b2._exp)
1262 else:
1263 eval("d1." + operation + "()")
1264 self.assertEqual(d1._sign, b1._sign)
1265 self.assertEqual(d1._int, b1._int)
1266 self.assertEqual(d1._exp, b1._exp)
1267 return
1268
1269 Decimal(d1)
1270 self.assertEqual(d1._sign, b1._sign)
1271 self.assertEqual(d1._int, b1._int)
1272 self.assertEqual(d1._exp, b1._exp)
1273
1274 checkSameDec("__abs__")
1275 checkSameDec("__add__", True)
1276 checkSameDec("__div__", True)
1277 checkSameDec("__divmod__", True)
Mark Dickinson2fc92632008-02-06 22:10:50 +00001278 checkSameDec("__eq__", True)
1279 checkSameDec("__ne__", True)
1280 checkSameDec("__le__", True)
1281 checkSameDec("__lt__", True)
1282 checkSameDec("__ge__", True)
1283 checkSameDec("__gt__", True)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001284 checkSameDec("__float__")
1285 checkSameDec("__floordiv__", True)
1286 checkSameDec("__hash__")
1287 checkSameDec("__int__")
Raymond Hettinger5a053642008-01-24 19:05:29 +00001288 checkSameDec("__trunc__")
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001289 checkSameDec("__long__")
1290 checkSameDec("__mod__", True)
1291 checkSameDec("__mul__", True)
1292 checkSameDec("__neg__")
1293 checkSameDec("__nonzero__")
1294 checkSameDec("__pos__")
1295 checkSameDec("__pow__", True)
1296 checkSameDec("__radd__", True)
1297 checkSameDec("__rdiv__", True)
1298 checkSameDec("__rdivmod__", True)
1299 checkSameDec("__repr__")
1300 checkSameDec("__rfloordiv__", True)
1301 checkSameDec("__rmod__", True)
1302 checkSameDec("__rmul__", True)
1303 checkSameDec("__rpow__", True)
1304 checkSameDec("__rsub__", True)
1305 checkSameDec("__str__")
1306 checkSameDec("__sub__", True)
1307 checkSameDec("__truediv__", True)
1308 checkSameDec("adjusted")
1309 checkSameDec("as_tuple")
1310 checkSameDec("compare", True)
1311 checkSameDec("max", True)
1312 checkSameDec("min", True)
1313 checkSameDec("normalize")
1314 checkSameDec("quantize", True)
1315 checkSameDec("remainder_near", True)
1316 checkSameDec("same_quantum", True)
1317 checkSameDec("sqrt")
1318 checkSameDec("to_eng_string")
1319 checkSameDec("to_integral")
1320
Facundo Batista6c398da2007-09-17 17:30:13 +00001321 def test_subclassing(self):
1322 # Different behaviours when subclassing Decimal
1323
1324 class MyDecimal(Decimal):
1325 pass
1326
1327 d1 = MyDecimal(1)
1328 d2 = MyDecimal(2)
1329 d = d1 + d2
1330 self.assertTrue(type(d) is Decimal)
1331
1332 d = d1.max(d2)
1333 self.assertTrue(type(d) is Decimal)
1334
Mark Dickinson3b24ccb2008-03-25 14:33:23 +00001335 def test_implicit_context(self):
1336 # Check results when context given implicitly. (Issue 2478)
1337 c = getcontext()
1338 self.assertEqual(str(Decimal(0).sqrt()),
1339 str(c.sqrt(Decimal(0))))
1340
Facundo Batista6c398da2007-09-17 17:30:13 +00001341
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001342class DecimalPythonAPItests(unittest.TestCase):
1343
Raymond Hettinger45fd4762009-02-03 03:42:07 +00001344 def test_abc(self):
1345 self.assert_(issubclass(Decimal, numbers.Number))
1346 self.assert_(not issubclass(Decimal, numbers.Real))
1347 self.assert_(isinstance(Decimal(0), numbers.Number))
1348 self.assert_(not isinstance(Decimal(0), numbers.Real))
1349
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001350 def test_pickle(self):
1351 d = Decimal('-3.141590000')
1352 p = pickle.dumps(d)
1353 e = pickle.loads(p)
1354 self.assertEqual(d, e)
1355
Raymond Hettinger5548be22004-07-05 18:49:38 +00001356 def test_int(self):
Raymond Hettinger605ed022004-11-24 07:28:48 +00001357 for x in range(-250, 250):
1358 s = '%0.2f' % (x / 100.0)
Raymond Hettinger5548be22004-07-05 18:49:38 +00001359 # should work the same as for floats
1360 self.assertEqual(int(Decimal(s)), int(float(s)))
Raymond Hettinger605ed022004-11-24 07:28:48 +00001361 # should work the same as to_integral in the ROUND_DOWN mode
Raymond Hettinger5548be22004-07-05 18:49:38 +00001362 d = Decimal(s)
Raymond Hettinger605ed022004-11-24 07:28:48 +00001363 r = d.to_integral(ROUND_DOWN)
Raymond Hettinger5548be22004-07-05 18:49:38 +00001364 self.assertEqual(Decimal(int(d)), r)
1365
Raymond Hettinger5a053642008-01-24 19:05:29 +00001366 def test_trunc(self):
1367 for x in range(-250, 250):
1368 s = '%0.2f' % (x / 100.0)
1369 # should work the same as for floats
1370 self.assertEqual(int(Decimal(s)), int(float(s)))
1371 # should work the same as to_integral in the ROUND_DOWN mode
1372 d = Decimal(s)
1373 r = d.to_integral(ROUND_DOWN)
Jeffrey Yasskinca2b69f2008-02-01 06:22:46 +00001374 self.assertEqual(Decimal(math.trunc(d)), r)
Raymond Hettinger5a053642008-01-24 19:05:29 +00001375
Raymond Hettingerd9c0a7a2004-07-03 10:02:28 +00001376class ContextAPItests(unittest.TestCase):
1377
1378 def test_pickle(self):
1379 c = Context()
1380 e = pickle.loads(pickle.dumps(c))
1381 for k in vars(c):
1382 v1 = vars(c)[k]
1383 v2 = vars(e)[k]
1384 self.assertEqual(v1, v2)
1385
Raymond Hettinger0aeac102004-07-05 22:53:03 +00001386 def test_equality_with_other_types(self):
1387 self.assert_(Decimal(10) in ['a', 1.0, Decimal(10), (1,2), {}])
1388 self.assert_(Decimal(10) not in ['a', 1.0, (1,2), {}])
1389
Raymond Hettinger955d2b22004-08-08 20:17:45 +00001390 def test_copy(self):
1391 # All copies should be deep
1392 c = Context()
1393 d = c.copy()
1394 self.assertNotEqual(id(c), id(d))
1395 self.assertNotEqual(id(c.flags), id(d.flags))
1396 self.assertNotEqual(id(c.traps), id(d.traps))
1397
Nick Coghlan8b6999b2006-08-31 12:00:43 +00001398class WithStatementTest(unittest.TestCase):
1399 # Can't do these as docstrings until Python 2.6
1400 # as doctest can't handle __future__ statements
Nick Coghlan8b6999b2006-08-31 12:00:43 +00001401
1402 def test_localcontext(self):
Nick Coghlanced12182006-09-02 03:54:17 +00001403 # Use a copy of the current context in the block
Nick Coghlan8b6999b2006-08-31 12:00:43 +00001404 orig_ctx = getcontext()
1405 with localcontext() as enter_ctx:
1406 set_ctx = getcontext()
1407 final_ctx = getcontext()
1408 self.assert_(orig_ctx is final_ctx, 'did not restore context correctly')
1409 self.assert_(orig_ctx is not set_ctx, 'did not copy the context')
1410 self.assert_(set_ctx is enter_ctx, '__enter__ returned wrong context')
1411
1412 def test_localcontextarg(self):
Nick Coghlanced12182006-09-02 03:54:17 +00001413 # Use a copy of the supplied context in the block
Nick Coghlan8b6999b2006-08-31 12:00:43 +00001414 orig_ctx = getcontext()
1415 new_ctx = Context(prec=42)
1416 with localcontext(new_ctx) as enter_ctx:
1417 set_ctx = getcontext()
1418 final_ctx = getcontext()
1419 self.assert_(orig_ctx is final_ctx, 'did not restore context correctly')
1420 self.assert_(set_ctx.prec == new_ctx.prec, 'did not set correct context')
1421 self.assert_(new_ctx is not set_ctx, 'did not copy the context')
1422 self.assert_(set_ctx is enter_ctx, '__enter__ returned wrong context')
1423
Facundo Batista353750c2007-09-13 18:13:15 +00001424class ContextFlags(unittest.TestCase):
1425 def test_flags_irrelevant(self):
1426 # check that the result (numeric result + flags raised) of an
1427 # arithmetic operation doesn't depend on the current flags
1428
1429 context = Context(prec=9, Emin = -999999999, Emax = 999999999,
1430 rounding=ROUND_HALF_EVEN, traps=[], flags=[])
1431
1432 # operations that raise various flags, in the form (function, arglist)
1433 operations = [
1434 (context._apply, [Decimal("100E-1000000009")]),
1435 (context.sqrt, [Decimal(2)]),
1436 (context.add, [Decimal("1.23456789"), Decimal("9.87654321")]),
1437 (context.multiply, [Decimal("1.23456789"), Decimal("9.87654321")]),
1438 (context.subtract, [Decimal("1.23456789"), Decimal("9.87654321")]),
1439 ]
1440
1441 # try various flags individually, then a whole lot at once
1442 flagsets = [[Inexact], [Rounded], [Underflow], [Clamped], [Subnormal],
1443 [Inexact, Rounded, Underflow, Clamped, Subnormal]]
1444
1445 for fn, args in operations:
1446 # find answer and flags raised using a clean context
1447 context.clear_flags()
1448 ans = fn(*args)
1449 flags = [k for k, v in context.flags.items() if v]
1450
1451 for extra_flags in flagsets:
1452 # set flags, before calling operation
1453 context.clear_flags()
1454 for flag in extra_flags:
1455 context._raise_error(flag)
1456 new_ans = fn(*args)
1457
1458 # flags that we expect to be set after the operation
1459 expected_flags = list(flags)
1460 for flag in extra_flags:
1461 if flag not in expected_flags:
1462 expected_flags.append(flag)
1463 expected_flags.sort()
1464
1465 # flags we actually got
1466 new_flags = [k for k,v in context.flags.items() if v]
1467 new_flags.sort()
1468
1469 self.assertEqual(ans, new_ans,
1470 "operation produces different answers depending on flags set: " +
1471 "expected %s, got %s." % (ans, new_ans))
1472 self.assertEqual(new_flags, expected_flags,
1473 "operation raises different flags depending on flags set: " +
1474 "expected %s, got %s" % (expected_flags, new_flags))
1475
1476def test_main(arith=False, verbose=None, todo_tests=None, debug=None):
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001477 """ Execute the tests.
1478
Raymond Hettingered20ad82004-09-04 20:09:13 +00001479 Runs all arithmetic tests if arith is True or if the "decimal" resource
1480 is enabled in regrtest.py
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001481 """
Raymond Hettingered20ad82004-09-04 20:09:13 +00001482
Neal Norwitzce4a9c92006-04-09 08:36:46 +00001483 init()
Facundo Batista353750c2007-09-13 18:13:15 +00001484 global TEST_ALL, DEBUG
Raymond Hettingered20ad82004-09-04 20:09:13 +00001485 TEST_ALL = arith or is_resource_enabled('decimal')
Facundo Batista353750c2007-09-13 18:13:15 +00001486 DEBUG = debug
Raymond Hettingered20ad82004-09-04 20:09:13 +00001487
Facundo Batista353750c2007-09-13 18:13:15 +00001488 if todo_tests is None:
1489 test_classes = [
1490 DecimalExplicitConstructionTest,
1491 DecimalImplicitConstructionTest,
1492 DecimalArithmeticOperatorsTest,
Mark Dickinson1ddf1d82008-02-29 02:16:37 +00001493 DecimalFormatTest,
Facundo Batista353750c2007-09-13 18:13:15 +00001494 DecimalUseOfContextTest,
1495 DecimalUsabilityTest,
1496 DecimalPythonAPItests,
1497 ContextAPItests,
1498 DecimalTest,
1499 WithStatementTest,
1500 ContextFlags
1501 ]
1502 else:
1503 test_classes = [DecimalTest]
1504
1505 # Dynamically build custom test definition for each file in the test
1506 # directory and add the definitions to the DecimalTest class. This
1507 # procedure insures that new files do not get skipped.
1508 for filename in os.listdir(directory):
1509 if '.decTest' not in filename or filename.startswith("."):
1510 continue
1511 head, tail = filename.split('.')
1512 if todo_tests is not None and head not in todo_tests:
1513 continue
1514 tester = lambda self, f=filename: self.eval_file(directory + f)
1515 setattr(DecimalTest, 'test_' + head, tester)
1516 del filename, head, tail, tester
1517
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001518
Tim Peters46cc7022006-03-31 04:11:16 +00001519 try:
1520 run_unittest(*test_classes)
Facundo Batista353750c2007-09-13 18:13:15 +00001521 if todo_tests is None:
1522 import decimal as DecimalModule
1523 run_doctest(DecimalModule, verbose)
Tim Peters46cc7022006-03-31 04:11:16 +00001524 finally:
1525 setcontext(ORIGINAL_CONTEXT)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001526
1527if __name__ == '__main__':
Facundo Batista353750c2007-09-13 18:13:15 +00001528 import optparse
1529 p = optparse.OptionParser("test_decimal.py [--debug] [{--skip | test1 [test2 [...]]}]")
1530 p.add_option('--debug', '-d', action='store_true', help='shows the test number and context before each test')
1531 p.add_option('--skip', '-s', action='store_true', help='skip over 90% of the arithmetic tests')
1532 (opt, args) = p.parse_args()
1533
1534 if opt.skip:
1535 test_main(arith=False, verbose=True)
1536 elif args:
1537 test_main(arith=True, verbose=True, todo_tests=args, debug=opt.debug)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001538 else:
Facundo Batista353750c2007-09-13 18:13:15 +00001539 test_main(arith=True, verbose=True)