blob: bf7d3b233431d300d63e76d4db5a6a4226a72990 [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
Christian Heimes400adb02008-02-01 08:12:03 +000028import math
Raymond Hettinger7c85fa42004-07-01 11:01:35 +000029import os, sys
30import pickle, copy
Christian Heimes400adb02008-02-01 08:12:03 +000031import unittest
Raymond Hettinger7c85fa42004-07-01 11:01:35 +000032from decimal import *
Raymond Hettinger82417ca2009-02-03 03:54:28 +000033import numbers
Benjamin Petersone549ead2009-03-28 21:42:05 +000034from 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
Guido van Rossumc1f779c2007-07-03 08:25:58 +000042Signals = tuple(getcontext().flags.keys())
Raymond Hettingerfed52962004-07-14 15:41:57 +000043
Thomas Wouters49fd7fa2006-04-21 10:40:58 +000044# Tests are built around these assumed context defaults.
45# test_main() restores the original context.
46def init():
47 global ORIGINAL_CONTEXT
48 ORIGINAL_CONTEXT = getcontext().copy()
Christian Heimes81ee3ef2008-05-04 22:42:01 +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 Dickinsond08fb832009-10-08 16:33:06 +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,
Thomas Wouters1b7f8912007-09-19 03:06:30 +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
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000107nameAdapter = {'and':'logical_and',
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000108 'apply':'_apply',
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000109 'class':'number_class',
110 'comparesig':'compare_signal',
111 'comparetotal':'compare_total',
112 'comparetotmag':'compare_total_mag',
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000113 'copy':'copy_decimal',
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000114 'copyabs':'copy_abs',
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000115 'copynegate':'copy_negate',
116 'copysign':'copy_sign',
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000117 'divideint':'divide_int',
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000118 'invert':'logical_invert',
Guido van Rossum8ce8a782007-11-01 19:42:39 +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',
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000129 'maxmag':'max_mag',
130 'minmag':'min_mag',
131 'nextminus':'next_minus',
132 'nextplus':'next_plus',
133 'nexttoward':'next_toward',
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000134 'or':'logical_or',
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000135 'reduce':'normalize',
Guido van Rossum8ce8a782007-11-01 19:42:39 +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
Guido van Rossum8ce8a782007-11-01 19:42:39 +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
Thomas Wouters1b7f8912007-09-19 03:06:30 +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 (
Thomas Wouters1b7f8912007-09-19 03:06:30 +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 Petersone549ead2009-03-28 21:42:05 +0000203 raise unittest.SkipTest
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000204 return
Neal Norwitz70967602006-03-17 08:29:44 +0000205 for line in open(file):
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000206 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)
Guido van Rossumb940e112007-01-10 16:19:56 +0000210 except DecimalException as exception:
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000211 #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):
Guido van Rossumc1f779c2007-07-03 08:25:58 +0000235 funct, value = (x.strip().lower() for x in s.split(':'))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000236 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]
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000258 if DEBUG:
259 print("Test ", id, end=" ")
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 Dickinsond08fb832009-10-08 16:33:06 +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
Guido van Rossumb940e112007-01-10 16:19:56 +0000307 except Signals as 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:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000315 v = Decimal(v, self.context)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000316 vals.append(v)
317
318 ans = FixQuotes(ans)
319
Thomas Wouters1b7f8912007-09-19 03:06:30 +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
Guido van Rossumb940e112007-01-10 16:19:56 +0000343 except Signals as 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
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000349 if DEBUG:
350 print("--", self.context)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000351 try:
352 result = str(funct(*vals))
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000353 if fname in LOGICAL_FUNCTIONS:
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000354 result = str(int(eval(result))) # 'True', 'False' -> '1', '0'
Guido van Rossumb940e112007-01-10 16:19:56 +0000355 except Signals as 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.
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000358 print("ERROR:", s)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000359 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
Guido van Rossum47b9ff62006-08-24 00:41:19 +0000364 myexceptions.sort(key=repr)
365 theirexceptions.sort(key=repr)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000366
367 self.assertEqual(result, ans,
368 'Incorrect answer for ' + s + ' -- got ' + result)
369 self.assertEqual(myexceptions, theirexceptions,
Thomas Wouters1b7f8912007-09-19 03:06:30 +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
Christian Heimesa62da1d2008-01-12 19:39:10 +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
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000439 def test_explicit_from_tuples(self):
440
441 #zero
442 d = Decimal( (0, (0,), 0) )
443 self.assertEqual(str(d), '0')
444
445 #int
446 d = Decimal( (1, (4, 5), 0) )
447 self.assertEqual(str(d), '-45')
448
449 #float
450 d = Decimal( (0, (4, 5, 3, 4), -2) )
451 self.assertEqual(str(d), '45.34')
452
453 #weird
454 d = Decimal( (1, (4, 3, 4, 9, 1, 3, 5, 3, 4), -25) )
455 self.assertEqual(str(d), '-4.34913534E-17')
456
457 #wrong number of items
458 self.assertRaises(ValueError, Decimal, (1, (4, 3, 4, 9, 1)) )
459
460 #bad sign
461 self.assertRaises(ValueError, Decimal, (8, (4, 3, 4, 9, 1), 2) )
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000462 self.assertRaises(ValueError, Decimal, (0., (4, 3, 4, 9, 1), 2) )
463 self.assertRaises(ValueError, Decimal, (Decimal(1), (4, 3, 4, 9, 1), 2))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000464
465 #bad exp
466 self.assertRaises(ValueError, Decimal, (1, (4, 3, 4, 9, 1), 'wrong!') )
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000467 self.assertRaises(ValueError, Decimal, (1, (4, 3, 4, 9, 1), 0.) )
468 self.assertRaises(ValueError, Decimal, (1, (4, 3, 4, 9, 1), '1') )
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000469
470 #bad coefficients
471 self.assertRaises(ValueError, Decimal, (1, (4, 3, 4, None, 1), 2) )
472 self.assertRaises(ValueError, Decimal, (1, (4, -3, 4, 9, 1), 2) )
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000473 self.assertRaises(ValueError, Decimal, (1, (4, 10, 4, 9, 1), 2) )
Guido van Rossum0d3fb8a2007-11-26 23:23:18 +0000474 self.assertRaises(ValueError, Decimal, (1, (4, 3, 4, 'a', 1), 2) )
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000475
476 def test_explicit_from_Decimal(self):
477
478 #positive
479 d = Decimal(45)
480 e = Decimal(d)
481 self.assertEqual(str(e), '45')
482 self.assertNotEqual(id(d), id(e))
483
484 #very large positive
485 d = Decimal(500000123)
486 e = Decimal(d)
487 self.assertEqual(str(e), '500000123')
488 self.assertNotEqual(id(d), id(e))
489
490 #negative
491 d = Decimal(-45)
492 e = Decimal(d)
493 self.assertEqual(str(e), '-45')
494 self.assertNotEqual(id(d), id(e))
495
496 #zero
497 d = Decimal(0)
498 e = Decimal(d)
499 self.assertEqual(str(e), '0')
500 self.assertNotEqual(id(d), id(e))
501
502 def test_explicit_context_create_decimal(self):
503
504 nc = copy.copy(getcontext())
505 nc.prec = 3
506
507 # empty
Raymond Hettingerfed52962004-07-14 15:41:57 +0000508 d = Decimal()
509 self.assertEqual(str(d), '0')
510 d = nc.create_decimal()
511 self.assertEqual(str(d), '0')
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000512
513 # from None
514 self.assertRaises(TypeError, nc.create_decimal, None)
515
516 # from int
517 d = nc.create_decimal(456)
Georg Brandlab91fde2009-08-13 08:51:18 +0000518 self.assertTrue(isinstance(d, Decimal))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000519 self.assertEqual(nc.create_decimal(45678),
520 nc.create_decimal('457E+2'))
521
522 # from string
523 d = Decimal('456789')
524 self.assertEqual(str(d), '456789')
525 d = nc.create_decimal('456789')
526 self.assertEqual(str(d), '4.57E+5')
Christian Heimesa62da1d2008-01-12 19:39:10 +0000527 # leading and trailing whitespace should result in a NaN;
528 # spaces are already checked in Cowlishaw's test-suite, so
529 # here we just check that a trailing newline results in a NaN
530 self.assertEqual(str(nc.create_decimal('3.14\n')), 'NaN')
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000531
532 # from tuples
533 d = Decimal( (1, (4, 3, 4, 9, 1, 3, 5, 3, 4), -25) )
534 self.assertEqual(str(d), '-4.34913534E-17')
535 d = nc.create_decimal( (1, (4, 3, 4, 9, 1, 3, 5, 3, 4), -25) )
536 self.assertEqual(str(d), '-4.35E-17')
537
538 # from Decimal
539 prevdec = Decimal(500000123)
540 d = Decimal(prevdec)
541 self.assertEqual(str(d), '500000123')
542 d = nc.create_decimal(prevdec)
543 self.assertEqual(str(d), '5.00E+8')
544
Mark Dickinson8d238292009-08-02 10:16:33 +0000545 def test_unicode_digits(self):
546 test_values = {
547 '\uff11': '1',
548 '\u0660.\u0660\u0663\u0667\u0662e-\u0663' : '0.0000372',
549 '-nan\u0c68\u0c6a\u0c66\u0c66' : '-NaN2400',
550 }
551 for input, expected in test_values.items():
552 self.assertEqual(str(Decimal(input)), expected)
553
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000554
555class DecimalImplicitConstructionTest(unittest.TestCase):
556 '''Unit tests for Implicit Construction cases of Decimal.'''
557
558 def test_implicit_from_None(self):
559 self.assertRaises(TypeError, eval, 'Decimal(5) + None', globals())
560
561 def test_implicit_from_int(self):
562 #normal
563 self.assertEqual(str(Decimal(5) + 45), '50')
564 #exceeding precision
565 self.assertEqual(Decimal(5) + 123456789000, Decimal(123456789000))
566
567 def test_implicit_from_string(self):
568 self.assertRaises(TypeError, eval, 'Decimal(5) + "3"', globals())
569
570 def test_implicit_from_float(self):
571 self.assertRaises(TypeError, eval, 'Decimal(5) + 2.2', globals())
572
573 def test_implicit_from_Decimal(self):
574 self.assertEqual(Decimal(5) + Decimal(45), Decimal(50))
575
Raymond Hettinger267b8682005-03-27 10:47:39 +0000576 def test_rop(self):
577 # Allow other classes to be trained to interact with Decimals
578 class E:
579 def __divmod__(self, other):
580 return 'divmod ' + str(other)
581 def __rdivmod__(self, other):
582 return str(other) + ' rdivmod'
583 def __lt__(self, other):
584 return 'lt ' + str(other)
585 def __gt__(self, other):
586 return 'gt ' + str(other)
587 def __le__(self, other):
588 return 'le ' + str(other)
589 def __ge__(self, other):
590 return 'ge ' + str(other)
591 def __eq__(self, other):
592 return 'eq ' + str(other)
593 def __ne__(self, other):
594 return 'ne ' + str(other)
595
596 self.assertEqual(divmod(E(), Decimal(10)), 'divmod 10')
597 self.assertEqual(divmod(Decimal(10), E()), '10 rdivmod')
598 self.assertEqual(eval('Decimal(10) < E()'), 'gt 10')
599 self.assertEqual(eval('Decimal(10) > E()'), 'lt 10')
600 self.assertEqual(eval('Decimal(10) <= E()'), 'ge 10')
601 self.assertEqual(eval('Decimal(10) >= E()'), 'le 10')
602 self.assertEqual(eval('Decimal(10) == E()'), 'eq 10')
603 self.assertEqual(eval('Decimal(10) != E()'), 'ne 10')
604
605 # insert operator methods and then exercise them
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000606 oplist = [
607 ('+', '__add__', '__radd__'),
608 ('-', '__sub__', '__rsub__'),
609 ('*', '__mul__', '__rmul__'),
Thomas Woutersdcc6d322006-04-21 11:30:52 +0000610 ('/', '__truediv__', '__rtruediv__'),
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000611 ('%', '__mod__', '__rmod__'),
612 ('//', '__floordiv__', '__rfloordiv__'),
613 ('**', '__pow__', '__rpow__')
614 ]
Raymond Hettinger267b8682005-03-27 10:47:39 +0000615
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000616 for sym, lop, rop in oplist:
Raymond Hettinger267b8682005-03-27 10:47:39 +0000617 setattr(E, lop, lambda self, other: 'str' + lop + str(other))
618 setattr(E, rop, lambda self, other: str(other) + rop + 'str')
619 self.assertEqual(eval('E()' + sym + 'Decimal(10)'),
620 'str' + lop + '10')
621 self.assertEqual(eval('Decimal(10)' + sym + 'E()'),
622 '10' + rop + 'str')
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000623
Mark Dickinson79f52032009-03-17 23:12:51 +0000624
Christian Heimesf16baeb2008-02-29 14:57:44 +0000625class DecimalFormatTest(unittest.TestCase):
626 '''Unit tests for the format function.'''
627 def test_formatting(self):
628 # triples giving a format, a Decimal, and the expected result
629 test_values = [
630 ('e', '0E-15', '0e-15'),
631 ('e', '2.3E-15', '2.3e-15'),
632 ('e', '2.30E+2', '2.30e+2'), # preserve significant zeros
633 ('e', '2.30000E-15', '2.30000e-15'),
634 ('e', '1.23456789123456789e40', '1.23456789123456789e+40'),
635 ('e', '1.5', '1.5e+0'),
636 ('e', '0.15', '1.5e-1'),
637 ('e', '0.015', '1.5e-2'),
638 ('e', '0.0000000000015', '1.5e-12'),
639 ('e', '15.0', '1.50e+1'),
640 ('e', '-15', '-1.5e+1'),
641 ('e', '0', '0e+0'),
642 ('e', '0E1', '0e+1'),
643 ('e', '0.0', '0e-1'),
644 ('e', '0.00', '0e-2'),
645 ('.6e', '0E-15', '0.000000e-9'),
646 ('.6e', '0', '0.000000e+6'),
647 ('.6e', '9.999999', '9.999999e+0'),
648 ('.6e', '9.9999999', '1.000000e+1'),
649 ('.6e', '-1.23e5', '-1.230000e+5'),
650 ('.6e', '1.23456789e-3', '1.234568e-3'),
651 ('f', '0', '0'),
652 ('f', '0.0', '0.0'),
653 ('f', '0E-2', '0.00'),
654 ('f', '0.00E-8', '0.0000000000'),
655 ('f', '0E1', '0'), # loses exponent information
656 ('f', '3.2E1', '32'),
657 ('f', '3.2E2', '320'),
658 ('f', '3.20E2', '320'),
659 ('f', '3.200E2', '320.0'),
660 ('f', '3.2E-6', '0.0000032'),
661 ('.6f', '0E-15', '0.000000'), # all zeros treated equally
662 ('.6f', '0E1', '0.000000'),
663 ('.6f', '0', '0.000000'),
664 ('.0f', '0', '0'), # no decimal point
665 ('.0f', '0e-2', '0'),
666 ('.0f', '3.14159265', '3'),
667 ('.1f', '3.14159265', '3.1'),
668 ('.4f', '3.14159265', '3.1416'),
669 ('.6f', '3.14159265', '3.141593'),
670 ('.7f', '3.14159265', '3.1415926'), # round-half-even!
671 ('.8f', '3.14159265', '3.14159265'),
672 ('.9f', '3.14159265', '3.141592650'),
673
674 ('g', '0', '0'),
675 ('g', '0.0', '0.0'),
676 ('g', '0E1', '0e+1'),
677 ('G', '0E1', '0E+1'),
678 ('g', '0E-5', '0.00000'),
679 ('g', '0E-6', '0.000000'),
680 ('g', '0E-7', '0e-7'),
681 ('g', '-0E2', '-0e+2'),
682 ('.0g', '3.14159265', '3'), # 0 sig fig -> 1 sig fig
683 ('.1g', '3.14159265', '3'),
684 ('.2g', '3.14159265', '3.1'),
685 ('.5g', '3.14159265', '3.1416'),
686 ('.7g', '3.14159265', '3.141593'),
687 ('.8g', '3.14159265', '3.1415926'), # round-half-even!
688 ('.9g', '3.14159265', '3.14159265'),
689 ('.10g', '3.14159265', '3.14159265'), # don't pad
690
691 ('%', '0E1', '0%'),
692 ('%', '0E0', '0%'),
693 ('%', '0E-1', '0%'),
694 ('%', '0E-2', '0%'),
695 ('%', '0E-3', '0.0%'),
696 ('%', '0E-4', '0.00%'),
697
698 ('.3%', '0', '0.000%'), # all zeros treated equally
699 ('.3%', '0E10', '0.000%'),
700 ('.3%', '0E-10', '0.000%'),
701 ('.3%', '2.34', '234.000%'),
702 ('.3%', '1.234567', '123.457%'),
703 ('.0%', '1.23', '123%'),
704
705 ('e', 'NaN', 'NaN'),
706 ('f', '-NaN123', '-NaN123'),
707 ('+g', 'NaN456', '+NaN456'),
708 ('.3e', 'Inf', 'Infinity'),
709 ('.16f', '-Inf', '-Infinity'),
710 ('.0g', '-sNaN', '-sNaN'),
711
712 ('', '1.00', '1.00'),
Mark Dickinsonad416342009-03-17 18:10:15 +0000713
Mark Dickinson79f52032009-03-17 23:12:51 +0000714 # test alignment and padding
Mark Dickinsonad416342009-03-17 18:10:15 +0000715 ('<6', '123', '123 '),
716 ('>6', '123', ' 123'),
717 ('^6', '123', ' 123 '),
718 ('=+6', '123', '+ 123'),
Mark Dickinson79f52032009-03-17 23:12:51 +0000719 ('#<10', 'NaN', 'NaN#######'),
720 ('#<10', '-4.3', '-4.3######'),
721 ('#<+10', '0.0130', '+0.0130###'),
722 ('#< 10', '0.0130', ' 0.0130###'),
723 ('@>10', '-Inf', '@-Infinity'),
724 ('#>5', '-Inf', '-Infinity'),
725 ('?^5', '123', '?123?'),
726 ('%^6', '123', '%123%%'),
727 (' ^6', '-45.6', '-45.6 '),
728 ('/=10', '-45.6', '-/////45.6'),
729 ('/=+10', '45.6', '+/////45.6'),
730 ('/= 10', '45.6', ' /////45.6'),
731
732 # thousands separator
733 (',', '1234567', '1,234,567'),
734 (',', '123456', '123,456'),
735 (',', '12345', '12,345'),
736 (',', '1234', '1,234'),
737 (',', '123', '123'),
738 (',', '12', '12'),
739 (',', '1', '1'),
740 (',', '0', '0'),
741 (',', '-1234567', '-1,234,567'),
742 (',', '-123456', '-123,456'),
743 ('7,', '123456', '123,456'),
744 ('8,', '123456', '123,456 '),
745 ('08,', '123456', '0,123,456'), # special case: extra 0 needed
746 ('+08,', '123456', '+123,456'), # but not if there's a sign
747 (' 08,', '123456', ' 123,456'),
748 ('08,', '-123456', '-123,456'),
749 ('+09,', '123456', '+0,123,456'),
750 # ... with fractional part...
751 ('07,', '1234.56', '1,234.56'),
752 ('08,', '1234.56', '1,234.56'),
753 ('09,', '1234.56', '01,234.56'),
754 ('010,', '1234.56', '001,234.56'),
755 ('011,', '1234.56', '0,001,234.56'),
756 ('012,', '1234.56', '0,001,234.56'),
757 ('08,.1f', '1234.5', '01,234.5'),
758 # no thousands separators in fraction part
759 (',', '1.23456789', '1.23456789'),
760 (',%', '123.456789', '12,345.6789%'),
761 (',e', '123456', '1.23456e+5'),
762 (',E', '123456', '1.23456E+5'),
Mark Dickinsond496d302009-09-07 16:23:26 +0000763
764 # issue 6850
765 ('a=-7.0', '0.12345', 'aaaa0.1'),
Christian Heimesf16baeb2008-02-29 14:57:44 +0000766 ]
767 for fmt, d, result in test_values:
768 self.assertEqual(format(Decimal(d), fmt), result)
769
Mark Dickinson79f52032009-03-17 23:12:51 +0000770 def test_n_format(self):
771 try:
772 from locale import CHAR_MAX
773 except ImportError:
774 return
775
776 # Set up some localeconv-like dictionaries
777 en_US = {
778 'decimal_point' : '.',
779 'grouping' : [3, 3, 0],
780 'thousands_sep': ','
781 }
782
783 fr_FR = {
784 'decimal_point' : ',',
785 'grouping' : [CHAR_MAX],
786 'thousands_sep' : ''
787 }
788
789 ru_RU = {
790 'decimal_point' : ',',
791 'grouping' : [3, 3, 0],
792 'thousands_sep' : ' '
793 }
794
795 crazy = {
796 'decimal_point' : '&',
797 'grouping' : [1, 4, 2, CHAR_MAX],
798 'thousands_sep' : '-'
799 }
800
801
802 def get_fmt(x, locale, fmt='n'):
803 return Decimal.__format__(Decimal(x), fmt, _localeconv=locale)
804
805 self.assertEqual(get_fmt(Decimal('12.7'), en_US), '12.7')
806 self.assertEqual(get_fmt(Decimal('12.7'), fr_FR), '12,7')
807 self.assertEqual(get_fmt(Decimal('12.7'), ru_RU), '12,7')
808 self.assertEqual(get_fmt(Decimal('12.7'), crazy), '1-2&7')
809
810 self.assertEqual(get_fmt(123456789, en_US), '123,456,789')
811 self.assertEqual(get_fmt(123456789, fr_FR), '123456789')
812 self.assertEqual(get_fmt(123456789, ru_RU), '123 456 789')
813 self.assertEqual(get_fmt(1234567890123, crazy), '123456-78-9012-3')
814
815 self.assertEqual(get_fmt(123456789, en_US, '.6n'), '1.23457e+8')
816 self.assertEqual(get_fmt(123456789, fr_FR, '.6n'), '1,23457e+8')
817 self.assertEqual(get_fmt(123456789, ru_RU, '.6n'), '1,23457e+8')
818 self.assertEqual(get_fmt(123456789, crazy, '.6n'), '1&23457e+8')
819
Mark Dickinson7303b592009-03-18 08:25:36 +0000820 # zero padding
821 self.assertEqual(get_fmt(1234, fr_FR, '03n'), '1234')
822 self.assertEqual(get_fmt(1234, fr_FR, '04n'), '1234')
823 self.assertEqual(get_fmt(1234, fr_FR, '05n'), '01234')
824 self.assertEqual(get_fmt(1234, fr_FR, '06n'), '001234')
825
826 self.assertEqual(get_fmt(12345, en_US, '05n'), '12,345')
827 self.assertEqual(get_fmt(12345, en_US, '06n'), '12,345')
828 self.assertEqual(get_fmt(12345, en_US, '07n'), '012,345')
829 self.assertEqual(get_fmt(12345, en_US, '08n'), '0,012,345')
830 self.assertEqual(get_fmt(12345, en_US, '09n'), '0,012,345')
831 self.assertEqual(get_fmt(12345, en_US, '010n'), '00,012,345')
832
833 self.assertEqual(get_fmt(123456, crazy, '06n'), '1-2345-6')
834 self.assertEqual(get_fmt(123456, crazy, '07n'), '1-2345-6')
835 self.assertEqual(get_fmt(123456, crazy, '08n'), '1-2345-6')
836 self.assertEqual(get_fmt(123456, crazy, '09n'), '01-2345-6')
837 self.assertEqual(get_fmt(123456, crazy, '010n'), '0-01-2345-6')
838 self.assertEqual(get_fmt(123456, crazy, '011n'), '0-01-2345-6')
839 self.assertEqual(get_fmt(123456, crazy, '012n'), '00-01-2345-6')
840 self.assertEqual(get_fmt(123456, crazy, '013n'), '000-01-2345-6')
841
Mark Dickinson79f52032009-03-17 23:12:51 +0000842
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000843class DecimalArithmeticOperatorsTest(unittest.TestCase):
844 '''Unit tests for all arithmetic operators, binary and unary.'''
845
846 def test_addition(self):
847
848 d1 = Decimal('-11.1')
849 d2 = Decimal('22.2')
850
851 #two Decimals
852 self.assertEqual(d1+d2, Decimal('11.1'))
853 self.assertEqual(d2+d1, Decimal('11.1'))
854
855 #with other type, left
856 c = d1 + 5
857 self.assertEqual(c, Decimal('-6.1'))
858 self.assertEqual(type(c), type(d1))
859
860 #with other type, right
861 c = 5 + d1
862 self.assertEqual(c, Decimal('-6.1'))
863 self.assertEqual(type(c), type(d1))
864
865 #inline with decimal
866 d1 += d2
867 self.assertEqual(d1, Decimal('11.1'))
868
869 #inline with other type
870 d1 += 5
871 self.assertEqual(d1, Decimal('16.1'))
872
873 def test_subtraction(self):
874
875 d1 = Decimal('-11.1')
876 d2 = Decimal('22.2')
877
878 #two Decimals
879 self.assertEqual(d1-d2, Decimal('-33.3'))
880 self.assertEqual(d2-d1, Decimal('33.3'))
881
882 #with other type, left
883 c = d1 - 5
884 self.assertEqual(c, Decimal('-16.1'))
885 self.assertEqual(type(c), type(d1))
886
887 #with other type, right
888 c = 5 - d1
889 self.assertEqual(c, Decimal('16.1'))
890 self.assertEqual(type(c), type(d1))
891
892 #inline with decimal
893 d1 -= d2
894 self.assertEqual(d1, Decimal('-33.3'))
895
896 #inline with other type
897 d1 -= 5
898 self.assertEqual(d1, Decimal('-38.3'))
899
900 def test_multiplication(self):
901
902 d1 = Decimal('-5')
903 d2 = Decimal('3')
904
905 #two Decimals
906 self.assertEqual(d1*d2, Decimal('-15'))
907 self.assertEqual(d2*d1, Decimal('-15'))
908
909 #with other type, left
910 c = d1 * 5
911 self.assertEqual(c, Decimal('-25'))
912 self.assertEqual(type(c), type(d1))
913
914 #with other type, right
915 c = 5 * d1
916 self.assertEqual(c, Decimal('-25'))
917 self.assertEqual(type(c), type(d1))
918
919 #inline with decimal
920 d1 *= d2
921 self.assertEqual(d1, Decimal('-15'))
922
923 #inline with other type
924 d1 *= 5
925 self.assertEqual(d1, Decimal('-75'))
926
927 def test_division(self):
928
929 d1 = Decimal('-5')
930 d2 = Decimal('2')
931
932 #two Decimals
933 self.assertEqual(d1/d2, Decimal('-2.5'))
934 self.assertEqual(d2/d1, Decimal('-0.4'))
935
936 #with other type, left
937 c = d1 / 4
938 self.assertEqual(c, Decimal('-1.25'))
939 self.assertEqual(type(c), type(d1))
940
941 #with other type, right
942 c = 4 / d1
943 self.assertEqual(c, Decimal('-0.8'))
944 self.assertEqual(type(c), type(d1))
945
946 #inline with decimal
947 d1 /= d2
948 self.assertEqual(d1, Decimal('-2.5'))
949
950 #inline with other type
951 d1 /= 4
952 self.assertEqual(d1, Decimal('-0.625'))
953
954 def test_floor_division(self):
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000955
956 d1 = Decimal('5')
957 d2 = Decimal('2')
958
959 #two Decimals
960 self.assertEqual(d1//d2, Decimal('2'))
961 self.assertEqual(d2//d1, Decimal('0'))
962
963 #with other type, left
964 c = d1 // 4
965 self.assertEqual(c, Decimal('1'))
966 self.assertEqual(type(c), type(d1))
967
968 #with other type, right
969 c = 7 // d1
970 self.assertEqual(c, Decimal('1'))
971 self.assertEqual(type(c), type(d1))
972
973 #inline with decimal
974 d1 //= d2
975 self.assertEqual(d1, Decimal('2'))
976
977 #inline with other type
978 d1 //= 2
979 self.assertEqual(d1, Decimal('1'))
980
981 def test_powering(self):
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000982
983 d1 = Decimal('5')
984 d2 = Decimal('2')
985
986 #two Decimals
987 self.assertEqual(d1**d2, Decimal('25'))
988 self.assertEqual(d2**d1, Decimal('32'))
989
990 #with other type, left
991 c = d1 ** 4
992 self.assertEqual(c, Decimal('625'))
993 self.assertEqual(type(c), type(d1))
994
995 #with other type, right
996 c = 7 ** d1
997 self.assertEqual(c, Decimal('16807'))
998 self.assertEqual(type(c), type(d1))
999
1000 #inline with decimal
1001 d1 **= d2
1002 self.assertEqual(d1, Decimal('25'))
1003
1004 #inline with other type
1005 d1 **= 4
1006 self.assertEqual(d1, Decimal('390625'))
1007
1008 def test_module(self):
1009
1010 d1 = Decimal('5')
1011 d2 = Decimal('2')
1012
1013 #two Decimals
1014 self.assertEqual(d1%d2, Decimal('1'))
1015 self.assertEqual(d2%d1, Decimal('2'))
1016
1017 #with other type, left
1018 c = d1 % 4
1019 self.assertEqual(c, Decimal('1'))
1020 self.assertEqual(type(c), type(d1))
1021
1022 #with other type, right
1023 c = 7 % d1
1024 self.assertEqual(c, Decimal('2'))
1025 self.assertEqual(type(c), type(d1))
1026
1027 #inline with decimal
1028 d1 %= d2
1029 self.assertEqual(d1, Decimal('1'))
1030
1031 #inline with other type
1032 d1 %= 4
1033 self.assertEqual(d1, Decimal('1'))
1034
1035 def test_floor_div_module(self):
1036
1037 d1 = Decimal('5')
1038 d2 = Decimal('2')
1039
1040 #two Decimals
1041 (p, q) = divmod(d1, d2)
1042 self.assertEqual(p, Decimal('2'))
1043 self.assertEqual(q, Decimal('1'))
1044 self.assertEqual(type(p), type(d1))
1045 self.assertEqual(type(q), type(d1))
1046
1047 #with other type, left
1048 (p, q) = divmod(d1, 4)
1049 self.assertEqual(p, Decimal('1'))
1050 self.assertEqual(q, Decimal('1'))
1051 self.assertEqual(type(p), type(d1))
1052 self.assertEqual(type(q), type(d1))
1053
1054 #with other type, right
1055 (p, q) = divmod(7, d1)
1056 self.assertEqual(p, Decimal('1'))
1057 self.assertEqual(q, Decimal('2'))
1058 self.assertEqual(type(p), type(d1))
1059 self.assertEqual(type(q), type(d1))
1060
1061 def test_unary_operators(self):
1062 self.assertEqual(+Decimal(45), Decimal(+45)) # +
1063 self.assertEqual(-Decimal(45), Decimal(-45)) # -
1064 self.assertEqual(abs(Decimal(45)), abs(Decimal(-45))) # abs
1065
Christian Heimes77c02eb2008-02-09 02:18:51 +00001066 def test_nan_comparisons(self):
1067 n = Decimal('NaN')
1068 s = Decimal('sNaN')
1069 i = Decimal('Inf')
1070 f = Decimal('2')
1071 for x, y in [(n, n), (n, i), (i, n), (n, f), (f, n),
1072 (s, n), (n, s), (s, i), (i, s), (s, f), (f, s), (s, s)]:
Georg Brandlab91fde2009-08-13 08:51:18 +00001073 self.assertTrue(x != y)
1074 self.assertTrue(not (x == y))
1075 self.assertTrue(not (x < y))
1076 self.assertTrue(not (x <= y))
1077 self.assertTrue(not (x > y))
1078 self.assertTrue(not (x >= y))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001079
1080# The following are two functions used to test threading in the next class
1081
1082def thfunc1(cls):
1083 d1 = Decimal(1)
1084 d3 = Decimal(3)
Christian Heimesfe337bf2008-03-23 21:54:12 +00001085 test1 = d1/d3
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001086 cls.synchro.wait()
Christian Heimesfe337bf2008-03-23 21:54:12 +00001087 test2 = d1/d3
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001088 cls.finish1.set()
Christian Heimesfe337bf2008-03-23 21:54:12 +00001089
Christian Heimes81ee3ef2008-05-04 22:42:01 +00001090 cls.assertEqual(test1, Decimal('0.3333333333333333333333333333'))
1091 cls.assertEqual(test2, Decimal('0.3333333333333333333333333333'))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001092 return
1093
1094def thfunc2(cls):
1095 d1 = Decimal(1)
1096 d3 = Decimal(3)
Christian Heimesfe337bf2008-03-23 21:54:12 +00001097 test1 = d1/d3
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001098 thiscontext = getcontext()
1099 thiscontext.prec = 18
Christian Heimesfe337bf2008-03-23 21:54:12 +00001100 test2 = d1/d3
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001101 cls.synchro.set()
1102 cls.finish2.set()
Christian Heimesfe337bf2008-03-23 21:54:12 +00001103
Christian Heimes81ee3ef2008-05-04 22:42:01 +00001104 cls.assertEqual(test1, Decimal('0.3333333333333333333333333333'))
Christian Heimesfe337bf2008-03-23 21:54:12 +00001105 cls.assertEqual(test2, Decimal('0.333333333333333333'))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001106 return
1107
1108
1109class DecimalUseOfContextTest(unittest.TestCase):
1110 '''Unit tests for Use of Context cases in Decimal.'''
1111
Raymond Hettinger7e71fa52004-12-18 19:07:19 +00001112 try:
1113 import threading
1114 except ImportError:
1115 threading = None
1116
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001117 # Take care executing this test from IDLE, there's an issue in threading
1118 # that hangs IDLE and I couldn't find it
1119
1120 def test_threading(self):
1121 #Test the "threading isolation" of a Context.
1122
1123 self.synchro = threading.Event()
1124 self.finish1 = threading.Event()
1125 self.finish2 = threading.Event()
1126
1127 th1 = threading.Thread(target=thfunc1, args=(self,))
1128 th2 = threading.Thread(target=thfunc2, args=(self,))
1129
1130 th1.start()
1131 th2.start()
1132
1133 self.finish1.wait()
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001134 self.finish2.wait()
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001135 return
1136
Raymond Hettinger7e71fa52004-12-18 19:07:19 +00001137 if threading is None:
1138 del test_threading
1139
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001140
1141class DecimalUsabilityTest(unittest.TestCase):
1142 '''Unit tests for Usability cases of Decimal.'''
1143
1144 def test_comparison_operators(self):
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001145
1146 da = Decimal('23.42')
1147 db = Decimal('23.42')
1148 dc = Decimal('45')
1149
1150 #two Decimals
Georg Brandlab91fde2009-08-13 08:51:18 +00001151 self.assertTrue(dc > da)
1152 self.assertTrue(dc >= da)
1153 self.assertTrue(da < dc)
1154 self.assertTrue(da <= dc)
Guido van Rossume61fd5b2007-07-11 12:20:59 +00001155 self.assertEqual(da, db)
Georg Brandlab91fde2009-08-13 08:51:18 +00001156 self.assertTrue(da != dc)
1157 self.assertTrue(da <= db)
1158 self.assertTrue(da >= db)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001159
1160 #a Decimal and an int
Georg Brandlab91fde2009-08-13 08:51:18 +00001161 self.assertTrue(dc > 23)
1162 self.assertTrue(23 < dc)
Guido van Rossume61fd5b2007-07-11 12:20:59 +00001163 self.assertEqual(dc, 45)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001164
1165 #a Decimal and uncomparable
Raymond Hettinger0aeac102004-07-05 22:53:03 +00001166 self.assertNotEqual(da, 'ugly')
1167 self.assertNotEqual(da, 32.7)
1168 self.assertNotEqual(da, object())
1169 self.assertNotEqual(da, object)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001170
Raymond Hettinger0aeac102004-07-05 22:53:03 +00001171 # sortable
Guido van Rossumc1f779c2007-07-03 08:25:58 +00001172 a = list(map(Decimal, range(100)))
Raymond Hettinger0aeac102004-07-05 22:53:03 +00001173 b = a[:]
1174 random.shuffle(a)
1175 a.sort()
1176 self.assertEqual(a, b)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001177
1178 def test_copy_and_deepcopy_methods(self):
1179 d = Decimal('43.24')
1180 c = copy.copy(d)
1181 self.assertEqual(id(c), id(d))
1182 dc = copy.deepcopy(d)
1183 self.assertEqual(id(dc), id(d))
1184
1185 def test_hash_method(self):
1186 #just that it's hashable
1187 hash(Decimal(23))
Thomas Wouters8ce81f72007-09-20 18:22:40 +00001188
1189 test_values = [Decimal(sign*(2**m + n))
1190 for m in [0, 14, 15, 16, 17, 30, 31,
1191 32, 33, 62, 63, 64, 65, 66]
1192 for n in range(-10, 10)
1193 for sign in [-1, 1]]
1194 test_values.extend([
1195 Decimal("-0"), # zeros
1196 Decimal("0.00"),
1197 Decimal("-0.000"),
1198 Decimal("0E10"),
1199 Decimal("-0E12"),
1200 Decimal("10.0"), # negative exponent
1201 Decimal("-23.00000"),
1202 Decimal("1230E100"), # positive exponent
1203 Decimal("-4.5678E50"),
1204 # a value for which hash(n) != hash(n % (2**64-1))
1205 # in Python pre-2.6
1206 Decimal(2**64 + 2**32 - 1),
1207 # selection of values which fail with the old (before
1208 # version 2.6) long.__hash__
1209 Decimal("1.634E100"),
1210 Decimal("90.697E100"),
1211 Decimal("188.83E100"),
1212 Decimal("1652.9E100"),
1213 Decimal("56531E100"),
1214 ])
1215
1216 # check that hash(d) == hash(int(d)) for integral values
1217 for value in test_values:
1218 self.assertEqual(hash(value), hash(int(value)))
1219
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001220 #the same hash that to an int
1221 self.assertEqual(hash(Decimal(23)), hash(23))
Raymond Hettingerbea3f6f2005-03-15 04:59:17 +00001222 self.assertRaises(TypeError, hash, Decimal('NaN'))
Georg Brandlab91fde2009-08-13 08:51:18 +00001223 self.assertTrue(hash(Decimal('Inf')))
1224 self.assertTrue(hash(Decimal('-Inf')))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001225
Christian Heimes2380ac72008-01-09 00:17:24 +00001226 # check that the value of the hash doesn't depend on the
1227 # current context (issue #1757)
1228 c = getcontext()
1229 old_precision = c.prec
1230 x = Decimal("123456789.1")
1231
1232 c.prec = 6
1233 h1 = hash(x)
1234 c.prec = 10
1235 h2 = hash(x)
1236 c.prec = 16
1237 h3 = hash(x)
1238
1239 self.assertEqual(h1, h2)
1240 self.assertEqual(h1, h3)
1241 c.prec = old_precision
1242
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001243 def test_min_and_max_methods(self):
1244
1245 d1 = Decimal('15.32')
1246 d2 = Decimal('28.5')
1247 l1 = 15
1248 l2 = 28
1249
1250 #between Decimals
Georg Brandlab91fde2009-08-13 08:51:18 +00001251 self.assertTrue(min(d1,d2) is d1)
1252 self.assertTrue(min(d2,d1) is d1)
1253 self.assertTrue(max(d1,d2) is d2)
1254 self.assertTrue(max(d2,d1) is d2)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001255
1256 #between Decimal and long
Georg Brandlab91fde2009-08-13 08:51:18 +00001257 self.assertTrue(min(d1,l2) is d1)
1258 self.assertTrue(min(l2,d1) is d1)
1259 self.assertTrue(max(l1,d2) is d2)
1260 self.assertTrue(max(d2,l1) is d2)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001261
1262 def test_as_nonzero(self):
1263 #as false
Georg Brandlab91fde2009-08-13 08:51:18 +00001264 self.assertFalse(Decimal(0))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001265 #as true
Georg Brandlab91fde2009-08-13 08:51:18 +00001266 self.assertTrue(Decimal('0.372'))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001267
1268 def test_tostring_methods(self):
1269 #Test str and repr methods.
1270
1271 d = Decimal('15.32')
1272 self.assertEqual(str(d), '15.32') # str
Christian Heimes68f5fbe2008-02-14 08:27:37 +00001273 self.assertEqual(repr(d), "Decimal('15.32')") # repr
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001274
1275 def test_tonum_methods(self):
1276 #Test float, int and long methods.
1277
1278 d1 = Decimal('66')
1279 d2 = Decimal('15.32')
1280
1281 #int
1282 self.assertEqual(int(d1), 66)
1283 self.assertEqual(int(d2), 15)
1284
1285 #long
Guido van Rossume2a383d2007-01-15 16:59:06 +00001286 self.assertEqual(int(d1), 66)
1287 self.assertEqual(int(d2), 15)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001288
1289 #float
1290 self.assertEqual(float(d1), 66)
1291 self.assertEqual(float(d2), 15.32)
1292
Mark Dickinsonb27406c2008-05-09 13:42:33 +00001293 #floor
1294 test_pairs = [
1295 ('123.00', 123),
1296 ('3.2', 3),
1297 ('3.54', 3),
1298 ('3.899', 3),
1299 ('-2.3', -3),
1300 ('-11.0', -11),
1301 ('0.0', 0),
1302 ('-0E3', 0),
1303 ]
1304 for d, i in test_pairs:
1305 self.assertEqual(math.floor(Decimal(d)), i)
1306 self.assertRaises(ValueError, math.floor, Decimal('-NaN'))
1307 self.assertRaises(ValueError, math.floor, Decimal('sNaN'))
1308 self.assertRaises(ValueError, math.floor, Decimal('NaN123'))
1309 self.assertRaises(OverflowError, math.floor, Decimal('Inf'))
1310 self.assertRaises(OverflowError, math.floor, Decimal('-Inf'))
1311
1312 #ceiling
1313 test_pairs = [
1314 ('123.00', 123),
1315 ('3.2', 4),
1316 ('3.54', 4),
1317 ('3.899', 4),
1318 ('-2.3', -2),
1319 ('-11.0', -11),
1320 ('0.0', 0),
1321 ('-0E3', 0),
1322 ]
1323 for d, i in test_pairs:
1324 self.assertEqual(math.ceil(Decimal(d)), i)
1325 self.assertRaises(ValueError, math.ceil, Decimal('-NaN'))
1326 self.assertRaises(ValueError, math.ceil, Decimal('sNaN'))
1327 self.assertRaises(ValueError, math.ceil, Decimal('NaN123'))
1328 self.assertRaises(OverflowError, math.ceil, Decimal('Inf'))
1329 self.assertRaises(OverflowError, math.ceil, Decimal('-Inf'))
1330
1331 #round, single argument
1332 test_pairs = [
1333 ('123.00', 123),
1334 ('3.2', 3),
1335 ('3.54', 4),
1336 ('3.899', 4),
1337 ('-2.3', -2),
1338 ('-11.0', -11),
1339 ('0.0', 0),
1340 ('-0E3', 0),
1341 ('-3.5', -4),
1342 ('-2.5', -2),
1343 ('-1.5', -2),
1344 ('-0.5', 0),
1345 ('0.5', 0),
1346 ('1.5', 2),
1347 ('2.5', 2),
1348 ('3.5', 4),
1349 ]
1350 for d, i in test_pairs:
1351 self.assertEqual(round(Decimal(d)), i)
1352 self.assertRaises(ValueError, round, Decimal('-NaN'))
1353 self.assertRaises(ValueError, round, Decimal('sNaN'))
1354 self.assertRaises(ValueError, round, Decimal('NaN123'))
1355 self.assertRaises(OverflowError, round, Decimal('Inf'))
1356 self.assertRaises(OverflowError, round, Decimal('-Inf'))
1357
1358 #round, two arguments; this is essentially equivalent
1359 #to quantize, which is already extensively tested
1360 test_triples = [
1361 ('123.456', -4, '0E+4'),
1362 ('123.456', -3, '0E+3'),
1363 ('123.456', -2, '1E+2'),
1364 ('123.456', -1, '1.2E+2'),
1365 ('123.456', 0, '123'),
1366 ('123.456', 1, '123.5'),
1367 ('123.456', 2, '123.46'),
1368 ('123.456', 3, '123.456'),
1369 ('123.456', 4, '123.4560'),
1370 ('123.455', 2, '123.46'),
1371 ('123.445', 2, '123.44'),
1372 ('Inf', 4, 'NaN'),
1373 ('-Inf', -23, 'NaN'),
1374 ('sNaN314', 3, 'NaN314'),
1375 ]
1376 for d, n, r in test_triples:
1377 self.assertEqual(str(round(Decimal(d), n)), r)
1378
1379
1380
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001381 def test_eval_round_trip(self):
1382
1383 #with zero
1384 d = Decimal( (0, (0,), 0) )
1385 self.assertEqual(d, eval(repr(d)))
1386
1387 #int
1388 d = Decimal( (1, (4, 5), 0) )
1389 self.assertEqual(d, eval(repr(d)))
1390
1391 #float
1392 d = Decimal( (0, (4, 5, 3, 4), -2) )
1393 self.assertEqual(d, eval(repr(d)))
1394
1395 #weird
1396 d = Decimal( (1, (4, 3, 4, 9, 1, 3, 5, 3, 4), -25) )
1397 self.assertEqual(d, eval(repr(d)))
1398
1399 def test_as_tuple(self):
1400
1401 #with zero
1402 d = Decimal(0)
1403 self.assertEqual(d.as_tuple(), (0, (0,), 0) )
1404
1405 #int
1406 d = Decimal(-45)
1407 self.assertEqual(d.as_tuple(), (1, (4, 5), 0) )
1408
1409 #complicated string
1410 d = Decimal("-4.34913534E-17")
1411 self.assertEqual(d.as_tuple(), (1, (4, 3, 4, 9, 1, 3, 5, 3, 4), -25) )
1412
1413 #inf
1414 d = Decimal("Infinity")
1415 self.assertEqual(d.as_tuple(), (0, (0,), 'F') )
1416
Guido van Rossum8ce8a782007-11-01 19:42:39 +00001417 #leading zeros in coefficient should be stripped
1418 d = Decimal( (0, (0, 0, 4, 0, 5, 3, 4), -2) )
1419 self.assertEqual(d.as_tuple(), (0, (4, 0, 5, 3, 4), -2) )
1420 d = Decimal( (1, (0, 0, 0), 37) )
1421 self.assertEqual(d.as_tuple(), (1, (0,), 37))
1422 d = Decimal( (1, (), 37) )
1423 self.assertEqual(d.as_tuple(), (1, (0,), 37))
1424
1425 #leading zeros in NaN diagnostic info should be stripped
1426 d = Decimal( (0, (0, 0, 4, 0, 5, 3, 4), 'n') )
1427 self.assertEqual(d.as_tuple(), (0, (4, 0, 5, 3, 4), 'n') )
1428 d = Decimal( (1, (0, 0, 0), 'N') )
1429 self.assertEqual(d.as_tuple(), (1, (), 'N') )
1430 d = Decimal( (1, (), 'n') )
1431 self.assertEqual(d.as_tuple(), (1, (), 'n') )
1432
1433 #coefficient in infinity should be ignored
1434 d = Decimal( (0, (4, 5, 3, 4), 'F') )
1435 self.assertEqual(d.as_tuple(), (0, (0,), 'F'))
1436 d = Decimal( (1, (0, 2, 7, 1), 'F') )
1437 self.assertEqual(d.as_tuple(), (1, (0,), 'F'))
1438
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001439 def test_immutability_operations(self):
1440 # Do operations and check that it didn't change change internal objects.
1441
1442 d1 = Decimal('-25e55')
1443 b1 = Decimal('-25e55')
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001444 d2 = Decimal('33e+33')
1445 b2 = Decimal('33e+33')
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001446
1447 def checkSameDec(operation, useOther=False):
1448 if useOther:
1449 eval("d1." + operation + "(d2)")
1450 self.assertEqual(d1._sign, b1._sign)
1451 self.assertEqual(d1._int, b1._int)
1452 self.assertEqual(d1._exp, b1._exp)
1453 self.assertEqual(d2._sign, b2._sign)
1454 self.assertEqual(d2._int, b2._int)
1455 self.assertEqual(d2._exp, b2._exp)
1456 else:
1457 eval("d1." + operation + "()")
1458 self.assertEqual(d1._sign, b1._sign)
1459 self.assertEqual(d1._int, b1._int)
1460 self.assertEqual(d1._exp, b1._exp)
1461 return
1462
1463 Decimal(d1)
1464 self.assertEqual(d1._sign, b1._sign)
1465 self.assertEqual(d1._int, b1._int)
1466 self.assertEqual(d1._exp, b1._exp)
1467
1468 checkSameDec("__abs__")
1469 checkSameDec("__add__", True)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001470 checkSameDec("__divmod__", True)
Christian Heimes77c02eb2008-02-09 02:18:51 +00001471 checkSameDec("__eq__", True)
1472 checkSameDec("__ne__", True)
1473 checkSameDec("__le__", True)
1474 checkSameDec("__lt__", True)
1475 checkSameDec("__ge__", True)
1476 checkSameDec("__gt__", True)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001477 checkSameDec("__float__")
1478 checkSameDec("__floordiv__", True)
1479 checkSameDec("__hash__")
1480 checkSameDec("__int__")
Christian Heimes969fe572008-01-25 11:23:10 +00001481 checkSameDec("__trunc__")
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001482 checkSameDec("__mod__", True)
1483 checkSameDec("__mul__", True)
1484 checkSameDec("__neg__")
Jack Diederich4dafcc42006-11-28 19:15:13 +00001485 checkSameDec("__bool__")
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001486 checkSameDec("__pos__")
1487 checkSameDec("__pow__", True)
1488 checkSameDec("__radd__", True)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001489 checkSameDec("__rdivmod__", True)
1490 checkSameDec("__repr__")
1491 checkSameDec("__rfloordiv__", True)
1492 checkSameDec("__rmod__", True)
1493 checkSameDec("__rmul__", True)
1494 checkSameDec("__rpow__", True)
1495 checkSameDec("__rsub__", True)
1496 checkSameDec("__str__")
1497 checkSameDec("__sub__", True)
1498 checkSameDec("__truediv__", True)
1499 checkSameDec("adjusted")
1500 checkSameDec("as_tuple")
1501 checkSameDec("compare", True)
1502 checkSameDec("max", True)
1503 checkSameDec("min", True)
1504 checkSameDec("normalize")
1505 checkSameDec("quantize", True)
1506 checkSameDec("remainder_near", True)
1507 checkSameDec("same_quantum", True)
1508 checkSameDec("sqrt")
1509 checkSameDec("to_eng_string")
1510 checkSameDec("to_integral")
1511
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001512 def test_subclassing(self):
1513 # Different behaviours when subclassing Decimal
1514
1515 class MyDecimal(Decimal):
1516 pass
1517
1518 d1 = MyDecimal(1)
1519 d2 = MyDecimal(2)
1520 d = d1 + d2
1521 self.assertTrue(type(d) is Decimal)
1522
1523 d = d1.max(d2)
1524 self.assertTrue(type(d) is Decimal)
1525
Christian Heimes0348fb62008-03-26 12:55:56 +00001526 def test_implicit_context(self):
1527 # Check results when context given implicitly. (Issue 2478)
1528 c = getcontext()
1529 self.assertEqual(str(Decimal(0).sqrt()),
1530 str(c.sqrt(Decimal(0))))
1531
Mark Dickinson9050bb22009-10-29 12:25:07 +00001532 def test_conversions_from_int(self):
1533 # Check that methods taking a second Decimal argument will
1534 # always accept an integer in place of a Decimal.
1535 self.assertEqual(Decimal(4).compare(3),
1536 Decimal(4).compare(Decimal(3)))
1537 self.assertEqual(Decimal(4).compare_signal(3),
1538 Decimal(4).compare_signal(Decimal(3)))
1539 self.assertEqual(Decimal(4).compare_total(3),
1540 Decimal(4).compare_total(Decimal(3)))
1541 self.assertEqual(Decimal(4).compare_total_mag(3),
1542 Decimal(4).compare_total_mag(Decimal(3)))
1543 self.assertEqual(Decimal(10101).logical_and(1001),
1544 Decimal(10101).logical_and(Decimal(1001)))
1545 self.assertEqual(Decimal(10101).logical_or(1001),
1546 Decimal(10101).logical_or(Decimal(1001)))
1547 self.assertEqual(Decimal(10101).logical_xor(1001),
1548 Decimal(10101).logical_xor(Decimal(1001)))
1549 self.assertEqual(Decimal(567).max(123),
1550 Decimal(567).max(Decimal(123)))
1551 self.assertEqual(Decimal(567).max_mag(123),
1552 Decimal(567).max_mag(Decimal(123)))
1553 self.assertEqual(Decimal(567).min(123),
1554 Decimal(567).min(Decimal(123)))
1555 self.assertEqual(Decimal(567).min_mag(123),
1556 Decimal(567).min_mag(Decimal(123)))
1557 self.assertEqual(Decimal(567).next_toward(123),
1558 Decimal(567).next_toward(Decimal(123)))
1559 self.assertEqual(Decimal(1234).quantize(100),
1560 Decimal(1234).quantize(Decimal(100)))
1561 self.assertEqual(Decimal(768).remainder_near(1234),
1562 Decimal(768).remainder_near(Decimal(1234)))
1563 self.assertEqual(Decimal(123).rotate(1),
1564 Decimal(123).rotate(Decimal(1)))
1565 self.assertEqual(Decimal(1234).same_quantum(1000),
1566 Decimal(1234).same_quantum(Decimal(1000)))
1567 self.assertEqual(Decimal('9.123').scaleb(-100),
1568 Decimal('9.123').scaleb(Decimal(-100)))
1569 self.assertEqual(Decimal(456).shift(-1),
1570 Decimal(456).shift(Decimal(-1)))
1571
1572 self.assertEqual(Decimal(-12).fma(Decimal(45), 67),
1573 Decimal(-12).fma(Decimal(45), Decimal(67)))
1574 self.assertEqual(Decimal(-12).fma(45, 67),
1575 Decimal(-12).fma(Decimal(45), Decimal(67)))
1576 self.assertEqual(Decimal(-12).fma(45, Decimal(67)),
1577 Decimal(-12).fma(Decimal(45), Decimal(67)))
1578
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001579
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001580class DecimalPythonAPItests(unittest.TestCase):
1581
Raymond Hettinger82417ca2009-02-03 03:54:28 +00001582 def test_abc(self):
Georg Brandlab91fde2009-08-13 08:51:18 +00001583 self.assertTrue(issubclass(Decimal, numbers.Number))
1584 self.assertTrue(not issubclass(Decimal, numbers.Real))
1585 self.assertTrue(isinstance(Decimal(0), numbers.Number))
1586 self.assertTrue(not isinstance(Decimal(0), numbers.Real))
Raymond Hettinger82417ca2009-02-03 03:54:28 +00001587
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001588 def test_pickle(self):
1589 d = Decimal('-3.141590000')
1590 p = pickle.dumps(d)
1591 e = pickle.loads(p)
1592 self.assertEqual(d, e)
1593
Raymond Hettinger5548be22004-07-05 18:49:38 +00001594 def test_int(self):
Raymond Hettinger605ed022004-11-24 07:28:48 +00001595 for x in range(-250, 250):
1596 s = '%0.2f' % (x / 100.0)
Raymond Hettinger5548be22004-07-05 18:49:38 +00001597 # should work the same as for floats
1598 self.assertEqual(int(Decimal(s)), int(float(s)))
Raymond Hettinger605ed022004-11-24 07:28:48 +00001599 # should work the same as to_integral in the ROUND_DOWN mode
Raymond Hettinger5548be22004-07-05 18:49:38 +00001600 d = Decimal(s)
Raymond Hettinger605ed022004-11-24 07:28:48 +00001601 r = d.to_integral(ROUND_DOWN)
Raymond Hettinger5548be22004-07-05 18:49:38 +00001602 self.assertEqual(Decimal(int(d)), r)
1603
Mark Dickinson8fde3da2009-09-08 19:23:44 +00001604 self.assertRaises(ValueError, int, Decimal('-nan'))
1605 self.assertRaises(ValueError, int, Decimal('snan'))
1606 self.assertRaises(OverflowError, int, Decimal('inf'))
1607 self.assertRaises(OverflowError, int, Decimal('-inf'))
1608
Christian Heimes969fe572008-01-25 11:23:10 +00001609 def test_trunc(self):
1610 for x in range(-250, 250):
1611 s = '%0.2f' % (x / 100.0)
1612 # should work the same as for floats
1613 self.assertEqual(int(Decimal(s)), int(float(s)))
1614 # should work the same as to_integral in the ROUND_DOWN mode
1615 d = Decimal(s)
1616 r = d.to_integral(ROUND_DOWN)
Christian Heimes400adb02008-02-01 08:12:03 +00001617 self.assertEqual(Decimal(math.trunc(d)), r)
Christian Heimes969fe572008-01-25 11:23:10 +00001618
Raymond Hettinger771ed762009-01-03 19:20:32 +00001619 def test_from_float(self):
1620
1621 class MyDecimal(Decimal):
1622 pass
1623
1624 r = MyDecimal.from_float(0.1)
1625 self.assertEqual(type(r), MyDecimal)
1626 self.assertEqual(str(r),
1627 '0.1000000000000000055511151231257827021181583404541015625')
1628 bigint = 12345678901234567890123456789
1629 self.assertEqual(MyDecimal.from_float(bigint), MyDecimal(bigint))
Georg Brandlab91fde2009-08-13 08:51:18 +00001630 self.assertTrue(MyDecimal.from_float(float('nan')).is_qnan())
1631 self.assertTrue(MyDecimal.from_float(float('inf')).is_infinite())
1632 self.assertTrue(MyDecimal.from_float(float('-inf')).is_infinite())
Raymond Hettinger771ed762009-01-03 19:20:32 +00001633 self.assertEqual(str(MyDecimal.from_float(float('nan'))),
1634 str(Decimal('NaN')))
1635 self.assertEqual(str(MyDecimal.from_float(float('inf'))),
1636 str(Decimal('Infinity')))
1637 self.assertEqual(str(MyDecimal.from_float(float('-inf'))),
1638 str(Decimal('-Infinity')))
1639 self.assertRaises(TypeError, MyDecimal.from_float, 'abc')
1640 for i in range(200):
1641 x = random.expovariate(0.01) * (random.random() * 2.0 - 1.0)
1642 self.assertEqual(x, float(MyDecimal.from_float(x))) # roundtrip
1643
1644 def test_create_decimal_from_float(self):
1645 context = Context(prec=5, rounding=ROUND_DOWN)
1646 self.assertEqual(
1647 context.create_decimal_from_float(math.pi),
1648 Decimal('3.1415')
1649 )
1650 context = Context(prec=5, rounding=ROUND_UP)
1651 self.assertEqual(
1652 context.create_decimal_from_float(math.pi),
1653 Decimal('3.1416')
1654 )
1655 context = Context(prec=5, traps=[Inexact])
1656 self.assertRaises(
1657 Inexact,
1658 context.create_decimal_from_float,
1659 math.pi
1660 )
1661 self.assertEqual(repr(context.create_decimal_from_float(-0.0)),
1662 "Decimal('-0')")
1663 self.assertEqual(repr(context.create_decimal_from_float(1.0)),
1664 "Decimal('1')")
1665 self.assertEqual(repr(context.create_decimal_from_float(10)),
1666 "Decimal('10')")
1667
Raymond Hettingerd9c0a7a2004-07-03 10:02:28 +00001668class ContextAPItests(unittest.TestCase):
1669
1670 def test_pickle(self):
1671 c = Context()
1672 e = pickle.loads(pickle.dumps(c))
1673 for k in vars(c):
1674 v1 = vars(c)[k]
1675 v2 = vars(e)[k]
1676 self.assertEqual(v1, v2)
1677
Raymond Hettinger0aeac102004-07-05 22:53:03 +00001678 def test_equality_with_other_types(self):
Georg Brandlab91fde2009-08-13 08:51:18 +00001679 self.assertTrue(Decimal(10) in ['a', 1.0, Decimal(10), (1,2), {}])
1680 self.assertTrue(Decimal(10) not in ['a', 1.0, (1,2), {}])
Raymond Hettinger0aeac102004-07-05 22:53:03 +00001681
Raymond Hettinger955d2b22004-08-08 20:17:45 +00001682 def test_copy(self):
1683 # All copies should be deep
1684 c = Context()
1685 d = c.copy()
1686 self.assertNotEqual(id(c), id(d))
1687 self.assertNotEqual(id(c.flags), id(d.flags))
1688 self.assertNotEqual(id(c.traps), id(d.traps))
1689
Thomas Wouters89f507f2006-12-13 04:49:30 +00001690class WithStatementTest(unittest.TestCase):
1691 # Can't do these as docstrings until Python 2.6
1692 # as doctest can't handle __future__ statements
1693
1694 def test_localcontext(self):
1695 # Use a copy of the current context in the block
1696 orig_ctx = getcontext()
1697 with localcontext() as enter_ctx:
1698 set_ctx = getcontext()
1699 final_ctx = getcontext()
Georg Brandlab91fde2009-08-13 08:51:18 +00001700 self.assertTrue(orig_ctx is final_ctx, 'did not restore context correctly')
1701 self.assertTrue(orig_ctx is not set_ctx, 'did not copy the context')
1702 self.assertTrue(set_ctx is enter_ctx, '__enter__ returned wrong context')
Thomas Wouters89f507f2006-12-13 04:49:30 +00001703
1704 def test_localcontextarg(self):
1705 # Use a copy of the supplied context in the block
1706 orig_ctx = getcontext()
1707 new_ctx = Context(prec=42)
1708 with localcontext(new_ctx) as enter_ctx:
1709 set_ctx = getcontext()
1710 final_ctx = getcontext()
Georg Brandlab91fde2009-08-13 08:51:18 +00001711 self.assertTrue(orig_ctx is final_ctx, 'did not restore context correctly')
1712 self.assertTrue(set_ctx.prec == new_ctx.prec, 'did not set correct context')
1713 self.assertTrue(new_ctx is not set_ctx, 'did not copy the context')
1714 self.assertTrue(set_ctx is enter_ctx, '__enter__ returned wrong context')
Thomas Wouters89f507f2006-12-13 04:49:30 +00001715
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001716class ContextFlags(unittest.TestCase):
1717 def test_flags_irrelevant(self):
1718 # check that the result (numeric result + flags raised) of an
1719 # arithmetic operation doesn't depend on the current flags
1720
1721 context = Context(prec=9, Emin = -999999999, Emax = 999999999,
1722 rounding=ROUND_HALF_EVEN, traps=[], flags=[])
1723
1724 # operations that raise various flags, in the form (function, arglist)
1725 operations = [
1726 (context._apply, [Decimal("100E-1000000009")]),
1727 (context.sqrt, [Decimal(2)]),
1728 (context.add, [Decimal("1.23456789"), Decimal("9.87654321")]),
1729 (context.multiply, [Decimal("1.23456789"), Decimal("9.87654321")]),
1730 (context.subtract, [Decimal("1.23456789"), Decimal("9.87654321")]),
1731 ]
1732
1733 # try various flags individually, then a whole lot at once
1734 flagsets = [[Inexact], [Rounded], [Underflow], [Clamped], [Subnormal],
1735 [Inexact, Rounded, Underflow, Clamped, Subnormal]]
1736
1737 for fn, args in operations:
1738 # find answer and flags raised using a clean context
1739 context.clear_flags()
1740 ans = fn(*args)
1741 flags = [k for k, v in context.flags.items() if v]
1742
1743 for extra_flags in flagsets:
1744 # set flags, before calling operation
1745 context.clear_flags()
1746 for flag in extra_flags:
1747 context._raise_error(flag)
1748 new_ans = fn(*args)
1749
1750 # flags that we expect to be set after the operation
1751 expected_flags = list(flags)
1752 for flag in extra_flags:
1753 if flag not in expected_flags:
1754 expected_flags.append(flag)
1755 expected_flags.sort(key=id)
1756
1757 # flags we actually got
1758 new_flags = [k for k,v in context.flags.items() if v]
1759 new_flags.sort(key=id)
1760
1761 self.assertEqual(ans, new_ans,
1762 "operation produces different answers depending on flags set: " +
1763 "expected %s, got %s." % (ans, new_ans))
1764 self.assertEqual(new_flags, expected_flags,
1765 "operation raises different flags depending on flags set: " +
1766 "expected %s, got %s" % (expected_flags, new_flags))
1767
1768def test_main(arith=False, verbose=None, todo_tests=None, debug=None):
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001769 """ Execute the tests.
1770
Raymond Hettingered20ad82004-09-04 20:09:13 +00001771 Runs all arithmetic tests if arith is True or if the "decimal" resource
1772 is enabled in regrtest.py
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001773 """
Raymond Hettingered20ad82004-09-04 20:09:13 +00001774
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00001775 init()
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001776 global TEST_ALL, DEBUG
Raymond Hettingered20ad82004-09-04 20:09:13 +00001777 TEST_ALL = arith or is_resource_enabled('decimal')
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001778 DEBUG = debug
Raymond Hettingered20ad82004-09-04 20:09:13 +00001779
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001780 if todo_tests is None:
1781 test_classes = [
1782 DecimalExplicitConstructionTest,
1783 DecimalImplicitConstructionTest,
1784 DecimalArithmeticOperatorsTest,
Christian Heimesf16baeb2008-02-29 14:57:44 +00001785 DecimalFormatTest,
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001786 DecimalUseOfContextTest,
1787 DecimalUsabilityTest,
1788 DecimalPythonAPItests,
1789 ContextAPItests,
1790 DecimalTest,
1791 WithStatementTest,
1792 ContextFlags
1793 ]
1794 else:
1795 test_classes = [DecimalTest]
1796
1797 # Dynamically build custom test definition for each file in the test
1798 # directory and add the definitions to the DecimalTest class. This
1799 # procedure insures that new files do not get skipped.
1800 for filename in os.listdir(directory):
1801 if '.decTest' not in filename or filename.startswith("."):
1802 continue
1803 head, tail = filename.split('.')
1804 if todo_tests is not None and head not in todo_tests:
1805 continue
1806 tester = lambda self, f=filename: self.eval_file(directory + f)
1807 setattr(DecimalTest, 'test_' + head, tester)
1808 del filename, head, tail, tester
1809
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001810
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00001811 try:
1812 run_unittest(*test_classes)
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001813 if todo_tests is None:
1814 import decimal as DecimalModule
1815 run_doctest(DecimalModule, verbose)
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00001816 finally:
1817 setcontext(ORIGINAL_CONTEXT)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001818
1819if __name__ == '__main__':
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001820 import optparse
1821 p = optparse.OptionParser("test_decimal.py [--debug] [{--skip | test1 [test2 [...]]}]")
1822 p.add_option('--debug', '-d', action='store_true', help='shows the test number and context before each test')
1823 p.add_option('--skip', '-s', action='store_true', help='skip over 90% of the arithmetic tests')
1824 (opt, args) = p.parse_args()
1825
1826 if opt.skip:
1827 test_main(arith=False, verbose=True)
1828 elif args:
1829 test_main(arith=True, verbose=True, todo_tests=args, debug=opt.debug)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001830 else:
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001831 test_main(arith=True, verbose=True)