blob: aa1ba9b0246b0f4af4005703eefd4086dba9e173 [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
Jeffrey Yasskinca2b69f2008-02-01 06:22:46 +000027import math
Raymond Hettinger7c85fa42004-07-01 11:01:35 +000028import os, sys
29import pickle, copy
Jeffrey Yasskinca2b69f2008-02-01 06:22:46 +000030import unittest
Raymond Hettinger7c85fa42004-07-01 11:01:35 +000031from decimal import *
Raymond Hettinger2c8585b2009-02-03 03:37:03 +000032import numbers
Senthil Kumarance8e33a2010-01-08 19:04:16 +000033from test.test_support import (run_unittest, run_doctest, is_resource_enabled)
Raymond Hettinger0aeac102004-07-05 22:53:03 +000034import random
Raymond Hettinger7e71fa52004-12-18 19:07:19 +000035try:
36 import threading
37except ImportError:
38 threading = None
Raymond Hettinger7c85fa42004-07-01 11:01:35 +000039
Raymond Hettingerfed52962004-07-14 15:41:57 +000040# Useful Test Constant
41Signals = getcontext().flags.keys()
42
Tim Peters46cc7022006-03-31 04:11:16 +000043# Tests are built around these assumed context defaults.
44# test_main() restores the original context.
Neal Norwitzce4a9c92006-04-09 08:36:46 +000045def init():
46 global ORIGINAL_CONTEXT
47 ORIGINAL_CONTEXT = getcontext().copy()
Facundo Batistaee340e52008-05-02 17:39:00 +000048 DefaultTestContext = Context(
49 prec = 9,
50 rounding = ROUND_HALF_EVEN,
51 traps = dict.fromkeys(Signals, 0)
52 )
53 setcontext(DefaultTestContext)
Raymond Hettinger6ea48452004-07-03 12:26:21 +000054
Raymond Hettinger7c85fa42004-07-01 11:01:35 +000055TESTDATADIR = 'decimaltestdata'
Raymond Hettingerd9c0a7a2004-07-03 10:02:28 +000056if __name__ == '__main__':
57 file = sys.argv[0]
58else:
59 file = __file__
60testdir = os.path.dirname(file) or os.curdir
Raymond Hettinger267b8682005-03-27 10:47:39 +000061directory = testdir + os.sep + TESTDATADIR + os.sep
Raymond Hettinger7c85fa42004-07-01 11:01:35 +000062
Raymond Hettinger267b8682005-03-27 10:47:39 +000063skip_expected = not os.path.isdir(directory)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +000064
Mark Dickinson539bff42009-10-08 16:28:39 +000065# list of individual .decTest test ids that correspond to tests that
66# we're skipping for one reason or another.
67skipped_test_ids = [
68 'scbx164', # skipping apparently implementation-specific scaleb
69 'scbx165', # tests, pending clarification of scaleb rules.
70]
71
Raymond Hettinger7c85fa42004-07-01 11:01:35 +000072# Make sure it actually raises errors when not expected and caught in flags
73# Slower, since it runs some things several times.
74EXTENDEDERRORTEST = False
75
Raymond Hettinger7c85fa42004-07-01 11:01:35 +000076#Map the test cases' error names to the actual errors
Raymond Hettinger7c85fa42004-07-01 11:01:35 +000077ErrorNames = {'clamped' : Clamped,
Raymond Hettinger5aa478b2004-07-09 10:02:53 +000078 'conversion_syntax' : InvalidOperation,
Raymond Hettinger7c85fa42004-07-01 11:01:35 +000079 'division_by_zero' : DivisionByZero,
Raymond Hettinger5aa478b2004-07-09 10:02:53 +000080 'division_impossible' : InvalidOperation,
81 'division_undefined' : InvalidOperation,
Raymond Hettinger7c85fa42004-07-01 11:01:35 +000082 'inexact' : Inexact,
Raymond Hettinger5aa478b2004-07-09 10:02:53 +000083 'invalid_context' : InvalidOperation,
Raymond Hettinger7c85fa42004-07-01 11:01:35 +000084 'invalid_operation' : InvalidOperation,
85 'overflow' : Overflow,
86 'rounded' : Rounded,
87 'subnormal' : Subnormal,
88 'underflow' : Underflow}
89
90
91def Nonfunction(*args):
92 """Doesn't do anything."""
93 return None
94
95RoundingDict = {'ceiling' : ROUND_CEILING, #Maps test-case names to roundings.
96 'down' : ROUND_DOWN,
97 'floor' : ROUND_FLOOR,
98 'half_down' : ROUND_HALF_DOWN,
99 'half_even' : ROUND_HALF_EVEN,
100 'half_up' : ROUND_HALF_UP,
Facundo Batista353750c2007-09-13 18:13:15 +0000101 'up' : ROUND_UP,
102 '05up' : ROUND_05UP}
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000103
104# Name adapter to be able to change the Decimal and Context
105# interface without changing the test files from Cowlishaw
Facundo Batista1a191df2007-10-02 17:01:24 +0000106nameAdapter = {'and':'logical_and',
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000107 'apply':'_apply',
Facundo Batista353750c2007-09-13 18:13:15 +0000108 'class':'number_class',
109 'comparesig':'compare_signal',
110 'comparetotal':'compare_total',
111 'comparetotmag':'compare_total_mag',
Facundo Batista353750c2007-09-13 18:13:15 +0000112 'copy':'copy_decimal',
Facundo Batista1a191df2007-10-02 17:01:24 +0000113 'copyabs':'copy_abs',
Facundo Batista353750c2007-09-13 18:13:15 +0000114 'copynegate':'copy_negate',
115 'copysign':'copy_sign',
Facundo Batista1a191df2007-10-02 17:01:24 +0000116 'divideint':'divide_int',
Facundo Batista353750c2007-09-13 18:13:15 +0000117 'invert':'logical_invert',
Facundo Batista1a191df2007-10-02 17:01:24 +0000118 'iscanonical':'is_canonical',
119 'isfinite':'is_finite',
120 'isinfinite':'is_infinite',
121 'isnan':'is_nan',
122 'isnormal':'is_normal',
123 'isqnan':'is_qnan',
124 'issigned':'is_signed',
125 'issnan':'is_snan',
126 'issubnormal':'is_subnormal',
127 'iszero':'is_zero',
Facundo Batista353750c2007-09-13 18:13:15 +0000128 'maxmag':'max_mag',
129 'minmag':'min_mag',
130 'nextminus':'next_minus',
131 'nextplus':'next_plus',
132 'nexttoward':'next_toward',
Facundo Batista1a191df2007-10-02 17:01:24 +0000133 'or':'logical_or',
Facundo Batista353750c2007-09-13 18:13:15 +0000134 'reduce':'normalize',
Facundo Batista1a191df2007-10-02 17:01:24 +0000135 'remaindernear':'remainder_near',
136 'samequantum':'same_quantum',
137 'squareroot':'sqrt',
138 'toeng':'to_eng_string',
139 'tointegral':'to_integral_value',
140 'tointegralx':'to_integral_exact',
141 'tosci':'to_sci_string',
142 'xor':'logical_xor',
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000143 }
144
Facundo Batista1a191df2007-10-02 17:01:24 +0000145# The following functions return True/False rather than a Decimal instance
146
147LOGICAL_FUNCTIONS = (
148 'is_canonical',
149 'is_finite',
150 'is_infinite',
151 'is_nan',
152 'is_normal',
153 'is_qnan',
154 'is_signed',
155 'is_snan',
156 'is_subnormal',
157 'is_zero',
158 'same_quantum',
159 )
160
Facundo Batista353750c2007-09-13 18:13:15 +0000161# For some operations (currently exp, ln, log10, power), the decNumber
162# reference implementation imposes additional restrictions on the
163# context and operands. These restrictions are not part of the
164# specification; however, the effect of these restrictions does show
165# up in some of the testcases. We skip testcases that violate these
166# restrictions, since Decimal behaves differently from decNumber for
167# these testcases so these testcases would otherwise fail.
168
169decNumberRestricted = ('power', 'ln', 'log10', 'exp')
170DEC_MAX_MATH = 999999
171def outside_decNumber_bounds(v, context):
172 if (context.prec > DEC_MAX_MATH or
173 context.Emax > DEC_MAX_MATH or
174 -context.Emin > DEC_MAX_MATH):
175 return True
176 if not v._is_special and v and (
Facundo Batista353750c2007-09-13 18:13:15 +0000177 v.adjusted() > DEC_MAX_MATH or
178 v.adjusted() < 1-2*DEC_MAX_MATH):
179 return True
180 return False
181
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000182class DecimalTest(unittest.TestCase):
183 """Class which tests the Decimal class against the test cases.
184
185 Changed for unittest.
186 """
187 def setUp(self):
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000188 self.context = Context()
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000189 self.ignore_list = ['#']
190 # Basically, a # means return NaN InvalidOperation.
191 # Different from a sNaN in trim
192
193 self.ChangeDict = {'precision' : self.change_precision,
194 'rounding' : self.change_rounding_method,
195 'maxexponent' : self.change_max_exponent,
196 'minexponent' : self.change_min_exponent,
197 'clamp' : self.change_clamp}
198
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000199 def eval_file(self, file):
200 global skip_expected
201 if skip_expected:
Benjamin Petersonbec087f2009-03-26 21:10:30 +0000202 raise unittest.SkipTest
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000203 return
Senthil Kumarance8e33a2010-01-08 19:04:16 +0000204 for line in open(file).xreadlines():
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000205 line = line.replace('\r\n', '').replace('\n', '')
Raymond Hettinger5aa478b2004-07-09 10:02:53 +0000206 #print line
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000207 try:
208 t = self.eval_line(line)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000209 except DecimalException, exception:
210 #Exception raised where there shoudn't have been one.
211 self.fail('Exception "'+exception.__class__.__name__ + '" raised on line '+line)
212
213 return
214
215 def eval_line(self, s):
216 if s.find(' -> ') >= 0 and s[:2] != '--' and not s.startswith(' --'):
217 s = (s.split('->')[0] + '->' +
218 s.split('->')[1].split('--')[0]).strip()
219 else:
220 s = s.split('--')[0].strip()
221
222 for ignore in self.ignore_list:
223 if s.find(ignore) >= 0:
224 #print s.split()[0], 'NotImplemented--', ignore
225 return
226 if not s:
227 return
228 elif ':' in s:
229 return self.eval_directive(s)
230 else:
231 return self.eval_equation(s)
232
233 def eval_directive(self, s):
234 funct, value = map(lambda x: x.strip().lower(), s.split(':'))
235 if funct == 'rounding':
236 value = RoundingDict[value]
237 else:
238 try:
239 value = int(value)
240 except ValueError:
241 pass
242
243 funct = self.ChangeDict.get(funct, Nonfunction)
244 funct(value)
245
246 def eval_equation(self, s):
247 #global DEFAULT_PRECISION
248 #print DEFAULT_PRECISION
Raymond Hettingered20ad82004-09-04 20:09:13 +0000249
250 if not TEST_ALL and random.random() < 0.90:
251 return
252
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000253 try:
254 Sides = s.split('->')
255 L = Sides[0].strip().split()
256 id = L[0]
Facundo Batista353750c2007-09-13 18:13:15 +0000257 if DEBUG:
258 print "Test ", id,
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000259 funct = L[1].lower()
260 valstemp = L[2:]
261 L = Sides[1].strip().split()
262 ans = L[0]
263 exceptions = L[1:]
264 except (TypeError, AttributeError, IndexError):
Raymond Hettingerd87ac8f2004-07-09 10:52:54 +0000265 raise InvalidOperation
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000266 def FixQuotes(val):
267 val = val.replace("''", 'SingleQuote').replace('""', 'DoubleQuote')
268 val = val.replace("'", '').replace('"', '')
269 val = val.replace('SingleQuote', "'").replace('DoubleQuote', '"')
270 return val
Mark Dickinson539bff42009-10-08 16:28:39 +0000271
272 if id in skipped_test_ids:
273 return
274
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000275 fname = nameAdapter.get(funct, funct)
276 if fname == 'rescale':
277 return
278 funct = getattr(self.context, fname)
279 vals = []
280 conglomerate = ''
281 quote = 0
282 theirexceptions = [ErrorNames[x.lower()] for x in exceptions]
283
Raymond Hettingerd9c0a7a2004-07-03 10:02:28 +0000284 for exception in Signals:
Raymond Hettingerbf440692004-07-10 14:14:37 +0000285 self.context.traps[exception] = 1 #Catch these bugs...
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000286 for exception in theirexceptions:
Raymond Hettingerbf440692004-07-10 14:14:37 +0000287 self.context.traps[exception] = 0
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000288 for i, val in enumerate(valstemp):
289 if val.count("'") % 2 == 1:
290 quote = 1 - quote
291 if quote:
292 conglomerate = conglomerate + ' ' + val
293 continue
294 else:
295 val = conglomerate + val
296 conglomerate = ''
297 v = FixQuotes(val)
298 if fname in ('to_sci_string', 'to_eng_string'):
299 if EXTENDEDERRORTEST:
300 for error in theirexceptions:
Raymond Hettingerbf440692004-07-10 14:14:37 +0000301 self.context.traps[error] = 1
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000302 try:
303 funct(self.context.create_decimal(v))
304 except error:
305 pass
Raymond Hettingerd9c0a7a2004-07-03 10:02:28 +0000306 except Signals, e:
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000307 self.fail("Raised %s in %s when %s disabled" % \
308 (e, s, error))
309 else:
310 self.fail("Did not raise %s in %s" % (error, s))
Raymond Hettingerbf440692004-07-10 14:14:37 +0000311 self.context.traps[error] = 0
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000312 v = self.context.create_decimal(v)
313 else:
Facundo Batista353750c2007-09-13 18:13:15 +0000314 v = Decimal(v, self.context)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000315 vals.append(v)
316
317 ans = FixQuotes(ans)
318
Facundo Batista353750c2007-09-13 18:13:15 +0000319 # skip tests that are related to bounds imposed in the decNumber
320 # reference implementation
321 if fname in decNumberRestricted:
322 if fname == 'power':
323 if not (vals[1]._isinteger() and
324 -1999999997 <= vals[1] <= 999999999):
325 if outside_decNumber_bounds(vals[0], self.context) or \
326 outside_decNumber_bounds(vals[1], self.context):
327 #print "Skipping test %s" % s
328 return
329 else:
330 if outside_decNumber_bounds(vals[0], self.context):
331 #print "Skipping test %s" % s
332 return
333
334
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000335 if EXTENDEDERRORTEST and fname not in ('to_sci_string', 'to_eng_string'):
336 for error in theirexceptions:
Raymond Hettingerbf440692004-07-10 14:14:37 +0000337 self.context.traps[error] = 1
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000338 try:
339 funct(*vals)
340 except error:
341 pass
Raymond Hettingerd9c0a7a2004-07-03 10:02:28 +0000342 except Signals, e:
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000343 self.fail("Raised %s in %s when %s disabled" % \
344 (e, s, error))
345 else:
346 self.fail("Did not raise %s in %s" % (error, s))
Raymond Hettingerbf440692004-07-10 14:14:37 +0000347 self.context.traps[error] = 0
Facundo Batista353750c2007-09-13 18:13:15 +0000348 if DEBUG:
349 print "--", self.context
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000350 try:
351 result = str(funct(*vals))
Facundo Batista1a191df2007-10-02 17:01:24 +0000352 if fname in LOGICAL_FUNCTIONS:
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000353 result = str(int(eval(result))) # 'True', 'False' -> '1', '0'
Raymond Hettingerd9c0a7a2004-07-03 10:02:28 +0000354 except Signals, error:
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000355 self.fail("Raised %s in %s" % (error, s))
356 except: #Catch any error long enough to state the test case.
357 print "ERROR:", s
358 raise
359
360 myexceptions = self.getexceptions()
Raymond Hettingerbf440692004-07-10 14:14:37 +0000361 self.context.clear_flags()
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000362
Senthil Kumarance8e33a2010-01-08 19:04:16 +0000363 myexceptions.sort()
364 theirexceptions.sort()
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000365
366 self.assertEqual(result, ans,
367 'Incorrect answer for ' + s + ' -- got ' + result)
368 self.assertEqual(myexceptions, theirexceptions,
Facundo Batista353750c2007-09-13 18:13:15 +0000369 'Incorrect flags set in ' + s + ' -- got ' + str(myexceptions))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000370 return
371
372 def getexceptions(self):
Raymond Hettingerf63ba432004-08-17 05:42:09 +0000373 return [e for e in Signals if self.context.flags[e]]
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000374
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000375 def change_precision(self, prec):
376 self.context.prec = prec
377 def change_rounding_method(self, rounding):
378 self.context.rounding = rounding
379 def change_min_exponent(self, exp):
380 self.context.Emin = exp
381 def change_max_exponent(self, exp):
382 self.context.Emax = exp
383 def change_clamp(self, clamp):
384 self.context._clamp = clamp
385
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000386
387
388# The following classes test the behaviour of Decimal according to PEP 327
389
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000390class DecimalExplicitConstructionTest(unittest.TestCase):
391 '''Unit tests for Explicit Construction cases of Decimal.'''
392
393 def test_explicit_empty(self):
394 self.assertEqual(Decimal(), Decimal("0"))
395
396 def test_explicit_from_None(self):
397 self.assertRaises(TypeError, Decimal, None)
398
399 def test_explicit_from_int(self):
400
401 #positive
402 d = Decimal(45)
403 self.assertEqual(str(d), '45')
404
405 #very large positive
406 d = Decimal(500000123)
407 self.assertEqual(str(d), '500000123')
408
409 #negative
410 d = Decimal(-45)
411 self.assertEqual(str(d), '-45')
412
413 #zero
414 d = Decimal(0)
415 self.assertEqual(str(d), '0')
416
417 def test_explicit_from_string(self):
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000418
419 #empty
420 self.assertEqual(str(Decimal('')), 'NaN')
421
422 #int
423 self.assertEqual(str(Decimal('45')), '45')
424
425 #float
426 self.assertEqual(str(Decimal('45.34')), '45.34')
427
428 #engineer notation
429 self.assertEqual(str(Decimal('45e2')), '4.5E+3')
430
431 #just not a number
432 self.assertEqual(str(Decimal('ugly')), 'NaN')
433
Mark Dickinson59bc20b2008-01-12 01:56:00 +0000434 #leading and trailing whitespace permitted
435 self.assertEqual(str(Decimal('1.3E4 \n')), '1.3E+4')
436 self.assertEqual(str(Decimal(' -7.89')), '-7.89')
437
Mark Dickinson8e85ffa2008-03-25 18:47:59 +0000438 #unicode strings should be permitted
439 self.assertEqual(str(Decimal(u'0E-017')), '0E-17')
440 self.assertEqual(str(Decimal(u'45')), '45')
441 self.assertEqual(str(Decimal(u'-Inf')), '-Infinity')
442 self.assertEqual(str(Decimal(u'NaN123')), 'NaN123')
443
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000444 def test_explicit_from_tuples(self):
445
446 #zero
447 d = Decimal( (0, (0,), 0) )
448 self.assertEqual(str(d), '0')
449
450 #int
451 d = Decimal( (1, (4, 5), 0) )
452 self.assertEqual(str(d), '-45')
453
454 #float
455 d = Decimal( (0, (4, 5, 3, 4), -2) )
456 self.assertEqual(str(d), '45.34')
457
458 #weird
459 d = Decimal( (1, (4, 3, 4, 9, 1, 3, 5, 3, 4), -25) )
460 self.assertEqual(str(d), '-4.34913534E-17')
461
462 #wrong number of items
463 self.assertRaises(ValueError, Decimal, (1, (4, 3, 4, 9, 1)) )
464
465 #bad sign
466 self.assertRaises(ValueError, Decimal, (8, (4, 3, 4, 9, 1), 2) )
Facundo Batista9b5e2312007-10-19 19:25:57 +0000467 self.assertRaises(ValueError, Decimal, (0., (4, 3, 4, 9, 1), 2) )
468 self.assertRaises(ValueError, Decimal, (Decimal(1), (4, 3, 4, 9, 1), 2))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000469
470 #bad exp
471 self.assertRaises(ValueError, Decimal, (1, (4, 3, 4, 9, 1), 'wrong!') )
Facundo Batista9b5e2312007-10-19 19:25:57 +0000472 self.assertRaises(ValueError, Decimal, (1, (4, 3, 4, 9, 1), 0.) )
473 self.assertRaises(ValueError, Decimal, (1, (4, 3, 4, 9, 1), '1') )
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000474
475 #bad coefficients
476 self.assertRaises(ValueError, Decimal, (1, (4, 3, 4, None, 1), 2) )
477 self.assertRaises(ValueError, Decimal, (1, (4, -3, 4, 9, 1), 2) )
Facundo Batista9b5e2312007-10-19 19:25:57 +0000478 self.assertRaises(ValueError, Decimal, (1, (4, 10, 4, 9, 1), 2) )
Facundo Batista72bc54f2007-11-23 17:59:00 +0000479 self.assertRaises(ValueError, Decimal, (1, (4, 3, 4, 'a', 1), 2) )
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000480
481 def test_explicit_from_Decimal(self):
482
483 #positive
484 d = Decimal(45)
485 e = Decimal(d)
486 self.assertEqual(str(e), '45')
487 self.assertNotEqual(id(d), id(e))
488
489 #very large positive
490 d = Decimal(500000123)
491 e = Decimal(d)
492 self.assertEqual(str(e), '500000123')
493 self.assertNotEqual(id(d), id(e))
494
495 #negative
496 d = Decimal(-45)
497 e = Decimal(d)
498 self.assertEqual(str(e), '-45')
499 self.assertNotEqual(id(d), id(e))
500
501 #zero
502 d = Decimal(0)
503 e = Decimal(d)
504 self.assertEqual(str(e), '0')
505 self.assertNotEqual(id(d), id(e))
506
507 def test_explicit_context_create_decimal(self):
508
509 nc = copy.copy(getcontext())
510 nc.prec = 3
511
512 # empty
Raymond Hettingerfed52962004-07-14 15:41:57 +0000513 d = Decimal()
514 self.assertEqual(str(d), '0')
515 d = nc.create_decimal()
516 self.assertEqual(str(d), '0')
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000517
518 # from None
519 self.assertRaises(TypeError, nc.create_decimal, None)
520
521 # from int
522 d = nc.create_decimal(456)
Ezio Melottib0f5adc2010-01-24 16:58:36 +0000523 self.assertIsInstance(d, Decimal)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000524 self.assertEqual(nc.create_decimal(45678),
525 nc.create_decimal('457E+2'))
526
527 # from string
528 d = Decimal('456789')
529 self.assertEqual(str(d), '456789')
530 d = nc.create_decimal('456789')
531 self.assertEqual(str(d), '4.57E+5')
Mark Dickinson59bc20b2008-01-12 01:56:00 +0000532 # leading and trailing whitespace should result in a NaN;
533 # spaces are already checked in Cowlishaw's test-suite, so
534 # here we just check that a trailing newline results in a NaN
535 self.assertEqual(str(nc.create_decimal('3.14\n')), 'NaN')
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000536
537 # from tuples
538 d = Decimal( (1, (4, 3, 4, 9, 1, 3, 5, 3, 4), -25) )
539 self.assertEqual(str(d), '-4.34913534E-17')
540 d = nc.create_decimal( (1, (4, 3, 4, 9, 1, 3, 5, 3, 4), -25) )
541 self.assertEqual(str(d), '-4.35E-17')
542
543 # from Decimal
544 prevdec = Decimal(500000123)
545 d = Decimal(prevdec)
546 self.assertEqual(str(d), '500000123')
547 d = nc.create_decimal(prevdec)
548 self.assertEqual(str(d), '5.00E+8')
549
Mark Dickinson4326ad82009-08-02 10:59:36 +0000550 def test_unicode_digits(self):
551 test_values = {
552 u'\uff11': '1',
553 u'\u0660.\u0660\u0663\u0667\u0662e-\u0663' : '0.0000372',
554 u'-nan\u0c68\u0c6a\u0c66\u0c66' : '-NaN2400',
555 }
556 for input, expected in test_values.items():
557 self.assertEqual(str(Decimal(input)), expected)
558
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000559
560class DecimalImplicitConstructionTest(unittest.TestCase):
561 '''Unit tests for Implicit Construction cases of Decimal.'''
562
563 def test_implicit_from_None(self):
564 self.assertRaises(TypeError, eval, 'Decimal(5) + None', globals())
565
566 def test_implicit_from_int(self):
567 #normal
568 self.assertEqual(str(Decimal(5) + 45), '50')
569 #exceeding precision
570 self.assertEqual(Decimal(5) + 123456789000, Decimal(123456789000))
571
572 def test_implicit_from_string(self):
573 self.assertRaises(TypeError, eval, 'Decimal(5) + "3"', globals())
574
575 def test_implicit_from_float(self):
576 self.assertRaises(TypeError, eval, 'Decimal(5) + 2.2', globals())
577
578 def test_implicit_from_Decimal(self):
579 self.assertEqual(Decimal(5) + Decimal(45), Decimal(50))
580
Raymond Hettinger267b8682005-03-27 10:47:39 +0000581 def test_rop(self):
582 # Allow other classes to be trained to interact with Decimals
583 class E:
584 def __divmod__(self, other):
585 return 'divmod ' + str(other)
586 def __rdivmod__(self, other):
587 return str(other) + ' rdivmod'
588 def __lt__(self, other):
589 return 'lt ' + str(other)
590 def __gt__(self, other):
591 return 'gt ' + str(other)
592 def __le__(self, other):
593 return 'le ' + str(other)
594 def __ge__(self, other):
595 return 'ge ' + str(other)
596 def __eq__(self, other):
597 return 'eq ' + str(other)
598 def __ne__(self, other):
599 return 'ne ' + str(other)
600
601 self.assertEqual(divmod(E(), Decimal(10)), 'divmod 10')
602 self.assertEqual(divmod(Decimal(10), E()), '10 rdivmod')
603 self.assertEqual(eval('Decimal(10) < E()'), 'gt 10')
604 self.assertEqual(eval('Decimal(10) > E()'), 'lt 10')
605 self.assertEqual(eval('Decimal(10) <= E()'), 'ge 10')
606 self.assertEqual(eval('Decimal(10) >= E()'), 'le 10')
607 self.assertEqual(eval('Decimal(10) == E()'), 'eq 10')
608 self.assertEqual(eval('Decimal(10) != E()'), 'ne 10')
609
610 # insert operator methods and then exercise them
Georg Brandl96c3f7f2006-03-28 08:06:35 +0000611 oplist = [
612 ('+', '__add__', '__radd__'),
613 ('-', '__sub__', '__rsub__'),
614 ('*', '__mul__', '__rmul__'),
615 ('%', '__mod__', '__rmod__'),
616 ('//', '__floordiv__', '__rfloordiv__'),
617 ('**', '__pow__', '__rpow__')
618 ]
Senthil Kumarance8e33a2010-01-08 19:04:16 +0000619 if 1/2 == 0:
620 # testing with classic division, so add __div__
621 oplist.append(('/', '__div__', '__rdiv__'))
622 else:
623 # testing with -Qnew, so add __truediv__
624 oplist.append(('/', '__truediv__', '__rtruediv__'))
Anthony Baxter4ef3a232006-03-30 12:59:11 +0000625
Georg Brandl96c3f7f2006-03-28 08:06:35 +0000626 for sym, lop, rop in oplist:
Raymond Hettinger267b8682005-03-27 10:47:39 +0000627 setattr(E, lop, lambda self, other: 'str' + lop + str(other))
628 setattr(E, rop, lambda self, other: str(other) + rop + 'str')
629 self.assertEqual(eval('E()' + sym + 'Decimal(10)'),
630 'str' + lop + '10')
631 self.assertEqual(eval('Decimal(10)' + sym + 'E()'),
632 '10' + rop + 'str')
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000633
Mark Dickinson277859d2009-03-17 23:03:46 +0000634
Mark Dickinson1ddf1d82008-02-29 02:16:37 +0000635class DecimalFormatTest(unittest.TestCase):
636 '''Unit tests for the format function.'''
637 def test_formatting(self):
638 # triples giving a format, a Decimal, and the expected result
639 test_values = [
640 ('e', '0E-15', '0e-15'),
641 ('e', '2.3E-15', '2.3e-15'),
642 ('e', '2.30E+2', '2.30e+2'), # preserve significant zeros
643 ('e', '2.30000E-15', '2.30000e-15'),
644 ('e', '1.23456789123456789e40', '1.23456789123456789e+40'),
645 ('e', '1.5', '1.5e+0'),
646 ('e', '0.15', '1.5e-1'),
647 ('e', '0.015', '1.5e-2'),
648 ('e', '0.0000000000015', '1.5e-12'),
649 ('e', '15.0', '1.50e+1'),
650 ('e', '-15', '-1.5e+1'),
651 ('e', '0', '0e+0'),
652 ('e', '0E1', '0e+1'),
653 ('e', '0.0', '0e-1'),
654 ('e', '0.00', '0e-2'),
655 ('.6e', '0E-15', '0.000000e-9'),
656 ('.6e', '0', '0.000000e+6'),
657 ('.6e', '9.999999', '9.999999e+0'),
658 ('.6e', '9.9999999', '1.000000e+1'),
659 ('.6e', '-1.23e5', '-1.230000e+5'),
660 ('.6e', '1.23456789e-3', '1.234568e-3'),
661 ('f', '0', '0'),
662 ('f', '0.0', '0.0'),
663 ('f', '0E-2', '0.00'),
664 ('f', '0.00E-8', '0.0000000000'),
665 ('f', '0E1', '0'), # loses exponent information
666 ('f', '3.2E1', '32'),
667 ('f', '3.2E2', '320'),
668 ('f', '3.20E2', '320'),
669 ('f', '3.200E2', '320.0'),
670 ('f', '3.2E-6', '0.0000032'),
671 ('.6f', '0E-15', '0.000000'), # all zeros treated equally
672 ('.6f', '0E1', '0.000000'),
673 ('.6f', '0', '0.000000'),
674 ('.0f', '0', '0'), # no decimal point
675 ('.0f', '0e-2', '0'),
676 ('.0f', '3.14159265', '3'),
677 ('.1f', '3.14159265', '3.1'),
678 ('.4f', '3.14159265', '3.1416'),
679 ('.6f', '3.14159265', '3.141593'),
680 ('.7f', '3.14159265', '3.1415926'), # round-half-even!
681 ('.8f', '3.14159265', '3.14159265'),
682 ('.9f', '3.14159265', '3.141592650'),
683
684 ('g', '0', '0'),
685 ('g', '0.0', '0.0'),
686 ('g', '0E1', '0e+1'),
687 ('G', '0E1', '0E+1'),
688 ('g', '0E-5', '0.00000'),
689 ('g', '0E-6', '0.000000'),
690 ('g', '0E-7', '0e-7'),
691 ('g', '-0E2', '-0e+2'),
692 ('.0g', '3.14159265', '3'), # 0 sig fig -> 1 sig fig
693 ('.1g', '3.14159265', '3'),
694 ('.2g', '3.14159265', '3.1'),
695 ('.5g', '3.14159265', '3.1416'),
696 ('.7g', '3.14159265', '3.141593'),
697 ('.8g', '3.14159265', '3.1415926'), # round-half-even!
698 ('.9g', '3.14159265', '3.14159265'),
699 ('.10g', '3.14159265', '3.14159265'), # don't pad
700
701 ('%', '0E1', '0%'),
702 ('%', '0E0', '0%'),
703 ('%', '0E-1', '0%'),
704 ('%', '0E-2', '0%'),
705 ('%', '0E-3', '0.0%'),
706 ('%', '0E-4', '0.00%'),
707
708 ('.3%', '0', '0.000%'), # all zeros treated equally
709 ('.3%', '0E10', '0.000%'),
710 ('.3%', '0E-10', '0.000%'),
711 ('.3%', '2.34', '234.000%'),
712 ('.3%', '1.234567', '123.457%'),
713 ('.0%', '1.23', '123%'),
714
715 ('e', 'NaN', 'NaN'),
716 ('f', '-NaN123', '-NaN123'),
717 ('+g', 'NaN456', '+NaN456'),
718 ('.3e', 'Inf', 'Infinity'),
719 ('.16f', '-Inf', '-Infinity'),
720 ('.0g', '-sNaN', '-sNaN'),
721
722 ('', '1.00', '1.00'),
Mark Dickinsonb065e522009-03-17 18:01:03 +0000723
Mark Dickinson277859d2009-03-17 23:03:46 +0000724 # test alignment and padding
Mark Dickinson5cfa8042009-09-08 20:20:19 +0000725 ('6', '123', ' 123'),
Mark Dickinsonb065e522009-03-17 18:01:03 +0000726 ('<6', '123', '123 '),
727 ('>6', '123', ' 123'),
728 ('^6', '123', ' 123 '),
729 ('=+6', '123', '+ 123'),
Mark Dickinson277859d2009-03-17 23:03:46 +0000730 ('#<10', 'NaN', 'NaN#######'),
731 ('#<10', '-4.3', '-4.3######'),
732 ('#<+10', '0.0130', '+0.0130###'),
733 ('#< 10', '0.0130', ' 0.0130###'),
734 ('@>10', '-Inf', '@-Infinity'),
735 ('#>5', '-Inf', '-Infinity'),
736 ('?^5', '123', '?123?'),
737 ('%^6', '123', '%123%%'),
738 (' ^6', '-45.6', '-45.6 '),
739 ('/=10', '-45.6', '-/////45.6'),
740 ('/=+10', '45.6', '+/////45.6'),
741 ('/= 10', '45.6', ' /////45.6'),
742
743 # thousands separator
744 (',', '1234567', '1,234,567'),
745 (',', '123456', '123,456'),
746 (',', '12345', '12,345'),
747 (',', '1234', '1,234'),
748 (',', '123', '123'),
749 (',', '12', '12'),
750 (',', '1', '1'),
751 (',', '0', '0'),
752 (',', '-1234567', '-1,234,567'),
753 (',', '-123456', '-123,456'),
754 ('7,', '123456', '123,456'),
Mark Dickinson5cfa8042009-09-08 20:20:19 +0000755 ('8,', '123456', ' 123,456'),
Mark Dickinson277859d2009-03-17 23:03:46 +0000756 ('08,', '123456', '0,123,456'), # special case: extra 0 needed
757 ('+08,', '123456', '+123,456'), # but not if there's a sign
758 (' 08,', '123456', ' 123,456'),
759 ('08,', '-123456', '-123,456'),
760 ('+09,', '123456', '+0,123,456'),
761 # ... with fractional part...
762 ('07,', '1234.56', '1,234.56'),
763 ('08,', '1234.56', '1,234.56'),
764 ('09,', '1234.56', '01,234.56'),
765 ('010,', '1234.56', '001,234.56'),
766 ('011,', '1234.56', '0,001,234.56'),
767 ('012,', '1234.56', '0,001,234.56'),
768 ('08,.1f', '1234.5', '01,234.5'),
769 # no thousands separators in fraction part
770 (',', '1.23456789', '1.23456789'),
771 (',%', '123.456789', '12,345.6789%'),
772 (',e', '123456', '1.23456e+5'),
773 (',E', '123456', '1.23456E+5'),
Mark Dickinson491ea552009-09-07 16:17:41 +0000774
775 # issue 6850
776 ('a=-7.0', '0.12345', 'aaaa0.1'),
Mark Dickinson1ddf1d82008-02-29 02:16:37 +0000777 ]
778 for fmt, d, result in test_values:
779 self.assertEqual(format(Decimal(d), fmt), result)
780
Mark Dickinson277859d2009-03-17 23:03:46 +0000781 def test_n_format(self):
782 try:
783 from locale import CHAR_MAX
784 except ImportError:
785 return
786
787 # Set up some localeconv-like dictionaries
788 en_US = {
789 'decimal_point' : '.',
790 'grouping' : [3, 3, 0],
791 'thousands_sep': ','
792 }
793
794 fr_FR = {
795 'decimal_point' : ',',
796 'grouping' : [CHAR_MAX],
797 'thousands_sep' : ''
798 }
799
800 ru_RU = {
801 'decimal_point' : ',',
802 'grouping' : [3, 3, 0],
803 'thousands_sep' : ' '
804 }
805
806 crazy = {
807 'decimal_point' : '&',
808 'grouping' : [1, 4, 2, CHAR_MAX],
809 'thousands_sep' : '-'
810 }
811
812
813 def get_fmt(x, locale, fmt='n'):
814 return Decimal.__format__(Decimal(x), fmt, _localeconv=locale)
815
816 self.assertEqual(get_fmt(Decimal('12.7'), en_US), '12.7')
817 self.assertEqual(get_fmt(Decimal('12.7'), fr_FR), '12,7')
818 self.assertEqual(get_fmt(Decimal('12.7'), ru_RU), '12,7')
819 self.assertEqual(get_fmt(Decimal('12.7'), crazy), '1-2&7')
820
821 self.assertEqual(get_fmt(123456789, en_US), '123,456,789')
822 self.assertEqual(get_fmt(123456789, fr_FR), '123456789')
823 self.assertEqual(get_fmt(123456789, ru_RU), '123 456 789')
824 self.assertEqual(get_fmt(1234567890123, crazy), '123456-78-9012-3')
825
826 self.assertEqual(get_fmt(123456789, en_US, '.6n'), '1.23457e+8')
827 self.assertEqual(get_fmt(123456789, fr_FR, '.6n'), '1,23457e+8')
828 self.assertEqual(get_fmt(123456789, ru_RU, '.6n'), '1,23457e+8')
829 self.assertEqual(get_fmt(123456789, crazy, '.6n'), '1&23457e+8')
830
Mark Dickinsonb14514a2009-03-18 08:22:51 +0000831 # zero padding
832 self.assertEqual(get_fmt(1234, fr_FR, '03n'), '1234')
833 self.assertEqual(get_fmt(1234, fr_FR, '04n'), '1234')
834 self.assertEqual(get_fmt(1234, fr_FR, '05n'), '01234')
835 self.assertEqual(get_fmt(1234, fr_FR, '06n'), '001234')
836
837 self.assertEqual(get_fmt(12345, en_US, '05n'), '12,345')
838 self.assertEqual(get_fmt(12345, en_US, '06n'), '12,345')
839 self.assertEqual(get_fmt(12345, en_US, '07n'), '012,345')
840 self.assertEqual(get_fmt(12345, en_US, '08n'), '0,012,345')
841 self.assertEqual(get_fmt(12345, en_US, '09n'), '0,012,345')
842 self.assertEqual(get_fmt(12345, en_US, '010n'), '00,012,345')
843
844 self.assertEqual(get_fmt(123456, crazy, '06n'), '1-2345-6')
845 self.assertEqual(get_fmt(123456, crazy, '07n'), '1-2345-6')
846 self.assertEqual(get_fmt(123456, crazy, '08n'), '1-2345-6')
847 self.assertEqual(get_fmt(123456, crazy, '09n'), '01-2345-6')
848 self.assertEqual(get_fmt(123456, crazy, '010n'), '0-01-2345-6')
849 self.assertEqual(get_fmt(123456, crazy, '011n'), '0-01-2345-6')
850 self.assertEqual(get_fmt(123456, crazy, '012n'), '00-01-2345-6')
851 self.assertEqual(get_fmt(123456, crazy, '013n'), '000-01-2345-6')
852
Mark Dickinson277859d2009-03-17 23:03:46 +0000853
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000854class DecimalArithmeticOperatorsTest(unittest.TestCase):
855 '''Unit tests for all arithmetic operators, binary and unary.'''
856
857 def test_addition(self):
858
859 d1 = Decimal('-11.1')
860 d2 = Decimal('22.2')
861
862 #two Decimals
863 self.assertEqual(d1+d2, Decimal('11.1'))
864 self.assertEqual(d2+d1, Decimal('11.1'))
865
866 #with other type, left
867 c = d1 + 5
868 self.assertEqual(c, Decimal('-6.1'))
869 self.assertEqual(type(c), type(d1))
870
871 #with other type, right
872 c = 5 + d1
873 self.assertEqual(c, Decimal('-6.1'))
874 self.assertEqual(type(c), type(d1))
875
876 #inline with decimal
877 d1 += d2
878 self.assertEqual(d1, Decimal('11.1'))
879
880 #inline with other type
881 d1 += 5
882 self.assertEqual(d1, Decimal('16.1'))
883
884 def test_subtraction(self):
885
886 d1 = Decimal('-11.1')
887 d2 = Decimal('22.2')
888
889 #two Decimals
890 self.assertEqual(d1-d2, Decimal('-33.3'))
891 self.assertEqual(d2-d1, Decimal('33.3'))
892
893 #with other type, left
894 c = d1 - 5
895 self.assertEqual(c, Decimal('-16.1'))
896 self.assertEqual(type(c), type(d1))
897
898 #with other type, right
899 c = 5 - d1
900 self.assertEqual(c, Decimal('16.1'))
901 self.assertEqual(type(c), type(d1))
902
903 #inline with decimal
904 d1 -= d2
905 self.assertEqual(d1, Decimal('-33.3'))
906
907 #inline with other type
908 d1 -= 5
909 self.assertEqual(d1, Decimal('-38.3'))
910
911 def test_multiplication(self):
912
913 d1 = Decimal('-5')
914 d2 = Decimal('3')
915
916 #two Decimals
917 self.assertEqual(d1*d2, Decimal('-15'))
918 self.assertEqual(d2*d1, Decimal('-15'))
919
920 #with other type, left
921 c = d1 * 5
922 self.assertEqual(c, Decimal('-25'))
923 self.assertEqual(type(c), type(d1))
924
925 #with other type, right
926 c = 5 * d1
927 self.assertEqual(c, Decimal('-25'))
928 self.assertEqual(type(c), type(d1))
929
930 #inline with decimal
931 d1 *= d2
932 self.assertEqual(d1, Decimal('-15'))
933
934 #inline with other type
935 d1 *= 5
936 self.assertEqual(d1, Decimal('-75'))
937
938 def test_division(self):
939
940 d1 = Decimal('-5')
941 d2 = Decimal('2')
942
943 #two Decimals
944 self.assertEqual(d1/d2, Decimal('-2.5'))
945 self.assertEqual(d2/d1, Decimal('-0.4'))
946
947 #with other type, left
948 c = d1 / 4
949 self.assertEqual(c, Decimal('-1.25'))
950 self.assertEqual(type(c), type(d1))
951
952 #with other type, right
953 c = 4 / d1
954 self.assertEqual(c, Decimal('-0.8'))
955 self.assertEqual(type(c), type(d1))
956
957 #inline with decimal
958 d1 /= d2
959 self.assertEqual(d1, Decimal('-2.5'))
960
961 #inline with other type
962 d1 /= 4
963 self.assertEqual(d1, Decimal('-0.625'))
964
965 def test_floor_division(self):
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000966
967 d1 = Decimal('5')
968 d2 = Decimal('2')
969
970 #two Decimals
971 self.assertEqual(d1//d2, Decimal('2'))
972 self.assertEqual(d2//d1, Decimal('0'))
973
974 #with other type, left
975 c = d1 // 4
976 self.assertEqual(c, Decimal('1'))
977 self.assertEqual(type(c), type(d1))
978
979 #with other type, right
980 c = 7 // d1
981 self.assertEqual(c, Decimal('1'))
982 self.assertEqual(type(c), type(d1))
983
984 #inline with decimal
985 d1 //= d2
986 self.assertEqual(d1, Decimal('2'))
987
988 #inline with other type
989 d1 //= 2
990 self.assertEqual(d1, Decimal('1'))
991
992 def test_powering(self):
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000993
994 d1 = Decimal('5')
995 d2 = Decimal('2')
996
997 #two Decimals
998 self.assertEqual(d1**d2, Decimal('25'))
999 self.assertEqual(d2**d1, Decimal('32'))
1000
1001 #with other type, left
1002 c = d1 ** 4
1003 self.assertEqual(c, Decimal('625'))
1004 self.assertEqual(type(c), type(d1))
1005
1006 #with other type, right
1007 c = 7 ** d1
1008 self.assertEqual(c, Decimal('16807'))
1009 self.assertEqual(type(c), type(d1))
1010
1011 #inline with decimal
1012 d1 **= d2
1013 self.assertEqual(d1, Decimal('25'))
1014
1015 #inline with other type
1016 d1 **= 4
1017 self.assertEqual(d1, Decimal('390625'))
1018
1019 def test_module(self):
1020
1021 d1 = Decimal('5')
1022 d2 = Decimal('2')
1023
1024 #two Decimals
1025 self.assertEqual(d1%d2, Decimal('1'))
1026 self.assertEqual(d2%d1, Decimal('2'))
1027
1028 #with other type, left
1029 c = d1 % 4
1030 self.assertEqual(c, Decimal('1'))
1031 self.assertEqual(type(c), type(d1))
1032
1033 #with other type, right
1034 c = 7 % d1
1035 self.assertEqual(c, Decimal('2'))
1036 self.assertEqual(type(c), type(d1))
1037
1038 #inline with decimal
1039 d1 %= d2
1040 self.assertEqual(d1, Decimal('1'))
1041
1042 #inline with other type
1043 d1 %= 4
1044 self.assertEqual(d1, Decimal('1'))
1045
1046 def test_floor_div_module(self):
1047
1048 d1 = Decimal('5')
1049 d2 = Decimal('2')
1050
1051 #two Decimals
1052 (p, q) = divmod(d1, d2)
1053 self.assertEqual(p, Decimal('2'))
1054 self.assertEqual(q, Decimal('1'))
1055 self.assertEqual(type(p), type(d1))
1056 self.assertEqual(type(q), type(d1))
1057
1058 #with other type, left
1059 (p, q) = divmod(d1, 4)
1060 self.assertEqual(p, Decimal('1'))
1061 self.assertEqual(q, Decimal('1'))
1062 self.assertEqual(type(p), type(d1))
1063 self.assertEqual(type(q), type(d1))
1064
1065 #with other type, right
1066 (p, q) = divmod(7, d1)
1067 self.assertEqual(p, Decimal('1'))
1068 self.assertEqual(q, Decimal('2'))
1069 self.assertEqual(type(p), type(d1))
1070 self.assertEqual(type(q), type(d1))
1071
1072 def test_unary_operators(self):
1073 self.assertEqual(+Decimal(45), Decimal(+45)) # +
1074 self.assertEqual(-Decimal(45), Decimal(-45)) # -
1075 self.assertEqual(abs(Decimal(45)), abs(Decimal(-45))) # abs
1076
Mark Dickinson2fc92632008-02-06 22:10:50 +00001077 def test_nan_comparisons(self):
1078 n = Decimal('NaN')
1079 s = Decimal('sNaN')
1080 i = Decimal('Inf')
1081 f = Decimal('2')
1082 for x, y in [(n, n), (n, i), (i, n), (n, f), (f, n),
1083 (s, n), (n, s), (s, i), (i, s), (s, f), (f, s), (s, s)]:
Benjamin Peterson5c8da862009-06-30 22:57:08 +00001084 self.assertTrue(x != y)
1085 self.assertTrue(not (x == y))
1086 self.assertTrue(not (x < y))
1087 self.assertTrue(not (x <= y))
1088 self.assertTrue(not (x > y))
1089 self.assertTrue(not (x >= y))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001090
1091# The following are two functions used to test threading in the next class
1092
1093def thfunc1(cls):
1094 d1 = Decimal(1)
1095 d3 = Decimal(3)
Facundo Batista64156672008-03-22 02:45:37 +00001096 test1 = d1/d3
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001097 cls.synchro.wait()
Facundo Batista64156672008-03-22 02:45:37 +00001098 test2 = d1/d3
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001099 cls.finish1.set()
Facundo Batista64156672008-03-22 02:45:37 +00001100
Facundo Batistaee340e52008-05-02 17:39:00 +00001101 cls.assertEqual(test1, Decimal('0.3333333333333333333333333333'))
1102 cls.assertEqual(test2, Decimal('0.3333333333333333333333333333'))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001103 return
1104
1105def thfunc2(cls):
1106 d1 = Decimal(1)
1107 d3 = Decimal(3)
Facundo Batista64156672008-03-22 02:45:37 +00001108 test1 = d1/d3
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001109 thiscontext = getcontext()
1110 thiscontext.prec = 18
Facundo Batista64156672008-03-22 02:45:37 +00001111 test2 = d1/d3
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001112 cls.synchro.set()
1113 cls.finish2.set()
Facundo Batista64156672008-03-22 02:45:37 +00001114
Facundo Batistaee340e52008-05-02 17:39:00 +00001115 cls.assertEqual(test1, Decimal('0.3333333333333333333333333333'))
Facundo Batista64156672008-03-22 02:45:37 +00001116 cls.assertEqual(test2, Decimal('0.333333333333333333'))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001117 return
1118
1119
1120class DecimalUseOfContextTest(unittest.TestCase):
1121 '''Unit tests for Use of Context cases in Decimal.'''
1122
Raymond Hettinger7e71fa52004-12-18 19:07:19 +00001123 try:
1124 import threading
1125 except ImportError:
1126 threading = None
1127
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001128 # Take care executing this test from IDLE, there's an issue in threading
1129 # that hangs IDLE and I couldn't find it
1130
1131 def test_threading(self):
1132 #Test the "threading isolation" of a Context.
1133
1134 self.synchro = threading.Event()
1135 self.finish1 = threading.Event()
1136 self.finish2 = threading.Event()
1137
1138 th1 = threading.Thread(target=thfunc1, args=(self,))
1139 th2 = threading.Thread(target=thfunc2, args=(self,))
1140
1141 th1.start()
1142 th2.start()
1143
1144 self.finish1.wait()
Thomas Woutersb3e6e8c2007-09-19 17:27:29 +00001145 self.finish2.wait()
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001146 return
1147
Raymond Hettinger7e71fa52004-12-18 19:07:19 +00001148 if threading is None:
1149 del test_threading
1150
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001151
1152class DecimalUsabilityTest(unittest.TestCase):
1153 '''Unit tests for Usability cases of Decimal.'''
1154
1155 def test_comparison_operators(self):
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001156
1157 da = Decimal('23.42')
1158 db = Decimal('23.42')
1159 dc = Decimal('45')
1160
1161 #two Decimals
Benjamin Peterson5c8da862009-06-30 22:57:08 +00001162 self.assertTrue(dc > da)
1163 self.assertTrue(dc >= da)
1164 self.assertTrue(da < dc)
1165 self.assertTrue(da <= dc)
1166 self.assertTrue(da == db)
1167 self.assertTrue(da != dc)
1168 self.assertTrue(da <= db)
1169 self.assertTrue(da >= db)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001170 self.assertEqual(cmp(dc,da), 1)
1171 self.assertEqual(cmp(da,dc), -1)
1172 self.assertEqual(cmp(da,db), 0)
1173
1174 #a Decimal and an int
Benjamin Peterson5c8da862009-06-30 22:57:08 +00001175 self.assertTrue(dc > 23)
1176 self.assertTrue(23 < dc)
1177 self.assertTrue(dc == 45)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001178 self.assertEqual(cmp(dc,23), 1)
1179 self.assertEqual(cmp(23,dc), -1)
1180 self.assertEqual(cmp(dc,45), 0)
1181
1182 #a Decimal and uncomparable
Raymond Hettinger0aeac102004-07-05 22:53:03 +00001183 self.assertNotEqual(da, 'ugly')
1184 self.assertNotEqual(da, 32.7)
1185 self.assertNotEqual(da, object())
1186 self.assertNotEqual(da, object)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001187
Raymond Hettinger0aeac102004-07-05 22:53:03 +00001188 # sortable
1189 a = map(Decimal, xrange(100))
1190 b = a[:]
1191 random.shuffle(a)
1192 a.sort()
1193 self.assertEqual(a, b)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001194
Facundo Batista353750c2007-09-13 18:13:15 +00001195 # with None
Senthil Kumarance8e33a2010-01-08 19:04:16 +00001196 self.assertFalse(Decimal(1) < None)
1197 self.assertTrue(Decimal(1) > None)
Facundo Batista353750c2007-09-13 18:13:15 +00001198
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001199 def test_copy_and_deepcopy_methods(self):
1200 d = Decimal('43.24')
1201 c = copy.copy(d)
1202 self.assertEqual(id(c), id(d))
1203 dc = copy.deepcopy(d)
1204 self.assertEqual(id(dc), id(d))
1205
1206 def test_hash_method(self):
1207 #just that it's hashable
1208 hash(Decimal(23))
Facundo Batista8c202442007-09-19 17:53:25 +00001209
1210 test_values = [Decimal(sign*(2**m + n))
1211 for m in [0, 14, 15, 16, 17, 30, 31,
1212 32, 33, 62, 63, 64, 65, 66]
1213 for n in range(-10, 10)
1214 for sign in [-1, 1]]
1215 test_values.extend([
1216 Decimal("-0"), # zeros
1217 Decimal("0.00"),
1218 Decimal("-0.000"),
1219 Decimal("0E10"),
1220 Decimal("-0E12"),
1221 Decimal("10.0"), # negative exponent
1222 Decimal("-23.00000"),
1223 Decimal("1230E100"), # positive exponent
1224 Decimal("-4.5678E50"),
1225 # a value for which hash(n) != hash(n % (2**64-1))
1226 # in Python pre-2.6
1227 Decimal(2**64 + 2**32 - 1),
1228 # selection of values which fail with the old (before
1229 # version 2.6) long.__hash__
1230 Decimal("1.634E100"),
1231 Decimal("90.697E100"),
1232 Decimal("188.83E100"),
1233 Decimal("1652.9E100"),
1234 Decimal("56531E100"),
1235 ])
1236
1237 # check that hash(d) == hash(int(d)) for integral values
1238 for value in test_values:
1239 self.assertEqual(hash(value), hash(int(value)))
1240
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001241 #the same hash that to an int
1242 self.assertEqual(hash(Decimal(23)), hash(23))
Raymond Hettingerbea3f6f2005-03-15 04:59:17 +00001243 self.assertRaises(TypeError, hash, Decimal('NaN'))
Benjamin Peterson5c8da862009-06-30 22:57:08 +00001244 self.assertTrue(hash(Decimal('Inf')))
1245 self.assertTrue(hash(Decimal('-Inf')))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001246
Facundo Batista52b25792008-01-08 12:25:20 +00001247 # check that the value of the hash doesn't depend on the
1248 # current context (issue #1757)
1249 c = getcontext()
1250 old_precision = c.prec
1251 x = Decimal("123456789.1")
1252
1253 c.prec = 6
1254 h1 = hash(x)
1255 c.prec = 10
1256 h2 = hash(x)
1257 c.prec = 16
1258 h3 = hash(x)
1259
1260 self.assertEqual(h1, h2)
1261 self.assertEqual(h1, h3)
1262 c.prec = old_precision
1263
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001264 def test_min_and_max_methods(self):
1265
1266 d1 = Decimal('15.32')
1267 d2 = Decimal('28.5')
1268 l1 = 15
1269 l2 = 28
1270
1271 #between Decimals
Benjamin Peterson5c8da862009-06-30 22:57:08 +00001272 self.assertTrue(min(d1,d2) is d1)
1273 self.assertTrue(min(d2,d1) is d1)
1274 self.assertTrue(max(d1,d2) is d2)
1275 self.assertTrue(max(d2,d1) is d2)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001276
1277 #between Decimal and long
Benjamin Peterson5c8da862009-06-30 22:57:08 +00001278 self.assertTrue(min(d1,l2) is d1)
1279 self.assertTrue(min(l2,d1) is d1)
1280 self.assertTrue(max(l1,d2) is d2)
1281 self.assertTrue(max(d2,l1) is d2)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001282
1283 def test_as_nonzero(self):
1284 #as false
Benjamin Peterson5c8da862009-06-30 22:57:08 +00001285 self.assertFalse(Decimal(0))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001286 #as true
Benjamin Peterson5c8da862009-06-30 22:57:08 +00001287 self.assertTrue(Decimal('0.372'))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001288
1289 def test_tostring_methods(self):
1290 #Test str and repr methods.
1291
1292 d = Decimal('15.32')
1293 self.assertEqual(str(d), '15.32') # str
Raymond Hettingerabe32372008-02-14 02:41:22 +00001294 self.assertEqual(repr(d), "Decimal('15.32')") # repr
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001295
Mark Dickinson8e85ffa2008-03-25 18:47:59 +00001296 # result type of string methods should be str, not unicode
1297 unicode_inputs = [u'123.4', u'0.5E2', u'Infinity', u'sNaN',
1298 u'-0.0E100', u'-NaN001', u'-Inf']
1299
1300 for u in unicode_inputs:
1301 d = Decimal(u)
1302 self.assertEqual(type(str(d)), str)
1303 self.assertEqual(type(repr(d)), str)
1304 self.assertEqual(type(d.to_eng_string()), str)
1305
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001306 def test_tonum_methods(self):
1307 #Test float, int and long methods.
1308
1309 d1 = Decimal('66')
1310 d2 = Decimal('15.32')
1311
1312 #int
1313 self.assertEqual(int(d1), 66)
1314 self.assertEqual(int(d2), 15)
1315
1316 #long
1317 self.assertEqual(long(d1), 66)
1318 self.assertEqual(long(d2), 15)
1319
1320 #float
1321 self.assertEqual(float(d1), 66)
1322 self.assertEqual(float(d2), 15.32)
1323
1324 def test_eval_round_trip(self):
1325
1326 #with zero
1327 d = Decimal( (0, (0,), 0) )
1328 self.assertEqual(d, eval(repr(d)))
1329
1330 #int
1331 d = Decimal( (1, (4, 5), 0) )
1332 self.assertEqual(d, eval(repr(d)))
1333
1334 #float
1335 d = Decimal( (0, (4, 5, 3, 4), -2) )
1336 self.assertEqual(d, eval(repr(d)))
1337
1338 #weird
1339 d = Decimal( (1, (4, 3, 4, 9, 1, 3, 5, 3, 4), -25) )
1340 self.assertEqual(d, eval(repr(d)))
1341
1342 def test_as_tuple(self):
1343
1344 #with zero
1345 d = Decimal(0)
1346 self.assertEqual(d.as_tuple(), (0, (0,), 0) )
1347
1348 #int
1349 d = Decimal(-45)
1350 self.assertEqual(d.as_tuple(), (1, (4, 5), 0) )
1351
1352 #complicated string
1353 d = Decimal("-4.34913534E-17")
1354 self.assertEqual(d.as_tuple(), (1, (4, 3, 4, 9, 1, 3, 5, 3, 4), -25) )
1355
1356 #inf
1357 d = Decimal("Infinity")
1358 self.assertEqual(d.as_tuple(), (0, (0,), 'F') )
1359
Facundo Batista9b5e2312007-10-19 19:25:57 +00001360 #leading zeros in coefficient should be stripped
1361 d = Decimal( (0, (0, 0, 4, 0, 5, 3, 4), -2) )
1362 self.assertEqual(d.as_tuple(), (0, (4, 0, 5, 3, 4), -2) )
1363 d = Decimal( (1, (0, 0, 0), 37) )
1364 self.assertEqual(d.as_tuple(), (1, (0,), 37))
1365 d = Decimal( (1, (), 37) )
1366 self.assertEqual(d.as_tuple(), (1, (0,), 37))
1367
1368 #leading zeros in NaN diagnostic info should be stripped
1369 d = Decimal( (0, (0, 0, 4, 0, 5, 3, 4), 'n') )
1370 self.assertEqual(d.as_tuple(), (0, (4, 0, 5, 3, 4), 'n') )
1371 d = Decimal( (1, (0, 0, 0), 'N') )
1372 self.assertEqual(d.as_tuple(), (1, (), 'N') )
1373 d = Decimal( (1, (), 'n') )
1374 self.assertEqual(d.as_tuple(), (1, (), 'n') )
1375
1376 #coefficient in infinity should be ignored
1377 d = Decimal( (0, (4, 5, 3, 4), 'F') )
1378 self.assertEqual(d.as_tuple(), (0, (0,), 'F'))
1379 d = Decimal( (1, (0, 2, 7, 1), 'F') )
1380 self.assertEqual(d.as_tuple(), (1, (0,), 'F'))
1381
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001382 def test_immutability_operations(self):
1383 # Do operations and check that it didn't change change internal objects.
1384
1385 d1 = Decimal('-25e55')
1386 b1 = Decimal('-25e55')
Facundo Batista353750c2007-09-13 18:13:15 +00001387 d2 = Decimal('33e+33')
1388 b2 = Decimal('33e+33')
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001389
1390 def checkSameDec(operation, useOther=False):
1391 if useOther:
1392 eval("d1." + operation + "(d2)")
1393 self.assertEqual(d1._sign, b1._sign)
1394 self.assertEqual(d1._int, b1._int)
1395 self.assertEqual(d1._exp, b1._exp)
1396 self.assertEqual(d2._sign, b2._sign)
1397 self.assertEqual(d2._int, b2._int)
1398 self.assertEqual(d2._exp, b2._exp)
1399 else:
1400 eval("d1." + operation + "()")
1401 self.assertEqual(d1._sign, b1._sign)
1402 self.assertEqual(d1._int, b1._int)
1403 self.assertEqual(d1._exp, b1._exp)
1404 return
1405
1406 Decimal(d1)
1407 self.assertEqual(d1._sign, b1._sign)
1408 self.assertEqual(d1._int, b1._int)
1409 self.assertEqual(d1._exp, b1._exp)
1410
1411 checkSameDec("__abs__")
1412 checkSameDec("__add__", True)
1413 checkSameDec("__div__", True)
1414 checkSameDec("__divmod__", True)
Mark Dickinson2fc92632008-02-06 22:10:50 +00001415 checkSameDec("__eq__", True)
1416 checkSameDec("__ne__", True)
1417 checkSameDec("__le__", True)
1418 checkSameDec("__lt__", True)
1419 checkSameDec("__ge__", True)
1420 checkSameDec("__gt__", True)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001421 checkSameDec("__float__")
1422 checkSameDec("__floordiv__", True)
1423 checkSameDec("__hash__")
1424 checkSameDec("__int__")
Raymond Hettinger5a053642008-01-24 19:05:29 +00001425 checkSameDec("__trunc__")
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001426 checkSameDec("__long__")
1427 checkSameDec("__mod__", True)
1428 checkSameDec("__mul__", True)
1429 checkSameDec("__neg__")
1430 checkSameDec("__nonzero__")
1431 checkSameDec("__pos__")
1432 checkSameDec("__pow__", True)
1433 checkSameDec("__radd__", True)
1434 checkSameDec("__rdiv__", True)
1435 checkSameDec("__rdivmod__", True)
1436 checkSameDec("__repr__")
1437 checkSameDec("__rfloordiv__", True)
1438 checkSameDec("__rmod__", True)
1439 checkSameDec("__rmul__", True)
1440 checkSameDec("__rpow__", True)
1441 checkSameDec("__rsub__", True)
1442 checkSameDec("__str__")
1443 checkSameDec("__sub__", True)
1444 checkSameDec("__truediv__", True)
1445 checkSameDec("adjusted")
1446 checkSameDec("as_tuple")
1447 checkSameDec("compare", True)
1448 checkSameDec("max", True)
1449 checkSameDec("min", True)
1450 checkSameDec("normalize")
1451 checkSameDec("quantize", True)
1452 checkSameDec("remainder_near", True)
1453 checkSameDec("same_quantum", True)
1454 checkSameDec("sqrt")
1455 checkSameDec("to_eng_string")
1456 checkSameDec("to_integral")
1457
Facundo Batista6c398da2007-09-17 17:30:13 +00001458 def test_subclassing(self):
1459 # Different behaviours when subclassing Decimal
1460
1461 class MyDecimal(Decimal):
1462 pass
1463
1464 d1 = MyDecimal(1)
1465 d2 = MyDecimal(2)
1466 d = d1 + d2
1467 self.assertTrue(type(d) is Decimal)
1468
1469 d = d1.max(d2)
1470 self.assertTrue(type(d) is Decimal)
1471
Mark Dickinson3b24ccb2008-03-25 14:33:23 +00001472 def test_implicit_context(self):
1473 # Check results when context given implicitly. (Issue 2478)
1474 c = getcontext()
1475 self.assertEqual(str(Decimal(0).sqrt()),
1476 str(c.sqrt(Decimal(0))))
1477
Mark Dickinson0c673122009-10-29 12:04:00 +00001478 def test_conversions_from_int(self):
1479 # Check that methods taking a second Decimal argument will
1480 # always accept an integer in place of a Decimal.
1481 self.assertEqual(Decimal(4).compare(3),
1482 Decimal(4).compare(Decimal(3)))
1483 self.assertEqual(Decimal(4).compare_signal(3),
1484 Decimal(4).compare_signal(Decimal(3)))
1485 self.assertEqual(Decimal(4).compare_total(3),
1486 Decimal(4).compare_total(Decimal(3)))
1487 self.assertEqual(Decimal(4).compare_total_mag(3),
1488 Decimal(4).compare_total_mag(Decimal(3)))
1489 self.assertEqual(Decimal(10101).logical_and(1001),
1490 Decimal(10101).logical_and(Decimal(1001)))
1491 self.assertEqual(Decimal(10101).logical_or(1001),
1492 Decimal(10101).logical_or(Decimal(1001)))
1493 self.assertEqual(Decimal(10101).logical_xor(1001),
1494 Decimal(10101).logical_xor(Decimal(1001)))
1495 self.assertEqual(Decimal(567).max(123),
1496 Decimal(567).max(Decimal(123)))
1497 self.assertEqual(Decimal(567).max_mag(123),
1498 Decimal(567).max_mag(Decimal(123)))
1499 self.assertEqual(Decimal(567).min(123),
1500 Decimal(567).min(Decimal(123)))
1501 self.assertEqual(Decimal(567).min_mag(123),
1502 Decimal(567).min_mag(Decimal(123)))
1503 self.assertEqual(Decimal(567).next_toward(123),
1504 Decimal(567).next_toward(Decimal(123)))
1505 self.assertEqual(Decimal(1234).quantize(100),
1506 Decimal(1234).quantize(Decimal(100)))
1507 self.assertEqual(Decimal(768).remainder_near(1234),
1508 Decimal(768).remainder_near(Decimal(1234)))
1509 self.assertEqual(Decimal(123).rotate(1),
1510 Decimal(123).rotate(Decimal(1)))
1511 self.assertEqual(Decimal(1234).same_quantum(1000),
1512 Decimal(1234).same_quantum(Decimal(1000)))
1513 self.assertEqual(Decimal('9.123').scaleb(-100),
1514 Decimal('9.123').scaleb(Decimal(-100)))
1515 self.assertEqual(Decimal(456).shift(-1),
1516 Decimal(456).shift(Decimal(-1)))
1517
1518 self.assertEqual(Decimal(-12).fma(Decimal(45), 67),
1519 Decimal(-12).fma(Decimal(45), Decimal(67)))
1520 self.assertEqual(Decimal(-12).fma(45, 67),
1521 Decimal(-12).fma(Decimal(45), Decimal(67)))
1522 self.assertEqual(Decimal(-12).fma(45, Decimal(67)),
1523 Decimal(-12).fma(Decimal(45), Decimal(67)))
1524
Facundo Batista6c398da2007-09-17 17:30:13 +00001525
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001526class DecimalPythonAPItests(unittest.TestCase):
1527
Raymond Hettinger2c8585b2009-02-03 03:37:03 +00001528 def test_abc(self):
Benjamin Peterson5c8da862009-06-30 22:57:08 +00001529 self.assertTrue(issubclass(Decimal, numbers.Number))
1530 self.assertTrue(not issubclass(Decimal, numbers.Real))
Ezio Melottib0f5adc2010-01-24 16:58:36 +00001531 self.assertIsInstance(Decimal(0), numbers.Number)
Benjamin Peterson5c8da862009-06-30 22:57:08 +00001532 self.assertTrue(not isinstance(Decimal(0), numbers.Real))
Raymond Hettinger2c8585b2009-02-03 03:37:03 +00001533
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001534 def test_pickle(self):
1535 d = Decimal('-3.141590000')
1536 p = pickle.dumps(d)
1537 e = pickle.loads(p)
1538 self.assertEqual(d, e)
1539
Raymond Hettinger5548be22004-07-05 18:49:38 +00001540 def test_int(self):
Raymond Hettinger605ed022004-11-24 07:28:48 +00001541 for x in range(-250, 250):
1542 s = '%0.2f' % (x / 100.0)
Raymond Hettinger5548be22004-07-05 18:49:38 +00001543 # should work the same as for floats
1544 self.assertEqual(int(Decimal(s)), int(float(s)))
Raymond Hettinger605ed022004-11-24 07:28:48 +00001545 # should work the same as to_integral in the ROUND_DOWN mode
Raymond Hettinger5548be22004-07-05 18:49:38 +00001546 d = Decimal(s)
Raymond Hettinger605ed022004-11-24 07:28:48 +00001547 r = d.to_integral(ROUND_DOWN)
Raymond Hettinger5548be22004-07-05 18:49:38 +00001548 self.assertEqual(Decimal(int(d)), r)
1549
Mark Dickinson968f1692009-09-07 18:04:58 +00001550 self.assertRaises(ValueError, int, Decimal('-nan'))
1551 self.assertRaises(ValueError, int, Decimal('snan'))
1552 self.assertRaises(OverflowError, int, Decimal('inf'))
1553 self.assertRaises(OverflowError, int, Decimal('-inf'))
1554
1555 self.assertRaises(ValueError, long, Decimal('-nan'))
1556 self.assertRaises(ValueError, long, Decimal('snan'))
1557 self.assertRaises(OverflowError, long, Decimal('inf'))
1558 self.assertRaises(OverflowError, long, Decimal('-inf'))
1559
Raymond Hettinger5a053642008-01-24 19:05:29 +00001560 def test_trunc(self):
1561 for x in range(-250, 250):
1562 s = '%0.2f' % (x / 100.0)
1563 # should work the same as for floats
1564 self.assertEqual(int(Decimal(s)), int(float(s)))
1565 # should work the same as to_integral in the ROUND_DOWN mode
1566 d = Decimal(s)
1567 r = d.to_integral(ROUND_DOWN)
Jeffrey Yasskinca2b69f2008-02-01 06:22:46 +00001568 self.assertEqual(Decimal(math.trunc(d)), r)
Raymond Hettinger5a053642008-01-24 19:05:29 +00001569
Raymond Hettingerf4d85972009-01-03 19:02:23 +00001570 def test_from_float(self):
1571
1572 class MyDecimal(Decimal):
1573 pass
1574
1575 r = MyDecimal.from_float(0.1)
1576 self.assertEqual(type(r), MyDecimal)
1577 self.assertEqual(str(r),
1578 '0.1000000000000000055511151231257827021181583404541015625')
1579 bigint = 12345678901234567890123456789
1580 self.assertEqual(MyDecimal.from_float(bigint), MyDecimal(bigint))
Benjamin Peterson5c8da862009-06-30 22:57:08 +00001581 self.assertTrue(MyDecimal.from_float(float('nan')).is_qnan())
1582 self.assertTrue(MyDecimal.from_float(float('inf')).is_infinite())
1583 self.assertTrue(MyDecimal.from_float(float('-inf')).is_infinite())
Raymond Hettingerf4d85972009-01-03 19:02:23 +00001584 self.assertEqual(str(MyDecimal.from_float(float('nan'))),
1585 str(Decimal('NaN')))
1586 self.assertEqual(str(MyDecimal.from_float(float('inf'))),
1587 str(Decimal('Infinity')))
1588 self.assertEqual(str(MyDecimal.from_float(float('-inf'))),
1589 str(Decimal('-Infinity')))
1590 self.assertRaises(TypeError, MyDecimal.from_float, 'abc')
1591 for i in range(200):
1592 x = random.expovariate(0.01) * (random.random() * 2.0 - 1.0)
1593 self.assertEqual(x, float(MyDecimal.from_float(x))) # roundtrip
1594
1595 def test_create_decimal_from_float(self):
1596 context = Context(prec=5, rounding=ROUND_DOWN)
1597 self.assertEqual(
1598 context.create_decimal_from_float(math.pi),
1599 Decimal('3.1415')
1600 )
1601 context = Context(prec=5, rounding=ROUND_UP)
1602 self.assertEqual(
1603 context.create_decimal_from_float(math.pi),
1604 Decimal('3.1416')
1605 )
1606 context = Context(prec=5, traps=[Inexact])
1607 self.assertRaises(
1608 Inexact,
1609 context.create_decimal_from_float,
1610 math.pi
1611 )
1612 self.assertEqual(repr(context.create_decimal_from_float(-0.0)),
1613 "Decimal('-0')")
1614 self.assertEqual(repr(context.create_decimal_from_float(1.0)),
1615 "Decimal('1')")
1616 self.assertEqual(repr(context.create_decimal_from_float(10)),
1617 "Decimal('10')")
1618
Raymond Hettingerd9c0a7a2004-07-03 10:02:28 +00001619class ContextAPItests(unittest.TestCase):
1620
1621 def test_pickle(self):
1622 c = Context()
1623 e = pickle.loads(pickle.dumps(c))
1624 for k in vars(c):
1625 v1 = vars(c)[k]
1626 v2 = vars(e)[k]
1627 self.assertEqual(v1, v2)
1628
Raymond Hettinger0aeac102004-07-05 22:53:03 +00001629 def test_equality_with_other_types(self):
Ezio Melottiaa980582010-01-23 23:04:36 +00001630 self.assertIn(Decimal(10), ['a', 1.0, Decimal(10), (1,2), {}])
1631 self.assertNotIn(Decimal(10), ['a', 1.0, (1,2), {}])
Raymond Hettinger0aeac102004-07-05 22:53:03 +00001632
Raymond Hettinger955d2b22004-08-08 20:17:45 +00001633 def test_copy(self):
1634 # All copies should be deep
1635 c = Context()
1636 d = c.copy()
1637 self.assertNotEqual(id(c), id(d))
1638 self.assertNotEqual(id(c.flags), id(d.flags))
1639 self.assertNotEqual(id(c.traps), id(d.traps))
1640
Nick Coghlan8b6999b2006-08-31 12:00:43 +00001641class WithStatementTest(unittest.TestCase):
1642 # Can't do these as docstrings until Python 2.6
1643 # as doctest can't handle __future__ statements
Nick Coghlan8b6999b2006-08-31 12:00:43 +00001644
1645 def test_localcontext(self):
Nick Coghlanced12182006-09-02 03:54:17 +00001646 # Use a copy of the current context in the block
Nick Coghlan8b6999b2006-08-31 12:00:43 +00001647 orig_ctx = getcontext()
1648 with localcontext() as enter_ctx:
1649 set_ctx = getcontext()
1650 final_ctx = getcontext()
Benjamin Peterson5c8da862009-06-30 22:57:08 +00001651 self.assertTrue(orig_ctx is final_ctx, 'did not restore context correctly')
1652 self.assertTrue(orig_ctx is not set_ctx, 'did not copy the context')
1653 self.assertTrue(set_ctx is enter_ctx, '__enter__ returned wrong context')
Nick Coghlan8b6999b2006-08-31 12:00:43 +00001654
1655 def test_localcontextarg(self):
Nick Coghlanced12182006-09-02 03:54:17 +00001656 # Use a copy of the supplied context in the block
Nick Coghlan8b6999b2006-08-31 12:00:43 +00001657 orig_ctx = getcontext()
1658 new_ctx = Context(prec=42)
1659 with localcontext(new_ctx) as enter_ctx:
1660 set_ctx = getcontext()
1661 final_ctx = getcontext()
Benjamin Peterson5c8da862009-06-30 22:57:08 +00001662 self.assertTrue(orig_ctx is final_ctx, 'did not restore context correctly')
1663 self.assertTrue(set_ctx.prec == new_ctx.prec, 'did not set correct context')
1664 self.assertTrue(new_ctx is not set_ctx, 'did not copy the context')
1665 self.assertTrue(set_ctx is enter_ctx, '__enter__ returned wrong context')
Nick Coghlan8b6999b2006-08-31 12:00:43 +00001666
Facundo Batista353750c2007-09-13 18:13:15 +00001667class ContextFlags(unittest.TestCase):
1668 def test_flags_irrelevant(self):
1669 # check that the result (numeric result + flags raised) of an
1670 # arithmetic operation doesn't depend on the current flags
1671
1672 context = Context(prec=9, Emin = -999999999, Emax = 999999999,
1673 rounding=ROUND_HALF_EVEN, traps=[], flags=[])
1674
1675 # operations that raise various flags, in the form (function, arglist)
1676 operations = [
1677 (context._apply, [Decimal("100E-1000000009")]),
1678 (context.sqrt, [Decimal(2)]),
1679 (context.add, [Decimal("1.23456789"), Decimal("9.87654321")]),
1680 (context.multiply, [Decimal("1.23456789"), Decimal("9.87654321")]),
1681 (context.subtract, [Decimal("1.23456789"), Decimal("9.87654321")]),
1682 ]
1683
1684 # try various flags individually, then a whole lot at once
1685 flagsets = [[Inexact], [Rounded], [Underflow], [Clamped], [Subnormal],
1686 [Inexact, Rounded, Underflow, Clamped, Subnormal]]
1687
1688 for fn, args in operations:
1689 # find answer and flags raised using a clean context
1690 context.clear_flags()
1691 ans = fn(*args)
1692 flags = [k for k, v in context.flags.items() if v]
1693
1694 for extra_flags in flagsets:
1695 # set flags, before calling operation
1696 context.clear_flags()
1697 for flag in extra_flags:
1698 context._raise_error(flag)
1699 new_ans = fn(*args)
1700
1701 # flags that we expect to be set after the operation
1702 expected_flags = list(flags)
1703 for flag in extra_flags:
1704 if flag not in expected_flags:
1705 expected_flags.append(flag)
Senthil Kumarance8e33a2010-01-08 19:04:16 +00001706 expected_flags.sort()
Facundo Batista353750c2007-09-13 18:13:15 +00001707
1708 # flags we actually got
1709 new_flags = [k for k,v in context.flags.items() if v]
Senthil Kumarance8e33a2010-01-08 19:04:16 +00001710 new_flags.sort()
Facundo Batista353750c2007-09-13 18:13:15 +00001711
1712 self.assertEqual(ans, new_ans,
1713 "operation produces different answers depending on flags set: " +
1714 "expected %s, got %s." % (ans, new_ans))
1715 self.assertEqual(new_flags, expected_flags,
1716 "operation raises different flags depending on flags set: " +
1717 "expected %s, got %s" % (expected_flags, new_flags))
1718
1719def test_main(arith=False, verbose=None, todo_tests=None, debug=None):
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001720 """ Execute the tests.
1721
Raymond Hettingered20ad82004-09-04 20:09:13 +00001722 Runs all arithmetic tests if arith is True or if the "decimal" resource
1723 is enabled in regrtest.py
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001724 """
Raymond Hettingered20ad82004-09-04 20:09:13 +00001725
Neal Norwitzce4a9c92006-04-09 08:36:46 +00001726 init()
Facundo Batista353750c2007-09-13 18:13:15 +00001727 global TEST_ALL, DEBUG
Raymond Hettingered20ad82004-09-04 20:09:13 +00001728 TEST_ALL = arith or is_resource_enabled('decimal')
Facundo Batista353750c2007-09-13 18:13:15 +00001729 DEBUG = debug
Raymond Hettingered20ad82004-09-04 20:09:13 +00001730
Facundo Batista353750c2007-09-13 18:13:15 +00001731 if todo_tests is None:
1732 test_classes = [
1733 DecimalExplicitConstructionTest,
1734 DecimalImplicitConstructionTest,
1735 DecimalArithmeticOperatorsTest,
Mark Dickinson1ddf1d82008-02-29 02:16:37 +00001736 DecimalFormatTest,
Facundo Batista353750c2007-09-13 18:13:15 +00001737 DecimalUseOfContextTest,
1738 DecimalUsabilityTest,
1739 DecimalPythonAPItests,
1740 ContextAPItests,
1741 DecimalTest,
1742 WithStatementTest,
1743 ContextFlags
1744 ]
1745 else:
1746 test_classes = [DecimalTest]
1747
1748 # Dynamically build custom test definition for each file in the test
1749 # directory and add the definitions to the DecimalTest class. This
1750 # procedure insures that new files do not get skipped.
1751 for filename in os.listdir(directory):
1752 if '.decTest' not in filename or filename.startswith("."):
1753 continue
1754 head, tail = filename.split('.')
1755 if todo_tests is not None and head not in todo_tests:
1756 continue
1757 tester = lambda self, f=filename: self.eval_file(directory + f)
1758 setattr(DecimalTest, 'test_' + head, tester)
1759 del filename, head, tail, tester
1760
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001761
Tim Peters46cc7022006-03-31 04:11:16 +00001762 try:
1763 run_unittest(*test_classes)
Facundo Batista353750c2007-09-13 18:13:15 +00001764 if todo_tests is None:
1765 import decimal as DecimalModule
1766 run_doctest(DecimalModule, verbose)
Tim Peters46cc7022006-03-31 04:11:16 +00001767 finally:
1768 setcontext(ORIGINAL_CONTEXT)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001769
1770if __name__ == '__main__':
Facundo Batista353750c2007-09-13 18:13:15 +00001771 import optparse
1772 p = optparse.OptionParser("test_decimal.py [--debug] [{--skip | test1 [test2 [...]]}]")
1773 p.add_option('--debug', '-d', action='store_true', help='shows the test number and context before each test')
1774 p.add_option('--skip', '-s', action='store_true', help='skip over 90% of the arithmetic tests')
1775 (opt, args) = p.parse_args()
1776
1777 if opt.skip:
1778 test_main(arith=False, verbose=True)
1779 elif args:
1780 test_main(arith=True, verbose=True, todo_tests=args, debug=opt.debug)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001781 else:
Facundo Batista353750c2007-09-13 18:13:15 +00001782 test_main(arith=True, verbose=True)