blob: da870083d641cec17d83384328778dc035a85f94 [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 *
Tim Peters46cc7022006-03-31 04:11:16 +000033from test.test_support import (TestSkipped, run_unittest, run_doctest,
34 is_resource_enabled)
Raymond Hettinger0aeac102004-07-05 22:53:03 +000035import random
Raymond Hettinger7e71fa52004-12-18 19:07:19 +000036try:
37 import threading
38except ImportError:
39 threading = None
Raymond Hettinger7c85fa42004-07-01 11:01:35 +000040
Raymond Hettingerfed52962004-07-14 15:41:57 +000041# Useful Test Constant
42Signals = getcontext().flags.keys()
43
Tim Peters46cc7022006-03-31 04:11:16 +000044# Tests are built around these assumed context defaults.
45# test_main() restores the original context.
Neal Norwitzce4a9c92006-04-09 08:36:46 +000046def init():
47 global ORIGINAL_CONTEXT
48 ORIGINAL_CONTEXT = getcontext().copy()
Facundo Batistaee340e52008-05-02 17:39:00 +000049 DefaultTestContext = Context(
50 prec = 9,
51 rounding = ROUND_HALF_EVEN,
52 traps = dict.fromkeys(Signals, 0)
53 )
54 setcontext(DefaultTestContext)
Raymond Hettinger6ea48452004-07-03 12:26:21 +000055
Raymond Hettinger7c85fa42004-07-01 11:01:35 +000056TESTDATADIR = 'decimaltestdata'
Raymond Hettingerd9c0a7a2004-07-03 10:02:28 +000057if __name__ == '__main__':
58 file = sys.argv[0]
59else:
60 file = __file__
61testdir = os.path.dirname(file) or os.curdir
Raymond Hettinger267b8682005-03-27 10:47:39 +000062directory = testdir + os.sep + TESTDATADIR + os.sep
Raymond Hettinger7c85fa42004-07-01 11:01:35 +000063
Raymond Hettinger267b8682005-03-27 10:47:39 +000064skip_expected = not os.path.isdir(directory)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +000065
66# Make sure it actually raises errors when not expected and caught in flags
67# Slower, since it runs some things several times.
68EXTENDEDERRORTEST = False
69
Raymond Hettinger7c85fa42004-07-01 11:01:35 +000070#Map the test cases' error names to the actual errors
Raymond Hettinger7c85fa42004-07-01 11:01:35 +000071ErrorNames = {'clamped' : Clamped,
Raymond Hettinger5aa478b2004-07-09 10:02:53 +000072 'conversion_syntax' : InvalidOperation,
Raymond Hettinger7c85fa42004-07-01 11:01:35 +000073 'division_by_zero' : DivisionByZero,
Raymond Hettinger5aa478b2004-07-09 10:02:53 +000074 'division_impossible' : InvalidOperation,
75 'division_undefined' : InvalidOperation,
Raymond Hettinger7c85fa42004-07-01 11:01:35 +000076 'inexact' : Inexact,
Raymond Hettinger5aa478b2004-07-09 10:02:53 +000077 'invalid_context' : InvalidOperation,
Raymond Hettinger7c85fa42004-07-01 11:01:35 +000078 'invalid_operation' : InvalidOperation,
79 'overflow' : Overflow,
80 'rounded' : Rounded,
81 'subnormal' : Subnormal,
82 'underflow' : Underflow}
83
84
85def Nonfunction(*args):
86 """Doesn't do anything."""
87 return None
88
89RoundingDict = {'ceiling' : ROUND_CEILING, #Maps test-case names to roundings.
90 'down' : ROUND_DOWN,
91 'floor' : ROUND_FLOOR,
92 'half_down' : ROUND_HALF_DOWN,
93 'half_even' : ROUND_HALF_EVEN,
94 'half_up' : ROUND_HALF_UP,
Facundo Batista353750c2007-09-13 18:13:15 +000095 'up' : ROUND_UP,
96 '05up' : ROUND_05UP}
Raymond Hettinger7c85fa42004-07-01 11:01:35 +000097
98# Name adapter to be able to change the Decimal and Context
99# interface without changing the test files from Cowlishaw
Facundo Batista1a191df2007-10-02 17:01:24 +0000100nameAdapter = {'and':'logical_and',
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000101 'apply':'_apply',
Facundo Batista353750c2007-09-13 18:13:15 +0000102 'class':'number_class',
103 'comparesig':'compare_signal',
104 'comparetotal':'compare_total',
105 'comparetotmag':'compare_total_mag',
Facundo Batista353750c2007-09-13 18:13:15 +0000106 'copy':'copy_decimal',
Facundo Batista1a191df2007-10-02 17:01:24 +0000107 'copyabs':'copy_abs',
Facundo Batista353750c2007-09-13 18:13:15 +0000108 'copynegate':'copy_negate',
109 'copysign':'copy_sign',
Facundo Batista1a191df2007-10-02 17:01:24 +0000110 'divideint':'divide_int',
Facundo Batista353750c2007-09-13 18:13:15 +0000111 'invert':'logical_invert',
Facundo Batista1a191df2007-10-02 17:01:24 +0000112 'iscanonical':'is_canonical',
113 'isfinite':'is_finite',
114 'isinfinite':'is_infinite',
115 'isnan':'is_nan',
116 'isnormal':'is_normal',
117 'isqnan':'is_qnan',
118 'issigned':'is_signed',
119 'issnan':'is_snan',
120 'issubnormal':'is_subnormal',
121 'iszero':'is_zero',
Facundo Batista353750c2007-09-13 18:13:15 +0000122 'maxmag':'max_mag',
123 'minmag':'min_mag',
124 'nextminus':'next_minus',
125 'nextplus':'next_plus',
126 'nexttoward':'next_toward',
Facundo Batista1a191df2007-10-02 17:01:24 +0000127 'or':'logical_or',
Facundo Batista353750c2007-09-13 18:13:15 +0000128 'reduce':'normalize',
Facundo Batista1a191df2007-10-02 17:01:24 +0000129 'remaindernear':'remainder_near',
130 'samequantum':'same_quantum',
131 'squareroot':'sqrt',
132 'toeng':'to_eng_string',
133 'tointegral':'to_integral_value',
134 'tointegralx':'to_integral_exact',
135 'tosci':'to_sci_string',
136 'xor':'logical_xor',
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000137 }
138
Facundo Batista1a191df2007-10-02 17:01:24 +0000139# The following functions return True/False rather than a Decimal instance
140
141LOGICAL_FUNCTIONS = (
142 'is_canonical',
143 'is_finite',
144 'is_infinite',
145 'is_nan',
146 'is_normal',
147 'is_qnan',
148 'is_signed',
149 'is_snan',
150 'is_subnormal',
151 'is_zero',
152 'same_quantum',
153 )
154
Facundo Batista353750c2007-09-13 18:13:15 +0000155# For some operations (currently exp, ln, log10, power), the decNumber
156# reference implementation imposes additional restrictions on the
157# context and operands. These restrictions are not part of the
158# specification; however, the effect of these restrictions does show
159# up in some of the testcases. We skip testcases that violate these
160# restrictions, since Decimal behaves differently from decNumber for
161# these testcases so these testcases would otherwise fail.
162
163decNumberRestricted = ('power', 'ln', 'log10', 'exp')
164DEC_MAX_MATH = 999999
165def outside_decNumber_bounds(v, context):
166 if (context.prec > DEC_MAX_MATH or
167 context.Emax > DEC_MAX_MATH or
168 -context.Emin > DEC_MAX_MATH):
169 return True
170 if not v._is_special and v and (
Facundo Batista353750c2007-09-13 18:13:15 +0000171 v.adjusted() > DEC_MAX_MATH or
172 v.adjusted() < 1-2*DEC_MAX_MATH):
173 return True
174 return False
175
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000176class DecimalTest(unittest.TestCase):
177 """Class which tests the Decimal class against the test cases.
178
179 Changed for unittest.
180 """
181 def setUp(self):
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000182 self.context = Context()
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000183 self.ignore_list = ['#']
184 # Basically, a # means return NaN InvalidOperation.
185 # Different from a sNaN in trim
186
187 self.ChangeDict = {'precision' : self.change_precision,
188 'rounding' : self.change_rounding_method,
189 'maxexponent' : self.change_max_exponent,
190 'minexponent' : self.change_min_exponent,
191 'clamp' : self.change_clamp}
192
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000193 def eval_file(self, file):
194 global skip_expected
195 if skip_expected:
196 raise TestSkipped
197 return
198 for line in open(file).xreadlines():
199 line = line.replace('\r\n', '').replace('\n', '')
Raymond Hettinger5aa478b2004-07-09 10:02:53 +0000200 #print line
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000201 try:
202 t = self.eval_line(line)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000203 except DecimalException, exception:
204 #Exception raised where there shoudn't have been one.
205 self.fail('Exception "'+exception.__class__.__name__ + '" raised on line '+line)
206
207 return
208
209 def eval_line(self, s):
210 if s.find(' -> ') >= 0 and s[:2] != '--' and not s.startswith(' --'):
211 s = (s.split('->')[0] + '->' +
212 s.split('->')[1].split('--')[0]).strip()
213 else:
214 s = s.split('--')[0].strip()
215
216 for ignore in self.ignore_list:
217 if s.find(ignore) >= 0:
218 #print s.split()[0], 'NotImplemented--', ignore
219 return
220 if not s:
221 return
222 elif ':' in s:
223 return self.eval_directive(s)
224 else:
225 return self.eval_equation(s)
226
227 def eval_directive(self, s):
228 funct, value = map(lambda x: x.strip().lower(), s.split(':'))
229 if funct == 'rounding':
230 value = RoundingDict[value]
231 else:
232 try:
233 value = int(value)
234 except ValueError:
235 pass
236
237 funct = self.ChangeDict.get(funct, Nonfunction)
238 funct(value)
239
240 def eval_equation(self, s):
241 #global DEFAULT_PRECISION
242 #print DEFAULT_PRECISION
Raymond Hettingered20ad82004-09-04 20:09:13 +0000243
244 if not TEST_ALL and random.random() < 0.90:
245 return
246
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000247 try:
248 Sides = s.split('->')
249 L = Sides[0].strip().split()
250 id = L[0]
Facundo Batista353750c2007-09-13 18:13:15 +0000251 if DEBUG:
252 print "Test ", id,
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000253 funct = L[1].lower()
254 valstemp = L[2:]
255 L = Sides[1].strip().split()
256 ans = L[0]
257 exceptions = L[1:]
258 except (TypeError, AttributeError, IndexError):
Raymond Hettingerd87ac8f2004-07-09 10:52:54 +0000259 raise InvalidOperation
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000260 def FixQuotes(val):
261 val = val.replace("''", 'SingleQuote').replace('""', 'DoubleQuote')
262 val = val.replace("'", '').replace('"', '')
263 val = val.replace('SingleQuote', "'").replace('DoubleQuote', '"')
264 return val
265 fname = nameAdapter.get(funct, funct)
266 if fname == 'rescale':
267 return
268 funct = getattr(self.context, fname)
269 vals = []
270 conglomerate = ''
271 quote = 0
272 theirexceptions = [ErrorNames[x.lower()] for x in exceptions]
273
Raymond Hettingerd9c0a7a2004-07-03 10:02:28 +0000274 for exception in Signals:
Raymond Hettingerbf440692004-07-10 14:14:37 +0000275 self.context.traps[exception] = 1 #Catch these bugs...
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000276 for exception in theirexceptions:
Raymond Hettingerbf440692004-07-10 14:14:37 +0000277 self.context.traps[exception] = 0
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000278 for i, val in enumerate(valstemp):
279 if val.count("'") % 2 == 1:
280 quote = 1 - quote
281 if quote:
282 conglomerate = conglomerate + ' ' + val
283 continue
284 else:
285 val = conglomerate + val
286 conglomerate = ''
287 v = FixQuotes(val)
288 if fname in ('to_sci_string', 'to_eng_string'):
289 if EXTENDEDERRORTEST:
290 for error in theirexceptions:
Raymond Hettingerbf440692004-07-10 14:14:37 +0000291 self.context.traps[error] = 1
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000292 try:
293 funct(self.context.create_decimal(v))
294 except error:
295 pass
Raymond Hettingerd9c0a7a2004-07-03 10:02:28 +0000296 except Signals, e:
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000297 self.fail("Raised %s in %s when %s disabled" % \
298 (e, s, error))
299 else:
300 self.fail("Did not raise %s in %s" % (error, s))
Raymond Hettingerbf440692004-07-10 14:14:37 +0000301 self.context.traps[error] = 0
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000302 v = self.context.create_decimal(v)
303 else:
Facundo Batista353750c2007-09-13 18:13:15 +0000304 v = Decimal(v, self.context)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000305 vals.append(v)
306
307 ans = FixQuotes(ans)
308
Facundo Batista353750c2007-09-13 18:13:15 +0000309 # skip tests that are related to bounds imposed in the decNumber
310 # reference implementation
311 if fname in decNumberRestricted:
312 if fname == 'power':
313 if not (vals[1]._isinteger() and
314 -1999999997 <= vals[1] <= 999999999):
315 if outside_decNumber_bounds(vals[0], self.context) or \
316 outside_decNumber_bounds(vals[1], self.context):
317 #print "Skipping test %s" % s
318 return
319 else:
320 if outside_decNumber_bounds(vals[0], self.context):
321 #print "Skipping test %s" % s
322 return
323
324
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000325 if EXTENDEDERRORTEST and fname not in ('to_sci_string', 'to_eng_string'):
326 for error in theirexceptions:
Raymond Hettingerbf440692004-07-10 14:14:37 +0000327 self.context.traps[error] = 1
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000328 try:
329 funct(*vals)
330 except error:
331 pass
Raymond Hettingerd9c0a7a2004-07-03 10:02:28 +0000332 except Signals, e:
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000333 self.fail("Raised %s in %s when %s disabled" % \
334 (e, s, error))
335 else:
336 self.fail("Did not raise %s in %s" % (error, s))
Raymond Hettingerbf440692004-07-10 14:14:37 +0000337 self.context.traps[error] = 0
Facundo Batista353750c2007-09-13 18:13:15 +0000338 if DEBUG:
339 print "--", self.context
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000340 try:
341 result = str(funct(*vals))
Facundo Batista1a191df2007-10-02 17:01:24 +0000342 if fname in LOGICAL_FUNCTIONS:
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000343 result = str(int(eval(result))) # 'True', 'False' -> '1', '0'
Raymond Hettingerd9c0a7a2004-07-03 10:02:28 +0000344 except Signals, error:
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000345 self.fail("Raised %s in %s" % (error, s))
346 except: #Catch any error long enough to state the test case.
347 print "ERROR:", s
348 raise
349
350 myexceptions = self.getexceptions()
Raymond Hettingerbf440692004-07-10 14:14:37 +0000351 self.context.clear_flags()
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000352
353 myexceptions.sort()
354 theirexceptions.sort()
355
356 self.assertEqual(result, ans,
357 'Incorrect answer for ' + s + ' -- got ' + result)
358 self.assertEqual(myexceptions, theirexceptions,
Facundo Batista353750c2007-09-13 18:13:15 +0000359 'Incorrect flags set in ' + s + ' -- got ' + str(myexceptions))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000360 return
361
362 def getexceptions(self):
Raymond Hettingerf63ba432004-08-17 05:42:09 +0000363 return [e for e in Signals if self.context.flags[e]]
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000364
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000365 def change_precision(self, prec):
366 self.context.prec = prec
367 def change_rounding_method(self, rounding):
368 self.context.rounding = rounding
369 def change_min_exponent(self, exp):
370 self.context.Emin = exp
371 def change_max_exponent(self, exp):
372 self.context.Emax = exp
373 def change_clamp(self, clamp):
374 self.context._clamp = clamp
375
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000376
377
378# The following classes test the behaviour of Decimal according to PEP 327
379
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000380class DecimalExplicitConstructionTest(unittest.TestCase):
381 '''Unit tests for Explicit Construction cases of Decimal.'''
382
383 def test_explicit_empty(self):
384 self.assertEqual(Decimal(), Decimal("0"))
385
386 def test_explicit_from_None(self):
387 self.assertRaises(TypeError, Decimal, None)
388
389 def test_explicit_from_int(self):
390
391 #positive
392 d = Decimal(45)
393 self.assertEqual(str(d), '45')
394
395 #very large positive
396 d = Decimal(500000123)
397 self.assertEqual(str(d), '500000123')
398
399 #negative
400 d = Decimal(-45)
401 self.assertEqual(str(d), '-45')
402
403 #zero
404 d = Decimal(0)
405 self.assertEqual(str(d), '0')
406
407 def test_explicit_from_string(self):
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000408
409 #empty
410 self.assertEqual(str(Decimal('')), 'NaN')
411
412 #int
413 self.assertEqual(str(Decimal('45')), '45')
414
415 #float
416 self.assertEqual(str(Decimal('45.34')), '45.34')
417
418 #engineer notation
419 self.assertEqual(str(Decimal('45e2')), '4.5E+3')
420
421 #just not a number
422 self.assertEqual(str(Decimal('ugly')), 'NaN')
423
Mark Dickinson59bc20b2008-01-12 01:56:00 +0000424 #leading and trailing whitespace permitted
425 self.assertEqual(str(Decimal('1.3E4 \n')), '1.3E+4')
426 self.assertEqual(str(Decimal(' -7.89')), '-7.89')
427
Mark Dickinson8e85ffa2008-03-25 18:47:59 +0000428 #unicode strings should be permitted
429 self.assertEqual(str(Decimal(u'0E-017')), '0E-17')
430 self.assertEqual(str(Decimal(u'45')), '45')
431 self.assertEqual(str(Decimal(u'-Inf')), '-Infinity')
432 self.assertEqual(str(Decimal(u'NaN123')), 'NaN123')
433
Mark Dickinson70c32892008-07-02 09:37:01 +0000434 #but alternate unicode digits should not
435 self.assertEqual(str(Decimal(u'\uff11')), 'NaN')
436
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000437 def test_explicit_from_tuples(self):
438
439 #zero
440 d = Decimal( (0, (0,), 0) )
441 self.assertEqual(str(d), '0')
442
443 #int
444 d = Decimal( (1, (4, 5), 0) )
445 self.assertEqual(str(d), '-45')
446
447 #float
448 d = Decimal( (0, (4, 5, 3, 4), -2) )
449 self.assertEqual(str(d), '45.34')
450
451 #weird
452 d = Decimal( (1, (4, 3, 4, 9, 1, 3, 5, 3, 4), -25) )
453 self.assertEqual(str(d), '-4.34913534E-17')
454
455 #wrong number of items
456 self.assertRaises(ValueError, Decimal, (1, (4, 3, 4, 9, 1)) )
457
458 #bad sign
459 self.assertRaises(ValueError, Decimal, (8, (4, 3, 4, 9, 1), 2) )
Facundo Batista9b5e2312007-10-19 19:25:57 +0000460 self.assertRaises(ValueError, Decimal, (0., (4, 3, 4, 9, 1), 2) )
461 self.assertRaises(ValueError, Decimal, (Decimal(1), (4, 3, 4, 9, 1), 2))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000462
463 #bad exp
464 self.assertRaises(ValueError, Decimal, (1, (4, 3, 4, 9, 1), 'wrong!') )
Facundo Batista9b5e2312007-10-19 19:25:57 +0000465 self.assertRaises(ValueError, Decimal, (1, (4, 3, 4, 9, 1), 0.) )
466 self.assertRaises(ValueError, Decimal, (1, (4, 3, 4, 9, 1), '1') )
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000467
468 #bad coefficients
469 self.assertRaises(ValueError, Decimal, (1, (4, 3, 4, None, 1), 2) )
470 self.assertRaises(ValueError, Decimal, (1, (4, -3, 4, 9, 1), 2) )
Facundo Batista9b5e2312007-10-19 19:25:57 +0000471 self.assertRaises(ValueError, Decimal, (1, (4, 10, 4, 9, 1), 2) )
Facundo Batista72bc54f2007-11-23 17:59:00 +0000472 self.assertRaises(ValueError, Decimal, (1, (4, 3, 4, 'a', 1), 2) )
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000473
474 def test_explicit_from_Decimal(self):
475
476 #positive
477 d = Decimal(45)
478 e = Decimal(d)
479 self.assertEqual(str(e), '45')
480 self.assertNotEqual(id(d), id(e))
481
482 #very large positive
483 d = Decimal(500000123)
484 e = Decimal(d)
485 self.assertEqual(str(e), '500000123')
486 self.assertNotEqual(id(d), id(e))
487
488 #negative
489 d = Decimal(-45)
490 e = Decimal(d)
491 self.assertEqual(str(e), '-45')
492 self.assertNotEqual(id(d), id(e))
493
494 #zero
495 d = Decimal(0)
496 e = Decimal(d)
497 self.assertEqual(str(e), '0')
498 self.assertNotEqual(id(d), id(e))
499
500 def test_explicit_context_create_decimal(self):
501
502 nc = copy.copy(getcontext())
503 nc.prec = 3
504
505 # empty
Raymond Hettingerfed52962004-07-14 15:41:57 +0000506 d = Decimal()
507 self.assertEqual(str(d), '0')
508 d = nc.create_decimal()
509 self.assertEqual(str(d), '0')
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000510
511 # from None
512 self.assertRaises(TypeError, nc.create_decimal, None)
513
514 # from int
515 d = nc.create_decimal(456)
516 self.failUnless(isinstance(d, Decimal))
517 self.assertEqual(nc.create_decimal(45678),
518 nc.create_decimal('457E+2'))
519
520 # from string
521 d = Decimal('456789')
522 self.assertEqual(str(d), '456789')
523 d = nc.create_decimal('456789')
524 self.assertEqual(str(d), '4.57E+5')
Mark Dickinson59bc20b2008-01-12 01:56:00 +0000525 # leading and trailing whitespace should result in a NaN;
526 # spaces are already checked in Cowlishaw's test-suite, so
527 # here we just check that a trailing newline results in a NaN
528 self.assertEqual(str(nc.create_decimal('3.14\n')), 'NaN')
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000529
530 # from tuples
531 d = Decimal( (1, (4, 3, 4, 9, 1, 3, 5, 3, 4), -25) )
532 self.assertEqual(str(d), '-4.34913534E-17')
533 d = nc.create_decimal( (1, (4, 3, 4, 9, 1, 3, 5, 3, 4), -25) )
534 self.assertEqual(str(d), '-4.35E-17')
535
536 # from Decimal
537 prevdec = Decimal(500000123)
538 d = Decimal(prevdec)
539 self.assertEqual(str(d), '500000123')
540 d = nc.create_decimal(prevdec)
541 self.assertEqual(str(d), '5.00E+8')
542
543
544class DecimalImplicitConstructionTest(unittest.TestCase):
545 '''Unit tests for Implicit Construction cases of Decimal.'''
546
547 def test_implicit_from_None(self):
548 self.assertRaises(TypeError, eval, 'Decimal(5) + None', globals())
549
550 def test_implicit_from_int(self):
551 #normal
552 self.assertEqual(str(Decimal(5) + 45), '50')
553 #exceeding precision
554 self.assertEqual(Decimal(5) + 123456789000, Decimal(123456789000))
555
556 def test_implicit_from_string(self):
557 self.assertRaises(TypeError, eval, 'Decimal(5) + "3"', globals())
558
559 def test_implicit_from_float(self):
560 self.assertRaises(TypeError, eval, 'Decimal(5) + 2.2', globals())
561
562 def test_implicit_from_Decimal(self):
563 self.assertEqual(Decimal(5) + Decimal(45), Decimal(50))
564
Raymond Hettinger267b8682005-03-27 10:47:39 +0000565 def test_rop(self):
566 # Allow other classes to be trained to interact with Decimals
567 class E:
568 def __divmod__(self, other):
569 return 'divmod ' + str(other)
570 def __rdivmod__(self, other):
571 return str(other) + ' rdivmod'
572 def __lt__(self, other):
573 return 'lt ' + str(other)
574 def __gt__(self, other):
575 return 'gt ' + str(other)
576 def __le__(self, other):
577 return 'le ' + str(other)
578 def __ge__(self, other):
579 return 'ge ' + str(other)
580 def __eq__(self, other):
581 return 'eq ' + str(other)
582 def __ne__(self, other):
583 return 'ne ' + str(other)
584
585 self.assertEqual(divmod(E(), Decimal(10)), 'divmod 10')
586 self.assertEqual(divmod(Decimal(10), E()), '10 rdivmod')
587 self.assertEqual(eval('Decimal(10) < E()'), 'gt 10')
588 self.assertEqual(eval('Decimal(10) > E()'), 'lt 10')
589 self.assertEqual(eval('Decimal(10) <= E()'), 'ge 10')
590 self.assertEqual(eval('Decimal(10) >= E()'), 'le 10')
591 self.assertEqual(eval('Decimal(10) == E()'), 'eq 10')
592 self.assertEqual(eval('Decimal(10) != E()'), 'ne 10')
593
594 # insert operator methods and then exercise them
Georg Brandl96c3f7f2006-03-28 08:06:35 +0000595 oplist = [
596 ('+', '__add__', '__radd__'),
597 ('-', '__sub__', '__rsub__'),
598 ('*', '__mul__', '__rmul__'),
599 ('%', '__mod__', '__rmod__'),
600 ('//', '__floordiv__', '__rfloordiv__'),
601 ('**', '__pow__', '__rpow__')
602 ]
603 if 1/2 == 0:
604 # testing with classic division, so add __div__
605 oplist.append(('/', '__div__', '__rdiv__'))
606 else:
607 # testing with -Qnew, so add __truediv__
608 oplist.append(('/', '__truediv__', '__rtruediv__'))
Anthony Baxter4ef3a232006-03-30 12:59:11 +0000609
Georg Brandl96c3f7f2006-03-28 08:06:35 +0000610 for sym, lop, rop in oplist:
Raymond Hettinger267b8682005-03-27 10:47:39 +0000611 setattr(E, lop, lambda self, other: 'str' + lop + str(other))
612 setattr(E, rop, lambda self, other: str(other) + rop + 'str')
613 self.assertEqual(eval('E()' + sym + 'Decimal(10)'),
614 'str' + lop + '10')
615 self.assertEqual(eval('Decimal(10)' + sym + 'E()'),
616 '10' + rop + 'str')
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000617
Mark Dickinson1ddf1d82008-02-29 02:16:37 +0000618class DecimalFormatTest(unittest.TestCase):
619 '''Unit tests for the format function.'''
620 def test_formatting(self):
621 # triples giving a format, a Decimal, and the expected result
622 test_values = [
623 ('e', '0E-15', '0e-15'),
624 ('e', '2.3E-15', '2.3e-15'),
625 ('e', '2.30E+2', '2.30e+2'), # preserve significant zeros
626 ('e', '2.30000E-15', '2.30000e-15'),
627 ('e', '1.23456789123456789e40', '1.23456789123456789e+40'),
628 ('e', '1.5', '1.5e+0'),
629 ('e', '0.15', '1.5e-1'),
630 ('e', '0.015', '1.5e-2'),
631 ('e', '0.0000000000015', '1.5e-12'),
632 ('e', '15.0', '1.50e+1'),
633 ('e', '-15', '-1.5e+1'),
634 ('e', '0', '0e+0'),
635 ('e', '0E1', '0e+1'),
636 ('e', '0.0', '0e-1'),
637 ('e', '0.00', '0e-2'),
638 ('.6e', '0E-15', '0.000000e-9'),
639 ('.6e', '0', '0.000000e+6'),
640 ('.6e', '9.999999', '9.999999e+0'),
641 ('.6e', '9.9999999', '1.000000e+1'),
642 ('.6e', '-1.23e5', '-1.230000e+5'),
643 ('.6e', '1.23456789e-3', '1.234568e-3'),
644 ('f', '0', '0'),
645 ('f', '0.0', '0.0'),
646 ('f', '0E-2', '0.00'),
647 ('f', '0.00E-8', '0.0000000000'),
648 ('f', '0E1', '0'), # loses exponent information
649 ('f', '3.2E1', '32'),
650 ('f', '3.2E2', '320'),
651 ('f', '3.20E2', '320'),
652 ('f', '3.200E2', '320.0'),
653 ('f', '3.2E-6', '0.0000032'),
654 ('.6f', '0E-15', '0.000000'), # all zeros treated equally
655 ('.6f', '0E1', '0.000000'),
656 ('.6f', '0', '0.000000'),
657 ('.0f', '0', '0'), # no decimal point
658 ('.0f', '0e-2', '0'),
659 ('.0f', '3.14159265', '3'),
660 ('.1f', '3.14159265', '3.1'),
661 ('.4f', '3.14159265', '3.1416'),
662 ('.6f', '3.14159265', '3.141593'),
663 ('.7f', '3.14159265', '3.1415926'), # round-half-even!
664 ('.8f', '3.14159265', '3.14159265'),
665 ('.9f', '3.14159265', '3.141592650'),
666
667 ('g', '0', '0'),
668 ('g', '0.0', '0.0'),
669 ('g', '0E1', '0e+1'),
670 ('G', '0E1', '0E+1'),
671 ('g', '0E-5', '0.00000'),
672 ('g', '0E-6', '0.000000'),
673 ('g', '0E-7', '0e-7'),
674 ('g', '-0E2', '-0e+2'),
675 ('.0g', '3.14159265', '3'), # 0 sig fig -> 1 sig fig
676 ('.1g', '3.14159265', '3'),
677 ('.2g', '3.14159265', '3.1'),
678 ('.5g', '3.14159265', '3.1416'),
679 ('.7g', '3.14159265', '3.141593'),
680 ('.8g', '3.14159265', '3.1415926'), # round-half-even!
681 ('.9g', '3.14159265', '3.14159265'),
682 ('.10g', '3.14159265', '3.14159265'), # don't pad
683
684 ('%', '0E1', '0%'),
685 ('%', '0E0', '0%'),
686 ('%', '0E-1', '0%'),
687 ('%', '0E-2', '0%'),
688 ('%', '0E-3', '0.0%'),
689 ('%', '0E-4', '0.00%'),
690
691 ('.3%', '0', '0.000%'), # all zeros treated equally
692 ('.3%', '0E10', '0.000%'),
693 ('.3%', '0E-10', '0.000%'),
694 ('.3%', '2.34', '234.000%'),
695 ('.3%', '1.234567', '123.457%'),
696 ('.0%', '1.23', '123%'),
697
698 ('e', 'NaN', 'NaN'),
699 ('f', '-NaN123', '-NaN123'),
700 ('+g', 'NaN456', '+NaN456'),
701 ('.3e', 'Inf', 'Infinity'),
702 ('.16f', '-Inf', '-Infinity'),
703 ('.0g', '-sNaN', '-sNaN'),
704
705 ('', '1.00', '1.00'),
706 ]
707 for fmt, d, result in test_values:
708 self.assertEqual(format(Decimal(d), fmt), result)
709
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000710class DecimalArithmeticOperatorsTest(unittest.TestCase):
711 '''Unit tests for all arithmetic operators, binary and unary.'''
712
713 def test_addition(self):
714
715 d1 = Decimal('-11.1')
716 d2 = Decimal('22.2')
717
718 #two Decimals
719 self.assertEqual(d1+d2, Decimal('11.1'))
720 self.assertEqual(d2+d1, Decimal('11.1'))
721
722 #with other type, left
723 c = d1 + 5
724 self.assertEqual(c, Decimal('-6.1'))
725 self.assertEqual(type(c), type(d1))
726
727 #with other type, right
728 c = 5 + d1
729 self.assertEqual(c, Decimal('-6.1'))
730 self.assertEqual(type(c), type(d1))
731
732 #inline with decimal
733 d1 += d2
734 self.assertEqual(d1, Decimal('11.1'))
735
736 #inline with other type
737 d1 += 5
738 self.assertEqual(d1, Decimal('16.1'))
739
740 def test_subtraction(self):
741
742 d1 = Decimal('-11.1')
743 d2 = Decimal('22.2')
744
745 #two Decimals
746 self.assertEqual(d1-d2, Decimal('-33.3'))
747 self.assertEqual(d2-d1, Decimal('33.3'))
748
749 #with other type, left
750 c = d1 - 5
751 self.assertEqual(c, Decimal('-16.1'))
752 self.assertEqual(type(c), type(d1))
753
754 #with other type, right
755 c = 5 - d1
756 self.assertEqual(c, Decimal('16.1'))
757 self.assertEqual(type(c), type(d1))
758
759 #inline with decimal
760 d1 -= d2
761 self.assertEqual(d1, Decimal('-33.3'))
762
763 #inline with other type
764 d1 -= 5
765 self.assertEqual(d1, Decimal('-38.3'))
766
767 def test_multiplication(self):
768
769 d1 = Decimal('-5')
770 d2 = Decimal('3')
771
772 #two Decimals
773 self.assertEqual(d1*d2, Decimal('-15'))
774 self.assertEqual(d2*d1, Decimal('-15'))
775
776 #with other type, left
777 c = d1 * 5
778 self.assertEqual(c, Decimal('-25'))
779 self.assertEqual(type(c), type(d1))
780
781 #with other type, right
782 c = 5 * d1
783 self.assertEqual(c, Decimal('-25'))
784 self.assertEqual(type(c), type(d1))
785
786 #inline with decimal
787 d1 *= d2
788 self.assertEqual(d1, Decimal('-15'))
789
790 #inline with other type
791 d1 *= 5
792 self.assertEqual(d1, Decimal('-75'))
793
794 def test_division(self):
795
796 d1 = Decimal('-5')
797 d2 = Decimal('2')
798
799 #two Decimals
800 self.assertEqual(d1/d2, Decimal('-2.5'))
801 self.assertEqual(d2/d1, Decimal('-0.4'))
802
803 #with other type, left
804 c = d1 / 4
805 self.assertEqual(c, Decimal('-1.25'))
806 self.assertEqual(type(c), type(d1))
807
808 #with other type, right
809 c = 4 / d1
810 self.assertEqual(c, Decimal('-0.8'))
811 self.assertEqual(type(c), type(d1))
812
813 #inline with decimal
814 d1 /= d2
815 self.assertEqual(d1, Decimal('-2.5'))
816
817 #inline with other type
818 d1 /= 4
819 self.assertEqual(d1, Decimal('-0.625'))
820
821 def test_floor_division(self):
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000822
823 d1 = Decimal('5')
824 d2 = Decimal('2')
825
826 #two Decimals
827 self.assertEqual(d1//d2, Decimal('2'))
828 self.assertEqual(d2//d1, Decimal('0'))
829
830 #with other type, left
831 c = d1 // 4
832 self.assertEqual(c, Decimal('1'))
833 self.assertEqual(type(c), type(d1))
834
835 #with other type, right
836 c = 7 // d1
837 self.assertEqual(c, Decimal('1'))
838 self.assertEqual(type(c), type(d1))
839
840 #inline with decimal
841 d1 //= d2
842 self.assertEqual(d1, Decimal('2'))
843
844 #inline with other type
845 d1 //= 2
846 self.assertEqual(d1, Decimal('1'))
847
848 def test_powering(self):
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000849
850 d1 = Decimal('5')
851 d2 = Decimal('2')
852
853 #two Decimals
854 self.assertEqual(d1**d2, Decimal('25'))
855 self.assertEqual(d2**d1, Decimal('32'))
856
857 #with other type, left
858 c = d1 ** 4
859 self.assertEqual(c, Decimal('625'))
860 self.assertEqual(type(c), type(d1))
861
862 #with other type, right
863 c = 7 ** d1
864 self.assertEqual(c, Decimal('16807'))
865 self.assertEqual(type(c), type(d1))
866
867 #inline with decimal
868 d1 **= d2
869 self.assertEqual(d1, Decimal('25'))
870
871 #inline with other type
872 d1 **= 4
873 self.assertEqual(d1, Decimal('390625'))
874
875 def test_module(self):
876
877 d1 = Decimal('5')
878 d2 = Decimal('2')
879
880 #two Decimals
881 self.assertEqual(d1%d2, Decimal('1'))
882 self.assertEqual(d2%d1, Decimal('2'))
883
884 #with other type, left
885 c = d1 % 4
886 self.assertEqual(c, Decimal('1'))
887 self.assertEqual(type(c), type(d1))
888
889 #with other type, right
890 c = 7 % d1
891 self.assertEqual(c, Decimal('2'))
892 self.assertEqual(type(c), type(d1))
893
894 #inline with decimal
895 d1 %= d2
896 self.assertEqual(d1, Decimal('1'))
897
898 #inline with other type
899 d1 %= 4
900 self.assertEqual(d1, Decimal('1'))
901
902 def test_floor_div_module(self):
903
904 d1 = Decimal('5')
905 d2 = Decimal('2')
906
907 #two Decimals
908 (p, q) = divmod(d1, d2)
909 self.assertEqual(p, Decimal('2'))
910 self.assertEqual(q, Decimal('1'))
911 self.assertEqual(type(p), type(d1))
912 self.assertEqual(type(q), type(d1))
913
914 #with other type, left
915 (p, q) = divmod(d1, 4)
916 self.assertEqual(p, Decimal('1'))
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, right
922 (p, q) = divmod(7, d1)
923 self.assertEqual(p, Decimal('1'))
924 self.assertEqual(q, Decimal('2'))
925 self.assertEqual(type(p), type(d1))
926 self.assertEqual(type(q), type(d1))
927
928 def test_unary_operators(self):
929 self.assertEqual(+Decimal(45), Decimal(+45)) # +
930 self.assertEqual(-Decimal(45), Decimal(-45)) # -
931 self.assertEqual(abs(Decimal(45)), abs(Decimal(-45))) # abs
932
Mark Dickinson2fc92632008-02-06 22:10:50 +0000933 def test_nan_comparisons(self):
934 n = Decimal('NaN')
935 s = Decimal('sNaN')
936 i = Decimal('Inf')
937 f = Decimal('2')
938 for x, y in [(n, n), (n, i), (i, n), (n, f), (f, n),
939 (s, n), (n, s), (s, i), (i, s), (s, f), (f, s), (s, s)]:
940 self.assert_(x != y)
941 self.assert_(not (x == y))
942 self.assert_(not (x < y))
943 self.assert_(not (x <= y))
944 self.assert_(not (x > y))
945 self.assert_(not (x >= y))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000946
947# The following are two functions used to test threading in the next class
948
949def thfunc1(cls):
950 d1 = Decimal(1)
951 d3 = Decimal(3)
Facundo Batista64156672008-03-22 02:45:37 +0000952 test1 = d1/d3
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000953 cls.synchro.wait()
Facundo Batista64156672008-03-22 02:45:37 +0000954 test2 = d1/d3
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000955 cls.finish1.set()
Facundo Batista64156672008-03-22 02:45:37 +0000956
Facundo Batistaee340e52008-05-02 17:39:00 +0000957 cls.assertEqual(test1, Decimal('0.3333333333333333333333333333'))
958 cls.assertEqual(test2, Decimal('0.3333333333333333333333333333'))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000959 return
960
961def thfunc2(cls):
962 d1 = Decimal(1)
963 d3 = Decimal(3)
Facundo Batista64156672008-03-22 02:45:37 +0000964 test1 = d1/d3
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000965 thiscontext = getcontext()
966 thiscontext.prec = 18
Facundo Batista64156672008-03-22 02:45:37 +0000967 test2 = d1/d3
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000968 cls.synchro.set()
969 cls.finish2.set()
Facundo Batista64156672008-03-22 02:45:37 +0000970
Facundo Batistaee340e52008-05-02 17:39:00 +0000971 cls.assertEqual(test1, Decimal('0.3333333333333333333333333333'))
Facundo Batista64156672008-03-22 02:45:37 +0000972 cls.assertEqual(test2, Decimal('0.333333333333333333'))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000973 return
974
975
976class DecimalUseOfContextTest(unittest.TestCase):
977 '''Unit tests for Use of Context cases in Decimal.'''
978
Raymond Hettinger7e71fa52004-12-18 19:07:19 +0000979 try:
980 import threading
981 except ImportError:
982 threading = None
983
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000984 # Take care executing this test from IDLE, there's an issue in threading
985 # that hangs IDLE and I couldn't find it
986
987 def test_threading(self):
988 #Test the "threading isolation" of a Context.
989
990 self.synchro = threading.Event()
991 self.finish1 = threading.Event()
992 self.finish2 = threading.Event()
993
994 th1 = threading.Thread(target=thfunc1, args=(self,))
995 th2 = threading.Thread(target=thfunc2, args=(self,))
996
997 th1.start()
998 th2.start()
999
1000 self.finish1.wait()
Thomas Woutersb3e6e8c2007-09-19 17:27:29 +00001001 self.finish2.wait()
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001002 return
1003
Raymond Hettinger7e71fa52004-12-18 19:07:19 +00001004 if threading is None:
1005 del test_threading
1006
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001007
1008class DecimalUsabilityTest(unittest.TestCase):
1009 '''Unit tests for Usability cases of Decimal.'''
1010
1011 def test_comparison_operators(self):
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001012
1013 da = Decimal('23.42')
1014 db = Decimal('23.42')
1015 dc = Decimal('45')
1016
1017 #two Decimals
1018 self.failUnless(dc > da)
1019 self.failUnless(dc >= da)
1020 self.failUnless(da < dc)
1021 self.failUnless(da <= dc)
1022 self.failUnless(da == db)
1023 self.failUnless(da != dc)
1024 self.failUnless(da <= db)
1025 self.failUnless(da >= db)
1026 self.assertEqual(cmp(dc,da), 1)
1027 self.assertEqual(cmp(da,dc), -1)
1028 self.assertEqual(cmp(da,db), 0)
1029
1030 #a Decimal and an int
1031 self.failUnless(dc > 23)
1032 self.failUnless(23 < dc)
1033 self.failUnless(dc == 45)
1034 self.assertEqual(cmp(dc,23), 1)
1035 self.assertEqual(cmp(23,dc), -1)
1036 self.assertEqual(cmp(dc,45), 0)
1037
1038 #a Decimal and uncomparable
Raymond Hettinger0aeac102004-07-05 22:53:03 +00001039 self.assertNotEqual(da, 'ugly')
1040 self.assertNotEqual(da, 32.7)
1041 self.assertNotEqual(da, object())
1042 self.assertNotEqual(da, object)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001043
Raymond Hettinger0aeac102004-07-05 22:53:03 +00001044 # sortable
1045 a = map(Decimal, xrange(100))
1046 b = a[:]
1047 random.shuffle(a)
1048 a.sort()
1049 self.assertEqual(a, b)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001050
Facundo Batista353750c2007-09-13 18:13:15 +00001051 # with None
1052 self.assertFalse(Decimal(1) < None)
1053 self.assertTrue(Decimal(1) > None)
1054
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001055 def test_copy_and_deepcopy_methods(self):
1056 d = Decimal('43.24')
1057 c = copy.copy(d)
1058 self.assertEqual(id(c), id(d))
1059 dc = copy.deepcopy(d)
1060 self.assertEqual(id(dc), id(d))
1061
1062 def test_hash_method(self):
1063 #just that it's hashable
1064 hash(Decimal(23))
Facundo Batista8c202442007-09-19 17:53:25 +00001065
1066 test_values = [Decimal(sign*(2**m + n))
1067 for m in [0, 14, 15, 16, 17, 30, 31,
1068 32, 33, 62, 63, 64, 65, 66]
1069 for n in range(-10, 10)
1070 for sign in [-1, 1]]
1071 test_values.extend([
1072 Decimal("-0"), # zeros
1073 Decimal("0.00"),
1074 Decimal("-0.000"),
1075 Decimal("0E10"),
1076 Decimal("-0E12"),
1077 Decimal("10.0"), # negative exponent
1078 Decimal("-23.00000"),
1079 Decimal("1230E100"), # positive exponent
1080 Decimal("-4.5678E50"),
1081 # a value for which hash(n) != hash(n % (2**64-1))
1082 # in Python pre-2.6
1083 Decimal(2**64 + 2**32 - 1),
1084 # selection of values which fail with the old (before
1085 # version 2.6) long.__hash__
1086 Decimal("1.634E100"),
1087 Decimal("90.697E100"),
1088 Decimal("188.83E100"),
1089 Decimal("1652.9E100"),
1090 Decimal("56531E100"),
1091 ])
1092
1093 # check that hash(d) == hash(int(d)) for integral values
1094 for value in test_values:
1095 self.assertEqual(hash(value), hash(int(value)))
1096
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001097 #the same hash that to an int
1098 self.assertEqual(hash(Decimal(23)), hash(23))
Raymond Hettingerbea3f6f2005-03-15 04:59:17 +00001099 self.assertRaises(TypeError, hash, Decimal('NaN'))
1100 self.assert_(hash(Decimal('Inf')))
1101 self.assert_(hash(Decimal('-Inf')))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001102
Facundo Batista52b25792008-01-08 12:25:20 +00001103 # check that the value of the hash doesn't depend on the
1104 # current context (issue #1757)
1105 c = getcontext()
1106 old_precision = c.prec
1107 x = Decimal("123456789.1")
1108
1109 c.prec = 6
1110 h1 = hash(x)
1111 c.prec = 10
1112 h2 = hash(x)
1113 c.prec = 16
1114 h3 = hash(x)
1115
1116 self.assertEqual(h1, h2)
1117 self.assertEqual(h1, h3)
1118 c.prec = old_precision
1119
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001120 def test_min_and_max_methods(self):
1121
1122 d1 = Decimal('15.32')
1123 d2 = Decimal('28.5')
1124 l1 = 15
1125 l2 = 28
1126
1127 #between Decimals
1128 self.failUnless(min(d1,d2) is d1)
1129 self.failUnless(min(d2,d1) is d1)
1130 self.failUnless(max(d1,d2) is d2)
1131 self.failUnless(max(d2,d1) is d2)
1132
1133 #between Decimal and long
1134 self.failUnless(min(d1,l2) is d1)
1135 self.failUnless(min(l2,d1) is d1)
1136 self.failUnless(max(l1,d2) is d2)
1137 self.failUnless(max(d2,l1) is d2)
1138
1139 def test_as_nonzero(self):
1140 #as false
1141 self.failIf(Decimal(0))
1142 #as true
1143 self.failUnless(Decimal('0.372'))
1144
1145 def test_tostring_methods(self):
1146 #Test str and repr methods.
1147
1148 d = Decimal('15.32')
1149 self.assertEqual(str(d), '15.32') # str
Raymond Hettingerabe32372008-02-14 02:41:22 +00001150 self.assertEqual(repr(d), "Decimal('15.32')") # repr
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001151
Mark Dickinson8e85ffa2008-03-25 18:47:59 +00001152 # result type of string methods should be str, not unicode
1153 unicode_inputs = [u'123.4', u'0.5E2', u'Infinity', u'sNaN',
1154 u'-0.0E100', u'-NaN001', u'-Inf']
1155
1156 for u in unicode_inputs:
1157 d = Decimal(u)
1158 self.assertEqual(type(str(d)), str)
1159 self.assertEqual(type(repr(d)), str)
1160 self.assertEqual(type(d.to_eng_string()), str)
1161
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001162 def test_tonum_methods(self):
1163 #Test float, int and long methods.
1164
1165 d1 = Decimal('66')
1166 d2 = Decimal('15.32')
1167
1168 #int
1169 self.assertEqual(int(d1), 66)
1170 self.assertEqual(int(d2), 15)
1171
1172 #long
1173 self.assertEqual(long(d1), 66)
1174 self.assertEqual(long(d2), 15)
1175
1176 #float
1177 self.assertEqual(float(d1), 66)
1178 self.assertEqual(float(d2), 15.32)
1179
1180 def test_eval_round_trip(self):
1181
1182 #with zero
1183 d = Decimal( (0, (0,), 0) )
1184 self.assertEqual(d, eval(repr(d)))
1185
1186 #int
1187 d = Decimal( (1, (4, 5), 0) )
1188 self.assertEqual(d, eval(repr(d)))
1189
1190 #float
1191 d = Decimal( (0, (4, 5, 3, 4), -2) )
1192 self.assertEqual(d, eval(repr(d)))
1193
1194 #weird
1195 d = Decimal( (1, (4, 3, 4, 9, 1, 3, 5, 3, 4), -25) )
1196 self.assertEqual(d, eval(repr(d)))
1197
1198 def test_as_tuple(self):
1199
1200 #with zero
1201 d = Decimal(0)
1202 self.assertEqual(d.as_tuple(), (0, (0,), 0) )
1203
1204 #int
1205 d = Decimal(-45)
1206 self.assertEqual(d.as_tuple(), (1, (4, 5), 0) )
1207
1208 #complicated string
1209 d = Decimal("-4.34913534E-17")
1210 self.assertEqual(d.as_tuple(), (1, (4, 3, 4, 9, 1, 3, 5, 3, 4), -25) )
1211
1212 #inf
1213 d = Decimal("Infinity")
1214 self.assertEqual(d.as_tuple(), (0, (0,), 'F') )
1215
Facundo Batista9b5e2312007-10-19 19:25:57 +00001216 #leading zeros in coefficient should be stripped
1217 d = Decimal( (0, (0, 0, 4, 0, 5, 3, 4), -2) )
1218 self.assertEqual(d.as_tuple(), (0, (4, 0, 5, 3, 4), -2) )
1219 d = Decimal( (1, (0, 0, 0), 37) )
1220 self.assertEqual(d.as_tuple(), (1, (0,), 37))
1221 d = Decimal( (1, (), 37) )
1222 self.assertEqual(d.as_tuple(), (1, (0,), 37))
1223
1224 #leading zeros in NaN diagnostic info should be stripped
1225 d = Decimal( (0, (0, 0, 4, 0, 5, 3, 4), 'n') )
1226 self.assertEqual(d.as_tuple(), (0, (4, 0, 5, 3, 4), 'n') )
1227 d = Decimal( (1, (0, 0, 0), 'N') )
1228 self.assertEqual(d.as_tuple(), (1, (), 'N') )
1229 d = Decimal( (1, (), 'n') )
1230 self.assertEqual(d.as_tuple(), (1, (), 'n') )
1231
1232 #coefficient in infinity should be ignored
1233 d = Decimal( (0, (4, 5, 3, 4), 'F') )
1234 self.assertEqual(d.as_tuple(), (0, (0,), 'F'))
1235 d = Decimal( (1, (0, 2, 7, 1), 'F') )
1236 self.assertEqual(d.as_tuple(), (1, (0,), 'F'))
1237
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001238 def test_immutability_operations(self):
1239 # Do operations and check that it didn't change change internal objects.
1240
1241 d1 = Decimal('-25e55')
1242 b1 = Decimal('-25e55')
Facundo Batista353750c2007-09-13 18:13:15 +00001243 d2 = Decimal('33e+33')
1244 b2 = Decimal('33e+33')
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001245
1246 def checkSameDec(operation, useOther=False):
1247 if useOther:
1248 eval("d1." + operation + "(d2)")
1249 self.assertEqual(d1._sign, b1._sign)
1250 self.assertEqual(d1._int, b1._int)
1251 self.assertEqual(d1._exp, b1._exp)
1252 self.assertEqual(d2._sign, b2._sign)
1253 self.assertEqual(d2._int, b2._int)
1254 self.assertEqual(d2._exp, b2._exp)
1255 else:
1256 eval("d1." + operation + "()")
1257 self.assertEqual(d1._sign, b1._sign)
1258 self.assertEqual(d1._int, b1._int)
1259 self.assertEqual(d1._exp, b1._exp)
1260 return
1261
1262 Decimal(d1)
1263 self.assertEqual(d1._sign, b1._sign)
1264 self.assertEqual(d1._int, b1._int)
1265 self.assertEqual(d1._exp, b1._exp)
1266
1267 checkSameDec("__abs__")
1268 checkSameDec("__add__", True)
1269 checkSameDec("__div__", True)
1270 checkSameDec("__divmod__", True)
Mark Dickinson2fc92632008-02-06 22:10:50 +00001271 checkSameDec("__eq__", True)
1272 checkSameDec("__ne__", True)
1273 checkSameDec("__le__", True)
1274 checkSameDec("__lt__", True)
1275 checkSameDec("__ge__", True)
1276 checkSameDec("__gt__", True)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001277 checkSameDec("__float__")
1278 checkSameDec("__floordiv__", True)
1279 checkSameDec("__hash__")
1280 checkSameDec("__int__")
Raymond Hettinger5a053642008-01-24 19:05:29 +00001281 checkSameDec("__trunc__")
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001282 checkSameDec("__long__")
1283 checkSameDec("__mod__", True)
1284 checkSameDec("__mul__", True)
1285 checkSameDec("__neg__")
1286 checkSameDec("__nonzero__")
1287 checkSameDec("__pos__")
1288 checkSameDec("__pow__", True)
1289 checkSameDec("__radd__", True)
1290 checkSameDec("__rdiv__", True)
1291 checkSameDec("__rdivmod__", True)
1292 checkSameDec("__repr__")
1293 checkSameDec("__rfloordiv__", True)
1294 checkSameDec("__rmod__", True)
1295 checkSameDec("__rmul__", True)
1296 checkSameDec("__rpow__", True)
1297 checkSameDec("__rsub__", True)
1298 checkSameDec("__str__")
1299 checkSameDec("__sub__", True)
1300 checkSameDec("__truediv__", True)
1301 checkSameDec("adjusted")
1302 checkSameDec("as_tuple")
1303 checkSameDec("compare", True)
1304 checkSameDec("max", True)
1305 checkSameDec("min", True)
1306 checkSameDec("normalize")
1307 checkSameDec("quantize", True)
1308 checkSameDec("remainder_near", True)
1309 checkSameDec("same_quantum", True)
1310 checkSameDec("sqrt")
1311 checkSameDec("to_eng_string")
1312 checkSameDec("to_integral")
1313
Facundo Batista6c398da2007-09-17 17:30:13 +00001314 def test_subclassing(self):
1315 # Different behaviours when subclassing Decimal
1316
1317 class MyDecimal(Decimal):
1318 pass
1319
1320 d1 = MyDecimal(1)
1321 d2 = MyDecimal(2)
1322 d = d1 + d2
1323 self.assertTrue(type(d) is Decimal)
1324
1325 d = d1.max(d2)
1326 self.assertTrue(type(d) is Decimal)
1327
Mark Dickinson3b24ccb2008-03-25 14:33:23 +00001328 def test_implicit_context(self):
1329 # Check results when context given implicitly. (Issue 2478)
1330 c = getcontext()
1331 self.assertEqual(str(Decimal(0).sqrt()),
1332 str(c.sqrt(Decimal(0))))
1333
Facundo Batista6c398da2007-09-17 17:30:13 +00001334
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001335class DecimalPythonAPItests(unittest.TestCase):
1336
1337 def test_pickle(self):
1338 d = Decimal('-3.141590000')
1339 p = pickle.dumps(d)
1340 e = pickle.loads(p)
1341 self.assertEqual(d, e)
1342
Raymond Hettinger5548be22004-07-05 18:49:38 +00001343 def test_int(self):
Raymond Hettinger605ed022004-11-24 07:28:48 +00001344 for x in range(-250, 250):
1345 s = '%0.2f' % (x / 100.0)
Raymond Hettinger5548be22004-07-05 18:49:38 +00001346 # should work the same as for floats
1347 self.assertEqual(int(Decimal(s)), int(float(s)))
Raymond Hettinger605ed022004-11-24 07:28:48 +00001348 # should work the same as to_integral in the ROUND_DOWN mode
Raymond Hettinger5548be22004-07-05 18:49:38 +00001349 d = Decimal(s)
Raymond Hettinger605ed022004-11-24 07:28:48 +00001350 r = d.to_integral(ROUND_DOWN)
Raymond Hettinger5548be22004-07-05 18:49:38 +00001351 self.assertEqual(Decimal(int(d)), r)
1352
Raymond Hettinger5a053642008-01-24 19:05:29 +00001353 def test_trunc(self):
1354 for x in range(-250, 250):
1355 s = '%0.2f' % (x / 100.0)
1356 # should work the same as for floats
1357 self.assertEqual(int(Decimal(s)), int(float(s)))
1358 # should work the same as to_integral in the ROUND_DOWN mode
1359 d = Decimal(s)
1360 r = d.to_integral(ROUND_DOWN)
Jeffrey Yasskinca2b69f2008-02-01 06:22:46 +00001361 self.assertEqual(Decimal(math.trunc(d)), r)
Raymond Hettinger5a053642008-01-24 19:05:29 +00001362
Raymond Hettingerf4d85972009-01-03 19:02:23 +00001363 def test_from_float(self):
1364
1365 class MyDecimal(Decimal):
1366 pass
1367
1368 r = MyDecimal.from_float(0.1)
1369 self.assertEqual(type(r), MyDecimal)
1370 self.assertEqual(str(r),
1371 '0.1000000000000000055511151231257827021181583404541015625')
1372 bigint = 12345678901234567890123456789
1373 self.assertEqual(MyDecimal.from_float(bigint), MyDecimal(bigint))
1374 self.assert_(MyDecimal.from_float(float('nan')).is_qnan())
1375 self.assert_(MyDecimal.from_float(float('inf')).is_infinite())
1376 self.assert_(MyDecimal.from_float(float('-inf')).is_infinite())
1377 self.assertEqual(str(MyDecimal.from_float(float('nan'))),
1378 str(Decimal('NaN')))
1379 self.assertEqual(str(MyDecimal.from_float(float('inf'))),
1380 str(Decimal('Infinity')))
1381 self.assertEqual(str(MyDecimal.from_float(float('-inf'))),
1382 str(Decimal('-Infinity')))
1383 self.assertRaises(TypeError, MyDecimal.from_float, 'abc')
1384 for i in range(200):
1385 x = random.expovariate(0.01) * (random.random() * 2.0 - 1.0)
1386 self.assertEqual(x, float(MyDecimal.from_float(x))) # roundtrip
1387
1388 def test_create_decimal_from_float(self):
1389 context = Context(prec=5, rounding=ROUND_DOWN)
1390 self.assertEqual(
1391 context.create_decimal_from_float(math.pi),
1392 Decimal('3.1415')
1393 )
1394 context = Context(prec=5, rounding=ROUND_UP)
1395 self.assertEqual(
1396 context.create_decimal_from_float(math.pi),
1397 Decimal('3.1416')
1398 )
1399 context = Context(prec=5, traps=[Inexact])
1400 self.assertRaises(
1401 Inexact,
1402 context.create_decimal_from_float,
1403 math.pi
1404 )
1405 self.assertEqual(repr(context.create_decimal_from_float(-0.0)),
1406 "Decimal('-0')")
1407 self.assertEqual(repr(context.create_decimal_from_float(1.0)),
1408 "Decimal('1')")
1409 self.assertEqual(repr(context.create_decimal_from_float(10)),
1410 "Decimal('10')")
1411
Raymond Hettingerd9c0a7a2004-07-03 10:02:28 +00001412class ContextAPItests(unittest.TestCase):
1413
1414 def test_pickle(self):
1415 c = Context()
1416 e = pickle.loads(pickle.dumps(c))
1417 for k in vars(c):
1418 v1 = vars(c)[k]
1419 v2 = vars(e)[k]
1420 self.assertEqual(v1, v2)
1421
Raymond Hettinger0aeac102004-07-05 22:53:03 +00001422 def test_equality_with_other_types(self):
1423 self.assert_(Decimal(10) in ['a', 1.0, Decimal(10), (1,2), {}])
1424 self.assert_(Decimal(10) not in ['a', 1.0, (1,2), {}])
1425
Raymond Hettinger955d2b22004-08-08 20:17:45 +00001426 def test_copy(self):
1427 # All copies should be deep
1428 c = Context()
1429 d = c.copy()
1430 self.assertNotEqual(id(c), id(d))
1431 self.assertNotEqual(id(c.flags), id(d.flags))
1432 self.assertNotEqual(id(c.traps), id(d.traps))
1433
Nick Coghlan8b6999b2006-08-31 12:00:43 +00001434class WithStatementTest(unittest.TestCase):
1435 # Can't do these as docstrings until Python 2.6
1436 # as doctest can't handle __future__ statements
Nick Coghlan8b6999b2006-08-31 12:00:43 +00001437
1438 def test_localcontext(self):
Nick Coghlanced12182006-09-02 03:54:17 +00001439 # Use a copy of the current context in the block
Nick Coghlan8b6999b2006-08-31 12:00:43 +00001440 orig_ctx = getcontext()
1441 with localcontext() as enter_ctx:
1442 set_ctx = getcontext()
1443 final_ctx = getcontext()
1444 self.assert_(orig_ctx is final_ctx, 'did not restore context correctly')
1445 self.assert_(orig_ctx is not set_ctx, 'did not copy the context')
1446 self.assert_(set_ctx is enter_ctx, '__enter__ returned wrong context')
1447
1448 def test_localcontextarg(self):
Nick Coghlanced12182006-09-02 03:54:17 +00001449 # Use a copy of the supplied context in the block
Nick Coghlan8b6999b2006-08-31 12:00:43 +00001450 orig_ctx = getcontext()
1451 new_ctx = Context(prec=42)
1452 with localcontext(new_ctx) as enter_ctx:
1453 set_ctx = getcontext()
1454 final_ctx = getcontext()
1455 self.assert_(orig_ctx is final_ctx, 'did not restore context correctly')
1456 self.assert_(set_ctx.prec == new_ctx.prec, 'did not set correct context')
1457 self.assert_(new_ctx is not set_ctx, 'did not copy the context')
1458 self.assert_(set_ctx is enter_ctx, '__enter__ returned wrong context')
1459
Facundo Batista353750c2007-09-13 18:13:15 +00001460class ContextFlags(unittest.TestCase):
1461 def test_flags_irrelevant(self):
1462 # check that the result (numeric result + flags raised) of an
1463 # arithmetic operation doesn't depend on the current flags
1464
1465 context = Context(prec=9, Emin = -999999999, Emax = 999999999,
1466 rounding=ROUND_HALF_EVEN, traps=[], flags=[])
1467
1468 # operations that raise various flags, in the form (function, arglist)
1469 operations = [
1470 (context._apply, [Decimal("100E-1000000009")]),
1471 (context.sqrt, [Decimal(2)]),
1472 (context.add, [Decimal("1.23456789"), Decimal("9.87654321")]),
1473 (context.multiply, [Decimal("1.23456789"), Decimal("9.87654321")]),
1474 (context.subtract, [Decimal("1.23456789"), Decimal("9.87654321")]),
1475 ]
1476
1477 # try various flags individually, then a whole lot at once
1478 flagsets = [[Inexact], [Rounded], [Underflow], [Clamped], [Subnormal],
1479 [Inexact, Rounded, Underflow, Clamped, Subnormal]]
1480
1481 for fn, args in operations:
1482 # find answer and flags raised using a clean context
1483 context.clear_flags()
1484 ans = fn(*args)
1485 flags = [k for k, v in context.flags.items() if v]
1486
1487 for extra_flags in flagsets:
1488 # set flags, before calling operation
1489 context.clear_flags()
1490 for flag in extra_flags:
1491 context._raise_error(flag)
1492 new_ans = fn(*args)
1493
1494 # flags that we expect to be set after the operation
1495 expected_flags = list(flags)
1496 for flag in extra_flags:
1497 if flag not in expected_flags:
1498 expected_flags.append(flag)
1499 expected_flags.sort()
1500
1501 # flags we actually got
1502 new_flags = [k for k,v in context.flags.items() if v]
1503 new_flags.sort()
1504
1505 self.assertEqual(ans, new_ans,
1506 "operation produces different answers depending on flags set: " +
1507 "expected %s, got %s." % (ans, new_ans))
1508 self.assertEqual(new_flags, expected_flags,
1509 "operation raises different flags depending on flags set: " +
1510 "expected %s, got %s" % (expected_flags, new_flags))
1511
1512def test_main(arith=False, verbose=None, todo_tests=None, debug=None):
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001513 """ Execute the tests.
1514
Raymond Hettingered20ad82004-09-04 20:09:13 +00001515 Runs all arithmetic tests if arith is True or if the "decimal" resource
1516 is enabled in regrtest.py
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001517 """
Raymond Hettingered20ad82004-09-04 20:09:13 +00001518
Neal Norwitzce4a9c92006-04-09 08:36:46 +00001519 init()
Facundo Batista353750c2007-09-13 18:13:15 +00001520 global TEST_ALL, DEBUG
Raymond Hettingered20ad82004-09-04 20:09:13 +00001521 TEST_ALL = arith or is_resource_enabled('decimal')
Facundo Batista353750c2007-09-13 18:13:15 +00001522 DEBUG = debug
Raymond Hettingered20ad82004-09-04 20:09:13 +00001523
Facundo Batista353750c2007-09-13 18:13:15 +00001524 if todo_tests is None:
1525 test_classes = [
1526 DecimalExplicitConstructionTest,
1527 DecimalImplicitConstructionTest,
1528 DecimalArithmeticOperatorsTest,
Mark Dickinson1ddf1d82008-02-29 02:16:37 +00001529 DecimalFormatTest,
Facundo Batista353750c2007-09-13 18:13:15 +00001530 DecimalUseOfContextTest,
1531 DecimalUsabilityTest,
1532 DecimalPythonAPItests,
1533 ContextAPItests,
1534 DecimalTest,
1535 WithStatementTest,
1536 ContextFlags
1537 ]
1538 else:
1539 test_classes = [DecimalTest]
1540
1541 # Dynamically build custom test definition for each file in the test
1542 # directory and add the definitions to the DecimalTest class. This
1543 # procedure insures that new files do not get skipped.
1544 for filename in os.listdir(directory):
1545 if '.decTest' not in filename or filename.startswith("."):
1546 continue
1547 head, tail = filename.split('.')
1548 if todo_tests is not None and head not in todo_tests:
1549 continue
1550 tester = lambda self, f=filename: self.eval_file(directory + f)
1551 setattr(DecimalTest, 'test_' + head, tester)
1552 del filename, head, tail, tester
1553
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001554
Tim Peters46cc7022006-03-31 04:11:16 +00001555 try:
1556 run_unittest(*test_classes)
Facundo Batista353750c2007-09-13 18:13:15 +00001557 if todo_tests is None:
1558 import decimal as DecimalModule
1559 run_doctest(DecimalModule, verbose)
Tim Peters46cc7022006-03-31 04:11:16 +00001560 finally:
1561 setcontext(ORIGINAL_CONTEXT)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001562
1563if __name__ == '__main__':
Facundo Batista353750c2007-09-13 18:13:15 +00001564 import optparse
1565 p = optparse.OptionParser("test_decimal.py [--debug] [{--skip | test1 [test2 [...]]}]")
1566 p.add_option('--debug', '-d', action='store_true', help='shows the test number and context before each test')
1567 p.add_option('--skip', '-s', action='store_true', help='skip over 90% of the arithmetic tests')
1568 (opt, args) = p.parse_args()
1569
1570 if opt.skip:
1571 test_main(arith=False, verbose=True)
1572 elif args:
1573 test_main(arith=True, verbose=True, todo_tests=args, debug=opt.debug)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001574 else:
Facundo Batista353750c2007-09-13 18:13:15 +00001575 test_main(arith=True, verbose=True)