blob: f0c44315bdb731a206c1c383248dcc2d1a8434dd [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
66# Make sure it actually raises errors when not expected and caught in flags
67# Slower, since it runs some things several times.
68EXTENDEDERRORTEST = False
69
Raymond Hettinger7c85fa42004-07-01 11:01:35 +000070#Map the test cases' error names to the actual errors
Raymond Hettinger7c85fa42004-07-01 11:01:35 +000071ErrorNames = {'clamped' : Clamped,
Raymond Hettinger5aa478b2004-07-09 10:02:53 +000072 'conversion_syntax' : InvalidOperation,
Raymond Hettinger7c85fa42004-07-01 11:01:35 +000073 'division_by_zero' : DivisionByZero,
Raymond Hettinger5aa478b2004-07-09 10:02:53 +000074 'division_impossible' : InvalidOperation,
75 'division_undefined' : InvalidOperation,
Raymond Hettinger7c85fa42004-07-01 11:01:35 +000076 'inexact' : Inexact,
Raymond Hettinger5aa478b2004-07-09 10:02:53 +000077 'invalid_context' : InvalidOperation,
Raymond Hettinger7c85fa42004-07-01 11:01:35 +000078 'invalid_operation' : InvalidOperation,
79 'overflow' : Overflow,
80 'rounded' : Rounded,
81 'subnormal' : Subnormal,
82 'underflow' : Underflow}
83
84
85def Nonfunction(*args):
86 """Doesn't do anything."""
87 return None
88
89RoundingDict = {'ceiling' : ROUND_CEILING, #Maps test-case names to roundings.
90 'down' : ROUND_DOWN,
91 'floor' : ROUND_FLOOR,
92 'half_down' : ROUND_HALF_DOWN,
93 'half_even' : ROUND_HALF_EVEN,
94 'half_up' : ROUND_HALF_UP,
Thomas Wouters1b7f8912007-09-19 03:06:30 +000095 'up' : ROUND_UP,
96 '05up' : ROUND_05UP}
Raymond Hettinger7c85fa42004-07-01 11:01:35 +000097
98# Name adapter to be able to change the Decimal and Context
99# interface without changing the test files from Cowlishaw
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000100nameAdapter = {'and':'logical_and',
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000101 'apply':'_apply',
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000102 'class':'number_class',
103 'comparesig':'compare_signal',
104 'comparetotal':'compare_total',
105 'comparetotmag':'compare_total_mag',
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000106 'copy':'copy_decimal',
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000107 'copyabs':'copy_abs',
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000108 'copynegate':'copy_negate',
109 'copysign':'copy_sign',
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000110 'divideint':'divide_int',
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000111 'invert':'logical_invert',
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000112 'iscanonical':'is_canonical',
113 'isfinite':'is_finite',
114 'isinfinite':'is_infinite',
115 'isnan':'is_nan',
116 'isnormal':'is_normal',
117 'isqnan':'is_qnan',
118 'issigned':'is_signed',
119 'issnan':'is_snan',
120 'issubnormal':'is_subnormal',
121 'iszero':'is_zero',
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000122 'maxmag':'max_mag',
123 'minmag':'min_mag',
124 'nextminus':'next_minus',
125 'nextplus':'next_plus',
126 'nexttoward':'next_toward',
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000127 'or':'logical_or',
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000128 'reduce':'normalize',
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000129 'remaindernear':'remainder_near',
130 'samequantum':'same_quantum',
131 'squareroot':'sqrt',
132 'toeng':'to_eng_string',
133 'tointegral':'to_integral_value',
134 'tointegralx':'to_integral_exact',
135 'tosci':'to_sci_string',
136 'xor':'logical_xor',
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000137 }
138
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000139# The following functions return True/False rather than a Decimal instance
140
141LOGICAL_FUNCTIONS = (
142 'is_canonical',
143 'is_finite',
144 'is_infinite',
145 'is_nan',
146 'is_normal',
147 'is_qnan',
148 'is_signed',
149 'is_snan',
150 'is_subnormal',
151 'is_zero',
152 'same_quantum',
153 )
154
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000155# For some operations (currently exp, ln, log10, power), the decNumber
156# reference implementation imposes additional restrictions on the
157# context and operands. These restrictions are not part of the
158# specification; however, the effect of these restrictions does show
159# up in some of the testcases. We skip testcases that violate these
160# restrictions, since Decimal behaves differently from decNumber for
161# these testcases so these testcases would otherwise fail.
162
163decNumberRestricted = ('power', 'ln', 'log10', 'exp')
164DEC_MAX_MATH = 999999
165def outside_decNumber_bounds(v, context):
166 if (context.prec > DEC_MAX_MATH or
167 context.Emax > DEC_MAX_MATH or
168 -context.Emin > DEC_MAX_MATH):
169 return True
170 if not v._is_special and v and (
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000171 v.adjusted() > DEC_MAX_MATH or
172 v.adjusted() < 1-2*DEC_MAX_MATH):
173 return True
174 return False
175
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000176class DecimalTest(unittest.TestCase):
177 """Class which tests the Decimal class against the test cases.
178
179 Changed for unittest.
180 """
181 def setUp(self):
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000182 self.context = Context()
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000183 self.ignore_list = ['#']
184 # Basically, a # means return NaN InvalidOperation.
185 # Different from a sNaN in trim
186
187 self.ChangeDict = {'precision' : self.change_precision,
188 'rounding' : self.change_rounding_method,
189 'maxexponent' : self.change_max_exponent,
190 'minexponent' : self.change_min_exponent,
191 'clamp' : self.change_clamp}
192
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000193 def eval_file(self, file):
194 global skip_expected
195 if skip_expected:
Benjamin Petersone549ead2009-03-28 21:42:05 +0000196 raise unittest.SkipTest
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000197 return
Neal Norwitz70967602006-03-17 08:29:44 +0000198 for line in open(file):
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000199 line = line.replace('\r\n', '').replace('\n', '')
Raymond Hettinger5aa478b2004-07-09 10:02:53 +0000200 #print line
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000201 try:
202 t = self.eval_line(line)
Guido van Rossumb940e112007-01-10 16:19:56 +0000203 except DecimalException as exception:
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000204 #Exception raised where there shoudn't have been one.
205 self.fail('Exception "'+exception.__class__.__name__ + '" raised on line '+line)
206
207 return
208
209 def eval_line(self, s):
210 if s.find(' -> ') >= 0 and s[:2] != '--' and not s.startswith(' --'):
211 s = (s.split('->')[0] + '->' +
212 s.split('->')[1].split('--')[0]).strip()
213 else:
214 s = s.split('--')[0].strip()
215
216 for ignore in self.ignore_list:
217 if s.find(ignore) >= 0:
218 #print s.split()[0], 'NotImplemented--', ignore
219 return
220 if not s:
221 return
222 elif ':' in s:
223 return self.eval_directive(s)
224 else:
225 return self.eval_equation(s)
226
227 def eval_directive(self, s):
Guido van Rossumc1f779c2007-07-03 08:25:58 +0000228 funct, value = (x.strip().lower() for x in s.split(':'))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000229 if funct == 'rounding':
230 value = RoundingDict[value]
231 else:
232 try:
233 value = int(value)
234 except ValueError:
235 pass
236
237 funct = self.ChangeDict.get(funct, Nonfunction)
238 funct(value)
239
240 def eval_equation(self, s):
241 #global DEFAULT_PRECISION
242 #print DEFAULT_PRECISION
Raymond Hettingered20ad82004-09-04 20:09:13 +0000243
244 if not TEST_ALL and random.random() < 0.90:
245 return
246
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000247 try:
248 Sides = s.split('->')
249 L = Sides[0].strip().split()
250 id = L[0]
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000251 if DEBUG:
252 print("Test ", id, end=" ")
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000253 funct = L[1].lower()
254 valstemp = L[2:]
255 L = Sides[1].strip().split()
256 ans = L[0]
257 exceptions = L[1:]
258 except (TypeError, AttributeError, IndexError):
Raymond Hettingerd87ac8f2004-07-09 10:52:54 +0000259 raise InvalidOperation
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000260 def FixQuotes(val):
261 val = val.replace("''", 'SingleQuote').replace('""', 'DoubleQuote')
262 val = val.replace("'", '').replace('"', '')
263 val = val.replace('SingleQuote', "'").replace('DoubleQuote', '"')
264 return val
265 fname = nameAdapter.get(funct, funct)
266 if fname == 'rescale':
267 return
268 funct = getattr(self.context, fname)
269 vals = []
270 conglomerate = ''
271 quote = 0
272 theirexceptions = [ErrorNames[x.lower()] for x in exceptions]
273
Raymond Hettingerd9c0a7a2004-07-03 10:02:28 +0000274 for exception in Signals:
Raymond Hettingerbf440692004-07-10 14:14:37 +0000275 self.context.traps[exception] = 1 #Catch these bugs...
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000276 for exception in theirexceptions:
Raymond Hettingerbf440692004-07-10 14:14:37 +0000277 self.context.traps[exception] = 0
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000278 for i, val in enumerate(valstemp):
279 if val.count("'") % 2 == 1:
280 quote = 1 - quote
281 if quote:
282 conglomerate = conglomerate + ' ' + val
283 continue
284 else:
285 val = conglomerate + val
286 conglomerate = ''
287 v = FixQuotes(val)
288 if fname in ('to_sci_string', 'to_eng_string'):
289 if EXTENDEDERRORTEST:
290 for error in theirexceptions:
Raymond Hettingerbf440692004-07-10 14:14:37 +0000291 self.context.traps[error] = 1
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000292 try:
293 funct(self.context.create_decimal(v))
294 except error:
295 pass
Guido van Rossumb940e112007-01-10 16:19:56 +0000296 except Signals as e:
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000297 self.fail("Raised %s in %s when %s disabled" % \
298 (e, s, error))
299 else:
300 self.fail("Did not raise %s in %s" % (error, s))
Raymond Hettingerbf440692004-07-10 14:14:37 +0000301 self.context.traps[error] = 0
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000302 v = self.context.create_decimal(v)
303 else:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000304 v = Decimal(v, self.context)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000305 vals.append(v)
306
307 ans = FixQuotes(ans)
308
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000309 # skip tests that are related to bounds imposed in the decNumber
310 # reference implementation
311 if fname in decNumberRestricted:
312 if fname == 'power':
313 if not (vals[1]._isinteger() and
314 -1999999997 <= vals[1] <= 999999999):
315 if outside_decNumber_bounds(vals[0], self.context) or \
316 outside_decNumber_bounds(vals[1], self.context):
317 #print "Skipping test %s" % s
318 return
319 else:
320 if outside_decNumber_bounds(vals[0], self.context):
321 #print "Skipping test %s" % s
322 return
323
324
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000325 if EXTENDEDERRORTEST and fname not in ('to_sci_string', 'to_eng_string'):
326 for error in theirexceptions:
Raymond Hettingerbf440692004-07-10 14:14:37 +0000327 self.context.traps[error] = 1
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000328 try:
329 funct(*vals)
330 except error:
331 pass
Guido van Rossumb940e112007-01-10 16:19:56 +0000332 except Signals as e:
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000333 self.fail("Raised %s in %s when %s disabled" % \
334 (e, s, error))
335 else:
336 self.fail("Did not raise %s in %s" % (error, s))
Raymond Hettingerbf440692004-07-10 14:14:37 +0000337 self.context.traps[error] = 0
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000338 if DEBUG:
339 print("--", self.context)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000340 try:
341 result = str(funct(*vals))
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000342 if fname in LOGICAL_FUNCTIONS:
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000343 result = str(int(eval(result))) # 'True', 'False' -> '1', '0'
Guido van Rossumb940e112007-01-10 16:19:56 +0000344 except Signals as error:
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000345 self.fail("Raised %s in %s" % (error, s))
346 except: #Catch any error long enough to state the test case.
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000347 print("ERROR:", s)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000348 raise
349
350 myexceptions = self.getexceptions()
Raymond Hettingerbf440692004-07-10 14:14:37 +0000351 self.context.clear_flags()
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000352
Guido van Rossum47b9ff62006-08-24 00:41:19 +0000353 myexceptions.sort(key=repr)
354 theirexceptions.sort(key=repr)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000355
356 self.assertEqual(result, ans,
357 'Incorrect answer for ' + s + ' -- got ' + result)
358 self.assertEqual(myexceptions, theirexceptions,
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000359 'Incorrect flags set in ' + s + ' -- got ' + str(myexceptions))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000360 return
361
362 def getexceptions(self):
Raymond Hettingerf63ba432004-08-17 05:42:09 +0000363 return [e for e in Signals if self.context.flags[e]]
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000364
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000365 def change_precision(self, prec):
366 self.context.prec = prec
367 def change_rounding_method(self, rounding):
368 self.context.rounding = rounding
369 def change_min_exponent(self, exp):
370 self.context.Emin = exp
371 def change_max_exponent(self, exp):
372 self.context.Emax = exp
373 def change_clamp(self, clamp):
374 self.context._clamp = clamp
375
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000376
377
378# The following classes test the behaviour of Decimal according to PEP 327
379
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000380class DecimalExplicitConstructionTest(unittest.TestCase):
381 '''Unit tests for Explicit Construction cases of Decimal.'''
382
383 def test_explicit_empty(self):
384 self.assertEqual(Decimal(), Decimal("0"))
385
386 def test_explicit_from_None(self):
387 self.assertRaises(TypeError, Decimal, None)
388
389 def test_explicit_from_int(self):
390
391 #positive
392 d = Decimal(45)
393 self.assertEqual(str(d), '45')
394
395 #very large positive
396 d = Decimal(500000123)
397 self.assertEqual(str(d), '500000123')
398
399 #negative
400 d = Decimal(-45)
401 self.assertEqual(str(d), '-45')
402
403 #zero
404 d = Decimal(0)
405 self.assertEqual(str(d), '0')
406
407 def test_explicit_from_string(self):
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000408
409 #empty
410 self.assertEqual(str(Decimal('')), 'NaN')
411
412 #int
413 self.assertEqual(str(Decimal('45')), '45')
414
415 #float
416 self.assertEqual(str(Decimal('45.34')), '45.34')
417
418 #engineer notation
419 self.assertEqual(str(Decimal('45e2')), '4.5E+3')
420
421 #just not a number
422 self.assertEqual(str(Decimal('ugly')), 'NaN')
423
Christian Heimesa62da1d2008-01-12 19:39:10 +0000424 #leading and trailing whitespace permitted
425 self.assertEqual(str(Decimal('1.3E4 \n')), '1.3E+4')
426 self.assertEqual(str(Decimal(' -7.89')), '-7.89')
427
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000428 def test_explicit_from_tuples(self):
429
430 #zero
431 d = Decimal( (0, (0,), 0) )
432 self.assertEqual(str(d), '0')
433
434 #int
435 d = Decimal( (1, (4, 5), 0) )
436 self.assertEqual(str(d), '-45')
437
438 #float
439 d = Decimal( (0, (4, 5, 3, 4), -2) )
440 self.assertEqual(str(d), '45.34')
441
442 #weird
443 d = Decimal( (1, (4, 3, 4, 9, 1, 3, 5, 3, 4), -25) )
444 self.assertEqual(str(d), '-4.34913534E-17')
445
446 #wrong number of items
447 self.assertRaises(ValueError, Decimal, (1, (4, 3, 4, 9, 1)) )
448
449 #bad sign
450 self.assertRaises(ValueError, Decimal, (8, (4, 3, 4, 9, 1), 2) )
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000451 self.assertRaises(ValueError, Decimal, (0., (4, 3, 4, 9, 1), 2) )
452 self.assertRaises(ValueError, Decimal, (Decimal(1), (4, 3, 4, 9, 1), 2))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000453
454 #bad exp
455 self.assertRaises(ValueError, Decimal, (1, (4, 3, 4, 9, 1), 'wrong!') )
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000456 self.assertRaises(ValueError, Decimal, (1, (4, 3, 4, 9, 1), 0.) )
457 self.assertRaises(ValueError, Decimal, (1, (4, 3, 4, 9, 1), '1') )
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000458
459 #bad coefficients
460 self.assertRaises(ValueError, Decimal, (1, (4, 3, 4, None, 1), 2) )
461 self.assertRaises(ValueError, Decimal, (1, (4, -3, 4, 9, 1), 2) )
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000462 self.assertRaises(ValueError, Decimal, (1, (4, 10, 4, 9, 1), 2) )
Guido van Rossum0d3fb8a2007-11-26 23:23:18 +0000463 self.assertRaises(ValueError, Decimal, (1, (4, 3, 4, 'a', 1), 2) )
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000464
465 def test_explicit_from_Decimal(self):
466
467 #positive
468 d = Decimal(45)
469 e = Decimal(d)
470 self.assertEqual(str(e), '45')
471 self.assertNotEqual(id(d), id(e))
472
473 #very large positive
474 d = Decimal(500000123)
475 e = Decimal(d)
476 self.assertEqual(str(e), '500000123')
477 self.assertNotEqual(id(d), id(e))
478
479 #negative
480 d = Decimal(-45)
481 e = Decimal(d)
482 self.assertEqual(str(e), '-45')
483 self.assertNotEqual(id(d), id(e))
484
485 #zero
486 d = Decimal(0)
487 e = Decimal(d)
488 self.assertEqual(str(e), '0')
489 self.assertNotEqual(id(d), id(e))
490
491 def test_explicit_context_create_decimal(self):
492
493 nc = copy.copy(getcontext())
494 nc.prec = 3
495
496 # empty
Raymond Hettingerfed52962004-07-14 15:41:57 +0000497 d = Decimal()
498 self.assertEqual(str(d), '0')
499 d = nc.create_decimal()
500 self.assertEqual(str(d), '0')
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000501
502 # from None
503 self.assertRaises(TypeError, nc.create_decimal, None)
504
505 # from int
506 d = nc.create_decimal(456)
Georg Brandlab91fde2009-08-13 08:51:18 +0000507 self.assertTrue(isinstance(d, Decimal))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000508 self.assertEqual(nc.create_decimal(45678),
509 nc.create_decimal('457E+2'))
510
511 # from string
512 d = Decimal('456789')
513 self.assertEqual(str(d), '456789')
514 d = nc.create_decimal('456789')
515 self.assertEqual(str(d), '4.57E+5')
Christian Heimesa62da1d2008-01-12 19:39:10 +0000516 # leading and trailing whitespace should result in a NaN;
517 # spaces are already checked in Cowlishaw's test-suite, so
518 # here we just check that a trailing newline results in a NaN
519 self.assertEqual(str(nc.create_decimal('3.14\n')), 'NaN')
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000520
521 # from tuples
522 d = Decimal( (1, (4, 3, 4, 9, 1, 3, 5, 3, 4), -25) )
523 self.assertEqual(str(d), '-4.34913534E-17')
524 d = nc.create_decimal( (1, (4, 3, 4, 9, 1, 3, 5, 3, 4), -25) )
525 self.assertEqual(str(d), '-4.35E-17')
526
527 # from Decimal
528 prevdec = Decimal(500000123)
529 d = Decimal(prevdec)
530 self.assertEqual(str(d), '500000123')
531 d = nc.create_decimal(prevdec)
532 self.assertEqual(str(d), '5.00E+8')
533
Mark Dickinson8d238292009-08-02 10:16:33 +0000534 def test_unicode_digits(self):
535 test_values = {
536 '\uff11': '1',
537 '\u0660.\u0660\u0663\u0667\u0662e-\u0663' : '0.0000372',
538 '-nan\u0c68\u0c6a\u0c66\u0c66' : '-NaN2400',
539 }
540 for input, expected in test_values.items():
541 self.assertEqual(str(Decimal(input)), expected)
542
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000543
544class DecimalImplicitConstructionTest(unittest.TestCase):
545 '''Unit tests for Implicit Construction cases of Decimal.'''
546
547 def test_implicit_from_None(self):
548 self.assertRaises(TypeError, eval, 'Decimal(5) + None', globals())
549
550 def test_implicit_from_int(self):
551 #normal
552 self.assertEqual(str(Decimal(5) + 45), '50')
553 #exceeding precision
554 self.assertEqual(Decimal(5) + 123456789000, Decimal(123456789000))
555
556 def test_implicit_from_string(self):
557 self.assertRaises(TypeError, eval, 'Decimal(5) + "3"', globals())
558
559 def test_implicit_from_float(self):
560 self.assertRaises(TypeError, eval, 'Decimal(5) + 2.2', globals())
561
562 def test_implicit_from_Decimal(self):
563 self.assertEqual(Decimal(5) + Decimal(45), Decimal(50))
564
Raymond Hettinger267b8682005-03-27 10:47:39 +0000565 def test_rop(self):
566 # Allow other classes to be trained to interact with Decimals
567 class E:
568 def __divmod__(self, other):
569 return 'divmod ' + str(other)
570 def __rdivmod__(self, other):
571 return str(other) + ' rdivmod'
572 def __lt__(self, other):
573 return 'lt ' + str(other)
574 def __gt__(self, other):
575 return 'gt ' + str(other)
576 def __le__(self, other):
577 return 'le ' + str(other)
578 def __ge__(self, other):
579 return 'ge ' + str(other)
580 def __eq__(self, other):
581 return 'eq ' + str(other)
582 def __ne__(self, other):
583 return 'ne ' + str(other)
584
585 self.assertEqual(divmod(E(), Decimal(10)), 'divmod 10')
586 self.assertEqual(divmod(Decimal(10), E()), '10 rdivmod')
587 self.assertEqual(eval('Decimal(10) < E()'), 'gt 10')
588 self.assertEqual(eval('Decimal(10) > E()'), 'lt 10')
589 self.assertEqual(eval('Decimal(10) <= E()'), 'ge 10')
590 self.assertEqual(eval('Decimal(10) >= E()'), 'le 10')
591 self.assertEqual(eval('Decimal(10) == E()'), 'eq 10')
592 self.assertEqual(eval('Decimal(10) != E()'), 'ne 10')
593
594 # insert operator methods and then exercise them
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000595 oplist = [
596 ('+', '__add__', '__radd__'),
597 ('-', '__sub__', '__rsub__'),
598 ('*', '__mul__', '__rmul__'),
Thomas Woutersdcc6d322006-04-21 11:30:52 +0000599 ('/', '__truediv__', '__rtruediv__'),
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000600 ('%', '__mod__', '__rmod__'),
601 ('//', '__floordiv__', '__rfloordiv__'),
602 ('**', '__pow__', '__rpow__')
603 ]
Raymond Hettinger267b8682005-03-27 10:47:39 +0000604
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000605 for sym, lop, rop in oplist:
Raymond Hettinger267b8682005-03-27 10:47:39 +0000606 setattr(E, lop, lambda self, other: 'str' + lop + str(other))
607 setattr(E, rop, lambda self, other: str(other) + rop + 'str')
608 self.assertEqual(eval('E()' + sym + 'Decimal(10)'),
609 'str' + lop + '10')
610 self.assertEqual(eval('Decimal(10)' + sym + 'E()'),
611 '10' + rop + 'str')
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000612
Mark Dickinson79f52032009-03-17 23:12:51 +0000613
Christian Heimesf16baeb2008-02-29 14:57:44 +0000614class DecimalFormatTest(unittest.TestCase):
615 '''Unit tests for the format function.'''
616 def test_formatting(self):
617 # triples giving a format, a Decimal, and the expected result
618 test_values = [
619 ('e', '0E-15', '0e-15'),
620 ('e', '2.3E-15', '2.3e-15'),
621 ('e', '2.30E+2', '2.30e+2'), # preserve significant zeros
622 ('e', '2.30000E-15', '2.30000e-15'),
623 ('e', '1.23456789123456789e40', '1.23456789123456789e+40'),
624 ('e', '1.5', '1.5e+0'),
625 ('e', '0.15', '1.5e-1'),
626 ('e', '0.015', '1.5e-2'),
627 ('e', '0.0000000000015', '1.5e-12'),
628 ('e', '15.0', '1.50e+1'),
629 ('e', '-15', '-1.5e+1'),
630 ('e', '0', '0e+0'),
631 ('e', '0E1', '0e+1'),
632 ('e', '0.0', '0e-1'),
633 ('e', '0.00', '0e-2'),
634 ('.6e', '0E-15', '0.000000e-9'),
635 ('.6e', '0', '0.000000e+6'),
636 ('.6e', '9.999999', '9.999999e+0'),
637 ('.6e', '9.9999999', '1.000000e+1'),
638 ('.6e', '-1.23e5', '-1.230000e+5'),
639 ('.6e', '1.23456789e-3', '1.234568e-3'),
640 ('f', '0', '0'),
641 ('f', '0.0', '0.0'),
642 ('f', '0E-2', '0.00'),
643 ('f', '0.00E-8', '0.0000000000'),
644 ('f', '0E1', '0'), # loses exponent information
645 ('f', '3.2E1', '32'),
646 ('f', '3.2E2', '320'),
647 ('f', '3.20E2', '320'),
648 ('f', '3.200E2', '320.0'),
649 ('f', '3.2E-6', '0.0000032'),
650 ('.6f', '0E-15', '0.000000'), # all zeros treated equally
651 ('.6f', '0E1', '0.000000'),
652 ('.6f', '0', '0.000000'),
653 ('.0f', '0', '0'), # no decimal point
654 ('.0f', '0e-2', '0'),
655 ('.0f', '3.14159265', '3'),
656 ('.1f', '3.14159265', '3.1'),
657 ('.4f', '3.14159265', '3.1416'),
658 ('.6f', '3.14159265', '3.141593'),
659 ('.7f', '3.14159265', '3.1415926'), # round-half-even!
660 ('.8f', '3.14159265', '3.14159265'),
661 ('.9f', '3.14159265', '3.141592650'),
662
663 ('g', '0', '0'),
664 ('g', '0.0', '0.0'),
665 ('g', '0E1', '0e+1'),
666 ('G', '0E1', '0E+1'),
667 ('g', '0E-5', '0.00000'),
668 ('g', '0E-6', '0.000000'),
669 ('g', '0E-7', '0e-7'),
670 ('g', '-0E2', '-0e+2'),
671 ('.0g', '3.14159265', '3'), # 0 sig fig -> 1 sig fig
672 ('.1g', '3.14159265', '3'),
673 ('.2g', '3.14159265', '3.1'),
674 ('.5g', '3.14159265', '3.1416'),
675 ('.7g', '3.14159265', '3.141593'),
676 ('.8g', '3.14159265', '3.1415926'), # round-half-even!
677 ('.9g', '3.14159265', '3.14159265'),
678 ('.10g', '3.14159265', '3.14159265'), # don't pad
679
680 ('%', '0E1', '0%'),
681 ('%', '0E0', '0%'),
682 ('%', '0E-1', '0%'),
683 ('%', '0E-2', '0%'),
684 ('%', '0E-3', '0.0%'),
685 ('%', '0E-4', '0.00%'),
686
687 ('.3%', '0', '0.000%'), # all zeros treated equally
688 ('.3%', '0E10', '0.000%'),
689 ('.3%', '0E-10', '0.000%'),
690 ('.3%', '2.34', '234.000%'),
691 ('.3%', '1.234567', '123.457%'),
692 ('.0%', '1.23', '123%'),
693
694 ('e', 'NaN', 'NaN'),
695 ('f', '-NaN123', '-NaN123'),
696 ('+g', 'NaN456', '+NaN456'),
697 ('.3e', 'Inf', 'Infinity'),
698 ('.16f', '-Inf', '-Infinity'),
699 ('.0g', '-sNaN', '-sNaN'),
700
701 ('', '1.00', '1.00'),
Mark Dickinsonad416342009-03-17 18:10:15 +0000702
Mark Dickinson79f52032009-03-17 23:12:51 +0000703 # test alignment and padding
Mark Dickinsonad416342009-03-17 18:10:15 +0000704 ('<6', '123', '123 '),
705 ('>6', '123', ' 123'),
706 ('^6', '123', ' 123 '),
707 ('=+6', '123', '+ 123'),
Mark Dickinson79f52032009-03-17 23:12:51 +0000708 ('#<10', 'NaN', 'NaN#######'),
709 ('#<10', '-4.3', '-4.3######'),
710 ('#<+10', '0.0130', '+0.0130###'),
711 ('#< 10', '0.0130', ' 0.0130###'),
712 ('@>10', '-Inf', '@-Infinity'),
713 ('#>5', '-Inf', '-Infinity'),
714 ('?^5', '123', '?123?'),
715 ('%^6', '123', '%123%%'),
716 (' ^6', '-45.6', '-45.6 '),
717 ('/=10', '-45.6', '-/////45.6'),
718 ('/=+10', '45.6', '+/////45.6'),
719 ('/= 10', '45.6', ' /////45.6'),
720
721 # thousands separator
722 (',', '1234567', '1,234,567'),
723 (',', '123456', '123,456'),
724 (',', '12345', '12,345'),
725 (',', '1234', '1,234'),
726 (',', '123', '123'),
727 (',', '12', '12'),
728 (',', '1', '1'),
729 (',', '0', '0'),
730 (',', '-1234567', '-1,234,567'),
731 (',', '-123456', '-123,456'),
732 ('7,', '123456', '123,456'),
733 ('8,', '123456', '123,456 '),
734 ('08,', '123456', '0,123,456'), # special case: extra 0 needed
735 ('+08,', '123456', '+123,456'), # but not if there's a sign
736 (' 08,', '123456', ' 123,456'),
737 ('08,', '-123456', '-123,456'),
738 ('+09,', '123456', '+0,123,456'),
739 # ... with fractional part...
740 ('07,', '1234.56', '1,234.56'),
741 ('08,', '1234.56', '1,234.56'),
742 ('09,', '1234.56', '01,234.56'),
743 ('010,', '1234.56', '001,234.56'),
744 ('011,', '1234.56', '0,001,234.56'),
745 ('012,', '1234.56', '0,001,234.56'),
746 ('08,.1f', '1234.5', '01,234.5'),
747 # no thousands separators in fraction part
748 (',', '1.23456789', '1.23456789'),
749 (',%', '123.456789', '12,345.6789%'),
750 (',e', '123456', '1.23456e+5'),
751 (',E', '123456', '1.23456E+5'),
Mark Dickinsond496d302009-09-07 16:23:26 +0000752
753 # issue 6850
754 ('a=-7.0', '0.12345', 'aaaa0.1'),
Christian Heimesf16baeb2008-02-29 14:57:44 +0000755 ]
756 for fmt, d, result in test_values:
757 self.assertEqual(format(Decimal(d), fmt), result)
758
Mark Dickinson79f52032009-03-17 23:12:51 +0000759 def test_n_format(self):
760 try:
761 from locale import CHAR_MAX
762 except ImportError:
763 return
764
765 # Set up some localeconv-like dictionaries
766 en_US = {
767 'decimal_point' : '.',
768 'grouping' : [3, 3, 0],
769 'thousands_sep': ','
770 }
771
772 fr_FR = {
773 'decimal_point' : ',',
774 'grouping' : [CHAR_MAX],
775 'thousands_sep' : ''
776 }
777
778 ru_RU = {
779 'decimal_point' : ',',
780 'grouping' : [3, 3, 0],
781 'thousands_sep' : ' '
782 }
783
784 crazy = {
785 'decimal_point' : '&',
786 'grouping' : [1, 4, 2, CHAR_MAX],
787 'thousands_sep' : '-'
788 }
789
790
791 def get_fmt(x, locale, fmt='n'):
792 return Decimal.__format__(Decimal(x), fmt, _localeconv=locale)
793
794 self.assertEqual(get_fmt(Decimal('12.7'), en_US), '12.7')
795 self.assertEqual(get_fmt(Decimal('12.7'), fr_FR), '12,7')
796 self.assertEqual(get_fmt(Decimal('12.7'), ru_RU), '12,7')
797 self.assertEqual(get_fmt(Decimal('12.7'), crazy), '1-2&7')
798
799 self.assertEqual(get_fmt(123456789, en_US), '123,456,789')
800 self.assertEqual(get_fmt(123456789, fr_FR), '123456789')
801 self.assertEqual(get_fmt(123456789, ru_RU), '123 456 789')
802 self.assertEqual(get_fmt(1234567890123, crazy), '123456-78-9012-3')
803
804 self.assertEqual(get_fmt(123456789, en_US, '.6n'), '1.23457e+8')
805 self.assertEqual(get_fmt(123456789, fr_FR, '.6n'), '1,23457e+8')
806 self.assertEqual(get_fmt(123456789, ru_RU, '.6n'), '1,23457e+8')
807 self.assertEqual(get_fmt(123456789, crazy, '.6n'), '1&23457e+8')
808
Mark Dickinson7303b592009-03-18 08:25:36 +0000809 # zero padding
810 self.assertEqual(get_fmt(1234, fr_FR, '03n'), '1234')
811 self.assertEqual(get_fmt(1234, fr_FR, '04n'), '1234')
812 self.assertEqual(get_fmt(1234, fr_FR, '05n'), '01234')
813 self.assertEqual(get_fmt(1234, fr_FR, '06n'), '001234')
814
815 self.assertEqual(get_fmt(12345, en_US, '05n'), '12,345')
816 self.assertEqual(get_fmt(12345, en_US, '06n'), '12,345')
817 self.assertEqual(get_fmt(12345, en_US, '07n'), '012,345')
818 self.assertEqual(get_fmt(12345, en_US, '08n'), '0,012,345')
819 self.assertEqual(get_fmt(12345, en_US, '09n'), '0,012,345')
820 self.assertEqual(get_fmt(12345, en_US, '010n'), '00,012,345')
821
822 self.assertEqual(get_fmt(123456, crazy, '06n'), '1-2345-6')
823 self.assertEqual(get_fmt(123456, crazy, '07n'), '1-2345-6')
824 self.assertEqual(get_fmt(123456, crazy, '08n'), '1-2345-6')
825 self.assertEqual(get_fmt(123456, crazy, '09n'), '01-2345-6')
826 self.assertEqual(get_fmt(123456, crazy, '010n'), '0-01-2345-6')
827 self.assertEqual(get_fmt(123456, crazy, '011n'), '0-01-2345-6')
828 self.assertEqual(get_fmt(123456, crazy, '012n'), '00-01-2345-6')
829 self.assertEqual(get_fmt(123456, crazy, '013n'), '000-01-2345-6')
830
Mark Dickinson79f52032009-03-17 23:12:51 +0000831
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000832class DecimalArithmeticOperatorsTest(unittest.TestCase):
833 '''Unit tests for all arithmetic operators, binary and unary.'''
834
835 def test_addition(self):
836
837 d1 = Decimal('-11.1')
838 d2 = Decimal('22.2')
839
840 #two Decimals
841 self.assertEqual(d1+d2, Decimal('11.1'))
842 self.assertEqual(d2+d1, Decimal('11.1'))
843
844 #with other type, left
845 c = d1 + 5
846 self.assertEqual(c, Decimal('-6.1'))
847 self.assertEqual(type(c), type(d1))
848
849 #with other type, right
850 c = 5 + d1
851 self.assertEqual(c, Decimal('-6.1'))
852 self.assertEqual(type(c), type(d1))
853
854 #inline with decimal
855 d1 += d2
856 self.assertEqual(d1, Decimal('11.1'))
857
858 #inline with other type
859 d1 += 5
860 self.assertEqual(d1, Decimal('16.1'))
861
862 def test_subtraction(self):
863
864 d1 = Decimal('-11.1')
865 d2 = Decimal('22.2')
866
867 #two Decimals
868 self.assertEqual(d1-d2, Decimal('-33.3'))
869 self.assertEqual(d2-d1, Decimal('33.3'))
870
871 #with other type, left
872 c = d1 - 5
873 self.assertEqual(c, Decimal('-16.1'))
874 self.assertEqual(type(c), type(d1))
875
876 #with other type, right
877 c = 5 - d1
878 self.assertEqual(c, Decimal('16.1'))
879 self.assertEqual(type(c), type(d1))
880
881 #inline with decimal
882 d1 -= d2
883 self.assertEqual(d1, Decimal('-33.3'))
884
885 #inline with other type
886 d1 -= 5
887 self.assertEqual(d1, Decimal('-38.3'))
888
889 def test_multiplication(self):
890
891 d1 = Decimal('-5')
892 d2 = Decimal('3')
893
894 #two Decimals
895 self.assertEqual(d1*d2, Decimal('-15'))
896 self.assertEqual(d2*d1, Decimal('-15'))
897
898 #with other type, left
899 c = d1 * 5
900 self.assertEqual(c, Decimal('-25'))
901 self.assertEqual(type(c), type(d1))
902
903 #with other type, right
904 c = 5 * d1
905 self.assertEqual(c, Decimal('-25'))
906 self.assertEqual(type(c), type(d1))
907
908 #inline with decimal
909 d1 *= d2
910 self.assertEqual(d1, Decimal('-15'))
911
912 #inline with other type
913 d1 *= 5
914 self.assertEqual(d1, Decimal('-75'))
915
916 def test_division(self):
917
918 d1 = Decimal('-5')
919 d2 = Decimal('2')
920
921 #two Decimals
922 self.assertEqual(d1/d2, Decimal('-2.5'))
923 self.assertEqual(d2/d1, Decimal('-0.4'))
924
925 #with other type, left
926 c = d1 / 4
927 self.assertEqual(c, Decimal('-1.25'))
928 self.assertEqual(type(c), type(d1))
929
930 #with other type, right
931 c = 4 / d1
932 self.assertEqual(c, Decimal('-0.8'))
933 self.assertEqual(type(c), type(d1))
934
935 #inline with decimal
936 d1 /= d2
937 self.assertEqual(d1, Decimal('-2.5'))
938
939 #inline with other type
940 d1 /= 4
941 self.assertEqual(d1, Decimal('-0.625'))
942
943 def test_floor_division(self):
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000944
945 d1 = Decimal('5')
946 d2 = Decimal('2')
947
948 #two Decimals
949 self.assertEqual(d1//d2, Decimal('2'))
950 self.assertEqual(d2//d1, Decimal('0'))
951
952 #with other type, left
953 c = d1 // 4
954 self.assertEqual(c, Decimal('1'))
955 self.assertEqual(type(c), type(d1))
956
957 #with other type, right
958 c = 7 // d1
959 self.assertEqual(c, Decimal('1'))
960 self.assertEqual(type(c), type(d1))
961
962 #inline with decimal
963 d1 //= d2
964 self.assertEqual(d1, Decimal('2'))
965
966 #inline with other type
967 d1 //= 2
968 self.assertEqual(d1, Decimal('1'))
969
970 def test_powering(self):
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000971
972 d1 = Decimal('5')
973 d2 = Decimal('2')
974
975 #two Decimals
976 self.assertEqual(d1**d2, Decimal('25'))
977 self.assertEqual(d2**d1, Decimal('32'))
978
979 #with other type, left
980 c = d1 ** 4
981 self.assertEqual(c, Decimal('625'))
982 self.assertEqual(type(c), type(d1))
983
984 #with other type, right
985 c = 7 ** d1
986 self.assertEqual(c, Decimal('16807'))
987 self.assertEqual(type(c), type(d1))
988
989 #inline with decimal
990 d1 **= d2
991 self.assertEqual(d1, Decimal('25'))
992
993 #inline with other type
994 d1 **= 4
995 self.assertEqual(d1, Decimal('390625'))
996
997 def test_module(self):
998
999 d1 = Decimal('5')
1000 d2 = Decimal('2')
1001
1002 #two Decimals
1003 self.assertEqual(d1%d2, Decimal('1'))
1004 self.assertEqual(d2%d1, Decimal('2'))
1005
1006 #with other type, left
1007 c = d1 % 4
1008 self.assertEqual(c, Decimal('1'))
1009 self.assertEqual(type(c), type(d1))
1010
1011 #with other type, right
1012 c = 7 % d1
1013 self.assertEqual(c, Decimal('2'))
1014 self.assertEqual(type(c), type(d1))
1015
1016 #inline with decimal
1017 d1 %= d2
1018 self.assertEqual(d1, Decimal('1'))
1019
1020 #inline with other type
1021 d1 %= 4
1022 self.assertEqual(d1, Decimal('1'))
1023
1024 def test_floor_div_module(self):
1025
1026 d1 = Decimal('5')
1027 d2 = Decimal('2')
1028
1029 #two Decimals
1030 (p, q) = divmod(d1, d2)
1031 self.assertEqual(p, Decimal('2'))
1032 self.assertEqual(q, Decimal('1'))
1033 self.assertEqual(type(p), type(d1))
1034 self.assertEqual(type(q), type(d1))
1035
1036 #with other type, left
1037 (p, q) = divmod(d1, 4)
1038 self.assertEqual(p, Decimal('1'))
1039 self.assertEqual(q, Decimal('1'))
1040 self.assertEqual(type(p), type(d1))
1041 self.assertEqual(type(q), type(d1))
1042
1043 #with other type, right
1044 (p, q) = divmod(7, d1)
1045 self.assertEqual(p, Decimal('1'))
1046 self.assertEqual(q, Decimal('2'))
1047 self.assertEqual(type(p), type(d1))
1048 self.assertEqual(type(q), type(d1))
1049
1050 def test_unary_operators(self):
1051 self.assertEqual(+Decimal(45), Decimal(+45)) # +
1052 self.assertEqual(-Decimal(45), Decimal(-45)) # -
1053 self.assertEqual(abs(Decimal(45)), abs(Decimal(-45))) # abs
1054
Christian Heimes77c02eb2008-02-09 02:18:51 +00001055 def test_nan_comparisons(self):
1056 n = Decimal('NaN')
1057 s = Decimal('sNaN')
1058 i = Decimal('Inf')
1059 f = Decimal('2')
1060 for x, y in [(n, n), (n, i), (i, n), (n, f), (f, n),
1061 (s, n), (n, s), (s, i), (i, s), (s, f), (f, s), (s, s)]:
Georg Brandlab91fde2009-08-13 08:51:18 +00001062 self.assertTrue(x != y)
1063 self.assertTrue(not (x == y))
1064 self.assertTrue(not (x < y))
1065 self.assertTrue(not (x <= y))
1066 self.assertTrue(not (x > y))
1067 self.assertTrue(not (x >= y))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001068
1069# The following are two functions used to test threading in the next class
1070
1071def thfunc1(cls):
1072 d1 = Decimal(1)
1073 d3 = Decimal(3)
Christian Heimesfe337bf2008-03-23 21:54:12 +00001074 test1 = d1/d3
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001075 cls.synchro.wait()
Christian Heimesfe337bf2008-03-23 21:54:12 +00001076 test2 = d1/d3
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001077 cls.finish1.set()
Christian Heimesfe337bf2008-03-23 21:54:12 +00001078
Christian Heimes81ee3ef2008-05-04 22:42:01 +00001079 cls.assertEqual(test1, Decimal('0.3333333333333333333333333333'))
1080 cls.assertEqual(test2, Decimal('0.3333333333333333333333333333'))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001081 return
1082
1083def thfunc2(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 thiscontext = getcontext()
1088 thiscontext.prec = 18
Christian Heimesfe337bf2008-03-23 21:54:12 +00001089 test2 = d1/d3
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001090 cls.synchro.set()
1091 cls.finish2.set()
Christian Heimesfe337bf2008-03-23 21:54:12 +00001092
Christian Heimes81ee3ef2008-05-04 22:42:01 +00001093 cls.assertEqual(test1, Decimal('0.3333333333333333333333333333'))
Christian Heimesfe337bf2008-03-23 21:54:12 +00001094 cls.assertEqual(test2, Decimal('0.333333333333333333'))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001095 return
1096
1097
1098class DecimalUseOfContextTest(unittest.TestCase):
1099 '''Unit tests for Use of Context cases in Decimal.'''
1100
Raymond Hettinger7e71fa52004-12-18 19:07:19 +00001101 try:
1102 import threading
1103 except ImportError:
1104 threading = None
1105
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001106 # Take care executing this test from IDLE, there's an issue in threading
1107 # that hangs IDLE and I couldn't find it
1108
1109 def test_threading(self):
1110 #Test the "threading isolation" of a Context.
1111
1112 self.synchro = threading.Event()
1113 self.finish1 = threading.Event()
1114 self.finish2 = threading.Event()
1115
1116 th1 = threading.Thread(target=thfunc1, args=(self,))
1117 th2 = threading.Thread(target=thfunc2, args=(self,))
1118
1119 th1.start()
1120 th2.start()
1121
1122 self.finish1.wait()
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001123 self.finish2.wait()
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001124 return
1125
Raymond Hettinger7e71fa52004-12-18 19:07:19 +00001126 if threading is None:
1127 del test_threading
1128
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001129
1130class DecimalUsabilityTest(unittest.TestCase):
1131 '''Unit tests for Usability cases of Decimal.'''
1132
1133 def test_comparison_operators(self):
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001134
1135 da = Decimal('23.42')
1136 db = Decimal('23.42')
1137 dc = Decimal('45')
1138
1139 #two Decimals
Georg Brandlab91fde2009-08-13 08:51:18 +00001140 self.assertTrue(dc > da)
1141 self.assertTrue(dc >= da)
1142 self.assertTrue(da < dc)
1143 self.assertTrue(da <= dc)
Guido van Rossume61fd5b2007-07-11 12:20:59 +00001144 self.assertEqual(da, db)
Georg Brandlab91fde2009-08-13 08:51:18 +00001145 self.assertTrue(da != dc)
1146 self.assertTrue(da <= db)
1147 self.assertTrue(da >= db)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001148
1149 #a Decimal and an int
Georg Brandlab91fde2009-08-13 08:51:18 +00001150 self.assertTrue(dc > 23)
1151 self.assertTrue(23 < dc)
Guido van Rossume61fd5b2007-07-11 12:20:59 +00001152 self.assertEqual(dc, 45)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001153
1154 #a Decimal and uncomparable
Raymond Hettinger0aeac102004-07-05 22:53:03 +00001155 self.assertNotEqual(da, 'ugly')
1156 self.assertNotEqual(da, 32.7)
1157 self.assertNotEqual(da, object())
1158 self.assertNotEqual(da, object)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001159
Raymond Hettinger0aeac102004-07-05 22:53:03 +00001160 # sortable
Guido van Rossumc1f779c2007-07-03 08:25:58 +00001161 a = list(map(Decimal, range(100)))
Raymond Hettinger0aeac102004-07-05 22:53:03 +00001162 b = a[:]
1163 random.shuffle(a)
1164 a.sort()
1165 self.assertEqual(a, b)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001166
1167 def test_copy_and_deepcopy_methods(self):
1168 d = Decimal('43.24')
1169 c = copy.copy(d)
1170 self.assertEqual(id(c), id(d))
1171 dc = copy.deepcopy(d)
1172 self.assertEqual(id(dc), id(d))
1173
1174 def test_hash_method(self):
1175 #just that it's hashable
1176 hash(Decimal(23))
Thomas Wouters8ce81f72007-09-20 18:22:40 +00001177
1178 test_values = [Decimal(sign*(2**m + n))
1179 for m in [0, 14, 15, 16, 17, 30, 31,
1180 32, 33, 62, 63, 64, 65, 66]
1181 for n in range(-10, 10)
1182 for sign in [-1, 1]]
1183 test_values.extend([
1184 Decimal("-0"), # zeros
1185 Decimal("0.00"),
1186 Decimal("-0.000"),
1187 Decimal("0E10"),
1188 Decimal("-0E12"),
1189 Decimal("10.0"), # negative exponent
1190 Decimal("-23.00000"),
1191 Decimal("1230E100"), # positive exponent
1192 Decimal("-4.5678E50"),
1193 # a value for which hash(n) != hash(n % (2**64-1))
1194 # in Python pre-2.6
1195 Decimal(2**64 + 2**32 - 1),
1196 # selection of values which fail with the old (before
1197 # version 2.6) long.__hash__
1198 Decimal("1.634E100"),
1199 Decimal("90.697E100"),
1200 Decimal("188.83E100"),
1201 Decimal("1652.9E100"),
1202 Decimal("56531E100"),
1203 ])
1204
1205 # check that hash(d) == hash(int(d)) for integral values
1206 for value in test_values:
1207 self.assertEqual(hash(value), hash(int(value)))
1208
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001209 #the same hash that to an int
1210 self.assertEqual(hash(Decimal(23)), hash(23))
Raymond Hettingerbea3f6f2005-03-15 04:59:17 +00001211 self.assertRaises(TypeError, hash, Decimal('NaN'))
Georg Brandlab91fde2009-08-13 08:51:18 +00001212 self.assertTrue(hash(Decimal('Inf')))
1213 self.assertTrue(hash(Decimal('-Inf')))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001214
Christian Heimes2380ac72008-01-09 00:17:24 +00001215 # check that the value of the hash doesn't depend on the
1216 # current context (issue #1757)
1217 c = getcontext()
1218 old_precision = c.prec
1219 x = Decimal("123456789.1")
1220
1221 c.prec = 6
1222 h1 = hash(x)
1223 c.prec = 10
1224 h2 = hash(x)
1225 c.prec = 16
1226 h3 = hash(x)
1227
1228 self.assertEqual(h1, h2)
1229 self.assertEqual(h1, h3)
1230 c.prec = old_precision
1231
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001232 def test_min_and_max_methods(self):
1233
1234 d1 = Decimal('15.32')
1235 d2 = Decimal('28.5')
1236 l1 = 15
1237 l2 = 28
1238
1239 #between Decimals
Georg Brandlab91fde2009-08-13 08:51:18 +00001240 self.assertTrue(min(d1,d2) is d1)
1241 self.assertTrue(min(d2,d1) is d1)
1242 self.assertTrue(max(d1,d2) is d2)
1243 self.assertTrue(max(d2,d1) is d2)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001244
1245 #between Decimal and long
Georg Brandlab91fde2009-08-13 08:51:18 +00001246 self.assertTrue(min(d1,l2) is d1)
1247 self.assertTrue(min(l2,d1) is d1)
1248 self.assertTrue(max(l1,d2) is d2)
1249 self.assertTrue(max(d2,l1) is d2)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001250
1251 def test_as_nonzero(self):
1252 #as false
Georg Brandlab91fde2009-08-13 08:51:18 +00001253 self.assertFalse(Decimal(0))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001254 #as true
Georg Brandlab91fde2009-08-13 08:51:18 +00001255 self.assertTrue(Decimal('0.372'))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001256
1257 def test_tostring_methods(self):
1258 #Test str and repr methods.
1259
1260 d = Decimal('15.32')
1261 self.assertEqual(str(d), '15.32') # str
Christian Heimes68f5fbe2008-02-14 08:27:37 +00001262 self.assertEqual(repr(d), "Decimal('15.32')") # repr
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001263
1264 def test_tonum_methods(self):
1265 #Test float, int and long methods.
1266
1267 d1 = Decimal('66')
1268 d2 = Decimal('15.32')
1269
1270 #int
1271 self.assertEqual(int(d1), 66)
1272 self.assertEqual(int(d2), 15)
1273
1274 #long
Guido van Rossume2a383d2007-01-15 16:59:06 +00001275 self.assertEqual(int(d1), 66)
1276 self.assertEqual(int(d2), 15)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001277
1278 #float
1279 self.assertEqual(float(d1), 66)
1280 self.assertEqual(float(d2), 15.32)
1281
Mark Dickinsonb27406c2008-05-09 13:42:33 +00001282 #floor
1283 test_pairs = [
1284 ('123.00', 123),
1285 ('3.2', 3),
1286 ('3.54', 3),
1287 ('3.899', 3),
1288 ('-2.3', -3),
1289 ('-11.0', -11),
1290 ('0.0', 0),
1291 ('-0E3', 0),
1292 ]
1293 for d, i in test_pairs:
1294 self.assertEqual(math.floor(Decimal(d)), i)
1295 self.assertRaises(ValueError, math.floor, Decimal('-NaN'))
1296 self.assertRaises(ValueError, math.floor, Decimal('sNaN'))
1297 self.assertRaises(ValueError, math.floor, Decimal('NaN123'))
1298 self.assertRaises(OverflowError, math.floor, Decimal('Inf'))
1299 self.assertRaises(OverflowError, math.floor, Decimal('-Inf'))
1300
1301 #ceiling
1302 test_pairs = [
1303 ('123.00', 123),
1304 ('3.2', 4),
1305 ('3.54', 4),
1306 ('3.899', 4),
1307 ('-2.3', -2),
1308 ('-11.0', -11),
1309 ('0.0', 0),
1310 ('-0E3', 0),
1311 ]
1312 for d, i in test_pairs:
1313 self.assertEqual(math.ceil(Decimal(d)), i)
1314 self.assertRaises(ValueError, math.ceil, Decimal('-NaN'))
1315 self.assertRaises(ValueError, math.ceil, Decimal('sNaN'))
1316 self.assertRaises(ValueError, math.ceil, Decimal('NaN123'))
1317 self.assertRaises(OverflowError, math.ceil, Decimal('Inf'))
1318 self.assertRaises(OverflowError, math.ceil, Decimal('-Inf'))
1319
1320 #round, single argument
1321 test_pairs = [
1322 ('123.00', 123),
1323 ('3.2', 3),
1324 ('3.54', 4),
1325 ('3.899', 4),
1326 ('-2.3', -2),
1327 ('-11.0', -11),
1328 ('0.0', 0),
1329 ('-0E3', 0),
1330 ('-3.5', -4),
1331 ('-2.5', -2),
1332 ('-1.5', -2),
1333 ('-0.5', 0),
1334 ('0.5', 0),
1335 ('1.5', 2),
1336 ('2.5', 2),
1337 ('3.5', 4),
1338 ]
1339 for d, i in test_pairs:
1340 self.assertEqual(round(Decimal(d)), i)
1341 self.assertRaises(ValueError, round, Decimal('-NaN'))
1342 self.assertRaises(ValueError, round, Decimal('sNaN'))
1343 self.assertRaises(ValueError, round, Decimal('NaN123'))
1344 self.assertRaises(OverflowError, round, Decimal('Inf'))
1345 self.assertRaises(OverflowError, round, Decimal('-Inf'))
1346
1347 #round, two arguments; this is essentially equivalent
1348 #to quantize, which is already extensively tested
1349 test_triples = [
1350 ('123.456', -4, '0E+4'),
1351 ('123.456', -3, '0E+3'),
1352 ('123.456', -2, '1E+2'),
1353 ('123.456', -1, '1.2E+2'),
1354 ('123.456', 0, '123'),
1355 ('123.456', 1, '123.5'),
1356 ('123.456', 2, '123.46'),
1357 ('123.456', 3, '123.456'),
1358 ('123.456', 4, '123.4560'),
1359 ('123.455', 2, '123.46'),
1360 ('123.445', 2, '123.44'),
1361 ('Inf', 4, 'NaN'),
1362 ('-Inf', -23, 'NaN'),
1363 ('sNaN314', 3, 'NaN314'),
1364 ]
1365 for d, n, r in test_triples:
1366 self.assertEqual(str(round(Decimal(d), n)), r)
1367
1368
1369
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001370 def test_eval_round_trip(self):
1371
1372 #with zero
1373 d = Decimal( (0, (0,), 0) )
1374 self.assertEqual(d, eval(repr(d)))
1375
1376 #int
1377 d = Decimal( (1, (4, 5), 0) )
1378 self.assertEqual(d, eval(repr(d)))
1379
1380 #float
1381 d = Decimal( (0, (4, 5, 3, 4), -2) )
1382 self.assertEqual(d, eval(repr(d)))
1383
1384 #weird
1385 d = Decimal( (1, (4, 3, 4, 9, 1, 3, 5, 3, 4), -25) )
1386 self.assertEqual(d, eval(repr(d)))
1387
1388 def test_as_tuple(self):
1389
1390 #with zero
1391 d = Decimal(0)
1392 self.assertEqual(d.as_tuple(), (0, (0,), 0) )
1393
1394 #int
1395 d = Decimal(-45)
1396 self.assertEqual(d.as_tuple(), (1, (4, 5), 0) )
1397
1398 #complicated string
1399 d = Decimal("-4.34913534E-17")
1400 self.assertEqual(d.as_tuple(), (1, (4, 3, 4, 9, 1, 3, 5, 3, 4), -25) )
1401
1402 #inf
1403 d = Decimal("Infinity")
1404 self.assertEqual(d.as_tuple(), (0, (0,), 'F') )
1405
Guido van Rossum8ce8a782007-11-01 19:42:39 +00001406 #leading zeros in coefficient should be stripped
1407 d = Decimal( (0, (0, 0, 4, 0, 5, 3, 4), -2) )
1408 self.assertEqual(d.as_tuple(), (0, (4, 0, 5, 3, 4), -2) )
1409 d = Decimal( (1, (0, 0, 0), 37) )
1410 self.assertEqual(d.as_tuple(), (1, (0,), 37))
1411 d = Decimal( (1, (), 37) )
1412 self.assertEqual(d.as_tuple(), (1, (0,), 37))
1413
1414 #leading zeros in NaN diagnostic info should be stripped
1415 d = Decimal( (0, (0, 0, 4, 0, 5, 3, 4), 'n') )
1416 self.assertEqual(d.as_tuple(), (0, (4, 0, 5, 3, 4), 'n') )
1417 d = Decimal( (1, (0, 0, 0), 'N') )
1418 self.assertEqual(d.as_tuple(), (1, (), 'N') )
1419 d = Decimal( (1, (), 'n') )
1420 self.assertEqual(d.as_tuple(), (1, (), 'n') )
1421
1422 #coefficient in infinity should be ignored
1423 d = Decimal( (0, (4, 5, 3, 4), 'F') )
1424 self.assertEqual(d.as_tuple(), (0, (0,), 'F'))
1425 d = Decimal( (1, (0, 2, 7, 1), 'F') )
1426 self.assertEqual(d.as_tuple(), (1, (0,), 'F'))
1427
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001428 def test_immutability_operations(self):
1429 # Do operations and check that it didn't change change internal objects.
1430
1431 d1 = Decimal('-25e55')
1432 b1 = Decimal('-25e55')
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001433 d2 = Decimal('33e+33')
1434 b2 = Decimal('33e+33')
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001435
1436 def checkSameDec(operation, useOther=False):
1437 if useOther:
1438 eval("d1." + operation + "(d2)")
1439 self.assertEqual(d1._sign, b1._sign)
1440 self.assertEqual(d1._int, b1._int)
1441 self.assertEqual(d1._exp, b1._exp)
1442 self.assertEqual(d2._sign, b2._sign)
1443 self.assertEqual(d2._int, b2._int)
1444 self.assertEqual(d2._exp, b2._exp)
1445 else:
1446 eval("d1." + operation + "()")
1447 self.assertEqual(d1._sign, b1._sign)
1448 self.assertEqual(d1._int, b1._int)
1449 self.assertEqual(d1._exp, b1._exp)
1450 return
1451
1452 Decimal(d1)
1453 self.assertEqual(d1._sign, b1._sign)
1454 self.assertEqual(d1._int, b1._int)
1455 self.assertEqual(d1._exp, b1._exp)
1456
1457 checkSameDec("__abs__")
1458 checkSameDec("__add__", True)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001459 checkSameDec("__divmod__", True)
Christian Heimes77c02eb2008-02-09 02:18:51 +00001460 checkSameDec("__eq__", True)
1461 checkSameDec("__ne__", True)
1462 checkSameDec("__le__", True)
1463 checkSameDec("__lt__", True)
1464 checkSameDec("__ge__", True)
1465 checkSameDec("__gt__", True)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001466 checkSameDec("__float__")
1467 checkSameDec("__floordiv__", True)
1468 checkSameDec("__hash__")
1469 checkSameDec("__int__")
Christian Heimes969fe572008-01-25 11:23:10 +00001470 checkSameDec("__trunc__")
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001471 checkSameDec("__mod__", True)
1472 checkSameDec("__mul__", True)
1473 checkSameDec("__neg__")
Jack Diederich4dafcc42006-11-28 19:15:13 +00001474 checkSameDec("__bool__")
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001475 checkSameDec("__pos__")
1476 checkSameDec("__pow__", True)
1477 checkSameDec("__radd__", True)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001478 checkSameDec("__rdivmod__", True)
1479 checkSameDec("__repr__")
1480 checkSameDec("__rfloordiv__", True)
1481 checkSameDec("__rmod__", True)
1482 checkSameDec("__rmul__", True)
1483 checkSameDec("__rpow__", True)
1484 checkSameDec("__rsub__", True)
1485 checkSameDec("__str__")
1486 checkSameDec("__sub__", True)
1487 checkSameDec("__truediv__", True)
1488 checkSameDec("adjusted")
1489 checkSameDec("as_tuple")
1490 checkSameDec("compare", True)
1491 checkSameDec("max", True)
1492 checkSameDec("min", True)
1493 checkSameDec("normalize")
1494 checkSameDec("quantize", True)
1495 checkSameDec("remainder_near", True)
1496 checkSameDec("same_quantum", True)
1497 checkSameDec("sqrt")
1498 checkSameDec("to_eng_string")
1499 checkSameDec("to_integral")
1500
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001501 def test_subclassing(self):
1502 # Different behaviours when subclassing Decimal
1503
1504 class MyDecimal(Decimal):
1505 pass
1506
1507 d1 = MyDecimal(1)
1508 d2 = MyDecimal(2)
1509 d = d1 + d2
1510 self.assertTrue(type(d) is Decimal)
1511
1512 d = d1.max(d2)
1513 self.assertTrue(type(d) is Decimal)
1514
Christian Heimes0348fb62008-03-26 12:55:56 +00001515 def test_implicit_context(self):
1516 # Check results when context given implicitly. (Issue 2478)
1517 c = getcontext()
1518 self.assertEqual(str(Decimal(0).sqrt()),
1519 str(c.sqrt(Decimal(0))))
1520
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001521
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001522class DecimalPythonAPItests(unittest.TestCase):
1523
Raymond Hettinger82417ca2009-02-03 03:54:28 +00001524 def test_abc(self):
Georg Brandlab91fde2009-08-13 08:51:18 +00001525 self.assertTrue(issubclass(Decimal, numbers.Number))
1526 self.assertTrue(not issubclass(Decimal, numbers.Real))
1527 self.assertTrue(isinstance(Decimal(0), numbers.Number))
1528 self.assertTrue(not isinstance(Decimal(0), numbers.Real))
Raymond Hettinger82417ca2009-02-03 03:54:28 +00001529
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001530 def test_pickle(self):
1531 d = Decimal('-3.141590000')
1532 p = pickle.dumps(d)
1533 e = pickle.loads(p)
1534 self.assertEqual(d, e)
1535
Raymond Hettinger5548be22004-07-05 18:49:38 +00001536 def test_int(self):
Raymond Hettinger605ed022004-11-24 07:28:48 +00001537 for x in range(-250, 250):
1538 s = '%0.2f' % (x / 100.0)
Raymond Hettinger5548be22004-07-05 18:49:38 +00001539 # should work the same as for floats
1540 self.assertEqual(int(Decimal(s)), int(float(s)))
Raymond Hettinger605ed022004-11-24 07:28:48 +00001541 # should work the same as to_integral in the ROUND_DOWN mode
Raymond Hettinger5548be22004-07-05 18:49:38 +00001542 d = Decimal(s)
Raymond Hettinger605ed022004-11-24 07:28:48 +00001543 r = d.to_integral(ROUND_DOWN)
Raymond Hettinger5548be22004-07-05 18:49:38 +00001544 self.assertEqual(Decimal(int(d)), r)
1545
Christian Heimes969fe572008-01-25 11:23:10 +00001546 def test_trunc(self):
1547 for x in range(-250, 250):
1548 s = '%0.2f' % (x / 100.0)
1549 # should work the same as for floats
1550 self.assertEqual(int(Decimal(s)), int(float(s)))
1551 # should work the same as to_integral in the ROUND_DOWN mode
1552 d = Decimal(s)
1553 r = d.to_integral(ROUND_DOWN)
Christian Heimes400adb02008-02-01 08:12:03 +00001554 self.assertEqual(Decimal(math.trunc(d)), r)
Christian Heimes969fe572008-01-25 11:23:10 +00001555
Raymond Hettinger771ed762009-01-03 19:20:32 +00001556 def test_from_float(self):
1557
1558 class MyDecimal(Decimal):
1559 pass
1560
1561 r = MyDecimal.from_float(0.1)
1562 self.assertEqual(type(r), MyDecimal)
1563 self.assertEqual(str(r),
1564 '0.1000000000000000055511151231257827021181583404541015625')
1565 bigint = 12345678901234567890123456789
1566 self.assertEqual(MyDecimal.from_float(bigint), MyDecimal(bigint))
Georg Brandlab91fde2009-08-13 08:51:18 +00001567 self.assertTrue(MyDecimal.from_float(float('nan')).is_qnan())
1568 self.assertTrue(MyDecimal.from_float(float('inf')).is_infinite())
1569 self.assertTrue(MyDecimal.from_float(float('-inf')).is_infinite())
Raymond Hettinger771ed762009-01-03 19:20:32 +00001570 self.assertEqual(str(MyDecimal.from_float(float('nan'))),
1571 str(Decimal('NaN')))
1572 self.assertEqual(str(MyDecimal.from_float(float('inf'))),
1573 str(Decimal('Infinity')))
1574 self.assertEqual(str(MyDecimal.from_float(float('-inf'))),
1575 str(Decimal('-Infinity')))
1576 self.assertRaises(TypeError, MyDecimal.from_float, 'abc')
1577 for i in range(200):
1578 x = random.expovariate(0.01) * (random.random() * 2.0 - 1.0)
1579 self.assertEqual(x, float(MyDecimal.from_float(x))) # roundtrip
1580
1581 def test_create_decimal_from_float(self):
1582 context = Context(prec=5, rounding=ROUND_DOWN)
1583 self.assertEqual(
1584 context.create_decimal_from_float(math.pi),
1585 Decimal('3.1415')
1586 )
1587 context = Context(prec=5, rounding=ROUND_UP)
1588 self.assertEqual(
1589 context.create_decimal_from_float(math.pi),
1590 Decimal('3.1416')
1591 )
1592 context = Context(prec=5, traps=[Inexact])
1593 self.assertRaises(
1594 Inexact,
1595 context.create_decimal_from_float,
1596 math.pi
1597 )
1598 self.assertEqual(repr(context.create_decimal_from_float(-0.0)),
1599 "Decimal('-0')")
1600 self.assertEqual(repr(context.create_decimal_from_float(1.0)),
1601 "Decimal('1')")
1602 self.assertEqual(repr(context.create_decimal_from_float(10)),
1603 "Decimal('10')")
1604
Raymond Hettingerd9c0a7a2004-07-03 10:02:28 +00001605class ContextAPItests(unittest.TestCase):
1606
1607 def test_pickle(self):
1608 c = Context()
1609 e = pickle.loads(pickle.dumps(c))
1610 for k in vars(c):
1611 v1 = vars(c)[k]
1612 v2 = vars(e)[k]
1613 self.assertEqual(v1, v2)
1614
Raymond Hettinger0aeac102004-07-05 22:53:03 +00001615 def test_equality_with_other_types(self):
Georg Brandlab91fde2009-08-13 08:51:18 +00001616 self.assertTrue(Decimal(10) in ['a', 1.0, Decimal(10), (1,2), {}])
1617 self.assertTrue(Decimal(10) not in ['a', 1.0, (1,2), {}])
Raymond Hettinger0aeac102004-07-05 22:53:03 +00001618
Raymond Hettinger955d2b22004-08-08 20:17:45 +00001619 def test_copy(self):
1620 # All copies should be deep
1621 c = Context()
1622 d = c.copy()
1623 self.assertNotEqual(id(c), id(d))
1624 self.assertNotEqual(id(c.flags), id(d.flags))
1625 self.assertNotEqual(id(c.traps), id(d.traps))
1626
Thomas Wouters89f507f2006-12-13 04:49:30 +00001627class WithStatementTest(unittest.TestCase):
1628 # Can't do these as docstrings until Python 2.6
1629 # as doctest can't handle __future__ statements
1630
1631 def test_localcontext(self):
1632 # Use a copy of the current context in the block
1633 orig_ctx = getcontext()
1634 with localcontext() as enter_ctx:
1635 set_ctx = getcontext()
1636 final_ctx = getcontext()
Georg Brandlab91fde2009-08-13 08:51:18 +00001637 self.assertTrue(orig_ctx is final_ctx, 'did not restore context correctly')
1638 self.assertTrue(orig_ctx is not set_ctx, 'did not copy the context')
1639 self.assertTrue(set_ctx is enter_ctx, '__enter__ returned wrong context')
Thomas Wouters89f507f2006-12-13 04:49:30 +00001640
1641 def test_localcontextarg(self):
1642 # Use a copy of the supplied context in the block
1643 orig_ctx = getcontext()
1644 new_ctx = Context(prec=42)
1645 with localcontext(new_ctx) as enter_ctx:
1646 set_ctx = getcontext()
1647 final_ctx = getcontext()
Georg Brandlab91fde2009-08-13 08:51:18 +00001648 self.assertTrue(orig_ctx is final_ctx, 'did not restore context correctly')
1649 self.assertTrue(set_ctx.prec == new_ctx.prec, 'did not set correct context')
1650 self.assertTrue(new_ctx is not set_ctx, 'did not copy the context')
1651 self.assertTrue(set_ctx is enter_ctx, '__enter__ returned wrong context')
Thomas Wouters89f507f2006-12-13 04:49:30 +00001652
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001653class ContextFlags(unittest.TestCase):
1654 def test_flags_irrelevant(self):
1655 # check that the result (numeric result + flags raised) of an
1656 # arithmetic operation doesn't depend on the current flags
1657
1658 context = Context(prec=9, Emin = -999999999, Emax = 999999999,
1659 rounding=ROUND_HALF_EVEN, traps=[], flags=[])
1660
1661 # operations that raise various flags, in the form (function, arglist)
1662 operations = [
1663 (context._apply, [Decimal("100E-1000000009")]),
1664 (context.sqrt, [Decimal(2)]),
1665 (context.add, [Decimal("1.23456789"), Decimal("9.87654321")]),
1666 (context.multiply, [Decimal("1.23456789"), Decimal("9.87654321")]),
1667 (context.subtract, [Decimal("1.23456789"), Decimal("9.87654321")]),
1668 ]
1669
1670 # try various flags individually, then a whole lot at once
1671 flagsets = [[Inexact], [Rounded], [Underflow], [Clamped], [Subnormal],
1672 [Inexact, Rounded, Underflow, Clamped, Subnormal]]
1673
1674 for fn, args in operations:
1675 # find answer and flags raised using a clean context
1676 context.clear_flags()
1677 ans = fn(*args)
1678 flags = [k for k, v in context.flags.items() if v]
1679
1680 for extra_flags in flagsets:
1681 # set flags, before calling operation
1682 context.clear_flags()
1683 for flag in extra_flags:
1684 context._raise_error(flag)
1685 new_ans = fn(*args)
1686
1687 # flags that we expect to be set after the operation
1688 expected_flags = list(flags)
1689 for flag in extra_flags:
1690 if flag not in expected_flags:
1691 expected_flags.append(flag)
1692 expected_flags.sort(key=id)
1693
1694 # flags we actually got
1695 new_flags = [k for k,v in context.flags.items() if v]
1696 new_flags.sort(key=id)
1697
1698 self.assertEqual(ans, new_ans,
1699 "operation produces different answers depending on flags set: " +
1700 "expected %s, got %s." % (ans, new_ans))
1701 self.assertEqual(new_flags, expected_flags,
1702 "operation raises different flags depending on flags set: " +
1703 "expected %s, got %s" % (expected_flags, new_flags))
1704
1705def test_main(arith=False, verbose=None, todo_tests=None, debug=None):
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001706 """ Execute the tests.
1707
Raymond Hettingered20ad82004-09-04 20:09:13 +00001708 Runs all arithmetic tests if arith is True or if the "decimal" resource
1709 is enabled in regrtest.py
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001710 """
Raymond Hettingered20ad82004-09-04 20:09:13 +00001711
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00001712 init()
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001713 global TEST_ALL, DEBUG
Raymond Hettingered20ad82004-09-04 20:09:13 +00001714 TEST_ALL = arith or is_resource_enabled('decimal')
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001715 DEBUG = debug
Raymond Hettingered20ad82004-09-04 20:09:13 +00001716
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001717 if todo_tests is None:
1718 test_classes = [
1719 DecimalExplicitConstructionTest,
1720 DecimalImplicitConstructionTest,
1721 DecimalArithmeticOperatorsTest,
Christian Heimesf16baeb2008-02-29 14:57:44 +00001722 DecimalFormatTest,
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001723 DecimalUseOfContextTest,
1724 DecimalUsabilityTest,
1725 DecimalPythonAPItests,
1726 ContextAPItests,
1727 DecimalTest,
1728 WithStatementTest,
1729 ContextFlags
1730 ]
1731 else:
1732 test_classes = [DecimalTest]
1733
1734 # Dynamically build custom test definition for each file in the test
1735 # directory and add the definitions to the DecimalTest class. This
1736 # procedure insures that new files do not get skipped.
1737 for filename in os.listdir(directory):
1738 if '.decTest' not in filename or filename.startswith("."):
1739 continue
1740 head, tail = filename.split('.')
1741 if todo_tests is not None and head not in todo_tests:
1742 continue
1743 tester = lambda self, f=filename: self.eval_file(directory + f)
1744 setattr(DecimalTest, 'test_' + head, tester)
1745 del filename, head, tail, tester
1746
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001747
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00001748 try:
1749 run_unittest(*test_classes)
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001750 if todo_tests is None:
1751 import decimal as DecimalModule
1752 run_doctest(DecimalModule, verbose)
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00001753 finally:
1754 setcontext(ORIGINAL_CONTEXT)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001755
1756if __name__ == '__main__':
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001757 import optparse
1758 p = optparse.OptionParser("test_decimal.py [--debug] [{--skip | test1 [test2 [...]]}]")
1759 p.add_option('--debug', '-d', action='store_true', help='shows the test number and context before each test')
1760 p.add_option('--skip', '-s', action='store_true', help='skip over 90% of the arithmetic tests')
1761 (opt, args) = p.parse_args()
1762
1763 if opt.skip:
1764 test_main(arith=False, verbose=True)
1765 elif args:
1766 test_main(arith=True, verbose=True, todo_tests=args, debug=opt.debug)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001767 else:
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001768 test_main(arith=True, verbose=True)