blob: 03cff604bb0a1b3e2d0211b0a909879e418a6d29 [file] [log] [blame]
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001# Copyright (c) 2004 Python Software Foundation.
2# All rights reserved.
3
4# Written by Eric Price <eprice at tjhsst.edu>
5# and Facundo Batista <facundo at taniquetil.com.ar>
6# and Raymond Hettinger <python at rcn.com>
7# and Aahz (aahz at pobox.com)
8# and Tim Peters
9
10"""
11These are the test cases for the Decimal module.
12
13There are two groups of tests, Arithmetic and Behaviour. The former test
14the Decimal arithmetic using the tests provided by Mike Cowlishaw. The latter
15test the pythonic behaviour according to PEP 327.
16
17Cowlishaw's tests can be downloaded from:
18
19 www2.hursley.ibm.com/decimal/dectest.zip
20
21This test module can be called from command line with one parameter (Arithmetic
22or Behaviour) to test each part, or without parameter to test both parts. If
23you're working through IDLE, you can import this test module and call test_main()
24with the corresponding argument.
25"""
Nick Coghlan8b6999b2006-08-31 12:00:43 +000026from __future__ import with_statement
Raymond Hettinger7c85fa42004-07-01 11:01:35 +000027
Raymond Hettinger7c85fa42004-07-01 11:01:35 +000028import 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 Batista353750c2007-09-13 18:13:15 +000093 'up' : ROUND_UP,
94 '05up' : ROUND_05UP}
Raymond Hettinger7c85fa42004-07-01 11:01:35 +000095
96# Name adapter to be able to change the Decimal and Context
97# interface without changing the test files from Cowlishaw
Facundo Batista1a191df2007-10-02 17:01:24 +000098nameAdapter = {'and':'logical_and',
Raymond Hettinger7c85fa42004-07-01 11:01:35 +000099 'apply':'_apply',
Facundo Batista353750c2007-09-13 18:13:15 +0000100 'class':'number_class',
101 'comparesig':'compare_signal',
102 'comparetotal':'compare_total',
103 'comparetotmag':'compare_total_mag',
Facundo Batista353750c2007-09-13 18:13:15 +0000104 'copy':'copy_decimal',
Facundo Batista1a191df2007-10-02 17:01:24 +0000105 'copyabs':'copy_abs',
Facundo Batista353750c2007-09-13 18:13:15 +0000106 'copynegate':'copy_negate',
107 'copysign':'copy_sign',
Facundo Batista1a191df2007-10-02 17:01:24 +0000108 'divideint':'divide_int',
Facundo Batista353750c2007-09-13 18:13:15 +0000109 'invert':'logical_invert',
Facundo Batista1a191df2007-10-02 17:01:24 +0000110 'iscanonical':'is_canonical',
111 'isfinite':'is_finite',
112 'isinfinite':'is_infinite',
113 'isnan':'is_nan',
114 'isnormal':'is_normal',
115 'isqnan':'is_qnan',
116 'issigned':'is_signed',
117 'issnan':'is_snan',
118 'issubnormal':'is_subnormal',
119 'iszero':'is_zero',
Facundo Batista353750c2007-09-13 18:13:15 +0000120 'maxmag':'max_mag',
121 'minmag':'min_mag',
122 'nextminus':'next_minus',
123 'nextplus':'next_plus',
124 'nexttoward':'next_toward',
Facundo Batista1a191df2007-10-02 17:01:24 +0000125 'or':'logical_or',
Facundo Batista353750c2007-09-13 18:13:15 +0000126 'reduce':'normalize',
Facundo Batista1a191df2007-10-02 17:01:24 +0000127 'remaindernear':'remainder_near',
128 'samequantum':'same_quantum',
129 'squareroot':'sqrt',
130 'toeng':'to_eng_string',
131 'tointegral':'to_integral_value',
132 'tointegralx':'to_integral_exact',
133 'tosci':'to_sci_string',
134 'xor':'logical_xor',
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000135 }
136
Facundo Batista1a191df2007-10-02 17:01:24 +0000137# The following functions return True/False rather than a Decimal instance
138
139LOGICAL_FUNCTIONS = (
140 'is_canonical',
141 'is_finite',
142 'is_infinite',
143 'is_nan',
144 'is_normal',
145 'is_qnan',
146 'is_signed',
147 'is_snan',
148 'is_subnormal',
149 'is_zero',
150 'same_quantum',
151 )
152
Facundo Batista353750c2007-09-13 18:13:15 +0000153# For some operations (currently exp, ln, log10, power), the decNumber
154# reference implementation imposes additional restrictions on the
155# context and operands. These restrictions are not part of the
156# specification; however, the effect of these restrictions does show
157# up in some of the testcases. We skip testcases that violate these
158# restrictions, since Decimal behaves differently from decNumber for
159# these testcases so these testcases would otherwise fail.
160
161decNumberRestricted = ('power', 'ln', 'log10', 'exp')
162DEC_MAX_MATH = 999999
163def outside_decNumber_bounds(v, context):
164 if (context.prec > DEC_MAX_MATH or
165 context.Emax > DEC_MAX_MATH or
166 -context.Emin > DEC_MAX_MATH):
167 return True
168 if not v._is_special and v and (
169 len(v._int) > DEC_MAX_MATH or
170 v.adjusted() > DEC_MAX_MATH or
171 v.adjusted() < 1-2*DEC_MAX_MATH):
172 return True
173 return False
174
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000175class DecimalTest(unittest.TestCase):
176 """Class which tests the Decimal class against the test cases.
177
178 Changed for unittest.
179 """
180 def setUp(self):
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000181 self.context = Context()
Raymond Hettingerbf440692004-07-10 14:14:37 +0000182 for key in DefaultContext.traps.keys():
183 DefaultContext.traps[key] = 1
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000184 self.ignore_list = ['#']
185 # Basically, a # means return NaN InvalidOperation.
186 # Different from a sNaN in trim
187
188 self.ChangeDict = {'precision' : self.change_precision,
189 'rounding' : self.change_rounding_method,
190 'maxexponent' : self.change_max_exponent,
191 'minexponent' : self.change_min_exponent,
192 'clamp' : self.change_clamp}
193
194 def tearDown(self):
195 """Cleaning up enviroment."""
196 # leaving context in original state
Raymond Hettingerbf440692004-07-10 14:14:37 +0000197 for key in DefaultContext.traps.keys():
198 DefaultContext.traps[key] = 0
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000199 return
200
201 def eval_file(self, file):
202 global skip_expected
203 if skip_expected:
204 raise TestSkipped
205 return
206 for line in open(file).xreadlines():
207 line = line.replace('\r\n', '').replace('\n', '')
Raymond Hettinger5aa478b2004-07-09 10:02:53 +0000208 #print line
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000209 try:
210 t = self.eval_line(line)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000211 except DecimalException, exception:
212 #Exception raised where there shoudn't have been one.
213 self.fail('Exception "'+exception.__class__.__name__ + '" raised on line '+line)
214
215 return
216
217 def eval_line(self, s):
218 if s.find(' -> ') >= 0 and s[:2] != '--' and not s.startswith(' --'):
219 s = (s.split('->')[0] + '->' +
220 s.split('->')[1].split('--')[0]).strip()
221 else:
222 s = s.split('--')[0].strip()
223
224 for ignore in self.ignore_list:
225 if s.find(ignore) >= 0:
226 #print s.split()[0], 'NotImplemented--', ignore
227 return
228 if not s:
229 return
230 elif ':' in s:
231 return self.eval_directive(s)
232 else:
233 return self.eval_equation(s)
234
235 def eval_directive(self, s):
236 funct, value = map(lambda x: x.strip().lower(), s.split(':'))
237 if funct == 'rounding':
238 value = RoundingDict[value]
239 else:
240 try:
241 value = int(value)
242 except ValueError:
243 pass
244
245 funct = self.ChangeDict.get(funct, Nonfunction)
246 funct(value)
247
248 def eval_equation(self, s):
249 #global DEFAULT_PRECISION
250 #print DEFAULT_PRECISION
Raymond Hettingered20ad82004-09-04 20:09:13 +0000251
252 if not TEST_ALL and random.random() < 0.90:
253 return
254
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000255 try:
256 Sides = s.split('->')
257 L = Sides[0].strip().split()
258 id = L[0]
Facundo Batista353750c2007-09-13 18:13:15 +0000259 if DEBUG:
260 print "Test ", id,
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000261 funct = L[1].lower()
262 valstemp = L[2:]
263 L = Sides[1].strip().split()
264 ans = L[0]
265 exceptions = L[1:]
266 except (TypeError, AttributeError, IndexError):
Raymond Hettingerd87ac8f2004-07-09 10:52:54 +0000267 raise InvalidOperation
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000268 def FixQuotes(val):
269 val = val.replace("''", 'SingleQuote').replace('""', 'DoubleQuote')
270 val = val.replace("'", '').replace('"', '')
271 val = val.replace('SingleQuote', "'").replace('DoubleQuote', '"')
272 return val
273 fname = nameAdapter.get(funct, funct)
274 if fname == 'rescale':
275 return
276 funct = getattr(self.context, fname)
277 vals = []
278 conglomerate = ''
279 quote = 0
280 theirexceptions = [ErrorNames[x.lower()] for x in exceptions]
281
Raymond Hettingerd9c0a7a2004-07-03 10:02:28 +0000282 for exception in Signals:
Raymond Hettingerbf440692004-07-10 14:14:37 +0000283 self.context.traps[exception] = 1 #Catch these bugs...
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000284 for exception in theirexceptions:
Raymond Hettingerbf440692004-07-10 14:14:37 +0000285 self.context.traps[exception] = 0
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000286 for i, val in enumerate(valstemp):
287 if val.count("'") % 2 == 1:
288 quote = 1 - quote
289 if quote:
290 conglomerate = conglomerate + ' ' + val
291 continue
292 else:
293 val = conglomerate + val
294 conglomerate = ''
295 v = FixQuotes(val)
296 if fname in ('to_sci_string', 'to_eng_string'):
297 if EXTENDEDERRORTEST:
298 for error in theirexceptions:
Raymond Hettingerbf440692004-07-10 14:14:37 +0000299 self.context.traps[error] = 1
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000300 try:
301 funct(self.context.create_decimal(v))
302 except error:
303 pass
Raymond Hettingerd9c0a7a2004-07-03 10:02:28 +0000304 except Signals, e:
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000305 self.fail("Raised %s in %s when %s disabled" % \
306 (e, s, error))
307 else:
308 self.fail("Did not raise %s in %s" % (error, s))
Raymond Hettingerbf440692004-07-10 14:14:37 +0000309 self.context.traps[error] = 0
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000310 v = self.context.create_decimal(v)
311 else:
Facundo Batista353750c2007-09-13 18:13:15 +0000312 v = Decimal(v, self.context)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000313 vals.append(v)
314
315 ans = FixQuotes(ans)
316
Facundo Batista353750c2007-09-13 18:13:15 +0000317 # skip tests that are related to bounds imposed in the decNumber
318 # reference implementation
319 if fname in decNumberRestricted:
320 if fname == 'power':
321 if not (vals[1]._isinteger() and
322 -1999999997 <= vals[1] <= 999999999):
323 if outside_decNumber_bounds(vals[0], self.context) or \
324 outside_decNumber_bounds(vals[1], self.context):
325 #print "Skipping test %s" % s
326 return
327 else:
328 if outside_decNumber_bounds(vals[0], self.context):
329 #print "Skipping test %s" % s
330 return
331
332
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000333 if EXTENDEDERRORTEST and fname not in ('to_sci_string', 'to_eng_string'):
334 for error in theirexceptions:
Raymond Hettingerbf440692004-07-10 14:14:37 +0000335 self.context.traps[error] = 1
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000336 try:
337 funct(*vals)
338 except error:
339 pass
Raymond Hettingerd9c0a7a2004-07-03 10:02:28 +0000340 except Signals, e:
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000341 self.fail("Raised %s in %s when %s disabled" % \
342 (e, s, error))
343 else:
344 self.fail("Did not raise %s in %s" % (error, s))
Raymond Hettingerbf440692004-07-10 14:14:37 +0000345 self.context.traps[error] = 0
Facundo Batista353750c2007-09-13 18:13:15 +0000346 if DEBUG:
347 print "--", self.context
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000348 try:
349 result = str(funct(*vals))
Facundo Batista1a191df2007-10-02 17:01:24 +0000350 if fname in LOGICAL_FUNCTIONS:
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000351 result = str(int(eval(result))) # 'True', 'False' -> '1', '0'
Raymond Hettingerd9c0a7a2004-07-03 10:02:28 +0000352 except Signals, error:
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000353 self.fail("Raised %s in %s" % (error, s))
354 except: #Catch any error long enough to state the test case.
355 print "ERROR:", s
356 raise
357
358 myexceptions = self.getexceptions()
Raymond Hettingerbf440692004-07-10 14:14:37 +0000359 self.context.clear_flags()
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000360
361 myexceptions.sort()
362 theirexceptions.sort()
363
364 self.assertEqual(result, ans,
365 'Incorrect answer for ' + s + ' -- got ' + result)
366 self.assertEqual(myexceptions, theirexceptions,
Facundo Batista353750c2007-09-13 18:13:15 +0000367 'Incorrect flags set in ' + s + ' -- got ' + str(myexceptions))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000368 return
369
370 def getexceptions(self):
Raymond Hettingerf63ba432004-08-17 05:42:09 +0000371 return [e for e in Signals if self.context.flags[e]]
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000372
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000373 def change_precision(self, prec):
374 self.context.prec = prec
375 def change_rounding_method(self, rounding):
376 self.context.rounding = rounding
377 def change_min_exponent(self, exp):
378 self.context.Emin = exp
379 def change_max_exponent(self, exp):
380 self.context.Emax = exp
381 def change_clamp(self, clamp):
382 self.context._clamp = clamp
383
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000384
385
386# The following classes test the behaviour of Decimal according to PEP 327
387
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000388class DecimalExplicitConstructionTest(unittest.TestCase):
389 '''Unit tests for Explicit Construction cases of Decimal.'''
390
391 def test_explicit_empty(self):
392 self.assertEqual(Decimal(), Decimal("0"))
393
394 def test_explicit_from_None(self):
395 self.assertRaises(TypeError, Decimal, None)
396
397 def test_explicit_from_int(self):
398
399 #positive
400 d = Decimal(45)
401 self.assertEqual(str(d), '45')
402
403 #very large positive
404 d = Decimal(500000123)
405 self.assertEqual(str(d), '500000123')
406
407 #negative
408 d = Decimal(-45)
409 self.assertEqual(str(d), '-45')
410
411 #zero
412 d = Decimal(0)
413 self.assertEqual(str(d), '0')
414
415 def test_explicit_from_string(self):
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000416
417 #empty
418 self.assertEqual(str(Decimal('')), 'NaN')
419
420 #int
421 self.assertEqual(str(Decimal('45')), '45')
422
423 #float
424 self.assertEqual(str(Decimal('45.34')), '45.34')
425
426 #engineer notation
427 self.assertEqual(str(Decimal('45e2')), '4.5E+3')
428
429 #just not a number
430 self.assertEqual(str(Decimal('ugly')), 'NaN')
431
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) )
Facundo Batista9b5e2312007-10-19 19:25:57 +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!') )
Facundo Batista9b5e2312007-10-19 19:25:57 +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) )
Facundo Batista9b5e2312007-10-19 19:25:57 +0000466 self.assertRaises(ValueError, Decimal, (1, (4, 10, 4, 9, 1), 2) )
Facundo Batista72bc54f2007-11-23 17:59:00 +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
Georg Brandl96c3f7f2006-03-28 08:06:35 +0000586 oplist = [
587 ('+', '__add__', '__radd__'),
588 ('-', '__sub__', '__rsub__'),
589 ('*', '__mul__', '__rmul__'),
590 ('%', '__mod__', '__rmod__'),
591 ('//', '__floordiv__', '__rfloordiv__'),
592 ('**', '__pow__', '__rpow__')
593 ]
594 if 1/2 == 0:
595 # testing with classic division, so add __div__
596 oplist.append(('/', '__div__', '__rdiv__'))
597 else:
598 # testing with -Qnew, so add __truediv__
599 oplist.append(('/', '__truediv__', '__rtruediv__'))
Anthony Baxter4ef3a232006-03-30 12:59:11 +0000600
Georg Brandl96c3f7f2006-03-28 08:06:35 +0000601 for sym, lop, rop in oplist:
Raymond Hettinger267b8682005-03-27 10:47:39 +0000602 setattr(E, lop, lambda self, other: 'str' + lop + str(other))
603 setattr(E, rop, lambda self, other: str(other) + rop + 'str')
604 self.assertEqual(eval('E()' + sym + 'Decimal(10)'),
605 'str' + lop + '10')
606 self.assertEqual(eval('Decimal(10)' + sym + 'E()'),
607 '10' + rop + 'str')
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000608
609class DecimalArithmeticOperatorsTest(unittest.TestCase):
610 '''Unit tests for all arithmetic operators, binary and unary.'''
611
612 def test_addition(self):
613
614 d1 = Decimal('-11.1')
615 d2 = Decimal('22.2')
616
617 #two Decimals
618 self.assertEqual(d1+d2, Decimal('11.1'))
619 self.assertEqual(d2+d1, Decimal('11.1'))
620
621 #with other type, left
622 c = d1 + 5
623 self.assertEqual(c, Decimal('-6.1'))
624 self.assertEqual(type(c), type(d1))
625
626 #with other type, right
627 c = 5 + d1
628 self.assertEqual(c, Decimal('-6.1'))
629 self.assertEqual(type(c), type(d1))
630
631 #inline with decimal
632 d1 += d2
633 self.assertEqual(d1, Decimal('11.1'))
634
635 #inline with other type
636 d1 += 5
637 self.assertEqual(d1, Decimal('16.1'))
638
639 def test_subtraction(self):
640
641 d1 = Decimal('-11.1')
642 d2 = Decimal('22.2')
643
644 #two Decimals
645 self.assertEqual(d1-d2, Decimal('-33.3'))
646 self.assertEqual(d2-d1, Decimal('33.3'))
647
648 #with other type, left
649 c = d1 - 5
650 self.assertEqual(c, Decimal('-16.1'))
651 self.assertEqual(type(c), type(d1))
652
653 #with other type, right
654 c = 5 - d1
655 self.assertEqual(c, Decimal('16.1'))
656 self.assertEqual(type(c), type(d1))
657
658 #inline with decimal
659 d1 -= d2
660 self.assertEqual(d1, Decimal('-33.3'))
661
662 #inline with other type
663 d1 -= 5
664 self.assertEqual(d1, Decimal('-38.3'))
665
666 def test_multiplication(self):
667
668 d1 = Decimal('-5')
669 d2 = Decimal('3')
670
671 #two Decimals
672 self.assertEqual(d1*d2, Decimal('-15'))
673 self.assertEqual(d2*d1, Decimal('-15'))
674
675 #with other type, left
676 c = d1 * 5
677 self.assertEqual(c, Decimal('-25'))
678 self.assertEqual(type(c), type(d1))
679
680 #with other type, right
681 c = 5 * d1
682 self.assertEqual(c, Decimal('-25'))
683 self.assertEqual(type(c), type(d1))
684
685 #inline with decimal
686 d1 *= d2
687 self.assertEqual(d1, Decimal('-15'))
688
689 #inline with other type
690 d1 *= 5
691 self.assertEqual(d1, Decimal('-75'))
692
693 def test_division(self):
694
695 d1 = Decimal('-5')
696 d2 = Decimal('2')
697
698 #two Decimals
699 self.assertEqual(d1/d2, Decimal('-2.5'))
700 self.assertEqual(d2/d1, Decimal('-0.4'))
701
702 #with other type, left
703 c = d1 / 4
704 self.assertEqual(c, Decimal('-1.25'))
705 self.assertEqual(type(c), type(d1))
706
707 #with other type, right
708 c = 4 / d1
709 self.assertEqual(c, Decimal('-0.8'))
710 self.assertEqual(type(c), type(d1))
711
712 #inline with decimal
713 d1 /= d2
714 self.assertEqual(d1, Decimal('-2.5'))
715
716 #inline with other type
717 d1 /= 4
718 self.assertEqual(d1, Decimal('-0.625'))
719
720 def test_floor_division(self):
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000721
722 d1 = Decimal('5')
723 d2 = Decimal('2')
724
725 #two Decimals
726 self.assertEqual(d1//d2, Decimal('2'))
727 self.assertEqual(d2//d1, Decimal('0'))
728
729 #with other type, left
730 c = d1 // 4
731 self.assertEqual(c, Decimal('1'))
732 self.assertEqual(type(c), type(d1))
733
734 #with other type, right
735 c = 7 // d1
736 self.assertEqual(c, Decimal('1'))
737 self.assertEqual(type(c), type(d1))
738
739 #inline with decimal
740 d1 //= d2
741 self.assertEqual(d1, Decimal('2'))
742
743 #inline with other type
744 d1 //= 2
745 self.assertEqual(d1, Decimal('1'))
746
747 def test_powering(self):
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000748
749 d1 = Decimal('5')
750 d2 = Decimal('2')
751
752 #two Decimals
753 self.assertEqual(d1**d2, Decimal('25'))
754 self.assertEqual(d2**d1, Decimal('32'))
755
756 #with other type, left
757 c = d1 ** 4
758 self.assertEqual(c, Decimal('625'))
759 self.assertEqual(type(c), type(d1))
760
761 #with other type, right
762 c = 7 ** d1
763 self.assertEqual(c, Decimal('16807'))
764 self.assertEqual(type(c), type(d1))
765
766 #inline with decimal
767 d1 **= d2
768 self.assertEqual(d1, Decimal('25'))
769
770 #inline with other type
771 d1 **= 4
772 self.assertEqual(d1, Decimal('390625'))
773
774 def test_module(self):
775
776 d1 = Decimal('5')
777 d2 = Decimal('2')
778
779 #two Decimals
780 self.assertEqual(d1%d2, Decimal('1'))
781 self.assertEqual(d2%d1, Decimal('2'))
782
783 #with other type, left
784 c = d1 % 4
785 self.assertEqual(c, Decimal('1'))
786 self.assertEqual(type(c), type(d1))
787
788 #with other type, right
789 c = 7 % d1
790 self.assertEqual(c, Decimal('2'))
791 self.assertEqual(type(c), type(d1))
792
793 #inline with decimal
794 d1 %= d2
795 self.assertEqual(d1, Decimal('1'))
796
797 #inline with other type
798 d1 %= 4
799 self.assertEqual(d1, Decimal('1'))
800
801 def test_floor_div_module(self):
802
803 d1 = Decimal('5')
804 d2 = Decimal('2')
805
806 #two Decimals
807 (p, q) = divmod(d1, d2)
808 self.assertEqual(p, Decimal('2'))
809 self.assertEqual(q, Decimal('1'))
810 self.assertEqual(type(p), type(d1))
811 self.assertEqual(type(q), type(d1))
812
813 #with other type, left
814 (p, q) = divmod(d1, 4)
815 self.assertEqual(p, Decimal('1'))
816 self.assertEqual(q, Decimal('1'))
817 self.assertEqual(type(p), type(d1))
818 self.assertEqual(type(q), type(d1))
819
820 #with other type, right
821 (p, q) = divmod(7, d1)
822 self.assertEqual(p, Decimal('1'))
823 self.assertEqual(q, Decimal('2'))
824 self.assertEqual(type(p), type(d1))
825 self.assertEqual(type(q), type(d1))
826
827 def test_unary_operators(self):
828 self.assertEqual(+Decimal(45), Decimal(+45)) # +
829 self.assertEqual(-Decimal(45), Decimal(-45)) # -
830 self.assertEqual(abs(Decimal(45)), abs(Decimal(-45))) # abs
831
832
833# The following are two functions used to test threading in the next class
834
835def thfunc1(cls):
836 d1 = Decimal(1)
837 d3 = Decimal(3)
838 cls.assertEqual(d1/d3, Decimal('0.333333333'))
839 cls.synchro.wait()
840 cls.assertEqual(d1/d3, Decimal('0.333333333'))
841 cls.finish1.set()
842 return
843
844def thfunc2(cls):
845 d1 = Decimal(1)
846 d3 = Decimal(3)
847 cls.assertEqual(d1/d3, Decimal('0.333333333'))
848 thiscontext = getcontext()
849 thiscontext.prec = 18
850 cls.assertEqual(d1/d3, Decimal('0.333333333333333333'))
851 cls.synchro.set()
852 cls.finish2.set()
853 return
854
855
856class DecimalUseOfContextTest(unittest.TestCase):
857 '''Unit tests for Use of Context cases in Decimal.'''
858
Raymond Hettinger7e71fa52004-12-18 19:07:19 +0000859 try:
860 import threading
861 except ImportError:
862 threading = None
863
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000864 # Take care executing this test from IDLE, there's an issue in threading
865 # that hangs IDLE and I couldn't find it
866
867 def test_threading(self):
868 #Test the "threading isolation" of a Context.
869
870 self.synchro = threading.Event()
871 self.finish1 = threading.Event()
872 self.finish2 = threading.Event()
873
874 th1 = threading.Thread(target=thfunc1, args=(self,))
875 th2 = threading.Thread(target=thfunc2, args=(self,))
876
877 th1.start()
878 th2.start()
879
880 self.finish1.wait()
Thomas Woutersb3e6e8c2007-09-19 17:27:29 +0000881 self.finish2.wait()
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000882 return
883
Raymond Hettinger7e71fa52004-12-18 19:07:19 +0000884 if threading is None:
885 del test_threading
886
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000887
888class DecimalUsabilityTest(unittest.TestCase):
889 '''Unit tests for Usability cases of Decimal.'''
890
891 def test_comparison_operators(self):
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000892
893 da = Decimal('23.42')
894 db = Decimal('23.42')
895 dc = Decimal('45')
896
897 #two Decimals
898 self.failUnless(dc > da)
899 self.failUnless(dc >= da)
900 self.failUnless(da < dc)
901 self.failUnless(da <= dc)
902 self.failUnless(da == db)
903 self.failUnless(da != dc)
904 self.failUnless(da <= db)
905 self.failUnless(da >= db)
906 self.assertEqual(cmp(dc,da), 1)
907 self.assertEqual(cmp(da,dc), -1)
908 self.assertEqual(cmp(da,db), 0)
909
910 #a Decimal and an int
911 self.failUnless(dc > 23)
912 self.failUnless(23 < dc)
913 self.failUnless(dc == 45)
914 self.assertEqual(cmp(dc,23), 1)
915 self.assertEqual(cmp(23,dc), -1)
916 self.assertEqual(cmp(dc,45), 0)
917
918 #a Decimal and uncomparable
Raymond Hettinger0aeac102004-07-05 22:53:03 +0000919 self.assertNotEqual(da, 'ugly')
920 self.assertNotEqual(da, 32.7)
921 self.assertNotEqual(da, object())
922 self.assertNotEqual(da, object)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000923
Raymond Hettinger0aeac102004-07-05 22:53:03 +0000924 # sortable
925 a = map(Decimal, xrange(100))
926 b = a[:]
927 random.shuffle(a)
928 a.sort()
929 self.assertEqual(a, b)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000930
Facundo Batista353750c2007-09-13 18:13:15 +0000931 # with None
932 self.assertFalse(Decimal(1) < None)
933 self.assertTrue(Decimal(1) > None)
934
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000935 def test_copy_and_deepcopy_methods(self):
936 d = Decimal('43.24')
937 c = copy.copy(d)
938 self.assertEqual(id(c), id(d))
939 dc = copy.deepcopy(d)
940 self.assertEqual(id(dc), id(d))
941
942 def test_hash_method(self):
943 #just that it's hashable
944 hash(Decimal(23))
Facundo Batista8c202442007-09-19 17:53:25 +0000945
946 test_values = [Decimal(sign*(2**m + n))
947 for m in [0, 14, 15, 16, 17, 30, 31,
948 32, 33, 62, 63, 64, 65, 66]
949 for n in range(-10, 10)
950 for sign in [-1, 1]]
951 test_values.extend([
952 Decimal("-0"), # zeros
953 Decimal("0.00"),
954 Decimal("-0.000"),
955 Decimal("0E10"),
956 Decimal("-0E12"),
957 Decimal("10.0"), # negative exponent
958 Decimal("-23.00000"),
959 Decimal("1230E100"), # positive exponent
960 Decimal("-4.5678E50"),
961 # a value for which hash(n) != hash(n % (2**64-1))
962 # in Python pre-2.6
963 Decimal(2**64 + 2**32 - 1),
964 # selection of values which fail with the old (before
965 # version 2.6) long.__hash__
966 Decimal("1.634E100"),
967 Decimal("90.697E100"),
968 Decimal("188.83E100"),
969 Decimal("1652.9E100"),
970 Decimal("56531E100"),
971 ])
972
973 # check that hash(d) == hash(int(d)) for integral values
974 for value in test_values:
975 self.assertEqual(hash(value), hash(int(value)))
976
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000977 #the same hash that to an int
978 self.assertEqual(hash(Decimal(23)), hash(23))
Raymond Hettingerbea3f6f2005-03-15 04:59:17 +0000979 self.assertRaises(TypeError, hash, Decimal('NaN'))
980 self.assert_(hash(Decimal('Inf')))
981 self.assert_(hash(Decimal('-Inf')))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000982
Facundo Batista52b25792008-01-08 12:25:20 +0000983 # check that the value of the hash doesn't depend on the
984 # current context (issue #1757)
985 c = getcontext()
986 old_precision = c.prec
987 x = Decimal("123456789.1")
988
989 c.prec = 6
990 h1 = hash(x)
991 c.prec = 10
992 h2 = hash(x)
993 c.prec = 16
994 h3 = hash(x)
995
996 self.assertEqual(h1, h2)
997 self.assertEqual(h1, h3)
998 c.prec = old_precision
999
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001000 def test_min_and_max_methods(self):
1001
1002 d1 = Decimal('15.32')
1003 d2 = Decimal('28.5')
1004 l1 = 15
1005 l2 = 28
1006
1007 #between Decimals
1008 self.failUnless(min(d1,d2) is d1)
1009 self.failUnless(min(d2,d1) is d1)
1010 self.failUnless(max(d1,d2) is d2)
1011 self.failUnless(max(d2,d1) is d2)
1012
1013 #between Decimal and long
1014 self.failUnless(min(d1,l2) is d1)
1015 self.failUnless(min(l2,d1) is d1)
1016 self.failUnless(max(l1,d2) is d2)
1017 self.failUnless(max(d2,l1) is d2)
1018
1019 def test_as_nonzero(self):
1020 #as false
1021 self.failIf(Decimal(0))
1022 #as true
1023 self.failUnless(Decimal('0.372'))
1024
1025 def test_tostring_methods(self):
1026 #Test str and repr methods.
1027
1028 d = Decimal('15.32')
1029 self.assertEqual(str(d), '15.32') # str
1030 self.assertEqual(repr(d), 'Decimal("15.32")') # repr
1031
1032 def test_tonum_methods(self):
1033 #Test float, int and long methods.
1034
1035 d1 = Decimal('66')
1036 d2 = Decimal('15.32')
1037
1038 #int
1039 self.assertEqual(int(d1), 66)
1040 self.assertEqual(int(d2), 15)
1041
1042 #long
1043 self.assertEqual(long(d1), 66)
1044 self.assertEqual(long(d2), 15)
1045
1046 #float
1047 self.assertEqual(float(d1), 66)
1048 self.assertEqual(float(d2), 15.32)
1049
1050 def test_eval_round_trip(self):
1051
1052 #with zero
1053 d = Decimal( (0, (0,), 0) )
1054 self.assertEqual(d, eval(repr(d)))
1055
1056 #int
1057 d = Decimal( (1, (4, 5), 0) )
1058 self.assertEqual(d, eval(repr(d)))
1059
1060 #float
1061 d = Decimal( (0, (4, 5, 3, 4), -2) )
1062 self.assertEqual(d, eval(repr(d)))
1063
1064 #weird
1065 d = Decimal( (1, (4, 3, 4, 9, 1, 3, 5, 3, 4), -25) )
1066 self.assertEqual(d, eval(repr(d)))
1067
1068 def test_as_tuple(self):
1069
1070 #with zero
1071 d = Decimal(0)
1072 self.assertEqual(d.as_tuple(), (0, (0,), 0) )
1073
1074 #int
1075 d = Decimal(-45)
1076 self.assertEqual(d.as_tuple(), (1, (4, 5), 0) )
1077
1078 #complicated string
1079 d = Decimal("-4.34913534E-17")
1080 self.assertEqual(d.as_tuple(), (1, (4, 3, 4, 9, 1, 3, 5, 3, 4), -25) )
1081
1082 #inf
1083 d = Decimal("Infinity")
1084 self.assertEqual(d.as_tuple(), (0, (0,), 'F') )
1085
Facundo Batista9b5e2312007-10-19 19:25:57 +00001086 #leading zeros in coefficient should be stripped
1087 d = Decimal( (0, (0, 0, 4, 0, 5, 3, 4), -2) )
1088 self.assertEqual(d.as_tuple(), (0, (4, 0, 5, 3, 4), -2) )
1089 d = Decimal( (1, (0, 0, 0), 37) )
1090 self.assertEqual(d.as_tuple(), (1, (0,), 37))
1091 d = Decimal( (1, (), 37) )
1092 self.assertEqual(d.as_tuple(), (1, (0,), 37))
1093
1094 #leading zeros in NaN diagnostic info should be stripped
1095 d = Decimal( (0, (0, 0, 4, 0, 5, 3, 4), 'n') )
1096 self.assertEqual(d.as_tuple(), (0, (4, 0, 5, 3, 4), 'n') )
1097 d = Decimal( (1, (0, 0, 0), 'N') )
1098 self.assertEqual(d.as_tuple(), (1, (), 'N') )
1099 d = Decimal( (1, (), 'n') )
1100 self.assertEqual(d.as_tuple(), (1, (), 'n') )
1101
1102 #coefficient in infinity should be ignored
1103 d = Decimal( (0, (4, 5, 3, 4), 'F') )
1104 self.assertEqual(d.as_tuple(), (0, (0,), 'F'))
1105 d = Decimal( (1, (0, 2, 7, 1), 'F') )
1106 self.assertEqual(d.as_tuple(), (1, (0,), 'F'))
1107
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001108 def test_immutability_operations(self):
1109 # Do operations and check that it didn't change change internal objects.
1110
1111 d1 = Decimal('-25e55')
1112 b1 = Decimal('-25e55')
Facundo Batista353750c2007-09-13 18:13:15 +00001113 d2 = Decimal('33e+33')
1114 b2 = Decimal('33e+33')
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001115
1116 def checkSameDec(operation, useOther=False):
1117 if useOther:
1118 eval("d1." + operation + "(d2)")
1119 self.assertEqual(d1._sign, b1._sign)
1120 self.assertEqual(d1._int, b1._int)
1121 self.assertEqual(d1._exp, b1._exp)
1122 self.assertEqual(d2._sign, b2._sign)
1123 self.assertEqual(d2._int, b2._int)
1124 self.assertEqual(d2._exp, b2._exp)
1125 else:
1126 eval("d1." + operation + "()")
1127 self.assertEqual(d1._sign, b1._sign)
1128 self.assertEqual(d1._int, b1._int)
1129 self.assertEqual(d1._exp, b1._exp)
1130 return
1131
1132 Decimal(d1)
1133 self.assertEqual(d1._sign, b1._sign)
1134 self.assertEqual(d1._int, b1._int)
1135 self.assertEqual(d1._exp, b1._exp)
1136
1137 checkSameDec("__abs__")
1138 checkSameDec("__add__", True)
1139 checkSameDec("__div__", True)
1140 checkSameDec("__divmod__", True)
1141 checkSameDec("__cmp__", True)
1142 checkSameDec("__float__")
1143 checkSameDec("__floordiv__", True)
1144 checkSameDec("__hash__")
1145 checkSameDec("__int__")
1146 checkSameDec("__long__")
1147 checkSameDec("__mod__", True)
1148 checkSameDec("__mul__", True)
1149 checkSameDec("__neg__")
1150 checkSameDec("__nonzero__")
1151 checkSameDec("__pos__")
1152 checkSameDec("__pow__", True)
1153 checkSameDec("__radd__", True)
1154 checkSameDec("__rdiv__", True)
1155 checkSameDec("__rdivmod__", True)
1156 checkSameDec("__repr__")
1157 checkSameDec("__rfloordiv__", True)
1158 checkSameDec("__rmod__", True)
1159 checkSameDec("__rmul__", True)
1160 checkSameDec("__rpow__", True)
1161 checkSameDec("__rsub__", True)
1162 checkSameDec("__str__")
1163 checkSameDec("__sub__", True)
1164 checkSameDec("__truediv__", True)
1165 checkSameDec("adjusted")
1166 checkSameDec("as_tuple")
1167 checkSameDec("compare", True)
1168 checkSameDec("max", True)
1169 checkSameDec("min", True)
1170 checkSameDec("normalize")
1171 checkSameDec("quantize", True)
1172 checkSameDec("remainder_near", True)
1173 checkSameDec("same_quantum", True)
1174 checkSameDec("sqrt")
1175 checkSameDec("to_eng_string")
1176 checkSameDec("to_integral")
1177
Facundo Batista6c398da2007-09-17 17:30:13 +00001178 def test_subclassing(self):
1179 # Different behaviours when subclassing Decimal
1180
1181 class MyDecimal(Decimal):
1182 pass
1183
1184 d1 = MyDecimal(1)
1185 d2 = MyDecimal(2)
1186 d = d1 + d2
1187 self.assertTrue(type(d) is Decimal)
1188
1189 d = d1.max(d2)
1190 self.assertTrue(type(d) is Decimal)
1191
1192
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001193class DecimalPythonAPItests(unittest.TestCase):
1194
1195 def test_pickle(self):
1196 d = Decimal('-3.141590000')
1197 p = pickle.dumps(d)
1198 e = pickle.loads(p)
1199 self.assertEqual(d, e)
1200
Raymond Hettinger5548be22004-07-05 18:49:38 +00001201 def test_int(self):
Raymond Hettinger605ed022004-11-24 07:28:48 +00001202 for x in range(-250, 250):
1203 s = '%0.2f' % (x / 100.0)
Raymond Hettinger5548be22004-07-05 18:49:38 +00001204 # should work the same as for floats
1205 self.assertEqual(int(Decimal(s)), int(float(s)))
Raymond Hettinger605ed022004-11-24 07:28:48 +00001206 # should work the same as to_integral in the ROUND_DOWN mode
Raymond Hettinger5548be22004-07-05 18:49:38 +00001207 d = Decimal(s)
Raymond Hettinger605ed022004-11-24 07:28:48 +00001208 r = d.to_integral(ROUND_DOWN)
Raymond Hettinger5548be22004-07-05 18:49:38 +00001209 self.assertEqual(Decimal(int(d)), r)
1210
Raymond Hettingerd9c0a7a2004-07-03 10:02:28 +00001211class ContextAPItests(unittest.TestCase):
1212
1213 def test_pickle(self):
1214 c = Context()
1215 e = pickle.loads(pickle.dumps(c))
1216 for k in vars(c):
1217 v1 = vars(c)[k]
1218 v2 = vars(e)[k]
1219 self.assertEqual(v1, v2)
1220
Raymond Hettinger0aeac102004-07-05 22:53:03 +00001221 def test_equality_with_other_types(self):
1222 self.assert_(Decimal(10) in ['a', 1.0, Decimal(10), (1,2), {}])
1223 self.assert_(Decimal(10) not in ['a', 1.0, (1,2), {}])
1224
Raymond Hettinger955d2b22004-08-08 20:17:45 +00001225 def test_copy(self):
1226 # All copies should be deep
1227 c = Context()
1228 d = c.copy()
1229 self.assertNotEqual(id(c), id(d))
1230 self.assertNotEqual(id(c.flags), id(d.flags))
1231 self.assertNotEqual(id(c.traps), id(d.traps))
1232
Nick Coghlan8b6999b2006-08-31 12:00:43 +00001233class WithStatementTest(unittest.TestCase):
1234 # Can't do these as docstrings until Python 2.6
1235 # as doctest can't handle __future__ statements
Nick Coghlan8b6999b2006-08-31 12:00:43 +00001236
1237 def test_localcontext(self):
Nick Coghlanced12182006-09-02 03:54:17 +00001238 # Use a copy of the current context in the block
Nick Coghlan8b6999b2006-08-31 12:00:43 +00001239 orig_ctx = getcontext()
1240 with localcontext() as enter_ctx:
1241 set_ctx = getcontext()
1242 final_ctx = getcontext()
1243 self.assert_(orig_ctx is final_ctx, 'did not restore context correctly')
1244 self.assert_(orig_ctx is not set_ctx, 'did not copy the context')
1245 self.assert_(set_ctx is enter_ctx, '__enter__ returned wrong context')
1246
1247 def test_localcontextarg(self):
Nick Coghlanced12182006-09-02 03:54:17 +00001248 # Use a copy of the supplied context in the block
Nick Coghlan8b6999b2006-08-31 12:00:43 +00001249 orig_ctx = getcontext()
1250 new_ctx = Context(prec=42)
1251 with localcontext(new_ctx) as enter_ctx:
1252 set_ctx = getcontext()
1253 final_ctx = getcontext()
1254 self.assert_(orig_ctx is final_ctx, 'did not restore context correctly')
1255 self.assert_(set_ctx.prec == new_ctx.prec, 'did not set correct context')
1256 self.assert_(new_ctx is not set_ctx, 'did not copy the context')
1257 self.assert_(set_ctx is enter_ctx, '__enter__ returned wrong context')
1258
Facundo Batista353750c2007-09-13 18:13:15 +00001259class ContextFlags(unittest.TestCase):
1260 def test_flags_irrelevant(self):
1261 # check that the result (numeric result + flags raised) of an
1262 # arithmetic operation doesn't depend on the current flags
1263
1264 context = Context(prec=9, Emin = -999999999, Emax = 999999999,
1265 rounding=ROUND_HALF_EVEN, traps=[], flags=[])
1266
1267 # operations that raise various flags, in the form (function, arglist)
1268 operations = [
1269 (context._apply, [Decimal("100E-1000000009")]),
1270 (context.sqrt, [Decimal(2)]),
1271 (context.add, [Decimal("1.23456789"), Decimal("9.87654321")]),
1272 (context.multiply, [Decimal("1.23456789"), Decimal("9.87654321")]),
1273 (context.subtract, [Decimal("1.23456789"), Decimal("9.87654321")]),
1274 ]
1275
1276 # try various flags individually, then a whole lot at once
1277 flagsets = [[Inexact], [Rounded], [Underflow], [Clamped], [Subnormal],
1278 [Inexact, Rounded, Underflow, Clamped, Subnormal]]
1279
1280 for fn, args in operations:
1281 # find answer and flags raised using a clean context
1282 context.clear_flags()
1283 ans = fn(*args)
1284 flags = [k for k, v in context.flags.items() if v]
1285
1286 for extra_flags in flagsets:
1287 # set flags, before calling operation
1288 context.clear_flags()
1289 for flag in extra_flags:
1290 context._raise_error(flag)
1291 new_ans = fn(*args)
1292
1293 # flags that we expect to be set after the operation
1294 expected_flags = list(flags)
1295 for flag in extra_flags:
1296 if flag not in expected_flags:
1297 expected_flags.append(flag)
1298 expected_flags.sort()
1299
1300 # flags we actually got
1301 new_flags = [k for k,v in context.flags.items() if v]
1302 new_flags.sort()
1303
1304 self.assertEqual(ans, new_ans,
1305 "operation produces different answers depending on flags set: " +
1306 "expected %s, got %s." % (ans, new_ans))
1307 self.assertEqual(new_flags, expected_flags,
1308 "operation raises different flags depending on flags set: " +
1309 "expected %s, got %s" % (expected_flags, new_flags))
1310
1311def test_main(arith=False, verbose=None, todo_tests=None, debug=None):
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001312 """ Execute the tests.
1313
Raymond Hettingered20ad82004-09-04 20:09:13 +00001314 Runs all arithmetic tests if arith is True or if the "decimal" resource
1315 is enabled in regrtest.py
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001316 """
Raymond Hettingered20ad82004-09-04 20:09:13 +00001317
Neal Norwitzce4a9c92006-04-09 08:36:46 +00001318 init()
Facundo Batista353750c2007-09-13 18:13:15 +00001319 global TEST_ALL, DEBUG
Raymond Hettingered20ad82004-09-04 20:09:13 +00001320 TEST_ALL = arith or is_resource_enabled('decimal')
Facundo Batista353750c2007-09-13 18:13:15 +00001321 DEBUG = debug
Raymond Hettingered20ad82004-09-04 20:09:13 +00001322
Facundo Batista353750c2007-09-13 18:13:15 +00001323 if todo_tests is None:
1324 test_classes = [
1325 DecimalExplicitConstructionTest,
1326 DecimalImplicitConstructionTest,
1327 DecimalArithmeticOperatorsTest,
1328 DecimalUseOfContextTest,
1329 DecimalUsabilityTest,
1330 DecimalPythonAPItests,
1331 ContextAPItests,
1332 DecimalTest,
1333 WithStatementTest,
1334 ContextFlags
1335 ]
1336 else:
1337 test_classes = [DecimalTest]
1338
1339 # Dynamically build custom test definition for each file in the test
1340 # directory and add the definitions to the DecimalTest class. This
1341 # procedure insures that new files do not get skipped.
1342 for filename in os.listdir(directory):
1343 if '.decTest' not in filename or filename.startswith("."):
1344 continue
1345 head, tail = filename.split('.')
1346 if todo_tests is not None and head not in todo_tests:
1347 continue
1348 tester = lambda self, f=filename: self.eval_file(directory + f)
1349 setattr(DecimalTest, 'test_' + head, tester)
1350 del filename, head, tail, tester
1351
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001352
Tim Peters46cc7022006-03-31 04:11:16 +00001353 try:
1354 run_unittest(*test_classes)
Facundo Batista353750c2007-09-13 18:13:15 +00001355 if todo_tests is None:
1356 import decimal as DecimalModule
1357 run_doctest(DecimalModule, verbose)
Tim Peters46cc7022006-03-31 04:11:16 +00001358 finally:
1359 setcontext(ORIGINAL_CONTEXT)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001360
1361if __name__ == '__main__':
Facundo Batista353750c2007-09-13 18:13:15 +00001362 import optparse
1363 p = optparse.OptionParser("test_decimal.py [--debug] [{--skip | test1 [test2 [...]]}]")
1364 p.add_option('--debug', '-d', action='store_true', help='shows the test number and context before each test')
1365 p.add_option('--skip', '-s', action='store_true', help='skip over 90% of the arithmetic tests')
1366 (opt, args) = p.parse_args()
1367
1368 if opt.skip:
1369 test_main(arith=False, verbose=True)
1370 elif args:
1371 test_main(arith=True, verbose=True, todo_tests=args, debug=opt.debug)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001372 else:
Facundo Batista353750c2007-09-13 18:13:15 +00001373 test_main(arith=True, verbose=True)