blob: e5f7f64fe09d62640d720d3bc55550e96fee7545 [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"""
Nick Coghlan8b6999b2006-08-31 12:00:43 +000026from __future__ import with_statement
Raymond Hettinger7c85fa42004-07-01 11:01:35 +000027
Raymond Hettinger7c85fa42004-07-01 11:01:35 +000028import glob
Jeffrey Yasskinca2b69f2008-02-01 06:22:46 +000029import math
Raymond Hettinger7c85fa42004-07-01 11:01:35 +000030import os, sys
31import pickle, copy
Jeffrey Yasskinca2b69f2008-02-01 06:22:46 +000032import unittest
Raymond Hettinger7c85fa42004-07-01 11:01:35 +000033from decimal import *
Tim Peters46cc7022006-03-31 04:11:16 +000034from test.test_support import (TestSkipped, run_unittest, run_doctest,
35 is_resource_enabled)
Raymond Hettinger0aeac102004-07-05 22:53:03 +000036import random
Raymond Hettinger7e71fa52004-12-18 19:07:19 +000037try:
38 import threading
39except ImportError:
40 threading = None
Raymond Hettinger7c85fa42004-07-01 11:01:35 +000041
Raymond Hettingerfed52962004-07-14 15:41:57 +000042# Useful Test Constant
43Signals = getcontext().flags.keys()
44
Tim Peters46cc7022006-03-31 04:11:16 +000045# Tests are built around these assumed context defaults.
46# test_main() restores the original context.
Neal Norwitzce4a9c92006-04-09 08:36:46 +000047def init():
48 global ORIGINAL_CONTEXT
49 ORIGINAL_CONTEXT = getcontext().copy()
50 DefaultContext.prec = 9
51 DefaultContext.rounding = ROUND_HALF_EVEN
52 DefaultContext.traps = dict.fromkeys(Signals, 0)
53 setcontext(DefaultContext)
Raymond Hettinger6ea48452004-07-03 12:26:21 +000054
Raymond Hettinger7c85fa42004-07-01 11:01:35 +000055TESTDATADIR = 'decimaltestdata'
Raymond Hettingerd9c0a7a2004-07-03 10:02:28 +000056if __name__ == '__main__':
57 file = sys.argv[0]
58else:
59 file = __file__
60testdir = os.path.dirname(file) or os.curdir
Raymond Hettinger267b8682005-03-27 10:47:39 +000061directory = testdir + os.sep + TESTDATADIR + os.sep
Raymond Hettinger7c85fa42004-07-01 11:01:35 +000062
Raymond Hettinger267b8682005-03-27 10:47:39 +000063skip_expected = not os.path.isdir(directory)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +000064
65# Make sure it actually raises errors when not expected and caught in flags
66# Slower, since it runs some things several times.
67EXTENDEDERRORTEST = False
68
Raymond Hettinger7c85fa42004-07-01 11:01:35 +000069#Map the test cases' error names to the actual errors
Raymond Hettinger7c85fa42004-07-01 11:01:35 +000070ErrorNames = {'clamped' : Clamped,
Raymond Hettinger5aa478b2004-07-09 10:02:53 +000071 'conversion_syntax' : InvalidOperation,
Raymond Hettinger7c85fa42004-07-01 11:01:35 +000072 'division_by_zero' : DivisionByZero,
Raymond Hettinger5aa478b2004-07-09 10:02:53 +000073 'division_impossible' : InvalidOperation,
74 'division_undefined' : InvalidOperation,
Raymond Hettinger7c85fa42004-07-01 11:01:35 +000075 'inexact' : Inexact,
Raymond Hettinger5aa478b2004-07-09 10:02:53 +000076 'invalid_context' : InvalidOperation,
Raymond Hettinger7c85fa42004-07-01 11:01:35 +000077 'invalid_operation' : InvalidOperation,
78 'overflow' : Overflow,
79 'rounded' : Rounded,
80 'subnormal' : Subnormal,
81 'underflow' : Underflow}
82
83
84def Nonfunction(*args):
85 """Doesn't do anything."""
86 return None
87
88RoundingDict = {'ceiling' : ROUND_CEILING, #Maps test-case names to roundings.
89 'down' : ROUND_DOWN,
90 'floor' : ROUND_FLOOR,
91 'half_down' : ROUND_HALF_DOWN,
92 'half_even' : ROUND_HALF_EVEN,
93 'half_up' : ROUND_HALF_UP,
Facundo Batista353750c2007-09-13 18:13:15 +000094 'up' : ROUND_UP,
95 '05up' : ROUND_05UP}
Raymond Hettinger7c85fa42004-07-01 11:01:35 +000096
97# Name adapter to be able to change the Decimal and Context
98# interface without changing the test files from Cowlishaw
Facundo Batista1a191df2007-10-02 17:01:24 +000099nameAdapter = {'and':'logical_and',
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000100 'apply':'_apply',
Facundo Batista353750c2007-09-13 18:13:15 +0000101 'class':'number_class',
102 'comparesig':'compare_signal',
103 'comparetotal':'compare_total',
104 'comparetotmag':'compare_total_mag',
Facundo Batista353750c2007-09-13 18:13:15 +0000105 'copy':'copy_decimal',
Facundo Batista1a191df2007-10-02 17:01:24 +0000106 'copyabs':'copy_abs',
Facundo Batista353750c2007-09-13 18:13:15 +0000107 'copynegate':'copy_negate',
108 'copysign':'copy_sign',
Facundo Batista1a191df2007-10-02 17:01:24 +0000109 'divideint':'divide_int',
Facundo Batista353750c2007-09-13 18:13:15 +0000110 'invert':'logical_invert',
Facundo Batista1a191df2007-10-02 17:01:24 +0000111 'iscanonical':'is_canonical',
112 'isfinite':'is_finite',
113 'isinfinite':'is_infinite',
114 'isnan':'is_nan',
115 'isnormal':'is_normal',
116 'isqnan':'is_qnan',
117 'issigned':'is_signed',
118 'issnan':'is_snan',
119 'issubnormal':'is_subnormal',
120 'iszero':'is_zero',
Facundo Batista353750c2007-09-13 18:13:15 +0000121 'maxmag':'max_mag',
122 'minmag':'min_mag',
123 'nextminus':'next_minus',
124 'nextplus':'next_plus',
125 'nexttoward':'next_toward',
Facundo Batista1a191df2007-10-02 17:01:24 +0000126 'or':'logical_or',
Facundo Batista353750c2007-09-13 18:13:15 +0000127 'reduce':'normalize',
Facundo Batista1a191df2007-10-02 17:01:24 +0000128 'remaindernear':'remainder_near',
129 'samequantum':'same_quantum',
130 'squareroot':'sqrt',
131 'toeng':'to_eng_string',
132 'tointegral':'to_integral_value',
133 'tointegralx':'to_integral_exact',
134 'tosci':'to_sci_string',
135 'xor':'logical_xor',
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000136 }
137
Facundo Batista1a191df2007-10-02 17:01:24 +0000138# The following functions return True/False rather than a Decimal instance
139
140LOGICAL_FUNCTIONS = (
141 'is_canonical',
142 'is_finite',
143 'is_infinite',
144 'is_nan',
145 'is_normal',
146 'is_qnan',
147 'is_signed',
148 'is_snan',
149 'is_subnormal',
150 'is_zero',
151 'same_quantum',
152 )
153
Facundo Batista353750c2007-09-13 18:13:15 +0000154# For some operations (currently exp, ln, log10, power), the decNumber
155# reference implementation imposes additional restrictions on the
156# context and operands. These restrictions are not part of the
157# specification; however, the effect of these restrictions does show
158# up in some of the testcases. We skip testcases that violate these
159# restrictions, since Decimal behaves differently from decNumber for
160# these testcases so these testcases would otherwise fail.
161
162decNumberRestricted = ('power', 'ln', 'log10', 'exp')
163DEC_MAX_MATH = 999999
164def outside_decNumber_bounds(v, context):
165 if (context.prec > DEC_MAX_MATH or
166 context.Emax > DEC_MAX_MATH or
167 -context.Emin > DEC_MAX_MATH):
168 return True
169 if not v._is_special and v and (
170 len(v._int) > DEC_MAX_MATH or
171 v.adjusted() > DEC_MAX_MATH or
172 v.adjusted() < 1-2*DEC_MAX_MATH):
173 return True
174 return False
175
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000176class DecimalTest(unittest.TestCase):
177 """Class which tests the Decimal class against the test cases.
178
179 Changed for unittest.
180 """
181 def setUp(self):
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000182 self.context = Context()
Raymond Hettingerbf440692004-07-10 14:14:37 +0000183 for key in DefaultContext.traps.keys():
184 DefaultContext.traps[key] = 1
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000185 self.ignore_list = ['#']
186 # Basically, a # means return NaN InvalidOperation.
187 # Different from a sNaN in trim
188
189 self.ChangeDict = {'precision' : self.change_precision,
190 'rounding' : self.change_rounding_method,
191 'maxexponent' : self.change_max_exponent,
192 'minexponent' : self.change_min_exponent,
193 'clamp' : self.change_clamp}
194
195 def tearDown(self):
196 """Cleaning up enviroment."""
197 # leaving context in original state
Raymond Hettingerbf440692004-07-10 14:14:37 +0000198 for key in DefaultContext.traps.keys():
199 DefaultContext.traps[key] = 0
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000200 return
201
202 def eval_file(self, file):
203 global skip_expected
204 if skip_expected:
205 raise TestSkipped
206 return
207 for line in open(file).xreadlines():
208 line = line.replace('\r\n', '').replace('\n', '')
Raymond Hettinger5aa478b2004-07-09 10:02:53 +0000209 #print line
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000210 try:
211 t = self.eval_line(line)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000212 except DecimalException, exception:
213 #Exception raised where there shoudn't have been one.
214 self.fail('Exception "'+exception.__class__.__name__ + '" raised on line '+line)
215
216 return
217
218 def eval_line(self, s):
219 if s.find(' -> ') >= 0 and s[:2] != '--' and not s.startswith(' --'):
220 s = (s.split('->')[0] + '->' +
221 s.split('->')[1].split('--')[0]).strip()
222 else:
223 s = s.split('--')[0].strip()
224
225 for ignore in self.ignore_list:
226 if s.find(ignore) >= 0:
227 #print s.split()[0], 'NotImplemented--', ignore
228 return
229 if not s:
230 return
231 elif ':' in s:
232 return self.eval_directive(s)
233 else:
234 return self.eval_equation(s)
235
236 def eval_directive(self, s):
237 funct, value = map(lambda x: x.strip().lower(), s.split(':'))
238 if funct == 'rounding':
239 value = RoundingDict[value]
240 else:
241 try:
242 value = int(value)
243 except ValueError:
244 pass
245
246 funct = self.ChangeDict.get(funct, Nonfunction)
247 funct(value)
248
249 def eval_equation(self, s):
250 #global DEFAULT_PRECISION
251 #print DEFAULT_PRECISION
Raymond Hettingered20ad82004-09-04 20:09:13 +0000252
253 if not TEST_ALL and random.random() < 0.90:
254 return
255
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000256 try:
257 Sides = s.split('->')
258 L = Sides[0].strip().split()
259 id = L[0]
Facundo Batista353750c2007-09-13 18:13:15 +0000260 if DEBUG:
261 print "Test ", id,
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000262 funct = L[1].lower()
263 valstemp = L[2:]
264 L = Sides[1].strip().split()
265 ans = L[0]
266 exceptions = L[1:]
267 except (TypeError, AttributeError, IndexError):
Raymond Hettingerd87ac8f2004-07-09 10:52:54 +0000268 raise InvalidOperation
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000269 def FixQuotes(val):
270 val = val.replace("''", 'SingleQuote').replace('""', 'DoubleQuote')
271 val = val.replace("'", '').replace('"', '')
272 val = val.replace('SingleQuote', "'").replace('DoubleQuote', '"')
273 return val
274 fname = nameAdapter.get(funct, funct)
275 if fname == 'rescale':
276 return
277 funct = getattr(self.context, fname)
278 vals = []
279 conglomerate = ''
280 quote = 0
281 theirexceptions = [ErrorNames[x.lower()] for x in exceptions]
282
Raymond Hettingerd9c0a7a2004-07-03 10:02:28 +0000283 for exception in Signals:
Raymond Hettingerbf440692004-07-10 14:14:37 +0000284 self.context.traps[exception] = 1 #Catch these bugs...
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000285 for exception in theirexceptions:
Raymond Hettingerbf440692004-07-10 14:14:37 +0000286 self.context.traps[exception] = 0
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000287 for i, val in enumerate(valstemp):
288 if val.count("'") % 2 == 1:
289 quote = 1 - quote
290 if quote:
291 conglomerate = conglomerate + ' ' + val
292 continue
293 else:
294 val = conglomerate + val
295 conglomerate = ''
296 v = FixQuotes(val)
297 if fname in ('to_sci_string', 'to_eng_string'):
298 if EXTENDEDERRORTEST:
299 for error in theirexceptions:
Raymond Hettingerbf440692004-07-10 14:14:37 +0000300 self.context.traps[error] = 1
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000301 try:
302 funct(self.context.create_decimal(v))
303 except error:
304 pass
Raymond Hettingerd9c0a7a2004-07-03 10:02:28 +0000305 except Signals, e:
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000306 self.fail("Raised %s in %s when %s disabled" % \
307 (e, s, error))
308 else:
309 self.fail("Did not raise %s in %s" % (error, s))
Raymond Hettingerbf440692004-07-10 14:14:37 +0000310 self.context.traps[error] = 0
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000311 v = self.context.create_decimal(v)
312 else:
Facundo Batista353750c2007-09-13 18:13:15 +0000313 v = Decimal(v, self.context)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000314 vals.append(v)
315
316 ans = FixQuotes(ans)
317
Facundo Batista353750c2007-09-13 18:13:15 +0000318 # skip tests that are related to bounds imposed in the decNumber
319 # reference implementation
320 if fname in decNumberRestricted:
321 if fname == 'power':
322 if not (vals[1]._isinteger() and
323 -1999999997 <= vals[1] <= 999999999):
324 if outside_decNumber_bounds(vals[0], self.context) or \
325 outside_decNumber_bounds(vals[1], self.context):
326 #print "Skipping test %s" % s
327 return
328 else:
329 if outside_decNumber_bounds(vals[0], self.context):
330 #print "Skipping test %s" % s
331 return
332
333
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000334 if EXTENDEDERRORTEST and fname not in ('to_sci_string', 'to_eng_string'):
335 for error in theirexceptions:
Raymond Hettingerbf440692004-07-10 14:14:37 +0000336 self.context.traps[error] = 1
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000337 try:
338 funct(*vals)
339 except error:
340 pass
Raymond Hettingerd9c0a7a2004-07-03 10:02:28 +0000341 except Signals, e:
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000342 self.fail("Raised %s in %s when %s disabled" % \
343 (e, s, error))
344 else:
345 self.fail("Did not raise %s in %s" % (error, s))
Raymond Hettingerbf440692004-07-10 14:14:37 +0000346 self.context.traps[error] = 0
Facundo Batista353750c2007-09-13 18:13:15 +0000347 if DEBUG:
348 print "--", self.context
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000349 try:
350 result = str(funct(*vals))
Facundo Batista1a191df2007-10-02 17:01:24 +0000351 if fname in LOGICAL_FUNCTIONS:
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000352 result = str(int(eval(result))) # 'True', 'False' -> '1', '0'
Raymond Hettingerd9c0a7a2004-07-03 10:02:28 +0000353 except Signals, error:
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000354 self.fail("Raised %s in %s" % (error, s))
355 except: #Catch any error long enough to state the test case.
356 print "ERROR:", s
357 raise
358
359 myexceptions = self.getexceptions()
Raymond Hettingerbf440692004-07-10 14:14:37 +0000360 self.context.clear_flags()
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000361
362 myexceptions.sort()
363 theirexceptions.sort()
364
365 self.assertEqual(result, ans,
366 'Incorrect answer for ' + s + ' -- got ' + result)
367 self.assertEqual(myexceptions, theirexceptions,
Facundo Batista353750c2007-09-13 18:13:15 +0000368 'Incorrect flags set in ' + s + ' -- got ' + str(myexceptions))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000369 return
370
371 def getexceptions(self):
Raymond Hettingerf63ba432004-08-17 05:42:09 +0000372 return [e for e in Signals if self.context.flags[e]]
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000373
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000374 def change_precision(self, prec):
375 self.context.prec = prec
376 def change_rounding_method(self, rounding):
377 self.context.rounding = rounding
378 def change_min_exponent(self, exp):
379 self.context.Emin = exp
380 def change_max_exponent(self, exp):
381 self.context.Emax = exp
382 def change_clamp(self, clamp):
383 self.context._clamp = clamp
384
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000385
386
387# The following classes test the behaviour of Decimal according to PEP 327
388
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000389class DecimalExplicitConstructionTest(unittest.TestCase):
390 '''Unit tests for Explicit Construction cases of Decimal.'''
391
392 def test_explicit_empty(self):
393 self.assertEqual(Decimal(), Decimal("0"))
394
395 def test_explicit_from_None(self):
396 self.assertRaises(TypeError, Decimal, None)
397
398 def test_explicit_from_int(self):
399
400 #positive
401 d = Decimal(45)
402 self.assertEqual(str(d), '45')
403
404 #very large positive
405 d = Decimal(500000123)
406 self.assertEqual(str(d), '500000123')
407
408 #negative
409 d = Decimal(-45)
410 self.assertEqual(str(d), '-45')
411
412 #zero
413 d = Decimal(0)
414 self.assertEqual(str(d), '0')
415
416 def test_explicit_from_string(self):
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000417
418 #empty
419 self.assertEqual(str(Decimal('')), 'NaN')
420
421 #int
422 self.assertEqual(str(Decimal('45')), '45')
423
424 #float
425 self.assertEqual(str(Decimal('45.34')), '45.34')
426
427 #engineer notation
428 self.assertEqual(str(Decimal('45e2')), '4.5E+3')
429
430 #just not a number
431 self.assertEqual(str(Decimal('ugly')), 'NaN')
432
Mark Dickinson59bc20b2008-01-12 01:56:00 +0000433 #leading and trailing whitespace permitted
434 self.assertEqual(str(Decimal('1.3E4 \n')), '1.3E+4')
435 self.assertEqual(str(Decimal(' -7.89')), '-7.89')
436
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000437 def test_explicit_from_tuples(self):
438
439 #zero
440 d = Decimal( (0, (0,), 0) )
441 self.assertEqual(str(d), '0')
442
443 #int
444 d = Decimal( (1, (4, 5), 0) )
445 self.assertEqual(str(d), '-45')
446
447 #float
448 d = Decimal( (0, (4, 5, 3, 4), -2) )
449 self.assertEqual(str(d), '45.34')
450
451 #weird
452 d = Decimal( (1, (4, 3, 4, 9, 1, 3, 5, 3, 4), -25) )
453 self.assertEqual(str(d), '-4.34913534E-17')
454
455 #wrong number of items
456 self.assertRaises(ValueError, Decimal, (1, (4, 3, 4, 9, 1)) )
457
458 #bad sign
459 self.assertRaises(ValueError, Decimal, (8, (4, 3, 4, 9, 1), 2) )
Facundo Batista9b5e2312007-10-19 19:25:57 +0000460 self.assertRaises(ValueError, Decimal, (0., (4, 3, 4, 9, 1), 2) )
461 self.assertRaises(ValueError, Decimal, (Decimal(1), (4, 3, 4, 9, 1), 2))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000462
463 #bad exp
464 self.assertRaises(ValueError, Decimal, (1, (4, 3, 4, 9, 1), 'wrong!') )
Facundo Batista9b5e2312007-10-19 19:25:57 +0000465 self.assertRaises(ValueError, Decimal, (1, (4, 3, 4, 9, 1), 0.) )
466 self.assertRaises(ValueError, Decimal, (1, (4, 3, 4, 9, 1), '1') )
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000467
468 #bad coefficients
469 self.assertRaises(ValueError, Decimal, (1, (4, 3, 4, None, 1), 2) )
470 self.assertRaises(ValueError, Decimal, (1, (4, -3, 4, 9, 1), 2) )
Facundo Batista9b5e2312007-10-19 19:25:57 +0000471 self.assertRaises(ValueError, Decimal, (1, (4, 10, 4, 9, 1), 2) )
Facundo Batista72bc54f2007-11-23 17:59:00 +0000472 self.assertRaises(ValueError, Decimal, (1, (4, 3, 4, 'a', 1), 2) )
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000473
474 def test_explicit_from_Decimal(self):
475
476 #positive
477 d = Decimal(45)
478 e = Decimal(d)
479 self.assertEqual(str(e), '45')
480 self.assertNotEqual(id(d), id(e))
481
482 #very large positive
483 d = Decimal(500000123)
484 e = Decimal(d)
485 self.assertEqual(str(e), '500000123')
486 self.assertNotEqual(id(d), id(e))
487
488 #negative
489 d = Decimal(-45)
490 e = Decimal(d)
491 self.assertEqual(str(e), '-45')
492 self.assertNotEqual(id(d), id(e))
493
494 #zero
495 d = Decimal(0)
496 e = Decimal(d)
497 self.assertEqual(str(e), '0')
498 self.assertNotEqual(id(d), id(e))
499
500 def test_explicit_context_create_decimal(self):
501
502 nc = copy.copy(getcontext())
503 nc.prec = 3
504
505 # empty
Raymond Hettingerfed52962004-07-14 15:41:57 +0000506 d = Decimal()
507 self.assertEqual(str(d), '0')
508 d = nc.create_decimal()
509 self.assertEqual(str(d), '0')
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000510
511 # from None
512 self.assertRaises(TypeError, nc.create_decimal, None)
513
514 # from int
515 d = nc.create_decimal(456)
516 self.failUnless(isinstance(d, Decimal))
517 self.assertEqual(nc.create_decimal(45678),
518 nc.create_decimal('457E+2'))
519
520 # from string
521 d = Decimal('456789')
522 self.assertEqual(str(d), '456789')
523 d = nc.create_decimal('456789')
524 self.assertEqual(str(d), '4.57E+5')
Mark Dickinson59bc20b2008-01-12 01:56:00 +0000525 # leading and trailing whitespace should result in a NaN;
526 # spaces are already checked in Cowlishaw's test-suite, so
527 # here we just check that a trailing newline results in a NaN
528 self.assertEqual(str(nc.create_decimal('3.14\n')), 'NaN')
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000529
530 # from tuples
531 d = Decimal( (1, (4, 3, 4, 9, 1, 3, 5, 3, 4), -25) )
532 self.assertEqual(str(d), '-4.34913534E-17')
533 d = nc.create_decimal( (1, (4, 3, 4, 9, 1, 3, 5, 3, 4), -25) )
534 self.assertEqual(str(d), '-4.35E-17')
535
536 # from Decimal
537 prevdec = Decimal(500000123)
538 d = Decimal(prevdec)
539 self.assertEqual(str(d), '500000123')
540 d = nc.create_decimal(prevdec)
541 self.assertEqual(str(d), '5.00E+8')
542
543
544class DecimalImplicitConstructionTest(unittest.TestCase):
545 '''Unit tests for Implicit Construction cases of Decimal.'''
546
547 def test_implicit_from_None(self):
548 self.assertRaises(TypeError, eval, 'Decimal(5) + None', globals())
549
550 def test_implicit_from_int(self):
551 #normal
552 self.assertEqual(str(Decimal(5) + 45), '50')
553 #exceeding precision
554 self.assertEqual(Decimal(5) + 123456789000, Decimal(123456789000))
555
556 def test_implicit_from_string(self):
557 self.assertRaises(TypeError, eval, 'Decimal(5) + "3"', globals())
558
559 def test_implicit_from_float(self):
560 self.assertRaises(TypeError, eval, 'Decimal(5) + 2.2', globals())
561
562 def test_implicit_from_Decimal(self):
563 self.assertEqual(Decimal(5) + Decimal(45), Decimal(50))
564
Raymond Hettinger267b8682005-03-27 10:47:39 +0000565 def test_rop(self):
566 # Allow other classes to be trained to interact with Decimals
567 class E:
568 def __divmod__(self, other):
569 return 'divmod ' + str(other)
570 def __rdivmod__(self, other):
571 return str(other) + ' rdivmod'
572 def __lt__(self, other):
573 return 'lt ' + str(other)
574 def __gt__(self, other):
575 return 'gt ' + str(other)
576 def __le__(self, other):
577 return 'le ' + str(other)
578 def __ge__(self, other):
579 return 'ge ' + str(other)
580 def __eq__(self, other):
581 return 'eq ' + str(other)
582 def __ne__(self, other):
583 return 'ne ' + str(other)
584
585 self.assertEqual(divmod(E(), Decimal(10)), 'divmod 10')
586 self.assertEqual(divmod(Decimal(10), E()), '10 rdivmod')
587 self.assertEqual(eval('Decimal(10) < E()'), 'gt 10')
588 self.assertEqual(eval('Decimal(10) > E()'), 'lt 10')
589 self.assertEqual(eval('Decimal(10) <= E()'), 'ge 10')
590 self.assertEqual(eval('Decimal(10) >= E()'), 'le 10')
591 self.assertEqual(eval('Decimal(10) == E()'), 'eq 10')
592 self.assertEqual(eval('Decimal(10) != E()'), 'ne 10')
593
594 # insert operator methods and then exercise them
Georg Brandl96c3f7f2006-03-28 08:06:35 +0000595 oplist = [
596 ('+', '__add__', '__radd__'),
597 ('-', '__sub__', '__rsub__'),
598 ('*', '__mul__', '__rmul__'),
599 ('%', '__mod__', '__rmod__'),
600 ('//', '__floordiv__', '__rfloordiv__'),
601 ('**', '__pow__', '__rpow__')
602 ]
603 if 1/2 == 0:
604 # testing with classic division, so add __div__
605 oplist.append(('/', '__div__', '__rdiv__'))
606 else:
607 # testing with -Qnew, so add __truediv__
608 oplist.append(('/', '__truediv__', '__rtruediv__'))
Anthony Baxter4ef3a232006-03-30 12:59:11 +0000609
Georg Brandl96c3f7f2006-03-28 08:06:35 +0000610 for sym, lop, rop in oplist:
Raymond Hettinger267b8682005-03-27 10:47:39 +0000611 setattr(E, lop, lambda self, other: 'str' + lop + str(other))
612 setattr(E, rop, lambda self, other: str(other) + rop + 'str')
613 self.assertEqual(eval('E()' + sym + 'Decimal(10)'),
614 'str' + lop + '10')
615 self.assertEqual(eval('Decimal(10)' + sym + 'E()'),
616 '10' + rop + 'str')
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000617
618class DecimalArithmeticOperatorsTest(unittest.TestCase):
619 '''Unit tests for all arithmetic operators, binary and unary.'''
620
621 def test_addition(self):
622
623 d1 = Decimal('-11.1')
624 d2 = Decimal('22.2')
625
626 #two Decimals
627 self.assertEqual(d1+d2, Decimal('11.1'))
628 self.assertEqual(d2+d1, Decimal('11.1'))
629
630 #with other type, left
631 c = d1 + 5
632 self.assertEqual(c, Decimal('-6.1'))
633 self.assertEqual(type(c), type(d1))
634
635 #with other type, right
636 c = 5 + d1
637 self.assertEqual(c, Decimal('-6.1'))
638 self.assertEqual(type(c), type(d1))
639
640 #inline with decimal
641 d1 += d2
642 self.assertEqual(d1, Decimal('11.1'))
643
644 #inline with other type
645 d1 += 5
646 self.assertEqual(d1, Decimal('16.1'))
647
648 def test_subtraction(self):
649
650 d1 = Decimal('-11.1')
651 d2 = Decimal('22.2')
652
653 #two Decimals
654 self.assertEqual(d1-d2, Decimal('-33.3'))
655 self.assertEqual(d2-d1, Decimal('33.3'))
656
657 #with other type, left
658 c = d1 - 5
659 self.assertEqual(c, Decimal('-16.1'))
660 self.assertEqual(type(c), type(d1))
661
662 #with other type, right
663 c = 5 - d1
664 self.assertEqual(c, Decimal('16.1'))
665 self.assertEqual(type(c), type(d1))
666
667 #inline with decimal
668 d1 -= d2
669 self.assertEqual(d1, Decimal('-33.3'))
670
671 #inline with other type
672 d1 -= 5
673 self.assertEqual(d1, Decimal('-38.3'))
674
675 def test_multiplication(self):
676
677 d1 = Decimal('-5')
678 d2 = Decimal('3')
679
680 #two Decimals
681 self.assertEqual(d1*d2, Decimal('-15'))
682 self.assertEqual(d2*d1, Decimal('-15'))
683
684 #with other type, left
685 c = d1 * 5
686 self.assertEqual(c, Decimal('-25'))
687 self.assertEqual(type(c), type(d1))
688
689 #with other type, right
690 c = 5 * d1
691 self.assertEqual(c, Decimal('-25'))
692 self.assertEqual(type(c), type(d1))
693
694 #inline with decimal
695 d1 *= d2
696 self.assertEqual(d1, Decimal('-15'))
697
698 #inline with other type
699 d1 *= 5
700 self.assertEqual(d1, Decimal('-75'))
701
702 def test_division(self):
703
704 d1 = Decimal('-5')
705 d2 = Decimal('2')
706
707 #two Decimals
708 self.assertEqual(d1/d2, Decimal('-2.5'))
709 self.assertEqual(d2/d1, Decimal('-0.4'))
710
711 #with other type, left
712 c = d1 / 4
713 self.assertEqual(c, Decimal('-1.25'))
714 self.assertEqual(type(c), type(d1))
715
716 #with other type, right
717 c = 4 / d1
718 self.assertEqual(c, Decimal('-0.8'))
719 self.assertEqual(type(c), type(d1))
720
721 #inline with decimal
722 d1 /= d2
723 self.assertEqual(d1, Decimal('-2.5'))
724
725 #inline with other type
726 d1 /= 4
727 self.assertEqual(d1, Decimal('-0.625'))
728
729 def test_floor_division(self):
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000730
731 d1 = Decimal('5')
732 d2 = Decimal('2')
733
734 #two Decimals
735 self.assertEqual(d1//d2, Decimal('2'))
736 self.assertEqual(d2//d1, Decimal('0'))
737
738 #with other type, left
739 c = d1 // 4
740 self.assertEqual(c, Decimal('1'))
741 self.assertEqual(type(c), type(d1))
742
743 #with other type, right
744 c = 7 // d1
745 self.assertEqual(c, Decimal('1'))
746 self.assertEqual(type(c), type(d1))
747
748 #inline with decimal
749 d1 //= d2
750 self.assertEqual(d1, Decimal('2'))
751
752 #inline with other type
753 d1 //= 2
754 self.assertEqual(d1, Decimal('1'))
755
756 def test_powering(self):
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000757
758 d1 = Decimal('5')
759 d2 = Decimal('2')
760
761 #two Decimals
762 self.assertEqual(d1**d2, Decimal('25'))
763 self.assertEqual(d2**d1, Decimal('32'))
764
765 #with other type, left
766 c = d1 ** 4
767 self.assertEqual(c, Decimal('625'))
768 self.assertEqual(type(c), type(d1))
769
770 #with other type, right
771 c = 7 ** d1
772 self.assertEqual(c, Decimal('16807'))
773 self.assertEqual(type(c), type(d1))
774
775 #inline with decimal
776 d1 **= d2
777 self.assertEqual(d1, Decimal('25'))
778
779 #inline with other type
780 d1 **= 4
781 self.assertEqual(d1, Decimal('390625'))
782
783 def test_module(self):
784
785 d1 = Decimal('5')
786 d2 = Decimal('2')
787
788 #two Decimals
789 self.assertEqual(d1%d2, Decimal('1'))
790 self.assertEqual(d2%d1, Decimal('2'))
791
792 #with other type, left
793 c = d1 % 4
794 self.assertEqual(c, Decimal('1'))
795 self.assertEqual(type(c), type(d1))
796
797 #with other type, right
798 c = 7 % d1
799 self.assertEqual(c, Decimal('2'))
800 self.assertEqual(type(c), type(d1))
801
802 #inline with decimal
803 d1 %= d2
804 self.assertEqual(d1, Decimal('1'))
805
806 #inline with other type
807 d1 %= 4
808 self.assertEqual(d1, Decimal('1'))
809
810 def test_floor_div_module(self):
811
812 d1 = Decimal('5')
813 d2 = Decimal('2')
814
815 #two Decimals
816 (p, q) = divmod(d1, d2)
817 self.assertEqual(p, Decimal('2'))
818 self.assertEqual(q, Decimal('1'))
819 self.assertEqual(type(p), type(d1))
820 self.assertEqual(type(q), type(d1))
821
822 #with other type, left
823 (p, q) = divmod(d1, 4)
824 self.assertEqual(p, Decimal('1'))
825 self.assertEqual(q, Decimal('1'))
826 self.assertEqual(type(p), type(d1))
827 self.assertEqual(type(q), type(d1))
828
829 #with other type, right
830 (p, q) = divmod(7, d1)
831 self.assertEqual(p, Decimal('1'))
832 self.assertEqual(q, Decimal('2'))
833 self.assertEqual(type(p), type(d1))
834 self.assertEqual(type(q), type(d1))
835
836 def test_unary_operators(self):
837 self.assertEqual(+Decimal(45), Decimal(+45)) # +
838 self.assertEqual(-Decimal(45), Decimal(-45)) # -
839 self.assertEqual(abs(Decimal(45)), abs(Decimal(-45))) # abs
840
Mark Dickinson2fc92632008-02-06 22:10:50 +0000841 def test_nan_comparisons(self):
842 n = Decimal('NaN')
843 s = Decimal('sNaN')
844 i = Decimal('Inf')
845 f = Decimal('2')
846 for x, y in [(n, n), (n, i), (i, n), (n, f), (f, n),
847 (s, n), (n, s), (s, i), (i, s), (s, f), (f, s), (s, s)]:
848 self.assert_(x != y)
849 self.assert_(not (x == y))
850 self.assert_(not (x < y))
851 self.assert_(not (x <= y))
852 self.assert_(not (x > y))
853 self.assert_(not (x >= y))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000854
855# The following are two functions used to test threading in the next class
856
857def thfunc1(cls):
858 d1 = Decimal(1)
859 d3 = Decimal(3)
860 cls.assertEqual(d1/d3, Decimal('0.333333333'))
861 cls.synchro.wait()
862 cls.assertEqual(d1/d3, Decimal('0.333333333'))
863 cls.finish1.set()
864 return
865
866def thfunc2(cls):
867 d1 = Decimal(1)
868 d3 = Decimal(3)
869 cls.assertEqual(d1/d3, Decimal('0.333333333'))
870 thiscontext = getcontext()
871 thiscontext.prec = 18
872 cls.assertEqual(d1/d3, Decimal('0.333333333333333333'))
873 cls.synchro.set()
874 cls.finish2.set()
875 return
876
877
878class DecimalUseOfContextTest(unittest.TestCase):
879 '''Unit tests for Use of Context cases in Decimal.'''
880
Raymond Hettinger7e71fa52004-12-18 19:07:19 +0000881 try:
882 import threading
883 except ImportError:
884 threading = None
885
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000886 # Take care executing this test from IDLE, there's an issue in threading
887 # that hangs IDLE and I couldn't find it
888
889 def test_threading(self):
890 #Test the "threading isolation" of a Context.
891
892 self.synchro = threading.Event()
893 self.finish1 = threading.Event()
894 self.finish2 = threading.Event()
895
896 th1 = threading.Thread(target=thfunc1, args=(self,))
897 th2 = threading.Thread(target=thfunc2, args=(self,))
898
899 th1.start()
900 th2.start()
901
902 self.finish1.wait()
Thomas Woutersb3e6e8c2007-09-19 17:27:29 +0000903 self.finish2.wait()
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000904 return
905
Raymond Hettinger7e71fa52004-12-18 19:07:19 +0000906 if threading is None:
907 del test_threading
908
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000909
910class DecimalUsabilityTest(unittest.TestCase):
911 '''Unit tests for Usability cases of Decimal.'''
912
913 def test_comparison_operators(self):
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000914
915 da = Decimal('23.42')
916 db = Decimal('23.42')
917 dc = Decimal('45')
918
919 #two Decimals
920 self.failUnless(dc > da)
921 self.failUnless(dc >= da)
922 self.failUnless(da < dc)
923 self.failUnless(da <= dc)
924 self.failUnless(da == db)
925 self.failUnless(da != dc)
926 self.failUnless(da <= db)
927 self.failUnless(da >= db)
928 self.assertEqual(cmp(dc,da), 1)
929 self.assertEqual(cmp(da,dc), -1)
930 self.assertEqual(cmp(da,db), 0)
931
932 #a Decimal and an int
933 self.failUnless(dc > 23)
934 self.failUnless(23 < dc)
935 self.failUnless(dc == 45)
936 self.assertEqual(cmp(dc,23), 1)
937 self.assertEqual(cmp(23,dc), -1)
938 self.assertEqual(cmp(dc,45), 0)
939
940 #a Decimal and uncomparable
Raymond Hettinger0aeac102004-07-05 22:53:03 +0000941 self.assertNotEqual(da, 'ugly')
942 self.assertNotEqual(da, 32.7)
943 self.assertNotEqual(da, object())
944 self.assertNotEqual(da, object)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000945
Raymond Hettinger0aeac102004-07-05 22:53:03 +0000946 # sortable
947 a = map(Decimal, xrange(100))
948 b = a[:]
949 random.shuffle(a)
950 a.sort()
951 self.assertEqual(a, b)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000952
Facundo Batista353750c2007-09-13 18:13:15 +0000953 # with None
954 self.assertFalse(Decimal(1) < None)
955 self.assertTrue(Decimal(1) > None)
956
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000957 def test_copy_and_deepcopy_methods(self):
958 d = Decimal('43.24')
959 c = copy.copy(d)
960 self.assertEqual(id(c), id(d))
961 dc = copy.deepcopy(d)
962 self.assertEqual(id(dc), id(d))
963
964 def test_hash_method(self):
965 #just that it's hashable
966 hash(Decimal(23))
Facundo Batista8c202442007-09-19 17:53:25 +0000967
968 test_values = [Decimal(sign*(2**m + n))
969 for m in [0, 14, 15, 16, 17, 30, 31,
970 32, 33, 62, 63, 64, 65, 66]
971 for n in range(-10, 10)
972 for sign in [-1, 1]]
973 test_values.extend([
974 Decimal("-0"), # zeros
975 Decimal("0.00"),
976 Decimal("-0.000"),
977 Decimal("0E10"),
978 Decimal("-0E12"),
979 Decimal("10.0"), # negative exponent
980 Decimal("-23.00000"),
981 Decimal("1230E100"), # positive exponent
982 Decimal("-4.5678E50"),
983 # a value for which hash(n) != hash(n % (2**64-1))
984 # in Python pre-2.6
985 Decimal(2**64 + 2**32 - 1),
986 # selection of values which fail with the old (before
987 # version 2.6) long.__hash__
988 Decimal("1.634E100"),
989 Decimal("90.697E100"),
990 Decimal("188.83E100"),
991 Decimal("1652.9E100"),
992 Decimal("56531E100"),
993 ])
994
995 # check that hash(d) == hash(int(d)) for integral values
996 for value in test_values:
997 self.assertEqual(hash(value), hash(int(value)))
998
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000999 #the same hash that to an int
1000 self.assertEqual(hash(Decimal(23)), hash(23))
Raymond Hettingerbea3f6f2005-03-15 04:59:17 +00001001 self.assertRaises(TypeError, hash, Decimal('NaN'))
1002 self.assert_(hash(Decimal('Inf')))
1003 self.assert_(hash(Decimal('-Inf')))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001004
Facundo Batista52b25792008-01-08 12:25:20 +00001005 # check that the value of the hash doesn't depend on the
1006 # current context (issue #1757)
1007 c = getcontext()
1008 old_precision = c.prec
1009 x = Decimal("123456789.1")
1010
1011 c.prec = 6
1012 h1 = hash(x)
1013 c.prec = 10
1014 h2 = hash(x)
1015 c.prec = 16
1016 h3 = hash(x)
1017
1018 self.assertEqual(h1, h2)
1019 self.assertEqual(h1, h3)
1020 c.prec = old_precision
1021
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001022 def test_min_and_max_methods(self):
1023
1024 d1 = Decimal('15.32')
1025 d2 = Decimal('28.5')
1026 l1 = 15
1027 l2 = 28
1028
1029 #between Decimals
1030 self.failUnless(min(d1,d2) is d1)
1031 self.failUnless(min(d2,d1) is d1)
1032 self.failUnless(max(d1,d2) is d2)
1033 self.failUnless(max(d2,d1) is d2)
1034
1035 #between Decimal and long
1036 self.failUnless(min(d1,l2) is d1)
1037 self.failUnless(min(l2,d1) is d1)
1038 self.failUnless(max(l1,d2) is d2)
1039 self.failUnless(max(d2,l1) is d2)
1040
1041 def test_as_nonzero(self):
1042 #as false
1043 self.failIf(Decimal(0))
1044 #as true
1045 self.failUnless(Decimal('0.372'))
1046
1047 def test_tostring_methods(self):
1048 #Test str and repr methods.
1049
1050 d = Decimal('15.32')
1051 self.assertEqual(str(d), '15.32') # str
Raymond Hettingerabe32372008-02-14 02:41:22 +00001052 self.assertEqual(repr(d), "Decimal('15.32')") # repr
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001053
1054 def test_tonum_methods(self):
1055 #Test float, int and long methods.
1056
1057 d1 = Decimal('66')
1058 d2 = Decimal('15.32')
1059
1060 #int
1061 self.assertEqual(int(d1), 66)
1062 self.assertEqual(int(d2), 15)
1063
1064 #long
1065 self.assertEqual(long(d1), 66)
1066 self.assertEqual(long(d2), 15)
1067
1068 #float
1069 self.assertEqual(float(d1), 66)
1070 self.assertEqual(float(d2), 15.32)
1071
1072 def test_eval_round_trip(self):
1073
1074 #with zero
1075 d = Decimal( (0, (0,), 0) )
1076 self.assertEqual(d, eval(repr(d)))
1077
1078 #int
1079 d = Decimal( (1, (4, 5), 0) )
1080 self.assertEqual(d, eval(repr(d)))
1081
1082 #float
1083 d = Decimal( (0, (4, 5, 3, 4), -2) )
1084 self.assertEqual(d, eval(repr(d)))
1085
1086 #weird
1087 d = Decimal( (1, (4, 3, 4, 9, 1, 3, 5, 3, 4), -25) )
1088 self.assertEqual(d, eval(repr(d)))
1089
1090 def test_as_tuple(self):
1091
1092 #with zero
1093 d = Decimal(0)
1094 self.assertEqual(d.as_tuple(), (0, (0,), 0) )
1095
1096 #int
1097 d = Decimal(-45)
1098 self.assertEqual(d.as_tuple(), (1, (4, 5), 0) )
1099
1100 #complicated string
1101 d = Decimal("-4.34913534E-17")
1102 self.assertEqual(d.as_tuple(), (1, (4, 3, 4, 9, 1, 3, 5, 3, 4), -25) )
1103
1104 #inf
1105 d = Decimal("Infinity")
1106 self.assertEqual(d.as_tuple(), (0, (0,), 'F') )
1107
Facundo Batista9b5e2312007-10-19 19:25:57 +00001108 #leading zeros in coefficient should be stripped
1109 d = Decimal( (0, (0, 0, 4, 0, 5, 3, 4), -2) )
1110 self.assertEqual(d.as_tuple(), (0, (4, 0, 5, 3, 4), -2) )
1111 d = Decimal( (1, (0, 0, 0), 37) )
1112 self.assertEqual(d.as_tuple(), (1, (0,), 37))
1113 d = Decimal( (1, (), 37) )
1114 self.assertEqual(d.as_tuple(), (1, (0,), 37))
1115
1116 #leading zeros in NaN diagnostic info should be stripped
1117 d = Decimal( (0, (0, 0, 4, 0, 5, 3, 4), 'n') )
1118 self.assertEqual(d.as_tuple(), (0, (4, 0, 5, 3, 4), 'n') )
1119 d = Decimal( (1, (0, 0, 0), 'N') )
1120 self.assertEqual(d.as_tuple(), (1, (), 'N') )
1121 d = Decimal( (1, (), 'n') )
1122 self.assertEqual(d.as_tuple(), (1, (), 'n') )
1123
1124 #coefficient in infinity should be ignored
1125 d = Decimal( (0, (4, 5, 3, 4), 'F') )
1126 self.assertEqual(d.as_tuple(), (0, (0,), 'F'))
1127 d = Decimal( (1, (0, 2, 7, 1), 'F') )
1128 self.assertEqual(d.as_tuple(), (1, (0,), 'F'))
1129
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001130 def test_immutability_operations(self):
1131 # Do operations and check that it didn't change change internal objects.
1132
1133 d1 = Decimal('-25e55')
1134 b1 = Decimal('-25e55')
Facundo Batista353750c2007-09-13 18:13:15 +00001135 d2 = Decimal('33e+33')
1136 b2 = Decimal('33e+33')
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001137
1138 def checkSameDec(operation, useOther=False):
1139 if useOther:
1140 eval("d1." + operation + "(d2)")
1141 self.assertEqual(d1._sign, b1._sign)
1142 self.assertEqual(d1._int, b1._int)
1143 self.assertEqual(d1._exp, b1._exp)
1144 self.assertEqual(d2._sign, b2._sign)
1145 self.assertEqual(d2._int, b2._int)
1146 self.assertEqual(d2._exp, b2._exp)
1147 else:
1148 eval("d1." + operation + "()")
1149 self.assertEqual(d1._sign, b1._sign)
1150 self.assertEqual(d1._int, b1._int)
1151 self.assertEqual(d1._exp, b1._exp)
1152 return
1153
1154 Decimal(d1)
1155 self.assertEqual(d1._sign, b1._sign)
1156 self.assertEqual(d1._int, b1._int)
1157 self.assertEqual(d1._exp, b1._exp)
1158
1159 checkSameDec("__abs__")
1160 checkSameDec("__add__", True)
1161 checkSameDec("__div__", True)
1162 checkSameDec("__divmod__", True)
Mark Dickinson2fc92632008-02-06 22:10:50 +00001163 checkSameDec("__eq__", True)
1164 checkSameDec("__ne__", True)
1165 checkSameDec("__le__", True)
1166 checkSameDec("__lt__", True)
1167 checkSameDec("__ge__", True)
1168 checkSameDec("__gt__", True)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001169 checkSameDec("__float__")
1170 checkSameDec("__floordiv__", True)
1171 checkSameDec("__hash__")
1172 checkSameDec("__int__")
Raymond Hettinger5a053642008-01-24 19:05:29 +00001173 checkSameDec("__trunc__")
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001174 checkSameDec("__long__")
1175 checkSameDec("__mod__", True)
1176 checkSameDec("__mul__", True)
1177 checkSameDec("__neg__")
1178 checkSameDec("__nonzero__")
1179 checkSameDec("__pos__")
1180 checkSameDec("__pow__", True)
1181 checkSameDec("__radd__", True)
1182 checkSameDec("__rdiv__", True)
1183 checkSameDec("__rdivmod__", True)
1184 checkSameDec("__repr__")
1185 checkSameDec("__rfloordiv__", True)
1186 checkSameDec("__rmod__", True)
1187 checkSameDec("__rmul__", True)
1188 checkSameDec("__rpow__", True)
1189 checkSameDec("__rsub__", True)
1190 checkSameDec("__str__")
1191 checkSameDec("__sub__", True)
1192 checkSameDec("__truediv__", True)
1193 checkSameDec("adjusted")
1194 checkSameDec("as_tuple")
1195 checkSameDec("compare", True)
1196 checkSameDec("max", True)
1197 checkSameDec("min", True)
1198 checkSameDec("normalize")
1199 checkSameDec("quantize", True)
1200 checkSameDec("remainder_near", True)
1201 checkSameDec("same_quantum", True)
1202 checkSameDec("sqrt")
1203 checkSameDec("to_eng_string")
1204 checkSameDec("to_integral")
1205
Facundo Batista6c398da2007-09-17 17:30:13 +00001206 def test_subclassing(self):
1207 # Different behaviours when subclassing Decimal
1208
1209 class MyDecimal(Decimal):
1210 pass
1211
1212 d1 = MyDecimal(1)
1213 d2 = MyDecimal(2)
1214 d = d1 + d2
1215 self.assertTrue(type(d) is Decimal)
1216
1217 d = d1.max(d2)
1218 self.assertTrue(type(d) is Decimal)
1219
1220
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001221class DecimalPythonAPItests(unittest.TestCase):
1222
1223 def test_pickle(self):
1224 d = Decimal('-3.141590000')
1225 p = pickle.dumps(d)
1226 e = pickle.loads(p)
1227 self.assertEqual(d, e)
1228
Raymond Hettinger5548be22004-07-05 18:49:38 +00001229 def test_int(self):
Raymond Hettinger605ed022004-11-24 07:28:48 +00001230 for x in range(-250, 250):
1231 s = '%0.2f' % (x / 100.0)
Raymond Hettinger5548be22004-07-05 18:49:38 +00001232 # should work the same as for floats
1233 self.assertEqual(int(Decimal(s)), int(float(s)))
Raymond Hettinger605ed022004-11-24 07:28:48 +00001234 # should work the same as to_integral in the ROUND_DOWN mode
Raymond Hettinger5548be22004-07-05 18:49:38 +00001235 d = Decimal(s)
Raymond Hettinger605ed022004-11-24 07:28:48 +00001236 r = d.to_integral(ROUND_DOWN)
Raymond Hettinger5548be22004-07-05 18:49:38 +00001237 self.assertEqual(Decimal(int(d)), r)
1238
Raymond Hettinger5a053642008-01-24 19:05:29 +00001239 def test_trunc(self):
1240 for x in range(-250, 250):
1241 s = '%0.2f' % (x / 100.0)
1242 # should work the same as for floats
1243 self.assertEqual(int(Decimal(s)), int(float(s)))
1244 # should work the same as to_integral in the ROUND_DOWN mode
1245 d = Decimal(s)
1246 r = d.to_integral(ROUND_DOWN)
Jeffrey Yasskinca2b69f2008-02-01 06:22:46 +00001247 self.assertEqual(Decimal(math.trunc(d)), r)
Raymond Hettinger5a053642008-01-24 19:05:29 +00001248
Raymond Hettingerd9c0a7a2004-07-03 10:02:28 +00001249class ContextAPItests(unittest.TestCase):
1250
1251 def test_pickle(self):
1252 c = Context()
1253 e = pickle.loads(pickle.dumps(c))
1254 for k in vars(c):
1255 v1 = vars(c)[k]
1256 v2 = vars(e)[k]
1257 self.assertEqual(v1, v2)
1258
Raymond Hettinger0aeac102004-07-05 22:53:03 +00001259 def test_equality_with_other_types(self):
1260 self.assert_(Decimal(10) in ['a', 1.0, Decimal(10), (1,2), {}])
1261 self.assert_(Decimal(10) not in ['a', 1.0, (1,2), {}])
1262
Raymond Hettinger955d2b22004-08-08 20:17:45 +00001263 def test_copy(self):
1264 # All copies should be deep
1265 c = Context()
1266 d = c.copy()
1267 self.assertNotEqual(id(c), id(d))
1268 self.assertNotEqual(id(c.flags), id(d.flags))
1269 self.assertNotEqual(id(c.traps), id(d.traps))
1270
Nick Coghlan8b6999b2006-08-31 12:00:43 +00001271class WithStatementTest(unittest.TestCase):
1272 # Can't do these as docstrings until Python 2.6
1273 # as doctest can't handle __future__ statements
Nick Coghlan8b6999b2006-08-31 12:00:43 +00001274
1275 def test_localcontext(self):
Nick Coghlanced12182006-09-02 03:54:17 +00001276 # Use a copy of the current context in the block
Nick Coghlan8b6999b2006-08-31 12:00:43 +00001277 orig_ctx = getcontext()
1278 with localcontext() as enter_ctx:
1279 set_ctx = getcontext()
1280 final_ctx = getcontext()
1281 self.assert_(orig_ctx is final_ctx, 'did not restore context correctly')
1282 self.assert_(orig_ctx is not set_ctx, 'did not copy the context')
1283 self.assert_(set_ctx is enter_ctx, '__enter__ returned wrong context')
1284
1285 def test_localcontextarg(self):
Nick Coghlanced12182006-09-02 03:54:17 +00001286 # Use a copy of the supplied context in the block
Nick Coghlan8b6999b2006-08-31 12:00:43 +00001287 orig_ctx = getcontext()
1288 new_ctx = Context(prec=42)
1289 with localcontext(new_ctx) as enter_ctx:
1290 set_ctx = getcontext()
1291 final_ctx = getcontext()
1292 self.assert_(orig_ctx is final_ctx, 'did not restore context correctly')
1293 self.assert_(set_ctx.prec == new_ctx.prec, 'did not set correct context')
1294 self.assert_(new_ctx is not set_ctx, 'did not copy the context')
1295 self.assert_(set_ctx is enter_ctx, '__enter__ returned wrong context')
1296
Facundo Batista353750c2007-09-13 18:13:15 +00001297class ContextFlags(unittest.TestCase):
1298 def test_flags_irrelevant(self):
1299 # check that the result (numeric result + flags raised) of an
1300 # arithmetic operation doesn't depend on the current flags
1301
1302 context = Context(prec=9, Emin = -999999999, Emax = 999999999,
1303 rounding=ROUND_HALF_EVEN, traps=[], flags=[])
1304
1305 # operations that raise various flags, in the form (function, arglist)
1306 operations = [
1307 (context._apply, [Decimal("100E-1000000009")]),
1308 (context.sqrt, [Decimal(2)]),
1309 (context.add, [Decimal("1.23456789"), Decimal("9.87654321")]),
1310 (context.multiply, [Decimal("1.23456789"), Decimal("9.87654321")]),
1311 (context.subtract, [Decimal("1.23456789"), Decimal("9.87654321")]),
1312 ]
1313
1314 # try various flags individually, then a whole lot at once
1315 flagsets = [[Inexact], [Rounded], [Underflow], [Clamped], [Subnormal],
1316 [Inexact, Rounded, Underflow, Clamped, Subnormal]]
1317
1318 for fn, args in operations:
1319 # find answer and flags raised using a clean context
1320 context.clear_flags()
1321 ans = fn(*args)
1322 flags = [k for k, v in context.flags.items() if v]
1323
1324 for extra_flags in flagsets:
1325 # set flags, before calling operation
1326 context.clear_flags()
1327 for flag in extra_flags:
1328 context._raise_error(flag)
1329 new_ans = fn(*args)
1330
1331 # flags that we expect to be set after the operation
1332 expected_flags = list(flags)
1333 for flag in extra_flags:
1334 if flag not in expected_flags:
1335 expected_flags.append(flag)
1336 expected_flags.sort()
1337
1338 # flags we actually got
1339 new_flags = [k for k,v in context.flags.items() if v]
1340 new_flags.sort()
1341
1342 self.assertEqual(ans, new_ans,
1343 "operation produces different answers depending on flags set: " +
1344 "expected %s, got %s." % (ans, new_ans))
1345 self.assertEqual(new_flags, expected_flags,
1346 "operation raises different flags depending on flags set: " +
1347 "expected %s, got %s" % (expected_flags, new_flags))
1348
1349def test_main(arith=False, verbose=None, todo_tests=None, debug=None):
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001350 """ Execute the tests.
1351
Raymond Hettingered20ad82004-09-04 20:09:13 +00001352 Runs all arithmetic tests if arith is True or if the "decimal" resource
1353 is enabled in regrtest.py
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001354 """
Raymond Hettingered20ad82004-09-04 20:09:13 +00001355
Neal Norwitzce4a9c92006-04-09 08:36:46 +00001356 init()
Facundo Batista353750c2007-09-13 18:13:15 +00001357 global TEST_ALL, DEBUG
Raymond Hettingered20ad82004-09-04 20:09:13 +00001358 TEST_ALL = arith or is_resource_enabled('decimal')
Facundo Batista353750c2007-09-13 18:13:15 +00001359 DEBUG = debug
Raymond Hettingered20ad82004-09-04 20:09:13 +00001360
Facundo Batista353750c2007-09-13 18:13:15 +00001361 if todo_tests is None:
1362 test_classes = [
1363 DecimalExplicitConstructionTest,
1364 DecimalImplicitConstructionTest,
1365 DecimalArithmeticOperatorsTest,
1366 DecimalUseOfContextTest,
1367 DecimalUsabilityTest,
1368 DecimalPythonAPItests,
1369 ContextAPItests,
1370 DecimalTest,
1371 WithStatementTest,
1372 ContextFlags
1373 ]
1374 else:
1375 test_classes = [DecimalTest]
1376
1377 # Dynamically build custom test definition for each file in the test
1378 # directory and add the definitions to the DecimalTest class. This
1379 # procedure insures that new files do not get skipped.
1380 for filename in os.listdir(directory):
1381 if '.decTest' not in filename or filename.startswith("."):
1382 continue
1383 head, tail = filename.split('.')
1384 if todo_tests is not None and head not in todo_tests:
1385 continue
1386 tester = lambda self, f=filename: self.eval_file(directory + f)
1387 setattr(DecimalTest, 'test_' + head, tester)
1388 del filename, head, tail, tester
1389
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001390
Tim Peters46cc7022006-03-31 04:11:16 +00001391 try:
1392 run_unittest(*test_classes)
Facundo Batista353750c2007-09-13 18:13:15 +00001393 if todo_tests is None:
1394 import decimal as DecimalModule
1395 run_doctest(DecimalModule, verbose)
Tim Peters46cc7022006-03-31 04:11:16 +00001396 finally:
1397 setcontext(ORIGINAL_CONTEXT)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001398
1399if __name__ == '__main__':
Facundo Batista353750c2007-09-13 18:13:15 +00001400 import optparse
1401 p = optparse.OptionParser("test_decimal.py [--debug] [{--skip | test1 [test2 [...]]}]")
1402 p.add_option('--debug', '-d', action='store_true', help='shows the test number and context before each test')
1403 p.add_option('--skip', '-s', action='store_true', help='skip over 90% of the arithmetic tests')
1404 (opt, args) = p.parse_args()
1405
1406 if opt.skip:
1407 test_main(arith=False, verbose=True)
1408 elif args:
1409 test_main(arith=True, verbose=True, todo_tests=args, debug=opt.debug)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001410 else:
Facundo Batista353750c2007-09-13 18:13:15 +00001411 test_main(arith=True, verbose=True)