blob: 3c64e64562fa6150a1075170c6d1c1587637e5ac [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"""
Thomas Wouters89f507f2006-12-13 04:49:30 +000026from __future__ import with_statement
Raymond Hettinger7c85fa42004-07-01 11:01:35 +000027
Raymond Hettinger7c85fa42004-07-01 11:01:35 +000028import unittest
29import glob
30import os, sys
31import pickle, copy
32from decimal import *
Thomas Wouters49fd7fa2006-04-21 10:40:58 +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
Guido van Rossumc1f779c2007-07-03 08:25:58 +000042Signals = tuple(getcontext().flags.keys())
Raymond Hettingerfed52962004-07-14 15:41:57 +000043
Thomas Wouters49fd7fa2006-04-21 10:40:58 +000044# Tests are built around these assumed context defaults.
45# test_main() restores the original context.
46def 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,
Thomas Wouters1b7f8912007-09-19 03:06:30 +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
Guido van Rossum8ce8a782007-11-01 19:42:39 +000098nameAdapter = {'and':'logical_and',
Raymond Hettinger7c85fa42004-07-01 11:01:35 +000099 'apply':'_apply',
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000100 'class':'number_class',
101 'comparesig':'compare_signal',
102 'comparetotal':'compare_total',
103 'comparetotmag':'compare_total_mag',
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000104 'copy':'copy_decimal',
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000105 'copyabs':'copy_abs',
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000106 'copynegate':'copy_negate',
107 'copysign':'copy_sign',
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000108 'divideint':'divide_int',
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000109 'invert':'logical_invert',
Guido van Rossum8ce8a782007-11-01 19:42:39 +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',
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000120 'maxmag':'max_mag',
121 'minmag':'min_mag',
122 'nextminus':'next_minus',
123 'nextplus':'next_plus',
124 'nexttoward':'next_toward',
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000125 'or':'logical_or',
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000126 'reduce':'normalize',
Guido van Rossum8ce8a782007-11-01 19:42:39 +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
Guido van Rossum8ce8a782007-11-01 19:42:39 +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
Thomas Wouters1b7f8912007-09-19 03:06:30 +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
Neal Norwitz70967602006-03-17 08:29:44 +0000206 for line in open(file):
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000207 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)
Guido van Rossumb940e112007-01-10 16:19:56 +0000211 except DecimalException as exception:
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000212 #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):
Guido van Rossumc1f779c2007-07-03 08:25:58 +0000236 funct, value = (x.strip().lower() for x in s.split(':'))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000237 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]
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000259 if DEBUG:
260 print("Test ", id, end=" ")
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
Guido van Rossumb940e112007-01-10 16:19:56 +0000304 except Signals as 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:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000312 v = Decimal(v, self.context)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000313 vals.append(v)
314
315 ans = FixQuotes(ans)
316
Thomas Wouters1b7f8912007-09-19 03:06:30 +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
Guido van Rossumb940e112007-01-10 16:19:56 +0000340 except Signals as 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
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000346 if DEBUG:
347 print("--", self.context)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000348 try:
349 result = str(funct(*vals))
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000350 if fname in LOGICAL_FUNCTIONS:
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000351 result = str(int(eval(result))) # 'True', 'False' -> '1', '0'
Guido van Rossumb940e112007-01-10 16:19:56 +0000352 except Signals as 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.
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000355 print("ERROR:", s)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000356 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
Guido van Rossum47b9ff62006-08-24 00:41:19 +0000361 myexceptions.sort(key=repr)
362 theirexceptions.sort(key=repr)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000363
364 self.assertEqual(result, ans,
365 'Incorrect answer for ' + s + ' -- got ' + result)
366 self.assertEqual(myexceptions, theirexceptions,
Thomas Wouters1b7f8912007-09-19 03:06:30 +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
432 def test_explicit_from_tuples(self):
433
434 #zero
435 d = Decimal( (0, (0,), 0) )
436 self.assertEqual(str(d), '0')
437
438 #int
439 d = Decimal( (1, (4, 5), 0) )
440 self.assertEqual(str(d), '-45')
441
442 #float
443 d = Decimal( (0, (4, 5, 3, 4), -2) )
444 self.assertEqual(str(d), '45.34')
445
446 #weird
447 d = Decimal( (1, (4, 3, 4, 9, 1, 3, 5, 3, 4), -25) )
448 self.assertEqual(str(d), '-4.34913534E-17')
449
450 #wrong number of items
451 self.assertRaises(ValueError, Decimal, (1, (4, 3, 4, 9, 1)) )
452
453 #bad sign
454 self.assertRaises(ValueError, Decimal, (8, (4, 3, 4, 9, 1), 2) )
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000455 self.assertRaises(ValueError, Decimal, (0., (4, 3, 4, 9, 1), 2) )
456 self.assertRaises(ValueError, Decimal, (Decimal(1), (4, 3, 4, 9, 1), 2))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000457
458 #bad exp
459 self.assertRaises(ValueError, Decimal, (1, (4, 3, 4, 9, 1), 'wrong!') )
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000460 self.assertRaises(ValueError, Decimal, (1, (4, 3, 4, 9, 1), 0.) )
461 self.assertRaises(ValueError, Decimal, (1, (4, 3, 4, 9, 1), '1') )
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000462
463 #bad coefficients
464 self.assertRaises(ValueError, Decimal, (1, (4, 3, 4, None, 1), 2) )
465 self.assertRaises(ValueError, Decimal, (1, (4, -3, 4, 9, 1), 2) )
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000466 self.assertRaises(ValueError, Decimal, (1, (4, 10, 4, 9, 1), 2) )
Guido van Rossum0d3fb8a2007-11-26 23:23:18 +0000467 self.assertRaises(ValueError, Decimal, (1, (4, 3, 4, 'a', 1), 2) )
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000468
469 def test_explicit_from_Decimal(self):
470
471 #positive
472 d = Decimal(45)
473 e = Decimal(d)
474 self.assertEqual(str(e), '45')
475 self.assertNotEqual(id(d), id(e))
476
477 #very large positive
478 d = Decimal(500000123)
479 e = Decimal(d)
480 self.assertEqual(str(e), '500000123')
481 self.assertNotEqual(id(d), id(e))
482
483 #negative
484 d = Decimal(-45)
485 e = Decimal(d)
486 self.assertEqual(str(e), '-45')
487 self.assertNotEqual(id(d), id(e))
488
489 #zero
490 d = Decimal(0)
491 e = Decimal(d)
492 self.assertEqual(str(e), '0')
493 self.assertNotEqual(id(d), id(e))
494
495 def test_explicit_context_create_decimal(self):
496
497 nc = copy.copy(getcontext())
498 nc.prec = 3
499
500 # empty
Raymond Hettingerfed52962004-07-14 15:41:57 +0000501 d = Decimal()
502 self.assertEqual(str(d), '0')
503 d = nc.create_decimal()
504 self.assertEqual(str(d), '0')
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000505
506 # from None
507 self.assertRaises(TypeError, nc.create_decimal, None)
508
509 # from int
510 d = nc.create_decimal(456)
511 self.failUnless(isinstance(d, Decimal))
512 self.assertEqual(nc.create_decimal(45678),
513 nc.create_decimal('457E+2'))
514
515 # from string
516 d = Decimal('456789')
517 self.assertEqual(str(d), '456789')
518 d = nc.create_decimal('456789')
519 self.assertEqual(str(d), '4.57E+5')
520
521 # from tuples
522 d = Decimal( (1, (4, 3, 4, 9, 1, 3, 5, 3, 4), -25) )
523 self.assertEqual(str(d), '-4.34913534E-17')
524 d = nc.create_decimal( (1, (4, 3, 4, 9, 1, 3, 5, 3, 4), -25) )
525 self.assertEqual(str(d), '-4.35E-17')
526
527 # from Decimal
528 prevdec = Decimal(500000123)
529 d = Decimal(prevdec)
530 self.assertEqual(str(d), '500000123')
531 d = nc.create_decimal(prevdec)
532 self.assertEqual(str(d), '5.00E+8')
533
534
535class DecimalImplicitConstructionTest(unittest.TestCase):
536 '''Unit tests for Implicit Construction cases of Decimal.'''
537
538 def test_implicit_from_None(self):
539 self.assertRaises(TypeError, eval, 'Decimal(5) + None', globals())
540
541 def test_implicit_from_int(self):
542 #normal
543 self.assertEqual(str(Decimal(5) + 45), '50')
544 #exceeding precision
545 self.assertEqual(Decimal(5) + 123456789000, Decimal(123456789000))
546
547 def test_implicit_from_string(self):
548 self.assertRaises(TypeError, eval, 'Decimal(5) + "3"', globals())
549
550 def test_implicit_from_float(self):
551 self.assertRaises(TypeError, eval, 'Decimal(5) + 2.2', globals())
552
553 def test_implicit_from_Decimal(self):
554 self.assertEqual(Decimal(5) + Decimal(45), Decimal(50))
555
Raymond Hettinger267b8682005-03-27 10:47:39 +0000556 def test_rop(self):
557 # Allow other classes to be trained to interact with Decimals
558 class E:
559 def __divmod__(self, other):
560 return 'divmod ' + str(other)
561 def __rdivmod__(self, other):
562 return str(other) + ' rdivmod'
563 def __lt__(self, other):
564 return 'lt ' + str(other)
565 def __gt__(self, other):
566 return 'gt ' + str(other)
567 def __le__(self, other):
568 return 'le ' + str(other)
569 def __ge__(self, other):
570 return 'ge ' + str(other)
571 def __eq__(self, other):
572 return 'eq ' + str(other)
573 def __ne__(self, other):
574 return 'ne ' + str(other)
575
576 self.assertEqual(divmod(E(), Decimal(10)), 'divmod 10')
577 self.assertEqual(divmod(Decimal(10), E()), '10 rdivmod')
578 self.assertEqual(eval('Decimal(10) < E()'), 'gt 10')
579 self.assertEqual(eval('Decimal(10) > E()'), 'lt 10')
580 self.assertEqual(eval('Decimal(10) <= E()'), 'ge 10')
581 self.assertEqual(eval('Decimal(10) >= E()'), 'le 10')
582 self.assertEqual(eval('Decimal(10) == E()'), 'eq 10')
583 self.assertEqual(eval('Decimal(10) != E()'), 'ne 10')
584
585 # insert operator methods and then exercise them
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000586 oplist = [
587 ('+', '__add__', '__radd__'),
588 ('-', '__sub__', '__rsub__'),
589 ('*', '__mul__', '__rmul__'),
Thomas Woutersdcc6d322006-04-21 11:30:52 +0000590 ('/', '__truediv__', '__rtruediv__'),
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000591 ('%', '__mod__', '__rmod__'),
592 ('//', '__floordiv__', '__rfloordiv__'),
593 ('**', '__pow__', '__rpow__')
594 ]
Raymond Hettinger267b8682005-03-27 10:47:39 +0000595
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000596 for sym, lop, rop in oplist:
Raymond Hettinger267b8682005-03-27 10:47:39 +0000597 setattr(E, lop, lambda self, other: 'str' + lop + str(other))
598 setattr(E, rop, lambda self, other: str(other) + rop + 'str')
599 self.assertEqual(eval('E()' + sym + 'Decimal(10)'),
600 'str' + lop + '10')
601 self.assertEqual(eval('Decimal(10)' + sym + 'E()'),
602 '10' + rop + 'str')
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000603
604class DecimalArithmeticOperatorsTest(unittest.TestCase):
605 '''Unit tests for all arithmetic operators, binary and unary.'''
606
607 def test_addition(self):
608
609 d1 = Decimal('-11.1')
610 d2 = Decimal('22.2')
611
612 #two Decimals
613 self.assertEqual(d1+d2, Decimal('11.1'))
614 self.assertEqual(d2+d1, Decimal('11.1'))
615
616 #with other type, left
617 c = d1 + 5
618 self.assertEqual(c, Decimal('-6.1'))
619 self.assertEqual(type(c), type(d1))
620
621 #with other type, right
622 c = 5 + d1
623 self.assertEqual(c, Decimal('-6.1'))
624 self.assertEqual(type(c), type(d1))
625
626 #inline with decimal
627 d1 += d2
628 self.assertEqual(d1, Decimal('11.1'))
629
630 #inline with other type
631 d1 += 5
632 self.assertEqual(d1, Decimal('16.1'))
633
634 def test_subtraction(self):
635
636 d1 = Decimal('-11.1')
637 d2 = Decimal('22.2')
638
639 #two Decimals
640 self.assertEqual(d1-d2, Decimal('-33.3'))
641 self.assertEqual(d2-d1, Decimal('33.3'))
642
643 #with other type, left
644 c = d1 - 5
645 self.assertEqual(c, Decimal('-16.1'))
646 self.assertEqual(type(c), type(d1))
647
648 #with other type, right
649 c = 5 - d1
650 self.assertEqual(c, Decimal('16.1'))
651 self.assertEqual(type(c), type(d1))
652
653 #inline with decimal
654 d1 -= d2
655 self.assertEqual(d1, Decimal('-33.3'))
656
657 #inline with other type
658 d1 -= 5
659 self.assertEqual(d1, Decimal('-38.3'))
660
661 def test_multiplication(self):
662
663 d1 = Decimal('-5')
664 d2 = Decimal('3')
665
666 #two Decimals
667 self.assertEqual(d1*d2, Decimal('-15'))
668 self.assertEqual(d2*d1, Decimal('-15'))
669
670 #with other type, left
671 c = d1 * 5
672 self.assertEqual(c, Decimal('-25'))
673 self.assertEqual(type(c), type(d1))
674
675 #with other type, right
676 c = 5 * d1
677 self.assertEqual(c, Decimal('-25'))
678 self.assertEqual(type(c), type(d1))
679
680 #inline with decimal
681 d1 *= d2
682 self.assertEqual(d1, Decimal('-15'))
683
684 #inline with other type
685 d1 *= 5
686 self.assertEqual(d1, Decimal('-75'))
687
688 def test_division(self):
689
690 d1 = Decimal('-5')
691 d2 = Decimal('2')
692
693 #two Decimals
694 self.assertEqual(d1/d2, Decimal('-2.5'))
695 self.assertEqual(d2/d1, Decimal('-0.4'))
696
697 #with other type, left
698 c = d1 / 4
699 self.assertEqual(c, Decimal('-1.25'))
700 self.assertEqual(type(c), type(d1))
701
702 #with other type, right
703 c = 4 / d1
704 self.assertEqual(c, Decimal('-0.8'))
705 self.assertEqual(type(c), type(d1))
706
707 #inline with decimal
708 d1 /= d2
709 self.assertEqual(d1, Decimal('-2.5'))
710
711 #inline with other type
712 d1 /= 4
713 self.assertEqual(d1, Decimal('-0.625'))
714
715 def test_floor_division(self):
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000716
717 d1 = Decimal('5')
718 d2 = Decimal('2')
719
720 #two Decimals
721 self.assertEqual(d1//d2, Decimal('2'))
722 self.assertEqual(d2//d1, Decimal('0'))
723
724 #with other type, left
725 c = d1 // 4
726 self.assertEqual(c, Decimal('1'))
727 self.assertEqual(type(c), type(d1))
728
729 #with other type, right
730 c = 7 // d1
731 self.assertEqual(c, Decimal('1'))
732 self.assertEqual(type(c), type(d1))
733
734 #inline with decimal
735 d1 //= d2
736 self.assertEqual(d1, Decimal('2'))
737
738 #inline with other type
739 d1 //= 2
740 self.assertEqual(d1, Decimal('1'))
741
742 def test_powering(self):
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000743
744 d1 = Decimal('5')
745 d2 = Decimal('2')
746
747 #two Decimals
748 self.assertEqual(d1**d2, Decimal('25'))
749 self.assertEqual(d2**d1, Decimal('32'))
750
751 #with other type, left
752 c = d1 ** 4
753 self.assertEqual(c, Decimal('625'))
754 self.assertEqual(type(c), type(d1))
755
756 #with other type, right
757 c = 7 ** d1
758 self.assertEqual(c, Decimal('16807'))
759 self.assertEqual(type(c), type(d1))
760
761 #inline with decimal
762 d1 **= d2
763 self.assertEqual(d1, Decimal('25'))
764
765 #inline with other type
766 d1 **= 4
767 self.assertEqual(d1, Decimal('390625'))
768
769 def test_module(self):
770
771 d1 = Decimal('5')
772 d2 = Decimal('2')
773
774 #two Decimals
775 self.assertEqual(d1%d2, Decimal('1'))
776 self.assertEqual(d2%d1, Decimal('2'))
777
778 #with other type, left
779 c = d1 % 4
780 self.assertEqual(c, Decimal('1'))
781 self.assertEqual(type(c), type(d1))
782
783 #with other type, right
784 c = 7 % d1
785 self.assertEqual(c, Decimal('2'))
786 self.assertEqual(type(c), type(d1))
787
788 #inline with decimal
789 d1 %= d2
790 self.assertEqual(d1, Decimal('1'))
791
792 #inline with other type
793 d1 %= 4
794 self.assertEqual(d1, Decimal('1'))
795
796 def test_floor_div_module(self):
797
798 d1 = Decimal('5')
799 d2 = Decimal('2')
800
801 #two Decimals
802 (p, q) = divmod(d1, d2)
803 self.assertEqual(p, Decimal('2'))
804 self.assertEqual(q, Decimal('1'))
805 self.assertEqual(type(p), type(d1))
806 self.assertEqual(type(q), type(d1))
807
808 #with other type, left
809 (p, q) = divmod(d1, 4)
810 self.assertEqual(p, Decimal('1'))
811 self.assertEqual(q, Decimal('1'))
812 self.assertEqual(type(p), type(d1))
813 self.assertEqual(type(q), type(d1))
814
815 #with other type, right
816 (p, q) = divmod(7, d1)
817 self.assertEqual(p, Decimal('1'))
818 self.assertEqual(q, Decimal('2'))
819 self.assertEqual(type(p), type(d1))
820 self.assertEqual(type(q), type(d1))
821
822 def test_unary_operators(self):
823 self.assertEqual(+Decimal(45), Decimal(+45)) # +
824 self.assertEqual(-Decimal(45), Decimal(-45)) # -
825 self.assertEqual(abs(Decimal(45)), abs(Decimal(-45))) # abs
826
827
828# The following are two functions used to test threading in the next class
829
830def thfunc1(cls):
831 d1 = Decimal(1)
832 d3 = Decimal(3)
833 cls.assertEqual(d1/d3, Decimal('0.333333333'))
834 cls.synchro.wait()
835 cls.assertEqual(d1/d3, Decimal('0.333333333'))
836 cls.finish1.set()
837 return
838
839def thfunc2(cls):
840 d1 = Decimal(1)
841 d3 = Decimal(3)
842 cls.assertEqual(d1/d3, Decimal('0.333333333'))
843 thiscontext = getcontext()
844 thiscontext.prec = 18
845 cls.assertEqual(d1/d3, Decimal('0.333333333333333333'))
846 cls.synchro.set()
847 cls.finish2.set()
848 return
849
850
851class DecimalUseOfContextTest(unittest.TestCase):
852 '''Unit tests for Use of Context cases in Decimal.'''
853
Raymond Hettinger7e71fa52004-12-18 19:07:19 +0000854 try:
855 import threading
856 except ImportError:
857 threading = None
858
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000859 # Take care executing this test from IDLE, there's an issue in threading
860 # that hangs IDLE and I couldn't find it
861
862 def test_threading(self):
863 #Test the "threading isolation" of a Context.
864
865 self.synchro = threading.Event()
866 self.finish1 = threading.Event()
867 self.finish2 = threading.Event()
868
869 th1 = threading.Thread(target=thfunc1, args=(self,))
870 th2 = threading.Thread(target=thfunc2, args=(self,))
871
872 th1.start()
873 th2.start()
874
875 self.finish1.wait()
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000876 self.finish2.wait()
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000877 return
878
Raymond Hettinger7e71fa52004-12-18 19:07:19 +0000879 if threading is None:
880 del test_threading
881
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000882
883class DecimalUsabilityTest(unittest.TestCase):
884 '''Unit tests for Usability cases of Decimal.'''
885
886 def test_comparison_operators(self):
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000887
888 da = Decimal('23.42')
889 db = Decimal('23.42')
890 dc = Decimal('45')
891
892 #two Decimals
893 self.failUnless(dc > da)
894 self.failUnless(dc >= da)
895 self.failUnless(da < dc)
896 self.failUnless(da <= dc)
Guido van Rossume61fd5b2007-07-11 12:20:59 +0000897 self.assertEqual(da, db)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000898 self.failUnless(da != dc)
899 self.failUnless(da <= db)
900 self.failUnless(da >= db)
901 self.assertEqual(cmp(dc,da), 1)
902 self.assertEqual(cmp(da,dc), -1)
903 self.assertEqual(cmp(da,db), 0)
904
905 #a Decimal and an int
906 self.failUnless(dc > 23)
907 self.failUnless(23 < dc)
Guido van Rossume61fd5b2007-07-11 12:20:59 +0000908 self.assertEqual(dc, 45)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000909 self.assertEqual(cmp(dc,23), 1)
910 self.assertEqual(cmp(23,dc), -1)
911 self.assertEqual(cmp(dc,45), 0)
912
913 #a Decimal and uncomparable
Raymond Hettinger0aeac102004-07-05 22:53:03 +0000914 self.assertNotEqual(da, 'ugly')
915 self.assertNotEqual(da, 32.7)
916 self.assertNotEqual(da, object())
917 self.assertNotEqual(da, object)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000918
Raymond Hettinger0aeac102004-07-05 22:53:03 +0000919 # sortable
Guido van Rossumc1f779c2007-07-03 08:25:58 +0000920 a = list(map(Decimal, range(100)))
Raymond Hettinger0aeac102004-07-05 22:53:03 +0000921 b = a[:]
922 random.shuffle(a)
923 a.sort()
924 self.assertEqual(a, b)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000925
926 def test_copy_and_deepcopy_methods(self):
927 d = Decimal('43.24')
928 c = copy.copy(d)
929 self.assertEqual(id(c), id(d))
930 dc = copy.deepcopy(d)
931 self.assertEqual(id(dc), id(d))
932
933 def test_hash_method(self):
934 #just that it's hashable
935 hash(Decimal(23))
Thomas Wouters8ce81f72007-09-20 18:22:40 +0000936
937 test_values = [Decimal(sign*(2**m + n))
938 for m in [0, 14, 15, 16, 17, 30, 31,
939 32, 33, 62, 63, 64, 65, 66]
940 for n in range(-10, 10)
941 for sign in [-1, 1]]
942 test_values.extend([
943 Decimal("-0"), # zeros
944 Decimal("0.00"),
945 Decimal("-0.000"),
946 Decimal("0E10"),
947 Decimal("-0E12"),
948 Decimal("10.0"), # negative exponent
949 Decimal("-23.00000"),
950 Decimal("1230E100"), # positive exponent
951 Decimal("-4.5678E50"),
952 # a value for which hash(n) != hash(n % (2**64-1))
953 # in Python pre-2.6
954 Decimal(2**64 + 2**32 - 1),
955 # selection of values which fail with the old (before
956 # version 2.6) long.__hash__
957 Decimal("1.634E100"),
958 Decimal("90.697E100"),
959 Decimal("188.83E100"),
960 Decimal("1652.9E100"),
961 Decimal("56531E100"),
962 ])
963
964 # check that hash(d) == hash(int(d)) for integral values
965 for value in test_values:
966 self.assertEqual(hash(value), hash(int(value)))
967
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000968 #the same hash that to an int
969 self.assertEqual(hash(Decimal(23)), hash(23))
Raymond Hettingerbea3f6f2005-03-15 04:59:17 +0000970 self.assertRaises(TypeError, hash, Decimal('NaN'))
971 self.assert_(hash(Decimal('Inf')))
972 self.assert_(hash(Decimal('-Inf')))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000973
974 def test_min_and_max_methods(self):
975
976 d1 = Decimal('15.32')
977 d2 = Decimal('28.5')
978 l1 = 15
979 l2 = 28
980
981 #between Decimals
982 self.failUnless(min(d1,d2) is d1)
983 self.failUnless(min(d2,d1) is d1)
984 self.failUnless(max(d1,d2) is d2)
985 self.failUnless(max(d2,d1) is d2)
986
987 #between Decimal and long
988 self.failUnless(min(d1,l2) is d1)
989 self.failUnless(min(l2,d1) is d1)
990 self.failUnless(max(l1,d2) is d2)
991 self.failUnless(max(d2,l1) is d2)
992
993 def test_as_nonzero(self):
994 #as false
995 self.failIf(Decimal(0))
996 #as true
997 self.failUnless(Decimal('0.372'))
998
999 def test_tostring_methods(self):
1000 #Test str and repr methods.
1001
1002 d = Decimal('15.32')
1003 self.assertEqual(str(d), '15.32') # str
1004 self.assertEqual(repr(d), 'Decimal("15.32")') # repr
1005
1006 def test_tonum_methods(self):
1007 #Test float, int and long methods.
1008
1009 d1 = Decimal('66')
1010 d2 = Decimal('15.32')
1011
1012 #int
1013 self.assertEqual(int(d1), 66)
1014 self.assertEqual(int(d2), 15)
1015
1016 #long
Guido van Rossume2a383d2007-01-15 16:59:06 +00001017 self.assertEqual(int(d1), 66)
1018 self.assertEqual(int(d2), 15)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001019
1020 #float
1021 self.assertEqual(float(d1), 66)
1022 self.assertEqual(float(d2), 15.32)
1023
1024 def test_eval_round_trip(self):
1025
1026 #with zero
1027 d = Decimal( (0, (0,), 0) )
1028 self.assertEqual(d, eval(repr(d)))
1029
1030 #int
1031 d = Decimal( (1, (4, 5), 0) )
1032 self.assertEqual(d, eval(repr(d)))
1033
1034 #float
1035 d = Decimal( (0, (4, 5, 3, 4), -2) )
1036 self.assertEqual(d, eval(repr(d)))
1037
1038 #weird
1039 d = Decimal( (1, (4, 3, 4, 9, 1, 3, 5, 3, 4), -25) )
1040 self.assertEqual(d, eval(repr(d)))
1041
1042 def test_as_tuple(self):
1043
1044 #with zero
1045 d = Decimal(0)
1046 self.assertEqual(d.as_tuple(), (0, (0,), 0) )
1047
1048 #int
1049 d = Decimal(-45)
1050 self.assertEqual(d.as_tuple(), (1, (4, 5), 0) )
1051
1052 #complicated string
1053 d = Decimal("-4.34913534E-17")
1054 self.assertEqual(d.as_tuple(), (1, (4, 3, 4, 9, 1, 3, 5, 3, 4), -25) )
1055
1056 #inf
1057 d = Decimal("Infinity")
1058 self.assertEqual(d.as_tuple(), (0, (0,), 'F') )
1059
Guido van Rossum8ce8a782007-11-01 19:42:39 +00001060 #leading zeros in coefficient should be stripped
1061 d = Decimal( (0, (0, 0, 4, 0, 5, 3, 4), -2) )
1062 self.assertEqual(d.as_tuple(), (0, (4, 0, 5, 3, 4), -2) )
1063 d = Decimal( (1, (0, 0, 0), 37) )
1064 self.assertEqual(d.as_tuple(), (1, (0,), 37))
1065 d = Decimal( (1, (), 37) )
1066 self.assertEqual(d.as_tuple(), (1, (0,), 37))
1067
1068 #leading zeros in NaN diagnostic info should be stripped
1069 d = Decimal( (0, (0, 0, 4, 0, 5, 3, 4), 'n') )
1070 self.assertEqual(d.as_tuple(), (0, (4, 0, 5, 3, 4), 'n') )
1071 d = Decimal( (1, (0, 0, 0), 'N') )
1072 self.assertEqual(d.as_tuple(), (1, (), 'N') )
1073 d = Decimal( (1, (), 'n') )
1074 self.assertEqual(d.as_tuple(), (1, (), 'n') )
1075
1076 #coefficient in infinity should be ignored
1077 d = Decimal( (0, (4, 5, 3, 4), 'F') )
1078 self.assertEqual(d.as_tuple(), (0, (0,), 'F'))
1079 d = Decimal( (1, (0, 2, 7, 1), 'F') )
1080 self.assertEqual(d.as_tuple(), (1, (0,), 'F'))
1081
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001082 def test_immutability_operations(self):
1083 # Do operations and check that it didn't change change internal objects.
1084
1085 d1 = Decimal('-25e55')
1086 b1 = Decimal('-25e55')
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001087 d2 = Decimal('33e+33')
1088 b2 = Decimal('33e+33')
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001089
1090 def checkSameDec(operation, useOther=False):
1091 if useOther:
1092 eval("d1." + operation + "(d2)")
1093 self.assertEqual(d1._sign, b1._sign)
1094 self.assertEqual(d1._int, b1._int)
1095 self.assertEqual(d1._exp, b1._exp)
1096 self.assertEqual(d2._sign, b2._sign)
1097 self.assertEqual(d2._int, b2._int)
1098 self.assertEqual(d2._exp, b2._exp)
1099 else:
1100 eval("d1." + operation + "()")
1101 self.assertEqual(d1._sign, b1._sign)
1102 self.assertEqual(d1._int, b1._int)
1103 self.assertEqual(d1._exp, b1._exp)
1104 return
1105
1106 Decimal(d1)
1107 self.assertEqual(d1._sign, b1._sign)
1108 self.assertEqual(d1._int, b1._int)
1109 self.assertEqual(d1._exp, b1._exp)
1110
1111 checkSameDec("__abs__")
1112 checkSameDec("__add__", True)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001113 checkSameDec("__divmod__", True)
1114 checkSameDec("__cmp__", True)
1115 checkSameDec("__float__")
1116 checkSameDec("__floordiv__", True)
1117 checkSameDec("__hash__")
1118 checkSameDec("__int__")
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001119 checkSameDec("__mod__", True)
1120 checkSameDec("__mul__", True)
1121 checkSameDec("__neg__")
Jack Diederich4dafcc42006-11-28 19:15:13 +00001122 checkSameDec("__bool__")
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001123 checkSameDec("__pos__")
1124 checkSameDec("__pow__", True)
1125 checkSameDec("__radd__", True)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001126 checkSameDec("__rdivmod__", True)
1127 checkSameDec("__repr__")
1128 checkSameDec("__rfloordiv__", True)
1129 checkSameDec("__rmod__", True)
1130 checkSameDec("__rmul__", True)
1131 checkSameDec("__rpow__", True)
1132 checkSameDec("__rsub__", True)
1133 checkSameDec("__str__")
1134 checkSameDec("__sub__", True)
1135 checkSameDec("__truediv__", True)
1136 checkSameDec("adjusted")
1137 checkSameDec("as_tuple")
1138 checkSameDec("compare", True)
1139 checkSameDec("max", True)
1140 checkSameDec("min", True)
1141 checkSameDec("normalize")
1142 checkSameDec("quantize", True)
1143 checkSameDec("remainder_near", True)
1144 checkSameDec("same_quantum", True)
1145 checkSameDec("sqrt")
1146 checkSameDec("to_eng_string")
1147 checkSameDec("to_integral")
1148
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001149 def test_subclassing(self):
1150 # Different behaviours when subclassing Decimal
1151
1152 class MyDecimal(Decimal):
1153 pass
1154
1155 d1 = MyDecimal(1)
1156 d2 = MyDecimal(2)
1157 d = d1 + d2
1158 self.assertTrue(type(d) is Decimal)
1159
1160 d = d1.max(d2)
1161 self.assertTrue(type(d) is Decimal)
1162
1163
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001164class DecimalPythonAPItests(unittest.TestCase):
1165
1166 def test_pickle(self):
1167 d = Decimal('-3.141590000')
1168 p = pickle.dumps(d)
1169 e = pickle.loads(p)
1170 self.assertEqual(d, e)
1171
Raymond Hettinger5548be22004-07-05 18:49:38 +00001172 def test_int(self):
Raymond Hettinger605ed022004-11-24 07:28:48 +00001173 for x in range(-250, 250):
1174 s = '%0.2f' % (x / 100.0)
Raymond Hettinger5548be22004-07-05 18:49:38 +00001175 # should work the same as for floats
1176 self.assertEqual(int(Decimal(s)), int(float(s)))
Raymond Hettinger605ed022004-11-24 07:28:48 +00001177 # should work the same as to_integral in the ROUND_DOWN mode
Raymond Hettinger5548be22004-07-05 18:49:38 +00001178 d = Decimal(s)
Raymond Hettinger605ed022004-11-24 07:28:48 +00001179 r = d.to_integral(ROUND_DOWN)
Raymond Hettinger5548be22004-07-05 18:49:38 +00001180 self.assertEqual(Decimal(int(d)), r)
1181
Raymond Hettingerd9c0a7a2004-07-03 10:02:28 +00001182class ContextAPItests(unittest.TestCase):
1183
1184 def test_pickle(self):
1185 c = Context()
1186 e = pickle.loads(pickle.dumps(c))
1187 for k in vars(c):
1188 v1 = vars(c)[k]
1189 v2 = vars(e)[k]
1190 self.assertEqual(v1, v2)
1191
Raymond Hettinger0aeac102004-07-05 22:53:03 +00001192 def test_equality_with_other_types(self):
1193 self.assert_(Decimal(10) in ['a', 1.0, Decimal(10), (1,2), {}])
1194 self.assert_(Decimal(10) not in ['a', 1.0, (1,2), {}])
1195
Raymond Hettinger955d2b22004-08-08 20:17:45 +00001196 def test_copy(self):
1197 # All copies should be deep
1198 c = Context()
1199 d = c.copy()
1200 self.assertNotEqual(id(c), id(d))
1201 self.assertNotEqual(id(c.flags), id(d.flags))
1202 self.assertNotEqual(id(c.traps), id(d.traps))
1203
Thomas Wouters89f507f2006-12-13 04:49:30 +00001204class WithStatementTest(unittest.TestCase):
1205 # Can't do these as docstrings until Python 2.6
1206 # as doctest can't handle __future__ statements
1207
1208 def test_localcontext(self):
1209 # Use a copy of the current context in the block
1210 orig_ctx = getcontext()
1211 with localcontext() as enter_ctx:
1212 set_ctx = getcontext()
1213 final_ctx = getcontext()
1214 self.assert_(orig_ctx is final_ctx, 'did not restore context correctly')
1215 self.assert_(orig_ctx is not set_ctx, 'did not copy the context')
1216 self.assert_(set_ctx is enter_ctx, '__enter__ returned wrong context')
1217
1218 def test_localcontextarg(self):
1219 # Use a copy of the supplied context in the block
1220 orig_ctx = getcontext()
1221 new_ctx = Context(prec=42)
1222 with localcontext(new_ctx) as enter_ctx:
1223 set_ctx = getcontext()
1224 final_ctx = getcontext()
1225 self.assert_(orig_ctx is final_ctx, 'did not restore context correctly')
1226 self.assert_(set_ctx.prec == new_ctx.prec, 'did not set correct context')
1227 self.assert_(new_ctx is not set_ctx, 'did not copy the context')
1228 self.assert_(set_ctx is enter_ctx, '__enter__ returned wrong context')
1229
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001230class ContextFlags(unittest.TestCase):
1231 def test_flags_irrelevant(self):
1232 # check that the result (numeric result + flags raised) of an
1233 # arithmetic operation doesn't depend on the current flags
1234
1235 context = Context(prec=9, Emin = -999999999, Emax = 999999999,
1236 rounding=ROUND_HALF_EVEN, traps=[], flags=[])
1237
1238 # operations that raise various flags, in the form (function, arglist)
1239 operations = [
1240 (context._apply, [Decimal("100E-1000000009")]),
1241 (context.sqrt, [Decimal(2)]),
1242 (context.add, [Decimal("1.23456789"), Decimal("9.87654321")]),
1243 (context.multiply, [Decimal("1.23456789"), Decimal("9.87654321")]),
1244 (context.subtract, [Decimal("1.23456789"), Decimal("9.87654321")]),
1245 ]
1246
1247 # try various flags individually, then a whole lot at once
1248 flagsets = [[Inexact], [Rounded], [Underflow], [Clamped], [Subnormal],
1249 [Inexact, Rounded, Underflow, Clamped, Subnormal]]
1250
1251 for fn, args in operations:
1252 # find answer and flags raised using a clean context
1253 context.clear_flags()
1254 ans = fn(*args)
1255 flags = [k for k, v in context.flags.items() if v]
1256
1257 for extra_flags in flagsets:
1258 # set flags, before calling operation
1259 context.clear_flags()
1260 for flag in extra_flags:
1261 context._raise_error(flag)
1262 new_ans = fn(*args)
1263
1264 # flags that we expect to be set after the operation
1265 expected_flags = list(flags)
1266 for flag in extra_flags:
1267 if flag not in expected_flags:
1268 expected_flags.append(flag)
1269 expected_flags.sort(key=id)
1270
1271 # flags we actually got
1272 new_flags = [k for k,v in context.flags.items() if v]
1273 new_flags.sort(key=id)
1274
1275 self.assertEqual(ans, new_ans,
1276 "operation produces different answers depending on flags set: " +
1277 "expected %s, got %s." % (ans, new_ans))
1278 self.assertEqual(new_flags, expected_flags,
1279 "operation raises different flags depending on flags set: " +
1280 "expected %s, got %s" % (expected_flags, new_flags))
1281
1282def test_main(arith=False, verbose=None, todo_tests=None, debug=None):
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001283 """ Execute the tests.
1284
Raymond Hettingered20ad82004-09-04 20:09:13 +00001285 Runs all arithmetic tests if arith is True or if the "decimal" resource
1286 is enabled in regrtest.py
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001287 """
Raymond Hettingered20ad82004-09-04 20:09:13 +00001288
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00001289 init()
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001290 global TEST_ALL, DEBUG
Raymond Hettingered20ad82004-09-04 20:09:13 +00001291 TEST_ALL = arith or is_resource_enabled('decimal')
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001292 DEBUG = debug
Raymond Hettingered20ad82004-09-04 20:09:13 +00001293
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001294 if todo_tests is None:
1295 test_classes = [
1296 DecimalExplicitConstructionTest,
1297 DecimalImplicitConstructionTest,
1298 DecimalArithmeticOperatorsTest,
1299 DecimalUseOfContextTest,
1300 DecimalUsabilityTest,
1301 DecimalPythonAPItests,
1302 ContextAPItests,
1303 DecimalTest,
1304 WithStatementTest,
1305 ContextFlags
1306 ]
1307 else:
1308 test_classes = [DecimalTest]
1309
1310 # Dynamically build custom test definition for each file in the test
1311 # directory and add the definitions to the DecimalTest class. This
1312 # procedure insures that new files do not get skipped.
1313 for filename in os.listdir(directory):
1314 if '.decTest' not in filename or filename.startswith("."):
1315 continue
1316 head, tail = filename.split('.')
1317 if todo_tests is not None and head not in todo_tests:
1318 continue
1319 tester = lambda self, f=filename: self.eval_file(directory + f)
1320 setattr(DecimalTest, 'test_' + head, tester)
1321 del filename, head, tail, tester
1322
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001323
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00001324 try:
1325 run_unittest(*test_classes)
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001326 if todo_tests is None:
1327 import decimal as DecimalModule
1328 run_doctest(DecimalModule, verbose)
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00001329 finally:
1330 setcontext(ORIGINAL_CONTEXT)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001331
1332if __name__ == '__main__':
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001333 import optparse
1334 p = optparse.OptionParser("test_decimal.py [--debug] [{--skip | test1 [test2 [...]]}]")
1335 p.add_option('--debug', '-d', action='store_true', help='shows the test number and context before each test')
1336 p.add_option('--skip', '-s', action='store_true', help='skip over 90% of the arithmetic tests')
1337 (opt, args) = p.parse_args()
1338
1339 if opt.skip:
1340 test_main(arith=False, verbose=True)
1341 elif args:
1342 test_main(arith=True, verbose=True, todo_tests=args, debug=opt.debug)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001343 else:
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001344 test_main(arith=True, verbose=True)