blob: db55b83fc3130872e81403eeb5b0c33e8700815e [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 Coghlanc48daf52006-09-03 01:08: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 *
Tim Peters46cc7022006-03-31 04:11:16 +000033from test.test_support import (TestSkipped, run_unittest, run_doctest,
34 is_resource_enabled)
Raymond Hettinger0aeac102004-07-05 22:53:03 +000035import random
Raymond Hettinger7e71fa52004-12-18 19:07:19 +000036try:
37 import threading
38except ImportError:
39 threading = None
Raymond Hettinger7c85fa42004-07-01 11:01:35 +000040
Raymond Hettingerfed52962004-07-14 15:41:57 +000041# Useful Test Constant
42Signals = getcontext().flags.keys()
43
Tim Peters46cc7022006-03-31 04:11:16 +000044# Tests are built around these assumed context defaults.
45# test_main() restores the original context.
Neal Norwitzce4a9c92006-04-09 08:36:46 +000046def init():
47 global ORIGINAL_CONTEXT
48 ORIGINAL_CONTEXT = getcontext().copy()
49 DefaultContext.prec = 9
50 DefaultContext.rounding = ROUND_HALF_EVEN
51 DefaultContext.traps = dict.fromkeys(Signals, 0)
52 setcontext(DefaultContext)
Raymond Hettinger6ea48452004-07-03 12:26:21 +000053
Raymond Hettinger7c85fa42004-07-01 11:01:35 +000054TESTDATADIR = 'decimaltestdata'
Raymond Hettingerd9c0a7a2004-07-03 10:02:28 +000055if __name__ == '__main__':
56 file = sys.argv[0]
57else:
58 file = __file__
59testdir = os.path.dirname(file) or os.curdir
Raymond Hettinger267b8682005-03-27 10:47:39 +000060directory = testdir + os.sep + TESTDATADIR + os.sep
Raymond Hettinger7c85fa42004-07-01 11:01:35 +000061
Raymond Hettinger267b8682005-03-27 10:47:39 +000062skip_expected = not os.path.isdir(directory)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +000063
64# Make sure it actually raises errors when not expected and caught in flags
65# Slower, since it runs some things several times.
66EXTENDEDERRORTEST = False
67
Raymond Hettinger7c85fa42004-07-01 11:01:35 +000068#Map the test cases' error names to the actual errors
Raymond Hettinger7c85fa42004-07-01 11:01:35 +000069ErrorNames = {'clamped' : Clamped,
Raymond Hettinger5aa478b2004-07-09 10:02:53 +000070 'conversion_syntax' : InvalidOperation,
Raymond Hettinger7c85fa42004-07-01 11:01:35 +000071 'division_by_zero' : DivisionByZero,
Raymond Hettinger5aa478b2004-07-09 10:02:53 +000072 'division_impossible' : InvalidOperation,
73 'division_undefined' : InvalidOperation,
Raymond Hettinger7c85fa42004-07-01 11:01:35 +000074 'inexact' : Inexact,
Raymond Hettinger5aa478b2004-07-09 10:02:53 +000075 'invalid_context' : InvalidOperation,
Raymond Hettinger7c85fa42004-07-01 11:01:35 +000076 'invalid_operation' : InvalidOperation,
77 'overflow' : Overflow,
78 'rounded' : Rounded,
79 'subnormal' : Subnormal,
80 'underflow' : Underflow}
81
82
83def Nonfunction(*args):
84 """Doesn't do anything."""
85 return None
86
87RoundingDict = {'ceiling' : ROUND_CEILING, #Maps test-case names to roundings.
88 'down' : ROUND_DOWN,
89 'floor' : ROUND_FLOOR,
90 'half_down' : ROUND_HALF_DOWN,
91 'half_even' : ROUND_HALF_EVEN,
92 'half_up' : ROUND_HALF_UP,
Facundo Batista5dfc4802008-01-08 16:20:31 +000093 'up' : ROUND_UP,
94 '05up' : ROUND_05UP}
Raymond Hettinger7c85fa42004-07-01 11:01:35 +000095
96# Name adapter to be able to change the Decimal and Context
97# interface without changing the test files from Cowlishaw
Facundo Batista5dfc4802008-01-08 16:20:31 +000098nameAdapter = {'and':'logical_and',
Raymond Hettinger7c85fa42004-07-01 11:01:35 +000099 'apply':'_apply',
Facundo Batista5dfc4802008-01-08 16:20:31 +0000100 'class':'number_class',
101 'comparesig':'compare_signal',
102 'comparetotal':'compare_total',
103 'comparetotmag':'compare_total_mag',
104 'copy':'copy_decimal',
105 'copyabs':'copy_abs',
106 'copynegate':'copy_negate',
107 'copysign':'copy_sign',
108 'divideint':'divide_int',
109 'invert':'logical_invert',
110 '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',
120 'maxmag':'max_mag',
121 'minmag':'min_mag',
122 'nextminus':'next_minus',
123 'nextplus':'next_plus',
124 'nexttoward':'next_toward',
125 'or':'logical_or',
126 'reduce':'normalize',
127 'remaindernear':'remainder_near',
128 'samequantum':'same_quantum',
129 'squareroot':'sqrt',
130 'toeng':'to_eng_string',
131 'tointegral':'to_integral_value',
132 'tointegralx':'to_integral_exact',
133 'tosci':'to_sci_string',
134 'xor':'logical_xor',
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000135 }
136
Facundo Batista5dfc4802008-01-08 16:20:31 +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
153# For some operations (currently exp, ln, log10, power), the decNumber
154# reference implementation imposes additional restrictions on the
155# context and operands. These restrictions are not part of the
156# specification; however, the effect of these restrictions does show
157# up in some of the testcases. We skip testcases that violate these
158# restrictions, since Decimal behaves differently from decNumber for
159# these testcases so these testcases would otherwise fail.
160
161decNumberRestricted = ('power', 'ln', 'log10', 'exp')
162DEC_MAX_MATH = 999999
163def outside_decNumber_bounds(v, context):
164 if (context.prec > DEC_MAX_MATH or
165 context.Emax > DEC_MAX_MATH or
166 -context.Emin > DEC_MAX_MATH):
167 return True
168 if not v._is_special and v and (
169 len(v._int) > DEC_MAX_MATH or
170 v.adjusted() > DEC_MAX_MATH or
171 v.adjusted() < 1-2*DEC_MAX_MATH):
172 return True
173 return False
174
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000175class DecimalTest(unittest.TestCase):
176 """Class which tests the Decimal class against the test cases.
177
178 Changed for unittest.
179 """
180 def setUp(self):
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000181 self.context = Context()
Raymond Hettingerbf440692004-07-10 14:14:37 +0000182 for key in DefaultContext.traps.keys():
183 DefaultContext.traps[key] = 1
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000184 self.ignore_list = ['#']
185 # Basically, a # means return NaN InvalidOperation.
186 # Different from a sNaN in trim
187
188 self.ChangeDict = {'precision' : self.change_precision,
189 'rounding' : self.change_rounding_method,
190 'maxexponent' : self.change_max_exponent,
191 'minexponent' : self.change_min_exponent,
192 'clamp' : self.change_clamp}
193
194 def tearDown(self):
195 """Cleaning up enviroment."""
196 # leaving context in original state
Raymond Hettingerbf440692004-07-10 14:14:37 +0000197 for key in DefaultContext.traps.keys():
198 DefaultContext.traps[key] = 0
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000199 return
200
201 def eval_file(self, file):
202 global skip_expected
203 if skip_expected:
204 raise TestSkipped
205 return
206 for line in open(file).xreadlines():
207 line = line.replace('\r\n', '').replace('\n', '')
Raymond Hettinger5aa478b2004-07-09 10:02:53 +0000208 #print line
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000209 try:
210 t = self.eval_line(line)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000211 except DecimalException, exception:
212 #Exception raised where there shoudn't have been one.
213 self.fail('Exception "'+exception.__class__.__name__ + '" raised on line '+line)
214
215 return
216
217 def eval_line(self, s):
218 if s.find(' -> ') >= 0 and s[:2] != '--' and not s.startswith(' --'):
219 s = (s.split('->')[0] + '->' +
220 s.split('->')[1].split('--')[0]).strip()
221 else:
222 s = s.split('--')[0].strip()
223
224 for ignore in self.ignore_list:
225 if s.find(ignore) >= 0:
226 #print s.split()[0], 'NotImplemented--', ignore
227 return
228 if not s:
229 return
230 elif ':' in s:
231 return self.eval_directive(s)
232 else:
233 return self.eval_equation(s)
234
235 def eval_directive(self, s):
236 funct, value = map(lambda x: x.strip().lower(), s.split(':'))
237 if funct == 'rounding':
238 value = RoundingDict[value]
239 else:
240 try:
241 value = int(value)
242 except ValueError:
243 pass
244
245 funct = self.ChangeDict.get(funct, Nonfunction)
246 funct(value)
247
248 def eval_equation(self, s):
249 #global DEFAULT_PRECISION
250 #print DEFAULT_PRECISION
Raymond Hettingered20ad82004-09-04 20:09:13 +0000251
252 if not TEST_ALL and random.random() < 0.90:
253 return
254
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000255 try:
256 Sides = s.split('->')
257 L = Sides[0].strip().split()
258 id = L[0]
Facundo Batista5dfc4802008-01-08 16:20:31 +0000259 if DEBUG:
260 print "Test ", id,
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000261 funct = L[1].lower()
262 valstemp = L[2:]
263 L = Sides[1].strip().split()
264 ans = L[0]
265 exceptions = L[1:]
266 except (TypeError, AttributeError, IndexError):
Raymond Hettingerd87ac8f2004-07-09 10:52:54 +0000267 raise InvalidOperation
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000268 def FixQuotes(val):
269 val = val.replace("''", 'SingleQuote').replace('""', 'DoubleQuote')
270 val = val.replace("'", '').replace('"', '')
271 val = val.replace('SingleQuote', "'").replace('DoubleQuote', '"')
272 return val
273 fname = nameAdapter.get(funct, funct)
274 if fname == 'rescale':
275 return
276 funct = getattr(self.context, fname)
277 vals = []
278 conglomerate = ''
279 quote = 0
280 theirexceptions = [ErrorNames[x.lower()] for x in exceptions]
281
Raymond Hettingerd9c0a7a2004-07-03 10:02:28 +0000282 for exception in Signals:
Raymond Hettingerbf440692004-07-10 14:14:37 +0000283 self.context.traps[exception] = 1 #Catch these bugs...
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000284 for exception in theirexceptions:
Raymond Hettingerbf440692004-07-10 14:14:37 +0000285 self.context.traps[exception] = 0
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000286 for i, val in enumerate(valstemp):
287 if val.count("'") % 2 == 1:
288 quote = 1 - quote
289 if quote:
290 conglomerate = conglomerate + ' ' + val
291 continue
292 else:
293 val = conglomerate + val
294 conglomerate = ''
295 v = FixQuotes(val)
296 if fname in ('to_sci_string', 'to_eng_string'):
297 if EXTENDEDERRORTEST:
298 for error in theirexceptions:
Raymond Hettingerbf440692004-07-10 14:14:37 +0000299 self.context.traps[error] = 1
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000300 try:
301 funct(self.context.create_decimal(v))
302 except error:
303 pass
Raymond Hettingerd9c0a7a2004-07-03 10:02:28 +0000304 except Signals, e:
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000305 self.fail("Raised %s in %s when %s disabled" % \
306 (e, s, error))
307 else:
308 self.fail("Did not raise %s in %s" % (error, s))
Raymond Hettingerbf440692004-07-10 14:14:37 +0000309 self.context.traps[error] = 0
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000310 v = self.context.create_decimal(v)
311 else:
Facundo Batista5dfc4802008-01-08 16:20:31 +0000312 v = Decimal(v, self.context)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000313 vals.append(v)
314
315 ans = FixQuotes(ans)
316
Facundo Batista5dfc4802008-01-08 16:20:31 +0000317 # skip tests that are related to bounds imposed in the decNumber
318 # reference implementation
319 if fname in decNumberRestricted:
320 if fname == 'power':
321 if not (vals[1]._isinteger() and
322 -1999999997 <= vals[1] <= 999999999):
323 if outside_decNumber_bounds(vals[0], self.context) or \
324 outside_decNumber_bounds(vals[1], self.context):
325 #print "Skipping test %s" % s
326 return
327 else:
328 if outside_decNumber_bounds(vals[0], self.context):
329 #print "Skipping test %s" % s
330 return
331
332
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000333 if EXTENDEDERRORTEST and fname not in ('to_sci_string', 'to_eng_string'):
334 for error in theirexceptions:
Raymond Hettingerbf440692004-07-10 14:14:37 +0000335 self.context.traps[error] = 1
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000336 try:
337 funct(*vals)
338 except error:
339 pass
Raymond Hettingerd9c0a7a2004-07-03 10:02:28 +0000340 except Signals, e:
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000341 self.fail("Raised %s in %s when %s disabled" % \
342 (e, s, error))
343 else:
344 self.fail("Did not raise %s in %s" % (error, s))
Raymond Hettingerbf440692004-07-10 14:14:37 +0000345 self.context.traps[error] = 0
Facundo Batista5dfc4802008-01-08 16:20:31 +0000346 if DEBUG:
347 print "--", self.context
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000348 try:
349 result = str(funct(*vals))
Facundo Batista5dfc4802008-01-08 16:20:31 +0000350 if fname in LOGICAL_FUNCTIONS:
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000351 result = str(int(eval(result))) # 'True', 'False' -> '1', '0'
Raymond Hettingerd9c0a7a2004-07-03 10:02:28 +0000352 except Signals, error:
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000353 self.fail("Raised %s in %s" % (error, s))
354 except: #Catch any error long enough to state the test case.
355 print "ERROR:", s
356 raise
357
358 myexceptions = self.getexceptions()
Raymond Hettingerbf440692004-07-10 14:14:37 +0000359 self.context.clear_flags()
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000360
361 myexceptions.sort()
362 theirexceptions.sort()
363
364 self.assertEqual(result, ans,
365 'Incorrect answer for ' + s + ' -- got ' + result)
366 self.assertEqual(myexceptions, theirexceptions,
Facundo Batista5dfc4802008-01-08 16:20:31 +0000367 'Incorrect flags set in ' + s + ' -- got ' + str(myexceptions))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000368 return
369
370 def getexceptions(self):
Raymond Hettingerf63ba432004-08-17 05:42:09 +0000371 return [e for e in Signals if self.context.flags[e]]
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000372
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000373 def change_precision(self, prec):
374 self.context.prec = prec
375 def change_rounding_method(self, rounding):
376 self.context.rounding = rounding
377 def change_min_exponent(self, exp):
378 self.context.Emin = exp
379 def change_max_exponent(self, exp):
380 self.context.Emax = exp
381 def change_clamp(self, clamp):
382 self.context._clamp = clamp
383
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000384
385
386# The following classes test the behaviour of Decimal according to PEP 327
387
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000388class DecimalExplicitConstructionTest(unittest.TestCase):
389 '''Unit tests for Explicit Construction cases of Decimal.'''
390
391 def test_explicit_empty(self):
392 self.assertEqual(Decimal(), Decimal("0"))
393
394 def test_explicit_from_None(self):
395 self.assertRaises(TypeError, Decimal, None)
396
397 def test_explicit_from_int(self):
398
399 #positive
400 d = Decimal(45)
401 self.assertEqual(str(d), '45')
402
403 #very large positive
404 d = Decimal(500000123)
405 self.assertEqual(str(d), '500000123')
406
407 #negative
408 d = Decimal(-45)
409 self.assertEqual(str(d), '-45')
410
411 #zero
412 d = Decimal(0)
413 self.assertEqual(str(d), '0')
414
415 def test_explicit_from_string(self):
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000416
417 #empty
418 self.assertEqual(str(Decimal('')), 'NaN')
419
420 #int
421 self.assertEqual(str(Decimal('45')), '45')
422
423 #float
424 self.assertEqual(str(Decimal('45.34')), '45.34')
425
426 #engineer notation
427 self.assertEqual(str(Decimal('45e2')), '4.5E+3')
428
429 #just not a number
430 self.assertEqual(str(Decimal('ugly')), 'NaN')
431
Mark Dickinsonbfdbfd42008-03-25 18:58:13 +0000432 #unicode strings should be permitted
433 self.assertEqual(str(Decimal(u'0E-017')), '0E-17')
434 self.assertEqual(str(Decimal(u'45')), '45')
435 self.assertEqual(str(Decimal(u'-Inf')), '-Infinity')
436 self.assertEqual(str(Decimal(u'NaN123')), 'NaN123')
437
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000438 def test_explicit_from_tuples(self):
439
440 #zero
441 d = Decimal( (0, (0,), 0) )
442 self.assertEqual(str(d), '0')
443
444 #int
445 d = Decimal( (1, (4, 5), 0) )
446 self.assertEqual(str(d), '-45')
447
448 #float
449 d = Decimal( (0, (4, 5, 3, 4), -2) )
450 self.assertEqual(str(d), '45.34')
451
452 #weird
453 d = Decimal( (1, (4, 3, 4, 9, 1, 3, 5, 3, 4), -25) )
454 self.assertEqual(str(d), '-4.34913534E-17')
455
456 #wrong number of items
457 self.assertRaises(ValueError, Decimal, (1, (4, 3, 4, 9, 1)) )
458
459 #bad sign
460 self.assertRaises(ValueError, Decimal, (8, (4, 3, 4, 9, 1), 2) )
Facundo Batista5dfc4802008-01-08 16:20:31 +0000461 self.assertRaises(ValueError, Decimal, (0., (4, 3, 4, 9, 1), 2) )
462 self.assertRaises(ValueError, Decimal, (Decimal(1), (4, 3, 4, 9, 1), 2))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000463
464 #bad exp
465 self.assertRaises(ValueError, Decimal, (1, (4, 3, 4, 9, 1), 'wrong!') )
Facundo Batista5dfc4802008-01-08 16:20:31 +0000466 self.assertRaises(ValueError, Decimal, (1, (4, 3, 4, 9, 1), 0.) )
467 self.assertRaises(ValueError, Decimal, (1, (4, 3, 4, 9, 1), '1') )
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000468
469 #bad coefficients
470 self.assertRaises(ValueError, Decimal, (1, (4, 3, 4, None, 1), 2) )
471 self.assertRaises(ValueError, Decimal, (1, (4, -3, 4, 9, 1), 2) )
Facundo Batista5dfc4802008-01-08 16:20:31 +0000472 self.assertRaises(ValueError, Decimal, (1, (4, 10, 4, 9, 1), 2) )
473 self.assertRaises(ValueError, Decimal, (1, (4, 3, 4, 'a', 1), 2) )
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000474
475 def test_explicit_from_Decimal(self):
476
477 #positive
478 d = Decimal(45)
479 e = Decimal(d)
480 self.assertEqual(str(e), '45')
481 self.assertNotEqual(id(d), id(e))
482
483 #very large positive
484 d = Decimal(500000123)
485 e = Decimal(d)
486 self.assertEqual(str(e), '500000123')
487 self.assertNotEqual(id(d), id(e))
488
489 #negative
490 d = Decimal(-45)
491 e = Decimal(d)
492 self.assertEqual(str(e), '-45')
493 self.assertNotEqual(id(d), id(e))
494
495 #zero
496 d = Decimal(0)
497 e = Decimal(d)
498 self.assertEqual(str(e), '0')
499 self.assertNotEqual(id(d), id(e))
500
501 def test_explicit_context_create_decimal(self):
502
503 nc = copy.copy(getcontext())
504 nc.prec = 3
505
506 # empty
Raymond Hettingerfed52962004-07-14 15:41:57 +0000507 d = Decimal()
508 self.assertEqual(str(d), '0')
509 d = nc.create_decimal()
510 self.assertEqual(str(d), '0')
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000511
512 # from None
513 self.assertRaises(TypeError, nc.create_decimal, None)
514
515 # from int
516 d = nc.create_decimal(456)
517 self.failUnless(isinstance(d, Decimal))
518 self.assertEqual(nc.create_decimal(45678),
519 nc.create_decimal('457E+2'))
520
521 # from string
522 d = Decimal('456789')
523 self.assertEqual(str(d), '456789')
524 d = nc.create_decimal('456789')
525 self.assertEqual(str(d), '4.57E+5')
526
527 # from tuples
528 d = Decimal( (1, (4, 3, 4, 9, 1, 3, 5, 3, 4), -25) )
529 self.assertEqual(str(d), '-4.34913534E-17')
530 d = nc.create_decimal( (1, (4, 3, 4, 9, 1, 3, 5, 3, 4), -25) )
531 self.assertEqual(str(d), '-4.35E-17')
532
533 # from Decimal
534 prevdec = Decimal(500000123)
535 d = Decimal(prevdec)
536 self.assertEqual(str(d), '500000123')
537 d = nc.create_decimal(prevdec)
538 self.assertEqual(str(d), '5.00E+8')
539
540
541class DecimalImplicitConstructionTest(unittest.TestCase):
542 '''Unit tests for Implicit Construction cases of Decimal.'''
543
544 def test_implicit_from_None(self):
545 self.assertRaises(TypeError, eval, 'Decimal(5) + None', globals())
546
547 def test_implicit_from_int(self):
548 #normal
549 self.assertEqual(str(Decimal(5) + 45), '50')
550 #exceeding precision
551 self.assertEqual(Decimal(5) + 123456789000, Decimal(123456789000))
552
553 def test_implicit_from_string(self):
554 self.assertRaises(TypeError, eval, 'Decimal(5) + "3"', globals())
555
556 def test_implicit_from_float(self):
557 self.assertRaises(TypeError, eval, 'Decimal(5) + 2.2', globals())
558
559 def test_implicit_from_Decimal(self):
560 self.assertEqual(Decimal(5) + Decimal(45), Decimal(50))
561
Raymond Hettinger267b8682005-03-27 10:47:39 +0000562 def test_rop(self):
563 # Allow other classes to be trained to interact with Decimals
564 class E:
565 def __divmod__(self, other):
566 return 'divmod ' + str(other)
567 def __rdivmod__(self, other):
568 return str(other) + ' rdivmod'
569 def __lt__(self, other):
570 return 'lt ' + str(other)
571 def __gt__(self, other):
572 return 'gt ' + str(other)
573 def __le__(self, other):
574 return 'le ' + str(other)
575 def __ge__(self, other):
576 return 'ge ' + str(other)
577 def __eq__(self, other):
578 return 'eq ' + str(other)
579 def __ne__(self, other):
580 return 'ne ' + str(other)
581
582 self.assertEqual(divmod(E(), Decimal(10)), 'divmod 10')
583 self.assertEqual(divmod(Decimal(10), E()), '10 rdivmod')
584 self.assertEqual(eval('Decimal(10) < E()'), 'gt 10')
585 self.assertEqual(eval('Decimal(10) > E()'), 'lt 10')
586 self.assertEqual(eval('Decimal(10) <= E()'), 'ge 10')
587 self.assertEqual(eval('Decimal(10) >= E()'), 'le 10')
588 self.assertEqual(eval('Decimal(10) == E()'), 'eq 10')
589 self.assertEqual(eval('Decimal(10) != E()'), 'ne 10')
590
591 # insert operator methods and then exercise them
Georg Brandl96c3f7f2006-03-28 08:06:35 +0000592 oplist = [
593 ('+', '__add__', '__radd__'),
594 ('-', '__sub__', '__rsub__'),
595 ('*', '__mul__', '__rmul__'),
596 ('%', '__mod__', '__rmod__'),
597 ('//', '__floordiv__', '__rfloordiv__'),
598 ('**', '__pow__', '__rpow__')
599 ]
600 if 1/2 == 0:
601 # testing with classic division, so add __div__
602 oplist.append(('/', '__div__', '__rdiv__'))
603 else:
604 # testing with -Qnew, so add __truediv__
605 oplist.append(('/', '__truediv__', '__rtruediv__'))
Anthony Baxter4ef3a232006-03-30 12:59:11 +0000606
Georg Brandl96c3f7f2006-03-28 08:06:35 +0000607 for sym, lop, rop in oplist:
Raymond Hettinger267b8682005-03-27 10:47:39 +0000608 setattr(E, lop, lambda self, other: 'str' + lop + str(other))
609 setattr(E, rop, lambda self, other: str(other) + rop + 'str')
610 self.assertEqual(eval('E()' + sym + 'Decimal(10)'),
611 'str' + lop + '10')
612 self.assertEqual(eval('Decimal(10)' + sym + 'E()'),
613 '10' + rop + 'str')
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000614
615class DecimalArithmeticOperatorsTest(unittest.TestCase):
616 '''Unit tests for all arithmetic operators, binary and unary.'''
617
618 def test_addition(self):
619
620 d1 = Decimal('-11.1')
621 d2 = Decimal('22.2')
622
623 #two Decimals
624 self.assertEqual(d1+d2, Decimal('11.1'))
625 self.assertEqual(d2+d1, Decimal('11.1'))
626
627 #with other type, left
628 c = d1 + 5
629 self.assertEqual(c, Decimal('-6.1'))
630 self.assertEqual(type(c), type(d1))
631
632 #with other type, right
633 c = 5 + d1
634 self.assertEqual(c, Decimal('-6.1'))
635 self.assertEqual(type(c), type(d1))
636
637 #inline with decimal
638 d1 += d2
639 self.assertEqual(d1, Decimal('11.1'))
640
641 #inline with other type
642 d1 += 5
643 self.assertEqual(d1, Decimal('16.1'))
644
645 def test_subtraction(self):
646
647 d1 = Decimal('-11.1')
648 d2 = Decimal('22.2')
649
650 #two Decimals
651 self.assertEqual(d1-d2, Decimal('-33.3'))
652 self.assertEqual(d2-d1, Decimal('33.3'))
653
654 #with other type, left
655 c = d1 - 5
656 self.assertEqual(c, Decimal('-16.1'))
657 self.assertEqual(type(c), type(d1))
658
659 #with other type, right
660 c = 5 - d1
661 self.assertEqual(c, Decimal('16.1'))
662 self.assertEqual(type(c), type(d1))
663
664 #inline with decimal
665 d1 -= d2
666 self.assertEqual(d1, Decimal('-33.3'))
667
668 #inline with other type
669 d1 -= 5
670 self.assertEqual(d1, Decimal('-38.3'))
671
672 def test_multiplication(self):
673
674 d1 = Decimal('-5')
675 d2 = Decimal('3')
676
677 #two Decimals
678 self.assertEqual(d1*d2, Decimal('-15'))
679 self.assertEqual(d2*d1, Decimal('-15'))
680
681 #with other type, left
682 c = d1 * 5
683 self.assertEqual(c, Decimal('-25'))
684 self.assertEqual(type(c), type(d1))
685
686 #with other type, right
687 c = 5 * d1
688 self.assertEqual(c, Decimal('-25'))
689 self.assertEqual(type(c), type(d1))
690
691 #inline with decimal
692 d1 *= d2
693 self.assertEqual(d1, Decimal('-15'))
694
695 #inline with other type
696 d1 *= 5
697 self.assertEqual(d1, Decimal('-75'))
698
699 def test_division(self):
700
701 d1 = Decimal('-5')
702 d2 = Decimal('2')
703
704 #two Decimals
705 self.assertEqual(d1/d2, Decimal('-2.5'))
706 self.assertEqual(d2/d1, Decimal('-0.4'))
707
708 #with other type, left
709 c = d1 / 4
710 self.assertEqual(c, Decimal('-1.25'))
711 self.assertEqual(type(c), type(d1))
712
713 #with other type, right
714 c = 4 / d1
715 self.assertEqual(c, Decimal('-0.8'))
716 self.assertEqual(type(c), type(d1))
717
718 #inline with decimal
719 d1 /= d2
720 self.assertEqual(d1, Decimal('-2.5'))
721
722 #inline with other type
723 d1 /= 4
724 self.assertEqual(d1, Decimal('-0.625'))
725
726 def test_floor_division(self):
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000727
728 d1 = Decimal('5')
729 d2 = Decimal('2')
730
731 #two Decimals
732 self.assertEqual(d1//d2, Decimal('2'))
733 self.assertEqual(d2//d1, Decimal('0'))
734
735 #with other type, left
736 c = d1 // 4
737 self.assertEqual(c, Decimal('1'))
738 self.assertEqual(type(c), type(d1))
739
740 #with other type, right
741 c = 7 // d1
742 self.assertEqual(c, Decimal('1'))
743 self.assertEqual(type(c), type(d1))
744
745 #inline with decimal
746 d1 //= d2
747 self.assertEqual(d1, Decimal('2'))
748
749 #inline with other type
750 d1 //= 2
751 self.assertEqual(d1, Decimal('1'))
752
753 def test_powering(self):
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000754
755 d1 = Decimal('5')
756 d2 = Decimal('2')
757
758 #two Decimals
759 self.assertEqual(d1**d2, Decimal('25'))
760 self.assertEqual(d2**d1, Decimal('32'))
761
762 #with other type, left
763 c = d1 ** 4
764 self.assertEqual(c, Decimal('625'))
765 self.assertEqual(type(c), type(d1))
766
767 #with other type, right
768 c = 7 ** d1
769 self.assertEqual(c, Decimal('16807'))
770 self.assertEqual(type(c), type(d1))
771
772 #inline with decimal
773 d1 **= d2
774 self.assertEqual(d1, Decimal('25'))
775
776 #inline with other type
777 d1 **= 4
778 self.assertEqual(d1, Decimal('390625'))
779
780 def test_module(self):
781
782 d1 = Decimal('5')
783 d2 = Decimal('2')
784
785 #two Decimals
786 self.assertEqual(d1%d2, Decimal('1'))
787 self.assertEqual(d2%d1, Decimal('2'))
788
789 #with other type, left
790 c = d1 % 4
791 self.assertEqual(c, Decimal('1'))
792 self.assertEqual(type(c), type(d1))
793
794 #with other type, right
795 c = 7 % d1
796 self.assertEqual(c, Decimal('2'))
797 self.assertEqual(type(c), type(d1))
798
799 #inline with decimal
800 d1 %= d2
801 self.assertEqual(d1, Decimal('1'))
802
803 #inline with other type
804 d1 %= 4
805 self.assertEqual(d1, Decimal('1'))
806
807 def test_floor_div_module(self):
808
809 d1 = Decimal('5')
810 d2 = Decimal('2')
811
812 #two Decimals
813 (p, q) = divmod(d1, d2)
814 self.assertEqual(p, Decimal('2'))
815 self.assertEqual(q, Decimal('1'))
816 self.assertEqual(type(p), type(d1))
817 self.assertEqual(type(q), type(d1))
818
819 #with other type, left
820 (p, q) = divmod(d1, 4)
821 self.assertEqual(p, Decimal('1'))
822 self.assertEqual(q, Decimal('1'))
823 self.assertEqual(type(p), type(d1))
824 self.assertEqual(type(q), type(d1))
825
826 #with other type, right
827 (p, q) = divmod(7, d1)
828 self.assertEqual(p, Decimal('1'))
829 self.assertEqual(q, Decimal('2'))
830 self.assertEqual(type(p), type(d1))
831 self.assertEqual(type(q), type(d1))
832
833 def test_unary_operators(self):
834 self.assertEqual(+Decimal(45), Decimal(+45)) # +
835 self.assertEqual(-Decimal(45), Decimal(-45)) # -
836 self.assertEqual(abs(Decimal(45)), abs(Decimal(-45))) # abs
837
838
839# The following are two functions used to test threading in the next class
840
841def thfunc1(cls):
842 d1 = Decimal(1)
843 d3 = Decimal(3)
844 cls.assertEqual(d1/d3, Decimal('0.333333333'))
845 cls.synchro.wait()
846 cls.assertEqual(d1/d3, Decimal('0.333333333'))
847 cls.finish1.set()
848 return
849
850def thfunc2(cls):
851 d1 = Decimal(1)
852 d3 = Decimal(3)
853 cls.assertEqual(d1/d3, Decimal('0.333333333'))
854 thiscontext = getcontext()
855 thiscontext.prec = 18
856 cls.assertEqual(d1/d3, Decimal('0.333333333333333333'))
857 cls.synchro.set()
858 cls.finish2.set()
859 return
860
861
862class DecimalUseOfContextTest(unittest.TestCase):
863 '''Unit tests for Use of Context cases in Decimal.'''
864
Raymond Hettinger7e71fa52004-12-18 19:07:19 +0000865 try:
866 import threading
867 except ImportError:
868 threading = None
869
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000870 # Take care executing this test from IDLE, there's an issue in threading
871 # that hangs IDLE and I couldn't find it
872
873 def test_threading(self):
874 #Test the "threading isolation" of a Context.
875
876 self.synchro = threading.Event()
877 self.finish1 = threading.Event()
878 self.finish2 = threading.Event()
879
880 th1 = threading.Thread(target=thfunc1, args=(self,))
881 th2 = threading.Thread(target=thfunc2, args=(self,))
882
883 th1.start()
884 th2.start()
885
886 self.finish1.wait()
Facundo Batista5dfc4802008-01-08 16:20:31 +0000887 self.finish2.wait()
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000888 return
889
Raymond Hettinger7e71fa52004-12-18 19:07:19 +0000890 if threading is None:
891 del test_threading
892
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000893
894class DecimalUsabilityTest(unittest.TestCase):
895 '''Unit tests for Usability cases of Decimal.'''
896
897 def test_comparison_operators(self):
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000898
899 da = Decimal('23.42')
900 db = Decimal('23.42')
901 dc = Decimal('45')
902
903 #two Decimals
904 self.failUnless(dc > da)
905 self.failUnless(dc >= da)
906 self.failUnless(da < dc)
907 self.failUnless(da <= dc)
908 self.failUnless(da == db)
909 self.failUnless(da != dc)
910 self.failUnless(da <= db)
911 self.failUnless(da >= db)
912 self.assertEqual(cmp(dc,da), 1)
913 self.assertEqual(cmp(da,dc), -1)
914 self.assertEqual(cmp(da,db), 0)
915
916 #a Decimal and an int
917 self.failUnless(dc > 23)
918 self.failUnless(23 < dc)
919 self.failUnless(dc == 45)
920 self.assertEqual(cmp(dc,23), 1)
921 self.assertEqual(cmp(23,dc), -1)
922 self.assertEqual(cmp(dc,45), 0)
923
924 #a Decimal and uncomparable
Raymond Hettinger0aeac102004-07-05 22:53:03 +0000925 self.assertNotEqual(da, 'ugly')
926 self.assertNotEqual(da, 32.7)
927 self.assertNotEqual(da, object())
928 self.assertNotEqual(da, object)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000929
Raymond Hettinger0aeac102004-07-05 22:53:03 +0000930 # sortable
931 a = map(Decimal, xrange(100))
932 b = a[:]
933 random.shuffle(a)
934 a.sort()
935 self.assertEqual(a, b)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000936
Facundo Batista5dfc4802008-01-08 16:20:31 +0000937 # with None
938 self.assertFalse(Decimal(1) < None)
939 self.assertTrue(Decimal(1) > None)
940
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000941 def test_copy_and_deepcopy_methods(self):
942 d = Decimal('43.24')
943 c = copy.copy(d)
944 self.assertEqual(id(c), id(d))
945 dc = copy.deepcopy(d)
946 self.assertEqual(id(dc), id(d))
947
948 def test_hash_method(self):
949 #just that it's hashable
950 hash(Decimal(23))
Facundo Batista5dfc4802008-01-08 16:20:31 +0000951
952 test_values = [Decimal(sign*(2**m + n))
953 for m in [0, 14, 15, 16, 17, 30, 31,
954 32, 33, 62, 63, 64, 65, 66]
955 for n in range(-10, 10)
956 for sign in [-1, 1]]
957 test_values.extend([
958 Decimal("-0"), # zeros
959 Decimal("0.00"),
960 Decimal("-0.000"),
961 Decimal("0E10"),
962 Decimal("-0E12"),
963 Decimal("10.0"), # negative exponent
964 Decimal("-23.00000"),
965 Decimal("1230E100"), # positive exponent
966 Decimal("-4.5678E50"),
967 # a value for which hash(n) != hash(n % (2**64-1))
968 # in Python pre-2.6
969 Decimal(2**64 + 2**32 - 1),
Mark Dickinsond77fedc2008-01-08 21:42:03 +0000970 # selection of values which fail with the Python 2.6
971 # version of Decimal.__hash__ and the Python 2.5
972 # version of long.__hash__. Included here to prevent
973 # an accidental backport of the Decimal.__hash__ from
974 # Python 2.6 to Python 2.5.
975 Decimal("1.634E100"),
976 Decimal("90.697E100"),
977 Decimal("188.83E100"),
978 Decimal("1652.9E100"),
979 Decimal("56531E100"),
Facundo Batista5dfc4802008-01-08 16:20:31 +0000980 ])
981
982 # check that hash(d) == hash(int(d)) for integral values
983 for value in test_values:
984 self.assertEqual(hash(value), hash(int(value)))
985
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000986 #the same hash that to an int
987 self.assertEqual(hash(Decimal(23)), hash(23))
Raymond Hettingerbea3f6f2005-03-15 04:59:17 +0000988 self.assertRaises(TypeError, hash, Decimal('NaN'))
989 self.assert_(hash(Decimal('Inf')))
990 self.assert_(hash(Decimal('-Inf')))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000991
Facundo Batista5dfc4802008-01-08 16:20:31 +0000992 # check that the value of the hash doesn't depend on the
993 # current context (issue #1757)
994 c = getcontext()
995 old_precision = c.prec
996 x = Decimal("123456789.1")
997
998 c.prec = 6
999 h1 = hash(x)
1000 c.prec = 10
1001 h2 = hash(x)
1002 c.prec = 16
1003 h3 = hash(x)
1004
1005 self.assertEqual(h1, h2)
1006 self.assertEqual(h1, h3)
1007 c.prec = old_precision
1008
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001009 def test_min_and_max_methods(self):
1010
1011 d1 = Decimal('15.32')
1012 d2 = Decimal('28.5')
1013 l1 = 15
1014 l2 = 28
1015
1016 #between Decimals
1017 self.failUnless(min(d1,d2) is d1)
1018 self.failUnless(min(d2,d1) is d1)
1019 self.failUnless(max(d1,d2) is d2)
1020 self.failUnless(max(d2,d1) is d2)
1021
1022 #between Decimal and long
1023 self.failUnless(min(d1,l2) is d1)
1024 self.failUnless(min(l2,d1) is d1)
1025 self.failUnless(max(l1,d2) is d2)
1026 self.failUnless(max(d2,l1) is d2)
1027
1028 def test_as_nonzero(self):
1029 #as false
1030 self.failIf(Decimal(0))
1031 #as true
1032 self.failUnless(Decimal('0.372'))
1033
1034 def test_tostring_methods(self):
1035 #Test str and repr methods.
1036
1037 d = Decimal('15.32')
1038 self.assertEqual(str(d), '15.32') # str
1039 self.assertEqual(repr(d), 'Decimal("15.32")') # repr
1040
Mark Dickinsonbfdbfd42008-03-25 18:58:13 +00001041 # result type of string methods should be str, not unicode
1042 unicode_inputs = [u'123.4', u'0.5E2', u'Infinity', u'sNaN',
1043 u'-0.0E100', u'-NaN001', u'-Inf']
1044
1045 for u in unicode_inputs:
1046 d = Decimal(u)
1047 self.assertEqual(type(str(d)), str)
1048 self.assertEqual(type(repr(d)), str)
1049 self.assertEqual(type(d.to_eng_string()), str)
1050
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001051 def test_tonum_methods(self):
1052 #Test float, int and long methods.
1053
1054 d1 = Decimal('66')
1055 d2 = Decimal('15.32')
1056
1057 #int
1058 self.assertEqual(int(d1), 66)
1059 self.assertEqual(int(d2), 15)
1060
1061 #long
1062 self.assertEqual(long(d1), 66)
1063 self.assertEqual(long(d2), 15)
1064
1065 #float
1066 self.assertEqual(float(d1), 66)
1067 self.assertEqual(float(d2), 15.32)
1068
1069 def test_eval_round_trip(self):
1070
1071 #with zero
1072 d = Decimal( (0, (0,), 0) )
1073 self.assertEqual(d, eval(repr(d)))
1074
1075 #int
1076 d = Decimal( (1, (4, 5), 0) )
1077 self.assertEqual(d, eval(repr(d)))
1078
1079 #float
1080 d = Decimal( (0, (4, 5, 3, 4), -2) )
1081 self.assertEqual(d, eval(repr(d)))
1082
1083 #weird
1084 d = Decimal( (1, (4, 3, 4, 9, 1, 3, 5, 3, 4), -25) )
1085 self.assertEqual(d, eval(repr(d)))
1086
1087 def test_as_tuple(self):
1088
1089 #with zero
1090 d = Decimal(0)
1091 self.assertEqual(d.as_tuple(), (0, (0,), 0) )
1092
1093 #int
1094 d = Decimal(-45)
1095 self.assertEqual(d.as_tuple(), (1, (4, 5), 0) )
1096
1097 #complicated string
1098 d = Decimal("-4.34913534E-17")
1099 self.assertEqual(d.as_tuple(), (1, (4, 3, 4, 9, 1, 3, 5, 3, 4), -25) )
1100
1101 #inf
1102 d = Decimal("Infinity")
1103 self.assertEqual(d.as_tuple(), (0, (0,), 'F') )
1104
Facundo Batista5dfc4802008-01-08 16:20:31 +00001105 #leading zeros in coefficient should be stripped
1106 d = Decimal( (0, (0, 0, 4, 0, 5, 3, 4), -2) )
1107 self.assertEqual(d.as_tuple(), (0, (4, 0, 5, 3, 4), -2) )
1108 d = Decimal( (1, (0, 0, 0), 37) )
1109 self.assertEqual(d.as_tuple(), (1, (0,), 37))
1110 d = Decimal( (1, (), 37) )
1111 self.assertEqual(d.as_tuple(), (1, (0,), 37))
1112
1113 #leading zeros in NaN diagnostic info should be stripped
1114 d = Decimal( (0, (0, 0, 4, 0, 5, 3, 4), 'n') )
1115 self.assertEqual(d.as_tuple(), (0, (4, 0, 5, 3, 4), 'n') )
1116 d = Decimal( (1, (0, 0, 0), 'N') )
1117 self.assertEqual(d.as_tuple(), (1, (), 'N') )
1118 d = Decimal( (1, (), 'n') )
1119 self.assertEqual(d.as_tuple(), (1, (), 'n') )
1120
1121 #coefficient in infinity should be ignored
1122 d = Decimal( (0, (4, 5, 3, 4), 'F') )
1123 self.assertEqual(d.as_tuple(), (0, (0,), 'F'))
1124 d = Decimal( (1, (0, 2, 7, 1), 'F') )
1125 self.assertEqual(d.as_tuple(), (1, (0,), 'F'))
1126
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001127 def test_immutability_operations(self):
1128 # Do operations and check that it didn't change change internal objects.
1129
1130 d1 = Decimal('-25e55')
1131 b1 = Decimal('-25e55')
Facundo Batista5dfc4802008-01-08 16:20:31 +00001132 d2 = Decimal('33e+33')
1133 b2 = Decimal('33e+33')
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001134
1135 def checkSameDec(operation, useOther=False):
1136 if useOther:
1137 eval("d1." + operation + "(d2)")
1138 self.assertEqual(d1._sign, b1._sign)
1139 self.assertEqual(d1._int, b1._int)
1140 self.assertEqual(d1._exp, b1._exp)
1141 self.assertEqual(d2._sign, b2._sign)
1142 self.assertEqual(d2._int, b2._int)
1143 self.assertEqual(d2._exp, b2._exp)
1144 else:
1145 eval("d1." + operation + "()")
1146 self.assertEqual(d1._sign, b1._sign)
1147 self.assertEqual(d1._int, b1._int)
1148 self.assertEqual(d1._exp, b1._exp)
1149 return
1150
1151 Decimal(d1)
1152 self.assertEqual(d1._sign, b1._sign)
1153 self.assertEqual(d1._int, b1._int)
1154 self.assertEqual(d1._exp, b1._exp)
1155
1156 checkSameDec("__abs__")
1157 checkSameDec("__add__", True)
1158 checkSameDec("__div__", True)
1159 checkSameDec("__divmod__", True)
1160 checkSameDec("__cmp__", True)
1161 checkSameDec("__float__")
1162 checkSameDec("__floordiv__", True)
1163 checkSameDec("__hash__")
1164 checkSameDec("__int__")
1165 checkSameDec("__long__")
1166 checkSameDec("__mod__", True)
1167 checkSameDec("__mul__", True)
1168 checkSameDec("__neg__")
1169 checkSameDec("__nonzero__")
1170 checkSameDec("__pos__")
1171 checkSameDec("__pow__", True)
1172 checkSameDec("__radd__", True)
1173 checkSameDec("__rdiv__", True)
1174 checkSameDec("__rdivmod__", True)
1175 checkSameDec("__repr__")
1176 checkSameDec("__rfloordiv__", True)
1177 checkSameDec("__rmod__", True)
1178 checkSameDec("__rmul__", True)
1179 checkSameDec("__rpow__", True)
1180 checkSameDec("__rsub__", True)
1181 checkSameDec("__str__")
1182 checkSameDec("__sub__", True)
1183 checkSameDec("__truediv__", True)
1184 checkSameDec("adjusted")
1185 checkSameDec("as_tuple")
1186 checkSameDec("compare", True)
1187 checkSameDec("max", True)
1188 checkSameDec("min", True)
1189 checkSameDec("normalize")
1190 checkSameDec("quantize", True)
1191 checkSameDec("remainder_near", True)
1192 checkSameDec("same_quantum", True)
1193 checkSameDec("sqrt")
1194 checkSameDec("to_eng_string")
1195 checkSameDec("to_integral")
1196
Facundo Batista5dfc4802008-01-08 16:20:31 +00001197 def test_subclassing(self):
1198 # Different behaviours when subclassing Decimal
1199
1200 class MyDecimal(Decimal):
1201 pass
1202
1203 d1 = MyDecimal(1)
1204 d2 = MyDecimal(2)
1205 d = d1 + d2
1206 self.assertTrue(type(d) is Decimal)
1207
1208 d = d1.max(d2)
1209 self.assertTrue(type(d) is Decimal)
1210
Mark Dickinson26c25d92008-03-25 14:35:25 +00001211 def test_implicit_context(self):
1212 # Check results when context given implicitly. (Issue 2478)
1213 c = getcontext()
1214 self.assertEqual(str(Decimal(0).sqrt()),
1215 str(c.sqrt(Decimal(0))))
1216
Facundo Batista5dfc4802008-01-08 16:20:31 +00001217
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001218class DecimalPythonAPItests(unittest.TestCase):
1219
1220 def test_pickle(self):
1221 d = Decimal('-3.141590000')
1222 p = pickle.dumps(d)
1223 e = pickle.loads(p)
1224 self.assertEqual(d, e)
1225
Raymond Hettinger5548be22004-07-05 18:49:38 +00001226 def test_int(self):
Raymond Hettinger605ed022004-11-24 07:28:48 +00001227 for x in range(-250, 250):
1228 s = '%0.2f' % (x / 100.0)
Raymond Hettinger5548be22004-07-05 18:49:38 +00001229 # should work the same as for floats
1230 self.assertEqual(int(Decimal(s)), int(float(s)))
Raymond Hettinger605ed022004-11-24 07:28:48 +00001231 # should work the same as to_integral in the ROUND_DOWN mode
Raymond Hettinger5548be22004-07-05 18:49:38 +00001232 d = Decimal(s)
Raymond Hettinger605ed022004-11-24 07:28:48 +00001233 r = d.to_integral(ROUND_DOWN)
Raymond Hettinger5548be22004-07-05 18:49:38 +00001234 self.assertEqual(Decimal(int(d)), r)
1235
Raymond Hettingerd9c0a7a2004-07-03 10:02:28 +00001236class ContextAPItests(unittest.TestCase):
1237
1238 def test_pickle(self):
1239 c = Context()
1240 e = pickle.loads(pickle.dumps(c))
1241 for k in vars(c):
1242 v1 = vars(c)[k]
1243 v2 = vars(e)[k]
1244 self.assertEqual(v1, v2)
1245
Raymond Hettinger0aeac102004-07-05 22:53:03 +00001246 def test_equality_with_other_types(self):
1247 self.assert_(Decimal(10) in ['a', 1.0, Decimal(10), (1,2), {}])
1248 self.assert_(Decimal(10) not in ['a', 1.0, (1,2), {}])
1249
Raymond Hettinger955d2b22004-08-08 20:17:45 +00001250 def test_copy(self):
1251 # All copies should be deep
1252 c = Context()
1253 d = c.copy()
1254 self.assertNotEqual(id(c), id(d))
1255 self.assertNotEqual(id(c.flags), id(d.flags))
1256 self.assertNotEqual(id(c.traps), id(d.traps))
1257
Nick Coghlanc48daf52006-09-03 01:08:30 +00001258class WithStatementTest(unittest.TestCase):
1259 # Can't do these as docstrings until Python 2.6
1260 # as doctest can't handle __future__ statements
1261
1262 def test_localcontext(self):
1263 # Use a copy of the current context in the block
1264 orig_ctx = getcontext()
1265 with localcontext() as enter_ctx:
1266 set_ctx = getcontext()
1267 final_ctx = getcontext()
1268 self.assert_(orig_ctx is final_ctx, 'did not restore context correctly')
1269 self.assert_(orig_ctx is not set_ctx, 'did not copy the context')
1270 self.assert_(set_ctx is enter_ctx, '__enter__ returned wrong context')
1271
1272 def test_localcontextarg(self):
1273 # Use a copy of the supplied context in the block
1274 orig_ctx = getcontext()
1275 new_ctx = Context(prec=42)
1276 with localcontext(new_ctx) as enter_ctx:
1277 set_ctx = getcontext()
1278 final_ctx = getcontext()
1279 self.assert_(orig_ctx is final_ctx, 'did not restore context correctly')
1280 self.assert_(set_ctx.prec == new_ctx.prec, 'did not set correct context')
1281 self.assert_(new_ctx is not set_ctx, 'did not copy the context')
1282 self.assert_(set_ctx is enter_ctx, '__enter__ returned wrong context')
1283
Facundo Batista5dfc4802008-01-08 16:20:31 +00001284class ContextFlags(unittest.TestCase):
1285 def test_flags_irrelevant(self):
1286 # check that the result (numeric result + flags raised) of an
1287 # arithmetic operation doesn't depend on the current flags
1288
1289 context = Context(prec=9, Emin = -999999999, Emax = 999999999,
1290 rounding=ROUND_HALF_EVEN, traps=[], flags=[])
1291
1292 # operations that raise various flags, in the form (function, arglist)
1293 operations = [
1294 (context._apply, [Decimal("100E-1000000009")]),
1295 (context.sqrt, [Decimal(2)]),
1296 (context.add, [Decimal("1.23456789"), Decimal("9.87654321")]),
1297 (context.multiply, [Decimal("1.23456789"), Decimal("9.87654321")]),
1298 (context.subtract, [Decimal("1.23456789"), Decimal("9.87654321")]),
1299 ]
1300
1301 # try various flags individually, then a whole lot at once
1302 flagsets = [[Inexact], [Rounded], [Underflow], [Clamped], [Subnormal],
1303 [Inexact, Rounded, Underflow, Clamped, Subnormal]]
1304
1305 for fn, args in operations:
1306 # find answer and flags raised using a clean context
1307 context.clear_flags()
1308 ans = fn(*args)
1309 flags = [k for k, v in context.flags.items() if v]
1310
1311 for extra_flags in flagsets:
1312 # set flags, before calling operation
1313 context.clear_flags()
1314 for flag in extra_flags:
1315 context._raise_error(flag)
1316 new_ans = fn(*args)
1317
1318 # flags that we expect to be set after the operation
1319 expected_flags = list(flags)
1320 for flag in extra_flags:
1321 if flag not in expected_flags:
1322 expected_flags.append(flag)
1323 expected_flags.sort()
1324
1325 # flags we actually got
1326 new_flags = [k for k,v in context.flags.items() if v]
1327 new_flags.sort()
1328
1329 self.assertEqual(ans, new_ans,
1330 "operation produces different answers depending on flags set: " +
1331 "expected %s, got %s." % (ans, new_ans))
1332 self.assertEqual(new_flags, expected_flags,
1333 "operation raises different flags depending on flags set: " +
1334 "expected %s, got %s" % (expected_flags, new_flags))
1335
1336def test_main(arith=False, verbose=None, todo_tests=None, debug=None):
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001337 """ Execute the tests.
1338
Raymond Hettingered20ad82004-09-04 20:09:13 +00001339 Runs all arithmetic tests if arith is True or if the "decimal" resource
1340 is enabled in regrtest.py
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001341 """
Raymond Hettingered20ad82004-09-04 20:09:13 +00001342
Neal Norwitzce4a9c92006-04-09 08:36:46 +00001343 init()
Facundo Batista5dfc4802008-01-08 16:20:31 +00001344 global TEST_ALL, DEBUG
Raymond Hettingered20ad82004-09-04 20:09:13 +00001345 TEST_ALL = arith or is_resource_enabled('decimal')
Facundo Batista5dfc4802008-01-08 16:20:31 +00001346 DEBUG = debug
Raymond Hettingered20ad82004-09-04 20:09:13 +00001347
Facundo Batista5dfc4802008-01-08 16:20:31 +00001348 if todo_tests is None:
1349 test_classes = [
1350 DecimalExplicitConstructionTest,
1351 DecimalImplicitConstructionTest,
1352 DecimalArithmeticOperatorsTest,
1353 DecimalUseOfContextTest,
1354 DecimalUsabilityTest,
1355 DecimalPythonAPItests,
1356 ContextAPItests,
1357 DecimalTest,
1358 WithStatementTest,
1359 ContextFlags
1360 ]
1361 else:
1362 test_classes = [DecimalTest]
1363
1364 # Dynamically build custom test definition for each file in the test
1365 # directory and add the definitions to the DecimalTest class. This
1366 # procedure insures that new files do not get skipped.
1367 for filename in os.listdir(directory):
1368 if '.decTest' not in filename or filename.startswith("."):
1369 continue
1370 head, tail = filename.split('.')
1371 if todo_tests is not None and head not in todo_tests:
1372 continue
1373 tester = lambda self, f=filename: self.eval_file(directory + f)
1374 setattr(DecimalTest, 'test_' + head, tester)
1375 del filename, head, tail, tester
1376
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001377
Tim Peters46cc7022006-03-31 04:11:16 +00001378 try:
1379 run_unittest(*test_classes)
Facundo Batista5dfc4802008-01-08 16:20:31 +00001380 if todo_tests is None:
1381 import decimal as DecimalModule
1382 run_doctest(DecimalModule, verbose)
Tim Peters46cc7022006-03-31 04:11:16 +00001383 finally:
1384 setcontext(ORIGINAL_CONTEXT)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001385
1386if __name__ == '__main__':
Facundo Batista5dfc4802008-01-08 16:20:31 +00001387 import optparse
1388 p = optparse.OptionParser("test_decimal.py [--debug] [{--skip | test1 [test2 [...]]}]")
1389 p.add_option('--debug', '-d', action='store_true', help='shows the test number and context before each test')
1390 p.add_option('--skip', '-s', action='store_true', help='skip over 90% of the arithmetic tests')
1391 (opt, args) = p.parse_args()
1392
1393 if opt.skip:
1394 test_main(arith=False, verbose=True)
1395 elif args:
1396 test_main(arith=True, verbose=True, todo_tests=args, debug=opt.debug)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001397 else:
Facundo Batista5dfc4802008-01-08 16:20:31 +00001398 test_main(arith=True, verbose=True)