blob: ddc5ac52e6bbbf1132aa8e2146bb8ecfa16e7f57 [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
Mark Dickinson539bff42009-10-08 16:28:39 +000066# list of individual .decTest test ids that correspond to tests that
67# we're skipping for one reason or another.
68skipped_test_ids = [
69 'scbx164', # skipping apparently implementation-specific scaleb
70 'scbx165', # tests, pending clarification of scaleb rules.
71]
72
Raymond Hettinger7c85fa42004-07-01 11:01:35 +000073# Make sure it actually raises errors when not expected and caught in flags
74# Slower, since it runs some things several times.
75EXTENDEDERRORTEST = False
76
Raymond Hettinger7c85fa42004-07-01 11:01:35 +000077#Map the test cases' error names to the actual errors
Raymond Hettinger7c85fa42004-07-01 11:01:35 +000078ErrorNames = {'clamped' : Clamped,
Raymond Hettinger5aa478b2004-07-09 10:02:53 +000079 'conversion_syntax' : InvalidOperation,
Raymond Hettinger7c85fa42004-07-01 11:01:35 +000080 'division_by_zero' : DivisionByZero,
Raymond Hettinger5aa478b2004-07-09 10:02:53 +000081 'division_impossible' : InvalidOperation,
82 'division_undefined' : InvalidOperation,
Raymond Hettinger7c85fa42004-07-01 11:01:35 +000083 'inexact' : Inexact,
Raymond Hettinger5aa478b2004-07-09 10:02:53 +000084 'invalid_context' : InvalidOperation,
Raymond Hettinger7c85fa42004-07-01 11:01:35 +000085 'invalid_operation' : InvalidOperation,
86 'overflow' : Overflow,
87 'rounded' : Rounded,
88 'subnormal' : Subnormal,
89 'underflow' : Underflow}
90
91
92def Nonfunction(*args):
93 """Doesn't do anything."""
94 return None
95
96RoundingDict = {'ceiling' : ROUND_CEILING, #Maps test-case names to roundings.
97 'down' : ROUND_DOWN,
98 'floor' : ROUND_FLOOR,
99 'half_down' : ROUND_HALF_DOWN,
100 'half_even' : ROUND_HALF_EVEN,
101 'half_up' : ROUND_HALF_UP,
Facundo Batista353750c2007-09-13 18:13:15 +0000102 'up' : ROUND_UP,
103 '05up' : ROUND_05UP}
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000104
105# Name adapter to be able to change the Decimal and Context
106# interface without changing the test files from Cowlishaw
Facundo Batista1a191df2007-10-02 17:01:24 +0000107nameAdapter = {'and':'logical_and',
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000108 'apply':'_apply',
Facundo Batista353750c2007-09-13 18:13:15 +0000109 'class':'number_class',
110 'comparesig':'compare_signal',
111 'comparetotal':'compare_total',
112 'comparetotmag':'compare_total_mag',
Facundo Batista353750c2007-09-13 18:13:15 +0000113 'copy':'copy_decimal',
Facundo Batista1a191df2007-10-02 17:01:24 +0000114 'copyabs':'copy_abs',
Facundo Batista353750c2007-09-13 18:13:15 +0000115 'copynegate':'copy_negate',
116 'copysign':'copy_sign',
Facundo Batista1a191df2007-10-02 17:01:24 +0000117 'divideint':'divide_int',
Facundo Batista353750c2007-09-13 18:13:15 +0000118 'invert':'logical_invert',
Facundo Batista1a191df2007-10-02 17:01:24 +0000119 'iscanonical':'is_canonical',
120 'isfinite':'is_finite',
121 'isinfinite':'is_infinite',
122 'isnan':'is_nan',
123 'isnormal':'is_normal',
124 'isqnan':'is_qnan',
125 'issigned':'is_signed',
126 'issnan':'is_snan',
127 'issubnormal':'is_subnormal',
128 'iszero':'is_zero',
Facundo Batista353750c2007-09-13 18:13:15 +0000129 'maxmag':'max_mag',
130 'minmag':'min_mag',
131 'nextminus':'next_minus',
132 'nextplus':'next_plus',
133 'nexttoward':'next_toward',
Facundo Batista1a191df2007-10-02 17:01:24 +0000134 'or':'logical_or',
Facundo Batista353750c2007-09-13 18:13:15 +0000135 'reduce':'normalize',
Facundo Batista1a191df2007-10-02 17:01:24 +0000136 'remaindernear':'remainder_near',
137 'samequantum':'same_quantum',
138 'squareroot':'sqrt',
139 'toeng':'to_eng_string',
140 'tointegral':'to_integral_value',
141 'tointegralx':'to_integral_exact',
142 'tosci':'to_sci_string',
143 'xor':'logical_xor',
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000144 }
145
Facundo Batista1a191df2007-10-02 17:01:24 +0000146# The following functions return True/False rather than a Decimal instance
147
148LOGICAL_FUNCTIONS = (
149 'is_canonical',
150 'is_finite',
151 'is_infinite',
152 'is_nan',
153 'is_normal',
154 'is_qnan',
155 'is_signed',
156 'is_snan',
157 'is_subnormal',
158 'is_zero',
159 'same_quantum',
160 )
161
Facundo Batista353750c2007-09-13 18:13:15 +0000162# For some operations (currently exp, ln, log10, power), the decNumber
163# reference implementation imposes additional restrictions on the
164# context and operands. These restrictions are not part of the
165# specification; however, the effect of these restrictions does show
166# up in some of the testcases. We skip testcases that violate these
167# restrictions, since Decimal behaves differently from decNumber for
168# these testcases so these testcases would otherwise fail.
169
170decNumberRestricted = ('power', 'ln', 'log10', 'exp')
171DEC_MAX_MATH = 999999
172def outside_decNumber_bounds(v, context):
173 if (context.prec > DEC_MAX_MATH or
174 context.Emax > DEC_MAX_MATH or
175 -context.Emin > DEC_MAX_MATH):
176 return True
177 if not v._is_special and v and (
Facundo Batista353750c2007-09-13 18:13:15 +0000178 v.adjusted() > DEC_MAX_MATH or
179 v.adjusted() < 1-2*DEC_MAX_MATH):
180 return True
181 return False
182
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000183class DecimalTest(unittest.TestCase):
184 """Class which tests the Decimal class against the test cases.
185
186 Changed for unittest.
187 """
188 def setUp(self):
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000189 self.context = Context()
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000190 self.ignore_list = ['#']
191 # Basically, a # means return NaN InvalidOperation.
192 # Different from a sNaN in trim
193
194 self.ChangeDict = {'precision' : self.change_precision,
195 'rounding' : self.change_rounding_method,
196 'maxexponent' : self.change_max_exponent,
197 'minexponent' : self.change_min_exponent,
198 'clamp' : self.change_clamp}
199
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000200 def eval_file(self, file):
201 global skip_expected
202 if skip_expected:
Benjamin Petersonbec087f2009-03-26 21:10:30 +0000203 raise unittest.SkipTest
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000204 return
205 for line in open(file).xreadlines():
206 line = line.replace('\r\n', '').replace('\n', '')
Raymond Hettinger5aa478b2004-07-09 10:02:53 +0000207 #print line
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000208 try:
209 t = self.eval_line(line)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000210 except DecimalException, exception:
211 #Exception raised where there shoudn't have been one.
212 self.fail('Exception "'+exception.__class__.__name__ + '" raised on line '+line)
213
214 return
215
216 def eval_line(self, s):
217 if s.find(' -> ') >= 0 and s[:2] != '--' and not s.startswith(' --'):
218 s = (s.split('->')[0] + '->' +
219 s.split('->')[1].split('--')[0]).strip()
220 else:
221 s = s.split('--')[0].strip()
222
223 for ignore in self.ignore_list:
224 if s.find(ignore) >= 0:
225 #print s.split()[0], 'NotImplemented--', ignore
226 return
227 if not s:
228 return
229 elif ':' in s:
230 return self.eval_directive(s)
231 else:
232 return self.eval_equation(s)
233
234 def eval_directive(self, s):
235 funct, value = map(lambda x: x.strip().lower(), s.split(':'))
236 if funct == 'rounding':
237 value = RoundingDict[value]
238 else:
239 try:
240 value = int(value)
241 except ValueError:
242 pass
243
244 funct = self.ChangeDict.get(funct, Nonfunction)
245 funct(value)
246
247 def eval_equation(self, s):
248 #global DEFAULT_PRECISION
249 #print DEFAULT_PRECISION
Raymond Hettingered20ad82004-09-04 20:09:13 +0000250
251 if not TEST_ALL and random.random() < 0.90:
252 return
253
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000254 try:
255 Sides = s.split('->')
256 L = Sides[0].strip().split()
257 id = L[0]
Facundo Batista353750c2007-09-13 18:13:15 +0000258 if DEBUG:
259 print "Test ", id,
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000260 funct = L[1].lower()
261 valstemp = L[2:]
262 L = Sides[1].strip().split()
263 ans = L[0]
264 exceptions = L[1:]
265 except (TypeError, AttributeError, IndexError):
Raymond Hettingerd87ac8f2004-07-09 10:52:54 +0000266 raise InvalidOperation
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000267 def FixQuotes(val):
268 val = val.replace("''", 'SingleQuote').replace('""', 'DoubleQuote')
269 val = val.replace("'", '').replace('"', '')
270 val = val.replace('SingleQuote', "'").replace('DoubleQuote', '"')
271 return val
Mark Dickinson539bff42009-10-08 16:28:39 +0000272
273 if id in skipped_test_ids:
274 return
275
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000276 fname = nameAdapter.get(funct, funct)
277 if fname == 'rescale':
278 return
279 funct = getattr(self.context, fname)
280 vals = []
281 conglomerate = ''
282 quote = 0
283 theirexceptions = [ErrorNames[x.lower()] for x in exceptions]
284
Raymond Hettingerd9c0a7a2004-07-03 10:02:28 +0000285 for exception in Signals:
Raymond Hettingerbf440692004-07-10 14:14:37 +0000286 self.context.traps[exception] = 1 #Catch these bugs...
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000287 for exception in theirexceptions:
Raymond Hettingerbf440692004-07-10 14:14:37 +0000288 self.context.traps[exception] = 0
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000289 for i, val in enumerate(valstemp):
290 if val.count("'") % 2 == 1:
291 quote = 1 - quote
292 if quote:
293 conglomerate = conglomerate + ' ' + val
294 continue
295 else:
296 val = conglomerate + val
297 conglomerate = ''
298 v = FixQuotes(val)
299 if fname in ('to_sci_string', 'to_eng_string'):
300 if EXTENDEDERRORTEST:
301 for error in theirexceptions:
Raymond Hettingerbf440692004-07-10 14:14:37 +0000302 self.context.traps[error] = 1
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000303 try:
304 funct(self.context.create_decimal(v))
305 except error:
306 pass
Raymond Hettingerd9c0a7a2004-07-03 10:02:28 +0000307 except Signals, e:
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000308 self.fail("Raised %s in %s when %s disabled" % \
309 (e, s, error))
310 else:
311 self.fail("Did not raise %s in %s" % (error, s))
Raymond Hettingerbf440692004-07-10 14:14:37 +0000312 self.context.traps[error] = 0
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000313 v = self.context.create_decimal(v)
314 else:
Facundo Batista353750c2007-09-13 18:13:15 +0000315 v = Decimal(v, self.context)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000316 vals.append(v)
317
318 ans = FixQuotes(ans)
319
Facundo Batista353750c2007-09-13 18:13:15 +0000320 # skip tests that are related to bounds imposed in the decNumber
321 # reference implementation
322 if fname in decNumberRestricted:
323 if fname == 'power':
324 if not (vals[1]._isinteger() and
325 -1999999997 <= vals[1] <= 999999999):
326 if outside_decNumber_bounds(vals[0], self.context) or \
327 outside_decNumber_bounds(vals[1], self.context):
328 #print "Skipping test %s" % s
329 return
330 else:
331 if outside_decNumber_bounds(vals[0], self.context):
332 #print "Skipping test %s" % s
333 return
334
335
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000336 if EXTENDEDERRORTEST and fname not in ('to_sci_string', 'to_eng_string'):
337 for error in theirexceptions:
Raymond Hettingerbf440692004-07-10 14:14:37 +0000338 self.context.traps[error] = 1
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000339 try:
340 funct(*vals)
341 except error:
342 pass
Raymond Hettingerd9c0a7a2004-07-03 10:02:28 +0000343 except Signals, e:
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000344 self.fail("Raised %s in %s when %s disabled" % \
345 (e, s, error))
346 else:
347 self.fail("Did not raise %s in %s" % (error, s))
Raymond Hettingerbf440692004-07-10 14:14:37 +0000348 self.context.traps[error] = 0
Facundo Batista353750c2007-09-13 18:13:15 +0000349 if DEBUG:
350 print "--", self.context
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000351 try:
352 result = str(funct(*vals))
Facundo Batista1a191df2007-10-02 17:01:24 +0000353 if fname in LOGICAL_FUNCTIONS:
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000354 result = str(int(eval(result))) # 'True', 'False' -> '1', '0'
Raymond Hettingerd9c0a7a2004-07-03 10:02:28 +0000355 except Signals, error:
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000356 self.fail("Raised %s in %s" % (error, s))
357 except: #Catch any error long enough to state the test case.
358 print "ERROR:", s
359 raise
360
361 myexceptions = self.getexceptions()
Raymond Hettingerbf440692004-07-10 14:14:37 +0000362 self.context.clear_flags()
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000363
364 myexceptions.sort()
365 theirexceptions.sort()
366
367 self.assertEqual(result, ans,
368 'Incorrect answer for ' + s + ' -- got ' + result)
369 self.assertEqual(myexceptions, theirexceptions,
Facundo Batista353750c2007-09-13 18:13:15 +0000370 'Incorrect flags set in ' + s + ' -- got ' + str(myexceptions))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000371 return
372
373 def getexceptions(self):
Raymond Hettingerf63ba432004-08-17 05:42:09 +0000374 return [e for e in Signals if self.context.flags[e]]
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000375
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000376 def change_precision(self, prec):
377 self.context.prec = prec
378 def change_rounding_method(self, rounding):
379 self.context.rounding = rounding
380 def change_min_exponent(self, exp):
381 self.context.Emin = exp
382 def change_max_exponent(self, exp):
383 self.context.Emax = exp
384 def change_clamp(self, clamp):
385 self.context._clamp = clamp
386
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000387
388
389# The following classes test the behaviour of Decimal according to PEP 327
390
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000391class DecimalExplicitConstructionTest(unittest.TestCase):
392 '''Unit tests for Explicit Construction cases of Decimal.'''
393
394 def test_explicit_empty(self):
395 self.assertEqual(Decimal(), Decimal("0"))
396
397 def test_explicit_from_None(self):
398 self.assertRaises(TypeError, Decimal, None)
399
400 def test_explicit_from_int(self):
401
402 #positive
403 d = Decimal(45)
404 self.assertEqual(str(d), '45')
405
406 #very large positive
407 d = Decimal(500000123)
408 self.assertEqual(str(d), '500000123')
409
410 #negative
411 d = Decimal(-45)
412 self.assertEqual(str(d), '-45')
413
414 #zero
415 d = Decimal(0)
416 self.assertEqual(str(d), '0')
417
418 def test_explicit_from_string(self):
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000419
420 #empty
421 self.assertEqual(str(Decimal('')), 'NaN')
422
423 #int
424 self.assertEqual(str(Decimal('45')), '45')
425
426 #float
427 self.assertEqual(str(Decimal('45.34')), '45.34')
428
429 #engineer notation
430 self.assertEqual(str(Decimal('45e2')), '4.5E+3')
431
432 #just not a number
433 self.assertEqual(str(Decimal('ugly')), 'NaN')
434
Mark Dickinson59bc20b2008-01-12 01:56:00 +0000435 #leading and trailing whitespace permitted
436 self.assertEqual(str(Decimal('1.3E4 \n')), '1.3E+4')
437 self.assertEqual(str(Decimal(' -7.89')), '-7.89')
438
Mark Dickinson8e85ffa2008-03-25 18:47:59 +0000439 #unicode strings should be permitted
440 self.assertEqual(str(Decimal(u'0E-017')), '0E-17')
441 self.assertEqual(str(Decimal(u'45')), '45')
442 self.assertEqual(str(Decimal(u'-Inf')), '-Infinity')
443 self.assertEqual(str(Decimal(u'NaN123')), 'NaN123')
444
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000445 def test_explicit_from_tuples(self):
446
447 #zero
448 d = Decimal( (0, (0,), 0) )
449 self.assertEqual(str(d), '0')
450
451 #int
452 d = Decimal( (1, (4, 5), 0) )
453 self.assertEqual(str(d), '-45')
454
455 #float
456 d = Decimal( (0, (4, 5, 3, 4), -2) )
457 self.assertEqual(str(d), '45.34')
458
459 #weird
460 d = Decimal( (1, (4, 3, 4, 9, 1, 3, 5, 3, 4), -25) )
461 self.assertEqual(str(d), '-4.34913534E-17')
462
463 #wrong number of items
464 self.assertRaises(ValueError, Decimal, (1, (4, 3, 4, 9, 1)) )
465
466 #bad sign
467 self.assertRaises(ValueError, Decimal, (8, (4, 3, 4, 9, 1), 2) )
Facundo Batista9b5e2312007-10-19 19:25:57 +0000468 self.assertRaises(ValueError, Decimal, (0., (4, 3, 4, 9, 1), 2) )
469 self.assertRaises(ValueError, Decimal, (Decimal(1), (4, 3, 4, 9, 1), 2))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000470
471 #bad exp
472 self.assertRaises(ValueError, Decimal, (1, (4, 3, 4, 9, 1), 'wrong!') )
Facundo Batista9b5e2312007-10-19 19:25:57 +0000473 self.assertRaises(ValueError, Decimal, (1, (4, 3, 4, 9, 1), 0.) )
474 self.assertRaises(ValueError, Decimal, (1, (4, 3, 4, 9, 1), '1') )
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000475
476 #bad coefficients
477 self.assertRaises(ValueError, Decimal, (1, (4, 3, 4, None, 1), 2) )
478 self.assertRaises(ValueError, Decimal, (1, (4, -3, 4, 9, 1), 2) )
Facundo Batista9b5e2312007-10-19 19:25:57 +0000479 self.assertRaises(ValueError, Decimal, (1, (4, 10, 4, 9, 1), 2) )
Facundo Batista72bc54f2007-11-23 17:59:00 +0000480 self.assertRaises(ValueError, Decimal, (1, (4, 3, 4, 'a', 1), 2) )
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000481
482 def test_explicit_from_Decimal(self):
483
484 #positive
485 d = Decimal(45)
486 e = Decimal(d)
487 self.assertEqual(str(e), '45')
488 self.assertNotEqual(id(d), id(e))
489
490 #very large positive
491 d = Decimal(500000123)
492 e = Decimal(d)
493 self.assertEqual(str(e), '500000123')
494 self.assertNotEqual(id(d), id(e))
495
496 #negative
497 d = Decimal(-45)
498 e = Decimal(d)
499 self.assertEqual(str(e), '-45')
500 self.assertNotEqual(id(d), id(e))
501
502 #zero
503 d = Decimal(0)
504 e = Decimal(d)
505 self.assertEqual(str(e), '0')
506 self.assertNotEqual(id(d), id(e))
507
508 def test_explicit_context_create_decimal(self):
509
510 nc = copy.copy(getcontext())
511 nc.prec = 3
512
513 # empty
Raymond Hettingerfed52962004-07-14 15:41:57 +0000514 d = Decimal()
515 self.assertEqual(str(d), '0')
516 d = nc.create_decimal()
517 self.assertEqual(str(d), '0')
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000518
519 # from None
520 self.assertRaises(TypeError, nc.create_decimal, None)
521
522 # from int
523 d = nc.create_decimal(456)
Benjamin Peterson5c8da862009-06-30 22:57:08 +0000524 self.assertTrue(isinstance(d, Decimal))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000525 self.assertEqual(nc.create_decimal(45678),
526 nc.create_decimal('457E+2'))
527
528 # from string
529 d = Decimal('456789')
530 self.assertEqual(str(d), '456789')
531 d = nc.create_decimal('456789')
532 self.assertEqual(str(d), '4.57E+5')
Mark Dickinson59bc20b2008-01-12 01:56:00 +0000533 # leading and trailing whitespace should result in a NaN;
534 # spaces are already checked in Cowlishaw's test-suite, so
535 # here we just check that a trailing newline results in a NaN
536 self.assertEqual(str(nc.create_decimal('3.14\n')), 'NaN')
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000537
538 # from tuples
539 d = Decimal( (1, (4, 3, 4, 9, 1, 3, 5, 3, 4), -25) )
540 self.assertEqual(str(d), '-4.34913534E-17')
541 d = nc.create_decimal( (1, (4, 3, 4, 9, 1, 3, 5, 3, 4), -25) )
542 self.assertEqual(str(d), '-4.35E-17')
543
544 # from Decimal
545 prevdec = Decimal(500000123)
546 d = Decimal(prevdec)
547 self.assertEqual(str(d), '500000123')
548 d = nc.create_decimal(prevdec)
549 self.assertEqual(str(d), '5.00E+8')
550
Mark Dickinson4326ad82009-08-02 10:59:36 +0000551 def test_unicode_digits(self):
552 test_values = {
553 u'\uff11': '1',
554 u'\u0660.\u0660\u0663\u0667\u0662e-\u0663' : '0.0000372',
555 u'-nan\u0c68\u0c6a\u0c66\u0c66' : '-NaN2400',
556 }
557 for input, expected in test_values.items():
558 self.assertEqual(str(Decimal(input)), expected)
559
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000560
561class DecimalImplicitConstructionTest(unittest.TestCase):
562 '''Unit tests for Implicit Construction cases of Decimal.'''
563
564 def test_implicit_from_None(self):
565 self.assertRaises(TypeError, eval, 'Decimal(5) + None', globals())
566
567 def test_implicit_from_int(self):
568 #normal
569 self.assertEqual(str(Decimal(5) + 45), '50')
570 #exceeding precision
571 self.assertEqual(Decimal(5) + 123456789000, Decimal(123456789000))
572
573 def test_implicit_from_string(self):
574 self.assertRaises(TypeError, eval, 'Decimal(5) + "3"', globals())
575
576 def test_implicit_from_float(self):
577 self.assertRaises(TypeError, eval, 'Decimal(5) + 2.2', globals())
578
579 def test_implicit_from_Decimal(self):
580 self.assertEqual(Decimal(5) + Decimal(45), Decimal(50))
581
Raymond Hettinger267b8682005-03-27 10:47:39 +0000582 def test_rop(self):
583 # Allow other classes to be trained to interact with Decimals
584 class E:
585 def __divmod__(self, other):
586 return 'divmod ' + str(other)
587 def __rdivmod__(self, other):
588 return str(other) + ' rdivmod'
589 def __lt__(self, other):
590 return 'lt ' + str(other)
591 def __gt__(self, other):
592 return 'gt ' + str(other)
593 def __le__(self, other):
594 return 'le ' + str(other)
595 def __ge__(self, other):
596 return 'ge ' + str(other)
597 def __eq__(self, other):
598 return 'eq ' + str(other)
599 def __ne__(self, other):
600 return 'ne ' + str(other)
601
602 self.assertEqual(divmod(E(), Decimal(10)), 'divmod 10')
603 self.assertEqual(divmod(Decimal(10), E()), '10 rdivmod')
604 self.assertEqual(eval('Decimal(10) < E()'), 'gt 10')
605 self.assertEqual(eval('Decimal(10) > E()'), 'lt 10')
606 self.assertEqual(eval('Decimal(10) <= E()'), 'ge 10')
607 self.assertEqual(eval('Decimal(10) >= E()'), 'le 10')
608 self.assertEqual(eval('Decimal(10) == E()'), 'eq 10')
609 self.assertEqual(eval('Decimal(10) != E()'), 'ne 10')
610
611 # insert operator methods and then exercise them
Georg Brandl96c3f7f2006-03-28 08:06:35 +0000612 oplist = [
613 ('+', '__add__', '__radd__'),
614 ('-', '__sub__', '__rsub__'),
615 ('*', '__mul__', '__rmul__'),
616 ('%', '__mod__', '__rmod__'),
617 ('//', '__floordiv__', '__rfloordiv__'),
618 ('**', '__pow__', '__rpow__')
619 ]
620 if 1/2 == 0:
621 # testing with classic division, so add __div__
622 oplist.append(('/', '__div__', '__rdiv__'))
623 else:
624 # testing with -Qnew, so add __truediv__
625 oplist.append(('/', '__truediv__', '__rtruediv__'))
Anthony Baxter4ef3a232006-03-30 12:59:11 +0000626
Georg Brandl96c3f7f2006-03-28 08:06:35 +0000627 for sym, lop, rop in oplist:
Raymond Hettinger267b8682005-03-27 10:47:39 +0000628 setattr(E, lop, lambda self, other: 'str' + lop + str(other))
629 setattr(E, rop, lambda self, other: str(other) + rop + 'str')
630 self.assertEqual(eval('E()' + sym + 'Decimal(10)'),
631 'str' + lop + '10')
632 self.assertEqual(eval('Decimal(10)' + sym + 'E()'),
633 '10' + rop + 'str')
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000634
Mark Dickinson277859d2009-03-17 23:03:46 +0000635
Mark Dickinson1ddf1d82008-02-29 02:16:37 +0000636class DecimalFormatTest(unittest.TestCase):
637 '''Unit tests for the format function.'''
638 def test_formatting(self):
639 # triples giving a format, a Decimal, and the expected result
640 test_values = [
641 ('e', '0E-15', '0e-15'),
642 ('e', '2.3E-15', '2.3e-15'),
643 ('e', '2.30E+2', '2.30e+2'), # preserve significant zeros
644 ('e', '2.30000E-15', '2.30000e-15'),
645 ('e', '1.23456789123456789e40', '1.23456789123456789e+40'),
646 ('e', '1.5', '1.5e+0'),
647 ('e', '0.15', '1.5e-1'),
648 ('e', '0.015', '1.5e-2'),
649 ('e', '0.0000000000015', '1.5e-12'),
650 ('e', '15.0', '1.50e+1'),
651 ('e', '-15', '-1.5e+1'),
652 ('e', '0', '0e+0'),
653 ('e', '0E1', '0e+1'),
654 ('e', '0.0', '0e-1'),
655 ('e', '0.00', '0e-2'),
656 ('.6e', '0E-15', '0.000000e-9'),
657 ('.6e', '0', '0.000000e+6'),
658 ('.6e', '9.999999', '9.999999e+0'),
659 ('.6e', '9.9999999', '1.000000e+1'),
660 ('.6e', '-1.23e5', '-1.230000e+5'),
661 ('.6e', '1.23456789e-3', '1.234568e-3'),
662 ('f', '0', '0'),
663 ('f', '0.0', '0.0'),
664 ('f', '0E-2', '0.00'),
665 ('f', '0.00E-8', '0.0000000000'),
666 ('f', '0E1', '0'), # loses exponent information
667 ('f', '3.2E1', '32'),
668 ('f', '3.2E2', '320'),
669 ('f', '3.20E2', '320'),
670 ('f', '3.200E2', '320.0'),
671 ('f', '3.2E-6', '0.0000032'),
672 ('.6f', '0E-15', '0.000000'), # all zeros treated equally
673 ('.6f', '0E1', '0.000000'),
674 ('.6f', '0', '0.000000'),
675 ('.0f', '0', '0'), # no decimal point
676 ('.0f', '0e-2', '0'),
677 ('.0f', '3.14159265', '3'),
678 ('.1f', '3.14159265', '3.1'),
679 ('.4f', '3.14159265', '3.1416'),
680 ('.6f', '3.14159265', '3.141593'),
681 ('.7f', '3.14159265', '3.1415926'), # round-half-even!
682 ('.8f', '3.14159265', '3.14159265'),
683 ('.9f', '3.14159265', '3.141592650'),
684
685 ('g', '0', '0'),
686 ('g', '0.0', '0.0'),
687 ('g', '0E1', '0e+1'),
688 ('G', '0E1', '0E+1'),
689 ('g', '0E-5', '0.00000'),
690 ('g', '0E-6', '0.000000'),
691 ('g', '0E-7', '0e-7'),
692 ('g', '-0E2', '-0e+2'),
693 ('.0g', '3.14159265', '3'), # 0 sig fig -> 1 sig fig
694 ('.1g', '3.14159265', '3'),
695 ('.2g', '3.14159265', '3.1'),
696 ('.5g', '3.14159265', '3.1416'),
697 ('.7g', '3.14159265', '3.141593'),
698 ('.8g', '3.14159265', '3.1415926'), # round-half-even!
699 ('.9g', '3.14159265', '3.14159265'),
700 ('.10g', '3.14159265', '3.14159265'), # don't pad
701
702 ('%', '0E1', '0%'),
703 ('%', '0E0', '0%'),
704 ('%', '0E-1', '0%'),
705 ('%', '0E-2', '0%'),
706 ('%', '0E-3', '0.0%'),
707 ('%', '0E-4', '0.00%'),
708
709 ('.3%', '0', '0.000%'), # all zeros treated equally
710 ('.3%', '0E10', '0.000%'),
711 ('.3%', '0E-10', '0.000%'),
712 ('.3%', '2.34', '234.000%'),
713 ('.3%', '1.234567', '123.457%'),
714 ('.0%', '1.23', '123%'),
715
716 ('e', 'NaN', 'NaN'),
717 ('f', '-NaN123', '-NaN123'),
718 ('+g', 'NaN456', '+NaN456'),
719 ('.3e', 'Inf', 'Infinity'),
720 ('.16f', '-Inf', '-Infinity'),
721 ('.0g', '-sNaN', '-sNaN'),
722
723 ('', '1.00', '1.00'),
Mark Dickinsonb065e522009-03-17 18:01:03 +0000724
Mark Dickinson277859d2009-03-17 23:03:46 +0000725 # test alignment and padding
Mark Dickinson5cfa8042009-09-08 20:20:19 +0000726 ('6', '123', ' 123'),
Mark Dickinsonb065e522009-03-17 18:01:03 +0000727 ('<6', '123', '123 '),
728 ('>6', '123', ' 123'),
729 ('^6', '123', ' 123 '),
730 ('=+6', '123', '+ 123'),
Mark Dickinson277859d2009-03-17 23:03:46 +0000731 ('#<10', 'NaN', 'NaN#######'),
732 ('#<10', '-4.3', '-4.3######'),
733 ('#<+10', '0.0130', '+0.0130###'),
734 ('#< 10', '0.0130', ' 0.0130###'),
735 ('@>10', '-Inf', '@-Infinity'),
736 ('#>5', '-Inf', '-Infinity'),
737 ('?^5', '123', '?123?'),
738 ('%^6', '123', '%123%%'),
739 (' ^6', '-45.6', '-45.6 '),
740 ('/=10', '-45.6', '-/////45.6'),
741 ('/=+10', '45.6', '+/////45.6'),
742 ('/= 10', '45.6', ' /////45.6'),
743
744 # thousands separator
745 (',', '1234567', '1,234,567'),
746 (',', '123456', '123,456'),
747 (',', '12345', '12,345'),
748 (',', '1234', '1,234'),
749 (',', '123', '123'),
750 (',', '12', '12'),
751 (',', '1', '1'),
752 (',', '0', '0'),
753 (',', '-1234567', '-1,234,567'),
754 (',', '-123456', '-123,456'),
755 ('7,', '123456', '123,456'),
Mark Dickinson5cfa8042009-09-08 20:20:19 +0000756 ('8,', '123456', ' 123,456'),
Mark Dickinson277859d2009-03-17 23:03:46 +0000757 ('08,', '123456', '0,123,456'), # special case: extra 0 needed
758 ('+08,', '123456', '+123,456'), # but not if there's a sign
759 (' 08,', '123456', ' 123,456'),
760 ('08,', '-123456', '-123,456'),
761 ('+09,', '123456', '+0,123,456'),
762 # ... with fractional part...
763 ('07,', '1234.56', '1,234.56'),
764 ('08,', '1234.56', '1,234.56'),
765 ('09,', '1234.56', '01,234.56'),
766 ('010,', '1234.56', '001,234.56'),
767 ('011,', '1234.56', '0,001,234.56'),
768 ('012,', '1234.56', '0,001,234.56'),
769 ('08,.1f', '1234.5', '01,234.5'),
770 # no thousands separators in fraction part
771 (',', '1.23456789', '1.23456789'),
772 (',%', '123.456789', '12,345.6789%'),
773 (',e', '123456', '1.23456e+5'),
774 (',E', '123456', '1.23456E+5'),
Mark Dickinson491ea552009-09-07 16:17:41 +0000775
776 # issue 6850
777 ('a=-7.0', '0.12345', 'aaaa0.1'),
Mark Dickinson1ddf1d82008-02-29 02:16:37 +0000778 ]
779 for fmt, d, result in test_values:
780 self.assertEqual(format(Decimal(d), fmt), result)
781
Mark Dickinson277859d2009-03-17 23:03:46 +0000782 def test_n_format(self):
783 try:
784 from locale import CHAR_MAX
785 except ImportError:
786 return
787
788 # Set up some localeconv-like dictionaries
789 en_US = {
790 'decimal_point' : '.',
791 'grouping' : [3, 3, 0],
792 'thousands_sep': ','
793 }
794
795 fr_FR = {
796 'decimal_point' : ',',
797 'grouping' : [CHAR_MAX],
798 'thousands_sep' : ''
799 }
800
801 ru_RU = {
802 'decimal_point' : ',',
803 'grouping' : [3, 3, 0],
804 'thousands_sep' : ' '
805 }
806
807 crazy = {
808 'decimal_point' : '&',
809 'grouping' : [1, 4, 2, CHAR_MAX],
810 'thousands_sep' : '-'
811 }
812
813
814 def get_fmt(x, locale, fmt='n'):
815 return Decimal.__format__(Decimal(x), fmt, _localeconv=locale)
816
817 self.assertEqual(get_fmt(Decimal('12.7'), en_US), '12.7')
818 self.assertEqual(get_fmt(Decimal('12.7'), fr_FR), '12,7')
819 self.assertEqual(get_fmt(Decimal('12.7'), ru_RU), '12,7')
820 self.assertEqual(get_fmt(Decimal('12.7'), crazy), '1-2&7')
821
822 self.assertEqual(get_fmt(123456789, en_US), '123,456,789')
823 self.assertEqual(get_fmt(123456789, fr_FR), '123456789')
824 self.assertEqual(get_fmt(123456789, ru_RU), '123 456 789')
825 self.assertEqual(get_fmt(1234567890123, crazy), '123456-78-9012-3')
826
827 self.assertEqual(get_fmt(123456789, en_US, '.6n'), '1.23457e+8')
828 self.assertEqual(get_fmt(123456789, fr_FR, '.6n'), '1,23457e+8')
829 self.assertEqual(get_fmt(123456789, ru_RU, '.6n'), '1,23457e+8')
830 self.assertEqual(get_fmt(123456789, crazy, '.6n'), '1&23457e+8')
831
Mark Dickinsonb14514a2009-03-18 08:22:51 +0000832 # zero padding
833 self.assertEqual(get_fmt(1234, fr_FR, '03n'), '1234')
834 self.assertEqual(get_fmt(1234, fr_FR, '04n'), '1234')
835 self.assertEqual(get_fmt(1234, fr_FR, '05n'), '01234')
836 self.assertEqual(get_fmt(1234, fr_FR, '06n'), '001234')
837
838 self.assertEqual(get_fmt(12345, en_US, '05n'), '12,345')
839 self.assertEqual(get_fmt(12345, en_US, '06n'), '12,345')
840 self.assertEqual(get_fmt(12345, en_US, '07n'), '012,345')
841 self.assertEqual(get_fmt(12345, en_US, '08n'), '0,012,345')
842 self.assertEqual(get_fmt(12345, en_US, '09n'), '0,012,345')
843 self.assertEqual(get_fmt(12345, en_US, '010n'), '00,012,345')
844
845 self.assertEqual(get_fmt(123456, crazy, '06n'), '1-2345-6')
846 self.assertEqual(get_fmt(123456, crazy, '07n'), '1-2345-6')
847 self.assertEqual(get_fmt(123456, crazy, '08n'), '1-2345-6')
848 self.assertEqual(get_fmt(123456, crazy, '09n'), '01-2345-6')
849 self.assertEqual(get_fmt(123456, crazy, '010n'), '0-01-2345-6')
850 self.assertEqual(get_fmt(123456, crazy, '011n'), '0-01-2345-6')
851 self.assertEqual(get_fmt(123456, crazy, '012n'), '00-01-2345-6')
852 self.assertEqual(get_fmt(123456, crazy, '013n'), '000-01-2345-6')
853
Mark Dickinson277859d2009-03-17 23:03:46 +0000854
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000855class DecimalArithmeticOperatorsTest(unittest.TestCase):
856 '''Unit tests for all arithmetic operators, binary and unary.'''
857
858 def test_addition(self):
859
860 d1 = Decimal('-11.1')
861 d2 = Decimal('22.2')
862
863 #two Decimals
864 self.assertEqual(d1+d2, Decimal('11.1'))
865 self.assertEqual(d2+d1, Decimal('11.1'))
866
867 #with other type, left
868 c = d1 + 5
869 self.assertEqual(c, Decimal('-6.1'))
870 self.assertEqual(type(c), type(d1))
871
872 #with other type, right
873 c = 5 + d1
874 self.assertEqual(c, Decimal('-6.1'))
875 self.assertEqual(type(c), type(d1))
876
877 #inline with decimal
878 d1 += d2
879 self.assertEqual(d1, Decimal('11.1'))
880
881 #inline with other type
882 d1 += 5
883 self.assertEqual(d1, Decimal('16.1'))
884
885 def test_subtraction(self):
886
887 d1 = Decimal('-11.1')
888 d2 = Decimal('22.2')
889
890 #two Decimals
891 self.assertEqual(d1-d2, Decimal('-33.3'))
892 self.assertEqual(d2-d1, Decimal('33.3'))
893
894 #with other type, left
895 c = d1 - 5
896 self.assertEqual(c, Decimal('-16.1'))
897 self.assertEqual(type(c), type(d1))
898
899 #with other type, right
900 c = 5 - d1
901 self.assertEqual(c, Decimal('16.1'))
902 self.assertEqual(type(c), type(d1))
903
904 #inline with decimal
905 d1 -= d2
906 self.assertEqual(d1, Decimal('-33.3'))
907
908 #inline with other type
909 d1 -= 5
910 self.assertEqual(d1, Decimal('-38.3'))
911
912 def test_multiplication(self):
913
914 d1 = Decimal('-5')
915 d2 = Decimal('3')
916
917 #two Decimals
918 self.assertEqual(d1*d2, Decimal('-15'))
919 self.assertEqual(d2*d1, Decimal('-15'))
920
921 #with other type, left
922 c = d1 * 5
923 self.assertEqual(c, Decimal('-25'))
924 self.assertEqual(type(c), type(d1))
925
926 #with other type, right
927 c = 5 * d1
928 self.assertEqual(c, Decimal('-25'))
929 self.assertEqual(type(c), type(d1))
930
931 #inline with decimal
932 d1 *= d2
933 self.assertEqual(d1, Decimal('-15'))
934
935 #inline with other type
936 d1 *= 5
937 self.assertEqual(d1, Decimal('-75'))
938
939 def test_division(self):
940
941 d1 = Decimal('-5')
942 d2 = Decimal('2')
943
944 #two Decimals
945 self.assertEqual(d1/d2, Decimal('-2.5'))
946 self.assertEqual(d2/d1, Decimal('-0.4'))
947
948 #with other type, left
949 c = d1 / 4
950 self.assertEqual(c, Decimal('-1.25'))
951 self.assertEqual(type(c), type(d1))
952
953 #with other type, right
954 c = 4 / d1
955 self.assertEqual(c, Decimal('-0.8'))
956 self.assertEqual(type(c), type(d1))
957
958 #inline with decimal
959 d1 /= d2
960 self.assertEqual(d1, Decimal('-2.5'))
961
962 #inline with other type
963 d1 /= 4
964 self.assertEqual(d1, Decimal('-0.625'))
965
966 def test_floor_division(self):
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000967
968 d1 = Decimal('5')
969 d2 = Decimal('2')
970
971 #two Decimals
972 self.assertEqual(d1//d2, Decimal('2'))
973 self.assertEqual(d2//d1, Decimal('0'))
974
975 #with other type, left
976 c = d1 // 4
977 self.assertEqual(c, Decimal('1'))
978 self.assertEqual(type(c), type(d1))
979
980 #with other type, right
981 c = 7 // d1
982 self.assertEqual(c, Decimal('1'))
983 self.assertEqual(type(c), type(d1))
984
985 #inline with decimal
986 d1 //= d2
987 self.assertEqual(d1, Decimal('2'))
988
989 #inline with other type
990 d1 //= 2
991 self.assertEqual(d1, Decimal('1'))
992
993 def test_powering(self):
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000994
995 d1 = Decimal('5')
996 d2 = Decimal('2')
997
998 #two Decimals
999 self.assertEqual(d1**d2, Decimal('25'))
1000 self.assertEqual(d2**d1, Decimal('32'))
1001
1002 #with other type, left
1003 c = d1 ** 4
1004 self.assertEqual(c, Decimal('625'))
1005 self.assertEqual(type(c), type(d1))
1006
1007 #with other type, right
1008 c = 7 ** d1
1009 self.assertEqual(c, Decimal('16807'))
1010 self.assertEqual(type(c), type(d1))
1011
1012 #inline with decimal
1013 d1 **= d2
1014 self.assertEqual(d1, Decimal('25'))
1015
1016 #inline with other type
1017 d1 **= 4
1018 self.assertEqual(d1, Decimal('390625'))
1019
1020 def test_module(self):
1021
1022 d1 = Decimal('5')
1023 d2 = Decimal('2')
1024
1025 #two Decimals
1026 self.assertEqual(d1%d2, Decimal('1'))
1027 self.assertEqual(d2%d1, Decimal('2'))
1028
1029 #with other type, left
1030 c = d1 % 4
1031 self.assertEqual(c, Decimal('1'))
1032 self.assertEqual(type(c), type(d1))
1033
1034 #with other type, right
1035 c = 7 % d1
1036 self.assertEqual(c, Decimal('2'))
1037 self.assertEqual(type(c), type(d1))
1038
1039 #inline with decimal
1040 d1 %= d2
1041 self.assertEqual(d1, Decimal('1'))
1042
1043 #inline with other type
1044 d1 %= 4
1045 self.assertEqual(d1, Decimal('1'))
1046
1047 def test_floor_div_module(self):
1048
1049 d1 = Decimal('5')
1050 d2 = Decimal('2')
1051
1052 #two Decimals
1053 (p, q) = divmod(d1, d2)
1054 self.assertEqual(p, Decimal('2'))
1055 self.assertEqual(q, Decimal('1'))
1056 self.assertEqual(type(p), type(d1))
1057 self.assertEqual(type(q), type(d1))
1058
1059 #with other type, left
1060 (p, q) = divmod(d1, 4)
1061 self.assertEqual(p, Decimal('1'))
1062 self.assertEqual(q, Decimal('1'))
1063 self.assertEqual(type(p), type(d1))
1064 self.assertEqual(type(q), type(d1))
1065
1066 #with other type, right
1067 (p, q) = divmod(7, d1)
1068 self.assertEqual(p, Decimal('1'))
1069 self.assertEqual(q, Decimal('2'))
1070 self.assertEqual(type(p), type(d1))
1071 self.assertEqual(type(q), type(d1))
1072
1073 def test_unary_operators(self):
1074 self.assertEqual(+Decimal(45), Decimal(+45)) # +
1075 self.assertEqual(-Decimal(45), Decimal(-45)) # -
1076 self.assertEqual(abs(Decimal(45)), abs(Decimal(-45))) # abs
1077
Mark Dickinson2fc92632008-02-06 22:10:50 +00001078 def test_nan_comparisons(self):
1079 n = Decimal('NaN')
1080 s = Decimal('sNaN')
1081 i = Decimal('Inf')
1082 f = Decimal('2')
1083 for x, y in [(n, n), (n, i), (i, n), (n, f), (f, n),
1084 (s, n), (n, s), (s, i), (i, s), (s, f), (f, s), (s, s)]:
Benjamin Peterson5c8da862009-06-30 22:57:08 +00001085 self.assertTrue(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))
1090 self.assertTrue(not (x >= y))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001091
1092# The following are two functions used to test threading in the next class
1093
1094def thfunc1(cls):
1095 d1 = Decimal(1)
1096 d3 = Decimal(3)
Facundo Batista64156672008-03-22 02:45:37 +00001097 test1 = d1/d3
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001098 cls.synchro.wait()
Facundo Batista64156672008-03-22 02:45:37 +00001099 test2 = d1/d3
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001100 cls.finish1.set()
Facundo Batista64156672008-03-22 02:45:37 +00001101
Facundo Batistaee340e52008-05-02 17:39:00 +00001102 cls.assertEqual(test1, Decimal('0.3333333333333333333333333333'))
1103 cls.assertEqual(test2, Decimal('0.3333333333333333333333333333'))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001104 return
1105
1106def thfunc2(cls):
1107 d1 = Decimal(1)
1108 d3 = Decimal(3)
Facundo Batista64156672008-03-22 02:45:37 +00001109 test1 = d1/d3
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001110 thiscontext = getcontext()
1111 thiscontext.prec = 18
Facundo Batista64156672008-03-22 02:45:37 +00001112 test2 = d1/d3
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001113 cls.synchro.set()
1114 cls.finish2.set()
Facundo Batista64156672008-03-22 02:45:37 +00001115
Facundo Batistaee340e52008-05-02 17:39:00 +00001116 cls.assertEqual(test1, Decimal('0.3333333333333333333333333333'))
Facundo Batista64156672008-03-22 02:45:37 +00001117 cls.assertEqual(test2, Decimal('0.333333333333333333'))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001118 return
1119
1120
1121class DecimalUseOfContextTest(unittest.TestCase):
1122 '''Unit tests for Use of Context cases in Decimal.'''
1123
Raymond Hettinger7e71fa52004-12-18 19:07:19 +00001124 try:
1125 import threading
1126 except ImportError:
1127 threading = None
1128
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001129 # Take care executing this test from IDLE, there's an issue in threading
1130 # that hangs IDLE and I couldn't find it
1131
1132 def test_threading(self):
1133 #Test the "threading isolation" of a Context.
1134
1135 self.synchro = threading.Event()
1136 self.finish1 = threading.Event()
1137 self.finish2 = threading.Event()
1138
1139 th1 = threading.Thread(target=thfunc1, args=(self,))
1140 th2 = threading.Thread(target=thfunc2, args=(self,))
1141
1142 th1.start()
1143 th2.start()
1144
1145 self.finish1.wait()
Thomas Woutersb3e6e8c2007-09-19 17:27:29 +00001146 self.finish2.wait()
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001147 return
1148
Raymond Hettinger7e71fa52004-12-18 19:07:19 +00001149 if threading is None:
1150 del test_threading
1151
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001152
1153class DecimalUsabilityTest(unittest.TestCase):
1154 '''Unit tests for Usability cases of Decimal.'''
1155
1156 def test_comparison_operators(self):
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001157
1158 da = Decimal('23.42')
1159 db = Decimal('23.42')
1160 dc = Decimal('45')
1161
1162 #two Decimals
Benjamin Peterson5c8da862009-06-30 22:57:08 +00001163 self.assertTrue(dc > da)
1164 self.assertTrue(dc >= da)
1165 self.assertTrue(da < dc)
1166 self.assertTrue(da <= dc)
1167 self.assertTrue(da == db)
1168 self.assertTrue(da != dc)
1169 self.assertTrue(da <= db)
1170 self.assertTrue(da >= db)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001171 self.assertEqual(cmp(dc,da), 1)
1172 self.assertEqual(cmp(da,dc), -1)
1173 self.assertEqual(cmp(da,db), 0)
1174
1175 #a Decimal and an int
Benjamin Peterson5c8da862009-06-30 22:57:08 +00001176 self.assertTrue(dc > 23)
1177 self.assertTrue(23 < dc)
1178 self.assertTrue(dc == 45)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001179 self.assertEqual(cmp(dc,23), 1)
1180 self.assertEqual(cmp(23,dc), -1)
1181 self.assertEqual(cmp(dc,45), 0)
1182
1183 #a Decimal and uncomparable
Raymond Hettinger0aeac102004-07-05 22:53:03 +00001184 self.assertNotEqual(da, 'ugly')
1185 self.assertNotEqual(da, 32.7)
1186 self.assertNotEqual(da, object())
1187 self.assertNotEqual(da, object)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001188
Raymond Hettinger0aeac102004-07-05 22:53:03 +00001189 # sortable
1190 a = map(Decimal, xrange(100))
1191 b = a[:]
1192 random.shuffle(a)
1193 a.sort()
1194 self.assertEqual(a, b)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001195
Facundo Batista353750c2007-09-13 18:13:15 +00001196 # with None
1197 self.assertFalse(Decimal(1) < None)
1198 self.assertTrue(Decimal(1) > None)
1199
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001200 def test_copy_and_deepcopy_methods(self):
1201 d = Decimal('43.24')
1202 c = copy.copy(d)
1203 self.assertEqual(id(c), id(d))
1204 dc = copy.deepcopy(d)
1205 self.assertEqual(id(dc), id(d))
1206
1207 def test_hash_method(self):
1208 #just that it's hashable
1209 hash(Decimal(23))
Facundo Batista8c202442007-09-19 17:53:25 +00001210
1211 test_values = [Decimal(sign*(2**m + n))
1212 for m in [0, 14, 15, 16, 17, 30, 31,
1213 32, 33, 62, 63, 64, 65, 66]
1214 for n in range(-10, 10)
1215 for sign in [-1, 1]]
1216 test_values.extend([
1217 Decimal("-0"), # zeros
1218 Decimal("0.00"),
1219 Decimal("-0.000"),
1220 Decimal("0E10"),
1221 Decimal("-0E12"),
1222 Decimal("10.0"), # negative exponent
1223 Decimal("-23.00000"),
1224 Decimal("1230E100"), # positive exponent
1225 Decimal("-4.5678E50"),
1226 # a value for which hash(n) != hash(n % (2**64-1))
1227 # in Python pre-2.6
1228 Decimal(2**64 + 2**32 - 1),
1229 # selection of values which fail with the old (before
1230 # version 2.6) long.__hash__
1231 Decimal("1.634E100"),
1232 Decimal("90.697E100"),
1233 Decimal("188.83E100"),
1234 Decimal("1652.9E100"),
1235 Decimal("56531E100"),
1236 ])
1237
1238 # check that hash(d) == hash(int(d)) for integral values
1239 for value in test_values:
1240 self.assertEqual(hash(value), hash(int(value)))
1241
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001242 #the same hash that to an int
1243 self.assertEqual(hash(Decimal(23)), hash(23))
Raymond Hettingerbea3f6f2005-03-15 04:59:17 +00001244 self.assertRaises(TypeError, hash, Decimal('NaN'))
Benjamin Peterson5c8da862009-06-30 22:57:08 +00001245 self.assertTrue(hash(Decimal('Inf')))
1246 self.assertTrue(hash(Decimal('-Inf')))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001247
Facundo Batista52b25792008-01-08 12:25:20 +00001248 # check that the value of the hash doesn't depend on the
1249 # current context (issue #1757)
1250 c = getcontext()
1251 old_precision = c.prec
1252 x = Decimal("123456789.1")
1253
1254 c.prec = 6
1255 h1 = hash(x)
1256 c.prec = 10
1257 h2 = hash(x)
1258 c.prec = 16
1259 h3 = hash(x)
1260
1261 self.assertEqual(h1, h2)
1262 self.assertEqual(h1, h3)
1263 c.prec = old_precision
1264
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001265 def test_min_and_max_methods(self):
1266
1267 d1 = Decimal('15.32')
1268 d2 = Decimal('28.5')
1269 l1 = 15
1270 l2 = 28
1271
1272 #between Decimals
Benjamin Peterson5c8da862009-06-30 22:57:08 +00001273 self.assertTrue(min(d1,d2) is d1)
1274 self.assertTrue(min(d2,d1) is d1)
1275 self.assertTrue(max(d1,d2) is d2)
1276 self.assertTrue(max(d2,d1) is d2)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001277
1278 #between Decimal and long
Benjamin Peterson5c8da862009-06-30 22:57:08 +00001279 self.assertTrue(min(d1,l2) is d1)
1280 self.assertTrue(min(l2,d1) is d1)
1281 self.assertTrue(max(l1,d2) is d2)
1282 self.assertTrue(max(d2,l1) is d2)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001283
1284 def test_as_nonzero(self):
1285 #as false
Benjamin Peterson5c8da862009-06-30 22:57:08 +00001286 self.assertFalse(Decimal(0))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001287 #as true
Benjamin Peterson5c8da862009-06-30 22:57:08 +00001288 self.assertTrue(Decimal('0.372'))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001289
1290 def test_tostring_methods(self):
1291 #Test str and repr methods.
1292
1293 d = Decimal('15.32')
1294 self.assertEqual(str(d), '15.32') # str
Raymond Hettingerabe32372008-02-14 02:41:22 +00001295 self.assertEqual(repr(d), "Decimal('15.32')") # repr
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001296
Mark Dickinson8e85ffa2008-03-25 18:47:59 +00001297 # result type of string methods should be str, not unicode
1298 unicode_inputs = [u'123.4', u'0.5E2', u'Infinity', u'sNaN',
1299 u'-0.0E100', u'-NaN001', u'-Inf']
1300
1301 for u in unicode_inputs:
1302 d = Decimal(u)
1303 self.assertEqual(type(str(d)), str)
1304 self.assertEqual(type(repr(d)), str)
1305 self.assertEqual(type(d.to_eng_string()), str)
1306
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001307 def test_tonum_methods(self):
1308 #Test float, int and long methods.
1309
1310 d1 = Decimal('66')
1311 d2 = Decimal('15.32')
1312
1313 #int
1314 self.assertEqual(int(d1), 66)
1315 self.assertEqual(int(d2), 15)
1316
1317 #long
1318 self.assertEqual(long(d1), 66)
1319 self.assertEqual(long(d2), 15)
1320
1321 #float
1322 self.assertEqual(float(d1), 66)
1323 self.assertEqual(float(d2), 15.32)
1324
1325 def test_eval_round_trip(self):
1326
1327 #with zero
1328 d = Decimal( (0, (0,), 0) )
1329 self.assertEqual(d, eval(repr(d)))
1330
1331 #int
1332 d = Decimal( (1, (4, 5), 0) )
1333 self.assertEqual(d, eval(repr(d)))
1334
1335 #float
1336 d = Decimal( (0, (4, 5, 3, 4), -2) )
1337 self.assertEqual(d, eval(repr(d)))
1338
1339 #weird
1340 d = Decimal( (1, (4, 3, 4, 9, 1, 3, 5, 3, 4), -25) )
1341 self.assertEqual(d, eval(repr(d)))
1342
1343 def test_as_tuple(self):
1344
1345 #with zero
1346 d = Decimal(0)
1347 self.assertEqual(d.as_tuple(), (0, (0,), 0) )
1348
1349 #int
1350 d = Decimal(-45)
1351 self.assertEqual(d.as_tuple(), (1, (4, 5), 0) )
1352
1353 #complicated string
1354 d = Decimal("-4.34913534E-17")
1355 self.assertEqual(d.as_tuple(), (1, (4, 3, 4, 9, 1, 3, 5, 3, 4), -25) )
1356
1357 #inf
1358 d = Decimal("Infinity")
1359 self.assertEqual(d.as_tuple(), (0, (0,), 'F') )
1360
Facundo Batista9b5e2312007-10-19 19:25:57 +00001361 #leading zeros in coefficient should be stripped
1362 d = Decimal( (0, (0, 0, 4, 0, 5, 3, 4), -2) )
1363 self.assertEqual(d.as_tuple(), (0, (4, 0, 5, 3, 4), -2) )
1364 d = Decimal( (1, (0, 0, 0), 37) )
1365 self.assertEqual(d.as_tuple(), (1, (0,), 37))
1366 d = Decimal( (1, (), 37) )
1367 self.assertEqual(d.as_tuple(), (1, (0,), 37))
1368
1369 #leading zeros in NaN diagnostic info should be stripped
1370 d = Decimal( (0, (0, 0, 4, 0, 5, 3, 4), 'n') )
1371 self.assertEqual(d.as_tuple(), (0, (4, 0, 5, 3, 4), 'n') )
1372 d = Decimal( (1, (0, 0, 0), 'N') )
1373 self.assertEqual(d.as_tuple(), (1, (), 'N') )
1374 d = Decimal( (1, (), 'n') )
1375 self.assertEqual(d.as_tuple(), (1, (), 'n') )
1376
1377 #coefficient in infinity should be ignored
1378 d = Decimal( (0, (4, 5, 3, 4), 'F') )
1379 self.assertEqual(d.as_tuple(), (0, (0,), 'F'))
1380 d = Decimal( (1, (0, 2, 7, 1), 'F') )
1381 self.assertEqual(d.as_tuple(), (1, (0,), 'F'))
1382
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001383 def test_immutability_operations(self):
1384 # Do operations and check that it didn't change change internal objects.
1385
1386 d1 = Decimal('-25e55')
1387 b1 = Decimal('-25e55')
Facundo Batista353750c2007-09-13 18:13:15 +00001388 d2 = Decimal('33e+33')
1389 b2 = Decimal('33e+33')
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001390
1391 def checkSameDec(operation, useOther=False):
1392 if useOther:
1393 eval("d1." + operation + "(d2)")
1394 self.assertEqual(d1._sign, b1._sign)
1395 self.assertEqual(d1._int, b1._int)
1396 self.assertEqual(d1._exp, b1._exp)
1397 self.assertEqual(d2._sign, b2._sign)
1398 self.assertEqual(d2._int, b2._int)
1399 self.assertEqual(d2._exp, b2._exp)
1400 else:
1401 eval("d1." + operation + "()")
1402 self.assertEqual(d1._sign, b1._sign)
1403 self.assertEqual(d1._int, b1._int)
1404 self.assertEqual(d1._exp, b1._exp)
1405 return
1406
1407 Decimal(d1)
1408 self.assertEqual(d1._sign, b1._sign)
1409 self.assertEqual(d1._int, b1._int)
1410 self.assertEqual(d1._exp, b1._exp)
1411
1412 checkSameDec("__abs__")
1413 checkSameDec("__add__", True)
1414 checkSameDec("__div__", True)
1415 checkSameDec("__divmod__", True)
Mark Dickinson2fc92632008-02-06 22:10:50 +00001416 checkSameDec("__eq__", True)
1417 checkSameDec("__ne__", True)
1418 checkSameDec("__le__", True)
1419 checkSameDec("__lt__", True)
1420 checkSameDec("__ge__", True)
1421 checkSameDec("__gt__", True)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001422 checkSameDec("__float__")
1423 checkSameDec("__floordiv__", True)
1424 checkSameDec("__hash__")
1425 checkSameDec("__int__")
Raymond Hettinger5a053642008-01-24 19:05:29 +00001426 checkSameDec("__trunc__")
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001427 checkSameDec("__long__")
1428 checkSameDec("__mod__", True)
1429 checkSameDec("__mul__", True)
1430 checkSameDec("__neg__")
1431 checkSameDec("__nonzero__")
1432 checkSameDec("__pos__")
1433 checkSameDec("__pow__", True)
1434 checkSameDec("__radd__", True)
1435 checkSameDec("__rdiv__", True)
1436 checkSameDec("__rdivmod__", True)
1437 checkSameDec("__repr__")
1438 checkSameDec("__rfloordiv__", True)
1439 checkSameDec("__rmod__", True)
1440 checkSameDec("__rmul__", True)
1441 checkSameDec("__rpow__", True)
1442 checkSameDec("__rsub__", True)
1443 checkSameDec("__str__")
1444 checkSameDec("__sub__", True)
1445 checkSameDec("__truediv__", True)
1446 checkSameDec("adjusted")
1447 checkSameDec("as_tuple")
1448 checkSameDec("compare", True)
1449 checkSameDec("max", True)
1450 checkSameDec("min", True)
1451 checkSameDec("normalize")
1452 checkSameDec("quantize", True)
1453 checkSameDec("remainder_near", True)
1454 checkSameDec("same_quantum", True)
1455 checkSameDec("sqrt")
1456 checkSameDec("to_eng_string")
1457 checkSameDec("to_integral")
1458
Facundo Batista6c398da2007-09-17 17:30:13 +00001459 def test_subclassing(self):
1460 # Different behaviours when subclassing Decimal
1461
1462 class MyDecimal(Decimal):
1463 pass
1464
1465 d1 = MyDecimal(1)
1466 d2 = MyDecimal(2)
1467 d = d1 + d2
1468 self.assertTrue(type(d) is Decimal)
1469
1470 d = d1.max(d2)
1471 self.assertTrue(type(d) is Decimal)
1472
Mark Dickinson3b24ccb2008-03-25 14:33:23 +00001473 def test_implicit_context(self):
1474 # Check results when context given implicitly. (Issue 2478)
1475 c = getcontext()
1476 self.assertEqual(str(Decimal(0).sqrt()),
1477 str(c.sqrt(Decimal(0))))
1478
Facundo Batista6c398da2007-09-17 17:30:13 +00001479
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001480class DecimalPythonAPItests(unittest.TestCase):
1481
Raymond Hettinger2c8585b2009-02-03 03:37:03 +00001482 def test_abc(self):
Benjamin Peterson5c8da862009-06-30 22:57:08 +00001483 self.assertTrue(issubclass(Decimal, numbers.Number))
1484 self.assertTrue(not issubclass(Decimal, numbers.Real))
1485 self.assertTrue(isinstance(Decimal(0), numbers.Number))
1486 self.assertTrue(not isinstance(Decimal(0), numbers.Real))
Raymond Hettinger2c8585b2009-02-03 03:37:03 +00001487
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001488 def test_pickle(self):
1489 d = Decimal('-3.141590000')
1490 p = pickle.dumps(d)
1491 e = pickle.loads(p)
1492 self.assertEqual(d, e)
1493
Raymond Hettinger5548be22004-07-05 18:49:38 +00001494 def test_int(self):
Raymond Hettinger605ed022004-11-24 07:28:48 +00001495 for x in range(-250, 250):
1496 s = '%0.2f' % (x / 100.0)
Raymond Hettinger5548be22004-07-05 18:49:38 +00001497 # should work the same as for floats
1498 self.assertEqual(int(Decimal(s)), int(float(s)))
Raymond Hettinger605ed022004-11-24 07:28:48 +00001499 # should work the same as to_integral in the ROUND_DOWN mode
Raymond Hettinger5548be22004-07-05 18:49:38 +00001500 d = Decimal(s)
Raymond Hettinger605ed022004-11-24 07:28:48 +00001501 r = d.to_integral(ROUND_DOWN)
Raymond Hettinger5548be22004-07-05 18:49:38 +00001502 self.assertEqual(Decimal(int(d)), r)
1503
Mark Dickinson968f1692009-09-07 18:04:58 +00001504 self.assertRaises(ValueError, int, Decimal('-nan'))
1505 self.assertRaises(ValueError, int, Decimal('snan'))
1506 self.assertRaises(OverflowError, int, Decimal('inf'))
1507 self.assertRaises(OverflowError, int, Decimal('-inf'))
1508
1509 self.assertRaises(ValueError, long, Decimal('-nan'))
1510 self.assertRaises(ValueError, long, Decimal('snan'))
1511 self.assertRaises(OverflowError, long, Decimal('inf'))
1512 self.assertRaises(OverflowError, long, Decimal('-inf'))
1513
Raymond Hettinger5a053642008-01-24 19:05:29 +00001514 def test_trunc(self):
1515 for x in range(-250, 250):
1516 s = '%0.2f' % (x / 100.0)
1517 # should work the same as for floats
1518 self.assertEqual(int(Decimal(s)), int(float(s)))
1519 # should work the same as to_integral in the ROUND_DOWN mode
1520 d = Decimal(s)
1521 r = d.to_integral(ROUND_DOWN)
Jeffrey Yasskinca2b69f2008-02-01 06:22:46 +00001522 self.assertEqual(Decimal(math.trunc(d)), r)
Raymond Hettinger5a053642008-01-24 19:05:29 +00001523
Raymond Hettingerf4d85972009-01-03 19:02:23 +00001524 def test_from_float(self):
1525
1526 class MyDecimal(Decimal):
1527 pass
1528
1529 r = MyDecimal.from_float(0.1)
1530 self.assertEqual(type(r), MyDecimal)
1531 self.assertEqual(str(r),
1532 '0.1000000000000000055511151231257827021181583404541015625')
1533 bigint = 12345678901234567890123456789
1534 self.assertEqual(MyDecimal.from_float(bigint), MyDecimal(bigint))
Benjamin Peterson5c8da862009-06-30 22:57:08 +00001535 self.assertTrue(MyDecimal.from_float(float('nan')).is_qnan())
1536 self.assertTrue(MyDecimal.from_float(float('inf')).is_infinite())
1537 self.assertTrue(MyDecimal.from_float(float('-inf')).is_infinite())
Raymond Hettingerf4d85972009-01-03 19:02:23 +00001538 self.assertEqual(str(MyDecimal.from_float(float('nan'))),
1539 str(Decimal('NaN')))
1540 self.assertEqual(str(MyDecimal.from_float(float('inf'))),
1541 str(Decimal('Infinity')))
1542 self.assertEqual(str(MyDecimal.from_float(float('-inf'))),
1543 str(Decimal('-Infinity')))
1544 self.assertRaises(TypeError, MyDecimal.from_float, 'abc')
1545 for i in range(200):
1546 x = random.expovariate(0.01) * (random.random() * 2.0 - 1.0)
1547 self.assertEqual(x, float(MyDecimal.from_float(x))) # roundtrip
1548
1549 def test_create_decimal_from_float(self):
1550 context = Context(prec=5, rounding=ROUND_DOWN)
1551 self.assertEqual(
1552 context.create_decimal_from_float(math.pi),
1553 Decimal('3.1415')
1554 )
1555 context = Context(prec=5, rounding=ROUND_UP)
1556 self.assertEqual(
1557 context.create_decimal_from_float(math.pi),
1558 Decimal('3.1416')
1559 )
1560 context = Context(prec=5, traps=[Inexact])
1561 self.assertRaises(
1562 Inexact,
1563 context.create_decimal_from_float,
1564 math.pi
1565 )
1566 self.assertEqual(repr(context.create_decimal_from_float(-0.0)),
1567 "Decimal('-0')")
1568 self.assertEqual(repr(context.create_decimal_from_float(1.0)),
1569 "Decimal('1')")
1570 self.assertEqual(repr(context.create_decimal_from_float(10)),
1571 "Decimal('10')")
1572
Raymond Hettingerd9c0a7a2004-07-03 10:02:28 +00001573class ContextAPItests(unittest.TestCase):
1574
1575 def test_pickle(self):
1576 c = Context()
1577 e = pickle.loads(pickle.dumps(c))
1578 for k in vars(c):
1579 v1 = vars(c)[k]
1580 v2 = vars(e)[k]
1581 self.assertEqual(v1, v2)
1582
Raymond Hettinger0aeac102004-07-05 22:53:03 +00001583 def test_equality_with_other_types(self):
Benjamin Peterson5c8da862009-06-30 22:57:08 +00001584 self.assertTrue(Decimal(10) in ['a', 1.0, Decimal(10), (1,2), {}])
1585 self.assertTrue(Decimal(10) not in ['a', 1.0, (1,2), {}])
Raymond Hettinger0aeac102004-07-05 22:53:03 +00001586
Raymond Hettinger955d2b22004-08-08 20:17:45 +00001587 def test_copy(self):
1588 # All copies should be deep
1589 c = Context()
1590 d = c.copy()
1591 self.assertNotEqual(id(c), id(d))
1592 self.assertNotEqual(id(c.flags), id(d.flags))
1593 self.assertNotEqual(id(c.traps), id(d.traps))
1594
Nick Coghlan8b6999b2006-08-31 12:00:43 +00001595class WithStatementTest(unittest.TestCase):
1596 # Can't do these as docstrings until Python 2.6
1597 # as doctest can't handle __future__ statements
Nick Coghlan8b6999b2006-08-31 12:00:43 +00001598
1599 def test_localcontext(self):
Nick Coghlanced12182006-09-02 03:54:17 +00001600 # Use a copy of the current context in the block
Nick Coghlan8b6999b2006-08-31 12:00:43 +00001601 orig_ctx = getcontext()
1602 with localcontext() 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(orig_ctx is not set_ctx, 'did not copy the context')
1607 self.assertTrue(set_ctx is enter_ctx, '__enter__ returned wrong context')
Nick Coghlan8b6999b2006-08-31 12:00:43 +00001608
1609 def test_localcontextarg(self):
Nick Coghlanced12182006-09-02 03:54:17 +00001610 # Use a copy of the supplied context in the block
Nick Coghlan8b6999b2006-08-31 12:00:43 +00001611 orig_ctx = getcontext()
1612 new_ctx = Context(prec=42)
1613 with localcontext(new_ctx) as enter_ctx:
1614 set_ctx = getcontext()
1615 final_ctx = getcontext()
Benjamin Peterson5c8da862009-06-30 22:57:08 +00001616 self.assertTrue(orig_ctx is final_ctx, 'did not restore context correctly')
1617 self.assertTrue(set_ctx.prec == new_ctx.prec, 'did not set correct context')
1618 self.assertTrue(new_ctx is not set_ctx, 'did not copy the context')
1619 self.assertTrue(set_ctx is enter_ctx, '__enter__ returned wrong context')
Nick Coghlan8b6999b2006-08-31 12:00:43 +00001620
Facundo Batista353750c2007-09-13 18:13:15 +00001621class ContextFlags(unittest.TestCase):
1622 def test_flags_irrelevant(self):
1623 # check that the result (numeric result + flags raised) of an
1624 # arithmetic operation doesn't depend on the current flags
1625
1626 context = Context(prec=9, Emin = -999999999, Emax = 999999999,
1627 rounding=ROUND_HALF_EVEN, traps=[], flags=[])
1628
1629 # operations that raise various flags, in the form (function, arglist)
1630 operations = [
1631 (context._apply, [Decimal("100E-1000000009")]),
1632 (context.sqrt, [Decimal(2)]),
1633 (context.add, [Decimal("1.23456789"), Decimal("9.87654321")]),
1634 (context.multiply, [Decimal("1.23456789"), Decimal("9.87654321")]),
1635 (context.subtract, [Decimal("1.23456789"), Decimal("9.87654321")]),
1636 ]
1637
1638 # try various flags individually, then a whole lot at once
1639 flagsets = [[Inexact], [Rounded], [Underflow], [Clamped], [Subnormal],
1640 [Inexact, Rounded, Underflow, Clamped, Subnormal]]
1641
1642 for fn, args in operations:
1643 # find answer and flags raised using a clean context
1644 context.clear_flags()
1645 ans = fn(*args)
1646 flags = [k for k, v in context.flags.items() if v]
1647
1648 for extra_flags in flagsets:
1649 # set flags, before calling operation
1650 context.clear_flags()
1651 for flag in extra_flags:
1652 context._raise_error(flag)
1653 new_ans = fn(*args)
1654
1655 # flags that we expect to be set after the operation
1656 expected_flags = list(flags)
1657 for flag in extra_flags:
1658 if flag not in expected_flags:
1659 expected_flags.append(flag)
1660 expected_flags.sort()
1661
1662 # flags we actually got
1663 new_flags = [k for k,v in context.flags.items() if v]
1664 new_flags.sort()
1665
1666 self.assertEqual(ans, new_ans,
1667 "operation produces different answers depending on flags set: " +
1668 "expected %s, got %s." % (ans, new_ans))
1669 self.assertEqual(new_flags, expected_flags,
1670 "operation raises different flags depending on flags set: " +
1671 "expected %s, got %s" % (expected_flags, new_flags))
1672
1673def test_main(arith=False, verbose=None, todo_tests=None, debug=None):
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001674 """ Execute the tests.
1675
Raymond Hettingered20ad82004-09-04 20:09:13 +00001676 Runs all arithmetic tests if arith is True or if the "decimal" resource
1677 is enabled in regrtest.py
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001678 """
Raymond Hettingered20ad82004-09-04 20:09:13 +00001679
Neal Norwitzce4a9c92006-04-09 08:36:46 +00001680 init()
Facundo Batista353750c2007-09-13 18:13:15 +00001681 global TEST_ALL, DEBUG
Raymond Hettingered20ad82004-09-04 20:09:13 +00001682 TEST_ALL = arith or is_resource_enabled('decimal')
Facundo Batista353750c2007-09-13 18:13:15 +00001683 DEBUG = debug
Raymond Hettingered20ad82004-09-04 20:09:13 +00001684
Facundo Batista353750c2007-09-13 18:13:15 +00001685 if todo_tests is None:
1686 test_classes = [
1687 DecimalExplicitConstructionTest,
1688 DecimalImplicitConstructionTest,
1689 DecimalArithmeticOperatorsTest,
Mark Dickinson1ddf1d82008-02-29 02:16:37 +00001690 DecimalFormatTest,
Facundo Batista353750c2007-09-13 18:13:15 +00001691 DecimalUseOfContextTest,
1692 DecimalUsabilityTest,
1693 DecimalPythonAPItests,
1694 ContextAPItests,
1695 DecimalTest,
1696 WithStatementTest,
1697 ContextFlags
1698 ]
1699 else:
1700 test_classes = [DecimalTest]
1701
1702 # Dynamically build custom test definition for each file in the test
1703 # directory and add the definitions to the DecimalTest class. This
1704 # procedure insures that new files do not get skipped.
1705 for filename in os.listdir(directory):
1706 if '.decTest' not in filename or filename.startswith("."):
1707 continue
1708 head, tail = filename.split('.')
1709 if todo_tests is not None and head not in todo_tests:
1710 continue
1711 tester = lambda self, f=filename: self.eval_file(directory + f)
1712 setattr(DecimalTest, 'test_' + head, tester)
1713 del filename, head, tail, tester
1714
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001715
Tim Peters46cc7022006-03-31 04:11:16 +00001716 try:
1717 run_unittest(*test_classes)
Facundo Batista353750c2007-09-13 18:13:15 +00001718 if todo_tests is None:
1719 import decimal as DecimalModule
1720 run_doctest(DecimalModule, verbose)
Tim Peters46cc7022006-03-31 04:11:16 +00001721 finally:
1722 setcontext(ORIGINAL_CONTEXT)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001723
1724if __name__ == '__main__':
Facundo Batista353750c2007-09-13 18:13:15 +00001725 import optparse
1726 p = optparse.OptionParser("test_decimal.py [--debug] [{--skip | test1 [test2 [...]]}]")
1727 p.add_option('--debug', '-d', action='store_true', help='shows the test number and context before each test')
1728 p.add_option('--skip', '-s', action='store_true', help='skip over 90% of the arithmetic tests')
1729 (opt, args) = p.parse_args()
1730
1731 if opt.skip:
1732 test_main(arith=False, verbose=True)
1733 elif args:
1734 test_main(arith=True, verbose=True, todo_tests=args, debug=opt.debug)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001735 else:
Facundo Batista353750c2007-09-13 18:13:15 +00001736 test_main(arith=True, verbose=True)