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