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