blob: f556c79a2daad499b2b3ea1e7c60435d57e978bd [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 Dickinson8a546532009-10-08 16:30:38 +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 Dickinson8a546532009-10-08 16:30:38 +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)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +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 Dickinson345adc42009-08-02 10:14:23 +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 Dickinson46ab5d02009-09-08 20:22:46 +0000715 ('6', '123', ' 123'),
Mark Dickinsonad416342009-03-17 18:10:15 +0000716 ('<6', '123', '123 '),
717 ('>6', '123', ' 123'),
718 ('^6', '123', ' 123 '),
719 ('=+6', '123', '+ 123'),
Mark Dickinson79f52032009-03-17 23:12:51 +0000720 ('#<10', 'NaN', 'NaN#######'),
721 ('#<10', '-4.3', '-4.3######'),
722 ('#<+10', '0.0130', '+0.0130###'),
723 ('#< 10', '0.0130', ' 0.0130###'),
724 ('@>10', '-Inf', '@-Infinity'),
725 ('#>5', '-Inf', '-Infinity'),
726 ('?^5', '123', '?123?'),
727 ('%^6', '123', '%123%%'),
728 (' ^6', '-45.6', '-45.6 '),
729 ('/=10', '-45.6', '-/////45.6'),
730 ('/=+10', '45.6', '+/////45.6'),
731 ('/= 10', '45.6', ' /////45.6'),
732
733 # thousands separator
734 (',', '1234567', '1,234,567'),
735 (',', '123456', '123,456'),
736 (',', '12345', '12,345'),
737 (',', '1234', '1,234'),
738 (',', '123', '123'),
739 (',', '12', '12'),
740 (',', '1', '1'),
741 (',', '0', '0'),
742 (',', '-1234567', '-1,234,567'),
743 (',', '-123456', '-123,456'),
744 ('7,', '123456', '123,456'),
Mark Dickinson46ab5d02009-09-08 20:22:46 +0000745 ('8,', '123456', ' 123,456'),
Mark Dickinson79f52032009-03-17 23:12:51 +0000746 ('08,', '123456', '0,123,456'), # special case: extra 0 needed
747 ('+08,', '123456', '+123,456'), # but not if there's a sign
748 (' 08,', '123456', ' 123,456'),
749 ('08,', '-123456', '-123,456'),
750 ('+09,', '123456', '+0,123,456'),
751 # ... with fractional part...
752 ('07,', '1234.56', '1,234.56'),
753 ('08,', '1234.56', '1,234.56'),
754 ('09,', '1234.56', '01,234.56'),
755 ('010,', '1234.56', '001,234.56'),
756 ('011,', '1234.56', '0,001,234.56'),
757 ('012,', '1234.56', '0,001,234.56'),
758 ('08,.1f', '1234.5', '01,234.5'),
759 # no thousands separators in fraction part
760 (',', '1.23456789', '1.23456789'),
761 (',%', '123.456789', '12,345.6789%'),
762 (',e', '123456', '1.23456e+5'),
763 (',E', '123456', '1.23456E+5'),
Mark Dickinson7718d2b2009-09-07 16:21:56 +0000764
765 # issue 6850
766 ('a=-7.0', '0.12345', 'aaaa0.1'),
Christian Heimesf16baeb2008-02-29 14:57:44 +0000767 ]
768 for fmt, d, result in test_values:
769 self.assertEqual(format(Decimal(d), fmt), result)
770
Mark Dickinson79f52032009-03-17 23:12:51 +0000771 def test_n_format(self):
772 try:
773 from locale import CHAR_MAX
774 except ImportError:
775 return
776
777 # Set up some localeconv-like dictionaries
778 en_US = {
779 'decimal_point' : '.',
780 'grouping' : [3, 3, 0],
781 'thousands_sep': ','
782 }
783
784 fr_FR = {
785 'decimal_point' : ',',
786 'grouping' : [CHAR_MAX],
787 'thousands_sep' : ''
788 }
789
790 ru_RU = {
791 'decimal_point' : ',',
792 'grouping' : [3, 3, 0],
793 'thousands_sep' : ' '
794 }
795
796 crazy = {
797 'decimal_point' : '&',
798 'grouping' : [1, 4, 2, CHAR_MAX],
799 'thousands_sep' : '-'
800 }
801
802
803 def get_fmt(x, locale, fmt='n'):
804 return Decimal.__format__(Decimal(x), fmt, _localeconv=locale)
805
806 self.assertEqual(get_fmt(Decimal('12.7'), en_US), '12.7')
807 self.assertEqual(get_fmt(Decimal('12.7'), fr_FR), '12,7')
808 self.assertEqual(get_fmt(Decimal('12.7'), ru_RU), '12,7')
809 self.assertEqual(get_fmt(Decimal('12.7'), crazy), '1-2&7')
810
811 self.assertEqual(get_fmt(123456789, en_US), '123,456,789')
812 self.assertEqual(get_fmt(123456789, fr_FR), '123456789')
813 self.assertEqual(get_fmt(123456789, ru_RU), '123 456 789')
814 self.assertEqual(get_fmt(1234567890123, crazy), '123456-78-9012-3')
815
816 self.assertEqual(get_fmt(123456789, en_US, '.6n'), '1.23457e+8')
817 self.assertEqual(get_fmt(123456789, fr_FR, '.6n'), '1,23457e+8')
818 self.assertEqual(get_fmt(123456789, ru_RU, '.6n'), '1,23457e+8')
819 self.assertEqual(get_fmt(123456789, crazy, '.6n'), '1&23457e+8')
820
Mark Dickinson7303b592009-03-18 08:25:36 +0000821 # zero padding
822 self.assertEqual(get_fmt(1234, fr_FR, '03n'), '1234')
823 self.assertEqual(get_fmt(1234, fr_FR, '04n'), '1234')
824 self.assertEqual(get_fmt(1234, fr_FR, '05n'), '01234')
825 self.assertEqual(get_fmt(1234, fr_FR, '06n'), '001234')
826
827 self.assertEqual(get_fmt(12345, en_US, '05n'), '12,345')
828 self.assertEqual(get_fmt(12345, en_US, '06n'), '12,345')
829 self.assertEqual(get_fmt(12345, en_US, '07n'), '012,345')
830 self.assertEqual(get_fmt(12345, en_US, '08n'), '0,012,345')
831 self.assertEqual(get_fmt(12345, en_US, '09n'), '0,012,345')
832 self.assertEqual(get_fmt(12345, en_US, '010n'), '00,012,345')
833
834 self.assertEqual(get_fmt(123456, crazy, '06n'), '1-2345-6')
835 self.assertEqual(get_fmt(123456, crazy, '07n'), '1-2345-6')
836 self.assertEqual(get_fmt(123456, crazy, '08n'), '1-2345-6')
837 self.assertEqual(get_fmt(123456, crazy, '09n'), '01-2345-6')
838 self.assertEqual(get_fmt(123456, crazy, '010n'), '0-01-2345-6')
839 self.assertEqual(get_fmt(123456, crazy, '011n'), '0-01-2345-6')
840 self.assertEqual(get_fmt(123456, crazy, '012n'), '00-01-2345-6')
841 self.assertEqual(get_fmt(123456, crazy, '013n'), '000-01-2345-6')
842
Mark Dickinson79f52032009-03-17 23:12:51 +0000843
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000844class DecimalArithmeticOperatorsTest(unittest.TestCase):
845 '''Unit tests for all arithmetic operators, binary and unary.'''
846
847 def test_addition(self):
848
849 d1 = Decimal('-11.1')
850 d2 = Decimal('22.2')
851
852 #two Decimals
853 self.assertEqual(d1+d2, Decimal('11.1'))
854 self.assertEqual(d2+d1, Decimal('11.1'))
855
856 #with other type, left
857 c = d1 + 5
858 self.assertEqual(c, Decimal('-6.1'))
859 self.assertEqual(type(c), type(d1))
860
861 #with other type, right
862 c = 5 + d1
863 self.assertEqual(c, Decimal('-6.1'))
864 self.assertEqual(type(c), type(d1))
865
866 #inline with decimal
867 d1 += d2
868 self.assertEqual(d1, Decimal('11.1'))
869
870 #inline with other type
871 d1 += 5
872 self.assertEqual(d1, Decimal('16.1'))
873
874 def test_subtraction(self):
875
876 d1 = Decimal('-11.1')
877 d2 = Decimal('22.2')
878
879 #two Decimals
880 self.assertEqual(d1-d2, Decimal('-33.3'))
881 self.assertEqual(d2-d1, Decimal('33.3'))
882
883 #with other type, left
884 c = d1 - 5
885 self.assertEqual(c, Decimal('-16.1'))
886 self.assertEqual(type(c), type(d1))
887
888 #with other type, right
889 c = 5 - d1
890 self.assertEqual(c, Decimal('16.1'))
891 self.assertEqual(type(c), type(d1))
892
893 #inline with decimal
894 d1 -= d2
895 self.assertEqual(d1, Decimal('-33.3'))
896
897 #inline with other type
898 d1 -= 5
899 self.assertEqual(d1, Decimal('-38.3'))
900
901 def test_multiplication(self):
902
903 d1 = Decimal('-5')
904 d2 = Decimal('3')
905
906 #two Decimals
907 self.assertEqual(d1*d2, Decimal('-15'))
908 self.assertEqual(d2*d1, Decimal('-15'))
909
910 #with other type, left
911 c = d1 * 5
912 self.assertEqual(c, Decimal('-25'))
913 self.assertEqual(type(c), type(d1))
914
915 #with other type, right
916 c = 5 * d1
917 self.assertEqual(c, Decimal('-25'))
918 self.assertEqual(type(c), type(d1))
919
920 #inline with decimal
921 d1 *= d2
922 self.assertEqual(d1, Decimal('-15'))
923
924 #inline with other type
925 d1 *= 5
926 self.assertEqual(d1, Decimal('-75'))
927
928 def test_division(self):
929
930 d1 = Decimal('-5')
931 d2 = Decimal('2')
932
933 #two Decimals
934 self.assertEqual(d1/d2, Decimal('-2.5'))
935 self.assertEqual(d2/d1, Decimal('-0.4'))
936
937 #with other type, left
938 c = d1 / 4
939 self.assertEqual(c, Decimal('-1.25'))
940 self.assertEqual(type(c), type(d1))
941
942 #with other type, right
943 c = 4 / d1
944 self.assertEqual(c, Decimal('-0.8'))
945 self.assertEqual(type(c), type(d1))
946
947 #inline with decimal
948 d1 /= d2
949 self.assertEqual(d1, Decimal('-2.5'))
950
951 #inline with other type
952 d1 /= 4
953 self.assertEqual(d1, Decimal('-0.625'))
954
955 def test_floor_division(self):
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000956
957 d1 = Decimal('5')
958 d2 = Decimal('2')
959
960 #two Decimals
961 self.assertEqual(d1//d2, Decimal('2'))
962 self.assertEqual(d2//d1, Decimal('0'))
963
964 #with other type, left
965 c = d1 // 4
966 self.assertEqual(c, Decimal('1'))
967 self.assertEqual(type(c), type(d1))
968
969 #with other type, right
970 c = 7 // d1
971 self.assertEqual(c, Decimal('1'))
972 self.assertEqual(type(c), type(d1))
973
974 #inline with decimal
975 d1 //= d2
976 self.assertEqual(d1, Decimal('2'))
977
978 #inline with other type
979 d1 //= 2
980 self.assertEqual(d1, Decimal('1'))
981
982 def test_powering(self):
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000983
984 d1 = Decimal('5')
985 d2 = Decimal('2')
986
987 #two Decimals
988 self.assertEqual(d1**d2, Decimal('25'))
989 self.assertEqual(d2**d1, Decimal('32'))
990
991 #with other type, left
992 c = d1 ** 4
993 self.assertEqual(c, Decimal('625'))
994 self.assertEqual(type(c), type(d1))
995
996 #with other type, right
997 c = 7 ** d1
998 self.assertEqual(c, Decimal('16807'))
999 self.assertEqual(type(c), type(d1))
1000
1001 #inline with decimal
1002 d1 **= d2
1003 self.assertEqual(d1, Decimal('25'))
1004
1005 #inline with other type
1006 d1 **= 4
1007 self.assertEqual(d1, Decimal('390625'))
1008
1009 def test_module(self):
1010
1011 d1 = Decimal('5')
1012 d2 = Decimal('2')
1013
1014 #two Decimals
1015 self.assertEqual(d1%d2, Decimal('1'))
1016 self.assertEqual(d2%d1, Decimal('2'))
1017
1018 #with other type, left
1019 c = d1 % 4
1020 self.assertEqual(c, Decimal('1'))
1021 self.assertEqual(type(c), type(d1))
1022
1023 #with other type, right
1024 c = 7 % d1
1025 self.assertEqual(c, Decimal('2'))
1026 self.assertEqual(type(c), type(d1))
1027
1028 #inline with decimal
1029 d1 %= d2
1030 self.assertEqual(d1, Decimal('1'))
1031
1032 #inline with other type
1033 d1 %= 4
1034 self.assertEqual(d1, Decimal('1'))
1035
1036 def test_floor_div_module(self):
1037
1038 d1 = Decimal('5')
1039 d2 = Decimal('2')
1040
1041 #two Decimals
1042 (p, q) = divmod(d1, d2)
1043 self.assertEqual(p, Decimal('2'))
1044 self.assertEqual(q, Decimal('1'))
1045 self.assertEqual(type(p), type(d1))
1046 self.assertEqual(type(q), type(d1))
1047
1048 #with other type, left
1049 (p, q) = divmod(d1, 4)
1050 self.assertEqual(p, Decimal('1'))
1051 self.assertEqual(q, Decimal('1'))
1052 self.assertEqual(type(p), type(d1))
1053 self.assertEqual(type(q), type(d1))
1054
1055 #with other type, right
1056 (p, q) = divmod(7, d1)
1057 self.assertEqual(p, Decimal('1'))
1058 self.assertEqual(q, Decimal('2'))
1059 self.assertEqual(type(p), type(d1))
1060 self.assertEqual(type(q), type(d1))
1061
1062 def test_unary_operators(self):
1063 self.assertEqual(+Decimal(45), Decimal(+45)) # +
1064 self.assertEqual(-Decimal(45), Decimal(-45)) # -
1065 self.assertEqual(abs(Decimal(45)), abs(Decimal(-45))) # abs
1066
Christian Heimes77c02eb2008-02-09 02:18:51 +00001067 def test_nan_comparisons(self):
1068 n = Decimal('NaN')
1069 s = Decimal('sNaN')
1070 i = Decimal('Inf')
1071 f = Decimal('2')
1072 for x, y in [(n, n), (n, i), (i, n), (n, f), (f, n),
1073 (s, n), (n, s), (s, i), (i, s), (s, f), (f, s), (s, s)]:
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001074 self.assertTrue(x != y)
1075 self.assertTrue(not (x == y))
1076 self.assertTrue(not (x < y))
1077 self.assertTrue(not (x <= y))
1078 self.assertTrue(not (x > y))
1079 self.assertTrue(not (x >= y))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001080
1081# The following are two functions used to test threading in the next class
1082
1083def thfunc1(cls):
1084 d1 = Decimal(1)
1085 d3 = Decimal(3)
Christian Heimesfe337bf2008-03-23 21:54:12 +00001086 test1 = d1/d3
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001087 cls.synchro.wait()
Christian Heimesfe337bf2008-03-23 21:54:12 +00001088 test2 = d1/d3
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001089 cls.finish1.set()
Christian Heimesfe337bf2008-03-23 21:54:12 +00001090
Christian Heimes81ee3ef2008-05-04 22:42:01 +00001091 cls.assertEqual(test1, Decimal('0.3333333333333333333333333333'))
1092 cls.assertEqual(test2, Decimal('0.3333333333333333333333333333'))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001093 return
1094
1095def thfunc2(cls):
1096 d1 = Decimal(1)
1097 d3 = Decimal(3)
Christian Heimesfe337bf2008-03-23 21:54:12 +00001098 test1 = d1/d3
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001099 thiscontext = getcontext()
1100 thiscontext.prec = 18
Christian Heimesfe337bf2008-03-23 21:54:12 +00001101 test2 = d1/d3
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001102 cls.synchro.set()
1103 cls.finish2.set()
Christian Heimesfe337bf2008-03-23 21:54:12 +00001104
Christian Heimes81ee3ef2008-05-04 22:42:01 +00001105 cls.assertEqual(test1, Decimal('0.3333333333333333333333333333'))
Christian Heimesfe337bf2008-03-23 21:54:12 +00001106 cls.assertEqual(test2, Decimal('0.333333333333333333'))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001107 return
1108
1109
1110class DecimalUseOfContextTest(unittest.TestCase):
1111 '''Unit tests for Use of Context cases in Decimal.'''
1112
Raymond Hettinger7e71fa52004-12-18 19:07:19 +00001113 try:
1114 import threading
1115 except ImportError:
1116 threading = None
1117
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001118 # Take care executing this test from IDLE, there's an issue in threading
1119 # that hangs IDLE and I couldn't find it
1120
1121 def test_threading(self):
1122 #Test the "threading isolation" of a Context.
1123
1124 self.synchro = threading.Event()
1125 self.finish1 = threading.Event()
1126 self.finish2 = threading.Event()
1127
1128 th1 = threading.Thread(target=thfunc1, args=(self,))
1129 th2 = threading.Thread(target=thfunc2, args=(self,))
1130
1131 th1.start()
1132 th2.start()
1133
1134 self.finish1.wait()
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001135 self.finish2.wait()
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001136 return
1137
Raymond Hettinger7e71fa52004-12-18 19:07:19 +00001138 if threading is None:
1139 del test_threading
1140
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001141
1142class DecimalUsabilityTest(unittest.TestCase):
1143 '''Unit tests for Usability cases of Decimal.'''
1144
1145 def test_comparison_operators(self):
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001146
1147 da = Decimal('23.42')
1148 db = Decimal('23.42')
1149 dc = Decimal('45')
1150
1151 #two Decimals
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001152 self.assertTrue(dc > da)
1153 self.assertTrue(dc >= da)
1154 self.assertTrue(da < dc)
1155 self.assertTrue(da <= dc)
Guido van Rossume61fd5b2007-07-11 12:20:59 +00001156 self.assertEqual(da, db)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001157 self.assertTrue(da != dc)
1158 self.assertTrue(da <= db)
1159 self.assertTrue(da >= db)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001160
1161 #a Decimal and an int
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001162 self.assertTrue(dc > 23)
1163 self.assertTrue(23 < dc)
Guido van Rossume61fd5b2007-07-11 12:20:59 +00001164 self.assertEqual(dc, 45)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001165
1166 #a Decimal and uncomparable
Raymond Hettinger0aeac102004-07-05 22:53:03 +00001167 self.assertNotEqual(da, 'ugly')
1168 self.assertNotEqual(da, 32.7)
1169 self.assertNotEqual(da, object())
1170 self.assertNotEqual(da, object)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001171
Raymond Hettinger0aeac102004-07-05 22:53:03 +00001172 # sortable
Guido van Rossumc1f779c2007-07-03 08:25:58 +00001173 a = list(map(Decimal, range(100)))
Raymond Hettinger0aeac102004-07-05 22:53:03 +00001174 b = a[:]
1175 random.shuffle(a)
1176 a.sort()
1177 self.assertEqual(a, b)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001178
1179 def test_copy_and_deepcopy_methods(self):
1180 d = Decimal('43.24')
1181 c = copy.copy(d)
1182 self.assertEqual(id(c), id(d))
1183 dc = copy.deepcopy(d)
1184 self.assertEqual(id(dc), id(d))
1185
1186 def test_hash_method(self):
1187 #just that it's hashable
1188 hash(Decimal(23))
Thomas Wouters8ce81f72007-09-20 18:22:40 +00001189
1190 test_values = [Decimal(sign*(2**m + n))
1191 for m in [0, 14, 15, 16, 17, 30, 31,
1192 32, 33, 62, 63, 64, 65, 66]
1193 for n in range(-10, 10)
1194 for sign in [-1, 1]]
1195 test_values.extend([
1196 Decimal("-0"), # zeros
1197 Decimal("0.00"),
1198 Decimal("-0.000"),
1199 Decimal("0E10"),
1200 Decimal("-0E12"),
1201 Decimal("10.0"), # negative exponent
1202 Decimal("-23.00000"),
1203 Decimal("1230E100"), # positive exponent
1204 Decimal("-4.5678E50"),
1205 # a value for which hash(n) != hash(n % (2**64-1))
1206 # in Python pre-2.6
1207 Decimal(2**64 + 2**32 - 1),
1208 # selection of values which fail with the old (before
1209 # version 2.6) long.__hash__
1210 Decimal("1.634E100"),
1211 Decimal("90.697E100"),
1212 Decimal("188.83E100"),
1213 Decimal("1652.9E100"),
1214 Decimal("56531E100"),
1215 ])
1216
1217 # check that hash(d) == hash(int(d)) for integral values
1218 for value in test_values:
1219 self.assertEqual(hash(value), hash(int(value)))
1220
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001221 #the same hash that to an int
1222 self.assertEqual(hash(Decimal(23)), hash(23))
Raymond Hettingerbea3f6f2005-03-15 04:59:17 +00001223 self.assertRaises(TypeError, hash, Decimal('NaN'))
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001224 self.assertTrue(hash(Decimal('Inf')))
1225 self.assertTrue(hash(Decimal('-Inf')))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001226
Christian Heimes2380ac72008-01-09 00:17:24 +00001227 # check that the value of the hash doesn't depend on the
1228 # current context (issue #1757)
1229 c = getcontext()
1230 old_precision = c.prec
1231 x = Decimal("123456789.1")
1232
1233 c.prec = 6
1234 h1 = hash(x)
1235 c.prec = 10
1236 h2 = hash(x)
1237 c.prec = 16
1238 h3 = hash(x)
1239
1240 self.assertEqual(h1, h2)
1241 self.assertEqual(h1, h3)
1242 c.prec = old_precision
1243
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001244 def test_min_and_max_methods(self):
1245
1246 d1 = Decimal('15.32')
1247 d2 = Decimal('28.5')
1248 l1 = 15
1249 l2 = 28
1250
1251 #between Decimals
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001252 self.assertTrue(min(d1,d2) is d1)
1253 self.assertTrue(min(d2,d1) is d1)
1254 self.assertTrue(max(d1,d2) is d2)
1255 self.assertTrue(max(d2,d1) is d2)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001256
1257 #between Decimal and long
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001258 self.assertTrue(min(d1,l2) is d1)
1259 self.assertTrue(min(l2,d1) is d1)
1260 self.assertTrue(max(l1,d2) is d2)
1261 self.assertTrue(max(d2,l1) is d2)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001262
1263 def test_as_nonzero(self):
1264 #as false
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001265 self.assertFalse(Decimal(0))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001266 #as true
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001267 self.assertTrue(Decimal('0.372'))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001268
1269 def test_tostring_methods(self):
1270 #Test str and repr methods.
1271
1272 d = Decimal('15.32')
1273 self.assertEqual(str(d), '15.32') # str
Christian Heimes68f5fbe2008-02-14 08:27:37 +00001274 self.assertEqual(repr(d), "Decimal('15.32')") # repr
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001275
1276 def test_tonum_methods(self):
1277 #Test float, int and long methods.
1278
1279 d1 = Decimal('66')
1280 d2 = Decimal('15.32')
1281
1282 #int
1283 self.assertEqual(int(d1), 66)
1284 self.assertEqual(int(d2), 15)
1285
1286 #long
Guido van Rossume2a383d2007-01-15 16:59:06 +00001287 self.assertEqual(int(d1), 66)
1288 self.assertEqual(int(d2), 15)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001289
1290 #float
1291 self.assertEqual(float(d1), 66)
1292 self.assertEqual(float(d2), 15.32)
1293
Mark Dickinsonb27406c2008-05-09 13:42:33 +00001294 #floor
1295 test_pairs = [
1296 ('123.00', 123),
1297 ('3.2', 3),
1298 ('3.54', 3),
1299 ('3.899', 3),
1300 ('-2.3', -3),
1301 ('-11.0', -11),
1302 ('0.0', 0),
1303 ('-0E3', 0),
1304 ]
1305 for d, i in test_pairs:
1306 self.assertEqual(math.floor(Decimal(d)), i)
1307 self.assertRaises(ValueError, math.floor, Decimal('-NaN'))
1308 self.assertRaises(ValueError, math.floor, Decimal('sNaN'))
1309 self.assertRaises(ValueError, math.floor, Decimal('NaN123'))
1310 self.assertRaises(OverflowError, math.floor, Decimal('Inf'))
1311 self.assertRaises(OverflowError, math.floor, Decimal('-Inf'))
1312
1313 #ceiling
1314 test_pairs = [
1315 ('123.00', 123),
1316 ('3.2', 4),
1317 ('3.54', 4),
1318 ('3.899', 4),
1319 ('-2.3', -2),
1320 ('-11.0', -11),
1321 ('0.0', 0),
1322 ('-0E3', 0),
1323 ]
1324 for d, i in test_pairs:
1325 self.assertEqual(math.ceil(Decimal(d)), i)
1326 self.assertRaises(ValueError, math.ceil, Decimal('-NaN'))
1327 self.assertRaises(ValueError, math.ceil, Decimal('sNaN'))
1328 self.assertRaises(ValueError, math.ceil, Decimal('NaN123'))
1329 self.assertRaises(OverflowError, math.ceil, Decimal('Inf'))
1330 self.assertRaises(OverflowError, math.ceil, Decimal('-Inf'))
1331
1332 #round, single argument
1333 test_pairs = [
1334 ('123.00', 123),
1335 ('3.2', 3),
1336 ('3.54', 4),
1337 ('3.899', 4),
1338 ('-2.3', -2),
1339 ('-11.0', -11),
1340 ('0.0', 0),
1341 ('-0E3', 0),
1342 ('-3.5', -4),
1343 ('-2.5', -2),
1344 ('-1.5', -2),
1345 ('-0.5', 0),
1346 ('0.5', 0),
1347 ('1.5', 2),
1348 ('2.5', 2),
1349 ('3.5', 4),
1350 ]
1351 for d, i in test_pairs:
1352 self.assertEqual(round(Decimal(d)), i)
1353 self.assertRaises(ValueError, round, Decimal('-NaN'))
1354 self.assertRaises(ValueError, round, Decimal('sNaN'))
1355 self.assertRaises(ValueError, round, Decimal('NaN123'))
1356 self.assertRaises(OverflowError, round, Decimal('Inf'))
1357 self.assertRaises(OverflowError, round, Decimal('-Inf'))
1358
1359 #round, two arguments; this is essentially equivalent
1360 #to quantize, which is already extensively tested
1361 test_triples = [
1362 ('123.456', -4, '0E+4'),
1363 ('123.456', -3, '0E+3'),
1364 ('123.456', -2, '1E+2'),
1365 ('123.456', -1, '1.2E+2'),
1366 ('123.456', 0, '123'),
1367 ('123.456', 1, '123.5'),
1368 ('123.456', 2, '123.46'),
1369 ('123.456', 3, '123.456'),
1370 ('123.456', 4, '123.4560'),
1371 ('123.455', 2, '123.46'),
1372 ('123.445', 2, '123.44'),
1373 ('Inf', 4, 'NaN'),
1374 ('-Inf', -23, 'NaN'),
1375 ('sNaN314', 3, 'NaN314'),
1376 ]
1377 for d, n, r in test_triples:
1378 self.assertEqual(str(round(Decimal(d), n)), r)
1379
1380
1381
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001382 def test_eval_round_trip(self):
1383
1384 #with zero
1385 d = Decimal( (0, (0,), 0) )
1386 self.assertEqual(d, eval(repr(d)))
1387
1388 #int
1389 d = Decimal( (1, (4, 5), 0) )
1390 self.assertEqual(d, eval(repr(d)))
1391
1392 #float
1393 d = Decimal( (0, (4, 5, 3, 4), -2) )
1394 self.assertEqual(d, eval(repr(d)))
1395
1396 #weird
1397 d = Decimal( (1, (4, 3, 4, 9, 1, 3, 5, 3, 4), -25) )
1398 self.assertEqual(d, eval(repr(d)))
1399
1400 def test_as_tuple(self):
1401
1402 #with zero
1403 d = Decimal(0)
1404 self.assertEqual(d.as_tuple(), (0, (0,), 0) )
1405
1406 #int
1407 d = Decimal(-45)
1408 self.assertEqual(d.as_tuple(), (1, (4, 5), 0) )
1409
1410 #complicated string
1411 d = Decimal("-4.34913534E-17")
1412 self.assertEqual(d.as_tuple(), (1, (4, 3, 4, 9, 1, 3, 5, 3, 4), -25) )
1413
1414 #inf
1415 d = Decimal("Infinity")
1416 self.assertEqual(d.as_tuple(), (0, (0,), 'F') )
1417
Guido van Rossum8ce8a782007-11-01 19:42:39 +00001418 #leading zeros in coefficient should be stripped
1419 d = Decimal( (0, (0, 0, 4, 0, 5, 3, 4), -2) )
1420 self.assertEqual(d.as_tuple(), (0, (4, 0, 5, 3, 4), -2) )
1421 d = Decimal( (1, (0, 0, 0), 37) )
1422 self.assertEqual(d.as_tuple(), (1, (0,), 37))
1423 d = Decimal( (1, (), 37) )
1424 self.assertEqual(d.as_tuple(), (1, (0,), 37))
1425
1426 #leading zeros in NaN diagnostic info should be stripped
1427 d = Decimal( (0, (0, 0, 4, 0, 5, 3, 4), 'n') )
1428 self.assertEqual(d.as_tuple(), (0, (4, 0, 5, 3, 4), 'n') )
1429 d = Decimal( (1, (0, 0, 0), 'N') )
1430 self.assertEqual(d.as_tuple(), (1, (), 'N') )
1431 d = Decimal( (1, (), 'n') )
1432 self.assertEqual(d.as_tuple(), (1, (), 'n') )
1433
1434 #coefficient in infinity should be ignored
1435 d = Decimal( (0, (4, 5, 3, 4), 'F') )
1436 self.assertEqual(d.as_tuple(), (0, (0,), 'F'))
1437 d = Decimal( (1, (0, 2, 7, 1), 'F') )
1438 self.assertEqual(d.as_tuple(), (1, (0,), 'F'))
1439
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001440 def test_immutability_operations(self):
1441 # Do operations and check that it didn't change change internal objects.
1442
1443 d1 = Decimal('-25e55')
1444 b1 = Decimal('-25e55')
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001445 d2 = Decimal('33e+33')
1446 b2 = Decimal('33e+33')
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001447
1448 def checkSameDec(operation, useOther=False):
1449 if useOther:
1450 eval("d1." + operation + "(d2)")
1451 self.assertEqual(d1._sign, b1._sign)
1452 self.assertEqual(d1._int, b1._int)
1453 self.assertEqual(d1._exp, b1._exp)
1454 self.assertEqual(d2._sign, b2._sign)
1455 self.assertEqual(d2._int, b2._int)
1456 self.assertEqual(d2._exp, b2._exp)
1457 else:
1458 eval("d1." + operation + "()")
1459 self.assertEqual(d1._sign, b1._sign)
1460 self.assertEqual(d1._int, b1._int)
1461 self.assertEqual(d1._exp, b1._exp)
1462 return
1463
1464 Decimal(d1)
1465 self.assertEqual(d1._sign, b1._sign)
1466 self.assertEqual(d1._int, b1._int)
1467 self.assertEqual(d1._exp, b1._exp)
1468
1469 checkSameDec("__abs__")
1470 checkSameDec("__add__", True)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001471 checkSameDec("__divmod__", True)
Christian Heimes77c02eb2008-02-09 02:18:51 +00001472 checkSameDec("__eq__", True)
1473 checkSameDec("__ne__", True)
1474 checkSameDec("__le__", True)
1475 checkSameDec("__lt__", True)
1476 checkSameDec("__ge__", True)
1477 checkSameDec("__gt__", True)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001478 checkSameDec("__float__")
1479 checkSameDec("__floordiv__", True)
1480 checkSameDec("__hash__")
1481 checkSameDec("__int__")
Christian Heimes969fe572008-01-25 11:23:10 +00001482 checkSameDec("__trunc__")
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001483 checkSameDec("__mod__", True)
1484 checkSameDec("__mul__", True)
1485 checkSameDec("__neg__")
Jack Diederich4dafcc42006-11-28 19:15:13 +00001486 checkSameDec("__bool__")
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001487 checkSameDec("__pos__")
1488 checkSameDec("__pow__", True)
1489 checkSameDec("__radd__", True)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001490 checkSameDec("__rdivmod__", True)
1491 checkSameDec("__repr__")
1492 checkSameDec("__rfloordiv__", True)
1493 checkSameDec("__rmod__", True)
1494 checkSameDec("__rmul__", True)
1495 checkSameDec("__rpow__", True)
1496 checkSameDec("__rsub__", True)
1497 checkSameDec("__str__")
1498 checkSameDec("__sub__", True)
1499 checkSameDec("__truediv__", True)
1500 checkSameDec("adjusted")
1501 checkSameDec("as_tuple")
1502 checkSameDec("compare", True)
1503 checkSameDec("max", True)
1504 checkSameDec("min", True)
1505 checkSameDec("normalize")
1506 checkSameDec("quantize", True)
1507 checkSameDec("remainder_near", True)
1508 checkSameDec("same_quantum", True)
1509 checkSameDec("sqrt")
1510 checkSameDec("to_eng_string")
1511 checkSameDec("to_integral")
1512
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001513 def test_subclassing(self):
1514 # Different behaviours when subclassing Decimal
1515
1516 class MyDecimal(Decimal):
1517 pass
1518
1519 d1 = MyDecimal(1)
1520 d2 = MyDecimal(2)
1521 d = d1 + d2
1522 self.assertTrue(type(d) is Decimal)
1523
1524 d = d1.max(d2)
1525 self.assertTrue(type(d) is Decimal)
1526
Christian Heimes0348fb62008-03-26 12:55:56 +00001527 def test_implicit_context(self):
1528 # Check results when context given implicitly. (Issue 2478)
1529 c = getcontext()
1530 self.assertEqual(str(Decimal(0).sqrt()),
1531 str(c.sqrt(Decimal(0))))
1532
Mark Dickinsona2d1fe02009-10-29 12:23:02 +00001533 def test_conversions_from_int(self):
1534 # Check that methods taking a second Decimal argument will
1535 # always accept an integer in place of a Decimal.
1536 self.assertEqual(Decimal(4).compare(3),
1537 Decimal(4).compare(Decimal(3)))
1538 self.assertEqual(Decimal(4).compare_signal(3),
1539 Decimal(4).compare_signal(Decimal(3)))
1540 self.assertEqual(Decimal(4).compare_total(3),
1541 Decimal(4).compare_total(Decimal(3)))
1542 self.assertEqual(Decimal(4).compare_total_mag(3),
1543 Decimal(4).compare_total_mag(Decimal(3)))
1544 self.assertEqual(Decimal(10101).logical_and(1001),
1545 Decimal(10101).logical_and(Decimal(1001)))
1546 self.assertEqual(Decimal(10101).logical_or(1001),
1547 Decimal(10101).logical_or(Decimal(1001)))
1548 self.assertEqual(Decimal(10101).logical_xor(1001),
1549 Decimal(10101).logical_xor(Decimal(1001)))
1550 self.assertEqual(Decimal(567).max(123),
1551 Decimal(567).max(Decimal(123)))
1552 self.assertEqual(Decimal(567).max_mag(123),
1553 Decimal(567).max_mag(Decimal(123)))
1554 self.assertEqual(Decimal(567).min(123),
1555 Decimal(567).min(Decimal(123)))
1556 self.assertEqual(Decimal(567).min_mag(123),
1557 Decimal(567).min_mag(Decimal(123)))
1558 self.assertEqual(Decimal(567).next_toward(123),
1559 Decimal(567).next_toward(Decimal(123)))
1560 self.assertEqual(Decimal(1234).quantize(100),
1561 Decimal(1234).quantize(Decimal(100)))
1562 self.assertEqual(Decimal(768).remainder_near(1234),
1563 Decimal(768).remainder_near(Decimal(1234)))
1564 self.assertEqual(Decimal(123).rotate(1),
1565 Decimal(123).rotate(Decimal(1)))
1566 self.assertEqual(Decimal(1234).same_quantum(1000),
1567 Decimal(1234).same_quantum(Decimal(1000)))
1568 self.assertEqual(Decimal('9.123').scaleb(-100),
1569 Decimal('9.123').scaleb(Decimal(-100)))
1570 self.assertEqual(Decimal(456).shift(-1),
1571 Decimal(456).shift(Decimal(-1)))
1572
1573 self.assertEqual(Decimal(-12).fma(Decimal(45), 67),
1574 Decimal(-12).fma(Decimal(45), Decimal(67)))
1575 self.assertEqual(Decimal(-12).fma(45, 67),
1576 Decimal(-12).fma(Decimal(45), Decimal(67)))
1577 self.assertEqual(Decimal(-12).fma(45, Decimal(67)),
1578 Decimal(-12).fma(Decimal(45), Decimal(67)))
1579
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001580
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001581class DecimalPythonAPItests(unittest.TestCase):
1582
Raymond Hettinger82417ca2009-02-03 03:54:28 +00001583 def test_abc(self):
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001584 self.assertTrue(issubclass(Decimal, numbers.Number))
1585 self.assertTrue(not issubclass(Decimal, numbers.Real))
1586 self.assertTrue(isinstance(Decimal(0), numbers.Number))
1587 self.assertTrue(not isinstance(Decimal(0), numbers.Real))
Raymond Hettinger82417ca2009-02-03 03:54:28 +00001588
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001589 def test_pickle(self):
1590 d = Decimal('-3.141590000')
1591 p = pickle.dumps(d)
1592 e = pickle.loads(p)
1593 self.assertEqual(d, e)
1594
Raymond Hettinger5548be22004-07-05 18:49:38 +00001595 def test_int(self):
Raymond Hettinger605ed022004-11-24 07:28:48 +00001596 for x in range(-250, 250):
1597 s = '%0.2f' % (x / 100.0)
Raymond Hettinger5548be22004-07-05 18:49:38 +00001598 # should work the same as for floats
1599 self.assertEqual(int(Decimal(s)), int(float(s)))
Raymond Hettinger605ed022004-11-24 07:28:48 +00001600 # should work the same as to_integral in the ROUND_DOWN mode
Raymond Hettinger5548be22004-07-05 18:49:38 +00001601 d = Decimal(s)
Raymond Hettinger605ed022004-11-24 07:28:48 +00001602 r = d.to_integral(ROUND_DOWN)
Raymond Hettinger5548be22004-07-05 18:49:38 +00001603 self.assertEqual(Decimal(int(d)), r)
1604
Mark Dickinson825fce32009-09-07 18:08:12 +00001605 self.assertRaises(ValueError, int, Decimal('-nan'))
1606 self.assertRaises(ValueError, int, Decimal('snan'))
1607 self.assertRaises(OverflowError, int, Decimal('inf'))
1608 self.assertRaises(OverflowError, int, Decimal('-inf'))
1609
Christian Heimes969fe572008-01-25 11:23:10 +00001610 def test_trunc(self):
1611 for x in range(-250, 250):
1612 s = '%0.2f' % (x / 100.0)
1613 # should work the same as for floats
1614 self.assertEqual(int(Decimal(s)), int(float(s)))
1615 # should work the same as to_integral in the ROUND_DOWN mode
1616 d = Decimal(s)
1617 r = d.to_integral(ROUND_DOWN)
Christian Heimes400adb02008-02-01 08:12:03 +00001618 self.assertEqual(Decimal(math.trunc(d)), r)
Christian Heimes969fe572008-01-25 11:23:10 +00001619
Raymond Hettinger771ed762009-01-03 19:20:32 +00001620 def test_from_float(self):
1621
1622 class MyDecimal(Decimal):
1623 pass
1624
1625 r = MyDecimal.from_float(0.1)
1626 self.assertEqual(type(r), MyDecimal)
1627 self.assertEqual(str(r),
1628 '0.1000000000000000055511151231257827021181583404541015625')
1629 bigint = 12345678901234567890123456789
1630 self.assertEqual(MyDecimal.from_float(bigint), MyDecimal(bigint))
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001631 self.assertTrue(MyDecimal.from_float(float('nan')).is_qnan())
1632 self.assertTrue(MyDecimal.from_float(float('inf')).is_infinite())
1633 self.assertTrue(MyDecimal.from_float(float('-inf')).is_infinite())
Raymond Hettinger771ed762009-01-03 19:20:32 +00001634 self.assertEqual(str(MyDecimal.from_float(float('nan'))),
1635 str(Decimal('NaN')))
1636 self.assertEqual(str(MyDecimal.from_float(float('inf'))),
1637 str(Decimal('Infinity')))
1638 self.assertEqual(str(MyDecimal.from_float(float('-inf'))),
1639 str(Decimal('-Infinity')))
1640 self.assertRaises(TypeError, MyDecimal.from_float, 'abc')
1641 for i in range(200):
1642 x = random.expovariate(0.01) * (random.random() * 2.0 - 1.0)
1643 self.assertEqual(x, float(MyDecimal.from_float(x))) # roundtrip
1644
1645 def test_create_decimal_from_float(self):
1646 context = Context(prec=5, rounding=ROUND_DOWN)
1647 self.assertEqual(
1648 context.create_decimal_from_float(math.pi),
1649 Decimal('3.1415')
1650 )
1651 context = Context(prec=5, rounding=ROUND_UP)
1652 self.assertEqual(
1653 context.create_decimal_from_float(math.pi),
1654 Decimal('3.1416')
1655 )
1656 context = Context(prec=5, traps=[Inexact])
1657 self.assertRaises(
1658 Inexact,
1659 context.create_decimal_from_float,
1660 math.pi
1661 )
1662 self.assertEqual(repr(context.create_decimal_from_float(-0.0)),
1663 "Decimal('-0')")
1664 self.assertEqual(repr(context.create_decimal_from_float(1.0)),
1665 "Decimal('1')")
1666 self.assertEqual(repr(context.create_decimal_from_float(10)),
1667 "Decimal('10')")
1668
Raymond Hettingerd9c0a7a2004-07-03 10:02:28 +00001669class ContextAPItests(unittest.TestCase):
1670
1671 def test_pickle(self):
1672 c = Context()
1673 e = pickle.loads(pickle.dumps(c))
1674 for k in vars(c):
1675 v1 = vars(c)[k]
1676 v2 = vars(e)[k]
1677 self.assertEqual(v1, v2)
1678
Raymond Hettinger0aeac102004-07-05 22:53:03 +00001679 def test_equality_with_other_types(self):
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001680 self.assertTrue(Decimal(10) in ['a', 1.0, Decimal(10), (1,2), {}])
1681 self.assertTrue(Decimal(10) not in ['a', 1.0, (1,2), {}])
Raymond Hettinger0aeac102004-07-05 22:53:03 +00001682
Raymond Hettinger955d2b22004-08-08 20:17:45 +00001683 def test_copy(self):
1684 # All copies should be deep
1685 c = Context()
1686 d = c.copy()
1687 self.assertNotEqual(id(c), id(d))
1688 self.assertNotEqual(id(c.flags), id(d.flags))
1689 self.assertNotEqual(id(c.traps), id(d.traps))
1690
Thomas Wouters89f507f2006-12-13 04:49:30 +00001691class WithStatementTest(unittest.TestCase):
1692 # Can't do these as docstrings until Python 2.6
1693 # as doctest can't handle __future__ statements
1694
1695 def test_localcontext(self):
1696 # Use a copy of the current context in the block
1697 orig_ctx = getcontext()
1698 with localcontext() as enter_ctx:
1699 set_ctx = getcontext()
1700 final_ctx = getcontext()
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001701 self.assertTrue(orig_ctx is final_ctx, 'did not restore context correctly')
1702 self.assertTrue(orig_ctx is not set_ctx, 'did not copy the context')
1703 self.assertTrue(set_ctx is enter_ctx, '__enter__ returned wrong context')
Thomas Wouters89f507f2006-12-13 04:49:30 +00001704
1705 def test_localcontextarg(self):
1706 # Use a copy of the supplied context in the block
1707 orig_ctx = getcontext()
1708 new_ctx = Context(prec=42)
1709 with localcontext(new_ctx) as enter_ctx:
1710 set_ctx = getcontext()
1711 final_ctx = getcontext()
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001712 self.assertTrue(orig_ctx is final_ctx, 'did not restore context correctly')
1713 self.assertTrue(set_ctx.prec == new_ctx.prec, 'did not set correct context')
1714 self.assertTrue(new_ctx is not set_ctx, 'did not copy the context')
1715 self.assertTrue(set_ctx is enter_ctx, '__enter__ returned wrong context')
Thomas Wouters89f507f2006-12-13 04:49:30 +00001716
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001717class ContextFlags(unittest.TestCase):
1718 def test_flags_irrelevant(self):
1719 # check that the result (numeric result + flags raised) of an
1720 # arithmetic operation doesn't depend on the current flags
1721
1722 context = Context(prec=9, Emin = -999999999, Emax = 999999999,
1723 rounding=ROUND_HALF_EVEN, traps=[], flags=[])
1724
1725 # operations that raise various flags, in the form (function, arglist)
1726 operations = [
1727 (context._apply, [Decimal("100E-1000000009")]),
1728 (context.sqrt, [Decimal(2)]),
1729 (context.add, [Decimal("1.23456789"), Decimal("9.87654321")]),
1730 (context.multiply, [Decimal("1.23456789"), Decimal("9.87654321")]),
1731 (context.subtract, [Decimal("1.23456789"), Decimal("9.87654321")]),
1732 ]
1733
1734 # try various flags individually, then a whole lot at once
1735 flagsets = [[Inexact], [Rounded], [Underflow], [Clamped], [Subnormal],
1736 [Inexact, Rounded, Underflow, Clamped, Subnormal]]
1737
1738 for fn, args in operations:
1739 # find answer and flags raised using a clean context
1740 context.clear_flags()
1741 ans = fn(*args)
1742 flags = [k for k, v in context.flags.items() if v]
1743
1744 for extra_flags in flagsets:
1745 # set flags, before calling operation
1746 context.clear_flags()
1747 for flag in extra_flags:
1748 context._raise_error(flag)
1749 new_ans = fn(*args)
1750
1751 # flags that we expect to be set after the operation
1752 expected_flags = list(flags)
1753 for flag in extra_flags:
1754 if flag not in expected_flags:
1755 expected_flags.append(flag)
1756 expected_flags.sort(key=id)
1757
1758 # flags we actually got
1759 new_flags = [k for k,v in context.flags.items() if v]
1760 new_flags.sort(key=id)
1761
1762 self.assertEqual(ans, new_ans,
1763 "operation produces different answers depending on flags set: " +
1764 "expected %s, got %s." % (ans, new_ans))
1765 self.assertEqual(new_flags, expected_flags,
1766 "operation raises different flags depending on flags set: " +
1767 "expected %s, got %s" % (expected_flags, new_flags))
1768
1769def test_main(arith=False, verbose=None, todo_tests=None, debug=None):
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001770 """ Execute the tests.
1771
Raymond Hettingered20ad82004-09-04 20:09:13 +00001772 Runs all arithmetic tests if arith is True or if the "decimal" resource
1773 is enabled in regrtest.py
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001774 """
Raymond Hettingered20ad82004-09-04 20:09:13 +00001775
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00001776 init()
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001777 global TEST_ALL, DEBUG
Raymond Hettingered20ad82004-09-04 20:09:13 +00001778 TEST_ALL = arith or is_resource_enabled('decimal')
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001779 DEBUG = debug
Raymond Hettingered20ad82004-09-04 20:09:13 +00001780
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001781 if todo_tests is None:
1782 test_classes = [
1783 DecimalExplicitConstructionTest,
1784 DecimalImplicitConstructionTest,
1785 DecimalArithmeticOperatorsTest,
Christian Heimesf16baeb2008-02-29 14:57:44 +00001786 DecimalFormatTest,
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001787 DecimalUseOfContextTest,
1788 DecimalUsabilityTest,
1789 DecimalPythonAPItests,
1790 ContextAPItests,
1791 DecimalTest,
1792 WithStatementTest,
1793 ContextFlags
1794 ]
1795 else:
1796 test_classes = [DecimalTest]
1797
1798 # Dynamically build custom test definition for each file in the test
1799 # directory and add the definitions to the DecimalTest class. This
1800 # procedure insures that new files do not get skipped.
1801 for filename in os.listdir(directory):
1802 if '.decTest' not in filename or filename.startswith("."):
1803 continue
1804 head, tail = filename.split('.')
1805 if todo_tests is not None and head not in todo_tests:
1806 continue
1807 tester = lambda self, f=filename: self.eval_file(directory + f)
1808 setattr(DecimalTest, 'test_' + head, tester)
1809 del filename, head, tail, tester
1810
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001811
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00001812 try:
1813 run_unittest(*test_classes)
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001814 if todo_tests is None:
1815 import decimal as DecimalModule
1816 run_doctest(DecimalModule, verbose)
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00001817 finally:
1818 setcontext(ORIGINAL_CONTEXT)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001819
1820if __name__ == '__main__':
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001821 import optparse
1822 p = optparse.OptionParser("test_decimal.py [--debug] [{--skip | test1 [test2 [...]]}]")
1823 p.add_option('--debug', '-d', action='store_true', help='shows the test number and context before each test')
1824 p.add_option('--skip', '-s', action='store_true', help='skip over 90% of the arithmetic tests')
1825 (opt, args) = p.parse_args()
1826
1827 if opt.skip:
1828 test_main(arith=False, verbose=True)
1829 elif args:
1830 test_main(arith=True, verbose=True, todo_tests=args, debug=opt.debug)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001831 else:
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001832 test_main(arith=True, verbose=True)