blob: 74304f70fe485538868a1c75dcb05305981c7cb9 [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 (
171 len(v._int) > DEC_MAX_MATH or
172 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'),
707 ]
708 for fmt, d, result in test_values:
709 self.assertEqual(format(Decimal(d), fmt), result)
710
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000711class DecimalArithmeticOperatorsTest(unittest.TestCase):
712 '''Unit tests for all arithmetic operators, binary and unary.'''
713
714 def test_addition(self):
715
716 d1 = Decimal('-11.1')
717 d2 = Decimal('22.2')
718
719 #two Decimals
720 self.assertEqual(d1+d2, Decimal('11.1'))
721 self.assertEqual(d2+d1, Decimal('11.1'))
722
723 #with other type, left
724 c = d1 + 5
725 self.assertEqual(c, Decimal('-6.1'))
726 self.assertEqual(type(c), type(d1))
727
728 #with other type, right
729 c = 5 + d1
730 self.assertEqual(c, Decimal('-6.1'))
731 self.assertEqual(type(c), type(d1))
732
733 #inline with decimal
734 d1 += d2
735 self.assertEqual(d1, Decimal('11.1'))
736
737 #inline with other type
738 d1 += 5
739 self.assertEqual(d1, Decimal('16.1'))
740
741 def test_subtraction(self):
742
743 d1 = Decimal('-11.1')
744 d2 = Decimal('22.2')
745
746 #two Decimals
747 self.assertEqual(d1-d2, Decimal('-33.3'))
748 self.assertEqual(d2-d1, Decimal('33.3'))
749
750 #with other type, left
751 c = d1 - 5
752 self.assertEqual(c, Decimal('-16.1'))
753 self.assertEqual(type(c), type(d1))
754
755 #with other type, right
756 c = 5 - d1
757 self.assertEqual(c, Decimal('16.1'))
758 self.assertEqual(type(c), type(d1))
759
760 #inline with decimal
761 d1 -= d2
762 self.assertEqual(d1, Decimal('-33.3'))
763
764 #inline with other type
765 d1 -= 5
766 self.assertEqual(d1, Decimal('-38.3'))
767
768 def test_multiplication(self):
769
770 d1 = Decimal('-5')
771 d2 = Decimal('3')
772
773 #two Decimals
774 self.assertEqual(d1*d2, Decimal('-15'))
775 self.assertEqual(d2*d1, Decimal('-15'))
776
777 #with other type, left
778 c = d1 * 5
779 self.assertEqual(c, Decimal('-25'))
780 self.assertEqual(type(c), type(d1))
781
782 #with other type, right
783 c = 5 * d1
784 self.assertEqual(c, Decimal('-25'))
785 self.assertEqual(type(c), type(d1))
786
787 #inline with decimal
788 d1 *= d2
789 self.assertEqual(d1, Decimal('-15'))
790
791 #inline with other type
792 d1 *= 5
793 self.assertEqual(d1, Decimal('-75'))
794
795 def test_division(self):
796
797 d1 = Decimal('-5')
798 d2 = Decimal('2')
799
800 #two Decimals
801 self.assertEqual(d1/d2, Decimal('-2.5'))
802 self.assertEqual(d2/d1, Decimal('-0.4'))
803
804 #with other type, left
805 c = d1 / 4
806 self.assertEqual(c, Decimal('-1.25'))
807 self.assertEqual(type(c), type(d1))
808
809 #with other type, right
810 c = 4 / d1
811 self.assertEqual(c, Decimal('-0.8'))
812 self.assertEqual(type(c), type(d1))
813
814 #inline with decimal
815 d1 /= d2
816 self.assertEqual(d1, Decimal('-2.5'))
817
818 #inline with other type
819 d1 /= 4
820 self.assertEqual(d1, Decimal('-0.625'))
821
822 def test_floor_division(self):
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000823
824 d1 = Decimal('5')
825 d2 = Decimal('2')
826
827 #two Decimals
828 self.assertEqual(d1//d2, Decimal('2'))
829 self.assertEqual(d2//d1, Decimal('0'))
830
831 #with other type, left
832 c = d1 // 4
833 self.assertEqual(c, Decimal('1'))
834 self.assertEqual(type(c), type(d1))
835
836 #with other type, right
837 c = 7 // d1
838 self.assertEqual(c, Decimal('1'))
839 self.assertEqual(type(c), type(d1))
840
841 #inline with decimal
842 d1 //= d2
843 self.assertEqual(d1, Decimal('2'))
844
845 #inline with other type
846 d1 //= 2
847 self.assertEqual(d1, Decimal('1'))
848
849 def test_powering(self):
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000850
851 d1 = Decimal('5')
852 d2 = Decimal('2')
853
854 #two Decimals
855 self.assertEqual(d1**d2, Decimal('25'))
856 self.assertEqual(d2**d1, Decimal('32'))
857
858 #with other type, left
859 c = d1 ** 4
860 self.assertEqual(c, Decimal('625'))
861 self.assertEqual(type(c), type(d1))
862
863 #with other type, right
864 c = 7 ** d1
865 self.assertEqual(c, Decimal('16807'))
866 self.assertEqual(type(c), type(d1))
867
868 #inline with decimal
869 d1 **= d2
870 self.assertEqual(d1, Decimal('25'))
871
872 #inline with other type
873 d1 **= 4
874 self.assertEqual(d1, Decimal('390625'))
875
876 def test_module(self):
877
878 d1 = Decimal('5')
879 d2 = Decimal('2')
880
881 #two Decimals
882 self.assertEqual(d1%d2, Decimal('1'))
883 self.assertEqual(d2%d1, Decimal('2'))
884
885 #with other type, left
886 c = d1 % 4
887 self.assertEqual(c, Decimal('1'))
888 self.assertEqual(type(c), type(d1))
889
890 #with other type, right
891 c = 7 % d1
892 self.assertEqual(c, Decimal('2'))
893 self.assertEqual(type(c), type(d1))
894
895 #inline with decimal
896 d1 %= d2
897 self.assertEqual(d1, Decimal('1'))
898
899 #inline with other type
900 d1 %= 4
901 self.assertEqual(d1, Decimal('1'))
902
903 def test_floor_div_module(self):
904
905 d1 = Decimal('5')
906 d2 = Decimal('2')
907
908 #two Decimals
909 (p, q) = divmod(d1, d2)
910 self.assertEqual(p, Decimal('2'))
911 self.assertEqual(q, Decimal('1'))
912 self.assertEqual(type(p), type(d1))
913 self.assertEqual(type(q), type(d1))
914
915 #with other type, left
916 (p, q) = divmod(d1, 4)
917 self.assertEqual(p, Decimal('1'))
918 self.assertEqual(q, Decimal('1'))
919 self.assertEqual(type(p), type(d1))
920 self.assertEqual(type(q), type(d1))
921
922 #with other type, right
923 (p, q) = divmod(7, d1)
924 self.assertEqual(p, Decimal('1'))
925 self.assertEqual(q, Decimal('2'))
926 self.assertEqual(type(p), type(d1))
927 self.assertEqual(type(q), type(d1))
928
929 def test_unary_operators(self):
930 self.assertEqual(+Decimal(45), Decimal(+45)) # +
931 self.assertEqual(-Decimal(45), Decimal(-45)) # -
932 self.assertEqual(abs(Decimal(45)), abs(Decimal(-45))) # abs
933
Mark Dickinson2fc92632008-02-06 22:10:50 +0000934 def test_nan_comparisons(self):
935 n = Decimal('NaN')
936 s = Decimal('sNaN')
937 i = Decimal('Inf')
938 f = Decimal('2')
939 for x, y in [(n, n), (n, i), (i, n), (n, f), (f, n),
940 (s, n), (n, s), (s, i), (i, s), (s, f), (f, s), (s, s)]:
941 self.assert_(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))
946 self.assert_(not (x >= y))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000947
948# The following are two functions used to test threading in the next class
949
950def thfunc1(cls):
951 d1 = Decimal(1)
952 d3 = Decimal(3)
Facundo Batista64156672008-03-22 02:45:37 +0000953 test1 = d1/d3
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000954 cls.synchro.wait()
Facundo Batista64156672008-03-22 02:45:37 +0000955 test2 = d1/d3
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000956 cls.finish1.set()
Facundo Batista64156672008-03-22 02:45:37 +0000957
Facundo Batistaee340e52008-05-02 17:39:00 +0000958 cls.assertEqual(test1, Decimal('0.3333333333333333333333333333'))
959 cls.assertEqual(test2, Decimal('0.3333333333333333333333333333'))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000960 return
961
962def thfunc2(cls):
963 d1 = Decimal(1)
964 d3 = Decimal(3)
Facundo Batista64156672008-03-22 02:45:37 +0000965 test1 = d1/d3
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000966 thiscontext = getcontext()
967 thiscontext.prec = 18
Facundo Batista64156672008-03-22 02:45:37 +0000968 test2 = d1/d3
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000969 cls.synchro.set()
970 cls.finish2.set()
Facundo Batista64156672008-03-22 02:45:37 +0000971
Facundo Batistaee340e52008-05-02 17:39:00 +0000972 cls.assertEqual(test1, Decimal('0.3333333333333333333333333333'))
Facundo Batista64156672008-03-22 02:45:37 +0000973 cls.assertEqual(test2, Decimal('0.333333333333333333'))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000974 return
975
976
977class DecimalUseOfContextTest(unittest.TestCase):
978 '''Unit tests for Use of Context cases in Decimal.'''
979
Raymond Hettinger7e71fa52004-12-18 19:07:19 +0000980 try:
981 import threading
982 except ImportError:
983 threading = None
984
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000985 # Take care executing this test from IDLE, there's an issue in threading
986 # that hangs IDLE and I couldn't find it
987
988 def test_threading(self):
989 #Test the "threading isolation" of a Context.
990
991 self.synchro = threading.Event()
992 self.finish1 = threading.Event()
993 self.finish2 = threading.Event()
994
995 th1 = threading.Thread(target=thfunc1, args=(self,))
996 th2 = threading.Thread(target=thfunc2, args=(self,))
997
998 th1.start()
999 th2.start()
1000
1001 self.finish1.wait()
Thomas Woutersb3e6e8c2007-09-19 17:27:29 +00001002 self.finish2.wait()
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001003 return
1004
Raymond Hettinger7e71fa52004-12-18 19:07:19 +00001005 if threading is None:
1006 del test_threading
1007
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001008
1009class DecimalUsabilityTest(unittest.TestCase):
1010 '''Unit tests for Usability cases of Decimal.'''
1011
1012 def test_comparison_operators(self):
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001013
1014 da = Decimal('23.42')
1015 db = Decimal('23.42')
1016 dc = Decimal('45')
1017
1018 #two Decimals
1019 self.failUnless(dc > da)
1020 self.failUnless(dc >= da)
1021 self.failUnless(da < dc)
1022 self.failUnless(da <= dc)
1023 self.failUnless(da == db)
1024 self.failUnless(da != dc)
1025 self.failUnless(da <= db)
1026 self.failUnless(da >= db)
1027 self.assertEqual(cmp(dc,da), 1)
1028 self.assertEqual(cmp(da,dc), -1)
1029 self.assertEqual(cmp(da,db), 0)
1030
1031 #a Decimal and an int
1032 self.failUnless(dc > 23)
1033 self.failUnless(23 < dc)
1034 self.failUnless(dc == 45)
1035 self.assertEqual(cmp(dc,23), 1)
1036 self.assertEqual(cmp(23,dc), -1)
1037 self.assertEqual(cmp(dc,45), 0)
1038
1039 #a Decimal and uncomparable
Raymond Hettinger0aeac102004-07-05 22:53:03 +00001040 self.assertNotEqual(da, 'ugly')
1041 self.assertNotEqual(da, 32.7)
1042 self.assertNotEqual(da, object())
1043 self.assertNotEqual(da, object)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001044
Raymond Hettinger0aeac102004-07-05 22:53:03 +00001045 # sortable
1046 a = map(Decimal, xrange(100))
1047 b = a[:]
1048 random.shuffle(a)
1049 a.sort()
1050 self.assertEqual(a, b)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001051
Facundo Batista353750c2007-09-13 18:13:15 +00001052 # with None
1053 self.assertFalse(Decimal(1) < None)
1054 self.assertTrue(Decimal(1) > None)
1055
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001056 def test_copy_and_deepcopy_methods(self):
1057 d = Decimal('43.24')
1058 c = copy.copy(d)
1059 self.assertEqual(id(c), id(d))
1060 dc = copy.deepcopy(d)
1061 self.assertEqual(id(dc), id(d))
1062
1063 def test_hash_method(self):
1064 #just that it's hashable
1065 hash(Decimal(23))
Facundo Batista8c202442007-09-19 17:53:25 +00001066
1067 test_values = [Decimal(sign*(2**m + n))
1068 for m in [0, 14, 15, 16, 17, 30, 31,
1069 32, 33, 62, 63, 64, 65, 66]
1070 for n in range(-10, 10)
1071 for sign in [-1, 1]]
1072 test_values.extend([
1073 Decimal("-0"), # zeros
1074 Decimal("0.00"),
1075 Decimal("-0.000"),
1076 Decimal("0E10"),
1077 Decimal("-0E12"),
1078 Decimal("10.0"), # negative exponent
1079 Decimal("-23.00000"),
1080 Decimal("1230E100"), # positive exponent
1081 Decimal("-4.5678E50"),
1082 # a value for which hash(n) != hash(n % (2**64-1))
1083 # in Python pre-2.6
1084 Decimal(2**64 + 2**32 - 1),
1085 # selection of values which fail with the old (before
1086 # version 2.6) long.__hash__
1087 Decimal("1.634E100"),
1088 Decimal("90.697E100"),
1089 Decimal("188.83E100"),
1090 Decimal("1652.9E100"),
1091 Decimal("56531E100"),
1092 ])
1093
1094 # check that hash(d) == hash(int(d)) for integral values
1095 for value in test_values:
1096 self.assertEqual(hash(value), hash(int(value)))
1097
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001098 #the same hash that to an int
1099 self.assertEqual(hash(Decimal(23)), hash(23))
Raymond Hettingerbea3f6f2005-03-15 04:59:17 +00001100 self.assertRaises(TypeError, hash, Decimal('NaN'))
1101 self.assert_(hash(Decimal('Inf')))
1102 self.assert_(hash(Decimal('-Inf')))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001103
Facundo Batista52b25792008-01-08 12:25:20 +00001104 # check that the value of the hash doesn't depend on the
1105 # current context (issue #1757)
1106 c = getcontext()
1107 old_precision = c.prec
1108 x = Decimal("123456789.1")
1109
1110 c.prec = 6
1111 h1 = hash(x)
1112 c.prec = 10
1113 h2 = hash(x)
1114 c.prec = 16
1115 h3 = hash(x)
1116
1117 self.assertEqual(h1, h2)
1118 self.assertEqual(h1, h3)
1119 c.prec = old_precision
1120
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001121 def test_min_and_max_methods(self):
1122
1123 d1 = Decimal('15.32')
1124 d2 = Decimal('28.5')
1125 l1 = 15
1126 l2 = 28
1127
1128 #between Decimals
1129 self.failUnless(min(d1,d2) is d1)
1130 self.failUnless(min(d2,d1) is d1)
1131 self.failUnless(max(d1,d2) is d2)
1132 self.failUnless(max(d2,d1) is d2)
1133
1134 #between Decimal and long
1135 self.failUnless(min(d1,l2) is d1)
1136 self.failUnless(min(l2,d1) is d1)
1137 self.failUnless(max(l1,d2) is d2)
1138 self.failUnless(max(d2,l1) is d2)
1139
1140 def test_as_nonzero(self):
1141 #as false
1142 self.failIf(Decimal(0))
1143 #as true
1144 self.failUnless(Decimal('0.372'))
1145
1146 def test_tostring_methods(self):
1147 #Test str and repr methods.
1148
1149 d = Decimal('15.32')
1150 self.assertEqual(str(d), '15.32') # str
Raymond Hettingerabe32372008-02-14 02:41:22 +00001151 self.assertEqual(repr(d), "Decimal('15.32')") # repr
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001152
Mark Dickinson8e85ffa2008-03-25 18:47:59 +00001153 # result type of string methods should be str, not unicode
1154 unicode_inputs = [u'123.4', u'0.5E2', u'Infinity', u'sNaN',
1155 u'-0.0E100', u'-NaN001', u'-Inf']
1156
1157 for u in unicode_inputs:
1158 d = Decimal(u)
1159 self.assertEqual(type(str(d)), str)
1160 self.assertEqual(type(repr(d)), str)
1161 self.assertEqual(type(d.to_eng_string()), str)
1162
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001163 def test_tonum_methods(self):
1164 #Test float, int and long methods.
1165
1166 d1 = Decimal('66')
1167 d2 = Decimal('15.32')
1168
1169 #int
1170 self.assertEqual(int(d1), 66)
1171 self.assertEqual(int(d2), 15)
1172
1173 #long
1174 self.assertEqual(long(d1), 66)
1175 self.assertEqual(long(d2), 15)
1176
1177 #float
1178 self.assertEqual(float(d1), 66)
1179 self.assertEqual(float(d2), 15.32)
1180
1181 def test_eval_round_trip(self):
1182
1183 #with zero
1184 d = Decimal( (0, (0,), 0) )
1185 self.assertEqual(d, eval(repr(d)))
1186
1187 #int
1188 d = Decimal( (1, (4, 5), 0) )
1189 self.assertEqual(d, eval(repr(d)))
1190
1191 #float
1192 d = Decimal( (0, (4, 5, 3, 4), -2) )
1193 self.assertEqual(d, eval(repr(d)))
1194
1195 #weird
1196 d = Decimal( (1, (4, 3, 4, 9, 1, 3, 5, 3, 4), -25) )
1197 self.assertEqual(d, eval(repr(d)))
1198
1199 def test_as_tuple(self):
1200
1201 #with zero
1202 d = Decimal(0)
1203 self.assertEqual(d.as_tuple(), (0, (0,), 0) )
1204
1205 #int
1206 d = Decimal(-45)
1207 self.assertEqual(d.as_tuple(), (1, (4, 5), 0) )
1208
1209 #complicated string
1210 d = Decimal("-4.34913534E-17")
1211 self.assertEqual(d.as_tuple(), (1, (4, 3, 4, 9, 1, 3, 5, 3, 4), -25) )
1212
1213 #inf
1214 d = Decimal("Infinity")
1215 self.assertEqual(d.as_tuple(), (0, (0,), 'F') )
1216
Facundo Batista9b5e2312007-10-19 19:25:57 +00001217 #leading zeros in coefficient should be stripped
1218 d = Decimal( (0, (0, 0, 4, 0, 5, 3, 4), -2) )
1219 self.assertEqual(d.as_tuple(), (0, (4, 0, 5, 3, 4), -2) )
1220 d = Decimal( (1, (0, 0, 0), 37) )
1221 self.assertEqual(d.as_tuple(), (1, (0,), 37))
1222 d = Decimal( (1, (), 37) )
1223 self.assertEqual(d.as_tuple(), (1, (0,), 37))
1224
1225 #leading zeros in NaN diagnostic info should be stripped
1226 d = Decimal( (0, (0, 0, 4, 0, 5, 3, 4), 'n') )
1227 self.assertEqual(d.as_tuple(), (0, (4, 0, 5, 3, 4), 'n') )
1228 d = Decimal( (1, (0, 0, 0), 'N') )
1229 self.assertEqual(d.as_tuple(), (1, (), 'N') )
1230 d = Decimal( (1, (), 'n') )
1231 self.assertEqual(d.as_tuple(), (1, (), 'n') )
1232
1233 #coefficient in infinity should be ignored
1234 d = Decimal( (0, (4, 5, 3, 4), 'F') )
1235 self.assertEqual(d.as_tuple(), (0, (0,), 'F'))
1236 d = Decimal( (1, (0, 2, 7, 1), 'F') )
1237 self.assertEqual(d.as_tuple(), (1, (0,), 'F'))
1238
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001239 def test_immutability_operations(self):
1240 # Do operations and check that it didn't change change internal objects.
1241
1242 d1 = Decimal('-25e55')
1243 b1 = Decimal('-25e55')
Facundo Batista353750c2007-09-13 18:13:15 +00001244 d2 = Decimal('33e+33')
1245 b2 = Decimal('33e+33')
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001246
1247 def checkSameDec(operation, useOther=False):
1248 if useOther:
1249 eval("d1." + operation + "(d2)")
1250 self.assertEqual(d1._sign, b1._sign)
1251 self.assertEqual(d1._int, b1._int)
1252 self.assertEqual(d1._exp, b1._exp)
1253 self.assertEqual(d2._sign, b2._sign)
1254 self.assertEqual(d2._int, b2._int)
1255 self.assertEqual(d2._exp, b2._exp)
1256 else:
1257 eval("d1." + operation + "()")
1258 self.assertEqual(d1._sign, b1._sign)
1259 self.assertEqual(d1._int, b1._int)
1260 self.assertEqual(d1._exp, b1._exp)
1261 return
1262
1263 Decimal(d1)
1264 self.assertEqual(d1._sign, b1._sign)
1265 self.assertEqual(d1._int, b1._int)
1266 self.assertEqual(d1._exp, b1._exp)
1267
1268 checkSameDec("__abs__")
1269 checkSameDec("__add__", True)
1270 checkSameDec("__div__", True)
1271 checkSameDec("__divmod__", True)
Mark Dickinson2fc92632008-02-06 22:10:50 +00001272 checkSameDec("__eq__", True)
1273 checkSameDec("__ne__", True)
1274 checkSameDec("__le__", True)
1275 checkSameDec("__lt__", True)
1276 checkSameDec("__ge__", True)
1277 checkSameDec("__gt__", True)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001278 checkSameDec("__float__")
1279 checkSameDec("__floordiv__", True)
1280 checkSameDec("__hash__")
1281 checkSameDec("__int__")
Raymond Hettinger5a053642008-01-24 19:05:29 +00001282 checkSameDec("__trunc__")
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001283 checkSameDec("__long__")
1284 checkSameDec("__mod__", True)
1285 checkSameDec("__mul__", True)
1286 checkSameDec("__neg__")
1287 checkSameDec("__nonzero__")
1288 checkSameDec("__pos__")
1289 checkSameDec("__pow__", True)
1290 checkSameDec("__radd__", True)
1291 checkSameDec("__rdiv__", True)
1292 checkSameDec("__rdivmod__", True)
1293 checkSameDec("__repr__")
1294 checkSameDec("__rfloordiv__", True)
1295 checkSameDec("__rmod__", True)
1296 checkSameDec("__rmul__", True)
1297 checkSameDec("__rpow__", True)
1298 checkSameDec("__rsub__", True)
1299 checkSameDec("__str__")
1300 checkSameDec("__sub__", True)
1301 checkSameDec("__truediv__", True)
1302 checkSameDec("adjusted")
1303 checkSameDec("as_tuple")
1304 checkSameDec("compare", True)
1305 checkSameDec("max", True)
1306 checkSameDec("min", True)
1307 checkSameDec("normalize")
1308 checkSameDec("quantize", True)
1309 checkSameDec("remainder_near", True)
1310 checkSameDec("same_quantum", True)
1311 checkSameDec("sqrt")
1312 checkSameDec("to_eng_string")
1313 checkSameDec("to_integral")
1314
Facundo Batista6c398da2007-09-17 17:30:13 +00001315 def test_subclassing(self):
1316 # Different behaviours when subclassing Decimal
1317
1318 class MyDecimal(Decimal):
1319 pass
1320
1321 d1 = MyDecimal(1)
1322 d2 = MyDecimal(2)
1323 d = d1 + d2
1324 self.assertTrue(type(d) is Decimal)
1325
1326 d = d1.max(d2)
1327 self.assertTrue(type(d) is Decimal)
1328
Mark Dickinson3b24ccb2008-03-25 14:33:23 +00001329 def test_implicit_context(self):
1330 # Check results when context given implicitly. (Issue 2478)
1331 c = getcontext()
1332 self.assertEqual(str(Decimal(0).sqrt()),
1333 str(c.sqrt(Decimal(0))))
1334
Facundo Batista6c398da2007-09-17 17:30:13 +00001335
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001336class DecimalPythonAPItests(unittest.TestCase):
1337
1338 def test_pickle(self):
1339 d = Decimal('-3.141590000')
1340 p = pickle.dumps(d)
1341 e = pickle.loads(p)
1342 self.assertEqual(d, e)
1343
Raymond Hettinger5548be22004-07-05 18:49:38 +00001344 def test_int(self):
Raymond Hettinger605ed022004-11-24 07:28:48 +00001345 for x in range(-250, 250):
1346 s = '%0.2f' % (x / 100.0)
Raymond Hettinger5548be22004-07-05 18:49:38 +00001347 # should work the same as for floats
1348 self.assertEqual(int(Decimal(s)), int(float(s)))
Raymond Hettinger605ed022004-11-24 07:28:48 +00001349 # should work the same as to_integral in the ROUND_DOWN mode
Raymond Hettinger5548be22004-07-05 18:49:38 +00001350 d = Decimal(s)
Raymond Hettinger605ed022004-11-24 07:28:48 +00001351 r = d.to_integral(ROUND_DOWN)
Raymond Hettinger5548be22004-07-05 18:49:38 +00001352 self.assertEqual(Decimal(int(d)), r)
1353
Raymond Hettinger5a053642008-01-24 19:05:29 +00001354 def test_trunc(self):
1355 for x in range(-250, 250):
1356 s = '%0.2f' % (x / 100.0)
1357 # should work the same as for floats
1358 self.assertEqual(int(Decimal(s)), int(float(s)))
1359 # should work the same as to_integral in the ROUND_DOWN mode
1360 d = Decimal(s)
1361 r = d.to_integral(ROUND_DOWN)
Jeffrey Yasskinca2b69f2008-02-01 06:22:46 +00001362 self.assertEqual(Decimal(math.trunc(d)), r)
Raymond Hettinger5a053642008-01-24 19:05:29 +00001363
Raymond Hettingerd9c0a7a2004-07-03 10:02:28 +00001364class ContextAPItests(unittest.TestCase):
1365
1366 def test_pickle(self):
1367 c = Context()
1368 e = pickle.loads(pickle.dumps(c))
1369 for k in vars(c):
1370 v1 = vars(c)[k]
1371 v2 = vars(e)[k]
1372 self.assertEqual(v1, v2)
1373
Raymond Hettinger0aeac102004-07-05 22:53:03 +00001374 def test_equality_with_other_types(self):
1375 self.assert_(Decimal(10) in ['a', 1.0, Decimal(10), (1,2), {}])
1376 self.assert_(Decimal(10) not in ['a', 1.0, (1,2), {}])
1377
Raymond Hettinger955d2b22004-08-08 20:17:45 +00001378 def test_copy(self):
1379 # All copies should be deep
1380 c = Context()
1381 d = c.copy()
1382 self.assertNotEqual(id(c), id(d))
1383 self.assertNotEqual(id(c.flags), id(d.flags))
1384 self.assertNotEqual(id(c.traps), id(d.traps))
1385
Nick Coghlan8b6999b2006-08-31 12:00:43 +00001386class WithStatementTest(unittest.TestCase):
1387 # Can't do these as docstrings until Python 2.6
1388 # as doctest can't handle __future__ statements
Nick Coghlan8b6999b2006-08-31 12:00:43 +00001389
1390 def test_localcontext(self):
Nick Coghlanced12182006-09-02 03:54:17 +00001391 # Use a copy of the current context in the block
Nick Coghlan8b6999b2006-08-31 12:00:43 +00001392 orig_ctx = getcontext()
1393 with localcontext() as enter_ctx:
1394 set_ctx = getcontext()
1395 final_ctx = getcontext()
1396 self.assert_(orig_ctx is final_ctx, 'did not restore context correctly')
1397 self.assert_(orig_ctx is not set_ctx, 'did not copy the context')
1398 self.assert_(set_ctx is enter_ctx, '__enter__ returned wrong context')
1399
1400 def test_localcontextarg(self):
Nick Coghlanced12182006-09-02 03:54:17 +00001401 # Use a copy of the supplied context in the block
Nick Coghlan8b6999b2006-08-31 12:00:43 +00001402 orig_ctx = getcontext()
1403 new_ctx = Context(prec=42)
1404 with localcontext(new_ctx) as enter_ctx:
1405 set_ctx = getcontext()
1406 final_ctx = getcontext()
1407 self.assert_(orig_ctx is final_ctx, 'did not restore context correctly')
1408 self.assert_(set_ctx.prec == new_ctx.prec, 'did not set correct context')
1409 self.assert_(new_ctx is not set_ctx, 'did not copy the context')
1410 self.assert_(set_ctx is enter_ctx, '__enter__ returned wrong context')
1411
Facundo Batista353750c2007-09-13 18:13:15 +00001412class ContextFlags(unittest.TestCase):
1413 def test_flags_irrelevant(self):
1414 # check that the result (numeric result + flags raised) of an
1415 # arithmetic operation doesn't depend on the current flags
1416
1417 context = Context(prec=9, Emin = -999999999, Emax = 999999999,
1418 rounding=ROUND_HALF_EVEN, traps=[], flags=[])
1419
1420 # operations that raise various flags, in the form (function, arglist)
1421 operations = [
1422 (context._apply, [Decimal("100E-1000000009")]),
1423 (context.sqrt, [Decimal(2)]),
1424 (context.add, [Decimal("1.23456789"), Decimal("9.87654321")]),
1425 (context.multiply, [Decimal("1.23456789"), Decimal("9.87654321")]),
1426 (context.subtract, [Decimal("1.23456789"), Decimal("9.87654321")]),
1427 ]
1428
1429 # try various flags individually, then a whole lot at once
1430 flagsets = [[Inexact], [Rounded], [Underflow], [Clamped], [Subnormal],
1431 [Inexact, Rounded, Underflow, Clamped, Subnormal]]
1432
1433 for fn, args in operations:
1434 # find answer and flags raised using a clean context
1435 context.clear_flags()
1436 ans = fn(*args)
1437 flags = [k for k, v in context.flags.items() if v]
1438
1439 for extra_flags in flagsets:
1440 # set flags, before calling operation
1441 context.clear_flags()
1442 for flag in extra_flags:
1443 context._raise_error(flag)
1444 new_ans = fn(*args)
1445
1446 # flags that we expect to be set after the operation
1447 expected_flags = list(flags)
1448 for flag in extra_flags:
1449 if flag not in expected_flags:
1450 expected_flags.append(flag)
1451 expected_flags.sort()
1452
1453 # flags we actually got
1454 new_flags = [k for k,v in context.flags.items() if v]
1455 new_flags.sort()
1456
1457 self.assertEqual(ans, new_ans,
1458 "operation produces different answers depending on flags set: " +
1459 "expected %s, got %s." % (ans, new_ans))
1460 self.assertEqual(new_flags, expected_flags,
1461 "operation raises different flags depending on flags set: " +
1462 "expected %s, got %s" % (expected_flags, new_flags))
1463
1464def test_main(arith=False, verbose=None, todo_tests=None, debug=None):
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001465 """ Execute the tests.
1466
Raymond Hettingered20ad82004-09-04 20:09:13 +00001467 Runs all arithmetic tests if arith is True or if the "decimal" resource
1468 is enabled in regrtest.py
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001469 """
Raymond Hettingered20ad82004-09-04 20:09:13 +00001470
Neal Norwitzce4a9c92006-04-09 08:36:46 +00001471 init()
Facundo Batista353750c2007-09-13 18:13:15 +00001472 global TEST_ALL, DEBUG
Raymond Hettingered20ad82004-09-04 20:09:13 +00001473 TEST_ALL = arith or is_resource_enabled('decimal')
Facundo Batista353750c2007-09-13 18:13:15 +00001474 DEBUG = debug
Raymond Hettingered20ad82004-09-04 20:09:13 +00001475
Facundo Batista353750c2007-09-13 18:13:15 +00001476 if todo_tests is None:
1477 test_classes = [
1478 DecimalExplicitConstructionTest,
1479 DecimalImplicitConstructionTest,
1480 DecimalArithmeticOperatorsTest,
Mark Dickinson1ddf1d82008-02-29 02:16:37 +00001481 DecimalFormatTest,
Facundo Batista353750c2007-09-13 18:13:15 +00001482 DecimalUseOfContextTest,
1483 DecimalUsabilityTest,
1484 DecimalPythonAPItests,
1485 ContextAPItests,
1486 DecimalTest,
1487 WithStatementTest,
1488 ContextFlags
1489 ]
1490 else:
1491 test_classes = [DecimalTest]
1492
1493 # Dynamically build custom test definition for each file in the test
1494 # directory and add the definitions to the DecimalTest class. This
1495 # procedure insures that new files do not get skipped.
1496 for filename in os.listdir(directory):
1497 if '.decTest' not in filename or filename.startswith("."):
1498 continue
1499 head, tail = filename.split('.')
1500 if todo_tests is not None and head not in todo_tests:
1501 continue
1502 tester = lambda self, f=filename: self.eval_file(directory + f)
1503 setattr(DecimalTest, 'test_' + head, tester)
1504 del filename, head, tail, tester
1505
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001506
Tim Peters46cc7022006-03-31 04:11:16 +00001507 try:
1508 run_unittest(*test_classes)
Facundo Batista353750c2007-09-13 18:13:15 +00001509 if todo_tests is None:
1510 import decimal as DecimalModule
1511 run_doctest(DecimalModule, verbose)
Tim Peters46cc7022006-03-31 04:11:16 +00001512 finally:
1513 setcontext(ORIGINAL_CONTEXT)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001514
1515if __name__ == '__main__':
Facundo Batista353750c2007-09-13 18:13:15 +00001516 import optparse
1517 p = optparse.OptionParser("test_decimal.py [--debug] [{--skip | test1 [test2 [...]]}]")
1518 p.add_option('--debug', '-d', action='store_true', help='shows the test number and context before each test')
1519 p.add_option('--skip', '-s', action='store_true', help='skip over 90% of the arithmetic tests')
1520 (opt, args) = p.parse_args()
1521
1522 if opt.skip:
1523 test_main(arith=False, verbose=True)
1524 elif args:
1525 test_main(arith=True, verbose=True, todo_tests=args, debug=opt.debug)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001526 else:
Facundo Batista353750c2007-09-13 18:13:15 +00001527 test_main(arith=True, verbose=True)