blob: b0d120536f96c4b5af675807f8c3ec84f467777c [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()
49 DefaultContext.prec = 9
50 DefaultContext.rounding = ROUND_HALF_EVEN
51 DefaultContext.traps = dict.fromkeys(Signals, 0)
52 setcontext(DefaultContext)
Raymond Hettinger6ea48452004-07-03 12:26:21 +000053
Raymond Hettinger7c85fa42004-07-01 11:01:35 +000054TESTDATADIR = 'decimaltestdata'
Raymond Hettingerd9c0a7a2004-07-03 10:02:28 +000055if __name__ == '__main__':
56 file = sys.argv[0]
57else:
58 file = __file__
59testdir = os.path.dirname(file) or os.curdir
Raymond Hettinger267b8682005-03-27 10:47:39 +000060directory = testdir + os.sep + TESTDATADIR + os.sep
Raymond Hettinger7c85fa42004-07-01 11:01:35 +000061
Raymond Hettinger267b8682005-03-27 10:47:39 +000062skip_expected = not os.path.isdir(directory)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +000063
64# Make sure it actually raises errors when not expected and caught in flags
65# Slower, since it runs some things several times.
66EXTENDEDERRORTEST = False
67
Raymond Hettinger7c85fa42004-07-01 11:01:35 +000068#Map the test cases' error names to the actual errors
Raymond Hettinger7c85fa42004-07-01 11:01:35 +000069ErrorNames = {'clamped' : Clamped,
Raymond Hettinger5aa478b2004-07-09 10:02:53 +000070 'conversion_syntax' : InvalidOperation,
Raymond Hettinger7c85fa42004-07-01 11:01:35 +000071 'division_by_zero' : DivisionByZero,
Raymond Hettinger5aa478b2004-07-09 10:02:53 +000072 'division_impossible' : InvalidOperation,
73 'division_undefined' : InvalidOperation,
Raymond Hettinger7c85fa42004-07-01 11:01:35 +000074 'inexact' : Inexact,
Raymond Hettinger5aa478b2004-07-09 10:02:53 +000075 'invalid_context' : InvalidOperation,
Raymond Hettinger7c85fa42004-07-01 11:01:35 +000076 'invalid_operation' : InvalidOperation,
77 'overflow' : Overflow,
78 'rounded' : Rounded,
79 'subnormal' : Subnormal,
80 'underflow' : Underflow}
81
82
83def Nonfunction(*args):
84 """Doesn't do anything."""
85 return None
86
87RoundingDict = {'ceiling' : ROUND_CEILING, #Maps test-case names to roundings.
88 'down' : ROUND_DOWN,
89 'floor' : ROUND_FLOOR,
90 'half_down' : ROUND_HALF_DOWN,
91 'half_even' : ROUND_HALF_EVEN,
92 'half_up' : ROUND_HALF_UP,
Facundo Batista353750c2007-09-13 18:13:15 +000093 'up' : ROUND_UP,
94 '05up' : ROUND_05UP}
Raymond Hettinger7c85fa42004-07-01 11:01:35 +000095
96# Name adapter to be able to change the Decimal and Context
97# interface without changing the test files from Cowlishaw
Facundo Batista1a191df2007-10-02 17:01:24 +000098nameAdapter = {'and':'logical_and',
Raymond Hettinger7c85fa42004-07-01 11:01:35 +000099 'apply':'_apply',
Facundo Batista353750c2007-09-13 18:13:15 +0000100 'class':'number_class',
101 'comparesig':'compare_signal',
102 'comparetotal':'compare_total',
103 'comparetotmag':'compare_total_mag',
Facundo Batista353750c2007-09-13 18:13:15 +0000104 'copy':'copy_decimal',
Facundo Batista1a191df2007-10-02 17:01:24 +0000105 'copyabs':'copy_abs',
Facundo Batista353750c2007-09-13 18:13:15 +0000106 'copynegate':'copy_negate',
107 'copysign':'copy_sign',
Facundo Batista1a191df2007-10-02 17:01:24 +0000108 'divideint':'divide_int',
Facundo Batista353750c2007-09-13 18:13:15 +0000109 'invert':'logical_invert',
Facundo Batista1a191df2007-10-02 17:01:24 +0000110 'iscanonical':'is_canonical',
111 'isfinite':'is_finite',
112 'isinfinite':'is_infinite',
113 'isnan':'is_nan',
114 'isnormal':'is_normal',
115 'isqnan':'is_qnan',
116 'issigned':'is_signed',
117 'issnan':'is_snan',
118 'issubnormal':'is_subnormal',
119 'iszero':'is_zero',
Facundo Batista353750c2007-09-13 18:13:15 +0000120 'maxmag':'max_mag',
121 'minmag':'min_mag',
122 'nextminus':'next_minus',
123 'nextplus':'next_plus',
124 'nexttoward':'next_toward',
Facundo Batista1a191df2007-10-02 17:01:24 +0000125 'or':'logical_or',
Facundo Batista353750c2007-09-13 18:13:15 +0000126 'reduce':'normalize',
Facundo Batista1a191df2007-10-02 17:01:24 +0000127 'remaindernear':'remainder_near',
128 'samequantum':'same_quantum',
129 'squareroot':'sqrt',
130 'toeng':'to_eng_string',
131 'tointegral':'to_integral_value',
132 'tointegralx':'to_integral_exact',
133 'tosci':'to_sci_string',
134 'xor':'logical_xor',
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000135 }
136
Facundo Batista1a191df2007-10-02 17:01:24 +0000137# The following functions return True/False rather than a Decimal instance
138
139LOGICAL_FUNCTIONS = (
140 'is_canonical',
141 'is_finite',
142 'is_infinite',
143 'is_nan',
144 'is_normal',
145 'is_qnan',
146 'is_signed',
147 'is_snan',
148 'is_subnormal',
149 'is_zero',
150 'same_quantum',
151 )
152
Facundo Batista353750c2007-09-13 18:13:15 +0000153# For some operations (currently exp, ln, log10, power), the decNumber
154# reference implementation imposes additional restrictions on the
155# context and operands. These restrictions are not part of the
156# specification; however, the effect of these restrictions does show
157# up in some of the testcases. We skip testcases that violate these
158# restrictions, since Decimal behaves differently from decNumber for
159# these testcases so these testcases would otherwise fail.
160
161decNumberRestricted = ('power', 'ln', 'log10', 'exp')
162DEC_MAX_MATH = 999999
163def outside_decNumber_bounds(v, context):
164 if (context.prec > DEC_MAX_MATH or
165 context.Emax > DEC_MAX_MATH or
166 -context.Emin > DEC_MAX_MATH):
167 return True
168 if not v._is_special and v and (
169 len(v._int) > DEC_MAX_MATH or
170 v.adjusted() > DEC_MAX_MATH or
171 v.adjusted() < 1-2*DEC_MAX_MATH):
172 return True
173 return False
174
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000175class DecimalTest(unittest.TestCase):
176 """Class which tests the Decimal class against the test cases.
177
178 Changed for unittest.
179 """
180 def setUp(self):
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000181 self.context = Context()
Raymond Hettingerbf440692004-07-10 14:14:37 +0000182 for key in DefaultContext.traps.keys():
183 DefaultContext.traps[key] = 1
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
194 def tearDown(self):
195 """Cleaning up enviroment."""
196 # leaving context in original state
Raymond Hettingerbf440692004-07-10 14:14:37 +0000197 for key in DefaultContext.traps.keys():
198 DefaultContext.traps[key] = 0
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000199 return
200
201 def eval_file(self, file):
202 global skip_expected
203 if skip_expected:
204 raise TestSkipped
205 return
206 for line in open(file).xreadlines():
207 line = line.replace('\r\n', '').replace('\n', '')
Raymond Hettinger5aa478b2004-07-09 10:02:53 +0000208 #print line
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000209 try:
210 t = self.eval_line(line)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000211 except DecimalException, exception:
212 #Exception raised where there shoudn't have been one.
213 self.fail('Exception "'+exception.__class__.__name__ + '" raised on line '+line)
214
215 return
216
217 def eval_line(self, s):
218 if s.find(' -> ') >= 0 and s[:2] != '--' and not s.startswith(' --'):
219 s = (s.split('->')[0] + '->' +
220 s.split('->')[1].split('--')[0]).strip()
221 else:
222 s = s.split('--')[0].strip()
223
224 for ignore in self.ignore_list:
225 if s.find(ignore) >= 0:
226 #print s.split()[0], 'NotImplemented--', ignore
227 return
228 if not s:
229 return
230 elif ':' in s:
231 return self.eval_directive(s)
232 else:
233 return self.eval_equation(s)
234
235 def eval_directive(self, s):
236 funct, value = map(lambda x: x.strip().lower(), s.split(':'))
237 if funct == 'rounding':
238 value = RoundingDict[value]
239 else:
240 try:
241 value = int(value)
242 except ValueError:
243 pass
244
245 funct = self.ChangeDict.get(funct, Nonfunction)
246 funct(value)
247
248 def eval_equation(self, s):
249 #global DEFAULT_PRECISION
250 #print DEFAULT_PRECISION
Raymond Hettingered20ad82004-09-04 20:09:13 +0000251
252 if not TEST_ALL and random.random() < 0.90:
253 return
254
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000255 try:
256 Sides = s.split('->')
257 L = Sides[0].strip().split()
258 id = L[0]
Facundo Batista353750c2007-09-13 18:13:15 +0000259 if DEBUG:
260 print "Test ", id,
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000261 funct = L[1].lower()
262 valstemp = L[2:]
263 L = Sides[1].strip().split()
264 ans = L[0]
265 exceptions = L[1:]
266 except (TypeError, AttributeError, IndexError):
Raymond Hettingerd87ac8f2004-07-09 10:52:54 +0000267 raise InvalidOperation
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000268 def FixQuotes(val):
269 val = val.replace("''", 'SingleQuote').replace('""', 'DoubleQuote')
270 val = val.replace("'", '').replace('"', '')
271 val = val.replace('SingleQuote', "'").replace('DoubleQuote', '"')
272 return val
273 fname = nameAdapter.get(funct, funct)
274 if fname == 'rescale':
275 return
276 funct = getattr(self.context, fname)
277 vals = []
278 conglomerate = ''
279 quote = 0
280 theirexceptions = [ErrorNames[x.lower()] for x in exceptions]
281
Raymond Hettingerd9c0a7a2004-07-03 10:02:28 +0000282 for exception in Signals:
Raymond Hettingerbf440692004-07-10 14:14:37 +0000283 self.context.traps[exception] = 1 #Catch these bugs...
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000284 for exception in theirexceptions:
Raymond Hettingerbf440692004-07-10 14:14:37 +0000285 self.context.traps[exception] = 0
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000286 for i, val in enumerate(valstemp):
287 if val.count("'") % 2 == 1:
288 quote = 1 - quote
289 if quote:
290 conglomerate = conglomerate + ' ' + val
291 continue
292 else:
293 val = conglomerate + val
294 conglomerate = ''
295 v = FixQuotes(val)
296 if fname in ('to_sci_string', 'to_eng_string'):
297 if EXTENDEDERRORTEST:
298 for error in theirexceptions:
Raymond Hettingerbf440692004-07-10 14:14:37 +0000299 self.context.traps[error] = 1
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000300 try:
301 funct(self.context.create_decimal(v))
302 except error:
303 pass
Raymond Hettingerd9c0a7a2004-07-03 10:02:28 +0000304 except Signals, e:
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000305 self.fail("Raised %s in %s when %s disabled" % \
306 (e, s, error))
307 else:
308 self.fail("Did not raise %s in %s" % (error, s))
Raymond Hettingerbf440692004-07-10 14:14:37 +0000309 self.context.traps[error] = 0
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000310 v = self.context.create_decimal(v)
311 else:
Facundo Batista353750c2007-09-13 18:13:15 +0000312 v = Decimal(v, self.context)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000313 vals.append(v)
314
315 ans = FixQuotes(ans)
316
Facundo Batista353750c2007-09-13 18:13:15 +0000317 # skip tests that are related to bounds imposed in the decNumber
318 # reference implementation
319 if fname in decNumberRestricted:
320 if fname == 'power':
321 if not (vals[1]._isinteger() and
322 -1999999997 <= vals[1] <= 999999999):
323 if outside_decNumber_bounds(vals[0], self.context) or \
324 outside_decNumber_bounds(vals[1], self.context):
325 #print "Skipping test %s" % s
326 return
327 else:
328 if outside_decNumber_bounds(vals[0], self.context):
329 #print "Skipping test %s" % s
330 return
331
332
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000333 if EXTENDEDERRORTEST and fname not in ('to_sci_string', 'to_eng_string'):
334 for error in theirexceptions:
Raymond Hettingerbf440692004-07-10 14:14:37 +0000335 self.context.traps[error] = 1
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000336 try:
337 funct(*vals)
338 except error:
339 pass
Raymond Hettingerd9c0a7a2004-07-03 10:02:28 +0000340 except Signals, e:
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000341 self.fail("Raised %s in %s when %s disabled" % \
342 (e, s, error))
343 else:
344 self.fail("Did not raise %s in %s" % (error, s))
Raymond Hettingerbf440692004-07-10 14:14:37 +0000345 self.context.traps[error] = 0
Facundo Batista353750c2007-09-13 18:13:15 +0000346 if DEBUG:
347 print "--", self.context
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000348 try:
349 result = str(funct(*vals))
Facundo Batista1a191df2007-10-02 17:01:24 +0000350 if fname in LOGICAL_FUNCTIONS:
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000351 result = str(int(eval(result))) # 'True', 'False' -> '1', '0'
Raymond Hettingerd9c0a7a2004-07-03 10:02:28 +0000352 except Signals, error:
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000353 self.fail("Raised %s in %s" % (error, s))
354 except: #Catch any error long enough to state the test case.
355 print "ERROR:", s
356 raise
357
358 myexceptions = self.getexceptions()
Raymond Hettingerbf440692004-07-10 14:14:37 +0000359 self.context.clear_flags()
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000360
361 myexceptions.sort()
362 theirexceptions.sort()
363
364 self.assertEqual(result, ans,
365 'Incorrect answer for ' + s + ' -- got ' + result)
366 self.assertEqual(myexceptions, theirexceptions,
Facundo Batista353750c2007-09-13 18:13:15 +0000367 'Incorrect flags set in ' + s + ' -- got ' + str(myexceptions))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000368 return
369
370 def getexceptions(self):
Raymond Hettingerf63ba432004-08-17 05:42:09 +0000371 return [e for e in Signals if self.context.flags[e]]
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000372
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000373 def change_precision(self, prec):
374 self.context.prec = prec
375 def change_rounding_method(self, rounding):
376 self.context.rounding = rounding
377 def change_min_exponent(self, exp):
378 self.context.Emin = exp
379 def change_max_exponent(self, exp):
380 self.context.Emax = exp
381 def change_clamp(self, clamp):
382 self.context._clamp = clamp
383
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000384
385
386# The following classes test the behaviour of Decimal according to PEP 327
387
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000388class DecimalExplicitConstructionTest(unittest.TestCase):
389 '''Unit tests for Explicit Construction cases of Decimal.'''
390
391 def test_explicit_empty(self):
392 self.assertEqual(Decimal(), Decimal("0"))
393
394 def test_explicit_from_None(self):
395 self.assertRaises(TypeError, Decimal, None)
396
397 def test_explicit_from_int(self):
398
399 #positive
400 d = Decimal(45)
401 self.assertEqual(str(d), '45')
402
403 #very large positive
404 d = Decimal(500000123)
405 self.assertEqual(str(d), '500000123')
406
407 #negative
408 d = Decimal(-45)
409 self.assertEqual(str(d), '-45')
410
411 #zero
412 d = Decimal(0)
413 self.assertEqual(str(d), '0')
414
415 def test_explicit_from_string(self):
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000416
417 #empty
418 self.assertEqual(str(Decimal('')), 'NaN')
419
420 #int
421 self.assertEqual(str(Decimal('45')), '45')
422
423 #float
424 self.assertEqual(str(Decimal('45.34')), '45.34')
425
426 #engineer notation
427 self.assertEqual(str(Decimal('45e2')), '4.5E+3')
428
429 #just not a number
430 self.assertEqual(str(Decimal('ugly')), 'NaN')
431
Mark Dickinson59bc20b2008-01-12 01:56:00 +0000432 #leading and trailing whitespace permitted
433 self.assertEqual(str(Decimal('1.3E4 \n')), '1.3E+4')
434 self.assertEqual(str(Decimal(' -7.89')), '-7.89')
435
Mark Dickinson8e85ffa2008-03-25 18:47:59 +0000436 #unicode strings should be permitted
437 self.assertEqual(str(Decimal(u'0E-017')), '0E-17')
438 self.assertEqual(str(Decimal(u'45')), '45')
439 self.assertEqual(str(Decimal(u'-Inf')), '-Infinity')
440 self.assertEqual(str(Decimal(u'NaN123')), 'NaN123')
441
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000442 def test_explicit_from_tuples(self):
443
444 #zero
445 d = Decimal( (0, (0,), 0) )
446 self.assertEqual(str(d), '0')
447
448 #int
449 d = Decimal( (1, (4, 5), 0) )
450 self.assertEqual(str(d), '-45')
451
452 #float
453 d = Decimal( (0, (4, 5, 3, 4), -2) )
454 self.assertEqual(str(d), '45.34')
455
456 #weird
457 d = Decimal( (1, (4, 3, 4, 9, 1, 3, 5, 3, 4), -25) )
458 self.assertEqual(str(d), '-4.34913534E-17')
459
460 #wrong number of items
461 self.assertRaises(ValueError, Decimal, (1, (4, 3, 4, 9, 1)) )
462
463 #bad sign
464 self.assertRaises(ValueError, Decimal, (8, (4, 3, 4, 9, 1), 2) )
Facundo Batista9b5e2312007-10-19 19:25:57 +0000465 self.assertRaises(ValueError, Decimal, (0., (4, 3, 4, 9, 1), 2) )
466 self.assertRaises(ValueError, Decimal, (Decimal(1), (4, 3, 4, 9, 1), 2))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000467
468 #bad exp
469 self.assertRaises(ValueError, Decimal, (1, (4, 3, 4, 9, 1), 'wrong!') )
Facundo Batista9b5e2312007-10-19 19:25:57 +0000470 self.assertRaises(ValueError, Decimal, (1, (4, 3, 4, 9, 1), 0.) )
471 self.assertRaises(ValueError, Decimal, (1, (4, 3, 4, 9, 1), '1') )
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000472
473 #bad coefficients
474 self.assertRaises(ValueError, Decimal, (1, (4, 3, 4, None, 1), 2) )
475 self.assertRaises(ValueError, Decimal, (1, (4, -3, 4, 9, 1), 2) )
Facundo Batista9b5e2312007-10-19 19:25:57 +0000476 self.assertRaises(ValueError, Decimal, (1, (4, 10, 4, 9, 1), 2) )
Facundo Batista72bc54f2007-11-23 17:59:00 +0000477 self.assertRaises(ValueError, Decimal, (1, (4, 3, 4, 'a', 1), 2) )
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000478
479 def test_explicit_from_Decimal(self):
480
481 #positive
482 d = Decimal(45)
483 e = Decimal(d)
484 self.assertEqual(str(e), '45')
485 self.assertNotEqual(id(d), id(e))
486
487 #very large positive
488 d = Decimal(500000123)
489 e = Decimal(d)
490 self.assertEqual(str(e), '500000123')
491 self.assertNotEqual(id(d), id(e))
492
493 #negative
494 d = Decimal(-45)
495 e = Decimal(d)
496 self.assertEqual(str(e), '-45')
497 self.assertNotEqual(id(d), id(e))
498
499 #zero
500 d = Decimal(0)
501 e = Decimal(d)
502 self.assertEqual(str(e), '0')
503 self.assertNotEqual(id(d), id(e))
504
505 def test_explicit_context_create_decimal(self):
506
507 nc = copy.copy(getcontext())
508 nc.prec = 3
509
510 # empty
Raymond Hettingerfed52962004-07-14 15:41:57 +0000511 d = Decimal()
512 self.assertEqual(str(d), '0')
513 d = nc.create_decimal()
514 self.assertEqual(str(d), '0')
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000515
516 # from None
517 self.assertRaises(TypeError, nc.create_decimal, None)
518
519 # from int
520 d = nc.create_decimal(456)
521 self.failUnless(isinstance(d, Decimal))
522 self.assertEqual(nc.create_decimal(45678),
523 nc.create_decimal('457E+2'))
524
525 # from string
526 d = Decimal('456789')
527 self.assertEqual(str(d), '456789')
528 d = nc.create_decimal('456789')
529 self.assertEqual(str(d), '4.57E+5')
Mark Dickinson59bc20b2008-01-12 01:56:00 +0000530 # leading and trailing whitespace should result in a NaN;
531 # spaces are already checked in Cowlishaw's test-suite, so
532 # here we just check that a trailing newline results in a NaN
533 self.assertEqual(str(nc.create_decimal('3.14\n')), 'NaN')
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000534
535 # from tuples
536 d = Decimal( (1, (4, 3, 4, 9, 1, 3, 5, 3, 4), -25) )
537 self.assertEqual(str(d), '-4.34913534E-17')
538 d = nc.create_decimal( (1, (4, 3, 4, 9, 1, 3, 5, 3, 4), -25) )
539 self.assertEqual(str(d), '-4.35E-17')
540
541 # from Decimal
542 prevdec = Decimal(500000123)
543 d = Decimal(prevdec)
544 self.assertEqual(str(d), '500000123')
545 d = nc.create_decimal(prevdec)
546 self.assertEqual(str(d), '5.00E+8')
547
548
549class DecimalImplicitConstructionTest(unittest.TestCase):
550 '''Unit tests for Implicit Construction cases of Decimal.'''
551
552 def test_implicit_from_None(self):
553 self.assertRaises(TypeError, eval, 'Decimal(5) + None', globals())
554
555 def test_implicit_from_int(self):
556 #normal
557 self.assertEqual(str(Decimal(5) + 45), '50')
558 #exceeding precision
559 self.assertEqual(Decimal(5) + 123456789000, Decimal(123456789000))
560
561 def test_implicit_from_string(self):
562 self.assertRaises(TypeError, eval, 'Decimal(5) + "3"', globals())
563
564 def test_implicit_from_float(self):
565 self.assertRaises(TypeError, eval, 'Decimal(5) + 2.2', globals())
566
567 def test_implicit_from_Decimal(self):
568 self.assertEqual(Decimal(5) + Decimal(45), Decimal(50))
569
Raymond Hettinger267b8682005-03-27 10:47:39 +0000570 def test_rop(self):
571 # Allow other classes to be trained to interact with Decimals
572 class E:
573 def __divmod__(self, other):
574 return 'divmod ' + str(other)
575 def __rdivmod__(self, other):
576 return str(other) + ' rdivmod'
577 def __lt__(self, other):
578 return 'lt ' + str(other)
579 def __gt__(self, other):
580 return 'gt ' + str(other)
581 def __le__(self, other):
582 return 'le ' + str(other)
583 def __ge__(self, other):
584 return 'ge ' + str(other)
585 def __eq__(self, other):
586 return 'eq ' + str(other)
587 def __ne__(self, other):
588 return 'ne ' + str(other)
589
590 self.assertEqual(divmod(E(), Decimal(10)), 'divmod 10')
591 self.assertEqual(divmod(Decimal(10), E()), '10 rdivmod')
592 self.assertEqual(eval('Decimal(10) < E()'), 'gt 10')
593 self.assertEqual(eval('Decimal(10) > E()'), 'lt 10')
594 self.assertEqual(eval('Decimal(10) <= E()'), 'ge 10')
595 self.assertEqual(eval('Decimal(10) >= E()'), 'le 10')
596 self.assertEqual(eval('Decimal(10) == E()'), 'eq 10')
597 self.assertEqual(eval('Decimal(10) != E()'), 'ne 10')
598
599 # insert operator methods and then exercise them
Georg Brandl96c3f7f2006-03-28 08:06:35 +0000600 oplist = [
601 ('+', '__add__', '__radd__'),
602 ('-', '__sub__', '__rsub__'),
603 ('*', '__mul__', '__rmul__'),
604 ('%', '__mod__', '__rmod__'),
605 ('//', '__floordiv__', '__rfloordiv__'),
606 ('**', '__pow__', '__rpow__')
607 ]
608 if 1/2 == 0:
609 # testing with classic division, so add __div__
610 oplist.append(('/', '__div__', '__rdiv__'))
611 else:
612 # testing with -Qnew, so add __truediv__
613 oplist.append(('/', '__truediv__', '__rtruediv__'))
Anthony Baxter4ef3a232006-03-30 12:59:11 +0000614
Georg Brandl96c3f7f2006-03-28 08:06:35 +0000615 for sym, lop, rop in oplist:
Raymond Hettinger267b8682005-03-27 10:47:39 +0000616 setattr(E, lop, lambda self, other: 'str' + lop + str(other))
617 setattr(E, rop, lambda self, other: str(other) + rop + 'str')
618 self.assertEqual(eval('E()' + sym + 'Decimal(10)'),
619 'str' + lop + '10')
620 self.assertEqual(eval('Decimal(10)' + sym + 'E()'),
621 '10' + rop + 'str')
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000622
Mark Dickinson1ddf1d82008-02-29 02:16:37 +0000623class DecimalFormatTest(unittest.TestCase):
624 '''Unit tests for the format function.'''
625 def test_formatting(self):
626 # triples giving a format, a Decimal, and the expected result
627 test_values = [
628 ('e', '0E-15', '0e-15'),
629 ('e', '2.3E-15', '2.3e-15'),
630 ('e', '2.30E+2', '2.30e+2'), # preserve significant zeros
631 ('e', '2.30000E-15', '2.30000e-15'),
632 ('e', '1.23456789123456789e40', '1.23456789123456789e+40'),
633 ('e', '1.5', '1.5e+0'),
634 ('e', '0.15', '1.5e-1'),
635 ('e', '0.015', '1.5e-2'),
636 ('e', '0.0000000000015', '1.5e-12'),
637 ('e', '15.0', '1.50e+1'),
638 ('e', '-15', '-1.5e+1'),
639 ('e', '0', '0e+0'),
640 ('e', '0E1', '0e+1'),
641 ('e', '0.0', '0e-1'),
642 ('e', '0.00', '0e-2'),
643 ('.6e', '0E-15', '0.000000e-9'),
644 ('.6e', '0', '0.000000e+6'),
645 ('.6e', '9.999999', '9.999999e+0'),
646 ('.6e', '9.9999999', '1.000000e+1'),
647 ('.6e', '-1.23e5', '-1.230000e+5'),
648 ('.6e', '1.23456789e-3', '1.234568e-3'),
649 ('f', '0', '0'),
650 ('f', '0.0', '0.0'),
651 ('f', '0E-2', '0.00'),
652 ('f', '0.00E-8', '0.0000000000'),
653 ('f', '0E1', '0'), # loses exponent information
654 ('f', '3.2E1', '32'),
655 ('f', '3.2E2', '320'),
656 ('f', '3.20E2', '320'),
657 ('f', '3.200E2', '320.0'),
658 ('f', '3.2E-6', '0.0000032'),
659 ('.6f', '0E-15', '0.000000'), # all zeros treated equally
660 ('.6f', '0E1', '0.000000'),
661 ('.6f', '0', '0.000000'),
662 ('.0f', '0', '0'), # no decimal point
663 ('.0f', '0e-2', '0'),
664 ('.0f', '3.14159265', '3'),
665 ('.1f', '3.14159265', '3.1'),
666 ('.4f', '3.14159265', '3.1416'),
667 ('.6f', '3.14159265', '3.141593'),
668 ('.7f', '3.14159265', '3.1415926'), # round-half-even!
669 ('.8f', '3.14159265', '3.14159265'),
670 ('.9f', '3.14159265', '3.141592650'),
671
672 ('g', '0', '0'),
673 ('g', '0.0', '0.0'),
674 ('g', '0E1', '0e+1'),
675 ('G', '0E1', '0E+1'),
676 ('g', '0E-5', '0.00000'),
677 ('g', '0E-6', '0.000000'),
678 ('g', '0E-7', '0e-7'),
679 ('g', '-0E2', '-0e+2'),
680 ('.0g', '3.14159265', '3'), # 0 sig fig -> 1 sig fig
681 ('.1g', '3.14159265', '3'),
682 ('.2g', '3.14159265', '3.1'),
683 ('.5g', '3.14159265', '3.1416'),
684 ('.7g', '3.14159265', '3.141593'),
685 ('.8g', '3.14159265', '3.1415926'), # round-half-even!
686 ('.9g', '3.14159265', '3.14159265'),
687 ('.10g', '3.14159265', '3.14159265'), # don't pad
688
689 ('%', '0E1', '0%'),
690 ('%', '0E0', '0%'),
691 ('%', '0E-1', '0%'),
692 ('%', '0E-2', '0%'),
693 ('%', '0E-3', '0.0%'),
694 ('%', '0E-4', '0.00%'),
695
696 ('.3%', '0', '0.000%'), # all zeros treated equally
697 ('.3%', '0E10', '0.000%'),
698 ('.3%', '0E-10', '0.000%'),
699 ('.3%', '2.34', '234.000%'),
700 ('.3%', '1.234567', '123.457%'),
701 ('.0%', '1.23', '123%'),
702
703 ('e', 'NaN', 'NaN'),
704 ('f', '-NaN123', '-NaN123'),
705 ('+g', 'NaN456', '+NaN456'),
706 ('.3e', 'Inf', 'Infinity'),
707 ('.16f', '-Inf', '-Infinity'),
708 ('.0g', '-sNaN', '-sNaN'),
709
710 ('', '1.00', '1.00'),
711 ]
712 for fmt, d, result in test_values:
713 self.assertEqual(format(Decimal(d), fmt), result)
714
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000715class DecimalArithmeticOperatorsTest(unittest.TestCase):
716 '''Unit tests for all arithmetic operators, binary and unary.'''
717
718 def test_addition(self):
719
720 d1 = Decimal('-11.1')
721 d2 = Decimal('22.2')
722
723 #two Decimals
724 self.assertEqual(d1+d2, Decimal('11.1'))
725 self.assertEqual(d2+d1, Decimal('11.1'))
726
727 #with other type, left
728 c = d1 + 5
729 self.assertEqual(c, Decimal('-6.1'))
730 self.assertEqual(type(c), type(d1))
731
732 #with other type, right
733 c = 5 + d1
734 self.assertEqual(c, Decimal('-6.1'))
735 self.assertEqual(type(c), type(d1))
736
737 #inline with decimal
738 d1 += d2
739 self.assertEqual(d1, Decimal('11.1'))
740
741 #inline with other type
742 d1 += 5
743 self.assertEqual(d1, Decimal('16.1'))
744
745 def test_subtraction(self):
746
747 d1 = Decimal('-11.1')
748 d2 = Decimal('22.2')
749
750 #two Decimals
751 self.assertEqual(d1-d2, Decimal('-33.3'))
752 self.assertEqual(d2-d1, Decimal('33.3'))
753
754 #with other type, left
755 c = d1 - 5
756 self.assertEqual(c, Decimal('-16.1'))
757 self.assertEqual(type(c), type(d1))
758
759 #with other type, right
760 c = 5 - d1
761 self.assertEqual(c, Decimal('16.1'))
762 self.assertEqual(type(c), type(d1))
763
764 #inline with decimal
765 d1 -= d2
766 self.assertEqual(d1, Decimal('-33.3'))
767
768 #inline with other type
769 d1 -= 5
770 self.assertEqual(d1, Decimal('-38.3'))
771
772 def test_multiplication(self):
773
774 d1 = Decimal('-5')
775 d2 = Decimal('3')
776
777 #two Decimals
778 self.assertEqual(d1*d2, Decimal('-15'))
779 self.assertEqual(d2*d1, Decimal('-15'))
780
781 #with other type, left
782 c = d1 * 5
783 self.assertEqual(c, Decimal('-25'))
784 self.assertEqual(type(c), type(d1))
785
786 #with other type, right
787 c = 5 * d1
788 self.assertEqual(c, Decimal('-25'))
789 self.assertEqual(type(c), type(d1))
790
791 #inline with decimal
792 d1 *= d2
793 self.assertEqual(d1, Decimal('-15'))
794
795 #inline with other type
796 d1 *= 5
797 self.assertEqual(d1, Decimal('-75'))
798
799 def test_division(self):
800
801 d1 = Decimal('-5')
802 d2 = Decimal('2')
803
804 #two Decimals
805 self.assertEqual(d1/d2, Decimal('-2.5'))
806 self.assertEqual(d2/d1, Decimal('-0.4'))
807
808 #with other type, left
809 c = d1 / 4
810 self.assertEqual(c, Decimal('-1.25'))
811 self.assertEqual(type(c), type(d1))
812
813 #with other type, right
814 c = 4 / d1
815 self.assertEqual(c, Decimal('-0.8'))
816 self.assertEqual(type(c), type(d1))
817
818 #inline with decimal
819 d1 /= d2
820 self.assertEqual(d1, Decimal('-2.5'))
821
822 #inline with other type
823 d1 /= 4
824 self.assertEqual(d1, Decimal('-0.625'))
825
826 def test_floor_division(self):
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000827
828 d1 = Decimal('5')
829 d2 = Decimal('2')
830
831 #two Decimals
832 self.assertEqual(d1//d2, Decimal('2'))
833 self.assertEqual(d2//d1, Decimal('0'))
834
835 #with other type, left
836 c = d1 // 4
837 self.assertEqual(c, Decimal('1'))
838 self.assertEqual(type(c), type(d1))
839
840 #with other type, right
841 c = 7 // d1
842 self.assertEqual(c, Decimal('1'))
843 self.assertEqual(type(c), type(d1))
844
845 #inline with decimal
846 d1 //= d2
847 self.assertEqual(d1, Decimal('2'))
848
849 #inline with other type
850 d1 //= 2
851 self.assertEqual(d1, Decimal('1'))
852
853 def test_powering(self):
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000854
855 d1 = Decimal('5')
856 d2 = Decimal('2')
857
858 #two Decimals
859 self.assertEqual(d1**d2, Decimal('25'))
860 self.assertEqual(d2**d1, Decimal('32'))
861
862 #with other type, left
863 c = d1 ** 4
864 self.assertEqual(c, Decimal('625'))
865 self.assertEqual(type(c), type(d1))
866
867 #with other type, right
868 c = 7 ** d1
869 self.assertEqual(c, Decimal('16807'))
870 self.assertEqual(type(c), type(d1))
871
872 #inline with decimal
873 d1 **= d2
874 self.assertEqual(d1, Decimal('25'))
875
876 #inline with other type
877 d1 **= 4
878 self.assertEqual(d1, Decimal('390625'))
879
880 def test_module(self):
881
882 d1 = Decimal('5')
883 d2 = Decimal('2')
884
885 #two Decimals
886 self.assertEqual(d1%d2, Decimal('1'))
887 self.assertEqual(d2%d1, Decimal('2'))
888
889 #with other type, left
890 c = d1 % 4
891 self.assertEqual(c, Decimal('1'))
892 self.assertEqual(type(c), type(d1))
893
894 #with other type, right
895 c = 7 % d1
896 self.assertEqual(c, Decimal('2'))
897 self.assertEqual(type(c), type(d1))
898
899 #inline with decimal
900 d1 %= d2
901 self.assertEqual(d1, Decimal('1'))
902
903 #inline with other type
904 d1 %= 4
905 self.assertEqual(d1, Decimal('1'))
906
907 def test_floor_div_module(self):
908
909 d1 = Decimal('5')
910 d2 = Decimal('2')
911
912 #two Decimals
913 (p, q) = divmod(d1, d2)
914 self.assertEqual(p, Decimal('2'))
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, left
920 (p, q) = divmod(d1, 4)
921 self.assertEqual(p, Decimal('1'))
922 self.assertEqual(q, Decimal('1'))
923 self.assertEqual(type(p), type(d1))
924 self.assertEqual(type(q), type(d1))
925
926 #with other type, right
927 (p, q) = divmod(7, d1)
928 self.assertEqual(p, Decimal('1'))
929 self.assertEqual(q, Decimal('2'))
930 self.assertEqual(type(p), type(d1))
931 self.assertEqual(type(q), type(d1))
932
933 def test_unary_operators(self):
934 self.assertEqual(+Decimal(45), Decimal(+45)) # +
935 self.assertEqual(-Decimal(45), Decimal(-45)) # -
936 self.assertEqual(abs(Decimal(45)), abs(Decimal(-45))) # abs
937
Mark Dickinson2fc92632008-02-06 22:10:50 +0000938 def test_nan_comparisons(self):
939 n = Decimal('NaN')
940 s = Decimal('sNaN')
941 i = Decimal('Inf')
942 f = Decimal('2')
943 for x, y in [(n, n), (n, i), (i, n), (n, f), (f, n),
944 (s, n), (n, s), (s, i), (i, s), (s, f), (f, s), (s, s)]:
945 self.assert_(x != y)
946 self.assert_(not (x == y))
947 self.assert_(not (x < y))
948 self.assert_(not (x <= y))
949 self.assert_(not (x > y))
950 self.assert_(not (x >= y))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000951
952# The following are two functions used to test threading in the next class
953
954def thfunc1(cls):
955 d1 = Decimal(1)
956 d3 = Decimal(3)
Facundo Batista64156672008-03-22 02:45:37 +0000957 test1 = d1/d3
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000958 cls.synchro.wait()
Facundo Batista64156672008-03-22 02:45:37 +0000959 test2 = d1/d3
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000960 cls.finish1.set()
Facundo Batista64156672008-03-22 02:45:37 +0000961
962 cls.assertEqual(test1, Decimal('0.333333333'))
963 cls.assertEqual(test2, Decimal('0.333333333'))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000964 return
965
966def thfunc2(cls):
967 d1 = Decimal(1)
968 d3 = Decimal(3)
Facundo Batista64156672008-03-22 02:45:37 +0000969 test1 = d1/d3
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000970 thiscontext = getcontext()
971 thiscontext.prec = 18
Facundo Batista64156672008-03-22 02:45:37 +0000972 test2 = d1/d3
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000973 cls.synchro.set()
974 cls.finish2.set()
Facundo Batista64156672008-03-22 02:45:37 +0000975
976 cls.assertEqual(test1, Decimal('0.333333333'))
977 cls.assertEqual(test2, Decimal('0.333333333333333333'))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000978 return
979
980
981class DecimalUseOfContextTest(unittest.TestCase):
982 '''Unit tests for Use of Context cases in Decimal.'''
983
Raymond Hettinger7e71fa52004-12-18 19:07:19 +0000984 try:
985 import threading
986 except ImportError:
987 threading = None
988
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000989 # Take care executing this test from IDLE, there's an issue in threading
990 # that hangs IDLE and I couldn't find it
991
992 def test_threading(self):
993 #Test the "threading isolation" of a Context.
994
995 self.synchro = threading.Event()
996 self.finish1 = threading.Event()
997 self.finish2 = threading.Event()
998
999 th1 = threading.Thread(target=thfunc1, args=(self,))
1000 th2 = threading.Thread(target=thfunc2, args=(self,))
1001
1002 th1.start()
1003 th2.start()
1004
1005 self.finish1.wait()
Thomas Woutersb3e6e8c2007-09-19 17:27:29 +00001006 self.finish2.wait()
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001007 return
1008
Raymond Hettinger7e71fa52004-12-18 19:07:19 +00001009 if threading is None:
1010 del test_threading
1011
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001012
1013class DecimalUsabilityTest(unittest.TestCase):
1014 '''Unit tests for Usability cases of Decimal.'''
1015
1016 def test_comparison_operators(self):
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001017
1018 da = Decimal('23.42')
1019 db = Decimal('23.42')
1020 dc = Decimal('45')
1021
1022 #two Decimals
1023 self.failUnless(dc > da)
1024 self.failUnless(dc >= da)
1025 self.failUnless(da < dc)
1026 self.failUnless(da <= dc)
1027 self.failUnless(da == db)
1028 self.failUnless(da != dc)
1029 self.failUnless(da <= db)
1030 self.failUnless(da >= db)
1031 self.assertEqual(cmp(dc,da), 1)
1032 self.assertEqual(cmp(da,dc), -1)
1033 self.assertEqual(cmp(da,db), 0)
1034
1035 #a Decimal and an int
1036 self.failUnless(dc > 23)
1037 self.failUnless(23 < dc)
1038 self.failUnless(dc == 45)
1039 self.assertEqual(cmp(dc,23), 1)
1040 self.assertEqual(cmp(23,dc), -1)
1041 self.assertEqual(cmp(dc,45), 0)
1042
1043 #a Decimal and uncomparable
Raymond Hettinger0aeac102004-07-05 22:53:03 +00001044 self.assertNotEqual(da, 'ugly')
1045 self.assertNotEqual(da, 32.7)
1046 self.assertNotEqual(da, object())
1047 self.assertNotEqual(da, object)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001048
Raymond Hettinger0aeac102004-07-05 22:53:03 +00001049 # sortable
1050 a = map(Decimal, xrange(100))
1051 b = a[:]
1052 random.shuffle(a)
1053 a.sort()
1054 self.assertEqual(a, b)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001055
Facundo Batista353750c2007-09-13 18:13:15 +00001056 # with None
1057 self.assertFalse(Decimal(1) < None)
1058 self.assertTrue(Decimal(1) > None)
1059
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001060 def test_copy_and_deepcopy_methods(self):
1061 d = Decimal('43.24')
1062 c = copy.copy(d)
1063 self.assertEqual(id(c), id(d))
1064 dc = copy.deepcopy(d)
1065 self.assertEqual(id(dc), id(d))
1066
1067 def test_hash_method(self):
1068 #just that it's hashable
1069 hash(Decimal(23))
Facundo Batista8c202442007-09-19 17:53:25 +00001070
1071 test_values = [Decimal(sign*(2**m + n))
1072 for m in [0, 14, 15, 16, 17, 30, 31,
1073 32, 33, 62, 63, 64, 65, 66]
1074 for n in range(-10, 10)
1075 for sign in [-1, 1]]
1076 test_values.extend([
1077 Decimal("-0"), # zeros
1078 Decimal("0.00"),
1079 Decimal("-0.000"),
1080 Decimal("0E10"),
1081 Decimal("-0E12"),
1082 Decimal("10.0"), # negative exponent
1083 Decimal("-23.00000"),
1084 Decimal("1230E100"), # positive exponent
1085 Decimal("-4.5678E50"),
1086 # a value for which hash(n) != hash(n % (2**64-1))
1087 # in Python pre-2.6
1088 Decimal(2**64 + 2**32 - 1),
1089 # selection of values which fail with the old (before
1090 # version 2.6) long.__hash__
1091 Decimal("1.634E100"),
1092 Decimal("90.697E100"),
1093 Decimal("188.83E100"),
1094 Decimal("1652.9E100"),
1095 Decimal("56531E100"),
1096 ])
1097
1098 # check that hash(d) == hash(int(d)) for integral values
1099 for value in test_values:
1100 self.assertEqual(hash(value), hash(int(value)))
1101
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001102 #the same hash that to an int
1103 self.assertEqual(hash(Decimal(23)), hash(23))
Raymond Hettingerbea3f6f2005-03-15 04:59:17 +00001104 self.assertRaises(TypeError, hash, Decimal('NaN'))
1105 self.assert_(hash(Decimal('Inf')))
1106 self.assert_(hash(Decimal('-Inf')))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001107
Facundo Batista52b25792008-01-08 12:25:20 +00001108 # check that the value of the hash doesn't depend on the
1109 # current context (issue #1757)
1110 c = getcontext()
1111 old_precision = c.prec
1112 x = Decimal("123456789.1")
1113
1114 c.prec = 6
1115 h1 = hash(x)
1116 c.prec = 10
1117 h2 = hash(x)
1118 c.prec = 16
1119 h3 = hash(x)
1120
1121 self.assertEqual(h1, h2)
1122 self.assertEqual(h1, h3)
1123 c.prec = old_precision
1124
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001125 def test_min_and_max_methods(self):
1126
1127 d1 = Decimal('15.32')
1128 d2 = Decimal('28.5')
1129 l1 = 15
1130 l2 = 28
1131
1132 #between Decimals
1133 self.failUnless(min(d1,d2) is d1)
1134 self.failUnless(min(d2,d1) is d1)
1135 self.failUnless(max(d1,d2) is d2)
1136 self.failUnless(max(d2,d1) is d2)
1137
1138 #between Decimal and long
1139 self.failUnless(min(d1,l2) is d1)
1140 self.failUnless(min(l2,d1) is d1)
1141 self.failUnless(max(l1,d2) is d2)
1142 self.failUnless(max(d2,l1) is d2)
1143
1144 def test_as_nonzero(self):
1145 #as false
1146 self.failIf(Decimal(0))
1147 #as true
1148 self.failUnless(Decimal('0.372'))
1149
1150 def test_tostring_methods(self):
1151 #Test str and repr methods.
1152
1153 d = Decimal('15.32')
1154 self.assertEqual(str(d), '15.32') # str
Raymond Hettingerabe32372008-02-14 02:41:22 +00001155 self.assertEqual(repr(d), "Decimal('15.32')") # repr
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001156
Mark Dickinson8e85ffa2008-03-25 18:47:59 +00001157 # result type of string methods should be str, not unicode
1158 unicode_inputs = [u'123.4', u'0.5E2', u'Infinity', u'sNaN',
1159 u'-0.0E100', u'-NaN001', u'-Inf']
1160
1161 for u in unicode_inputs:
1162 d = Decimal(u)
1163 self.assertEqual(type(str(d)), str)
1164 self.assertEqual(type(repr(d)), str)
1165 self.assertEqual(type(d.to_eng_string()), str)
1166
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001167 def test_tonum_methods(self):
1168 #Test float, int and long methods.
1169
1170 d1 = Decimal('66')
1171 d2 = Decimal('15.32')
1172
1173 #int
1174 self.assertEqual(int(d1), 66)
1175 self.assertEqual(int(d2), 15)
1176
1177 #long
1178 self.assertEqual(long(d1), 66)
1179 self.assertEqual(long(d2), 15)
1180
1181 #float
1182 self.assertEqual(float(d1), 66)
1183 self.assertEqual(float(d2), 15.32)
1184
1185 def test_eval_round_trip(self):
1186
1187 #with zero
1188 d = Decimal( (0, (0,), 0) )
1189 self.assertEqual(d, eval(repr(d)))
1190
1191 #int
1192 d = Decimal( (1, (4, 5), 0) )
1193 self.assertEqual(d, eval(repr(d)))
1194
1195 #float
1196 d = Decimal( (0, (4, 5, 3, 4), -2) )
1197 self.assertEqual(d, eval(repr(d)))
1198
1199 #weird
1200 d = Decimal( (1, (4, 3, 4, 9, 1, 3, 5, 3, 4), -25) )
1201 self.assertEqual(d, eval(repr(d)))
1202
1203 def test_as_tuple(self):
1204
1205 #with zero
1206 d = Decimal(0)
1207 self.assertEqual(d.as_tuple(), (0, (0,), 0) )
1208
1209 #int
1210 d = Decimal(-45)
1211 self.assertEqual(d.as_tuple(), (1, (4, 5), 0) )
1212
1213 #complicated string
1214 d = Decimal("-4.34913534E-17")
1215 self.assertEqual(d.as_tuple(), (1, (4, 3, 4, 9, 1, 3, 5, 3, 4), -25) )
1216
1217 #inf
1218 d = Decimal("Infinity")
1219 self.assertEqual(d.as_tuple(), (0, (0,), 'F') )
1220
Facundo Batista9b5e2312007-10-19 19:25:57 +00001221 #leading zeros in coefficient should be stripped
1222 d = Decimal( (0, (0, 0, 4, 0, 5, 3, 4), -2) )
1223 self.assertEqual(d.as_tuple(), (0, (4, 0, 5, 3, 4), -2) )
1224 d = Decimal( (1, (0, 0, 0), 37) )
1225 self.assertEqual(d.as_tuple(), (1, (0,), 37))
1226 d = Decimal( (1, (), 37) )
1227 self.assertEqual(d.as_tuple(), (1, (0,), 37))
1228
1229 #leading zeros in NaN diagnostic info should be stripped
1230 d = Decimal( (0, (0, 0, 4, 0, 5, 3, 4), 'n') )
1231 self.assertEqual(d.as_tuple(), (0, (4, 0, 5, 3, 4), 'n') )
1232 d = Decimal( (1, (0, 0, 0), 'N') )
1233 self.assertEqual(d.as_tuple(), (1, (), 'N') )
1234 d = Decimal( (1, (), 'n') )
1235 self.assertEqual(d.as_tuple(), (1, (), 'n') )
1236
1237 #coefficient in infinity should be ignored
1238 d = Decimal( (0, (4, 5, 3, 4), 'F') )
1239 self.assertEqual(d.as_tuple(), (0, (0,), 'F'))
1240 d = Decimal( (1, (0, 2, 7, 1), 'F') )
1241 self.assertEqual(d.as_tuple(), (1, (0,), 'F'))
1242
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001243 def test_immutability_operations(self):
1244 # Do operations and check that it didn't change change internal objects.
1245
1246 d1 = Decimal('-25e55')
1247 b1 = Decimal('-25e55')
Facundo Batista353750c2007-09-13 18:13:15 +00001248 d2 = Decimal('33e+33')
1249 b2 = Decimal('33e+33')
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001250
1251 def checkSameDec(operation, useOther=False):
1252 if useOther:
1253 eval("d1." + operation + "(d2)")
1254 self.assertEqual(d1._sign, b1._sign)
1255 self.assertEqual(d1._int, b1._int)
1256 self.assertEqual(d1._exp, b1._exp)
1257 self.assertEqual(d2._sign, b2._sign)
1258 self.assertEqual(d2._int, b2._int)
1259 self.assertEqual(d2._exp, b2._exp)
1260 else:
1261 eval("d1." + operation + "()")
1262 self.assertEqual(d1._sign, b1._sign)
1263 self.assertEqual(d1._int, b1._int)
1264 self.assertEqual(d1._exp, b1._exp)
1265 return
1266
1267 Decimal(d1)
1268 self.assertEqual(d1._sign, b1._sign)
1269 self.assertEqual(d1._int, b1._int)
1270 self.assertEqual(d1._exp, b1._exp)
1271
1272 checkSameDec("__abs__")
1273 checkSameDec("__add__", True)
1274 checkSameDec("__div__", True)
1275 checkSameDec("__divmod__", True)
Mark Dickinson2fc92632008-02-06 22:10:50 +00001276 checkSameDec("__eq__", True)
1277 checkSameDec("__ne__", True)
1278 checkSameDec("__le__", True)
1279 checkSameDec("__lt__", True)
1280 checkSameDec("__ge__", True)
1281 checkSameDec("__gt__", True)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001282 checkSameDec("__float__")
1283 checkSameDec("__floordiv__", True)
1284 checkSameDec("__hash__")
1285 checkSameDec("__int__")
Raymond Hettinger5a053642008-01-24 19:05:29 +00001286 checkSameDec("__trunc__")
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001287 checkSameDec("__long__")
1288 checkSameDec("__mod__", True)
1289 checkSameDec("__mul__", True)
1290 checkSameDec("__neg__")
1291 checkSameDec("__nonzero__")
1292 checkSameDec("__pos__")
1293 checkSameDec("__pow__", True)
1294 checkSameDec("__radd__", True)
1295 checkSameDec("__rdiv__", True)
1296 checkSameDec("__rdivmod__", True)
1297 checkSameDec("__repr__")
1298 checkSameDec("__rfloordiv__", True)
1299 checkSameDec("__rmod__", True)
1300 checkSameDec("__rmul__", True)
1301 checkSameDec("__rpow__", True)
1302 checkSameDec("__rsub__", True)
1303 checkSameDec("__str__")
1304 checkSameDec("__sub__", True)
1305 checkSameDec("__truediv__", True)
1306 checkSameDec("adjusted")
1307 checkSameDec("as_tuple")
1308 checkSameDec("compare", True)
1309 checkSameDec("max", True)
1310 checkSameDec("min", True)
1311 checkSameDec("normalize")
1312 checkSameDec("quantize", True)
1313 checkSameDec("remainder_near", True)
1314 checkSameDec("same_quantum", True)
1315 checkSameDec("sqrt")
1316 checkSameDec("to_eng_string")
1317 checkSameDec("to_integral")
1318
Facundo Batista6c398da2007-09-17 17:30:13 +00001319 def test_subclassing(self):
1320 # Different behaviours when subclassing Decimal
1321
1322 class MyDecimal(Decimal):
1323 pass
1324
1325 d1 = MyDecimal(1)
1326 d2 = MyDecimal(2)
1327 d = d1 + d2
1328 self.assertTrue(type(d) is Decimal)
1329
1330 d = d1.max(d2)
1331 self.assertTrue(type(d) is Decimal)
1332
Mark Dickinson3b24ccb2008-03-25 14:33:23 +00001333 def test_implicit_context(self):
1334 # Check results when context given implicitly. (Issue 2478)
1335 c = getcontext()
1336 self.assertEqual(str(Decimal(0).sqrt()),
1337 str(c.sqrt(Decimal(0))))
1338
Facundo Batista6c398da2007-09-17 17:30:13 +00001339
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001340class DecimalPythonAPItests(unittest.TestCase):
1341
1342 def test_pickle(self):
1343 d = Decimal('-3.141590000')
1344 p = pickle.dumps(d)
1345 e = pickle.loads(p)
1346 self.assertEqual(d, e)
1347
Raymond Hettinger5548be22004-07-05 18:49:38 +00001348 def test_int(self):
Raymond Hettinger605ed022004-11-24 07:28:48 +00001349 for x in range(-250, 250):
1350 s = '%0.2f' % (x / 100.0)
Raymond Hettinger5548be22004-07-05 18:49:38 +00001351 # should work the same as for floats
1352 self.assertEqual(int(Decimal(s)), int(float(s)))
Raymond Hettinger605ed022004-11-24 07:28:48 +00001353 # should work the same as to_integral in the ROUND_DOWN mode
Raymond Hettinger5548be22004-07-05 18:49:38 +00001354 d = Decimal(s)
Raymond Hettinger605ed022004-11-24 07:28:48 +00001355 r = d.to_integral(ROUND_DOWN)
Raymond Hettinger5548be22004-07-05 18:49:38 +00001356 self.assertEqual(Decimal(int(d)), r)
1357
Raymond Hettinger5a053642008-01-24 19:05:29 +00001358 def test_trunc(self):
1359 for x in range(-250, 250):
1360 s = '%0.2f' % (x / 100.0)
1361 # should work the same as for floats
1362 self.assertEqual(int(Decimal(s)), int(float(s)))
1363 # should work the same as to_integral in the ROUND_DOWN mode
1364 d = Decimal(s)
1365 r = d.to_integral(ROUND_DOWN)
Jeffrey Yasskinca2b69f2008-02-01 06:22:46 +00001366 self.assertEqual(Decimal(math.trunc(d)), r)
Raymond Hettinger5a053642008-01-24 19:05:29 +00001367
Raymond Hettingerd9c0a7a2004-07-03 10:02:28 +00001368class ContextAPItests(unittest.TestCase):
1369
1370 def test_pickle(self):
1371 c = Context()
1372 e = pickle.loads(pickle.dumps(c))
1373 for k in vars(c):
1374 v1 = vars(c)[k]
1375 v2 = vars(e)[k]
1376 self.assertEqual(v1, v2)
1377
Raymond Hettinger0aeac102004-07-05 22:53:03 +00001378 def test_equality_with_other_types(self):
1379 self.assert_(Decimal(10) in ['a', 1.0, Decimal(10), (1,2), {}])
1380 self.assert_(Decimal(10) not in ['a', 1.0, (1,2), {}])
1381
Raymond Hettinger955d2b22004-08-08 20:17:45 +00001382 def test_copy(self):
1383 # All copies should be deep
1384 c = Context()
1385 d = c.copy()
1386 self.assertNotEqual(id(c), id(d))
1387 self.assertNotEqual(id(c.flags), id(d.flags))
1388 self.assertNotEqual(id(c.traps), id(d.traps))
1389
Nick Coghlan8b6999b2006-08-31 12:00:43 +00001390class WithStatementTest(unittest.TestCase):
1391 # Can't do these as docstrings until Python 2.6
1392 # as doctest can't handle __future__ statements
Nick Coghlan8b6999b2006-08-31 12:00:43 +00001393
1394 def test_localcontext(self):
Nick Coghlanced12182006-09-02 03:54:17 +00001395 # Use a copy of the current context in the block
Nick Coghlan8b6999b2006-08-31 12:00:43 +00001396 orig_ctx = getcontext()
1397 with localcontext() as enter_ctx:
1398 set_ctx = getcontext()
1399 final_ctx = getcontext()
1400 self.assert_(orig_ctx is final_ctx, 'did not restore context correctly')
1401 self.assert_(orig_ctx is not set_ctx, 'did not copy the context')
1402 self.assert_(set_ctx is enter_ctx, '__enter__ returned wrong context')
1403
1404 def test_localcontextarg(self):
Nick Coghlanced12182006-09-02 03:54:17 +00001405 # Use a copy of the supplied context in the block
Nick Coghlan8b6999b2006-08-31 12:00:43 +00001406 orig_ctx = getcontext()
1407 new_ctx = Context(prec=42)
1408 with localcontext(new_ctx) as enter_ctx:
1409 set_ctx = getcontext()
1410 final_ctx = getcontext()
1411 self.assert_(orig_ctx is final_ctx, 'did not restore context correctly')
1412 self.assert_(set_ctx.prec == new_ctx.prec, 'did not set correct context')
1413 self.assert_(new_ctx is not set_ctx, 'did not copy the context')
1414 self.assert_(set_ctx is enter_ctx, '__enter__ returned wrong context')
1415
Facundo Batista353750c2007-09-13 18:13:15 +00001416class ContextFlags(unittest.TestCase):
1417 def test_flags_irrelevant(self):
1418 # check that the result (numeric result + flags raised) of an
1419 # arithmetic operation doesn't depend on the current flags
1420
1421 context = Context(prec=9, Emin = -999999999, Emax = 999999999,
1422 rounding=ROUND_HALF_EVEN, traps=[], flags=[])
1423
1424 # operations that raise various flags, in the form (function, arglist)
1425 operations = [
1426 (context._apply, [Decimal("100E-1000000009")]),
1427 (context.sqrt, [Decimal(2)]),
1428 (context.add, [Decimal("1.23456789"), Decimal("9.87654321")]),
1429 (context.multiply, [Decimal("1.23456789"), Decimal("9.87654321")]),
1430 (context.subtract, [Decimal("1.23456789"), Decimal("9.87654321")]),
1431 ]
1432
1433 # try various flags individually, then a whole lot at once
1434 flagsets = [[Inexact], [Rounded], [Underflow], [Clamped], [Subnormal],
1435 [Inexact, Rounded, Underflow, Clamped, Subnormal]]
1436
1437 for fn, args in operations:
1438 # find answer and flags raised using a clean context
1439 context.clear_flags()
1440 ans = fn(*args)
1441 flags = [k for k, v in context.flags.items() if v]
1442
1443 for extra_flags in flagsets:
1444 # set flags, before calling operation
1445 context.clear_flags()
1446 for flag in extra_flags:
1447 context._raise_error(flag)
1448 new_ans = fn(*args)
1449
1450 # flags that we expect to be set after the operation
1451 expected_flags = list(flags)
1452 for flag in extra_flags:
1453 if flag not in expected_flags:
1454 expected_flags.append(flag)
1455 expected_flags.sort()
1456
1457 # flags we actually got
1458 new_flags = [k for k,v in context.flags.items() if v]
1459 new_flags.sort()
1460
1461 self.assertEqual(ans, new_ans,
1462 "operation produces different answers depending on flags set: " +
1463 "expected %s, got %s." % (ans, new_ans))
1464 self.assertEqual(new_flags, expected_flags,
1465 "operation raises different flags depending on flags set: " +
1466 "expected %s, got %s" % (expected_flags, new_flags))
1467
1468def test_main(arith=False, verbose=None, todo_tests=None, debug=None):
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001469 """ Execute the tests.
1470
Raymond Hettingered20ad82004-09-04 20:09:13 +00001471 Runs all arithmetic tests if arith is True or if the "decimal" resource
1472 is enabled in regrtest.py
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001473 """
Raymond Hettingered20ad82004-09-04 20:09:13 +00001474
Neal Norwitzce4a9c92006-04-09 08:36:46 +00001475 init()
Facundo Batista353750c2007-09-13 18:13:15 +00001476 global TEST_ALL, DEBUG
Raymond Hettingered20ad82004-09-04 20:09:13 +00001477 TEST_ALL = arith or is_resource_enabled('decimal')
Facundo Batista353750c2007-09-13 18:13:15 +00001478 DEBUG = debug
Raymond Hettingered20ad82004-09-04 20:09:13 +00001479
Facundo Batista353750c2007-09-13 18:13:15 +00001480 if todo_tests is None:
1481 test_classes = [
1482 DecimalExplicitConstructionTest,
1483 DecimalImplicitConstructionTest,
1484 DecimalArithmeticOperatorsTest,
Mark Dickinson1ddf1d82008-02-29 02:16:37 +00001485 DecimalFormatTest,
Facundo Batista353750c2007-09-13 18:13:15 +00001486 DecimalUseOfContextTest,
1487 DecimalUsabilityTest,
1488 DecimalPythonAPItests,
1489 ContextAPItests,
1490 DecimalTest,
1491 WithStatementTest,
1492 ContextFlags
1493 ]
1494 else:
1495 test_classes = [DecimalTest]
1496
1497 # Dynamically build custom test definition for each file in the test
1498 # directory and add the definitions to the DecimalTest class. This
1499 # procedure insures that new files do not get skipped.
1500 for filename in os.listdir(directory):
1501 if '.decTest' not in filename or filename.startswith("."):
1502 continue
1503 head, tail = filename.split('.')
1504 if todo_tests is not None and head not in todo_tests:
1505 continue
1506 tester = lambda self, f=filename: self.eval_file(directory + f)
1507 setattr(DecimalTest, 'test_' + head, tester)
1508 del filename, head, tail, tester
1509
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001510
Tim Peters46cc7022006-03-31 04:11:16 +00001511 try:
1512 run_unittest(*test_classes)
Facundo Batista353750c2007-09-13 18:13:15 +00001513 if todo_tests is None:
1514 import decimal as DecimalModule
1515 run_doctest(DecimalModule, verbose)
Tim Peters46cc7022006-03-31 04:11:16 +00001516 finally:
1517 setcontext(ORIGINAL_CONTEXT)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001518
1519if __name__ == '__main__':
Facundo Batista353750c2007-09-13 18:13:15 +00001520 import optparse
1521 p = optparse.OptionParser("test_decimal.py [--debug] [{--skip | test1 [test2 [...]]}]")
1522 p.add_option('--debug', '-d', action='store_true', help='shows the test number and context before each test')
1523 p.add_option('--skip', '-s', action='store_true', help='skip over 90% of the arithmetic tests')
1524 (opt, args) = p.parse_args()
1525
1526 if opt.skip:
1527 test_main(arith=False, verbose=True)
1528 elif args:
1529 test_main(arith=True, verbose=True, todo_tests=args, debug=opt.debug)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001530 else:
Facundo Batista353750c2007-09-13 18:13:15 +00001531 test_main(arith=True, verbose=True)