blob: 131c893532773823509a7627424931db86834ec8 [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"""
26
Raymond Hettinger7c85fa42004-07-01 11:01:35 +000027import glob
Jeffrey Yasskinca2b69f2008-02-01 06:22:46 +000028import math
Raymond Hettinger7c85fa42004-07-01 11:01:35 +000029import os, sys
30import pickle, copy
Jeffrey Yasskinca2b69f2008-02-01 06:22:46 +000031import unittest
Raymond Hettinger7c85fa42004-07-01 11:01:35 +000032from decimal import *
Raymond Hettinger2c8585b2009-02-03 03:37:03 +000033import numbers
Benjamin Peterson888a39b2009-03-26 20:48:25 +000034from test.test_support import (SkipTest, run_unittest, run_doctest,
Tim Peters46cc7022006-03-31 04:11:16 +000035 is_resource_enabled)
Raymond Hettinger0aeac102004-07-05 22:53:03 +000036import random
Raymond Hettinger7e71fa52004-12-18 19:07:19 +000037try:
38 import threading
39except ImportError:
40 threading = None
Raymond Hettinger7c85fa42004-07-01 11:01:35 +000041
Raymond Hettingerfed52962004-07-14 15:41:57 +000042# Useful Test Constant
43Signals = getcontext().flags.keys()
44
Tim Peters46cc7022006-03-31 04:11:16 +000045# Tests are built around these assumed context defaults.
46# test_main() restores the original context.
Neal Norwitzce4a9c92006-04-09 08:36:46 +000047def init():
48 global ORIGINAL_CONTEXT
49 ORIGINAL_CONTEXT = getcontext().copy()
Facundo Batistaee340e52008-05-02 17:39:00 +000050 DefaultTestContext = Context(
51 prec = 9,
52 rounding = ROUND_HALF_EVEN,
53 traps = dict.fromkeys(Signals, 0)
54 )
55 setcontext(DefaultTestContext)
Raymond Hettinger6ea48452004-07-03 12:26:21 +000056
Raymond Hettinger7c85fa42004-07-01 11:01:35 +000057TESTDATADIR = 'decimaltestdata'
Raymond Hettingerd9c0a7a2004-07-03 10:02:28 +000058if __name__ == '__main__':
59 file = sys.argv[0]
60else:
61 file = __file__
62testdir = os.path.dirname(file) or os.curdir
Raymond Hettinger267b8682005-03-27 10:47:39 +000063directory = testdir + os.sep + TESTDATADIR + os.sep
Raymond Hettinger7c85fa42004-07-01 11:01:35 +000064
Raymond Hettinger267b8682005-03-27 10:47:39 +000065skip_expected = not os.path.isdir(directory)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +000066
67# Make sure it actually raises errors when not expected and caught in flags
68# Slower, since it runs some things several times.
69EXTENDEDERRORTEST = False
70
Raymond Hettinger7c85fa42004-07-01 11:01:35 +000071#Map the test cases' error names to the actual errors
Raymond Hettinger7c85fa42004-07-01 11:01:35 +000072ErrorNames = {'clamped' : Clamped,
Raymond Hettinger5aa478b2004-07-09 10:02:53 +000073 'conversion_syntax' : InvalidOperation,
Raymond Hettinger7c85fa42004-07-01 11:01:35 +000074 'division_by_zero' : DivisionByZero,
Raymond Hettinger5aa478b2004-07-09 10:02:53 +000075 'division_impossible' : InvalidOperation,
76 'division_undefined' : InvalidOperation,
Raymond Hettinger7c85fa42004-07-01 11:01:35 +000077 'inexact' : Inexact,
Raymond Hettinger5aa478b2004-07-09 10:02:53 +000078 'invalid_context' : InvalidOperation,
Raymond Hettinger7c85fa42004-07-01 11:01:35 +000079 'invalid_operation' : InvalidOperation,
80 'overflow' : Overflow,
81 'rounded' : Rounded,
82 'subnormal' : Subnormal,
83 'underflow' : Underflow}
84
85
86def Nonfunction(*args):
87 """Doesn't do anything."""
88 return None
89
90RoundingDict = {'ceiling' : ROUND_CEILING, #Maps test-case names to roundings.
91 'down' : ROUND_DOWN,
92 'floor' : ROUND_FLOOR,
93 'half_down' : ROUND_HALF_DOWN,
94 'half_even' : ROUND_HALF_EVEN,
95 'half_up' : ROUND_HALF_UP,
Facundo Batista353750c2007-09-13 18:13:15 +000096 'up' : ROUND_UP,
97 '05up' : ROUND_05UP}
Raymond Hettinger7c85fa42004-07-01 11:01:35 +000098
99# Name adapter to be able to change the Decimal and Context
100# interface without changing the test files from Cowlishaw
Facundo Batista1a191df2007-10-02 17:01:24 +0000101nameAdapter = {'and':'logical_and',
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000102 'apply':'_apply',
Facundo Batista353750c2007-09-13 18:13:15 +0000103 'class':'number_class',
104 'comparesig':'compare_signal',
105 'comparetotal':'compare_total',
106 'comparetotmag':'compare_total_mag',
Facundo Batista353750c2007-09-13 18:13:15 +0000107 'copy':'copy_decimal',
Facundo Batista1a191df2007-10-02 17:01:24 +0000108 'copyabs':'copy_abs',
Facundo Batista353750c2007-09-13 18:13:15 +0000109 'copynegate':'copy_negate',
110 'copysign':'copy_sign',
Facundo Batista1a191df2007-10-02 17:01:24 +0000111 'divideint':'divide_int',
Facundo Batista353750c2007-09-13 18:13:15 +0000112 'invert':'logical_invert',
Facundo Batista1a191df2007-10-02 17:01:24 +0000113 'iscanonical':'is_canonical',
114 'isfinite':'is_finite',
115 'isinfinite':'is_infinite',
116 'isnan':'is_nan',
117 'isnormal':'is_normal',
118 'isqnan':'is_qnan',
119 'issigned':'is_signed',
120 'issnan':'is_snan',
121 'issubnormal':'is_subnormal',
122 'iszero':'is_zero',
Facundo Batista353750c2007-09-13 18:13:15 +0000123 'maxmag':'max_mag',
124 'minmag':'min_mag',
125 'nextminus':'next_minus',
126 'nextplus':'next_plus',
127 'nexttoward':'next_toward',
Facundo Batista1a191df2007-10-02 17:01:24 +0000128 'or':'logical_or',
Facundo Batista353750c2007-09-13 18:13:15 +0000129 'reduce':'normalize',
Facundo Batista1a191df2007-10-02 17:01:24 +0000130 'remaindernear':'remainder_near',
131 'samequantum':'same_quantum',
132 'squareroot':'sqrt',
133 'toeng':'to_eng_string',
134 'tointegral':'to_integral_value',
135 'tointegralx':'to_integral_exact',
136 'tosci':'to_sci_string',
137 'xor':'logical_xor',
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000138 }
139
Facundo Batista1a191df2007-10-02 17:01:24 +0000140# The following functions return True/False rather than a Decimal instance
141
142LOGICAL_FUNCTIONS = (
143 'is_canonical',
144 'is_finite',
145 'is_infinite',
146 'is_nan',
147 'is_normal',
148 'is_qnan',
149 'is_signed',
150 'is_snan',
151 'is_subnormal',
152 'is_zero',
153 'same_quantum',
154 )
155
Facundo Batista353750c2007-09-13 18:13:15 +0000156# For some operations (currently exp, ln, log10, power), the decNumber
157# reference implementation imposes additional restrictions on the
158# context and operands. These restrictions are not part of the
159# specification; however, the effect of these restrictions does show
160# up in some of the testcases. We skip testcases that violate these
161# restrictions, since Decimal behaves differently from decNumber for
162# these testcases so these testcases would otherwise fail.
163
164decNumberRestricted = ('power', 'ln', 'log10', 'exp')
165DEC_MAX_MATH = 999999
166def outside_decNumber_bounds(v, context):
167 if (context.prec > DEC_MAX_MATH or
168 context.Emax > DEC_MAX_MATH or
169 -context.Emin > DEC_MAX_MATH):
170 return True
171 if not v._is_special and v and (
Facundo Batista353750c2007-09-13 18:13:15 +0000172 v.adjusted() > DEC_MAX_MATH or
173 v.adjusted() < 1-2*DEC_MAX_MATH):
174 return True
175 return False
176
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000177class DecimalTest(unittest.TestCase):
178 """Class which tests the Decimal class against the test cases.
179
180 Changed for unittest.
181 """
182 def setUp(self):
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000183 self.context = Context()
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
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000194 def eval_file(self, file):
195 global skip_expected
196 if skip_expected:
Benjamin Peterson888a39b2009-03-26 20:48:25 +0000197 raise SkipTest
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000198 return
199 for line in open(file).xreadlines():
200 line = line.replace('\r\n', '').replace('\n', '')
Raymond Hettinger5aa478b2004-07-09 10:02:53 +0000201 #print line
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000202 try:
203 t = self.eval_line(line)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000204 except DecimalException, exception:
205 #Exception raised where there shoudn't have been one.
206 self.fail('Exception "'+exception.__class__.__name__ + '" raised on line '+line)
207
208 return
209
210 def eval_line(self, s):
211 if s.find(' -> ') >= 0 and s[:2] != '--' and not s.startswith(' --'):
212 s = (s.split('->')[0] + '->' +
213 s.split('->')[1].split('--')[0]).strip()
214 else:
215 s = s.split('--')[0].strip()
216
217 for ignore in self.ignore_list:
218 if s.find(ignore) >= 0:
219 #print s.split()[0], 'NotImplemented--', ignore
220 return
221 if not s:
222 return
223 elif ':' in s:
224 return self.eval_directive(s)
225 else:
226 return self.eval_equation(s)
227
228 def eval_directive(self, s):
229 funct, value = map(lambda x: x.strip().lower(), s.split(':'))
230 if funct == 'rounding':
231 value = RoundingDict[value]
232 else:
233 try:
234 value = int(value)
235 except ValueError:
236 pass
237
238 funct = self.ChangeDict.get(funct, Nonfunction)
239 funct(value)
240
241 def eval_equation(self, s):
242 #global DEFAULT_PRECISION
243 #print DEFAULT_PRECISION
Raymond Hettingered20ad82004-09-04 20:09:13 +0000244
245 if not TEST_ALL and random.random() < 0.90:
246 return
247
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000248 try:
249 Sides = s.split('->')
250 L = Sides[0].strip().split()
251 id = L[0]
Facundo Batista353750c2007-09-13 18:13:15 +0000252 if DEBUG:
253 print "Test ", id,
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000254 funct = L[1].lower()
255 valstemp = L[2:]
256 L = Sides[1].strip().split()
257 ans = L[0]
258 exceptions = L[1:]
259 except (TypeError, AttributeError, IndexError):
Raymond Hettingerd87ac8f2004-07-09 10:52:54 +0000260 raise InvalidOperation
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000261 def FixQuotes(val):
262 val = val.replace("''", 'SingleQuote').replace('""', 'DoubleQuote')
263 val = val.replace("'", '').replace('"', '')
264 val = val.replace('SingleQuote', "'").replace('DoubleQuote', '"')
265 return val
266 fname = nameAdapter.get(funct, funct)
267 if fname == 'rescale':
268 return
269 funct = getattr(self.context, fname)
270 vals = []
271 conglomerate = ''
272 quote = 0
273 theirexceptions = [ErrorNames[x.lower()] for x in exceptions]
274
Raymond Hettingerd9c0a7a2004-07-03 10:02:28 +0000275 for exception in Signals:
Raymond Hettingerbf440692004-07-10 14:14:37 +0000276 self.context.traps[exception] = 1 #Catch these bugs...
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000277 for exception in theirexceptions:
Raymond Hettingerbf440692004-07-10 14:14:37 +0000278 self.context.traps[exception] = 0
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000279 for i, val in enumerate(valstemp):
280 if val.count("'") % 2 == 1:
281 quote = 1 - quote
282 if quote:
283 conglomerate = conglomerate + ' ' + val
284 continue
285 else:
286 val = conglomerate + val
287 conglomerate = ''
288 v = FixQuotes(val)
289 if fname in ('to_sci_string', 'to_eng_string'):
290 if EXTENDEDERRORTEST:
291 for error in theirexceptions:
Raymond Hettingerbf440692004-07-10 14:14:37 +0000292 self.context.traps[error] = 1
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000293 try:
294 funct(self.context.create_decimal(v))
295 except error:
296 pass
Raymond Hettingerd9c0a7a2004-07-03 10:02:28 +0000297 except Signals, e:
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000298 self.fail("Raised %s in %s when %s disabled" % \
299 (e, s, error))
300 else:
301 self.fail("Did not raise %s in %s" % (error, s))
Raymond Hettingerbf440692004-07-10 14:14:37 +0000302 self.context.traps[error] = 0
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000303 v = self.context.create_decimal(v)
304 else:
Facundo Batista353750c2007-09-13 18:13:15 +0000305 v = Decimal(v, self.context)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000306 vals.append(v)
307
308 ans = FixQuotes(ans)
309
Facundo Batista353750c2007-09-13 18:13:15 +0000310 # skip tests that are related to bounds imposed in the decNumber
311 # reference implementation
312 if fname in decNumberRestricted:
313 if fname == 'power':
314 if not (vals[1]._isinteger() and
315 -1999999997 <= vals[1] <= 999999999):
316 if outside_decNumber_bounds(vals[0], self.context) or \
317 outside_decNumber_bounds(vals[1], self.context):
318 #print "Skipping test %s" % s
319 return
320 else:
321 if outside_decNumber_bounds(vals[0], self.context):
322 #print "Skipping test %s" % s
323 return
324
325
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000326 if EXTENDEDERRORTEST and fname not in ('to_sci_string', 'to_eng_string'):
327 for error in theirexceptions:
Raymond Hettingerbf440692004-07-10 14:14:37 +0000328 self.context.traps[error] = 1
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000329 try:
330 funct(*vals)
331 except error:
332 pass
Raymond Hettingerd9c0a7a2004-07-03 10:02:28 +0000333 except Signals, e:
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000334 self.fail("Raised %s in %s when %s disabled" % \
335 (e, s, error))
336 else:
337 self.fail("Did not raise %s in %s" % (error, s))
Raymond Hettingerbf440692004-07-10 14:14:37 +0000338 self.context.traps[error] = 0
Facundo Batista353750c2007-09-13 18:13:15 +0000339 if DEBUG:
340 print "--", self.context
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000341 try:
342 result = str(funct(*vals))
Facundo Batista1a191df2007-10-02 17:01:24 +0000343 if fname in LOGICAL_FUNCTIONS:
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000344 result = str(int(eval(result))) # 'True', 'False' -> '1', '0'
Raymond Hettingerd9c0a7a2004-07-03 10:02:28 +0000345 except Signals, error:
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000346 self.fail("Raised %s in %s" % (error, s))
347 except: #Catch any error long enough to state the test case.
348 print "ERROR:", s
349 raise
350
351 myexceptions = self.getexceptions()
Raymond Hettingerbf440692004-07-10 14:14:37 +0000352 self.context.clear_flags()
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000353
354 myexceptions.sort()
355 theirexceptions.sort()
356
357 self.assertEqual(result, ans,
358 'Incorrect answer for ' + s + ' -- got ' + result)
359 self.assertEqual(myexceptions, theirexceptions,
Facundo Batista353750c2007-09-13 18:13:15 +0000360 'Incorrect flags set in ' + s + ' -- got ' + str(myexceptions))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000361 return
362
363 def getexceptions(self):
Raymond Hettingerf63ba432004-08-17 05:42:09 +0000364 return [e for e in Signals if self.context.flags[e]]
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000365
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000366 def change_precision(self, prec):
367 self.context.prec = prec
368 def change_rounding_method(self, rounding):
369 self.context.rounding = rounding
370 def change_min_exponent(self, exp):
371 self.context.Emin = exp
372 def change_max_exponent(self, exp):
373 self.context.Emax = exp
374 def change_clamp(self, clamp):
375 self.context._clamp = clamp
376
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000377
378
379# The following classes test the behaviour of Decimal according to PEP 327
380
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000381class DecimalExplicitConstructionTest(unittest.TestCase):
382 '''Unit tests for Explicit Construction cases of Decimal.'''
383
384 def test_explicit_empty(self):
385 self.assertEqual(Decimal(), Decimal("0"))
386
387 def test_explicit_from_None(self):
388 self.assertRaises(TypeError, Decimal, None)
389
390 def test_explicit_from_int(self):
391
392 #positive
393 d = Decimal(45)
394 self.assertEqual(str(d), '45')
395
396 #very large positive
397 d = Decimal(500000123)
398 self.assertEqual(str(d), '500000123')
399
400 #negative
401 d = Decimal(-45)
402 self.assertEqual(str(d), '-45')
403
404 #zero
405 d = Decimal(0)
406 self.assertEqual(str(d), '0')
407
408 def test_explicit_from_string(self):
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000409
410 #empty
411 self.assertEqual(str(Decimal('')), 'NaN')
412
413 #int
414 self.assertEqual(str(Decimal('45')), '45')
415
416 #float
417 self.assertEqual(str(Decimal('45.34')), '45.34')
418
419 #engineer notation
420 self.assertEqual(str(Decimal('45e2')), '4.5E+3')
421
422 #just not a number
423 self.assertEqual(str(Decimal('ugly')), 'NaN')
424
Mark Dickinson59bc20b2008-01-12 01:56:00 +0000425 #leading and trailing whitespace permitted
426 self.assertEqual(str(Decimal('1.3E4 \n')), '1.3E+4')
427 self.assertEqual(str(Decimal(' -7.89')), '-7.89')
428
Mark Dickinson8e85ffa2008-03-25 18:47:59 +0000429 #unicode strings should be permitted
430 self.assertEqual(str(Decimal(u'0E-017')), '0E-17')
431 self.assertEqual(str(Decimal(u'45')), '45')
432 self.assertEqual(str(Decimal(u'-Inf')), '-Infinity')
433 self.assertEqual(str(Decimal(u'NaN123')), 'NaN123')
434
Mark Dickinson70c32892008-07-02 09:37:01 +0000435 #but alternate unicode digits should not
436 self.assertEqual(str(Decimal(u'\uff11')), 'NaN')
437
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000438 def test_explicit_from_tuples(self):
439
440 #zero
441 d = Decimal( (0, (0,), 0) )
442 self.assertEqual(str(d), '0')
443
444 #int
445 d = Decimal( (1, (4, 5), 0) )
446 self.assertEqual(str(d), '-45')
447
448 #float
449 d = Decimal( (0, (4, 5, 3, 4), -2) )
450 self.assertEqual(str(d), '45.34')
451
452 #weird
453 d = Decimal( (1, (4, 3, 4, 9, 1, 3, 5, 3, 4), -25) )
454 self.assertEqual(str(d), '-4.34913534E-17')
455
456 #wrong number of items
457 self.assertRaises(ValueError, Decimal, (1, (4, 3, 4, 9, 1)) )
458
459 #bad sign
460 self.assertRaises(ValueError, Decimal, (8, (4, 3, 4, 9, 1), 2) )
Facundo Batista9b5e2312007-10-19 19:25:57 +0000461 self.assertRaises(ValueError, Decimal, (0., (4, 3, 4, 9, 1), 2) )
462 self.assertRaises(ValueError, Decimal, (Decimal(1), (4, 3, 4, 9, 1), 2))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000463
464 #bad exp
465 self.assertRaises(ValueError, Decimal, (1, (4, 3, 4, 9, 1), 'wrong!') )
Facundo Batista9b5e2312007-10-19 19:25:57 +0000466 self.assertRaises(ValueError, Decimal, (1, (4, 3, 4, 9, 1), 0.) )
467 self.assertRaises(ValueError, Decimal, (1, (4, 3, 4, 9, 1), '1') )
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000468
469 #bad coefficients
470 self.assertRaises(ValueError, Decimal, (1, (4, 3, 4, None, 1), 2) )
471 self.assertRaises(ValueError, Decimal, (1, (4, -3, 4, 9, 1), 2) )
Facundo Batista9b5e2312007-10-19 19:25:57 +0000472 self.assertRaises(ValueError, Decimal, (1, (4, 10, 4, 9, 1), 2) )
Facundo Batista72bc54f2007-11-23 17:59:00 +0000473 self.assertRaises(ValueError, Decimal, (1, (4, 3, 4, 'a', 1), 2) )
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000474
475 def test_explicit_from_Decimal(self):
476
477 #positive
478 d = Decimal(45)
479 e = Decimal(d)
480 self.assertEqual(str(e), '45')
481 self.assertNotEqual(id(d), id(e))
482
483 #very large positive
484 d = Decimal(500000123)
485 e = Decimal(d)
486 self.assertEqual(str(e), '500000123')
487 self.assertNotEqual(id(d), id(e))
488
489 #negative
490 d = Decimal(-45)
491 e = Decimal(d)
492 self.assertEqual(str(e), '-45')
493 self.assertNotEqual(id(d), id(e))
494
495 #zero
496 d = Decimal(0)
497 e = Decimal(d)
498 self.assertEqual(str(e), '0')
499 self.assertNotEqual(id(d), id(e))
500
501 def test_explicit_context_create_decimal(self):
502
503 nc = copy.copy(getcontext())
504 nc.prec = 3
505
506 # empty
Raymond Hettingerfed52962004-07-14 15:41:57 +0000507 d = Decimal()
508 self.assertEqual(str(d), '0')
509 d = nc.create_decimal()
510 self.assertEqual(str(d), '0')
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000511
512 # from None
513 self.assertRaises(TypeError, nc.create_decimal, None)
514
515 # from int
516 d = nc.create_decimal(456)
517 self.failUnless(isinstance(d, Decimal))
518 self.assertEqual(nc.create_decimal(45678),
519 nc.create_decimal('457E+2'))
520
521 # from string
522 d = Decimal('456789')
523 self.assertEqual(str(d), '456789')
524 d = nc.create_decimal('456789')
525 self.assertEqual(str(d), '4.57E+5')
Mark Dickinson59bc20b2008-01-12 01:56:00 +0000526 # leading and trailing whitespace should result in a NaN;
527 # spaces are already checked in Cowlishaw's test-suite, so
528 # here we just check that a trailing newline results in a NaN
529 self.assertEqual(str(nc.create_decimal('3.14\n')), 'NaN')
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000530
531 # from tuples
532 d = Decimal( (1, (4, 3, 4, 9, 1, 3, 5, 3, 4), -25) )
533 self.assertEqual(str(d), '-4.34913534E-17')
534 d = nc.create_decimal( (1, (4, 3, 4, 9, 1, 3, 5, 3, 4), -25) )
535 self.assertEqual(str(d), '-4.35E-17')
536
537 # from Decimal
538 prevdec = Decimal(500000123)
539 d = Decimal(prevdec)
540 self.assertEqual(str(d), '500000123')
541 d = nc.create_decimal(prevdec)
542 self.assertEqual(str(d), '5.00E+8')
543
544
545class DecimalImplicitConstructionTest(unittest.TestCase):
546 '''Unit tests for Implicit Construction cases of Decimal.'''
547
548 def test_implicit_from_None(self):
549 self.assertRaises(TypeError, eval, 'Decimal(5) + None', globals())
550
551 def test_implicit_from_int(self):
552 #normal
553 self.assertEqual(str(Decimal(5) + 45), '50')
554 #exceeding precision
555 self.assertEqual(Decimal(5) + 123456789000, Decimal(123456789000))
556
557 def test_implicit_from_string(self):
558 self.assertRaises(TypeError, eval, 'Decimal(5) + "3"', globals())
559
560 def test_implicit_from_float(self):
561 self.assertRaises(TypeError, eval, 'Decimal(5) + 2.2', globals())
562
563 def test_implicit_from_Decimal(self):
564 self.assertEqual(Decimal(5) + Decimal(45), Decimal(50))
565
Raymond Hettinger267b8682005-03-27 10:47:39 +0000566 def test_rop(self):
567 # Allow other classes to be trained to interact with Decimals
568 class E:
569 def __divmod__(self, other):
570 return 'divmod ' + str(other)
571 def __rdivmod__(self, other):
572 return str(other) + ' rdivmod'
573 def __lt__(self, other):
574 return 'lt ' + str(other)
575 def __gt__(self, other):
576 return 'gt ' + str(other)
577 def __le__(self, other):
578 return 'le ' + str(other)
579 def __ge__(self, other):
580 return 'ge ' + str(other)
581 def __eq__(self, other):
582 return 'eq ' + str(other)
583 def __ne__(self, other):
584 return 'ne ' + str(other)
585
586 self.assertEqual(divmod(E(), Decimal(10)), 'divmod 10')
587 self.assertEqual(divmod(Decimal(10), E()), '10 rdivmod')
588 self.assertEqual(eval('Decimal(10) < E()'), 'gt 10')
589 self.assertEqual(eval('Decimal(10) > E()'), 'lt 10')
590 self.assertEqual(eval('Decimal(10) <= E()'), 'ge 10')
591 self.assertEqual(eval('Decimal(10) >= E()'), 'le 10')
592 self.assertEqual(eval('Decimal(10) == E()'), 'eq 10')
593 self.assertEqual(eval('Decimal(10) != E()'), 'ne 10')
594
595 # insert operator methods and then exercise them
Georg Brandl96c3f7f2006-03-28 08:06:35 +0000596 oplist = [
597 ('+', '__add__', '__radd__'),
598 ('-', '__sub__', '__rsub__'),
599 ('*', '__mul__', '__rmul__'),
600 ('%', '__mod__', '__rmod__'),
601 ('//', '__floordiv__', '__rfloordiv__'),
602 ('**', '__pow__', '__rpow__')
603 ]
604 if 1/2 == 0:
605 # testing with classic division, so add __div__
606 oplist.append(('/', '__div__', '__rdiv__'))
607 else:
608 # testing with -Qnew, so add __truediv__
609 oplist.append(('/', '__truediv__', '__rtruediv__'))
Anthony Baxter4ef3a232006-03-30 12:59:11 +0000610
Georg Brandl96c3f7f2006-03-28 08:06:35 +0000611 for sym, lop, rop in oplist:
Raymond Hettinger267b8682005-03-27 10:47:39 +0000612 setattr(E, lop, lambda self, other: 'str' + lop + str(other))
613 setattr(E, rop, lambda self, other: str(other) + rop + 'str')
614 self.assertEqual(eval('E()' + sym + 'Decimal(10)'),
615 'str' + lop + '10')
616 self.assertEqual(eval('Decimal(10)' + sym + 'E()'),
617 '10' + rop + 'str')
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000618
Mark Dickinson277859d2009-03-17 23:03:46 +0000619
Mark Dickinson1ddf1d82008-02-29 02:16:37 +0000620class DecimalFormatTest(unittest.TestCase):
621 '''Unit tests for the format function.'''
622 def test_formatting(self):
623 # triples giving a format, a Decimal, and the expected result
624 test_values = [
625 ('e', '0E-15', '0e-15'),
626 ('e', '2.3E-15', '2.3e-15'),
627 ('e', '2.30E+2', '2.30e+2'), # preserve significant zeros
628 ('e', '2.30000E-15', '2.30000e-15'),
629 ('e', '1.23456789123456789e40', '1.23456789123456789e+40'),
630 ('e', '1.5', '1.5e+0'),
631 ('e', '0.15', '1.5e-1'),
632 ('e', '0.015', '1.5e-2'),
633 ('e', '0.0000000000015', '1.5e-12'),
634 ('e', '15.0', '1.50e+1'),
635 ('e', '-15', '-1.5e+1'),
636 ('e', '0', '0e+0'),
637 ('e', '0E1', '0e+1'),
638 ('e', '0.0', '0e-1'),
639 ('e', '0.00', '0e-2'),
640 ('.6e', '0E-15', '0.000000e-9'),
641 ('.6e', '0', '0.000000e+6'),
642 ('.6e', '9.999999', '9.999999e+0'),
643 ('.6e', '9.9999999', '1.000000e+1'),
644 ('.6e', '-1.23e5', '-1.230000e+5'),
645 ('.6e', '1.23456789e-3', '1.234568e-3'),
646 ('f', '0', '0'),
647 ('f', '0.0', '0.0'),
648 ('f', '0E-2', '0.00'),
649 ('f', '0.00E-8', '0.0000000000'),
650 ('f', '0E1', '0'), # loses exponent information
651 ('f', '3.2E1', '32'),
652 ('f', '3.2E2', '320'),
653 ('f', '3.20E2', '320'),
654 ('f', '3.200E2', '320.0'),
655 ('f', '3.2E-6', '0.0000032'),
656 ('.6f', '0E-15', '0.000000'), # all zeros treated equally
657 ('.6f', '0E1', '0.000000'),
658 ('.6f', '0', '0.000000'),
659 ('.0f', '0', '0'), # no decimal point
660 ('.0f', '0e-2', '0'),
661 ('.0f', '3.14159265', '3'),
662 ('.1f', '3.14159265', '3.1'),
663 ('.4f', '3.14159265', '3.1416'),
664 ('.6f', '3.14159265', '3.141593'),
665 ('.7f', '3.14159265', '3.1415926'), # round-half-even!
666 ('.8f', '3.14159265', '3.14159265'),
667 ('.9f', '3.14159265', '3.141592650'),
668
669 ('g', '0', '0'),
670 ('g', '0.0', '0.0'),
671 ('g', '0E1', '0e+1'),
672 ('G', '0E1', '0E+1'),
673 ('g', '0E-5', '0.00000'),
674 ('g', '0E-6', '0.000000'),
675 ('g', '0E-7', '0e-7'),
676 ('g', '-0E2', '-0e+2'),
677 ('.0g', '3.14159265', '3'), # 0 sig fig -> 1 sig fig
678 ('.1g', '3.14159265', '3'),
679 ('.2g', '3.14159265', '3.1'),
680 ('.5g', '3.14159265', '3.1416'),
681 ('.7g', '3.14159265', '3.141593'),
682 ('.8g', '3.14159265', '3.1415926'), # round-half-even!
683 ('.9g', '3.14159265', '3.14159265'),
684 ('.10g', '3.14159265', '3.14159265'), # don't pad
685
686 ('%', '0E1', '0%'),
687 ('%', '0E0', '0%'),
688 ('%', '0E-1', '0%'),
689 ('%', '0E-2', '0%'),
690 ('%', '0E-3', '0.0%'),
691 ('%', '0E-4', '0.00%'),
692
693 ('.3%', '0', '0.000%'), # all zeros treated equally
694 ('.3%', '0E10', '0.000%'),
695 ('.3%', '0E-10', '0.000%'),
696 ('.3%', '2.34', '234.000%'),
697 ('.3%', '1.234567', '123.457%'),
698 ('.0%', '1.23', '123%'),
699
700 ('e', 'NaN', 'NaN'),
701 ('f', '-NaN123', '-NaN123'),
702 ('+g', 'NaN456', '+NaN456'),
703 ('.3e', 'Inf', 'Infinity'),
704 ('.16f', '-Inf', '-Infinity'),
705 ('.0g', '-sNaN', '-sNaN'),
706
707 ('', '1.00', '1.00'),
Mark Dickinsonb065e522009-03-17 18:01:03 +0000708
Mark Dickinson277859d2009-03-17 23:03:46 +0000709 # test alignment and padding
Mark Dickinsonb065e522009-03-17 18:01:03 +0000710 ('<6', '123', '123 '),
711 ('>6', '123', ' 123'),
712 ('^6', '123', ' 123 '),
713 ('=+6', '123', '+ 123'),
Mark Dickinson277859d2009-03-17 23:03:46 +0000714 ('#<10', 'NaN', 'NaN#######'),
715 ('#<10', '-4.3', '-4.3######'),
716 ('#<+10', '0.0130', '+0.0130###'),
717 ('#< 10', '0.0130', ' 0.0130###'),
718 ('@>10', '-Inf', '@-Infinity'),
719 ('#>5', '-Inf', '-Infinity'),
720 ('?^5', '123', '?123?'),
721 ('%^6', '123', '%123%%'),
722 (' ^6', '-45.6', '-45.6 '),
723 ('/=10', '-45.6', '-/////45.6'),
724 ('/=+10', '45.6', '+/////45.6'),
725 ('/= 10', '45.6', ' /////45.6'),
726
727 # thousands separator
728 (',', '1234567', '1,234,567'),
729 (',', '123456', '123,456'),
730 (',', '12345', '12,345'),
731 (',', '1234', '1,234'),
732 (',', '123', '123'),
733 (',', '12', '12'),
734 (',', '1', '1'),
735 (',', '0', '0'),
736 (',', '-1234567', '-1,234,567'),
737 (',', '-123456', '-123,456'),
738 ('7,', '123456', '123,456'),
739 ('8,', '123456', '123,456 '),
740 ('08,', '123456', '0,123,456'), # special case: extra 0 needed
741 ('+08,', '123456', '+123,456'), # but not if there's a sign
742 (' 08,', '123456', ' 123,456'),
743 ('08,', '-123456', '-123,456'),
744 ('+09,', '123456', '+0,123,456'),
745 # ... with fractional part...
746 ('07,', '1234.56', '1,234.56'),
747 ('08,', '1234.56', '1,234.56'),
748 ('09,', '1234.56', '01,234.56'),
749 ('010,', '1234.56', '001,234.56'),
750 ('011,', '1234.56', '0,001,234.56'),
751 ('012,', '1234.56', '0,001,234.56'),
752 ('08,.1f', '1234.5', '01,234.5'),
753 # no thousands separators in fraction part
754 (',', '1.23456789', '1.23456789'),
755 (',%', '123.456789', '12,345.6789%'),
756 (',e', '123456', '1.23456e+5'),
757 (',E', '123456', '1.23456E+5'),
Mark Dickinson1ddf1d82008-02-29 02:16:37 +0000758 ]
759 for fmt, d, result in test_values:
760 self.assertEqual(format(Decimal(d), fmt), result)
761
Mark Dickinson277859d2009-03-17 23:03:46 +0000762 def test_n_format(self):
763 try:
764 from locale import CHAR_MAX
765 except ImportError:
766 return
767
768 # Set up some localeconv-like dictionaries
769 en_US = {
770 'decimal_point' : '.',
771 'grouping' : [3, 3, 0],
772 'thousands_sep': ','
773 }
774
775 fr_FR = {
776 'decimal_point' : ',',
777 'grouping' : [CHAR_MAX],
778 'thousands_sep' : ''
779 }
780
781 ru_RU = {
782 'decimal_point' : ',',
783 'grouping' : [3, 3, 0],
784 'thousands_sep' : ' '
785 }
786
787 crazy = {
788 'decimal_point' : '&',
789 'grouping' : [1, 4, 2, CHAR_MAX],
790 'thousands_sep' : '-'
791 }
792
793
794 def get_fmt(x, locale, fmt='n'):
795 return Decimal.__format__(Decimal(x), fmt, _localeconv=locale)
796
797 self.assertEqual(get_fmt(Decimal('12.7'), en_US), '12.7')
798 self.assertEqual(get_fmt(Decimal('12.7'), fr_FR), '12,7')
799 self.assertEqual(get_fmt(Decimal('12.7'), ru_RU), '12,7')
800 self.assertEqual(get_fmt(Decimal('12.7'), crazy), '1-2&7')
801
802 self.assertEqual(get_fmt(123456789, en_US), '123,456,789')
803 self.assertEqual(get_fmt(123456789, fr_FR), '123456789')
804 self.assertEqual(get_fmt(123456789, ru_RU), '123 456 789')
805 self.assertEqual(get_fmt(1234567890123, crazy), '123456-78-9012-3')
806
807 self.assertEqual(get_fmt(123456789, en_US, '.6n'), '1.23457e+8')
808 self.assertEqual(get_fmt(123456789, fr_FR, '.6n'), '1,23457e+8')
809 self.assertEqual(get_fmt(123456789, ru_RU, '.6n'), '1,23457e+8')
810 self.assertEqual(get_fmt(123456789, crazy, '.6n'), '1&23457e+8')
811
Mark Dickinsonb14514a2009-03-18 08:22:51 +0000812 # zero padding
813 self.assertEqual(get_fmt(1234, fr_FR, '03n'), '1234')
814 self.assertEqual(get_fmt(1234, fr_FR, '04n'), '1234')
815 self.assertEqual(get_fmt(1234, fr_FR, '05n'), '01234')
816 self.assertEqual(get_fmt(1234, fr_FR, '06n'), '001234')
817
818 self.assertEqual(get_fmt(12345, en_US, '05n'), '12,345')
819 self.assertEqual(get_fmt(12345, en_US, '06n'), '12,345')
820 self.assertEqual(get_fmt(12345, en_US, '07n'), '012,345')
821 self.assertEqual(get_fmt(12345, en_US, '08n'), '0,012,345')
822 self.assertEqual(get_fmt(12345, en_US, '09n'), '0,012,345')
823 self.assertEqual(get_fmt(12345, en_US, '010n'), '00,012,345')
824
825 self.assertEqual(get_fmt(123456, crazy, '06n'), '1-2345-6')
826 self.assertEqual(get_fmt(123456, crazy, '07n'), '1-2345-6')
827 self.assertEqual(get_fmt(123456, crazy, '08n'), '1-2345-6')
828 self.assertEqual(get_fmt(123456, crazy, '09n'), '01-2345-6')
829 self.assertEqual(get_fmt(123456, crazy, '010n'), '0-01-2345-6')
830 self.assertEqual(get_fmt(123456, crazy, '011n'), '0-01-2345-6')
831 self.assertEqual(get_fmt(123456, crazy, '012n'), '00-01-2345-6')
832 self.assertEqual(get_fmt(123456, crazy, '013n'), '000-01-2345-6')
833
Mark Dickinson277859d2009-03-17 23:03:46 +0000834
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000835class DecimalArithmeticOperatorsTest(unittest.TestCase):
836 '''Unit tests for all arithmetic operators, binary and unary.'''
837
838 def test_addition(self):
839
840 d1 = Decimal('-11.1')
841 d2 = Decimal('22.2')
842
843 #two Decimals
844 self.assertEqual(d1+d2, Decimal('11.1'))
845 self.assertEqual(d2+d1, Decimal('11.1'))
846
847 #with other type, left
848 c = d1 + 5
849 self.assertEqual(c, Decimal('-6.1'))
850 self.assertEqual(type(c), type(d1))
851
852 #with other type, right
853 c = 5 + d1
854 self.assertEqual(c, Decimal('-6.1'))
855 self.assertEqual(type(c), type(d1))
856
857 #inline with decimal
858 d1 += d2
859 self.assertEqual(d1, Decimal('11.1'))
860
861 #inline with other type
862 d1 += 5
863 self.assertEqual(d1, Decimal('16.1'))
864
865 def test_subtraction(self):
866
867 d1 = Decimal('-11.1')
868 d2 = Decimal('22.2')
869
870 #two Decimals
871 self.assertEqual(d1-d2, Decimal('-33.3'))
872 self.assertEqual(d2-d1, Decimal('33.3'))
873
874 #with other type, left
875 c = d1 - 5
876 self.assertEqual(c, Decimal('-16.1'))
877 self.assertEqual(type(c), type(d1))
878
879 #with other type, right
880 c = 5 - d1
881 self.assertEqual(c, Decimal('16.1'))
882 self.assertEqual(type(c), type(d1))
883
884 #inline with decimal
885 d1 -= d2
886 self.assertEqual(d1, Decimal('-33.3'))
887
888 #inline with other type
889 d1 -= 5
890 self.assertEqual(d1, Decimal('-38.3'))
891
892 def test_multiplication(self):
893
894 d1 = Decimal('-5')
895 d2 = Decimal('3')
896
897 #two Decimals
898 self.assertEqual(d1*d2, Decimal('-15'))
899 self.assertEqual(d2*d1, Decimal('-15'))
900
901 #with other type, left
902 c = d1 * 5
903 self.assertEqual(c, Decimal('-25'))
904 self.assertEqual(type(c), type(d1))
905
906 #with other type, right
907 c = 5 * d1
908 self.assertEqual(c, Decimal('-25'))
909 self.assertEqual(type(c), type(d1))
910
911 #inline with decimal
912 d1 *= d2
913 self.assertEqual(d1, Decimal('-15'))
914
915 #inline with other type
916 d1 *= 5
917 self.assertEqual(d1, Decimal('-75'))
918
919 def test_division(self):
920
921 d1 = Decimal('-5')
922 d2 = Decimal('2')
923
924 #two Decimals
925 self.assertEqual(d1/d2, Decimal('-2.5'))
926 self.assertEqual(d2/d1, Decimal('-0.4'))
927
928 #with other type, left
929 c = d1 / 4
930 self.assertEqual(c, Decimal('-1.25'))
931 self.assertEqual(type(c), type(d1))
932
933 #with other type, right
934 c = 4 / d1
935 self.assertEqual(c, Decimal('-0.8'))
936 self.assertEqual(type(c), type(d1))
937
938 #inline with decimal
939 d1 /= d2
940 self.assertEqual(d1, Decimal('-2.5'))
941
942 #inline with other type
943 d1 /= 4
944 self.assertEqual(d1, Decimal('-0.625'))
945
946 def test_floor_division(self):
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000947
948 d1 = Decimal('5')
949 d2 = Decimal('2')
950
951 #two Decimals
952 self.assertEqual(d1//d2, Decimal('2'))
953 self.assertEqual(d2//d1, Decimal('0'))
954
955 #with other type, left
956 c = d1 // 4
957 self.assertEqual(c, Decimal('1'))
958 self.assertEqual(type(c), type(d1))
959
960 #with other type, right
961 c = 7 // d1
962 self.assertEqual(c, Decimal('1'))
963 self.assertEqual(type(c), type(d1))
964
965 #inline with decimal
966 d1 //= d2
967 self.assertEqual(d1, Decimal('2'))
968
969 #inline with other type
970 d1 //= 2
971 self.assertEqual(d1, Decimal('1'))
972
973 def test_powering(self):
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000974
975 d1 = Decimal('5')
976 d2 = Decimal('2')
977
978 #two Decimals
979 self.assertEqual(d1**d2, Decimal('25'))
980 self.assertEqual(d2**d1, Decimal('32'))
981
982 #with other type, left
983 c = d1 ** 4
984 self.assertEqual(c, Decimal('625'))
985 self.assertEqual(type(c), type(d1))
986
987 #with other type, right
988 c = 7 ** d1
989 self.assertEqual(c, Decimal('16807'))
990 self.assertEqual(type(c), type(d1))
991
992 #inline with decimal
993 d1 **= d2
994 self.assertEqual(d1, Decimal('25'))
995
996 #inline with other type
997 d1 **= 4
998 self.assertEqual(d1, Decimal('390625'))
999
1000 def test_module(self):
1001
1002 d1 = Decimal('5')
1003 d2 = Decimal('2')
1004
1005 #two Decimals
1006 self.assertEqual(d1%d2, Decimal('1'))
1007 self.assertEqual(d2%d1, Decimal('2'))
1008
1009 #with other type, left
1010 c = d1 % 4
1011 self.assertEqual(c, Decimal('1'))
1012 self.assertEqual(type(c), type(d1))
1013
1014 #with other type, right
1015 c = 7 % d1
1016 self.assertEqual(c, Decimal('2'))
1017 self.assertEqual(type(c), type(d1))
1018
1019 #inline with decimal
1020 d1 %= d2
1021 self.assertEqual(d1, Decimal('1'))
1022
1023 #inline with other type
1024 d1 %= 4
1025 self.assertEqual(d1, Decimal('1'))
1026
1027 def test_floor_div_module(self):
1028
1029 d1 = Decimal('5')
1030 d2 = Decimal('2')
1031
1032 #two Decimals
1033 (p, q) = divmod(d1, d2)
1034 self.assertEqual(p, Decimal('2'))
1035 self.assertEqual(q, Decimal('1'))
1036 self.assertEqual(type(p), type(d1))
1037 self.assertEqual(type(q), type(d1))
1038
1039 #with other type, left
1040 (p, q) = divmod(d1, 4)
1041 self.assertEqual(p, Decimal('1'))
1042 self.assertEqual(q, Decimal('1'))
1043 self.assertEqual(type(p), type(d1))
1044 self.assertEqual(type(q), type(d1))
1045
1046 #with other type, right
1047 (p, q) = divmod(7, d1)
1048 self.assertEqual(p, Decimal('1'))
1049 self.assertEqual(q, Decimal('2'))
1050 self.assertEqual(type(p), type(d1))
1051 self.assertEqual(type(q), type(d1))
1052
1053 def test_unary_operators(self):
1054 self.assertEqual(+Decimal(45), Decimal(+45)) # +
1055 self.assertEqual(-Decimal(45), Decimal(-45)) # -
1056 self.assertEqual(abs(Decimal(45)), abs(Decimal(-45))) # abs
1057
Mark Dickinson2fc92632008-02-06 22:10:50 +00001058 def test_nan_comparisons(self):
1059 n = Decimal('NaN')
1060 s = Decimal('sNaN')
1061 i = Decimal('Inf')
1062 f = Decimal('2')
1063 for x, y in [(n, n), (n, i), (i, n), (n, f), (f, n),
1064 (s, n), (n, s), (s, i), (i, s), (s, f), (f, s), (s, s)]:
1065 self.assert_(x != y)
1066 self.assert_(not (x == y))
1067 self.assert_(not (x < y))
1068 self.assert_(not (x <= y))
1069 self.assert_(not (x > y))
1070 self.assert_(not (x >= y))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001071
1072# The following are two functions used to test threading in the next class
1073
1074def thfunc1(cls):
1075 d1 = Decimal(1)
1076 d3 = Decimal(3)
Facundo Batista64156672008-03-22 02:45:37 +00001077 test1 = d1/d3
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001078 cls.synchro.wait()
Facundo Batista64156672008-03-22 02:45:37 +00001079 test2 = d1/d3
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001080 cls.finish1.set()
Facundo Batista64156672008-03-22 02:45:37 +00001081
Facundo Batistaee340e52008-05-02 17:39:00 +00001082 cls.assertEqual(test1, Decimal('0.3333333333333333333333333333'))
1083 cls.assertEqual(test2, Decimal('0.3333333333333333333333333333'))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001084 return
1085
1086def thfunc2(cls):
1087 d1 = Decimal(1)
1088 d3 = Decimal(3)
Facundo Batista64156672008-03-22 02:45:37 +00001089 test1 = d1/d3
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001090 thiscontext = getcontext()
1091 thiscontext.prec = 18
Facundo Batista64156672008-03-22 02:45:37 +00001092 test2 = d1/d3
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001093 cls.synchro.set()
1094 cls.finish2.set()
Facundo Batista64156672008-03-22 02:45:37 +00001095
Facundo Batistaee340e52008-05-02 17:39:00 +00001096 cls.assertEqual(test1, Decimal('0.3333333333333333333333333333'))
Facundo Batista64156672008-03-22 02:45:37 +00001097 cls.assertEqual(test2, Decimal('0.333333333333333333'))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001098 return
1099
1100
1101class DecimalUseOfContextTest(unittest.TestCase):
1102 '''Unit tests for Use of Context cases in Decimal.'''
1103
Raymond Hettinger7e71fa52004-12-18 19:07:19 +00001104 try:
1105 import threading
1106 except ImportError:
1107 threading = None
1108
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001109 # Take care executing this test from IDLE, there's an issue in threading
1110 # that hangs IDLE and I couldn't find it
1111
1112 def test_threading(self):
1113 #Test the "threading isolation" of a Context.
1114
1115 self.synchro = threading.Event()
1116 self.finish1 = threading.Event()
1117 self.finish2 = threading.Event()
1118
1119 th1 = threading.Thread(target=thfunc1, args=(self,))
1120 th2 = threading.Thread(target=thfunc2, args=(self,))
1121
1122 th1.start()
1123 th2.start()
1124
1125 self.finish1.wait()
Thomas Woutersb3e6e8c2007-09-19 17:27:29 +00001126 self.finish2.wait()
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001127 return
1128
Raymond Hettinger7e71fa52004-12-18 19:07:19 +00001129 if threading is None:
1130 del test_threading
1131
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001132
1133class DecimalUsabilityTest(unittest.TestCase):
1134 '''Unit tests for Usability cases of Decimal.'''
1135
1136 def test_comparison_operators(self):
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001137
1138 da = Decimal('23.42')
1139 db = Decimal('23.42')
1140 dc = Decimal('45')
1141
1142 #two Decimals
1143 self.failUnless(dc > da)
1144 self.failUnless(dc >= da)
1145 self.failUnless(da < dc)
1146 self.failUnless(da <= dc)
1147 self.failUnless(da == db)
1148 self.failUnless(da != dc)
1149 self.failUnless(da <= db)
1150 self.failUnless(da >= db)
1151 self.assertEqual(cmp(dc,da), 1)
1152 self.assertEqual(cmp(da,dc), -1)
1153 self.assertEqual(cmp(da,db), 0)
1154
1155 #a Decimal and an int
1156 self.failUnless(dc > 23)
1157 self.failUnless(23 < dc)
1158 self.failUnless(dc == 45)
1159 self.assertEqual(cmp(dc,23), 1)
1160 self.assertEqual(cmp(23,dc), -1)
1161 self.assertEqual(cmp(dc,45), 0)
1162
1163 #a Decimal and uncomparable
Raymond Hettinger0aeac102004-07-05 22:53:03 +00001164 self.assertNotEqual(da, 'ugly')
1165 self.assertNotEqual(da, 32.7)
1166 self.assertNotEqual(da, object())
1167 self.assertNotEqual(da, object)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001168
Raymond Hettinger0aeac102004-07-05 22:53:03 +00001169 # sortable
1170 a = map(Decimal, xrange(100))
1171 b = a[:]
1172 random.shuffle(a)
1173 a.sort()
1174 self.assertEqual(a, b)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001175
Facundo Batista353750c2007-09-13 18:13:15 +00001176 # with None
1177 self.assertFalse(Decimal(1) < None)
1178 self.assertTrue(Decimal(1) > None)
1179
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001180 def test_copy_and_deepcopy_methods(self):
1181 d = Decimal('43.24')
1182 c = copy.copy(d)
1183 self.assertEqual(id(c), id(d))
1184 dc = copy.deepcopy(d)
1185 self.assertEqual(id(dc), id(d))
1186
1187 def test_hash_method(self):
1188 #just that it's hashable
1189 hash(Decimal(23))
Facundo Batista8c202442007-09-19 17:53:25 +00001190
1191 test_values = [Decimal(sign*(2**m + n))
1192 for m in [0, 14, 15, 16, 17, 30, 31,
1193 32, 33, 62, 63, 64, 65, 66]
1194 for n in range(-10, 10)
1195 for sign in [-1, 1]]
1196 test_values.extend([
1197 Decimal("-0"), # zeros
1198 Decimal("0.00"),
1199 Decimal("-0.000"),
1200 Decimal("0E10"),
1201 Decimal("-0E12"),
1202 Decimal("10.0"), # negative exponent
1203 Decimal("-23.00000"),
1204 Decimal("1230E100"), # positive exponent
1205 Decimal("-4.5678E50"),
1206 # a value for which hash(n) != hash(n % (2**64-1))
1207 # in Python pre-2.6
1208 Decimal(2**64 + 2**32 - 1),
1209 # selection of values which fail with the old (before
1210 # version 2.6) long.__hash__
1211 Decimal("1.634E100"),
1212 Decimal("90.697E100"),
1213 Decimal("188.83E100"),
1214 Decimal("1652.9E100"),
1215 Decimal("56531E100"),
1216 ])
1217
1218 # check that hash(d) == hash(int(d)) for integral values
1219 for value in test_values:
1220 self.assertEqual(hash(value), hash(int(value)))
1221
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001222 #the same hash that to an int
1223 self.assertEqual(hash(Decimal(23)), hash(23))
Raymond Hettingerbea3f6f2005-03-15 04:59:17 +00001224 self.assertRaises(TypeError, hash, Decimal('NaN'))
1225 self.assert_(hash(Decimal('Inf')))
1226 self.assert_(hash(Decimal('-Inf')))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001227
Facundo Batista52b25792008-01-08 12:25:20 +00001228 # check that the value of the hash doesn't depend on the
1229 # current context (issue #1757)
1230 c = getcontext()
1231 old_precision = c.prec
1232 x = Decimal("123456789.1")
1233
1234 c.prec = 6
1235 h1 = hash(x)
1236 c.prec = 10
1237 h2 = hash(x)
1238 c.prec = 16
1239 h3 = hash(x)
1240
1241 self.assertEqual(h1, h2)
1242 self.assertEqual(h1, h3)
1243 c.prec = old_precision
1244
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001245 def test_min_and_max_methods(self):
1246
1247 d1 = Decimal('15.32')
1248 d2 = Decimal('28.5')
1249 l1 = 15
1250 l2 = 28
1251
1252 #between Decimals
1253 self.failUnless(min(d1,d2) is d1)
1254 self.failUnless(min(d2,d1) is d1)
1255 self.failUnless(max(d1,d2) is d2)
1256 self.failUnless(max(d2,d1) is d2)
1257
1258 #between Decimal and long
1259 self.failUnless(min(d1,l2) is d1)
1260 self.failUnless(min(l2,d1) is d1)
1261 self.failUnless(max(l1,d2) is d2)
1262 self.failUnless(max(d2,l1) is d2)
1263
1264 def test_as_nonzero(self):
1265 #as false
1266 self.failIf(Decimal(0))
1267 #as true
1268 self.failUnless(Decimal('0.372'))
1269
1270 def test_tostring_methods(self):
1271 #Test str and repr methods.
1272
1273 d = Decimal('15.32')
1274 self.assertEqual(str(d), '15.32') # str
Raymond Hettingerabe32372008-02-14 02:41:22 +00001275 self.assertEqual(repr(d), "Decimal('15.32')") # repr
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001276
Mark Dickinson8e85ffa2008-03-25 18:47:59 +00001277 # result type of string methods should be str, not unicode
1278 unicode_inputs = [u'123.4', u'0.5E2', u'Infinity', u'sNaN',
1279 u'-0.0E100', u'-NaN001', u'-Inf']
1280
1281 for u in unicode_inputs:
1282 d = Decimal(u)
1283 self.assertEqual(type(str(d)), str)
1284 self.assertEqual(type(repr(d)), str)
1285 self.assertEqual(type(d.to_eng_string()), str)
1286
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001287 def test_tonum_methods(self):
1288 #Test float, int and long methods.
1289
1290 d1 = Decimal('66')
1291 d2 = Decimal('15.32')
1292
1293 #int
1294 self.assertEqual(int(d1), 66)
1295 self.assertEqual(int(d2), 15)
1296
1297 #long
1298 self.assertEqual(long(d1), 66)
1299 self.assertEqual(long(d2), 15)
1300
1301 #float
1302 self.assertEqual(float(d1), 66)
1303 self.assertEqual(float(d2), 15.32)
1304
1305 def test_eval_round_trip(self):
1306
1307 #with zero
1308 d = Decimal( (0, (0,), 0) )
1309 self.assertEqual(d, eval(repr(d)))
1310
1311 #int
1312 d = Decimal( (1, (4, 5), 0) )
1313 self.assertEqual(d, eval(repr(d)))
1314
1315 #float
1316 d = Decimal( (0, (4, 5, 3, 4), -2) )
1317 self.assertEqual(d, eval(repr(d)))
1318
1319 #weird
1320 d = Decimal( (1, (4, 3, 4, 9, 1, 3, 5, 3, 4), -25) )
1321 self.assertEqual(d, eval(repr(d)))
1322
1323 def test_as_tuple(self):
1324
1325 #with zero
1326 d = Decimal(0)
1327 self.assertEqual(d.as_tuple(), (0, (0,), 0) )
1328
1329 #int
1330 d = Decimal(-45)
1331 self.assertEqual(d.as_tuple(), (1, (4, 5), 0) )
1332
1333 #complicated string
1334 d = Decimal("-4.34913534E-17")
1335 self.assertEqual(d.as_tuple(), (1, (4, 3, 4, 9, 1, 3, 5, 3, 4), -25) )
1336
1337 #inf
1338 d = Decimal("Infinity")
1339 self.assertEqual(d.as_tuple(), (0, (0,), 'F') )
1340
Facundo Batista9b5e2312007-10-19 19:25:57 +00001341 #leading zeros in coefficient should be stripped
1342 d = Decimal( (0, (0, 0, 4, 0, 5, 3, 4), -2) )
1343 self.assertEqual(d.as_tuple(), (0, (4, 0, 5, 3, 4), -2) )
1344 d = Decimal( (1, (0, 0, 0), 37) )
1345 self.assertEqual(d.as_tuple(), (1, (0,), 37))
1346 d = Decimal( (1, (), 37) )
1347 self.assertEqual(d.as_tuple(), (1, (0,), 37))
1348
1349 #leading zeros in NaN diagnostic info should be stripped
1350 d = Decimal( (0, (0, 0, 4, 0, 5, 3, 4), 'n') )
1351 self.assertEqual(d.as_tuple(), (0, (4, 0, 5, 3, 4), 'n') )
1352 d = Decimal( (1, (0, 0, 0), 'N') )
1353 self.assertEqual(d.as_tuple(), (1, (), 'N') )
1354 d = Decimal( (1, (), 'n') )
1355 self.assertEqual(d.as_tuple(), (1, (), 'n') )
1356
1357 #coefficient in infinity should be ignored
1358 d = Decimal( (0, (4, 5, 3, 4), 'F') )
1359 self.assertEqual(d.as_tuple(), (0, (0,), 'F'))
1360 d = Decimal( (1, (0, 2, 7, 1), 'F') )
1361 self.assertEqual(d.as_tuple(), (1, (0,), 'F'))
1362
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001363 def test_immutability_operations(self):
1364 # Do operations and check that it didn't change change internal objects.
1365
1366 d1 = Decimal('-25e55')
1367 b1 = Decimal('-25e55')
Facundo Batista353750c2007-09-13 18:13:15 +00001368 d2 = Decimal('33e+33')
1369 b2 = Decimal('33e+33')
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001370
1371 def checkSameDec(operation, useOther=False):
1372 if useOther:
1373 eval("d1." + operation + "(d2)")
1374 self.assertEqual(d1._sign, b1._sign)
1375 self.assertEqual(d1._int, b1._int)
1376 self.assertEqual(d1._exp, b1._exp)
1377 self.assertEqual(d2._sign, b2._sign)
1378 self.assertEqual(d2._int, b2._int)
1379 self.assertEqual(d2._exp, b2._exp)
1380 else:
1381 eval("d1." + operation + "()")
1382 self.assertEqual(d1._sign, b1._sign)
1383 self.assertEqual(d1._int, b1._int)
1384 self.assertEqual(d1._exp, b1._exp)
1385 return
1386
1387 Decimal(d1)
1388 self.assertEqual(d1._sign, b1._sign)
1389 self.assertEqual(d1._int, b1._int)
1390 self.assertEqual(d1._exp, b1._exp)
1391
1392 checkSameDec("__abs__")
1393 checkSameDec("__add__", True)
1394 checkSameDec("__div__", True)
1395 checkSameDec("__divmod__", True)
Mark Dickinson2fc92632008-02-06 22:10:50 +00001396 checkSameDec("__eq__", True)
1397 checkSameDec("__ne__", True)
1398 checkSameDec("__le__", True)
1399 checkSameDec("__lt__", True)
1400 checkSameDec("__ge__", True)
1401 checkSameDec("__gt__", True)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001402 checkSameDec("__float__")
1403 checkSameDec("__floordiv__", True)
1404 checkSameDec("__hash__")
1405 checkSameDec("__int__")
Raymond Hettinger5a053642008-01-24 19:05:29 +00001406 checkSameDec("__trunc__")
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001407 checkSameDec("__long__")
1408 checkSameDec("__mod__", True)
1409 checkSameDec("__mul__", True)
1410 checkSameDec("__neg__")
1411 checkSameDec("__nonzero__")
1412 checkSameDec("__pos__")
1413 checkSameDec("__pow__", True)
1414 checkSameDec("__radd__", True)
1415 checkSameDec("__rdiv__", True)
1416 checkSameDec("__rdivmod__", True)
1417 checkSameDec("__repr__")
1418 checkSameDec("__rfloordiv__", True)
1419 checkSameDec("__rmod__", True)
1420 checkSameDec("__rmul__", True)
1421 checkSameDec("__rpow__", True)
1422 checkSameDec("__rsub__", True)
1423 checkSameDec("__str__")
1424 checkSameDec("__sub__", True)
1425 checkSameDec("__truediv__", True)
1426 checkSameDec("adjusted")
1427 checkSameDec("as_tuple")
1428 checkSameDec("compare", True)
1429 checkSameDec("max", True)
1430 checkSameDec("min", True)
1431 checkSameDec("normalize")
1432 checkSameDec("quantize", True)
1433 checkSameDec("remainder_near", True)
1434 checkSameDec("same_quantum", True)
1435 checkSameDec("sqrt")
1436 checkSameDec("to_eng_string")
1437 checkSameDec("to_integral")
1438
Facundo Batista6c398da2007-09-17 17:30:13 +00001439 def test_subclassing(self):
1440 # Different behaviours when subclassing Decimal
1441
1442 class MyDecimal(Decimal):
1443 pass
1444
1445 d1 = MyDecimal(1)
1446 d2 = MyDecimal(2)
1447 d = d1 + d2
1448 self.assertTrue(type(d) is Decimal)
1449
1450 d = d1.max(d2)
1451 self.assertTrue(type(d) is Decimal)
1452
Mark Dickinson3b24ccb2008-03-25 14:33:23 +00001453 def test_implicit_context(self):
1454 # Check results when context given implicitly. (Issue 2478)
1455 c = getcontext()
1456 self.assertEqual(str(Decimal(0).sqrt()),
1457 str(c.sqrt(Decimal(0))))
1458
Facundo Batista6c398da2007-09-17 17:30:13 +00001459
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001460class DecimalPythonAPItests(unittest.TestCase):
1461
Raymond Hettinger2c8585b2009-02-03 03:37:03 +00001462 def test_abc(self):
1463 self.assert_(issubclass(Decimal, numbers.Number))
1464 self.assert_(not issubclass(Decimal, numbers.Real))
1465 self.assert_(isinstance(Decimal(0), numbers.Number))
1466 self.assert_(not isinstance(Decimal(0), numbers.Real))
1467
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001468 def test_pickle(self):
1469 d = Decimal('-3.141590000')
1470 p = pickle.dumps(d)
1471 e = pickle.loads(p)
1472 self.assertEqual(d, e)
1473
Raymond Hettinger5548be22004-07-05 18:49:38 +00001474 def test_int(self):
Raymond Hettinger605ed022004-11-24 07:28:48 +00001475 for x in range(-250, 250):
1476 s = '%0.2f' % (x / 100.0)
Raymond Hettinger5548be22004-07-05 18:49:38 +00001477 # should work the same as for floats
1478 self.assertEqual(int(Decimal(s)), int(float(s)))
Raymond Hettinger605ed022004-11-24 07:28:48 +00001479 # should work the same as to_integral in the ROUND_DOWN mode
Raymond Hettinger5548be22004-07-05 18:49:38 +00001480 d = Decimal(s)
Raymond Hettinger605ed022004-11-24 07:28:48 +00001481 r = d.to_integral(ROUND_DOWN)
Raymond Hettinger5548be22004-07-05 18:49:38 +00001482 self.assertEqual(Decimal(int(d)), r)
1483
Raymond Hettinger5a053642008-01-24 19:05:29 +00001484 def test_trunc(self):
1485 for x in range(-250, 250):
1486 s = '%0.2f' % (x / 100.0)
1487 # should work the same as for floats
1488 self.assertEqual(int(Decimal(s)), int(float(s)))
1489 # should work the same as to_integral in the ROUND_DOWN mode
1490 d = Decimal(s)
1491 r = d.to_integral(ROUND_DOWN)
Jeffrey Yasskinca2b69f2008-02-01 06:22:46 +00001492 self.assertEqual(Decimal(math.trunc(d)), r)
Raymond Hettinger5a053642008-01-24 19:05:29 +00001493
Raymond Hettingerf4d85972009-01-03 19:02:23 +00001494 def test_from_float(self):
1495
1496 class MyDecimal(Decimal):
1497 pass
1498
1499 r = MyDecimal.from_float(0.1)
1500 self.assertEqual(type(r), MyDecimal)
1501 self.assertEqual(str(r),
1502 '0.1000000000000000055511151231257827021181583404541015625')
1503 bigint = 12345678901234567890123456789
1504 self.assertEqual(MyDecimal.from_float(bigint), MyDecimal(bigint))
1505 self.assert_(MyDecimal.from_float(float('nan')).is_qnan())
1506 self.assert_(MyDecimal.from_float(float('inf')).is_infinite())
1507 self.assert_(MyDecimal.from_float(float('-inf')).is_infinite())
1508 self.assertEqual(str(MyDecimal.from_float(float('nan'))),
1509 str(Decimal('NaN')))
1510 self.assertEqual(str(MyDecimal.from_float(float('inf'))),
1511 str(Decimal('Infinity')))
1512 self.assertEqual(str(MyDecimal.from_float(float('-inf'))),
1513 str(Decimal('-Infinity')))
1514 self.assertRaises(TypeError, MyDecimal.from_float, 'abc')
1515 for i in range(200):
1516 x = random.expovariate(0.01) * (random.random() * 2.0 - 1.0)
1517 self.assertEqual(x, float(MyDecimal.from_float(x))) # roundtrip
1518
1519 def test_create_decimal_from_float(self):
1520 context = Context(prec=5, rounding=ROUND_DOWN)
1521 self.assertEqual(
1522 context.create_decimal_from_float(math.pi),
1523 Decimal('3.1415')
1524 )
1525 context = Context(prec=5, rounding=ROUND_UP)
1526 self.assertEqual(
1527 context.create_decimal_from_float(math.pi),
1528 Decimal('3.1416')
1529 )
1530 context = Context(prec=5, traps=[Inexact])
1531 self.assertRaises(
1532 Inexact,
1533 context.create_decimal_from_float,
1534 math.pi
1535 )
1536 self.assertEqual(repr(context.create_decimal_from_float(-0.0)),
1537 "Decimal('-0')")
1538 self.assertEqual(repr(context.create_decimal_from_float(1.0)),
1539 "Decimal('1')")
1540 self.assertEqual(repr(context.create_decimal_from_float(10)),
1541 "Decimal('10')")
1542
Raymond Hettingerd9c0a7a2004-07-03 10:02:28 +00001543class ContextAPItests(unittest.TestCase):
1544
1545 def test_pickle(self):
1546 c = Context()
1547 e = pickle.loads(pickle.dumps(c))
1548 for k in vars(c):
1549 v1 = vars(c)[k]
1550 v2 = vars(e)[k]
1551 self.assertEqual(v1, v2)
1552
Raymond Hettinger0aeac102004-07-05 22:53:03 +00001553 def test_equality_with_other_types(self):
1554 self.assert_(Decimal(10) in ['a', 1.0, Decimal(10), (1,2), {}])
1555 self.assert_(Decimal(10) not in ['a', 1.0, (1,2), {}])
1556
Raymond Hettinger955d2b22004-08-08 20:17:45 +00001557 def test_copy(self):
1558 # All copies should be deep
1559 c = Context()
1560 d = c.copy()
1561 self.assertNotEqual(id(c), id(d))
1562 self.assertNotEqual(id(c.flags), id(d.flags))
1563 self.assertNotEqual(id(c.traps), id(d.traps))
1564
Nick Coghlan8b6999b2006-08-31 12:00:43 +00001565class WithStatementTest(unittest.TestCase):
1566 # Can't do these as docstrings until Python 2.6
1567 # as doctest can't handle __future__ statements
Nick Coghlan8b6999b2006-08-31 12:00:43 +00001568
1569 def test_localcontext(self):
Nick Coghlanced12182006-09-02 03:54:17 +00001570 # Use a copy of the current context in the block
Nick Coghlan8b6999b2006-08-31 12:00:43 +00001571 orig_ctx = getcontext()
1572 with localcontext() as enter_ctx:
1573 set_ctx = getcontext()
1574 final_ctx = getcontext()
1575 self.assert_(orig_ctx is final_ctx, 'did not restore context correctly')
1576 self.assert_(orig_ctx is not set_ctx, 'did not copy the context')
1577 self.assert_(set_ctx is enter_ctx, '__enter__ returned wrong context')
1578
1579 def test_localcontextarg(self):
Nick Coghlanced12182006-09-02 03:54:17 +00001580 # Use a copy of the supplied context in the block
Nick Coghlan8b6999b2006-08-31 12:00:43 +00001581 orig_ctx = getcontext()
1582 new_ctx = Context(prec=42)
1583 with localcontext(new_ctx) as enter_ctx:
1584 set_ctx = getcontext()
1585 final_ctx = getcontext()
1586 self.assert_(orig_ctx is final_ctx, 'did not restore context correctly')
1587 self.assert_(set_ctx.prec == new_ctx.prec, 'did not set correct context')
1588 self.assert_(new_ctx is not set_ctx, 'did not copy the context')
1589 self.assert_(set_ctx is enter_ctx, '__enter__ returned wrong context')
1590
Facundo Batista353750c2007-09-13 18:13:15 +00001591class ContextFlags(unittest.TestCase):
1592 def test_flags_irrelevant(self):
1593 # check that the result (numeric result + flags raised) of an
1594 # arithmetic operation doesn't depend on the current flags
1595
1596 context = Context(prec=9, Emin = -999999999, Emax = 999999999,
1597 rounding=ROUND_HALF_EVEN, traps=[], flags=[])
1598
1599 # operations that raise various flags, in the form (function, arglist)
1600 operations = [
1601 (context._apply, [Decimal("100E-1000000009")]),
1602 (context.sqrt, [Decimal(2)]),
1603 (context.add, [Decimal("1.23456789"), Decimal("9.87654321")]),
1604 (context.multiply, [Decimal("1.23456789"), Decimal("9.87654321")]),
1605 (context.subtract, [Decimal("1.23456789"), Decimal("9.87654321")]),
1606 ]
1607
1608 # try various flags individually, then a whole lot at once
1609 flagsets = [[Inexact], [Rounded], [Underflow], [Clamped], [Subnormal],
1610 [Inexact, Rounded, Underflow, Clamped, Subnormal]]
1611
1612 for fn, args in operations:
1613 # find answer and flags raised using a clean context
1614 context.clear_flags()
1615 ans = fn(*args)
1616 flags = [k for k, v in context.flags.items() if v]
1617
1618 for extra_flags in flagsets:
1619 # set flags, before calling operation
1620 context.clear_flags()
1621 for flag in extra_flags:
1622 context._raise_error(flag)
1623 new_ans = fn(*args)
1624
1625 # flags that we expect to be set after the operation
1626 expected_flags = list(flags)
1627 for flag in extra_flags:
1628 if flag not in expected_flags:
1629 expected_flags.append(flag)
1630 expected_flags.sort()
1631
1632 # flags we actually got
1633 new_flags = [k for k,v in context.flags.items() if v]
1634 new_flags.sort()
1635
1636 self.assertEqual(ans, new_ans,
1637 "operation produces different answers depending on flags set: " +
1638 "expected %s, got %s." % (ans, new_ans))
1639 self.assertEqual(new_flags, expected_flags,
1640 "operation raises different flags depending on flags set: " +
1641 "expected %s, got %s" % (expected_flags, new_flags))
1642
1643def test_main(arith=False, verbose=None, todo_tests=None, debug=None):
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001644 """ Execute the tests.
1645
Raymond Hettingered20ad82004-09-04 20:09:13 +00001646 Runs all arithmetic tests if arith is True or if the "decimal" resource
1647 is enabled in regrtest.py
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001648 """
Raymond Hettingered20ad82004-09-04 20:09:13 +00001649
Neal Norwitzce4a9c92006-04-09 08:36:46 +00001650 init()
Facundo Batista353750c2007-09-13 18:13:15 +00001651 global TEST_ALL, DEBUG
Raymond Hettingered20ad82004-09-04 20:09:13 +00001652 TEST_ALL = arith or is_resource_enabled('decimal')
Facundo Batista353750c2007-09-13 18:13:15 +00001653 DEBUG = debug
Raymond Hettingered20ad82004-09-04 20:09:13 +00001654
Facundo Batista353750c2007-09-13 18:13:15 +00001655 if todo_tests is None:
1656 test_classes = [
1657 DecimalExplicitConstructionTest,
1658 DecimalImplicitConstructionTest,
1659 DecimalArithmeticOperatorsTest,
Mark Dickinson1ddf1d82008-02-29 02:16:37 +00001660 DecimalFormatTest,
Facundo Batista353750c2007-09-13 18:13:15 +00001661 DecimalUseOfContextTest,
1662 DecimalUsabilityTest,
1663 DecimalPythonAPItests,
1664 ContextAPItests,
1665 DecimalTest,
1666 WithStatementTest,
1667 ContextFlags
1668 ]
1669 else:
1670 test_classes = [DecimalTest]
1671
1672 # Dynamically build custom test definition for each file in the test
1673 # directory and add the definitions to the DecimalTest class. This
1674 # procedure insures that new files do not get skipped.
1675 for filename in os.listdir(directory):
1676 if '.decTest' not in filename or filename.startswith("."):
1677 continue
1678 head, tail = filename.split('.')
1679 if todo_tests is not None and head not in todo_tests:
1680 continue
1681 tester = lambda self, f=filename: self.eval_file(directory + f)
1682 setattr(DecimalTest, 'test_' + head, tester)
1683 del filename, head, tail, tester
1684
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001685
Tim Peters46cc7022006-03-31 04:11:16 +00001686 try:
1687 run_unittest(*test_classes)
Facundo Batista353750c2007-09-13 18:13:15 +00001688 if todo_tests is None:
1689 import decimal as DecimalModule
1690 run_doctest(DecimalModule, verbose)
Tim Peters46cc7022006-03-31 04:11:16 +00001691 finally:
1692 setcontext(ORIGINAL_CONTEXT)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001693
1694if __name__ == '__main__':
Facundo Batista353750c2007-09-13 18:13:15 +00001695 import optparse
1696 p = optparse.OptionParser("test_decimal.py [--debug] [{--skip | test1 [test2 [...]]}]")
1697 p.add_option('--debug', '-d', action='store_true', help='shows the test number and context before each test')
1698 p.add_option('--skip', '-s', action='store_true', help='skip over 90% of the arithmetic tests')
1699 (opt, args) = p.parse_args()
1700
1701 if opt.skip:
1702 test_main(arith=False, verbose=True)
1703 elif args:
1704 test_main(arith=True, verbose=True, todo_tests=args, debug=opt.debug)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001705 else:
Facundo Batista353750c2007-09-13 18:13:15 +00001706 test_main(arith=True, verbose=True)