blob: 27d1aa618c6e56d4bc444e5f7933516eab3be64e [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) )
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000467
468 def test_explicit_from_Decimal(self):
469
470 #positive
471 d = Decimal(45)
472 e = Decimal(d)
473 self.assertEqual(str(e), '45')
474 self.assertNotEqual(id(d), id(e))
475
476 #very large positive
477 d = Decimal(500000123)
478 e = Decimal(d)
479 self.assertEqual(str(e), '500000123')
480 self.assertNotEqual(id(d), id(e))
481
482 #negative
483 d = Decimal(-45)
484 e = Decimal(d)
485 self.assertEqual(str(e), '-45')
486 self.assertNotEqual(id(d), id(e))
487
488 #zero
489 d = Decimal(0)
490 e = Decimal(d)
491 self.assertEqual(str(e), '0')
492 self.assertNotEqual(id(d), id(e))
493
494 def test_explicit_context_create_decimal(self):
495
496 nc = copy.copy(getcontext())
497 nc.prec = 3
498
499 # empty
Raymond Hettingerfed52962004-07-14 15:41:57 +0000500 d = Decimal()
501 self.assertEqual(str(d), '0')
502 d = nc.create_decimal()
503 self.assertEqual(str(d), '0')
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000504
505 # from None
506 self.assertRaises(TypeError, nc.create_decimal, None)
507
508 # from int
509 d = nc.create_decimal(456)
510 self.failUnless(isinstance(d, Decimal))
511 self.assertEqual(nc.create_decimal(45678),
512 nc.create_decimal('457E+2'))
513
514 # from string
515 d = Decimal('456789')
516 self.assertEqual(str(d), '456789')
517 d = nc.create_decimal('456789')
518 self.assertEqual(str(d), '4.57E+5')
519
520 # from tuples
521 d = Decimal( (1, (4, 3, 4, 9, 1, 3, 5, 3, 4), -25) )
522 self.assertEqual(str(d), '-4.34913534E-17')
523 d = nc.create_decimal( (1, (4, 3, 4, 9, 1, 3, 5, 3, 4), -25) )
524 self.assertEqual(str(d), '-4.35E-17')
525
526 # from Decimal
527 prevdec = Decimal(500000123)
528 d = Decimal(prevdec)
529 self.assertEqual(str(d), '500000123')
530 d = nc.create_decimal(prevdec)
531 self.assertEqual(str(d), '5.00E+8')
532
533
534class DecimalImplicitConstructionTest(unittest.TestCase):
535 '''Unit tests for Implicit Construction cases of Decimal.'''
536
537 def test_implicit_from_None(self):
538 self.assertRaises(TypeError, eval, 'Decimal(5) + None', globals())
539
540 def test_implicit_from_int(self):
541 #normal
542 self.assertEqual(str(Decimal(5) + 45), '50')
543 #exceeding precision
544 self.assertEqual(Decimal(5) + 123456789000, Decimal(123456789000))
545
546 def test_implicit_from_string(self):
547 self.assertRaises(TypeError, eval, 'Decimal(5) + "3"', globals())
548
549 def test_implicit_from_float(self):
550 self.assertRaises(TypeError, eval, 'Decimal(5) + 2.2', globals())
551
552 def test_implicit_from_Decimal(self):
553 self.assertEqual(Decimal(5) + Decimal(45), Decimal(50))
554
Raymond Hettinger267b8682005-03-27 10:47:39 +0000555 def test_rop(self):
556 # Allow other classes to be trained to interact with Decimals
557 class E:
558 def __divmod__(self, other):
559 return 'divmod ' + str(other)
560 def __rdivmod__(self, other):
561 return str(other) + ' rdivmod'
562 def __lt__(self, other):
563 return 'lt ' + str(other)
564 def __gt__(self, other):
565 return 'gt ' + str(other)
566 def __le__(self, other):
567 return 'le ' + str(other)
568 def __ge__(self, other):
569 return 'ge ' + str(other)
570 def __eq__(self, other):
571 return 'eq ' + str(other)
572 def __ne__(self, other):
573 return 'ne ' + str(other)
574
575 self.assertEqual(divmod(E(), Decimal(10)), 'divmod 10')
576 self.assertEqual(divmod(Decimal(10), E()), '10 rdivmod')
577 self.assertEqual(eval('Decimal(10) < E()'), 'gt 10')
578 self.assertEqual(eval('Decimal(10) > E()'), 'lt 10')
579 self.assertEqual(eval('Decimal(10) <= E()'), 'ge 10')
580 self.assertEqual(eval('Decimal(10) >= E()'), 'le 10')
581 self.assertEqual(eval('Decimal(10) == E()'), 'eq 10')
582 self.assertEqual(eval('Decimal(10) != E()'), 'ne 10')
583
584 # insert operator methods and then exercise them
Georg Brandl96c3f7f2006-03-28 08:06:35 +0000585 oplist = [
586 ('+', '__add__', '__radd__'),
587 ('-', '__sub__', '__rsub__'),
588 ('*', '__mul__', '__rmul__'),
589 ('%', '__mod__', '__rmod__'),
590 ('//', '__floordiv__', '__rfloordiv__'),
591 ('**', '__pow__', '__rpow__')
592 ]
593 if 1/2 == 0:
594 # testing with classic division, so add __div__
595 oplist.append(('/', '__div__', '__rdiv__'))
596 else:
597 # testing with -Qnew, so add __truediv__
598 oplist.append(('/', '__truediv__', '__rtruediv__'))
Anthony Baxter4ef3a232006-03-30 12:59:11 +0000599
Georg Brandl96c3f7f2006-03-28 08:06:35 +0000600 for sym, lop, rop in oplist:
Raymond Hettinger267b8682005-03-27 10:47:39 +0000601 setattr(E, lop, lambda self, other: 'str' + lop + str(other))
602 setattr(E, rop, lambda self, other: str(other) + rop + 'str')
603 self.assertEqual(eval('E()' + sym + 'Decimal(10)'),
604 'str' + lop + '10')
605 self.assertEqual(eval('Decimal(10)' + sym + 'E()'),
606 '10' + rop + 'str')
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000607
608class DecimalArithmeticOperatorsTest(unittest.TestCase):
609 '''Unit tests for all arithmetic operators, binary and unary.'''
610
611 def test_addition(self):
612
613 d1 = Decimal('-11.1')
614 d2 = Decimal('22.2')
615
616 #two Decimals
617 self.assertEqual(d1+d2, Decimal('11.1'))
618 self.assertEqual(d2+d1, Decimal('11.1'))
619
620 #with other type, left
621 c = d1 + 5
622 self.assertEqual(c, Decimal('-6.1'))
623 self.assertEqual(type(c), type(d1))
624
625 #with other type, right
626 c = 5 + d1
627 self.assertEqual(c, Decimal('-6.1'))
628 self.assertEqual(type(c), type(d1))
629
630 #inline with decimal
631 d1 += d2
632 self.assertEqual(d1, Decimal('11.1'))
633
634 #inline with other type
635 d1 += 5
636 self.assertEqual(d1, Decimal('16.1'))
637
638 def test_subtraction(self):
639
640 d1 = Decimal('-11.1')
641 d2 = Decimal('22.2')
642
643 #two Decimals
644 self.assertEqual(d1-d2, Decimal('-33.3'))
645 self.assertEqual(d2-d1, Decimal('33.3'))
646
647 #with other type, left
648 c = d1 - 5
649 self.assertEqual(c, Decimal('-16.1'))
650 self.assertEqual(type(c), type(d1))
651
652 #with other type, right
653 c = 5 - d1
654 self.assertEqual(c, Decimal('16.1'))
655 self.assertEqual(type(c), type(d1))
656
657 #inline with decimal
658 d1 -= d2
659 self.assertEqual(d1, Decimal('-33.3'))
660
661 #inline with other type
662 d1 -= 5
663 self.assertEqual(d1, Decimal('-38.3'))
664
665 def test_multiplication(self):
666
667 d1 = Decimal('-5')
668 d2 = Decimal('3')
669
670 #two Decimals
671 self.assertEqual(d1*d2, Decimal('-15'))
672 self.assertEqual(d2*d1, Decimal('-15'))
673
674 #with other type, left
675 c = d1 * 5
676 self.assertEqual(c, Decimal('-25'))
677 self.assertEqual(type(c), type(d1))
678
679 #with other type, right
680 c = 5 * d1
681 self.assertEqual(c, Decimal('-25'))
682 self.assertEqual(type(c), type(d1))
683
684 #inline with decimal
685 d1 *= d2
686 self.assertEqual(d1, Decimal('-15'))
687
688 #inline with other type
689 d1 *= 5
690 self.assertEqual(d1, Decimal('-75'))
691
692 def test_division(self):
693
694 d1 = Decimal('-5')
695 d2 = Decimal('2')
696
697 #two Decimals
698 self.assertEqual(d1/d2, Decimal('-2.5'))
699 self.assertEqual(d2/d1, Decimal('-0.4'))
700
701 #with other type, left
702 c = d1 / 4
703 self.assertEqual(c, Decimal('-1.25'))
704 self.assertEqual(type(c), type(d1))
705
706 #with other type, right
707 c = 4 / d1
708 self.assertEqual(c, Decimal('-0.8'))
709 self.assertEqual(type(c), type(d1))
710
711 #inline with decimal
712 d1 /= d2
713 self.assertEqual(d1, Decimal('-2.5'))
714
715 #inline with other type
716 d1 /= 4
717 self.assertEqual(d1, Decimal('-0.625'))
718
719 def test_floor_division(self):
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000720
721 d1 = Decimal('5')
722 d2 = Decimal('2')
723
724 #two Decimals
725 self.assertEqual(d1//d2, Decimal('2'))
726 self.assertEqual(d2//d1, Decimal('0'))
727
728 #with other type, left
729 c = d1 // 4
730 self.assertEqual(c, Decimal('1'))
731 self.assertEqual(type(c), type(d1))
732
733 #with other type, right
734 c = 7 // d1
735 self.assertEqual(c, Decimal('1'))
736 self.assertEqual(type(c), type(d1))
737
738 #inline with decimal
739 d1 //= d2
740 self.assertEqual(d1, Decimal('2'))
741
742 #inline with other type
743 d1 //= 2
744 self.assertEqual(d1, Decimal('1'))
745
746 def test_powering(self):
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000747
748 d1 = Decimal('5')
749 d2 = Decimal('2')
750
751 #two Decimals
752 self.assertEqual(d1**d2, Decimal('25'))
753 self.assertEqual(d2**d1, Decimal('32'))
754
755 #with other type, left
756 c = d1 ** 4
757 self.assertEqual(c, Decimal('625'))
758 self.assertEqual(type(c), type(d1))
759
760 #with other type, right
761 c = 7 ** d1
762 self.assertEqual(c, Decimal('16807'))
763 self.assertEqual(type(c), type(d1))
764
765 #inline with decimal
766 d1 **= d2
767 self.assertEqual(d1, Decimal('25'))
768
769 #inline with other type
770 d1 **= 4
771 self.assertEqual(d1, Decimal('390625'))
772
773 def test_module(self):
774
775 d1 = Decimal('5')
776 d2 = Decimal('2')
777
778 #two Decimals
779 self.assertEqual(d1%d2, Decimal('1'))
780 self.assertEqual(d2%d1, Decimal('2'))
781
782 #with other type, left
783 c = d1 % 4
784 self.assertEqual(c, Decimal('1'))
785 self.assertEqual(type(c), type(d1))
786
787 #with other type, right
788 c = 7 % d1
789 self.assertEqual(c, Decimal('2'))
790 self.assertEqual(type(c), type(d1))
791
792 #inline with decimal
793 d1 %= d2
794 self.assertEqual(d1, Decimal('1'))
795
796 #inline with other type
797 d1 %= 4
798 self.assertEqual(d1, Decimal('1'))
799
800 def test_floor_div_module(self):
801
802 d1 = Decimal('5')
803 d2 = Decimal('2')
804
805 #two Decimals
806 (p, q) = divmod(d1, d2)
807 self.assertEqual(p, Decimal('2'))
808 self.assertEqual(q, Decimal('1'))
809 self.assertEqual(type(p), type(d1))
810 self.assertEqual(type(q), type(d1))
811
812 #with other type, left
813 (p, q) = divmod(d1, 4)
814 self.assertEqual(p, Decimal('1'))
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, right
820 (p, q) = divmod(7, d1)
821 self.assertEqual(p, Decimal('1'))
822 self.assertEqual(q, Decimal('2'))
823 self.assertEqual(type(p), type(d1))
824 self.assertEqual(type(q), type(d1))
825
826 def test_unary_operators(self):
827 self.assertEqual(+Decimal(45), Decimal(+45)) # +
828 self.assertEqual(-Decimal(45), Decimal(-45)) # -
829 self.assertEqual(abs(Decimal(45)), abs(Decimal(-45))) # abs
830
831
832# The following are two functions used to test threading in the next class
833
834def thfunc1(cls):
835 d1 = Decimal(1)
836 d3 = Decimal(3)
837 cls.assertEqual(d1/d3, Decimal('0.333333333'))
838 cls.synchro.wait()
839 cls.assertEqual(d1/d3, Decimal('0.333333333'))
840 cls.finish1.set()
841 return
842
843def thfunc2(cls):
844 d1 = Decimal(1)
845 d3 = Decimal(3)
846 cls.assertEqual(d1/d3, Decimal('0.333333333'))
847 thiscontext = getcontext()
848 thiscontext.prec = 18
849 cls.assertEqual(d1/d3, Decimal('0.333333333333333333'))
850 cls.synchro.set()
851 cls.finish2.set()
852 return
853
854
855class DecimalUseOfContextTest(unittest.TestCase):
856 '''Unit tests for Use of Context cases in Decimal.'''
857
Raymond Hettinger7e71fa52004-12-18 19:07:19 +0000858 try:
859 import threading
860 except ImportError:
861 threading = None
862
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000863 # Take care executing this test from IDLE, there's an issue in threading
864 # that hangs IDLE and I couldn't find it
865
866 def test_threading(self):
867 #Test the "threading isolation" of a Context.
868
869 self.synchro = threading.Event()
870 self.finish1 = threading.Event()
871 self.finish2 = threading.Event()
872
873 th1 = threading.Thread(target=thfunc1, args=(self,))
874 th2 = threading.Thread(target=thfunc2, args=(self,))
875
876 th1.start()
877 th2.start()
878
879 self.finish1.wait()
Thomas Woutersb3e6e8c2007-09-19 17:27:29 +0000880 self.finish2.wait()
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000881 return
882
Raymond Hettinger7e71fa52004-12-18 19:07:19 +0000883 if threading is None:
884 del test_threading
885
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000886
887class DecimalUsabilityTest(unittest.TestCase):
888 '''Unit tests for Usability cases of Decimal.'''
889
890 def test_comparison_operators(self):
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000891
892 da = Decimal('23.42')
893 db = Decimal('23.42')
894 dc = Decimal('45')
895
896 #two Decimals
897 self.failUnless(dc > da)
898 self.failUnless(dc >= da)
899 self.failUnless(da < dc)
900 self.failUnless(da <= dc)
901 self.failUnless(da == db)
902 self.failUnless(da != dc)
903 self.failUnless(da <= db)
904 self.failUnless(da >= db)
905 self.assertEqual(cmp(dc,da), 1)
906 self.assertEqual(cmp(da,dc), -1)
907 self.assertEqual(cmp(da,db), 0)
908
909 #a Decimal and an int
910 self.failUnless(dc > 23)
911 self.failUnless(23 < dc)
912 self.failUnless(dc == 45)
913 self.assertEqual(cmp(dc,23), 1)
914 self.assertEqual(cmp(23,dc), -1)
915 self.assertEqual(cmp(dc,45), 0)
916
917 #a Decimal and uncomparable
Raymond Hettinger0aeac102004-07-05 22:53:03 +0000918 self.assertNotEqual(da, 'ugly')
919 self.assertNotEqual(da, 32.7)
920 self.assertNotEqual(da, object())
921 self.assertNotEqual(da, object)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000922
Raymond Hettinger0aeac102004-07-05 22:53:03 +0000923 # sortable
924 a = map(Decimal, xrange(100))
925 b = a[:]
926 random.shuffle(a)
927 a.sort()
928 self.assertEqual(a, b)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000929
Facundo Batista353750c2007-09-13 18:13:15 +0000930 # with None
931 self.assertFalse(Decimal(1) < None)
932 self.assertTrue(Decimal(1) > None)
933
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000934 def test_copy_and_deepcopy_methods(self):
935 d = Decimal('43.24')
936 c = copy.copy(d)
937 self.assertEqual(id(c), id(d))
938 dc = copy.deepcopy(d)
939 self.assertEqual(id(dc), id(d))
940
941 def test_hash_method(self):
942 #just that it's hashable
943 hash(Decimal(23))
Facundo Batista8c202442007-09-19 17:53:25 +0000944
945 test_values = [Decimal(sign*(2**m + n))
946 for m in [0, 14, 15, 16, 17, 30, 31,
947 32, 33, 62, 63, 64, 65, 66]
948 for n in range(-10, 10)
949 for sign in [-1, 1]]
950 test_values.extend([
951 Decimal("-0"), # zeros
952 Decimal("0.00"),
953 Decimal("-0.000"),
954 Decimal("0E10"),
955 Decimal("-0E12"),
956 Decimal("10.0"), # negative exponent
957 Decimal("-23.00000"),
958 Decimal("1230E100"), # positive exponent
959 Decimal("-4.5678E50"),
960 # a value for which hash(n) != hash(n % (2**64-1))
961 # in Python pre-2.6
962 Decimal(2**64 + 2**32 - 1),
963 # selection of values which fail with the old (before
964 # version 2.6) long.__hash__
965 Decimal("1.634E100"),
966 Decimal("90.697E100"),
967 Decimal("188.83E100"),
968 Decimal("1652.9E100"),
969 Decimal("56531E100"),
970 ])
971
972 # check that hash(d) == hash(int(d)) for integral values
973 for value in test_values:
974 self.assertEqual(hash(value), hash(int(value)))
975
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000976 #the same hash that to an int
977 self.assertEqual(hash(Decimal(23)), hash(23))
Raymond Hettingerbea3f6f2005-03-15 04:59:17 +0000978 self.assertRaises(TypeError, hash, Decimal('NaN'))
979 self.assert_(hash(Decimal('Inf')))
980 self.assert_(hash(Decimal('-Inf')))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000981
982 def test_min_and_max_methods(self):
983
984 d1 = Decimal('15.32')
985 d2 = Decimal('28.5')
986 l1 = 15
987 l2 = 28
988
989 #between Decimals
990 self.failUnless(min(d1,d2) is d1)
991 self.failUnless(min(d2,d1) is d1)
992 self.failUnless(max(d1,d2) is d2)
993 self.failUnless(max(d2,d1) is d2)
994
995 #between Decimal and long
996 self.failUnless(min(d1,l2) is d1)
997 self.failUnless(min(l2,d1) is d1)
998 self.failUnless(max(l1,d2) is d2)
999 self.failUnless(max(d2,l1) is d2)
1000
1001 def test_as_nonzero(self):
1002 #as false
1003 self.failIf(Decimal(0))
1004 #as true
1005 self.failUnless(Decimal('0.372'))
1006
1007 def test_tostring_methods(self):
1008 #Test str and repr methods.
1009
1010 d = Decimal('15.32')
1011 self.assertEqual(str(d), '15.32') # str
1012 self.assertEqual(repr(d), 'Decimal("15.32")') # repr
1013
1014 def test_tonum_methods(self):
1015 #Test float, int and long methods.
1016
1017 d1 = Decimal('66')
1018 d2 = Decimal('15.32')
1019
1020 #int
1021 self.assertEqual(int(d1), 66)
1022 self.assertEqual(int(d2), 15)
1023
1024 #long
1025 self.assertEqual(long(d1), 66)
1026 self.assertEqual(long(d2), 15)
1027
1028 #float
1029 self.assertEqual(float(d1), 66)
1030 self.assertEqual(float(d2), 15.32)
1031
1032 def test_eval_round_trip(self):
1033
1034 #with zero
1035 d = Decimal( (0, (0,), 0) )
1036 self.assertEqual(d, eval(repr(d)))
1037
1038 #int
1039 d = Decimal( (1, (4, 5), 0) )
1040 self.assertEqual(d, eval(repr(d)))
1041
1042 #float
1043 d = Decimal( (0, (4, 5, 3, 4), -2) )
1044 self.assertEqual(d, eval(repr(d)))
1045
1046 #weird
1047 d = Decimal( (1, (4, 3, 4, 9, 1, 3, 5, 3, 4), -25) )
1048 self.assertEqual(d, eval(repr(d)))
1049
1050 def test_as_tuple(self):
1051
1052 #with zero
1053 d = Decimal(0)
1054 self.assertEqual(d.as_tuple(), (0, (0,), 0) )
1055
1056 #int
1057 d = Decimal(-45)
1058 self.assertEqual(d.as_tuple(), (1, (4, 5), 0) )
1059
1060 #complicated string
1061 d = Decimal("-4.34913534E-17")
1062 self.assertEqual(d.as_tuple(), (1, (4, 3, 4, 9, 1, 3, 5, 3, 4), -25) )
1063
1064 #inf
1065 d = Decimal("Infinity")
1066 self.assertEqual(d.as_tuple(), (0, (0,), 'F') )
1067
Facundo Batista9b5e2312007-10-19 19:25:57 +00001068 #leading zeros in coefficient should be stripped
1069 d = Decimal( (0, (0, 0, 4, 0, 5, 3, 4), -2) )
1070 self.assertEqual(d.as_tuple(), (0, (4, 0, 5, 3, 4), -2) )
1071 d = Decimal( (1, (0, 0, 0), 37) )
1072 self.assertEqual(d.as_tuple(), (1, (0,), 37))
1073 d = Decimal( (1, (), 37) )
1074 self.assertEqual(d.as_tuple(), (1, (0,), 37))
1075
1076 #leading zeros in NaN diagnostic info should be stripped
1077 d = Decimal( (0, (0, 0, 4, 0, 5, 3, 4), 'n') )
1078 self.assertEqual(d.as_tuple(), (0, (4, 0, 5, 3, 4), 'n') )
1079 d = Decimal( (1, (0, 0, 0), 'N') )
1080 self.assertEqual(d.as_tuple(), (1, (), 'N') )
1081 d = Decimal( (1, (), 'n') )
1082 self.assertEqual(d.as_tuple(), (1, (), 'n') )
1083
1084 #coefficient in infinity should be ignored
1085 d = Decimal( (0, (4, 5, 3, 4), 'F') )
1086 self.assertEqual(d.as_tuple(), (0, (0,), 'F'))
1087 d = Decimal( (1, (0, 2, 7, 1), 'F') )
1088 self.assertEqual(d.as_tuple(), (1, (0,), 'F'))
1089
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001090 def test_immutability_operations(self):
1091 # Do operations and check that it didn't change change internal objects.
1092
1093 d1 = Decimal('-25e55')
1094 b1 = Decimal('-25e55')
Facundo Batista353750c2007-09-13 18:13:15 +00001095 d2 = Decimal('33e+33')
1096 b2 = Decimal('33e+33')
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001097
1098 def checkSameDec(operation, useOther=False):
1099 if useOther:
1100 eval("d1." + operation + "(d2)")
1101 self.assertEqual(d1._sign, b1._sign)
1102 self.assertEqual(d1._int, b1._int)
1103 self.assertEqual(d1._exp, b1._exp)
1104 self.assertEqual(d2._sign, b2._sign)
1105 self.assertEqual(d2._int, b2._int)
1106 self.assertEqual(d2._exp, b2._exp)
1107 else:
1108 eval("d1." + operation + "()")
1109 self.assertEqual(d1._sign, b1._sign)
1110 self.assertEqual(d1._int, b1._int)
1111 self.assertEqual(d1._exp, b1._exp)
1112 return
1113
1114 Decimal(d1)
1115 self.assertEqual(d1._sign, b1._sign)
1116 self.assertEqual(d1._int, b1._int)
1117 self.assertEqual(d1._exp, b1._exp)
1118
1119 checkSameDec("__abs__")
1120 checkSameDec("__add__", True)
1121 checkSameDec("__div__", True)
1122 checkSameDec("__divmod__", True)
1123 checkSameDec("__cmp__", True)
1124 checkSameDec("__float__")
1125 checkSameDec("__floordiv__", True)
1126 checkSameDec("__hash__")
1127 checkSameDec("__int__")
1128 checkSameDec("__long__")
1129 checkSameDec("__mod__", True)
1130 checkSameDec("__mul__", True)
1131 checkSameDec("__neg__")
1132 checkSameDec("__nonzero__")
1133 checkSameDec("__pos__")
1134 checkSameDec("__pow__", True)
1135 checkSameDec("__radd__", True)
1136 checkSameDec("__rdiv__", True)
1137 checkSameDec("__rdivmod__", True)
1138 checkSameDec("__repr__")
1139 checkSameDec("__rfloordiv__", True)
1140 checkSameDec("__rmod__", True)
1141 checkSameDec("__rmul__", True)
1142 checkSameDec("__rpow__", True)
1143 checkSameDec("__rsub__", True)
1144 checkSameDec("__str__")
1145 checkSameDec("__sub__", True)
1146 checkSameDec("__truediv__", True)
1147 checkSameDec("adjusted")
1148 checkSameDec("as_tuple")
1149 checkSameDec("compare", True)
1150 checkSameDec("max", True)
1151 checkSameDec("min", True)
1152 checkSameDec("normalize")
1153 checkSameDec("quantize", True)
1154 checkSameDec("remainder_near", True)
1155 checkSameDec("same_quantum", True)
1156 checkSameDec("sqrt")
1157 checkSameDec("to_eng_string")
1158 checkSameDec("to_integral")
1159
Facundo Batista6c398da2007-09-17 17:30:13 +00001160 def test_subclassing(self):
1161 # Different behaviours when subclassing Decimal
1162
1163 class MyDecimal(Decimal):
1164 pass
1165
1166 d1 = MyDecimal(1)
1167 d2 = MyDecimal(2)
1168 d = d1 + d2
1169 self.assertTrue(type(d) is Decimal)
1170
1171 d = d1.max(d2)
1172 self.assertTrue(type(d) is Decimal)
1173
1174
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001175class DecimalPythonAPItests(unittest.TestCase):
1176
1177 def test_pickle(self):
1178 d = Decimal('-3.141590000')
1179 p = pickle.dumps(d)
1180 e = pickle.loads(p)
1181 self.assertEqual(d, e)
1182
Raymond Hettinger5548be22004-07-05 18:49:38 +00001183 def test_int(self):
Raymond Hettinger605ed022004-11-24 07:28:48 +00001184 for x in range(-250, 250):
1185 s = '%0.2f' % (x / 100.0)
Raymond Hettinger5548be22004-07-05 18:49:38 +00001186 # should work the same as for floats
1187 self.assertEqual(int(Decimal(s)), int(float(s)))
Raymond Hettinger605ed022004-11-24 07:28:48 +00001188 # should work the same as to_integral in the ROUND_DOWN mode
Raymond Hettinger5548be22004-07-05 18:49:38 +00001189 d = Decimal(s)
Raymond Hettinger605ed022004-11-24 07:28:48 +00001190 r = d.to_integral(ROUND_DOWN)
Raymond Hettinger5548be22004-07-05 18:49:38 +00001191 self.assertEqual(Decimal(int(d)), r)
1192
Raymond Hettingerd9c0a7a2004-07-03 10:02:28 +00001193class ContextAPItests(unittest.TestCase):
1194
1195 def test_pickle(self):
1196 c = Context()
1197 e = pickle.loads(pickle.dumps(c))
1198 for k in vars(c):
1199 v1 = vars(c)[k]
1200 v2 = vars(e)[k]
1201 self.assertEqual(v1, v2)
1202
Raymond Hettinger0aeac102004-07-05 22:53:03 +00001203 def test_equality_with_other_types(self):
1204 self.assert_(Decimal(10) in ['a', 1.0, Decimal(10), (1,2), {}])
1205 self.assert_(Decimal(10) not in ['a', 1.0, (1,2), {}])
1206
Raymond Hettinger955d2b22004-08-08 20:17:45 +00001207 def test_copy(self):
1208 # All copies should be deep
1209 c = Context()
1210 d = c.copy()
1211 self.assertNotEqual(id(c), id(d))
1212 self.assertNotEqual(id(c.flags), id(d.flags))
1213 self.assertNotEqual(id(c.traps), id(d.traps))
1214
Nick Coghlan8b6999b2006-08-31 12:00:43 +00001215class WithStatementTest(unittest.TestCase):
1216 # Can't do these as docstrings until Python 2.6
1217 # as doctest can't handle __future__ statements
Nick Coghlan8b6999b2006-08-31 12:00:43 +00001218
1219 def test_localcontext(self):
Nick Coghlanced12182006-09-02 03:54:17 +00001220 # Use a copy of the current context in the block
Nick Coghlan8b6999b2006-08-31 12:00:43 +00001221 orig_ctx = getcontext()
1222 with localcontext() as enter_ctx:
1223 set_ctx = getcontext()
1224 final_ctx = getcontext()
1225 self.assert_(orig_ctx is final_ctx, 'did not restore context correctly')
1226 self.assert_(orig_ctx is not set_ctx, 'did not copy the context')
1227 self.assert_(set_ctx is enter_ctx, '__enter__ returned wrong context')
1228
1229 def test_localcontextarg(self):
Nick Coghlanced12182006-09-02 03:54:17 +00001230 # Use a copy of the supplied context in the block
Nick Coghlan8b6999b2006-08-31 12:00:43 +00001231 orig_ctx = getcontext()
1232 new_ctx = Context(prec=42)
1233 with localcontext(new_ctx) as enter_ctx:
1234 set_ctx = getcontext()
1235 final_ctx = getcontext()
1236 self.assert_(orig_ctx is final_ctx, 'did not restore context correctly')
1237 self.assert_(set_ctx.prec == new_ctx.prec, 'did not set correct context')
1238 self.assert_(new_ctx is not set_ctx, 'did not copy the context')
1239 self.assert_(set_ctx is enter_ctx, '__enter__ returned wrong context')
1240
Facundo Batista353750c2007-09-13 18:13:15 +00001241class ContextFlags(unittest.TestCase):
1242 def test_flags_irrelevant(self):
1243 # check that the result (numeric result + flags raised) of an
1244 # arithmetic operation doesn't depend on the current flags
1245
1246 context = Context(prec=9, Emin = -999999999, Emax = 999999999,
1247 rounding=ROUND_HALF_EVEN, traps=[], flags=[])
1248
1249 # operations that raise various flags, in the form (function, arglist)
1250 operations = [
1251 (context._apply, [Decimal("100E-1000000009")]),
1252 (context.sqrt, [Decimal(2)]),
1253 (context.add, [Decimal("1.23456789"), Decimal("9.87654321")]),
1254 (context.multiply, [Decimal("1.23456789"), Decimal("9.87654321")]),
1255 (context.subtract, [Decimal("1.23456789"), Decimal("9.87654321")]),
1256 ]
1257
1258 # try various flags individually, then a whole lot at once
1259 flagsets = [[Inexact], [Rounded], [Underflow], [Clamped], [Subnormal],
1260 [Inexact, Rounded, Underflow, Clamped, Subnormal]]
1261
1262 for fn, args in operations:
1263 # find answer and flags raised using a clean context
1264 context.clear_flags()
1265 ans = fn(*args)
1266 flags = [k for k, v in context.flags.items() if v]
1267
1268 for extra_flags in flagsets:
1269 # set flags, before calling operation
1270 context.clear_flags()
1271 for flag in extra_flags:
1272 context._raise_error(flag)
1273 new_ans = fn(*args)
1274
1275 # flags that we expect to be set after the operation
1276 expected_flags = list(flags)
1277 for flag in extra_flags:
1278 if flag not in expected_flags:
1279 expected_flags.append(flag)
1280 expected_flags.sort()
1281
1282 # flags we actually got
1283 new_flags = [k for k,v in context.flags.items() if v]
1284 new_flags.sort()
1285
1286 self.assertEqual(ans, new_ans,
1287 "operation produces different answers depending on flags set: " +
1288 "expected %s, got %s." % (ans, new_ans))
1289 self.assertEqual(new_flags, expected_flags,
1290 "operation raises different flags depending on flags set: " +
1291 "expected %s, got %s" % (expected_flags, new_flags))
1292
1293def test_main(arith=False, verbose=None, todo_tests=None, debug=None):
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001294 """ Execute the tests.
1295
Raymond Hettingered20ad82004-09-04 20:09:13 +00001296 Runs all arithmetic tests if arith is True or if the "decimal" resource
1297 is enabled in regrtest.py
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001298 """
Raymond Hettingered20ad82004-09-04 20:09:13 +00001299
Neal Norwitzce4a9c92006-04-09 08:36:46 +00001300 init()
Facundo Batista353750c2007-09-13 18:13:15 +00001301 global TEST_ALL, DEBUG
Raymond Hettingered20ad82004-09-04 20:09:13 +00001302 TEST_ALL = arith or is_resource_enabled('decimal')
Facundo Batista353750c2007-09-13 18:13:15 +00001303 DEBUG = debug
Raymond Hettingered20ad82004-09-04 20:09:13 +00001304
Facundo Batista353750c2007-09-13 18:13:15 +00001305 if todo_tests is None:
1306 test_classes = [
1307 DecimalExplicitConstructionTest,
1308 DecimalImplicitConstructionTest,
1309 DecimalArithmeticOperatorsTest,
1310 DecimalUseOfContextTest,
1311 DecimalUsabilityTest,
1312 DecimalPythonAPItests,
1313 ContextAPItests,
1314 DecimalTest,
1315 WithStatementTest,
1316 ContextFlags
1317 ]
1318 else:
1319 test_classes = [DecimalTest]
1320
1321 # Dynamically build custom test definition for each file in the test
1322 # directory and add the definitions to the DecimalTest class. This
1323 # procedure insures that new files do not get skipped.
1324 for filename in os.listdir(directory):
1325 if '.decTest' not in filename or filename.startswith("."):
1326 continue
1327 head, tail = filename.split('.')
1328 if todo_tests is not None and head not in todo_tests:
1329 continue
1330 tester = lambda self, f=filename: self.eval_file(directory + f)
1331 setattr(DecimalTest, 'test_' + head, tester)
1332 del filename, head, tail, tester
1333
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001334
Tim Peters46cc7022006-03-31 04:11:16 +00001335 try:
1336 run_unittest(*test_classes)
Facundo Batista353750c2007-09-13 18:13:15 +00001337 if todo_tests is None:
1338 import decimal as DecimalModule
1339 run_doctest(DecimalModule, verbose)
Tim Peters46cc7022006-03-31 04:11:16 +00001340 finally:
1341 setcontext(ORIGINAL_CONTEXT)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001342
1343if __name__ == '__main__':
Facundo Batista353750c2007-09-13 18:13:15 +00001344 import optparse
1345 p = optparse.OptionParser("test_decimal.py [--debug] [{--skip | test1 [test2 [...]]}]")
1346 p.add_option('--debug', '-d', action='store_true', help='shows the test number and context before each test')
1347 p.add_option('--skip', '-s', action='store_true', help='skip over 90% of the arithmetic tests')
1348 (opt, args) = p.parse_args()
1349
1350 if opt.skip:
1351 test_main(arith=False, verbose=True)
1352 elif args:
1353 test_main(arith=True, verbose=True, todo_tests=args, debug=opt.debug)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001354 else:
Facundo Batista353750c2007-09-13 18:13:15 +00001355 test_main(arith=True, verbose=True)