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