blob: 9fef0d2232edf1c7172e7826a13e3130ab094fcf [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
Senthil Kumaran3ddc4352010-01-08 18:41:40 +000034from test.test_support import (run_unittest, run_doctest,
35 is_resource_enabled, check_warnings)
Raymond Hettinger0aeac102004-07-05 22:53:03 +000036import random
Raymond Hettinger7e71fa52004-12-18 19:07:19 +000037try:
38 import threading
39except ImportError:
40 threading = None
Raymond Hettinger7c85fa42004-07-01 11:01:35 +000041
Raymond Hettingerfed52962004-07-14 15:41:57 +000042# Useful Test Constant
43Signals = getcontext().flags.keys()
44
Tim Peters46cc7022006-03-31 04:11:16 +000045# Tests are built around these assumed context defaults.
46# test_main() restores the original context.
Neal Norwitzce4a9c92006-04-09 08:36:46 +000047def init():
48 global ORIGINAL_CONTEXT
49 ORIGINAL_CONTEXT = getcontext().copy()
Facundo Batistaee340e52008-05-02 17:39:00 +000050 DefaultTestContext = Context(
51 prec = 9,
52 rounding = ROUND_HALF_EVEN,
53 traps = dict.fromkeys(Signals, 0)
54 )
55 setcontext(DefaultTestContext)
Raymond Hettinger6ea48452004-07-03 12:26:21 +000056
Raymond Hettinger7c85fa42004-07-01 11:01:35 +000057TESTDATADIR = 'decimaltestdata'
Raymond Hettingerd9c0a7a2004-07-03 10:02:28 +000058if __name__ == '__main__':
59 file = sys.argv[0]
60else:
61 file = __file__
62testdir = os.path.dirname(file) or os.curdir
Raymond Hettinger267b8682005-03-27 10:47:39 +000063directory = testdir + os.sep + TESTDATADIR + os.sep
Raymond Hettinger7c85fa42004-07-01 11:01:35 +000064
Raymond Hettinger267b8682005-03-27 10:47:39 +000065skip_expected = not os.path.isdir(directory)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +000066
Mark Dickinson539bff42009-10-08 16:28:39 +000067# list of individual .decTest test ids that correspond to tests that
68# we're skipping for one reason or another.
69skipped_test_ids = [
70 'scbx164', # skipping apparently implementation-specific scaleb
71 'scbx165', # tests, pending clarification of scaleb rules.
72]
73
Raymond Hettinger7c85fa42004-07-01 11:01:35 +000074# Make sure it actually raises errors when not expected and caught in flags
75# Slower, since it runs some things several times.
76EXTENDEDERRORTEST = False
77
Raymond Hettinger7c85fa42004-07-01 11:01:35 +000078#Map the test cases' error names to the actual errors
Raymond Hettinger7c85fa42004-07-01 11:01:35 +000079ErrorNames = {'clamped' : Clamped,
Raymond Hettinger5aa478b2004-07-09 10:02:53 +000080 'conversion_syntax' : InvalidOperation,
Raymond Hettinger7c85fa42004-07-01 11:01:35 +000081 'division_by_zero' : DivisionByZero,
Raymond Hettinger5aa478b2004-07-09 10:02:53 +000082 'division_impossible' : InvalidOperation,
83 'division_undefined' : InvalidOperation,
Raymond Hettinger7c85fa42004-07-01 11:01:35 +000084 'inexact' : Inexact,
Raymond Hettinger5aa478b2004-07-09 10:02:53 +000085 'invalid_context' : InvalidOperation,
Raymond Hettinger7c85fa42004-07-01 11:01:35 +000086 'invalid_operation' : InvalidOperation,
87 'overflow' : Overflow,
88 'rounded' : Rounded,
89 'subnormal' : Subnormal,
90 'underflow' : Underflow}
91
92
93def Nonfunction(*args):
94 """Doesn't do anything."""
95 return None
96
97RoundingDict = {'ceiling' : ROUND_CEILING, #Maps test-case names to roundings.
98 'down' : ROUND_DOWN,
99 'floor' : ROUND_FLOOR,
100 'half_down' : ROUND_HALF_DOWN,
101 'half_even' : ROUND_HALF_EVEN,
102 'half_up' : ROUND_HALF_UP,
Facundo Batista353750c2007-09-13 18:13:15 +0000103 'up' : ROUND_UP,
104 '05up' : ROUND_05UP}
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000105
106# Name adapter to be able to change the Decimal and Context
107# interface without changing the test files from Cowlishaw
Facundo Batista1a191df2007-10-02 17:01:24 +0000108nameAdapter = {'and':'logical_and',
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000109 'apply':'_apply',
Facundo Batista353750c2007-09-13 18:13:15 +0000110 'class':'number_class',
111 'comparesig':'compare_signal',
112 'comparetotal':'compare_total',
113 'comparetotmag':'compare_total_mag',
Facundo Batista353750c2007-09-13 18:13:15 +0000114 'copy':'copy_decimal',
Facundo Batista1a191df2007-10-02 17:01:24 +0000115 'copyabs':'copy_abs',
Facundo Batista353750c2007-09-13 18:13:15 +0000116 'copynegate':'copy_negate',
117 'copysign':'copy_sign',
Facundo Batista1a191df2007-10-02 17:01:24 +0000118 'divideint':'divide_int',
Facundo Batista353750c2007-09-13 18:13:15 +0000119 'invert':'logical_invert',
Facundo Batista1a191df2007-10-02 17:01:24 +0000120 'iscanonical':'is_canonical',
121 'isfinite':'is_finite',
122 'isinfinite':'is_infinite',
123 'isnan':'is_nan',
124 'isnormal':'is_normal',
125 'isqnan':'is_qnan',
126 'issigned':'is_signed',
127 'issnan':'is_snan',
128 'issubnormal':'is_subnormal',
129 'iszero':'is_zero',
Facundo Batista353750c2007-09-13 18:13:15 +0000130 'maxmag':'max_mag',
131 'minmag':'min_mag',
132 'nextminus':'next_minus',
133 'nextplus':'next_plus',
134 'nexttoward':'next_toward',
Facundo Batista1a191df2007-10-02 17:01:24 +0000135 'or':'logical_or',
Facundo Batista353750c2007-09-13 18:13:15 +0000136 'reduce':'normalize',
Facundo Batista1a191df2007-10-02 17:01:24 +0000137 'remaindernear':'remainder_near',
138 'samequantum':'same_quantum',
139 'squareroot':'sqrt',
140 'toeng':'to_eng_string',
141 'tointegral':'to_integral_value',
142 'tointegralx':'to_integral_exact',
143 'tosci':'to_sci_string',
144 'xor':'logical_xor',
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000145 }
146
Facundo Batista1a191df2007-10-02 17:01:24 +0000147# The following functions return True/False rather than a Decimal instance
148
149LOGICAL_FUNCTIONS = (
150 'is_canonical',
151 'is_finite',
152 'is_infinite',
153 'is_nan',
154 'is_normal',
155 'is_qnan',
156 'is_signed',
157 'is_snan',
158 'is_subnormal',
159 'is_zero',
160 'same_quantum',
161 )
162
Facundo Batista353750c2007-09-13 18:13:15 +0000163# For some operations (currently exp, ln, log10, power), the decNumber
164# reference implementation imposes additional restrictions on the
165# context and operands. These restrictions are not part of the
166# specification; however, the effect of these restrictions does show
167# up in some of the testcases. We skip testcases that violate these
168# restrictions, since Decimal behaves differently from decNumber for
169# these testcases so these testcases would otherwise fail.
170
171decNumberRestricted = ('power', 'ln', 'log10', 'exp')
172DEC_MAX_MATH = 999999
173def outside_decNumber_bounds(v, context):
174 if (context.prec > DEC_MAX_MATH or
175 context.Emax > DEC_MAX_MATH or
176 -context.Emin > DEC_MAX_MATH):
177 return True
178 if not v._is_special and v and (
Facundo Batista353750c2007-09-13 18:13:15 +0000179 v.adjusted() > DEC_MAX_MATH or
180 v.adjusted() < 1-2*DEC_MAX_MATH):
181 return True
182 return False
183
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000184class DecimalTest(unittest.TestCase):
185 """Class which tests the Decimal class against the test cases.
186
187 Changed for unittest.
188 """
189 def setUp(self):
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000190 self.context = Context()
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000191 self.ignore_list = ['#']
192 # Basically, a # means return NaN InvalidOperation.
193 # Different from a sNaN in trim
194
195 self.ChangeDict = {'precision' : self.change_precision,
196 'rounding' : self.change_rounding_method,
197 'maxexponent' : self.change_max_exponent,
198 'minexponent' : self.change_min_exponent,
199 'clamp' : self.change_clamp}
200
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000201 def eval_file(self, file):
202 global skip_expected
203 if skip_expected:
Benjamin Petersonbec087f2009-03-26 21:10:30 +0000204 raise unittest.SkipTest
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000205 return
Senthil Kumaran3ddc4352010-01-08 18:41:40 +0000206 for line in open(file):
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000207 line = line.replace('\r\n', '').replace('\n', '')
Raymond Hettinger5aa478b2004-07-09 10:02:53 +0000208 #print line
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000209 try:
210 t = self.eval_line(line)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000211 except DecimalException, exception:
212 #Exception raised where there shoudn't have been one.
213 self.fail('Exception "'+exception.__class__.__name__ + '" raised on line '+line)
214
215 return
216
217 def eval_line(self, s):
218 if s.find(' -> ') >= 0 and s[:2] != '--' and not s.startswith(' --'):
219 s = (s.split('->')[0] + '->' +
220 s.split('->')[1].split('--')[0]).strip()
221 else:
222 s = s.split('--')[0].strip()
223
224 for ignore in self.ignore_list:
225 if s.find(ignore) >= 0:
226 #print s.split()[0], 'NotImplemented--', ignore
227 return
228 if not s:
229 return
230 elif ':' in s:
231 return self.eval_directive(s)
232 else:
233 return self.eval_equation(s)
234
235 def eval_directive(self, s):
236 funct, value = map(lambda x: x.strip().lower(), s.split(':'))
237 if funct == 'rounding':
238 value = RoundingDict[value]
239 else:
240 try:
241 value = int(value)
242 except ValueError:
243 pass
244
245 funct = self.ChangeDict.get(funct, Nonfunction)
246 funct(value)
247
248 def eval_equation(self, s):
249 #global DEFAULT_PRECISION
250 #print DEFAULT_PRECISION
Raymond Hettingered20ad82004-09-04 20:09:13 +0000251
252 if not TEST_ALL and random.random() < 0.90:
253 return
254
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000255 try:
256 Sides = s.split('->')
257 L = Sides[0].strip().split()
258 id = L[0]
Facundo Batista353750c2007-09-13 18:13:15 +0000259 if DEBUG:
260 print "Test ", id,
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000261 funct = L[1].lower()
262 valstemp = L[2:]
263 L = Sides[1].strip().split()
264 ans = L[0]
265 exceptions = L[1:]
266 except (TypeError, AttributeError, IndexError):
Raymond Hettingerd87ac8f2004-07-09 10:52:54 +0000267 raise InvalidOperation
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000268 def FixQuotes(val):
269 val = val.replace("''", 'SingleQuote').replace('""', 'DoubleQuote')
270 val = val.replace("'", '').replace('"', '')
271 val = val.replace('SingleQuote', "'").replace('DoubleQuote', '"')
272 return val
Mark Dickinson539bff42009-10-08 16:28:39 +0000273
274 if id in skipped_test_ids:
275 return
276
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000277 fname = nameAdapter.get(funct, funct)
278 if fname == 'rescale':
279 return
280 funct = getattr(self.context, fname)
281 vals = []
282 conglomerate = ''
283 quote = 0
284 theirexceptions = [ErrorNames[x.lower()] for x in exceptions]
285
Raymond Hettingerd9c0a7a2004-07-03 10:02:28 +0000286 for exception in Signals:
Raymond Hettingerbf440692004-07-10 14:14:37 +0000287 self.context.traps[exception] = 1 #Catch these bugs...
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000288 for exception in theirexceptions:
Raymond Hettingerbf440692004-07-10 14:14:37 +0000289 self.context.traps[exception] = 0
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000290 for i, val in enumerate(valstemp):
291 if val.count("'") % 2 == 1:
292 quote = 1 - quote
293 if quote:
294 conglomerate = conglomerate + ' ' + val
295 continue
296 else:
297 val = conglomerate + val
298 conglomerate = ''
299 v = FixQuotes(val)
300 if fname in ('to_sci_string', 'to_eng_string'):
301 if EXTENDEDERRORTEST:
302 for error in theirexceptions:
Raymond Hettingerbf440692004-07-10 14:14:37 +0000303 self.context.traps[error] = 1
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000304 try:
305 funct(self.context.create_decimal(v))
306 except error:
307 pass
Raymond Hettingerd9c0a7a2004-07-03 10:02:28 +0000308 except Signals, e:
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000309 self.fail("Raised %s in %s when %s disabled" % \
310 (e, s, error))
311 else:
312 self.fail("Did not raise %s in %s" % (error, s))
Raymond Hettingerbf440692004-07-10 14:14:37 +0000313 self.context.traps[error] = 0
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000314 v = self.context.create_decimal(v)
315 else:
Facundo Batista353750c2007-09-13 18:13:15 +0000316 v = Decimal(v, self.context)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000317 vals.append(v)
318
319 ans = FixQuotes(ans)
320
Facundo Batista353750c2007-09-13 18:13:15 +0000321 # skip tests that are related to bounds imposed in the decNumber
322 # reference implementation
323 if fname in decNumberRestricted:
324 if fname == 'power':
325 if not (vals[1]._isinteger() and
326 -1999999997 <= vals[1] <= 999999999):
327 if outside_decNumber_bounds(vals[0], self.context) or \
328 outside_decNumber_bounds(vals[1], self.context):
329 #print "Skipping test %s" % s
330 return
331 else:
332 if outside_decNumber_bounds(vals[0], self.context):
333 #print "Skipping test %s" % s
334 return
335
336
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000337 if EXTENDEDERRORTEST and fname not in ('to_sci_string', 'to_eng_string'):
338 for error in theirexceptions:
Raymond Hettingerbf440692004-07-10 14:14:37 +0000339 self.context.traps[error] = 1
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000340 try:
341 funct(*vals)
342 except error:
343 pass
Raymond Hettingerd9c0a7a2004-07-03 10:02:28 +0000344 except Signals, e:
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000345 self.fail("Raised %s in %s when %s disabled" % \
346 (e, s, error))
347 else:
348 self.fail("Did not raise %s in %s" % (error, s))
Raymond Hettingerbf440692004-07-10 14:14:37 +0000349 self.context.traps[error] = 0
Facundo Batista353750c2007-09-13 18:13:15 +0000350 if DEBUG:
351 print "--", self.context
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000352 try:
353 result = str(funct(*vals))
Facundo Batista1a191df2007-10-02 17:01:24 +0000354 if fname in LOGICAL_FUNCTIONS:
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000355 result = str(int(eval(result))) # 'True', 'False' -> '1', '0'
Raymond Hettingerd9c0a7a2004-07-03 10:02:28 +0000356 except Signals, error:
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000357 self.fail("Raised %s in %s" % (error, s))
358 except: #Catch any error long enough to state the test case.
359 print "ERROR:", s
360 raise
361
362 myexceptions = self.getexceptions()
Raymond Hettingerbf440692004-07-10 14:14:37 +0000363 self.context.clear_flags()
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000364
Senthil Kumaran3ddc4352010-01-08 18:41:40 +0000365 # Silence Py3k warning
366 with check_warnings():
367 myexceptions.sort()
368 theirexceptions.sort()
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000369
370 self.assertEqual(result, ans,
371 'Incorrect answer for ' + s + ' -- got ' + result)
372 self.assertEqual(myexceptions, theirexceptions,
Facundo Batista353750c2007-09-13 18:13:15 +0000373 'Incorrect flags set in ' + s + ' -- got ' + str(myexceptions))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000374 return
375
376 def getexceptions(self):
Raymond Hettingerf63ba432004-08-17 05:42:09 +0000377 return [e for e in Signals if self.context.flags[e]]
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000378
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000379 def change_precision(self, prec):
380 self.context.prec = prec
381 def change_rounding_method(self, rounding):
382 self.context.rounding = rounding
383 def change_min_exponent(self, exp):
384 self.context.Emin = exp
385 def change_max_exponent(self, exp):
386 self.context.Emax = exp
387 def change_clamp(self, clamp):
388 self.context._clamp = clamp
389
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000390
391
392# The following classes test the behaviour of Decimal according to PEP 327
393
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000394class DecimalExplicitConstructionTest(unittest.TestCase):
395 '''Unit tests for Explicit Construction cases of Decimal.'''
396
397 def test_explicit_empty(self):
398 self.assertEqual(Decimal(), Decimal("0"))
399
400 def test_explicit_from_None(self):
401 self.assertRaises(TypeError, Decimal, None)
402
403 def test_explicit_from_int(self):
404
405 #positive
406 d = Decimal(45)
407 self.assertEqual(str(d), '45')
408
409 #very large positive
410 d = Decimal(500000123)
411 self.assertEqual(str(d), '500000123')
412
413 #negative
414 d = Decimal(-45)
415 self.assertEqual(str(d), '-45')
416
417 #zero
418 d = Decimal(0)
419 self.assertEqual(str(d), '0')
420
421 def test_explicit_from_string(self):
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000422
423 #empty
424 self.assertEqual(str(Decimal('')), 'NaN')
425
426 #int
427 self.assertEqual(str(Decimal('45')), '45')
428
429 #float
430 self.assertEqual(str(Decimal('45.34')), '45.34')
431
432 #engineer notation
433 self.assertEqual(str(Decimal('45e2')), '4.5E+3')
434
435 #just not a number
436 self.assertEqual(str(Decimal('ugly')), 'NaN')
437
Mark Dickinson59bc20b2008-01-12 01:56:00 +0000438 #leading and trailing whitespace permitted
439 self.assertEqual(str(Decimal('1.3E4 \n')), '1.3E+4')
440 self.assertEqual(str(Decimal(' -7.89')), '-7.89')
441
Mark Dickinson8e85ffa2008-03-25 18:47:59 +0000442 #unicode strings should be permitted
443 self.assertEqual(str(Decimal(u'0E-017')), '0E-17')
444 self.assertEqual(str(Decimal(u'45')), '45')
445 self.assertEqual(str(Decimal(u'-Inf')), '-Infinity')
446 self.assertEqual(str(Decimal(u'NaN123')), 'NaN123')
447
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000448 def test_explicit_from_tuples(self):
449
450 #zero
451 d = Decimal( (0, (0,), 0) )
452 self.assertEqual(str(d), '0')
453
454 #int
455 d = Decimal( (1, (4, 5), 0) )
456 self.assertEqual(str(d), '-45')
457
458 #float
459 d = Decimal( (0, (4, 5, 3, 4), -2) )
460 self.assertEqual(str(d), '45.34')
461
462 #weird
463 d = Decimal( (1, (4, 3, 4, 9, 1, 3, 5, 3, 4), -25) )
464 self.assertEqual(str(d), '-4.34913534E-17')
465
466 #wrong number of items
467 self.assertRaises(ValueError, Decimal, (1, (4, 3, 4, 9, 1)) )
468
469 #bad sign
470 self.assertRaises(ValueError, Decimal, (8, (4, 3, 4, 9, 1), 2) )
Facundo Batista9b5e2312007-10-19 19:25:57 +0000471 self.assertRaises(ValueError, Decimal, (0., (4, 3, 4, 9, 1), 2) )
472 self.assertRaises(ValueError, Decimal, (Decimal(1), (4, 3, 4, 9, 1), 2))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000473
474 #bad exp
475 self.assertRaises(ValueError, Decimal, (1, (4, 3, 4, 9, 1), 'wrong!') )
Facundo Batista9b5e2312007-10-19 19:25:57 +0000476 self.assertRaises(ValueError, Decimal, (1, (4, 3, 4, 9, 1), 0.) )
477 self.assertRaises(ValueError, Decimal, (1, (4, 3, 4, 9, 1), '1') )
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000478
479 #bad coefficients
480 self.assertRaises(ValueError, Decimal, (1, (4, 3, 4, None, 1), 2) )
481 self.assertRaises(ValueError, Decimal, (1, (4, -3, 4, 9, 1), 2) )
Facundo Batista9b5e2312007-10-19 19:25:57 +0000482 self.assertRaises(ValueError, Decimal, (1, (4, 10, 4, 9, 1), 2) )
Facundo Batista72bc54f2007-11-23 17:59:00 +0000483 self.assertRaises(ValueError, Decimal, (1, (4, 3, 4, 'a', 1), 2) )
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000484
485 def test_explicit_from_Decimal(self):
486
487 #positive
488 d = Decimal(45)
489 e = Decimal(d)
490 self.assertEqual(str(e), '45')
491 self.assertNotEqual(id(d), id(e))
492
493 #very large positive
494 d = Decimal(500000123)
495 e = Decimal(d)
496 self.assertEqual(str(e), '500000123')
497 self.assertNotEqual(id(d), id(e))
498
499 #negative
500 d = Decimal(-45)
501 e = Decimal(d)
502 self.assertEqual(str(e), '-45')
503 self.assertNotEqual(id(d), id(e))
504
505 #zero
506 d = Decimal(0)
507 e = Decimal(d)
508 self.assertEqual(str(e), '0')
509 self.assertNotEqual(id(d), id(e))
510
511 def test_explicit_context_create_decimal(self):
512
513 nc = copy.copy(getcontext())
514 nc.prec = 3
515
516 # empty
Raymond Hettingerfed52962004-07-14 15:41:57 +0000517 d = Decimal()
518 self.assertEqual(str(d), '0')
519 d = nc.create_decimal()
520 self.assertEqual(str(d), '0')
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000521
522 # from None
523 self.assertRaises(TypeError, nc.create_decimal, None)
524
525 # from int
526 d = nc.create_decimal(456)
Benjamin Peterson5c8da862009-06-30 22:57:08 +0000527 self.assertTrue(isinstance(d, Decimal))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000528 self.assertEqual(nc.create_decimal(45678),
529 nc.create_decimal('457E+2'))
530
531 # from string
532 d = Decimal('456789')
533 self.assertEqual(str(d), '456789')
534 d = nc.create_decimal('456789')
535 self.assertEqual(str(d), '4.57E+5')
Mark Dickinson59bc20b2008-01-12 01:56:00 +0000536 # leading and trailing whitespace should result in a NaN;
537 # spaces are already checked in Cowlishaw's test-suite, so
538 # here we just check that a trailing newline results in a NaN
539 self.assertEqual(str(nc.create_decimal('3.14\n')), 'NaN')
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000540
541 # from tuples
542 d = Decimal( (1, (4, 3, 4, 9, 1, 3, 5, 3, 4), -25) )
543 self.assertEqual(str(d), '-4.34913534E-17')
544 d = nc.create_decimal( (1, (4, 3, 4, 9, 1, 3, 5, 3, 4), -25) )
545 self.assertEqual(str(d), '-4.35E-17')
546
547 # from Decimal
548 prevdec = Decimal(500000123)
549 d = Decimal(prevdec)
550 self.assertEqual(str(d), '500000123')
551 d = nc.create_decimal(prevdec)
552 self.assertEqual(str(d), '5.00E+8')
553
Mark Dickinson4326ad82009-08-02 10:59:36 +0000554 def test_unicode_digits(self):
555 test_values = {
556 u'\uff11': '1',
557 u'\u0660.\u0660\u0663\u0667\u0662e-\u0663' : '0.0000372',
558 u'-nan\u0c68\u0c6a\u0c66\u0c66' : '-NaN2400',
559 }
560 for input, expected in test_values.items():
561 self.assertEqual(str(Decimal(input)), expected)
562
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000563
564class DecimalImplicitConstructionTest(unittest.TestCase):
565 '''Unit tests for Implicit Construction cases of Decimal.'''
566
567 def test_implicit_from_None(self):
568 self.assertRaises(TypeError, eval, 'Decimal(5) + None', globals())
569
570 def test_implicit_from_int(self):
571 #normal
572 self.assertEqual(str(Decimal(5) + 45), '50')
573 #exceeding precision
574 self.assertEqual(Decimal(5) + 123456789000, Decimal(123456789000))
575
576 def test_implicit_from_string(self):
577 self.assertRaises(TypeError, eval, 'Decimal(5) + "3"', globals())
578
579 def test_implicit_from_float(self):
580 self.assertRaises(TypeError, eval, 'Decimal(5) + 2.2', globals())
581
582 def test_implicit_from_Decimal(self):
583 self.assertEqual(Decimal(5) + Decimal(45), Decimal(50))
584
Raymond Hettinger267b8682005-03-27 10:47:39 +0000585 def test_rop(self):
586 # Allow other classes to be trained to interact with Decimals
587 class E:
588 def __divmod__(self, other):
589 return 'divmod ' + str(other)
590 def __rdivmod__(self, other):
591 return str(other) + ' rdivmod'
592 def __lt__(self, other):
593 return 'lt ' + str(other)
594 def __gt__(self, other):
595 return 'gt ' + str(other)
596 def __le__(self, other):
597 return 'le ' + str(other)
598 def __ge__(self, other):
599 return 'ge ' + str(other)
600 def __eq__(self, other):
601 return 'eq ' + str(other)
602 def __ne__(self, other):
603 return 'ne ' + str(other)
604
605 self.assertEqual(divmod(E(), Decimal(10)), 'divmod 10')
606 self.assertEqual(divmod(Decimal(10), E()), '10 rdivmod')
607 self.assertEqual(eval('Decimal(10) < E()'), 'gt 10')
608 self.assertEqual(eval('Decimal(10) > E()'), 'lt 10')
609 self.assertEqual(eval('Decimal(10) <= E()'), 'ge 10')
610 self.assertEqual(eval('Decimal(10) >= E()'), 'le 10')
611 self.assertEqual(eval('Decimal(10) == E()'), 'eq 10')
612 self.assertEqual(eval('Decimal(10) != E()'), 'ne 10')
613
614 # insert operator methods and then exercise them
Georg Brandl96c3f7f2006-03-28 08:06:35 +0000615 oplist = [
616 ('+', '__add__', '__radd__'),
617 ('-', '__sub__', '__rsub__'),
618 ('*', '__mul__', '__rmul__'),
619 ('%', '__mod__', '__rmod__'),
620 ('//', '__floordiv__', '__rfloordiv__'),
621 ('**', '__pow__', '__rpow__')
622 ]
Senthil Kumaran3ddc4352010-01-08 18:41:40 +0000623 # Silence Py3k warning
624 with check_warnings():
625 if 1/2 == 0:
626 # testing with classic division, so add __div__
627 oplist.append(('/', '__div__', '__rdiv__'))
628 else:
629 # testing with -Qnew, so add __truediv__
630 oplist.append(('/', '__truediv__', '__rtruediv__'))
Anthony Baxter4ef3a232006-03-30 12:59:11 +0000631
Georg Brandl96c3f7f2006-03-28 08:06:35 +0000632 for sym, lop, rop in oplist:
Raymond Hettinger267b8682005-03-27 10:47:39 +0000633 setattr(E, lop, lambda self, other: 'str' + lop + str(other))
634 setattr(E, rop, lambda self, other: str(other) + rop + 'str')
635 self.assertEqual(eval('E()' + sym + 'Decimal(10)'),
636 'str' + lop + '10')
637 self.assertEqual(eval('Decimal(10)' + sym + 'E()'),
638 '10' + rop + 'str')
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000639
Mark Dickinson277859d2009-03-17 23:03:46 +0000640
Mark Dickinson1ddf1d82008-02-29 02:16:37 +0000641class DecimalFormatTest(unittest.TestCase):
642 '''Unit tests for the format function.'''
643 def test_formatting(self):
644 # triples giving a format, a Decimal, and the expected result
645 test_values = [
646 ('e', '0E-15', '0e-15'),
647 ('e', '2.3E-15', '2.3e-15'),
648 ('e', '2.30E+2', '2.30e+2'), # preserve significant zeros
649 ('e', '2.30000E-15', '2.30000e-15'),
650 ('e', '1.23456789123456789e40', '1.23456789123456789e+40'),
651 ('e', '1.5', '1.5e+0'),
652 ('e', '0.15', '1.5e-1'),
653 ('e', '0.015', '1.5e-2'),
654 ('e', '0.0000000000015', '1.5e-12'),
655 ('e', '15.0', '1.50e+1'),
656 ('e', '-15', '-1.5e+1'),
657 ('e', '0', '0e+0'),
658 ('e', '0E1', '0e+1'),
659 ('e', '0.0', '0e-1'),
660 ('e', '0.00', '0e-2'),
661 ('.6e', '0E-15', '0.000000e-9'),
662 ('.6e', '0', '0.000000e+6'),
663 ('.6e', '9.999999', '9.999999e+0'),
664 ('.6e', '9.9999999', '1.000000e+1'),
665 ('.6e', '-1.23e5', '-1.230000e+5'),
666 ('.6e', '1.23456789e-3', '1.234568e-3'),
667 ('f', '0', '0'),
668 ('f', '0.0', '0.0'),
669 ('f', '0E-2', '0.00'),
670 ('f', '0.00E-8', '0.0000000000'),
671 ('f', '0E1', '0'), # loses exponent information
672 ('f', '3.2E1', '32'),
673 ('f', '3.2E2', '320'),
674 ('f', '3.20E2', '320'),
675 ('f', '3.200E2', '320.0'),
676 ('f', '3.2E-6', '0.0000032'),
677 ('.6f', '0E-15', '0.000000'), # all zeros treated equally
678 ('.6f', '0E1', '0.000000'),
679 ('.6f', '0', '0.000000'),
680 ('.0f', '0', '0'), # no decimal point
681 ('.0f', '0e-2', '0'),
682 ('.0f', '3.14159265', '3'),
683 ('.1f', '3.14159265', '3.1'),
684 ('.4f', '3.14159265', '3.1416'),
685 ('.6f', '3.14159265', '3.141593'),
686 ('.7f', '3.14159265', '3.1415926'), # round-half-even!
687 ('.8f', '3.14159265', '3.14159265'),
688 ('.9f', '3.14159265', '3.141592650'),
689
690 ('g', '0', '0'),
691 ('g', '0.0', '0.0'),
692 ('g', '0E1', '0e+1'),
693 ('G', '0E1', '0E+1'),
694 ('g', '0E-5', '0.00000'),
695 ('g', '0E-6', '0.000000'),
696 ('g', '0E-7', '0e-7'),
697 ('g', '-0E2', '-0e+2'),
698 ('.0g', '3.14159265', '3'), # 0 sig fig -> 1 sig fig
699 ('.1g', '3.14159265', '3'),
700 ('.2g', '3.14159265', '3.1'),
701 ('.5g', '3.14159265', '3.1416'),
702 ('.7g', '3.14159265', '3.141593'),
703 ('.8g', '3.14159265', '3.1415926'), # round-half-even!
704 ('.9g', '3.14159265', '3.14159265'),
705 ('.10g', '3.14159265', '3.14159265'), # don't pad
706
707 ('%', '0E1', '0%'),
708 ('%', '0E0', '0%'),
709 ('%', '0E-1', '0%'),
710 ('%', '0E-2', '0%'),
711 ('%', '0E-3', '0.0%'),
712 ('%', '0E-4', '0.00%'),
713
714 ('.3%', '0', '0.000%'), # all zeros treated equally
715 ('.3%', '0E10', '0.000%'),
716 ('.3%', '0E-10', '0.000%'),
717 ('.3%', '2.34', '234.000%'),
718 ('.3%', '1.234567', '123.457%'),
719 ('.0%', '1.23', '123%'),
720
721 ('e', 'NaN', 'NaN'),
722 ('f', '-NaN123', '-NaN123'),
723 ('+g', 'NaN456', '+NaN456'),
724 ('.3e', 'Inf', 'Infinity'),
725 ('.16f', '-Inf', '-Infinity'),
726 ('.0g', '-sNaN', '-sNaN'),
727
728 ('', '1.00', '1.00'),
Mark Dickinsonb065e522009-03-17 18:01:03 +0000729
Mark Dickinson277859d2009-03-17 23:03:46 +0000730 # test alignment and padding
Mark Dickinson5cfa8042009-09-08 20:20:19 +0000731 ('6', '123', ' 123'),
Mark Dickinsonb065e522009-03-17 18:01:03 +0000732 ('<6', '123', '123 '),
733 ('>6', '123', ' 123'),
734 ('^6', '123', ' 123 '),
735 ('=+6', '123', '+ 123'),
Mark Dickinson277859d2009-03-17 23:03:46 +0000736 ('#<10', 'NaN', 'NaN#######'),
737 ('#<10', '-4.3', '-4.3######'),
738 ('#<+10', '0.0130', '+0.0130###'),
739 ('#< 10', '0.0130', ' 0.0130###'),
740 ('@>10', '-Inf', '@-Infinity'),
741 ('#>5', '-Inf', '-Infinity'),
742 ('?^5', '123', '?123?'),
743 ('%^6', '123', '%123%%'),
744 (' ^6', '-45.6', '-45.6 '),
745 ('/=10', '-45.6', '-/////45.6'),
746 ('/=+10', '45.6', '+/////45.6'),
747 ('/= 10', '45.6', ' /////45.6'),
748
749 # thousands separator
750 (',', '1234567', '1,234,567'),
751 (',', '123456', '123,456'),
752 (',', '12345', '12,345'),
753 (',', '1234', '1,234'),
754 (',', '123', '123'),
755 (',', '12', '12'),
756 (',', '1', '1'),
757 (',', '0', '0'),
758 (',', '-1234567', '-1,234,567'),
759 (',', '-123456', '-123,456'),
760 ('7,', '123456', '123,456'),
Mark Dickinson5cfa8042009-09-08 20:20:19 +0000761 ('8,', '123456', ' 123,456'),
Mark Dickinson277859d2009-03-17 23:03:46 +0000762 ('08,', '123456', '0,123,456'), # special case: extra 0 needed
763 ('+08,', '123456', '+123,456'), # but not if there's a sign
764 (' 08,', '123456', ' 123,456'),
765 ('08,', '-123456', '-123,456'),
766 ('+09,', '123456', '+0,123,456'),
767 # ... with fractional part...
768 ('07,', '1234.56', '1,234.56'),
769 ('08,', '1234.56', '1,234.56'),
770 ('09,', '1234.56', '01,234.56'),
771 ('010,', '1234.56', '001,234.56'),
772 ('011,', '1234.56', '0,001,234.56'),
773 ('012,', '1234.56', '0,001,234.56'),
774 ('08,.1f', '1234.5', '01,234.5'),
775 # no thousands separators in fraction part
776 (',', '1.23456789', '1.23456789'),
777 (',%', '123.456789', '12,345.6789%'),
778 (',e', '123456', '1.23456e+5'),
779 (',E', '123456', '1.23456E+5'),
Mark Dickinson491ea552009-09-07 16:17:41 +0000780
781 # issue 6850
782 ('a=-7.0', '0.12345', 'aaaa0.1'),
Mark Dickinson1ddf1d82008-02-29 02:16:37 +0000783 ]
784 for fmt, d, result in test_values:
785 self.assertEqual(format(Decimal(d), fmt), result)
786
Mark Dickinson277859d2009-03-17 23:03:46 +0000787 def test_n_format(self):
788 try:
789 from locale import CHAR_MAX
790 except ImportError:
791 return
792
793 # Set up some localeconv-like dictionaries
794 en_US = {
795 'decimal_point' : '.',
796 'grouping' : [3, 3, 0],
797 'thousands_sep': ','
798 }
799
800 fr_FR = {
801 'decimal_point' : ',',
802 'grouping' : [CHAR_MAX],
803 'thousands_sep' : ''
804 }
805
806 ru_RU = {
807 'decimal_point' : ',',
808 'grouping' : [3, 3, 0],
809 'thousands_sep' : ' '
810 }
811
812 crazy = {
813 'decimal_point' : '&',
814 'grouping' : [1, 4, 2, CHAR_MAX],
815 'thousands_sep' : '-'
816 }
817
818
819 def get_fmt(x, locale, fmt='n'):
820 return Decimal.__format__(Decimal(x), fmt, _localeconv=locale)
821
822 self.assertEqual(get_fmt(Decimal('12.7'), en_US), '12.7')
823 self.assertEqual(get_fmt(Decimal('12.7'), fr_FR), '12,7')
824 self.assertEqual(get_fmt(Decimal('12.7'), ru_RU), '12,7')
825 self.assertEqual(get_fmt(Decimal('12.7'), crazy), '1-2&7')
826
827 self.assertEqual(get_fmt(123456789, en_US), '123,456,789')
828 self.assertEqual(get_fmt(123456789, fr_FR), '123456789')
829 self.assertEqual(get_fmt(123456789, ru_RU), '123 456 789')
830 self.assertEqual(get_fmt(1234567890123, crazy), '123456-78-9012-3')
831
832 self.assertEqual(get_fmt(123456789, en_US, '.6n'), '1.23457e+8')
833 self.assertEqual(get_fmt(123456789, fr_FR, '.6n'), '1,23457e+8')
834 self.assertEqual(get_fmt(123456789, ru_RU, '.6n'), '1,23457e+8')
835 self.assertEqual(get_fmt(123456789, crazy, '.6n'), '1&23457e+8')
836
Mark Dickinsonb14514a2009-03-18 08:22:51 +0000837 # zero padding
838 self.assertEqual(get_fmt(1234, fr_FR, '03n'), '1234')
839 self.assertEqual(get_fmt(1234, fr_FR, '04n'), '1234')
840 self.assertEqual(get_fmt(1234, fr_FR, '05n'), '01234')
841 self.assertEqual(get_fmt(1234, fr_FR, '06n'), '001234')
842
843 self.assertEqual(get_fmt(12345, en_US, '05n'), '12,345')
844 self.assertEqual(get_fmt(12345, en_US, '06n'), '12,345')
845 self.assertEqual(get_fmt(12345, en_US, '07n'), '012,345')
846 self.assertEqual(get_fmt(12345, en_US, '08n'), '0,012,345')
847 self.assertEqual(get_fmt(12345, en_US, '09n'), '0,012,345')
848 self.assertEqual(get_fmt(12345, en_US, '010n'), '00,012,345')
849
850 self.assertEqual(get_fmt(123456, crazy, '06n'), '1-2345-6')
851 self.assertEqual(get_fmt(123456, crazy, '07n'), '1-2345-6')
852 self.assertEqual(get_fmt(123456, crazy, '08n'), '1-2345-6')
853 self.assertEqual(get_fmt(123456, crazy, '09n'), '01-2345-6')
854 self.assertEqual(get_fmt(123456, crazy, '010n'), '0-01-2345-6')
855 self.assertEqual(get_fmt(123456, crazy, '011n'), '0-01-2345-6')
856 self.assertEqual(get_fmt(123456, crazy, '012n'), '00-01-2345-6')
857 self.assertEqual(get_fmt(123456, crazy, '013n'), '000-01-2345-6')
858
Mark Dickinson277859d2009-03-17 23:03:46 +0000859
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000860class DecimalArithmeticOperatorsTest(unittest.TestCase):
861 '''Unit tests for all arithmetic operators, binary and unary.'''
862
863 def test_addition(self):
864
865 d1 = Decimal('-11.1')
866 d2 = Decimal('22.2')
867
868 #two Decimals
869 self.assertEqual(d1+d2, Decimal('11.1'))
870 self.assertEqual(d2+d1, Decimal('11.1'))
871
872 #with other type, left
873 c = d1 + 5
874 self.assertEqual(c, Decimal('-6.1'))
875 self.assertEqual(type(c), type(d1))
876
877 #with other type, right
878 c = 5 + d1
879 self.assertEqual(c, Decimal('-6.1'))
880 self.assertEqual(type(c), type(d1))
881
882 #inline with decimal
883 d1 += d2
884 self.assertEqual(d1, Decimal('11.1'))
885
886 #inline with other type
887 d1 += 5
888 self.assertEqual(d1, Decimal('16.1'))
889
890 def test_subtraction(self):
891
892 d1 = Decimal('-11.1')
893 d2 = Decimal('22.2')
894
895 #two Decimals
896 self.assertEqual(d1-d2, Decimal('-33.3'))
897 self.assertEqual(d2-d1, Decimal('33.3'))
898
899 #with other type, left
900 c = d1 - 5
901 self.assertEqual(c, Decimal('-16.1'))
902 self.assertEqual(type(c), type(d1))
903
904 #with other type, right
905 c = 5 - d1
906 self.assertEqual(c, Decimal('16.1'))
907 self.assertEqual(type(c), type(d1))
908
909 #inline with decimal
910 d1 -= d2
911 self.assertEqual(d1, Decimal('-33.3'))
912
913 #inline with other type
914 d1 -= 5
915 self.assertEqual(d1, Decimal('-38.3'))
916
917 def test_multiplication(self):
918
919 d1 = Decimal('-5')
920 d2 = Decimal('3')
921
922 #two Decimals
923 self.assertEqual(d1*d2, Decimal('-15'))
924 self.assertEqual(d2*d1, Decimal('-15'))
925
926 #with other type, left
927 c = d1 * 5
928 self.assertEqual(c, Decimal('-25'))
929 self.assertEqual(type(c), type(d1))
930
931 #with other type, right
932 c = 5 * d1
933 self.assertEqual(c, Decimal('-25'))
934 self.assertEqual(type(c), type(d1))
935
936 #inline with decimal
937 d1 *= d2
938 self.assertEqual(d1, Decimal('-15'))
939
940 #inline with other type
941 d1 *= 5
942 self.assertEqual(d1, Decimal('-75'))
943
944 def test_division(self):
945
946 d1 = Decimal('-5')
947 d2 = Decimal('2')
948
949 #two Decimals
950 self.assertEqual(d1/d2, Decimal('-2.5'))
951 self.assertEqual(d2/d1, Decimal('-0.4'))
952
953 #with other type, left
954 c = d1 / 4
955 self.assertEqual(c, Decimal('-1.25'))
956 self.assertEqual(type(c), type(d1))
957
958 #with other type, right
959 c = 4 / d1
960 self.assertEqual(c, Decimal('-0.8'))
961 self.assertEqual(type(c), type(d1))
962
963 #inline with decimal
964 d1 /= d2
965 self.assertEqual(d1, Decimal('-2.5'))
966
967 #inline with other type
968 d1 /= 4
969 self.assertEqual(d1, Decimal('-0.625'))
970
971 def test_floor_division(self):
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000972
973 d1 = Decimal('5')
974 d2 = Decimal('2')
975
976 #two Decimals
977 self.assertEqual(d1//d2, Decimal('2'))
978 self.assertEqual(d2//d1, Decimal('0'))
979
980 #with other type, left
981 c = d1 // 4
982 self.assertEqual(c, Decimal('1'))
983 self.assertEqual(type(c), type(d1))
984
985 #with other type, right
986 c = 7 // d1
987 self.assertEqual(c, Decimal('1'))
988 self.assertEqual(type(c), type(d1))
989
990 #inline with decimal
991 d1 //= d2
992 self.assertEqual(d1, Decimal('2'))
993
994 #inline with other type
995 d1 //= 2
996 self.assertEqual(d1, Decimal('1'))
997
998 def test_powering(self):
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000999
1000 d1 = Decimal('5')
1001 d2 = Decimal('2')
1002
1003 #two Decimals
1004 self.assertEqual(d1**d2, Decimal('25'))
1005 self.assertEqual(d2**d1, Decimal('32'))
1006
1007 #with other type, left
1008 c = d1 ** 4
1009 self.assertEqual(c, Decimal('625'))
1010 self.assertEqual(type(c), type(d1))
1011
1012 #with other type, right
1013 c = 7 ** d1
1014 self.assertEqual(c, Decimal('16807'))
1015 self.assertEqual(type(c), type(d1))
1016
1017 #inline with decimal
1018 d1 **= d2
1019 self.assertEqual(d1, Decimal('25'))
1020
1021 #inline with other type
1022 d1 **= 4
1023 self.assertEqual(d1, Decimal('390625'))
1024
1025 def test_module(self):
1026
1027 d1 = Decimal('5')
1028 d2 = Decimal('2')
1029
1030 #two Decimals
1031 self.assertEqual(d1%d2, Decimal('1'))
1032 self.assertEqual(d2%d1, Decimal('2'))
1033
1034 #with other type, left
1035 c = d1 % 4
1036 self.assertEqual(c, Decimal('1'))
1037 self.assertEqual(type(c), type(d1))
1038
1039 #with other type, right
1040 c = 7 % d1
1041 self.assertEqual(c, Decimal('2'))
1042 self.assertEqual(type(c), type(d1))
1043
1044 #inline with decimal
1045 d1 %= d2
1046 self.assertEqual(d1, Decimal('1'))
1047
1048 #inline with other type
1049 d1 %= 4
1050 self.assertEqual(d1, Decimal('1'))
1051
1052 def test_floor_div_module(self):
1053
1054 d1 = Decimal('5')
1055 d2 = Decimal('2')
1056
1057 #two Decimals
1058 (p, q) = divmod(d1, d2)
1059 self.assertEqual(p, Decimal('2'))
1060 self.assertEqual(q, Decimal('1'))
1061 self.assertEqual(type(p), type(d1))
1062 self.assertEqual(type(q), type(d1))
1063
1064 #with other type, left
1065 (p, q) = divmod(d1, 4)
1066 self.assertEqual(p, Decimal('1'))
1067 self.assertEqual(q, Decimal('1'))
1068 self.assertEqual(type(p), type(d1))
1069 self.assertEqual(type(q), type(d1))
1070
1071 #with other type, right
1072 (p, q) = divmod(7, d1)
1073 self.assertEqual(p, Decimal('1'))
1074 self.assertEqual(q, Decimal('2'))
1075 self.assertEqual(type(p), type(d1))
1076 self.assertEqual(type(q), type(d1))
1077
1078 def test_unary_operators(self):
1079 self.assertEqual(+Decimal(45), Decimal(+45)) # +
1080 self.assertEqual(-Decimal(45), Decimal(-45)) # -
1081 self.assertEqual(abs(Decimal(45)), abs(Decimal(-45))) # abs
1082
Mark Dickinson2fc92632008-02-06 22:10:50 +00001083 def test_nan_comparisons(self):
1084 n = Decimal('NaN')
1085 s = Decimal('sNaN')
1086 i = Decimal('Inf')
1087 f = Decimal('2')
1088 for x, y in [(n, n), (n, i), (i, n), (n, f), (f, n),
1089 (s, n), (n, s), (s, i), (i, s), (s, f), (f, s), (s, s)]:
Benjamin Peterson5c8da862009-06-30 22:57:08 +00001090 self.assertTrue(x != y)
1091 self.assertTrue(not (x == y))
1092 self.assertTrue(not (x < y))
1093 self.assertTrue(not (x <= y))
1094 self.assertTrue(not (x > y))
1095 self.assertTrue(not (x >= y))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001096
1097# The following are two functions used to test threading in the next class
1098
1099def thfunc1(cls):
1100 d1 = Decimal(1)
1101 d3 = Decimal(3)
Facundo Batista64156672008-03-22 02:45:37 +00001102 test1 = d1/d3
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001103 cls.synchro.wait()
Facundo Batista64156672008-03-22 02:45:37 +00001104 test2 = d1/d3
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001105 cls.finish1.set()
Facundo Batista64156672008-03-22 02:45:37 +00001106
Facundo Batistaee340e52008-05-02 17:39:00 +00001107 cls.assertEqual(test1, Decimal('0.3333333333333333333333333333'))
1108 cls.assertEqual(test2, Decimal('0.3333333333333333333333333333'))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001109 return
1110
1111def thfunc2(cls):
1112 d1 = Decimal(1)
1113 d3 = Decimal(3)
Facundo Batista64156672008-03-22 02:45:37 +00001114 test1 = d1/d3
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001115 thiscontext = getcontext()
1116 thiscontext.prec = 18
Facundo Batista64156672008-03-22 02:45:37 +00001117 test2 = d1/d3
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001118 cls.synchro.set()
1119 cls.finish2.set()
Facundo Batista64156672008-03-22 02:45:37 +00001120
Facundo Batistaee340e52008-05-02 17:39:00 +00001121 cls.assertEqual(test1, Decimal('0.3333333333333333333333333333'))
Facundo Batista64156672008-03-22 02:45:37 +00001122 cls.assertEqual(test2, Decimal('0.333333333333333333'))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001123 return
1124
1125
1126class DecimalUseOfContextTest(unittest.TestCase):
1127 '''Unit tests for Use of Context cases in Decimal.'''
1128
Raymond Hettinger7e71fa52004-12-18 19:07:19 +00001129 try:
1130 import threading
1131 except ImportError:
1132 threading = None
1133
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001134 # Take care executing this test from IDLE, there's an issue in threading
1135 # that hangs IDLE and I couldn't find it
1136
1137 def test_threading(self):
1138 #Test the "threading isolation" of a Context.
1139
1140 self.synchro = threading.Event()
1141 self.finish1 = threading.Event()
1142 self.finish2 = threading.Event()
1143
1144 th1 = threading.Thread(target=thfunc1, args=(self,))
1145 th2 = threading.Thread(target=thfunc2, args=(self,))
1146
1147 th1.start()
1148 th2.start()
1149
1150 self.finish1.wait()
Thomas Woutersb3e6e8c2007-09-19 17:27:29 +00001151 self.finish2.wait()
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001152 return
1153
Raymond Hettinger7e71fa52004-12-18 19:07:19 +00001154 if threading is None:
1155 del test_threading
1156
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001157
1158class DecimalUsabilityTest(unittest.TestCase):
1159 '''Unit tests for Usability cases of Decimal.'''
1160
1161 def test_comparison_operators(self):
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001162
1163 da = Decimal('23.42')
1164 db = Decimal('23.42')
1165 dc = Decimal('45')
1166
1167 #two Decimals
Benjamin Peterson5c8da862009-06-30 22:57:08 +00001168 self.assertTrue(dc > da)
1169 self.assertTrue(dc >= da)
1170 self.assertTrue(da < dc)
1171 self.assertTrue(da <= dc)
1172 self.assertTrue(da == db)
1173 self.assertTrue(da != dc)
1174 self.assertTrue(da <= db)
1175 self.assertTrue(da >= db)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001176 self.assertEqual(cmp(dc,da), 1)
1177 self.assertEqual(cmp(da,dc), -1)
1178 self.assertEqual(cmp(da,db), 0)
1179
1180 #a Decimal and an int
Benjamin Peterson5c8da862009-06-30 22:57:08 +00001181 self.assertTrue(dc > 23)
1182 self.assertTrue(23 < dc)
1183 self.assertTrue(dc == 45)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001184 self.assertEqual(cmp(dc,23), 1)
1185 self.assertEqual(cmp(23,dc), -1)
1186 self.assertEqual(cmp(dc,45), 0)
1187
1188 #a Decimal and uncomparable
Raymond Hettinger0aeac102004-07-05 22:53:03 +00001189 self.assertNotEqual(da, 'ugly')
1190 self.assertNotEqual(da, 32.7)
1191 self.assertNotEqual(da, object())
1192 self.assertNotEqual(da, object)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001193
Raymond Hettinger0aeac102004-07-05 22:53:03 +00001194 # sortable
1195 a = map(Decimal, xrange(100))
1196 b = a[:]
1197 random.shuffle(a)
1198 a.sort()
1199 self.assertEqual(a, b)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001200
Facundo Batista353750c2007-09-13 18:13:15 +00001201 # with None
Senthil Kumaran3ddc4352010-01-08 18:41:40 +00001202 # Silence Py3k warning
1203 with check_warnings():
1204 self.assertFalse(Decimal(1) < None)
1205 self.assertTrue(Decimal(1) > None)
Facundo Batista353750c2007-09-13 18:13:15 +00001206
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001207 def test_copy_and_deepcopy_methods(self):
1208 d = Decimal('43.24')
1209 c = copy.copy(d)
1210 self.assertEqual(id(c), id(d))
1211 dc = copy.deepcopy(d)
1212 self.assertEqual(id(dc), id(d))
1213
1214 def test_hash_method(self):
1215 #just that it's hashable
1216 hash(Decimal(23))
Facundo Batista8c202442007-09-19 17:53:25 +00001217
1218 test_values = [Decimal(sign*(2**m + n))
1219 for m in [0, 14, 15, 16, 17, 30, 31,
1220 32, 33, 62, 63, 64, 65, 66]
1221 for n in range(-10, 10)
1222 for sign in [-1, 1]]
1223 test_values.extend([
1224 Decimal("-0"), # zeros
1225 Decimal("0.00"),
1226 Decimal("-0.000"),
1227 Decimal("0E10"),
1228 Decimal("-0E12"),
1229 Decimal("10.0"), # negative exponent
1230 Decimal("-23.00000"),
1231 Decimal("1230E100"), # positive exponent
1232 Decimal("-4.5678E50"),
1233 # a value for which hash(n) != hash(n % (2**64-1))
1234 # in Python pre-2.6
1235 Decimal(2**64 + 2**32 - 1),
1236 # selection of values which fail with the old (before
1237 # version 2.6) long.__hash__
1238 Decimal("1.634E100"),
1239 Decimal("90.697E100"),
1240 Decimal("188.83E100"),
1241 Decimal("1652.9E100"),
1242 Decimal("56531E100"),
1243 ])
1244
1245 # check that hash(d) == hash(int(d)) for integral values
1246 for value in test_values:
1247 self.assertEqual(hash(value), hash(int(value)))
1248
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001249 #the same hash that to an int
1250 self.assertEqual(hash(Decimal(23)), hash(23))
Raymond Hettingerbea3f6f2005-03-15 04:59:17 +00001251 self.assertRaises(TypeError, hash, Decimal('NaN'))
Benjamin Peterson5c8da862009-06-30 22:57:08 +00001252 self.assertTrue(hash(Decimal('Inf')))
1253 self.assertTrue(hash(Decimal('-Inf')))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001254
Facundo Batista52b25792008-01-08 12:25:20 +00001255 # check that the value of the hash doesn't depend on the
1256 # current context (issue #1757)
1257 c = getcontext()
1258 old_precision = c.prec
1259 x = Decimal("123456789.1")
1260
1261 c.prec = 6
1262 h1 = hash(x)
1263 c.prec = 10
1264 h2 = hash(x)
1265 c.prec = 16
1266 h3 = hash(x)
1267
1268 self.assertEqual(h1, h2)
1269 self.assertEqual(h1, h3)
1270 c.prec = old_precision
1271
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001272 def test_min_and_max_methods(self):
1273
1274 d1 = Decimal('15.32')
1275 d2 = Decimal('28.5')
1276 l1 = 15
1277 l2 = 28
1278
1279 #between Decimals
Benjamin Peterson5c8da862009-06-30 22:57:08 +00001280 self.assertTrue(min(d1,d2) is d1)
1281 self.assertTrue(min(d2,d1) is d1)
1282 self.assertTrue(max(d1,d2) is d2)
1283 self.assertTrue(max(d2,d1) is d2)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001284
1285 #between Decimal and long
Benjamin Peterson5c8da862009-06-30 22:57:08 +00001286 self.assertTrue(min(d1,l2) is d1)
1287 self.assertTrue(min(l2,d1) is d1)
1288 self.assertTrue(max(l1,d2) is d2)
1289 self.assertTrue(max(d2,l1) is d2)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001290
1291 def test_as_nonzero(self):
1292 #as false
Benjamin Peterson5c8da862009-06-30 22:57:08 +00001293 self.assertFalse(Decimal(0))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001294 #as true
Benjamin Peterson5c8da862009-06-30 22:57:08 +00001295 self.assertTrue(Decimal('0.372'))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001296
1297 def test_tostring_methods(self):
1298 #Test str and repr methods.
1299
1300 d = Decimal('15.32')
1301 self.assertEqual(str(d), '15.32') # str
Raymond Hettingerabe32372008-02-14 02:41:22 +00001302 self.assertEqual(repr(d), "Decimal('15.32')") # repr
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001303
Mark Dickinson8e85ffa2008-03-25 18:47:59 +00001304 # result type of string methods should be str, not unicode
1305 unicode_inputs = [u'123.4', u'0.5E2', u'Infinity', u'sNaN',
1306 u'-0.0E100', u'-NaN001', u'-Inf']
1307
1308 for u in unicode_inputs:
1309 d = Decimal(u)
1310 self.assertEqual(type(str(d)), str)
1311 self.assertEqual(type(repr(d)), str)
1312 self.assertEqual(type(d.to_eng_string()), str)
1313
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001314 def test_tonum_methods(self):
1315 #Test float, int and long methods.
1316
1317 d1 = Decimal('66')
1318 d2 = Decimal('15.32')
1319
1320 #int
1321 self.assertEqual(int(d1), 66)
1322 self.assertEqual(int(d2), 15)
1323
1324 #long
1325 self.assertEqual(long(d1), 66)
1326 self.assertEqual(long(d2), 15)
1327
1328 #float
1329 self.assertEqual(float(d1), 66)
1330 self.assertEqual(float(d2), 15.32)
1331
1332 def test_eval_round_trip(self):
1333
1334 #with zero
1335 d = Decimal( (0, (0,), 0) )
1336 self.assertEqual(d, eval(repr(d)))
1337
1338 #int
1339 d = Decimal( (1, (4, 5), 0) )
1340 self.assertEqual(d, eval(repr(d)))
1341
1342 #float
1343 d = Decimal( (0, (4, 5, 3, 4), -2) )
1344 self.assertEqual(d, eval(repr(d)))
1345
1346 #weird
1347 d = Decimal( (1, (4, 3, 4, 9, 1, 3, 5, 3, 4), -25) )
1348 self.assertEqual(d, eval(repr(d)))
1349
1350 def test_as_tuple(self):
1351
1352 #with zero
1353 d = Decimal(0)
1354 self.assertEqual(d.as_tuple(), (0, (0,), 0) )
1355
1356 #int
1357 d = Decimal(-45)
1358 self.assertEqual(d.as_tuple(), (1, (4, 5), 0) )
1359
1360 #complicated string
1361 d = Decimal("-4.34913534E-17")
1362 self.assertEqual(d.as_tuple(), (1, (4, 3, 4, 9, 1, 3, 5, 3, 4), -25) )
1363
1364 #inf
1365 d = Decimal("Infinity")
1366 self.assertEqual(d.as_tuple(), (0, (0,), 'F') )
1367
Facundo Batista9b5e2312007-10-19 19:25:57 +00001368 #leading zeros in coefficient should be stripped
1369 d = Decimal( (0, (0, 0, 4, 0, 5, 3, 4), -2) )
1370 self.assertEqual(d.as_tuple(), (0, (4, 0, 5, 3, 4), -2) )
1371 d = Decimal( (1, (0, 0, 0), 37) )
1372 self.assertEqual(d.as_tuple(), (1, (0,), 37))
1373 d = Decimal( (1, (), 37) )
1374 self.assertEqual(d.as_tuple(), (1, (0,), 37))
1375
1376 #leading zeros in NaN diagnostic info should be stripped
1377 d = Decimal( (0, (0, 0, 4, 0, 5, 3, 4), 'n') )
1378 self.assertEqual(d.as_tuple(), (0, (4, 0, 5, 3, 4), 'n') )
1379 d = Decimal( (1, (0, 0, 0), 'N') )
1380 self.assertEqual(d.as_tuple(), (1, (), 'N') )
1381 d = Decimal( (1, (), 'n') )
1382 self.assertEqual(d.as_tuple(), (1, (), 'n') )
1383
1384 #coefficient in infinity should be ignored
1385 d = Decimal( (0, (4, 5, 3, 4), 'F') )
1386 self.assertEqual(d.as_tuple(), (0, (0,), 'F'))
1387 d = Decimal( (1, (0, 2, 7, 1), 'F') )
1388 self.assertEqual(d.as_tuple(), (1, (0,), 'F'))
1389
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001390 def test_immutability_operations(self):
1391 # Do operations and check that it didn't change change internal objects.
1392
1393 d1 = Decimal('-25e55')
1394 b1 = Decimal('-25e55')
Facundo Batista353750c2007-09-13 18:13:15 +00001395 d2 = Decimal('33e+33')
1396 b2 = Decimal('33e+33')
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001397
1398 def checkSameDec(operation, useOther=False):
1399 if useOther:
1400 eval("d1." + operation + "(d2)")
1401 self.assertEqual(d1._sign, b1._sign)
1402 self.assertEqual(d1._int, b1._int)
1403 self.assertEqual(d1._exp, b1._exp)
1404 self.assertEqual(d2._sign, b2._sign)
1405 self.assertEqual(d2._int, b2._int)
1406 self.assertEqual(d2._exp, b2._exp)
1407 else:
1408 eval("d1." + operation + "()")
1409 self.assertEqual(d1._sign, b1._sign)
1410 self.assertEqual(d1._int, b1._int)
1411 self.assertEqual(d1._exp, b1._exp)
1412 return
1413
1414 Decimal(d1)
1415 self.assertEqual(d1._sign, b1._sign)
1416 self.assertEqual(d1._int, b1._int)
1417 self.assertEqual(d1._exp, b1._exp)
1418
1419 checkSameDec("__abs__")
1420 checkSameDec("__add__", True)
1421 checkSameDec("__div__", True)
1422 checkSameDec("__divmod__", True)
Mark Dickinson2fc92632008-02-06 22:10:50 +00001423 checkSameDec("__eq__", True)
1424 checkSameDec("__ne__", True)
1425 checkSameDec("__le__", True)
1426 checkSameDec("__lt__", True)
1427 checkSameDec("__ge__", True)
1428 checkSameDec("__gt__", True)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001429 checkSameDec("__float__")
1430 checkSameDec("__floordiv__", True)
1431 checkSameDec("__hash__")
1432 checkSameDec("__int__")
Raymond Hettinger5a053642008-01-24 19:05:29 +00001433 checkSameDec("__trunc__")
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001434 checkSameDec("__long__")
1435 checkSameDec("__mod__", True)
1436 checkSameDec("__mul__", True)
1437 checkSameDec("__neg__")
1438 checkSameDec("__nonzero__")
1439 checkSameDec("__pos__")
1440 checkSameDec("__pow__", True)
1441 checkSameDec("__radd__", True)
1442 checkSameDec("__rdiv__", True)
1443 checkSameDec("__rdivmod__", True)
1444 checkSameDec("__repr__")
1445 checkSameDec("__rfloordiv__", True)
1446 checkSameDec("__rmod__", True)
1447 checkSameDec("__rmul__", True)
1448 checkSameDec("__rpow__", True)
1449 checkSameDec("__rsub__", True)
1450 checkSameDec("__str__")
1451 checkSameDec("__sub__", True)
1452 checkSameDec("__truediv__", True)
1453 checkSameDec("adjusted")
1454 checkSameDec("as_tuple")
1455 checkSameDec("compare", True)
1456 checkSameDec("max", True)
1457 checkSameDec("min", True)
1458 checkSameDec("normalize")
1459 checkSameDec("quantize", True)
1460 checkSameDec("remainder_near", True)
1461 checkSameDec("same_quantum", True)
1462 checkSameDec("sqrt")
1463 checkSameDec("to_eng_string")
1464 checkSameDec("to_integral")
1465
Facundo Batista6c398da2007-09-17 17:30:13 +00001466 def test_subclassing(self):
1467 # Different behaviours when subclassing Decimal
1468
1469 class MyDecimal(Decimal):
1470 pass
1471
1472 d1 = MyDecimal(1)
1473 d2 = MyDecimal(2)
1474 d = d1 + d2
1475 self.assertTrue(type(d) is Decimal)
1476
1477 d = d1.max(d2)
1478 self.assertTrue(type(d) is Decimal)
1479
Mark Dickinson3b24ccb2008-03-25 14:33:23 +00001480 def test_implicit_context(self):
1481 # Check results when context given implicitly. (Issue 2478)
1482 c = getcontext()
1483 self.assertEqual(str(Decimal(0).sqrt()),
1484 str(c.sqrt(Decimal(0))))
1485
Mark Dickinson0c673122009-10-29 12:04:00 +00001486 def test_conversions_from_int(self):
1487 # Check that methods taking a second Decimal argument will
1488 # always accept an integer in place of a Decimal.
1489 self.assertEqual(Decimal(4).compare(3),
1490 Decimal(4).compare(Decimal(3)))
1491 self.assertEqual(Decimal(4).compare_signal(3),
1492 Decimal(4).compare_signal(Decimal(3)))
1493 self.assertEqual(Decimal(4).compare_total(3),
1494 Decimal(4).compare_total(Decimal(3)))
1495 self.assertEqual(Decimal(4).compare_total_mag(3),
1496 Decimal(4).compare_total_mag(Decimal(3)))
1497 self.assertEqual(Decimal(10101).logical_and(1001),
1498 Decimal(10101).logical_and(Decimal(1001)))
1499 self.assertEqual(Decimal(10101).logical_or(1001),
1500 Decimal(10101).logical_or(Decimal(1001)))
1501 self.assertEqual(Decimal(10101).logical_xor(1001),
1502 Decimal(10101).logical_xor(Decimal(1001)))
1503 self.assertEqual(Decimal(567).max(123),
1504 Decimal(567).max(Decimal(123)))
1505 self.assertEqual(Decimal(567).max_mag(123),
1506 Decimal(567).max_mag(Decimal(123)))
1507 self.assertEqual(Decimal(567).min(123),
1508 Decimal(567).min(Decimal(123)))
1509 self.assertEqual(Decimal(567).min_mag(123),
1510 Decimal(567).min_mag(Decimal(123)))
1511 self.assertEqual(Decimal(567).next_toward(123),
1512 Decimal(567).next_toward(Decimal(123)))
1513 self.assertEqual(Decimal(1234).quantize(100),
1514 Decimal(1234).quantize(Decimal(100)))
1515 self.assertEqual(Decimal(768).remainder_near(1234),
1516 Decimal(768).remainder_near(Decimal(1234)))
1517 self.assertEqual(Decimal(123).rotate(1),
1518 Decimal(123).rotate(Decimal(1)))
1519 self.assertEqual(Decimal(1234).same_quantum(1000),
1520 Decimal(1234).same_quantum(Decimal(1000)))
1521 self.assertEqual(Decimal('9.123').scaleb(-100),
1522 Decimal('9.123').scaleb(Decimal(-100)))
1523 self.assertEqual(Decimal(456).shift(-1),
1524 Decimal(456).shift(Decimal(-1)))
1525
1526 self.assertEqual(Decimal(-12).fma(Decimal(45), 67),
1527 Decimal(-12).fma(Decimal(45), Decimal(67)))
1528 self.assertEqual(Decimal(-12).fma(45, 67),
1529 Decimal(-12).fma(Decimal(45), Decimal(67)))
1530 self.assertEqual(Decimal(-12).fma(45, Decimal(67)),
1531 Decimal(-12).fma(Decimal(45), Decimal(67)))
1532
Facundo Batista6c398da2007-09-17 17:30:13 +00001533
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001534class DecimalPythonAPItests(unittest.TestCase):
1535
Raymond Hettinger2c8585b2009-02-03 03:37:03 +00001536 def test_abc(self):
Benjamin Peterson5c8da862009-06-30 22:57:08 +00001537 self.assertTrue(issubclass(Decimal, numbers.Number))
1538 self.assertTrue(not issubclass(Decimal, numbers.Real))
1539 self.assertTrue(isinstance(Decimal(0), numbers.Number))
1540 self.assertTrue(not isinstance(Decimal(0), numbers.Real))
Raymond Hettinger2c8585b2009-02-03 03:37:03 +00001541
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001542 def test_pickle(self):
1543 d = Decimal('-3.141590000')
1544 p = pickle.dumps(d)
1545 e = pickle.loads(p)
1546 self.assertEqual(d, e)
1547
Raymond Hettinger5548be22004-07-05 18:49:38 +00001548 def test_int(self):
Raymond Hettinger605ed022004-11-24 07:28:48 +00001549 for x in range(-250, 250):
1550 s = '%0.2f' % (x / 100.0)
Raymond Hettinger5548be22004-07-05 18:49:38 +00001551 # should work the same as for floats
1552 self.assertEqual(int(Decimal(s)), int(float(s)))
Raymond Hettinger605ed022004-11-24 07:28:48 +00001553 # should work the same as to_integral in the ROUND_DOWN mode
Raymond Hettinger5548be22004-07-05 18:49:38 +00001554 d = Decimal(s)
Raymond Hettinger605ed022004-11-24 07:28:48 +00001555 r = d.to_integral(ROUND_DOWN)
Raymond Hettinger5548be22004-07-05 18:49:38 +00001556 self.assertEqual(Decimal(int(d)), r)
1557
Mark Dickinson968f1692009-09-07 18:04:58 +00001558 self.assertRaises(ValueError, int, Decimal('-nan'))
1559 self.assertRaises(ValueError, int, Decimal('snan'))
1560 self.assertRaises(OverflowError, int, Decimal('inf'))
1561 self.assertRaises(OverflowError, int, Decimal('-inf'))
1562
1563 self.assertRaises(ValueError, long, Decimal('-nan'))
1564 self.assertRaises(ValueError, long, Decimal('snan'))
1565 self.assertRaises(OverflowError, long, Decimal('inf'))
1566 self.assertRaises(OverflowError, long, Decimal('-inf'))
1567
Raymond Hettinger5a053642008-01-24 19:05:29 +00001568 def test_trunc(self):
1569 for x in range(-250, 250):
1570 s = '%0.2f' % (x / 100.0)
1571 # should work the same as for floats
1572 self.assertEqual(int(Decimal(s)), int(float(s)))
1573 # should work the same as to_integral in the ROUND_DOWN mode
1574 d = Decimal(s)
1575 r = d.to_integral(ROUND_DOWN)
Jeffrey Yasskinca2b69f2008-02-01 06:22:46 +00001576 self.assertEqual(Decimal(math.trunc(d)), r)
Raymond Hettinger5a053642008-01-24 19:05:29 +00001577
Raymond Hettingerf4d85972009-01-03 19:02:23 +00001578 def test_from_float(self):
1579
1580 class MyDecimal(Decimal):
1581 pass
1582
1583 r = MyDecimal.from_float(0.1)
1584 self.assertEqual(type(r), MyDecimal)
1585 self.assertEqual(str(r),
1586 '0.1000000000000000055511151231257827021181583404541015625')
1587 bigint = 12345678901234567890123456789
1588 self.assertEqual(MyDecimal.from_float(bigint), MyDecimal(bigint))
Benjamin Peterson5c8da862009-06-30 22:57:08 +00001589 self.assertTrue(MyDecimal.from_float(float('nan')).is_qnan())
1590 self.assertTrue(MyDecimal.from_float(float('inf')).is_infinite())
1591 self.assertTrue(MyDecimal.from_float(float('-inf')).is_infinite())
Raymond Hettingerf4d85972009-01-03 19:02:23 +00001592 self.assertEqual(str(MyDecimal.from_float(float('nan'))),
1593 str(Decimal('NaN')))
1594 self.assertEqual(str(MyDecimal.from_float(float('inf'))),
1595 str(Decimal('Infinity')))
1596 self.assertEqual(str(MyDecimal.from_float(float('-inf'))),
1597 str(Decimal('-Infinity')))
1598 self.assertRaises(TypeError, MyDecimal.from_float, 'abc')
1599 for i in range(200):
1600 x = random.expovariate(0.01) * (random.random() * 2.0 - 1.0)
1601 self.assertEqual(x, float(MyDecimal.from_float(x))) # roundtrip
1602
1603 def test_create_decimal_from_float(self):
1604 context = Context(prec=5, rounding=ROUND_DOWN)
1605 self.assertEqual(
1606 context.create_decimal_from_float(math.pi),
1607 Decimal('3.1415')
1608 )
1609 context = Context(prec=5, rounding=ROUND_UP)
1610 self.assertEqual(
1611 context.create_decimal_from_float(math.pi),
1612 Decimal('3.1416')
1613 )
1614 context = Context(prec=5, traps=[Inexact])
1615 self.assertRaises(
1616 Inexact,
1617 context.create_decimal_from_float,
1618 math.pi
1619 )
1620 self.assertEqual(repr(context.create_decimal_from_float(-0.0)),
1621 "Decimal('-0')")
1622 self.assertEqual(repr(context.create_decimal_from_float(1.0)),
1623 "Decimal('1')")
1624 self.assertEqual(repr(context.create_decimal_from_float(10)),
1625 "Decimal('10')")
1626
Raymond Hettingerd9c0a7a2004-07-03 10:02:28 +00001627class ContextAPItests(unittest.TestCase):
1628
1629 def test_pickle(self):
1630 c = Context()
1631 e = pickle.loads(pickle.dumps(c))
1632 for k in vars(c):
1633 v1 = vars(c)[k]
1634 v2 = vars(e)[k]
1635 self.assertEqual(v1, v2)
1636
Raymond Hettinger0aeac102004-07-05 22:53:03 +00001637 def test_equality_with_other_types(self):
Benjamin Peterson5c8da862009-06-30 22:57:08 +00001638 self.assertTrue(Decimal(10) in ['a', 1.0, Decimal(10), (1,2), {}])
1639 self.assertTrue(Decimal(10) not in ['a', 1.0, (1,2), {}])
Raymond Hettinger0aeac102004-07-05 22:53:03 +00001640
Raymond Hettinger955d2b22004-08-08 20:17:45 +00001641 def test_copy(self):
1642 # All copies should be deep
1643 c = Context()
1644 d = c.copy()
1645 self.assertNotEqual(id(c), id(d))
1646 self.assertNotEqual(id(c.flags), id(d.flags))
1647 self.assertNotEqual(id(c.traps), id(d.traps))
1648
Nick Coghlan8b6999b2006-08-31 12:00:43 +00001649class WithStatementTest(unittest.TestCase):
1650 # Can't do these as docstrings until Python 2.6
1651 # as doctest can't handle __future__ statements
Nick Coghlan8b6999b2006-08-31 12:00:43 +00001652
1653 def test_localcontext(self):
Nick Coghlanced12182006-09-02 03:54:17 +00001654 # Use a copy of the current context in the block
Nick Coghlan8b6999b2006-08-31 12:00:43 +00001655 orig_ctx = getcontext()
1656 with localcontext() as enter_ctx:
1657 set_ctx = getcontext()
1658 final_ctx = getcontext()
Benjamin Peterson5c8da862009-06-30 22:57:08 +00001659 self.assertTrue(orig_ctx is final_ctx, 'did not restore context correctly')
1660 self.assertTrue(orig_ctx is not set_ctx, 'did not copy the context')
1661 self.assertTrue(set_ctx is enter_ctx, '__enter__ returned wrong context')
Nick Coghlan8b6999b2006-08-31 12:00:43 +00001662
1663 def test_localcontextarg(self):
Nick Coghlanced12182006-09-02 03:54:17 +00001664 # Use a copy of the supplied context in the block
Nick Coghlan8b6999b2006-08-31 12:00:43 +00001665 orig_ctx = getcontext()
1666 new_ctx = Context(prec=42)
1667 with localcontext(new_ctx) as enter_ctx:
1668 set_ctx = getcontext()
1669 final_ctx = getcontext()
Benjamin Peterson5c8da862009-06-30 22:57:08 +00001670 self.assertTrue(orig_ctx is final_ctx, 'did not restore context correctly')
1671 self.assertTrue(set_ctx.prec == new_ctx.prec, 'did not set correct context')
1672 self.assertTrue(new_ctx is not set_ctx, 'did not copy the context')
1673 self.assertTrue(set_ctx is enter_ctx, '__enter__ returned wrong context')
Nick Coghlan8b6999b2006-08-31 12:00:43 +00001674
Facundo Batista353750c2007-09-13 18:13:15 +00001675class ContextFlags(unittest.TestCase):
1676 def test_flags_irrelevant(self):
1677 # check that the result (numeric result + flags raised) of an
1678 # arithmetic operation doesn't depend on the current flags
1679
1680 context = Context(prec=9, Emin = -999999999, Emax = 999999999,
1681 rounding=ROUND_HALF_EVEN, traps=[], flags=[])
1682
1683 # operations that raise various flags, in the form (function, arglist)
1684 operations = [
1685 (context._apply, [Decimal("100E-1000000009")]),
1686 (context.sqrt, [Decimal(2)]),
1687 (context.add, [Decimal("1.23456789"), Decimal("9.87654321")]),
1688 (context.multiply, [Decimal("1.23456789"), Decimal("9.87654321")]),
1689 (context.subtract, [Decimal("1.23456789"), Decimal("9.87654321")]),
1690 ]
1691
1692 # try various flags individually, then a whole lot at once
1693 flagsets = [[Inexact], [Rounded], [Underflow], [Clamped], [Subnormal],
1694 [Inexact, Rounded, Underflow, Clamped, Subnormal]]
1695
1696 for fn, args in operations:
1697 # find answer and flags raised using a clean context
1698 context.clear_flags()
1699 ans = fn(*args)
1700 flags = [k for k, v in context.flags.items() if v]
1701
1702 for extra_flags in flagsets:
1703 # set flags, before calling operation
1704 context.clear_flags()
1705 for flag in extra_flags:
1706 context._raise_error(flag)
1707 new_ans = fn(*args)
1708
1709 # flags that we expect to be set after the operation
1710 expected_flags = list(flags)
1711 for flag in extra_flags:
1712 if flag not in expected_flags:
1713 expected_flags.append(flag)
Facundo Batista353750c2007-09-13 18:13:15 +00001714
1715 # flags we actually got
1716 new_flags = [k for k,v in context.flags.items() if v]
Senthil Kumaran3ddc4352010-01-08 18:41:40 +00001717
1718 # Silence Py3k warning
1719 with check_warnings():
1720 expected_flags.sort()
1721 new_flags.sort()
Facundo Batista353750c2007-09-13 18:13:15 +00001722
1723 self.assertEqual(ans, new_ans,
1724 "operation produces different answers depending on flags set: " +
1725 "expected %s, got %s." % (ans, new_ans))
1726 self.assertEqual(new_flags, expected_flags,
1727 "operation raises different flags depending on flags set: " +
1728 "expected %s, got %s" % (expected_flags, new_flags))
1729
1730def test_main(arith=False, verbose=None, todo_tests=None, debug=None):
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001731 """ Execute the tests.
1732
Raymond Hettingered20ad82004-09-04 20:09:13 +00001733 Runs all arithmetic tests if arith is True or if the "decimal" resource
1734 is enabled in regrtest.py
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001735 """
Raymond Hettingered20ad82004-09-04 20:09:13 +00001736
Neal Norwitzce4a9c92006-04-09 08:36:46 +00001737 init()
Facundo Batista353750c2007-09-13 18:13:15 +00001738 global TEST_ALL, DEBUG
Raymond Hettingered20ad82004-09-04 20:09:13 +00001739 TEST_ALL = arith or is_resource_enabled('decimal')
Facundo Batista353750c2007-09-13 18:13:15 +00001740 DEBUG = debug
Raymond Hettingered20ad82004-09-04 20:09:13 +00001741
Facundo Batista353750c2007-09-13 18:13:15 +00001742 if todo_tests is None:
1743 test_classes = [
1744 DecimalExplicitConstructionTest,
1745 DecimalImplicitConstructionTest,
1746 DecimalArithmeticOperatorsTest,
Mark Dickinson1ddf1d82008-02-29 02:16:37 +00001747 DecimalFormatTest,
Facundo Batista353750c2007-09-13 18:13:15 +00001748 DecimalUseOfContextTest,
1749 DecimalUsabilityTest,
1750 DecimalPythonAPItests,
1751 ContextAPItests,
1752 DecimalTest,
1753 WithStatementTest,
1754 ContextFlags
1755 ]
1756 else:
1757 test_classes = [DecimalTest]
1758
1759 # Dynamically build custom test definition for each file in the test
1760 # directory and add the definitions to the DecimalTest class. This
1761 # procedure insures that new files do not get skipped.
1762 for filename in os.listdir(directory):
1763 if '.decTest' not in filename or filename.startswith("."):
1764 continue
1765 head, tail = filename.split('.')
1766 if todo_tests is not None and head not in todo_tests:
1767 continue
1768 tester = lambda self, f=filename: self.eval_file(directory + f)
1769 setattr(DecimalTest, 'test_' + head, tester)
1770 del filename, head, tail, tester
1771
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001772
Tim Peters46cc7022006-03-31 04:11:16 +00001773 try:
1774 run_unittest(*test_classes)
Facundo Batista353750c2007-09-13 18:13:15 +00001775 if todo_tests is None:
1776 import decimal as DecimalModule
1777 run_doctest(DecimalModule, verbose)
Tim Peters46cc7022006-03-31 04:11:16 +00001778 finally:
1779 setcontext(ORIGINAL_CONTEXT)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001780
1781if __name__ == '__main__':
Facundo Batista353750c2007-09-13 18:13:15 +00001782 import optparse
1783 p = optparse.OptionParser("test_decimal.py [--debug] [{--skip | test1 [test2 [...]]}]")
1784 p.add_option('--debug', '-d', action='store_true', help='shows the test number and context before each test')
1785 p.add_option('--skip', '-s', action='store_true', help='skip over 90% of the arithmetic tests')
1786 (opt, args) = p.parse_args()
1787
1788 if opt.skip:
1789 test_main(arith=False, verbose=True)
1790 elif args:
1791 test_main(arith=True, verbose=True, todo_tests=args, debug=opt.debug)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001792 else:
Facundo Batista353750c2007-09-13 18:13:15 +00001793 test_main(arith=True, verbose=True)