blob: 01282315c66e698f5f79abeeba30168ccff92ee5 [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
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000434 def test_explicit_from_tuples(self):
435
436 #zero
437 d = Decimal( (0, (0,), 0) )
438 self.assertEqual(str(d), '0')
439
440 #int
441 d = Decimal( (1, (4, 5), 0) )
442 self.assertEqual(str(d), '-45')
443
444 #float
445 d = Decimal( (0, (4, 5, 3, 4), -2) )
446 self.assertEqual(str(d), '45.34')
447
448 #weird
449 d = Decimal( (1, (4, 3, 4, 9, 1, 3, 5, 3, 4), -25) )
450 self.assertEqual(str(d), '-4.34913534E-17')
451
452 #wrong number of items
453 self.assertRaises(ValueError, Decimal, (1, (4, 3, 4, 9, 1)) )
454
455 #bad sign
456 self.assertRaises(ValueError, Decimal, (8, (4, 3, 4, 9, 1), 2) )
Facundo Batista9b5e2312007-10-19 19:25:57 +0000457 self.assertRaises(ValueError, Decimal, (0., (4, 3, 4, 9, 1), 2) )
458 self.assertRaises(ValueError, Decimal, (Decimal(1), (4, 3, 4, 9, 1), 2))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000459
460 #bad exp
461 self.assertRaises(ValueError, Decimal, (1, (4, 3, 4, 9, 1), 'wrong!') )
Facundo Batista9b5e2312007-10-19 19:25:57 +0000462 self.assertRaises(ValueError, Decimal, (1, (4, 3, 4, 9, 1), 0.) )
463 self.assertRaises(ValueError, Decimal, (1, (4, 3, 4, 9, 1), '1') )
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000464
465 #bad coefficients
466 self.assertRaises(ValueError, Decimal, (1, (4, 3, 4, None, 1), 2) )
467 self.assertRaises(ValueError, Decimal, (1, (4, -3, 4, 9, 1), 2) )
Facundo Batista9b5e2312007-10-19 19:25:57 +0000468 self.assertRaises(ValueError, Decimal, (1, (4, 10, 4, 9, 1), 2) )
Facundo Batista72bc54f2007-11-23 17:59:00 +0000469 self.assertRaises(ValueError, Decimal, (1, (4, 3, 4, 'a', 1), 2) )
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000470
471 def test_explicit_from_Decimal(self):
472
473 #positive
474 d = Decimal(45)
475 e = Decimal(d)
476 self.assertEqual(str(e), '45')
477 self.assertNotEqual(id(d), id(e))
478
479 #very large positive
480 d = Decimal(500000123)
481 e = Decimal(d)
482 self.assertEqual(str(e), '500000123')
483 self.assertNotEqual(id(d), id(e))
484
485 #negative
486 d = Decimal(-45)
487 e = Decimal(d)
488 self.assertEqual(str(e), '-45')
489 self.assertNotEqual(id(d), id(e))
490
491 #zero
492 d = Decimal(0)
493 e = Decimal(d)
494 self.assertEqual(str(e), '0')
495 self.assertNotEqual(id(d), id(e))
496
497 def test_explicit_context_create_decimal(self):
498
499 nc = copy.copy(getcontext())
500 nc.prec = 3
501
502 # empty
Raymond Hettingerfed52962004-07-14 15:41:57 +0000503 d = Decimal()
504 self.assertEqual(str(d), '0')
505 d = nc.create_decimal()
506 self.assertEqual(str(d), '0')
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000507
508 # from None
509 self.assertRaises(TypeError, nc.create_decimal, None)
510
511 # from int
512 d = nc.create_decimal(456)
Benjamin Peterson5c8da862009-06-30 22:57:08 +0000513 self.assertTrue(isinstance(d, Decimal))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000514 self.assertEqual(nc.create_decimal(45678),
515 nc.create_decimal('457E+2'))
516
517 # from string
518 d = Decimal('456789')
519 self.assertEqual(str(d), '456789')
520 d = nc.create_decimal('456789')
521 self.assertEqual(str(d), '4.57E+5')
Mark Dickinson59bc20b2008-01-12 01:56:00 +0000522 # leading and trailing whitespace should result in a NaN;
523 # spaces are already checked in Cowlishaw's test-suite, so
524 # here we just check that a trailing newline results in a NaN
525 self.assertEqual(str(nc.create_decimal('3.14\n')), 'NaN')
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000526
527 # from tuples
528 d = Decimal( (1, (4, 3, 4, 9, 1, 3, 5, 3, 4), -25) )
529 self.assertEqual(str(d), '-4.34913534E-17')
530 d = nc.create_decimal( (1, (4, 3, 4, 9, 1, 3, 5, 3, 4), -25) )
531 self.assertEqual(str(d), '-4.35E-17')
532
533 # from Decimal
534 prevdec = Decimal(500000123)
535 d = Decimal(prevdec)
536 self.assertEqual(str(d), '500000123')
537 d = nc.create_decimal(prevdec)
538 self.assertEqual(str(d), '5.00E+8')
539
Mark Dickinson4326ad82009-08-02 10:59:36 +0000540 def test_unicode_digits(self):
541 test_values = {
542 u'\uff11': '1',
543 u'\u0660.\u0660\u0663\u0667\u0662e-\u0663' : '0.0000372',
544 u'-nan\u0c68\u0c6a\u0c66\u0c66' : '-NaN2400',
545 }
546 for input, expected in test_values.items():
547 self.assertEqual(str(Decimal(input)), expected)
548
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000549
550class DecimalImplicitConstructionTest(unittest.TestCase):
551 '''Unit tests for Implicit Construction cases of Decimal.'''
552
553 def test_implicit_from_None(self):
554 self.assertRaises(TypeError, eval, 'Decimal(5) + None', globals())
555
556 def test_implicit_from_int(self):
557 #normal
558 self.assertEqual(str(Decimal(5) + 45), '50')
559 #exceeding precision
560 self.assertEqual(Decimal(5) + 123456789000, Decimal(123456789000))
561
562 def test_implicit_from_string(self):
563 self.assertRaises(TypeError, eval, 'Decimal(5) + "3"', globals())
564
565 def test_implicit_from_float(self):
566 self.assertRaises(TypeError, eval, 'Decimal(5) + 2.2', globals())
567
568 def test_implicit_from_Decimal(self):
569 self.assertEqual(Decimal(5) + Decimal(45), Decimal(50))
570
Raymond Hettinger267b8682005-03-27 10:47:39 +0000571 def test_rop(self):
572 # Allow other classes to be trained to interact with Decimals
573 class E:
574 def __divmod__(self, other):
575 return 'divmod ' + str(other)
576 def __rdivmod__(self, other):
577 return str(other) + ' rdivmod'
578 def __lt__(self, other):
579 return 'lt ' + str(other)
580 def __gt__(self, other):
581 return 'gt ' + str(other)
582 def __le__(self, other):
583 return 'le ' + str(other)
584 def __ge__(self, other):
585 return 'ge ' + str(other)
586 def __eq__(self, other):
587 return 'eq ' + str(other)
588 def __ne__(self, other):
589 return 'ne ' + str(other)
590
591 self.assertEqual(divmod(E(), Decimal(10)), 'divmod 10')
592 self.assertEqual(divmod(Decimal(10), E()), '10 rdivmod')
593 self.assertEqual(eval('Decimal(10) < E()'), 'gt 10')
594 self.assertEqual(eval('Decimal(10) > E()'), 'lt 10')
595 self.assertEqual(eval('Decimal(10) <= E()'), 'ge 10')
596 self.assertEqual(eval('Decimal(10) >= E()'), 'le 10')
597 self.assertEqual(eval('Decimal(10) == E()'), 'eq 10')
598 self.assertEqual(eval('Decimal(10) != E()'), 'ne 10')
599
600 # insert operator methods and then exercise them
Georg Brandl96c3f7f2006-03-28 08:06:35 +0000601 oplist = [
602 ('+', '__add__', '__radd__'),
603 ('-', '__sub__', '__rsub__'),
604 ('*', '__mul__', '__rmul__'),
605 ('%', '__mod__', '__rmod__'),
606 ('//', '__floordiv__', '__rfloordiv__'),
607 ('**', '__pow__', '__rpow__')
608 ]
609 if 1/2 == 0:
610 # testing with classic division, so add __div__
611 oplist.append(('/', '__div__', '__rdiv__'))
612 else:
613 # testing with -Qnew, so add __truediv__
614 oplist.append(('/', '__truediv__', '__rtruediv__'))
Anthony Baxter4ef3a232006-03-30 12:59:11 +0000615
Georg Brandl96c3f7f2006-03-28 08:06:35 +0000616 for sym, lop, rop in oplist:
Raymond Hettinger267b8682005-03-27 10:47:39 +0000617 setattr(E, lop, lambda self, other: 'str' + lop + str(other))
618 setattr(E, rop, lambda self, other: str(other) + rop + 'str')
619 self.assertEqual(eval('E()' + sym + 'Decimal(10)'),
620 'str' + lop + '10')
621 self.assertEqual(eval('Decimal(10)' + sym + 'E()'),
622 '10' + rop + 'str')
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000623
Mark Dickinson277859d2009-03-17 23:03:46 +0000624
Mark Dickinson1ddf1d82008-02-29 02:16:37 +0000625class DecimalFormatTest(unittest.TestCase):
626 '''Unit tests for the format function.'''
627 def test_formatting(self):
628 # triples giving a format, a Decimal, and the expected result
629 test_values = [
630 ('e', '0E-15', '0e-15'),
631 ('e', '2.3E-15', '2.3e-15'),
632 ('e', '2.30E+2', '2.30e+2'), # preserve significant zeros
633 ('e', '2.30000E-15', '2.30000e-15'),
634 ('e', '1.23456789123456789e40', '1.23456789123456789e+40'),
635 ('e', '1.5', '1.5e+0'),
636 ('e', '0.15', '1.5e-1'),
637 ('e', '0.015', '1.5e-2'),
638 ('e', '0.0000000000015', '1.5e-12'),
639 ('e', '15.0', '1.50e+1'),
640 ('e', '-15', '-1.5e+1'),
641 ('e', '0', '0e+0'),
642 ('e', '0E1', '0e+1'),
643 ('e', '0.0', '0e-1'),
644 ('e', '0.00', '0e-2'),
645 ('.6e', '0E-15', '0.000000e-9'),
646 ('.6e', '0', '0.000000e+6'),
647 ('.6e', '9.999999', '9.999999e+0'),
648 ('.6e', '9.9999999', '1.000000e+1'),
649 ('.6e', '-1.23e5', '-1.230000e+5'),
650 ('.6e', '1.23456789e-3', '1.234568e-3'),
651 ('f', '0', '0'),
652 ('f', '0.0', '0.0'),
653 ('f', '0E-2', '0.00'),
654 ('f', '0.00E-8', '0.0000000000'),
655 ('f', '0E1', '0'), # loses exponent information
656 ('f', '3.2E1', '32'),
657 ('f', '3.2E2', '320'),
658 ('f', '3.20E2', '320'),
659 ('f', '3.200E2', '320.0'),
660 ('f', '3.2E-6', '0.0000032'),
661 ('.6f', '0E-15', '0.000000'), # all zeros treated equally
662 ('.6f', '0E1', '0.000000'),
663 ('.6f', '0', '0.000000'),
664 ('.0f', '0', '0'), # no decimal point
665 ('.0f', '0e-2', '0'),
666 ('.0f', '3.14159265', '3'),
667 ('.1f', '3.14159265', '3.1'),
668 ('.4f', '3.14159265', '3.1416'),
669 ('.6f', '3.14159265', '3.141593'),
670 ('.7f', '3.14159265', '3.1415926'), # round-half-even!
671 ('.8f', '3.14159265', '3.14159265'),
672 ('.9f', '3.14159265', '3.141592650'),
673
674 ('g', '0', '0'),
675 ('g', '0.0', '0.0'),
676 ('g', '0E1', '0e+1'),
677 ('G', '0E1', '0E+1'),
678 ('g', '0E-5', '0.00000'),
679 ('g', '0E-6', '0.000000'),
680 ('g', '0E-7', '0e-7'),
681 ('g', '-0E2', '-0e+2'),
682 ('.0g', '3.14159265', '3'), # 0 sig fig -> 1 sig fig
683 ('.1g', '3.14159265', '3'),
684 ('.2g', '3.14159265', '3.1'),
685 ('.5g', '3.14159265', '3.1416'),
686 ('.7g', '3.14159265', '3.141593'),
687 ('.8g', '3.14159265', '3.1415926'), # round-half-even!
688 ('.9g', '3.14159265', '3.14159265'),
689 ('.10g', '3.14159265', '3.14159265'), # don't pad
690
691 ('%', '0E1', '0%'),
692 ('%', '0E0', '0%'),
693 ('%', '0E-1', '0%'),
694 ('%', '0E-2', '0%'),
695 ('%', '0E-3', '0.0%'),
696 ('%', '0E-4', '0.00%'),
697
698 ('.3%', '0', '0.000%'), # all zeros treated equally
699 ('.3%', '0E10', '0.000%'),
700 ('.3%', '0E-10', '0.000%'),
701 ('.3%', '2.34', '234.000%'),
702 ('.3%', '1.234567', '123.457%'),
703 ('.0%', '1.23', '123%'),
704
705 ('e', 'NaN', 'NaN'),
706 ('f', '-NaN123', '-NaN123'),
707 ('+g', 'NaN456', '+NaN456'),
708 ('.3e', 'Inf', 'Infinity'),
709 ('.16f', '-Inf', '-Infinity'),
710 ('.0g', '-sNaN', '-sNaN'),
711
712 ('', '1.00', '1.00'),
Mark Dickinsonb065e522009-03-17 18:01:03 +0000713
Mark Dickinson277859d2009-03-17 23:03:46 +0000714 # test alignment and padding
Mark Dickinson5cfa8042009-09-08 20:20:19 +0000715 ('6', '123', ' 123'),
Mark Dickinsonb065e522009-03-17 18:01:03 +0000716 ('<6', '123', '123 '),
717 ('>6', '123', ' 123'),
718 ('^6', '123', ' 123 '),
719 ('=+6', '123', '+ 123'),
Mark Dickinson277859d2009-03-17 23:03:46 +0000720 ('#<10', 'NaN', 'NaN#######'),
721 ('#<10', '-4.3', '-4.3######'),
722 ('#<+10', '0.0130', '+0.0130###'),
723 ('#< 10', '0.0130', ' 0.0130###'),
724 ('@>10', '-Inf', '@-Infinity'),
725 ('#>5', '-Inf', '-Infinity'),
726 ('?^5', '123', '?123?'),
727 ('%^6', '123', '%123%%'),
728 (' ^6', '-45.6', '-45.6 '),
729 ('/=10', '-45.6', '-/////45.6'),
730 ('/=+10', '45.6', '+/////45.6'),
731 ('/= 10', '45.6', ' /////45.6'),
732
733 # thousands separator
734 (',', '1234567', '1,234,567'),
735 (',', '123456', '123,456'),
736 (',', '12345', '12,345'),
737 (',', '1234', '1,234'),
738 (',', '123', '123'),
739 (',', '12', '12'),
740 (',', '1', '1'),
741 (',', '0', '0'),
742 (',', '-1234567', '-1,234,567'),
743 (',', '-123456', '-123,456'),
744 ('7,', '123456', '123,456'),
Mark Dickinson5cfa8042009-09-08 20:20:19 +0000745 ('8,', '123456', ' 123,456'),
Mark Dickinson277859d2009-03-17 23:03:46 +0000746 ('08,', '123456', '0,123,456'), # special case: extra 0 needed
747 ('+08,', '123456', '+123,456'), # but not if there's a sign
748 (' 08,', '123456', ' 123,456'),
749 ('08,', '-123456', '-123,456'),
750 ('+09,', '123456', '+0,123,456'),
751 # ... with fractional part...
752 ('07,', '1234.56', '1,234.56'),
753 ('08,', '1234.56', '1,234.56'),
754 ('09,', '1234.56', '01,234.56'),
755 ('010,', '1234.56', '001,234.56'),
756 ('011,', '1234.56', '0,001,234.56'),
757 ('012,', '1234.56', '0,001,234.56'),
758 ('08,.1f', '1234.5', '01,234.5'),
759 # no thousands separators in fraction part
760 (',', '1.23456789', '1.23456789'),
761 (',%', '123.456789', '12,345.6789%'),
762 (',e', '123456', '1.23456e+5'),
763 (',E', '123456', '1.23456E+5'),
Mark Dickinson491ea552009-09-07 16:17:41 +0000764
765 # issue 6850
766 ('a=-7.0', '0.12345', 'aaaa0.1'),
Mark Dickinson1ddf1d82008-02-29 02:16:37 +0000767 ]
768 for fmt, d, result in test_values:
769 self.assertEqual(format(Decimal(d), fmt), result)
770
Mark Dickinson277859d2009-03-17 23:03:46 +0000771 def test_n_format(self):
772 try:
773 from locale import CHAR_MAX
774 except ImportError:
775 return
776
777 # Set up some localeconv-like dictionaries
778 en_US = {
779 'decimal_point' : '.',
780 'grouping' : [3, 3, 0],
781 'thousands_sep': ','
782 }
783
784 fr_FR = {
785 'decimal_point' : ',',
786 'grouping' : [CHAR_MAX],
787 'thousands_sep' : ''
788 }
789
790 ru_RU = {
791 'decimal_point' : ',',
792 'grouping' : [3, 3, 0],
793 'thousands_sep' : ' '
794 }
795
796 crazy = {
797 'decimal_point' : '&',
798 'grouping' : [1, 4, 2, CHAR_MAX],
799 'thousands_sep' : '-'
800 }
801
802
803 def get_fmt(x, locale, fmt='n'):
804 return Decimal.__format__(Decimal(x), fmt, _localeconv=locale)
805
806 self.assertEqual(get_fmt(Decimal('12.7'), en_US), '12.7')
807 self.assertEqual(get_fmt(Decimal('12.7'), fr_FR), '12,7')
808 self.assertEqual(get_fmt(Decimal('12.7'), ru_RU), '12,7')
809 self.assertEqual(get_fmt(Decimal('12.7'), crazy), '1-2&7')
810
811 self.assertEqual(get_fmt(123456789, en_US), '123,456,789')
812 self.assertEqual(get_fmt(123456789, fr_FR), '123456789')
813 self.assertEqual(get_fmt(123456789, ru_RU), '123 456 789')
814 self.assertEqual(get_fmt(1234567890123, crazy), '123456-78-9012-3')
815
816 self.assertEqual(get_fmt(123456789, en_US, '.6n'), '1.23457e+8')
817 self.assertEqual(get_fmt(123456789, fr_FR, '.6n'), '1,23457e+8')
818 self.assertEqual(get_fmt(123456789, ru_RU, '.6n'), '1,23457e+8')
819 self.assertEqual(get_fmt(123456789, crazy, '.6n'), '1&23457e+8')
820
Mark Dickinsonb14514a2009-03-18 08:22:51 +0000821 # zero padding
822 self.assertEqual(get_fmt(1234, fr_FR, '03n'), '1234')
823 self.assertEqual(get_fmt(1234, fr_FR, '04n'), '1234')
824 self.assertEqual(get_fmt(1234, fr_FR, '05n'), '01234')
825 self.assertEqual(get_fmt(1234, fr_FR, '06n'), '001234')
826
827 self.assertEqual(get_fmt(12345, en_US, '05n'), '12,345')
828 self.assertEqual(get_fmt(12345, en_US, '06n'), '12,345')
829 self.assertEqual(get_fmt(12345, en_US, '07n'), '012,345')
830 self.assertEqual(get_fmt(12345, en_US, '08n'), '0,012,345')
831 self.assertEqual(get_fmt(12345, en_US, '09n'), '0,012,345')
832 self.assertEqual(get_fmt(12345, en_US, '010n'), '00,012,345')
833
834 self.assertEqual(get_fmt(123456, crazy, '06n'), '1-2345-6')
835 self.assertEqual(get_fmt(123456, crazy, '07n'), '1-2345-6')
836 self.assertEqual(get_fmt(123456, crazy, '08n'), '1-2345-6')
837 self.assertEqual(get_fmt(123456, crazy, '09n'), '01-2345-6')
838 self.assertEqual(get_fmt(123456, crazy, '010n'), '0-01-2345-6')
839 self.assertEqual(get_fmt(123456, crazy, '011n'), '0-01-2345-6')
840 self.assertEqual(get_fmt(123456, crazy, '012n'), '00-01-2345-6')
841 self.assertEqual(get_fmt(123456, crazy, '013n'), '000-01-2345-6')
842
Mark Dickinson277859d2009-03-17 23:03:46 +0000843
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000844class DecimalArithmeticOperatorsTest(unittest.TestCase):
845 '''Unit tests for all arithmetic operators, binary and unary.'''
846
847 def test_addition(self):
848
849 d1 = Decimal('-11.1')
850 d2 = Decimal('22.2')
851
852 #two Decimals
853 self.assertEqual(d1+d2, Decimal('11.1'))
854 self.assertEqual(d2+d1, Decimal('11.1'))
855
856 #with other type, left
857 c = d1 + 5
858 self.assertEqual(c, Decimal('-6.1'))
859 self.assertEqual(type(c), type(d1))
860
861 #with other type, right
862 c = 5 + d1
863 self.assertEqual(c, Decimal('-6.1'))
864 self.assertEqual(type(c), type(d1))
865
866 #inline with decimal
867 d1 += d2
868 self.assertEqual(d1, Decimal('11.1'))
869
870 #inline with other type
871 d1 += 5
872 self.assertEqual(d1, Decimal('16.1'))
873
874 def test_subtraction(self):
875
876 d1 = Decimal('-11.1')
877 d2 = Decimal('22.2')
878
879 #two Decimals
880 self.assertEqual(d1-d2, Decimal('-33.3'))
881 self.assertEqual(d2-d1, Decimal('33.3'))
882
883 #with other type, left
884 c = d1 - 5
885 self.assertEqual(c, Decimal('-16.1'))
886 self.assertEqual(type(c), type(d1))
887
888 #with other type, right
889 c = 5 - d1
890 self.assertEqual(c, Decimal('16.1'))
891 self.assertEqual(type(c), type(d1))
892
893 #inline with decimal
894 d1 -= d2
895 self.assertEqual(d1, Decimal('-33.3'))
896
897 #inline with other type
898 d1 -= 5
899 self.assertEqual(d1, Decimal('-38.3'))
900
901 def test_multiplication(self):
902
903 d1 = Decimal('-5')
904 d2 = Decimal('3')
905
906 #two Decimals
907 self.assertEqual(d1*d2, Decimal('-15'))
908 self.assertEqual(d2*d1, Decimal('-15'))
909
910 #with other type, left
911 c = d1 * 5
912 self.assertEqual(c, Decimal('-25'))
913 self.assertEqual(type(c), type(d1))
914
915 #with other type, right
916 c = 5 * d1
917 self.assertEqual(c, Decimal('-25'))
918 self.assertEqual(type(c), type(d1))
919
920 #inline with decimal
921 d1 *= d2
922 self.assertEqual(d1, Decimal('-15'))
923
924 #inline with other type
925 d1 *= 5
926 self.assertEqual(d1, Decimal('-75'))
927
928 def test_division(self):
929
930 d1 = Decimal('-5')
931 d2 = Decimal('2')
932
933 #two Decimals
934 self.assertEqual(d1/d2, Decimal('-2.5'))
935 self.assertEqual(d2/d1, Decimal('-0.4'))
936
937 #with other type, left
938 c = d1 / 4
939 self.assertEqual(c, Decimal('-1.25'))
940 self.assertEqual(type(c), type(d1))
941
942 #with other type, right
943 c = 4 / d1
944 self.assertEqual(c, Decimal('-0.8'))
945 self.assertEqual(type(c), type(d1))
946
947 #inline with decimal
948 d1 /= d2
949 self.assertEqual(d1, Decimal('-2.5'))
950
951 #inline with other type
952 d1 /= 4
953 self.assertEqual(d1, Decimal('-0.625'))
954
955 def test_floor_division(self):
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000956
957 d1 = Decimal('5')
958 d2 = Decimal('2')
959
960 #two Decimals
961 self.assertEqual(d1//d2, Decimal('2'))
962 self.assertEqual(d2//d1, Decimal('0'))
963
964 #with other type, left
965 c = d1 // 4
966 self.assertEqual(c, Decimal('1'))
967 self.assertEqual(type(c), type(d1))
968
969 #with other type, right
970 c = 7 // d1
971 self.assertEqual(c, Decimal('1'))
972 self.assertEqual(type(c), type(d1))
973
974 #inline with decimal
975 d1 //= d2
976 self.assertEqual(d1, Decimal('2'))
977
978 #inline with other type
979 d1 //= 2
980 self.assertEqual(d1, Decimal('1'))
981
982 def test_powering(self):
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000983
984 d1 = Decimal('5')
985 d2 = Decimal('2')
986
987 #two Decimals
988 self.assertEqual(d1**d2, Decimal('25'))
989 self.assertEqual(d2**d1, Decimal('32'))
990
991 #with other type, left
992 c = d1 ** 4
993 self.assertEqual(c, Decimal('625'))
994 self.assertEqual(type(c), type(d1))
995
996 #with other type, right
997 c = 7 ** d1
998 self.assertEqual(c, Decimal('16807'))
999 self.assertEqual(type(c), type(d1))
1000
1001 #inline with decimal
1002 d1 **= d2
1003 self.assertEqual(d1, Decimal('25'))
1004
1005 #inline with other type
1006 d1 **= 4
1007 self.assertEqual(d1, Decimal('390625'))
1008
1009 def test_module(self):
1010
1011 d1 = Decimal('5')
1012 d2 = Decimal('2')
1013
1014 #two Decimals
1015 self.assertEqual(d1%d2, Decimal('1'))
1016 self.assertEqual(d2%d1, Decimal('2'))
1017
1018 #with other type, left
1019 c = d1 % 4
1020 self.assertEqual(c, Decimal('1'))
1021 self.assertEqual(type(c), type(d1))
1022
1023 #with other type, right
1024 c = 7 % d1
1025 self.assertEqual(c, Decimal('2'))
1026 self.assertEqual(type(c), type(d1))
1027
1028 #inline with decimal
1029 d1 %= d2
1030 self.assertEqual(d1, Decimal('1'))
1031
1032 #inline with other type
1033 d1 %= 4
1034 self.assertEqual(d1, Decimal('1'))
1035
1036 def test_floor_div_module(self):
1037
1038 d1 = Decimal('5')
1039 d2 = Decimal('2')
1040
1041 #two Decimals
1042 (p, q) = divmod(d1, d2)
1043 self.assertEqual(p, Decimal('2'))
1044 self.assertEqual(q, Decimal('1'))
1045 self.assertEqual(type(p), type(d1))
1046 self.assertEqual(type(q), type(d1))
1047
1048 #with other type, left
1049 (p, q) = divmod(d1, 4)
1050 self.assertEqual(p, Decimal('1'))
1051 self.assertEqual(q, Decimal('1'))
1052 self.assertEqual(type(p), type(d1))
1053 self.assertEqual(type(q), type(d1))
1054
1055 #with other type, right
1056 (p, q) = divmod(7, d1)
1057 self.assertEqual(p, Decimal('1'))
1058 self.assertEqual(q, Decimal('2'))
1059 self.assertEqual(type(p), type(d1))
1060 self.assertEqual(type(q), type(d1))
1061
1062 def test_unary_operators(self):
1063 self.assertEqual(+Decimal(45), Decimal(+45)) # +
1064 self.assertEqual(-Decimal(45), Decimal(-45)) # -
1065 self.assertEqual(abs(Decimal(45)), abs(Decimal(-45))) # abs
1066
Mark Dickinson2fc92632008-02-06 22:10:50 +00001067 def test_nan_comparisons(self):
1068 n = Decimal('NaN')
1069 s = Decimal('sNaN')
1070 i = Decimal('Inf')
1071 f = Decimal('2')
1072 for x, y in [(n, n), (n, i), (i, n), (n, f), (f, n),
1073 (s, n), (n, s), (s, i), (i, s), (s, f), (f, s), (s, s)]:
Benjamin Peterson5c8da862009-06-30 22:57:08 +00001074 self.assertTrue(x != y)
1075 self.assertTrue(not (x == y))
1076 self.assertTrue(not (x < y))
1077 self.assertTrue(not (x <= y))
1078 self.assertTrue(not (x > y))
1079 self.assertTrue(not (x >= y))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001080
1081# The following are two functions used to test threading in the next class
1082
1083def thfunc1(cls):
1084 d1 = Decimal(1)
1085 d3 = Decimal(3)
Facundo Batista64156672008-03-22 02:45:37 +00001086 test1 = d1/d3
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001087 cls.synchro.wait()
Facundo Batista64156672008-03-22 02:45:37 +00001088 test2 = d1/d3
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001089 cls.finish1.set()
Facundo Batista64156672008-03-22 02:45:37 +00001090
Facundo Batistaee340e52008-05-02 17:39:00 +00001091 cls.assertEqual(test1, Decimal('0.3333333333333333333333333333'))
1092 cls.assertEqual(test2, Decimal('0.3333333333333333333333333333'))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001093 return
1094
1095def thfunc2(cls):
1096 d1 = Decimal(1)
1097 d3 = Decimal(3)
Facundo Batista64156672008-03-22 02:45:37 +00001098 test1 = d1/d3
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001099 thiscontext = getcontext()
1100 thiscontext.prec = 18
Facundo Batista64156672008-03-22 02:45:37 +00001101 test2 = d1/d3
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001102 cls.synchro.set()
1103 cls.finish2.set()
Facundo Batista64156672008-03-22 02:45:37 +00001104
Facundo Batistaee340e52008-05-02 17:39:00 +00001105 cls.assertEqual(test1, Decimal('0.3333333333333333333333333333'))
Facundo Batista64156672008-03-22 02:45:37 +00001106 cls.assertEqual(test2, Decimal('0.333333333333333333'))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001107 return
1108
1109
1110class DecimalUseOfContextTest(unittest.TestCase):
1111 '''Unit tests for Use of Context cases in Decimal.'''
1112
Raymond Hettinger7e71fa52004-12-18 19:07:19 +00001113 try:
1114 import threading
1115 except ImportError:
1116 threading = None
1117
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001118 # Take care executing this test from IDLE, there's an issue in threading
1119 # that hangs IDLE and I couldn't find it
1120
1121 def test_threading(self):
1122 #Test the "threading isolation" of a Context.
1123
1124 self.synchro = threading.Event()
1125 self.finish1 = threading.Event()
1126 self.finish2 = threading.Event()
1127
1128 th1 = threading.Thread(target=thfunc1, args=(self,))
1129 th2 = threading.Thread(target=thfunc2, args=(self,))
1130
1131 th1.start()
1132 th2.start()
1133
1134 self.finish1.wait()
Thomas Woutersb3e6e8c2007-09-19 17:27:29 +00001135 self.finish2.wait()
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001136 return
1137
Raymond Hettinger7e71fa52004-12-18 19:07:19 +00001138 if threading is None:
1139 del test_threading
1140
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001141
1142class DecimalUsabilityTest(unittest.TestCase):
1143 '''Unit tests for Usability cases of Decimal.'''
1144
1145 def test_comparison_operators(self):
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001146
1147 da = Decimal('23.42')
1148 db = Decimal('23.42')
1149 dc = Decimal('45')
1150
1151 #two Decimals
Benjamin Peterson5c8da862009-06-30 22:57:08 +00001152 self.assertTrue(dc > da)
1153 self.assertTrue(dc >= da)
1154 self.assertTrue(da < dc)
1155 self.assertTrue(da <= dc)
1156 self.assertTrue(da == db)
1157 self.assertTrue(da != dc)
1158 self.assertTrue(da <= db)
1159 self.assertTrue(da >= db)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001160 self.assertEqual(cmp(dc,da), 1)
1161 self.assertEqual(cmp(da,dc), -1)
1162 self.assertEqual(cmp(da,db), 0)
1163
1164 #a Decimal and an int
Benjamin Peterson5c8da862009-06-30 22:57:08 +00001165 self.assertTrue(dc > 23)
1166 self.assertTrue(23 < dc)
1167 self.assertTrue(dc == 45)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001168 self.assertEqual(cmp(dc,23), 1)
1169 self.assertEqual(cmp(23,dc), -1)
1170 self.assertEqual(cmp(dc,45), 0)
1171
1172 #a Decimal and uncomparable
Raymond Hettinger0aeac102004-07-05 22:53:03 +00001173 self.assertNotEqual(da, 'ugly')
1174 self.assertNotEqual(da, 32.7)
1175 self.assertNotEqual(da, object())
1176 self.assertNotEqual(da, object)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001177
Raymond Hettinger0aeac102004-07-05 22:53:03 +00001178 # sortable
1179 a = map(Decimal, xrange(100))
1180 b = a[:]
1181 random.shuffle(a)
1182 a.sort()
1183 self.assertEqual(a, b)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001184
Facundo Batista353750c2007-09-13 18:13:15 +00001185 # with None
1186 self.assertFalse(Decimal(1) < None)
1187 self.assertTrue(Decimal(1) > None)
1188
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001189 def test_copy_and_deepcopy_methods(self):
1190 d = Decimal('43.24')
1191 c = copy.copy(d)
1192 self.assertEqual(id(c), id(d))
1193 dc = copy.deepcopy(d)
1194 self.assertEqual(id(dc), id(d))
1195
1196 def test_hash_method(self):
1197 #just that it's hashable
1198 hash(Decimal(23))
Facundo Batista8c202442007-09-19 17:53:25 +00001199
1200 test_values = [Decimal(sign*(2**m + n))
1201 for m in [0, 14, 15, 16, 17, 30, 31,
1202 32, 33, 62, 63, 64, 65, 66]
1203 for n in range(-10, 10)
1204 for sign in [-1, 1]]
1205 test_values.extend([
1206 Decimal("-0"), # zeros
1207 Decimal("0.00"),
1208 Decimal("-0.000"),
1209 Decimal("0E10"),
1210 Decimal("-0E12"),
1211 Decimal("10.0"), # negative exponent
1212 Decimal("-23.00000"),
1213 Decimal("1230E100"), # positive exponent
1214 Decimal("-4.5678E50"),
1215 # a value for which hash(n) != hash(n % (2**64-1))
1216 # in Python pre-2.6
1217 Decimal(2**64 + 2**32 - 1),
1218 # selection of values which fail with the old (before
1219 # version 2.6) long.__hash__
1220 Decimal("1.634E100"),
1221 Decimal("90.697E100"),
1222 Decimal("188.83E100"),
1223 Decimal("1652.9E100"),
1224 Decimal("56531E100"),
1225 ])
1226
1227 # check that hash(d) == hash(int(d)) for integral values
1228 for value in test_values:
1229 self.assertEqual(hash(value), hash(int(value)))
1230
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001231 #the same hash that to an int
1232 self.assertEqual(hash(Decimal(23)), hash(23))
Raymond Hettingerbea3f6f2005-03-15 04:59:17 +00001233 self.assertRaises(TypeError, hash, Decimal('NaN'))
Benjamin Peterson5c8da862009-06-30 22:57:08 +00001234 self.assertTrue(hash(Decimal('Inf')))
1235 self.assertTrue(hash(Decimal('-Inf')))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001236
Facundo Batista52b25792008-01-08 12:25:20 +00001237 # check that the value of the hash doesn't depend on the
1238 # current context (issue #1757)
1239 c = getcontext()
1240 old_precision = c.prec
1241 x = Decimal("123456789.1")
1242
1243 c.prec = 6
1244 h1 = hash(x)
1245 c.prec = 10
1246 h2 = hash(x)
1247 c.prec = 16
1248 h3 = hash(x)
1249
1250 self.assertEqual(h1, h2)
1251 self.assertEqual(h1, h3)
1252 c.prec = old_precision
1253
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001254 def test_min_and_max_methods(self):
1255
1256 d1 = Decimal('15.32')
1257 d2 = Decimal('28.5')
1258 l1 = 15
1259 l2 = 28
1260
1261 #between Decimals
Benjamin Peterson5c8da862009-06-30 22:57:08 +00001262 self.assertTrue(min(d1,d2) is d1)
1263 self.assertTrue(min(d2,d1) is d1)
1264 self.assertTrue(max(d1,d2) is d2)
1265 self.assertTrue(max(d2,d1) is d2)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001266
1267 #between Decimal and long
Benjamin Peterson5c8da862009-06-30 22:57:08 +00001268 self.assertTrue(min(d1,l2) is d1)
1269 self.assertTrue(min(l2,d1) is d1)
1270 self.assertTrue(max(l1,d2) is d2)
1271 self.assertTrue(max(d2,l1) is d2)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001272
1273 def test_as_nonzero(self):
1274 #as false
Benjamin Peterson5c8da862009-06-30 22:57:08 +00001275 self.assertFalse(Decimal(0))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001276 #as true
Benjamin Peterson5c8da862009-06-30 22:57:08 +00001277 self.assertTrue(Decimal('0.372'))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001278
1279 def test_tostring_methods(self):
1280 #Test str and repr methods.
1281
1282 d = Decimal('15.32')
1283 self.assertEqual(str(d), '15.32') # str
Raymond Hettingerabe32372008-02-14 02:41:22 +00001284 self.assertEqual(repr(d), "Decimal('15.32')") # repr
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001285
Mark Dickinson8e85ffa2008-03-25 18:47:59 +00001286 # result type of string methods should be str, not unicode
1287 unicode_inputs = [u'123.4', u'0.5E2', u'Infinity', u'sNaN',
1288 u'-0.0E100', u'-NaN001', u'-Inf']
1289
1290 for u in unicode_inputs:
1291 d = Decimal(u)
1292 self.assertEqual(type(str(d)), str)
1293 self.assertEqual(type(repr(d)), str)
1294 self.assertEqual(type(d.to_eng_string()), str)
1295
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001296 def test_tonum_methods(self):
1297 #Test float, int and long methods.
1298
1299 d1 = Decimal('66')
1300 d2 = Decimal('15.32')
1301
1302 #int
1303 self.assertEqual(int(d1), 66)
1304 self.assertEqual(int(d2), 15)
1305
1306 #long
1307 self.assertEqual(long(d1), 66)
1308 self.assertEqual(long(d2), 15)
1309
1310 #float
1311 self.assertEqual(float(d1), 66)
1312 self.assertEqual(float(d2), 15.32)
1313
1314 def test_eval_round_trip(self):
1315
1316 #with zero
1317 d = Decimal( (0, (0,), 0) )
1318 self.assertEqual(d, eval(repr(d)))
1319
1320 #int
1321 d = Decimal( (1, (4, 5), 0) )
1322 self.assertEqual(d, eval(repr(d)))
1323
1324 #float
1325 d = Decimal( (0, (4, 5, 3, 4), -2) )
1326 self.assertEqual(d, eval(repr(d)))
1327
1328 #weird
1329 d = Decimal( (1, (4, 3, 4, 9, 1, 3, 5, 3, 4), -25) )
1330 self.assertEqual(d, eval(repr(d)))
1331
1332 def test_as_tuple(self):
1333
1334 #with zero
1335 d = Decimal(0)
1336 self.assertEqual(d.as_tuple(), (0, (0,), 0) )
1337
1338 #int
1339 d = Decimal(-45)
1340 self.assertEqual(d.as_tuple(), (1, (4, 5), 0) )
1341
1342 #complicated string
1343 d = Decimal("-4.34913534E-17")
1344 self.assertEqual(d.as_tuple(), (1, (4, 3, 4, 9, 1, 3, 5, 3, 4), -25) )
1345
1346 #inf
1347 d = Decimal("Infinity")
1348 self.assertEqual(d.as_tuple(), (0, (0,), 'F') )
1349
Facundo Batista9b5e2312007-10-19 19:25:57 +00001350 #leading zeros in coefficient should be stripped
1351 d = Decimal( (0, (0, 0, 4, 0, 5, 3, 4), -2) )
1352 self.assertEqual(d.as_tuple(), (0, (4, 0, 5, 3, 4), -2) )
1353 d = Decimal( (1, (0, 0, 0), 37) )
1354 self.assertEqual(d.as_tuple(), (1, (0,), 37))
1355 d = Decimal( (1, (), 37) )
1356 self.assertEqual(d.as_tuple(), (1, (0,), 37))
1357
1358 #leading zeros in NaN diagnostic info should be stripped
1359 d = Decimal( (0, (0, 0, 4, 0, 5, 3, 4), 'n') )
1360 self.assertEqual(d.as_tuple(), (0, (4, 0, 5, 3, 4), 'n') )
1361 d = Decimal( (1, (0, 0, 0), 'N') )
1362 self.assertEqual(d.as_tuple(), (1, (), 'N') )
1363 d = Decimal( (1, (), 'n') )
1364 self.assertEqual(d.as_tuple(), (1, (), 'n') )
1365
1366 #coefficient in infinity should be ignored
1367 d = Decimal( (0, (4, 5, 3, 4), 'F') )
1368 self.assertEqual(d.as_tuple(), (0, (0,), 'F'))
1369 d = Decimal( (1, (0, 2, 7, 1), 'F') )
1370 self.assertEqual(d.as_tuple(), (1, (0,), 'F'))
1371
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001372 def test_immutability_operations(self):
1373 # Do operations and check that it didn't change change internal objects.
1374
1375 d1 = Decimal('-25e55')
1376 b1 = Decimal('-25e55')
Facundo Batista353750c2007-09-13 18:13:15 +00001377 d2 = Decimal('33e+33')
1378 b2 = Decimal('33e+33')
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001379
1380 def checkSameDec(operation, useOther=False):
1381 if useOther:
1382 eval("d1." + operation + "(d2)")
1383 self.assertEqual(d1._sign, b1._sign)
1384 self.assertEqual(d1._int, b1._int)
1385 self.assertEqual(d1._exp, b1._exp)
1386 self.assertEqual(d2._sign, b2._sign)
1387 self.assertEqual(d2._int, b2._int)
1388 self.assertEqual(d2._exp, b2._exp)
1389 else:
1390 eval("d1." + operation + "()")
1391 self.assertEqual(d1._sign, b1._sign)
1392 self.assertEqual(d1._int, b1._int)
1393 self.assertEqual(d1._exp, b1._exp)
1394 return
1395
1396 Decimal(d1)
1397 self.assertEqual(d1._sign, b1._sign)
1398 self.assertEqual(d1._int, b1._int)
1399 self.assertEqual(d1._exp, b1._exp)
1400
1401 checkSameDec("__abs__")
1402 checkSameDec("__add__", True)
1403 checkSameDec("__div__", True)
1404 checkSameDec("__divmod__", True)
Mark Dickinson2fc92632008-02-06 22:10:50 +00001405 checkSameDec("__eq__", True)
1406 checkSameDec("__ne__", True)
1407 checkSameDec("__le__", True)
1408 checkSameDec("__lt__", True)
1409 checkSameDec("__ge__", True)
1410 checkSameDec("__gt__", True)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001411 checkSameDec("__float__")
1412 checkSameDec("__floordiv__", True)
1413 checkSameDec("__hash__")
1414 checkSameDec("__int__")
Raymond Hettinger5a053642008-01-24 19:05:29 +00001415 checkSameDec("__trunc__")
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001416 checkSameDec("__long__")
1417 checkSameDec("__mod__", True)
1418 checkSameDec("__mul__", True)
1419 checkSameDec("__neg__")
1420 checkSameDec("__nonzero__")
1421 checkSameDec("__pos__")
1422 checkSameDec("__pow__", True)
1423 checkSameDec("__radd__", True)
1424 checkSameDec("__rdiv__", True)
1425 checkSameDec("__rdivmod__", True)
1426 checkSameDec("__repr__")
1427 checkSameDec("__rfloordiv__", True)
1428 checkSameDec("__rmod__", True)
1429 checkSameDec("__rmul__", True)
1430 checkSameDec("__rpow__", True)
1431 checkSameDec("__rsub__", True)
1432 checkSameDec("__str__")
1433 checkSameDec("__sub__", True)
1434 checkSameDec("__truediv__", True)
1435 checkSameDec("adjusted")
1436 checkSameDec("as_tuple")
1437 checkSameDec("compare", True)
1438 checkSameDec("max", True)
1439 checkSameDec("min", True)
1440 checkSameDec("normalize")
1441 checkSameDec("quantize", True)
1442 checkSameDec("remainder_near", True)
1443 checkSameDec("same_quantum", True)
1444 checkSameDec("sqrt")
1445 checkSameDec("to_eng_string")
1446 checkSameDec("to_integral")
1447
Facundo Batista6c398da2007-09-17 17:30:13 +00001448 def test_subclassing(self):
1449 # Different behaviours when subclassing Decimal
1450
1451 class MyDecimal(Decimal):
1452 pass
1453
1454 d1 = MyDecimal(1)
1455 d2 = MyDecimal(2)
1456 d = d1 + d2
1457 self.assertTrue(type(d) is Decimal)
1458
1459 d = d1.max(d2)
1460 self.assertTrue(type(d) is Decimal)
1461
Mark Dickinson3b24ccb2008-03-25 14:33:23 +00001462 def test_implicit_context(self):
1463 # Check results when context given implicitly. (Issue 2478)
1464 c = getcontext()
1465 self.assertEqual(str(Decimal(0).sqrt()),
1466 str(c.sqrt(Decimal(0))))
1467
Facundo Batista6c398da2007-09-17 17:30:13 +00001468
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001469class DecimalPythonAPItests(unittest.TestCase):
1470
Raymond Hettinger2c8585b2009-02-03 03:37:03 +00001471 def test_abc(self):
Benjamin Peterson5c8da862009-06-30 22:57:08 +00001472 self.assertTrue(issubclass(Decimal, numbers.Number))
1473 self.assertTrue(not issubclass(Decimal, numbers.Real))
1474 self.assertTrue(isinstance(Decimal(0), numbers.Number))
1475 self.assertTrue(not isinstance(Decimal(0), numbers.Real))
Raymond Hettinger2c8585b2009-02-03 03:37:03 +00001476
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001477 def test_pickle(self):
1478 d = Decimal('-3.141590000')
1479 p = pickle.dumps(d)
1480 e = pickle.loads(p)
1481 self.assertEqual(d, e)
1482
Raymond Hettinger5548be22004-07-05 18:49:38 +00001483 def test_int(self):
Raymond Hettinger605ed022004-11-24 07:28:48 +00001484 for x in range(-250, 250):
1485 s = '%0.2f' % (x / 100.0)
Raymond Hettinger5548be22004-07-05 18:49:38 +00001486 # should work the same as for floats
1487 self.assertEqual(int(Decimal(s)), int(float(s)))
Raymond Hettinger605ed022004-11-24 07:28:48 +00001488 # should work the same as to_integral in the ROUND_DOWN mode
Raymond Hettinger5548be22004-07-05 18:49:38 +00001489 d = Decimal(s)
Raymond Hettinger605ed022004-11-24 07:28:48 +00001490 r = d.to_integral(ROUND_DOWN)
Raymond Hettinger5548be22004-07-05 18:49:38 +00001491 self.assertEqual(Decimal(int(d)), r)
1492
Mark Dickinson968f1692009-09-07 18:04:58 +00001493 self.assertRaises(ValueError, int, Decimal('-nan'))
1494 self.assertRaises(ValueError, int, Decimal('snan'))
1495 self.assertRaises(OverflowError, int, Decimal('inf'))
1496 self.assertRaises(OverflowError, int, Decimal('-inf'))
1497
1498 self.assertRaises(ValueError, long, Decimal('-nan'))
1499 self.assertRaises(ValueError, long, Decimal('snan'))
1500 self.assertRaises(OverflowError, long, Decimal('inf'))
1501 self.assertRaises(OverflowError, long, Decimal('-inf'))
1502
Raymond Hettinger5a053642008-01-24 19:05:29 +00001503 def test_trunc(self):
1504 for x in range(-250, 250):
1505 s = '%0.2f' % (x / 100.0)
1506 # should work the same as for floats
1507 self.assertEqual(int(Decimal(s)), int(float(s)))
1508 # should work the same as to_integral in the ROUND_DOWN mode
1509 d = Decimal(s)
1510 r = d.to_integral(ROUND_DOWN)
Jeffrey Yasskinca2b69f2008-02-01 06:22:46 +00001511 self.assertEqual(Decimal(math.trunc(d)), r)
Raymond Hettinger5a053642008-01-24 19:05:29 +00001512
Raymond Hettingerf4d85972009-01-03 19:02:23 +00001513 def test_from_float(self):
1514
1515 class MyDecimal(Decimal):
1516 pass
1517
1518 r = MyDecimal.from_float(0.1)
1519 self.assertEqual(type(r), MyDecimal)
1520 self.assertEqual(str(r),
1521 '0.1000000000000000055511151231257827021181583404541015625')
1522 bigint = 12345678901234567890123456789
1523 self.assertEqual(MyDecimal.from_float(bigint), MyDecimal(bigint))
Benjamin Peterson5c8da862009-06-30 22:57:08 +00001524 self.assertTrue(MyDecimal.from_float(float('nan')).is_qnan())
1525 self.assertTrue(MyDecimal.from_float(float('inf')).is_infinite())
1526 self.assertTrue(MyDecimal.from_float(float('-inf')).is_infinite())
Raymond Hettingerf4d85972009-01-03 19:02:23 +00001527 self.assertEqual(str(MyDecimal.from_float(float('nan'))),
1528 str(Decimal('NaN')))
1529 self.assertEqual(str(MyDecimal.from_float(float('inf'))),
1530 str(Decimal('Infinity')))
1531 self.assertEqual(str(MyDecimal.from_float(float('-inf'))),
1532 str(Decimal('-Infinity')))
1533 self.assertRaises(TypeError, MyDecimal.from_float, 'abc')
1534 for i in range(200):
1535 x = random.expovariate(0.01) * (random.random() * 2.0 - 1.0)
1536 self.assertEqual(x, float(MyDecimal.from_float(x))) # roundtrip
1537
1538 def test_create_decimal_from_float(self):
1539 context = Context(prec=5, rounding=ROUND_DOWN)
1540 self.assertEqual(
1541 context.create_decimal_from_float(math.pi),
1542 Decimal('3.1415')
1543 )
1544 context = Context(prec=5, rounding=ROUND_UP)
1545 self.assertEqual(
1546 context.create_decimal_from_float(math.pi),
1547 Decimal('3.1416')
1548 )
1549 context = Context(prec=5, traps=[Inexact])
1550 self.assertRaises(
1551 Inexact,
1552 context.create_decimal_from_float,
1553 math.pi
1554 )
1555 self.assertEqual(repr(context.create_decimal_from_float(-0.0)),
1556 "Decimal('-0')")
1557 self.assertEqual(repr(context.create_decimal_from_float(1.0)),
1558 "Decimal('1')")
1559 self.assertEqual(repr(context.create_decimal_from_float(10)),
1560 "Decimal('10')")
1561
Raymond Hettingerd9c0a7a2004-07-03 10:02:28 +00001562class ContextAPItests(unittest.TestCase):
1563
1564 def test_pickle(self):
1565 c = Context()
1566 e = pickle.loads(pickle.dumps(c))
1567 for k in vars(c):
1568 v1 = vars(c)[k]
1569 v2 = vars(e)[k]
1570 self.assertEqual(v1, v2)
1571
Raymond Hettinger0aeac102004-07-05 22:53:03 +00001572 def test_equality_with_other_types(self):
Benjamin Peterson5c8da862009-06-30 22:57:08 +00001573 self.assertTrue(Decimal(10) in ['a', 1.0, Decimal(10), (1,2), {}])
1574 self.assertTrue(Decimal(10) not in ['a', 1.0, (1,2), {}])
Raymond Hettinger0aeac102004-07-05 22:53:03 +00001575
Raymond Hettinger955d2b22004-08-08 20:17:45 +00001576 def test_copy(self):
1577 # All copies should be deep
1578 c = Context()
1579 d = c.copy()
1580 self.assertNotEqual(id(c), id(d))
1581 self.assertNotEqual(id(c.flags), id(d.flags))
1582 self.assertNotEqual(id(c.traps), id(d.traps))
1583
Nick Coghlan8b6999b2006-08-31 12:00:43 +00001584class WithStatementTest(unittest.TestCase):
1585 # Can't do these as docstrings until Python 2.6
1586 # as doctest can't handle __future__ statements
Nick Coghlan8b6999b2006-08-31 12:00:43 +00001587
1588 def test_localcontext(self):
Nick Coghlanced12182006-09-02 03:54:17 +00001589 # Use a copy of the current context in the block
Nick Coghlan8b6999b2006-08-31 12:00:43 +00001590 orig_ctx = getcontext()
1591 with localcontext() as enter_ctx:
1592 set_ctx = getcontext()
1593 final_ctx = getcontext()
Benjamin Peterson5c8da862009-06-30 22:57:08 +00001594 self.assertTrue(orig_ctx is final_ctx, 'did not restore context correctly')
1595 self.assertTrue(orig_ctx is not set_ctx, 'did not copy the context')
1596 self.assertTrue(set_ctx is enter_ctx, '__enter__ returned wrong context')
Nick Coghlan8b6999b2006-08-31 12:00:43 +00001597
1598 def test_localcontextarg(self):
Nick Coghlanced12182006-09-02 03:54:17 +00001599 # Use a copy of the supplied context in the block
Nick Coghlan8b6999b2006-08-31 12:00:43 +00001600 orig_ctx = getcontext()
1601 new_ctx = Context(prec=42)
1602 with localcontext(new_ctx) as enter_ctx:
1603 set_ctx = getcontext()
1604 final_ctx = getcontext()
Benjamin Peterson5c8da862009-06-30 22:57:08 +00001605 self.assertTrue(orig_ctx is final_ctx, 'did not restore context correctly')
1606 self.assertTrue(set_ctx.prec == new_ctx.prec, 'did not set correct context')
1607 self.assertTrue(new_ctx is not set_ctx, 'did not copy the context')
1608 self.assertTrue(set_ctx is enter_ctx, '__enter__ returned wrong context')
Nick Coghlan8b6999b2006-08-31 12:00:43 +00001609
Facundo Batista353750c2007-09-13 18:13:15 +00001610class ContextFlags(unittest.TestCase):
1611 def test_flags_irrelevant(self):
1612 # check that the result (numeric result + flags raised) of an
1613 # arithmetic operation doesn't depend on the current flags
1614
1615 context = Context(prec=9, Emin = -999999999, Emax = 999999999,
1616 rounding=ROUND_HALF_EVEN, traps=[], flags=[])
1617
1618 # operations that raise various flags, in the form (function, arglist)
1619 operations = [
1620 (context._apply, [Decimal("100E-1000000009")]),
1621 (context.sqrt, [Decimal(2)]),
1622 (context.add, [Decimal("1.23456789"), Decimal("9.87654321")]),
1623 (context.multiply, [Decimal("1.23456789"), Decimal("9.87654321")]),
1624 (context.subtract, [Decimal("1.23456789"), Decimal("9.87654321")]),
1625 ]
1626
1627 # try various flags individually, then a whole lot at once
1628 flagsets = [[Inexact], [Rounded], [Underflow], [Clamped], [Subnormal],
1629 [Inexact, Rounded, Underflow, Clamped, Subnormal]]
1630
1631 for fn, args in operations:
1632 # find answer and flags raised using a clean context
1633 context.clear_flags()
1634 ans = fn(*args)
1635 flags = [k for k, v in context.flags.items() if v]
1636
1637 for extra_flags in flagsets:
1638 # set flags, before calling operation
1639 context.clear_flags()
1640 for flag in extra_flags:
1641 context._raise_error(flag)
1642 new_ans = fn(*args)
1643
1644 # flags that we expect to be set after the operation
1645 expected_flags = list(flags)
1646 for flag in extra_flags:
1647 if flag not in expected_flags:
1648 expected_flags.append(flag)
1649 expected_flags.sort()
1650
1651 # flags we actually got
1652 new_flags = [k for k,v in context.flags.items() if v]
1653 new_flags.sort()
1654
1655 self.assertEqual(ans, new_ans,
1656 "operation produces different answers depending on flags set: " +
1657 "expected %s, got %s." % (ans, new_ans))
1658 self.assertEqual(new_flags, expected_flags,
1659 "operation raises different flags depending on flags set: " +
1660 "expected %s, got %s" % (expected_flags, new_flags))
1661
1662def test_main(arith=False, verbose=None, todo_tests=None, debug=None):
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001663 """ Execute the tests.
1664
Raymond Hettingered20ad82004-09-04 20:09:13 +00001665 Runs all arithmetic tests if arith is True or if the "decimal" resource
1666 is enabled in regrtest.py
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001667 """
Raymond Hettingered20ad82004-09-04 20:09:13 +00001668
Neal Norwitzce4a9c92006-04-09 08:36:46 +00001669 init()
Facundo Batista353750c2007-09-13 18:13:15 +00001670 global TEST_ALL, DEBUG
Raymond Hettingered20ad82004-09-04 20:09:13 +00001671 TEST_ALL = arith or is_resource_enabled('decimal')
Facundo Batista353750c2007-09-13 18:13:15 +00001672 DEBUG = debug
Raymond Hettingered20ad82004-09-04 20:09:13 +00001673
Facundo Batista353750c2007-09-13 18:13:15 +00001674 if todo_tests is None:
1675 test_classes = [
1676 DecimalExplicitConstructionTest,
1677 DecimalImplicitConstructionTest,
1678 DecimalArithmeticOperatorsTest,
Mark Dickinson1ddf1d82008-02-29 02:16:37 +00001679 DecimalFormatTest,
Facundo Batista353750c2007-09-13 18:13:15 +00001680 DecimalUseOfContextTest,
1681 DecimalUsabilityTest,
1682 DecimalPythonAPItests,
1683 ContextAPItests,
1684 DecimalTest,
1685 WithStatementTest,
1686 ContextFlags
1687 ]
1688 else:
1689 test_classes = [DecimalTest]
1690
1691 # Dynamically build custom test definition for each file in the test
1692 # directory and add the definitions to the DecimalTest class. This
1693 # procedure insures that new files do not get skipped.
1694 for filename in os.listdir(directory):
1695 if '.decTest' not in filename or filename.startswith("."):
1696 continue
1697 head, tail = filename.split('.')
1698 if todo_tests is not None and head not in todo_tests:
1699 continue
1700 tester = lambda self, f=filename: self.eval_file(directory + f)
1701 setattr(DecimalTest, 'test_' + head, tester)
1702 del filename, head, tail, tester
1703
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001704
Tim Peters46cc7022006-03-31 04:11:16 +00001705 try:
1706 run_unittest(*test_classes)
Facundo Batista353750c2007-09-13 18:13:15 +00001707 if todo_tests is None:
1708 import decimal as DecimalModule
1709 run_doctest(DecimalModule, verbose)
Tim Peters46cc7022006-03-31 04:11:16 +00001710 finally:
1711 setcontext(ORIGINAL_CONTEXT)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001712
1713if __name__ == '__main__':
Facundo Batista353750c2007-09-13 18:13:15 +00001714 import optparse
1715 p = optparse.OptionParser("test_decimal.py [--debug] [{--skip | test1 [test2 [...]]}]")
1716 p.add_option('--debug', '-d', action='store_true', help='shows the test number and context before each test')
1717 p.add_option('--skip', '-s', action='store_true', help='skip over 90% of the arithmetic tests')
1718 (opt, args) = p.parse_args()
1719
1720 if opt.skip:
1721 test_main(arith=False, verbose=True)
1722 elif args:
1723 test_main(arith=True, verbose=True, todo_tests=args, debug=opt.debug)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001724 else:
Facundo Batista353750c2007-09-13 18:13:15 +00001725 test_main(arith=True, verbose=True)