blob: 01deeedfcb7bd9a08f1060f13b1bb054122d81b4 [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)
507 self.failUnless(isinstance(d, Decimal))
508 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'),
Christian Heimesf16baeb2008-02-29 14:57:44 +0000752 ]
753 for fmt, d, result in test_values:
754 self.assertEqual(format(Decimal(d), fmt), result)
755
Mark Dickinson79f52032009-03-17 23:12:51 +0000756 def test_n_format(self):
757 try:
758 from locale import CHAR_MAX
759 except ImportError:
760 return
761
762 # Set up some localeconv-like dictionaries
763 en_US = {
764 'decimal_point' : '.',
765 'grouping' : [3, 3, 0],
766 'thousands_sep': ','
767 }
768
769 fr_FR = {
770 'decimal_point' : ',',
771 'grouping' : [CHAR_MAX],
772 'thousands_sep' : ''
773 }
774
775 ru_RU = {
776 'decimal_point' : ',',
777 'grouping' : [3, 3, 0],
778 'thousands_sep' : ' '
779 }
780
781 crazy = {
782 'decimal_point' : '&',
783 'grouping' : [1, 4, 2, CHAR_MAX],
784 'thousands_sep' : '-'
785 }
786
787
788 def get_fmt(x, locale, fmt='n'):
789 return Decimal.__format__(Decimal(x), fmt, _localeconv=locale)
790
791 self.assertEqual(get_fmt(Decimal('12.7'), en_US), '12.7')
792 self.assertEqual(get_fmt(Decimal('12.7'), fr_FR), '12,7')
793 self.assertEqual(get_fmt(Decimal('12.7'), ru_RU), '12,7')
794 self.assertEqual(get_fmt(Decimal('12.7'), crazy), '1-2&7')
795
796 self.assertEqual(get_fmt(123456789, en_US), '123,456,789')
797 self.assertEqual(get_fmt(123456789, fr_FR), '123456789')
798 self.assertEqual(get_fmt(123456789, ru_RU), '123 456 789')
799 self.assertEqual(get_fmt(1234567890123, crazy), '123456-78-9012-3')
800
801 self.assertEqual(get_fmt(123456789, en_US, '.6n'), '1.23457e+8')
802 self.assertEqual(get_fmt(123456789, fr_FR, '.6n'), '1,23457e+8')
803 self.assertEqual(get_fmt(123456789, ru_RU, '.6n'), '1,23457e+8')
804 self.assertEqual(get_fmt(123456789, crazy, '.6n'), '1&23457e+8')
805
Mark Dickinson7303b592009-03-18 08:25:36 +0000806 # zero padding
807 self.assertEqual(get_fmt(1234, fr_FR, '03n'), '1234')
808 self.assertEqual(get_fmt(1234, fr_FR, '04n'), '1234')
809 self.assertEqual(get_fmt(1234, fr_FR, '05n'), '01234')
810 self.assertEqual(get_fmt(1234, fr_FR, '06n'), '001234')
811
812 self.assertEqual(get_fmt(12345, en_US, '05n'), '12,345')
813 self.assertEqual(get_fmt(12345, en_US, '06n'), '12,345')
814 self.assertEqual(get_fmt(12345, en_US, '07n'), '012,345')
815 self.assertEqual(get_fmt(12345, en_US, '08n'), '0,012,345')
816 self.assertEqual(get_fmt(12345, en_US, '09n'), '0,012,345')
817 self.assertEqual(get_fmt(12345, en_US, '010n'), '00,012,345')
818
819 self.assertEqual(get_fmt(123456, crazy, '06n'), '1-2345-6')
820 self.assertEqual(get_fmt(123456, crazy, '07n'), '1-2345-6')
821 self.assertEqual(get_fmt(123456, crazy, '08n'), '1-2345-6')
822 self.assertEqual(get_fmt(123456, crazy, '09n'), '01-2345-6')
823 self.assertEqual(get_fmt(123456, crazy, '010n'), '0-01-2345-6')
824 self.assertEqual(get_fmt(123456, crazy, '011n'), '0-01-2345-6')
825 self.assertEqual(get_fmt(123456, crazy, '012n'), '00-01-2345-6')
826 self.assertEqual(get_fmt(123456, crazy, '013n'), '000-01-2345-6')
827
Mark Dickinson79f52032009-03-17 23:12:51 +0000828
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000829class DecimalArithmeticOperatorsTest(unittest.TestCase):
830 '''Unit tests for all arithmetic operators, binary and unary.'''
831
832 def test_addition(self):
833
834 d1 = Decimal('-11.1')
835 d2 = Decimal('22.2')
836
837 #two Decimals
838 self.assertEqual(d1+d2, Decimal('11.1'))
839 self.assertEqual(d2+d1, Decimal('11.1'))
840
841 #with other type, left
842 c = d1 + 5
843 self.assertEqual(c, Decimal('-6.1'))
844 self.assertEqual(type(c), type(d1))
845
846 #with other type, right
847 c = 5 + d1
848 self.assertEqual(c, Decimal('-6.1'))
849 self.assertEqual(type(c), type(d1))
850
851 #inline with decimal
852 d1 += d2
853 self.assertEqual(d1, Decimal('11.1'))
854
855 #inline with other type
856 d1 += 5
857 self.assertEqual(d1, Decimal('16.1'))
858
859 def test_subtraction(self):
860
861 d1 = Decimal('-11.1')
862 d2 = Decimal('22.2')
863
864 #two Decimals
865 self.assertEqual(d1-d2, Decimal('-33.3'))
866 self.assertEqual(d2-d1, Decimal('33.3'))
867
868 #with other type, left
869 c = d1 - 5
870 self.assertEqual(c, Decimal('-16.1'))
871 self.assertEqual(type(c), type(d1))
872
873 #with other type, right
874 c = 5 - d1
875 self.assertEqual(c, Decimal('16.1'))
876 self.assertEqual(type(c), type(d1))
877
878 #inline with decimal
879 d1 -= d2
880 self.assertEqual(d1, Decimal('-33.3'))
881
882 #inline with other type
883 d1 -= 5
884 self.assertEqual(d1, Decimal('-38.3'))
885
886 def test_multiplication(self):
887
888 d1 = Decimal('-5')
889 d2 = Decimal('3')
890
891 #two Decimals
892 self.assertEqual(d1*d2, Decimal('-15'))
893 self.assertEqual(d2*d1, Decimal('-15'))
894
895 #with other type, left
896 c = d1 * 5
897 self.assertEqual(c, Decimal('-25'))
898 self.assertEqual(type(c), type(d1))
899
900 #with other type, right
901 c = 5 * d1
902 self.assertEqual(c, Decimal('-25'))
903 self.assertEqual(type(c), type(d1))
904
905 #inline with decimal
906 d1 *= d2
907 self.assertEqual(d1, Decimal('-15'))
908
909 #inline with other type
910 d1 *= 5
911 self.assertEqual(d1, Decimal('-75'))
912
913 def test_division(self):
914
915 d1 = Decimal('-5')
916 d2 = Decimal('2')
917
918 #two Decimals
919 self.assertEqual(d1/d2, Decimal('-2.5'))
920 self.assertEqual(d2/d1, Decimal('-0.4'))
921
922 #with other type, left
923 c = d1 / 4
924 self.assertEqual(c, Decimal('-1.25'))
925 self.assertEqual(type(c), type(d1))
926
927 #with other type, right
928 c = 4 / d1
929 self.assertEqual(c, Decimal('-0.8'))
930 self.assertEqual(type(c), type(d1))
931
932 #inline with decimal
933 d1 /= d2
934 self.assertEqual(d1, Decimal('-2.5'))
935
936 #inline with other type
937 d1 /= 4
938 self.assertEqual(d1, Decimal('-0.625'))
939
940 def test_floor_division(self):
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000941
942 d1 = Decimal('5')
943 d2 = Decimal('2')
944
945 #two Decimals
946 self.assertEqual(d1//d2, Decimal('2'))
947 self.assertEqual(d2//d1, Decimal('0'))
948
949 #with other type, left
950 c = d1 // 4
951 self.assertEqual(c, Decimal('1'))
952 self.assertEqual(type(c), type(d1))
953
954 #with other type, right
955 c = 7 // d1
956 self.assertEqual(c, Decimal('1'))
957 self.assertEqual(type(c), type(d1))
958
959 #inline with decimal
960 d1 //= d2
961 self.assertEqual(d1, Decimal('2'))
962
963 #inline with other type
964 d1 //= 2
965 self.assertEqual(d1, Decimal('1'))
966
967 def test_powering(self):
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000968
969 d1 = Decimal('5')
970 d2 = Decimal('2')
971
972 #two Decimals
973 self.assertEqual(d1**d2, Decimal('25'))
974 self.assertEqual(d2**d1, Decimal('32'))
975
976 #with other type, left
977 c = d1 ** 4
978 self.assertEqual(c, Decimal('625'))
979 self.assertEqual(type(c), type(d1))
980
981 #with other type, right
982 c = 7 ** d1
983 self.assertEqual(c, Decimal('16807'))
984 self.assertEqual(type(c), type(d1))
985
986 #inline with decimal
987 d1 **= d2
988 self.assertEqual(d1, Decimal('25'))
989
990 #inline with other type
991 d1 **= 4
992 self.assertEqual(d1, Decimal('390625'))
993
994 def test_module(self):
995
996 d1 = Decimal('5')
997 d2 = Decimal('2')
998
999 #two Decimals
1000 self.assertEqual(d1%d2, Decimal('1'))
1001 self.assertEqual(d2%d1, Decimal('2'))
1002
1003 #with other type, left
1004 c = d1 % 4
1005 self.assertEqual(c, Decimal('1'))
1006 self.assertEqual(type(c), type(d1))
1007
1008 #with other type, right
1009 c = 7 % d1
1010 self.assertEqual(c, Decimal('2'))
1011 self.assertEqual(type(c), type(d1))
1012
1013 #inline with decimal
1014 d1 %= d2
1015 self.assertEqual(d1, Decimal('1'))
1016
1017 #inline with other type
1018 d1 %= 4
1019 self.assertEqual(d1, Decimal('1'))
1020
1021 def test_floor_div_module(self):
1022
1023 d1 = Decimal('5')
1024 d2 = Decimal('2')
1025
1026 #two Decimals
1027 (p, q) = divmod(d1, d2)
1028 self.assertEqual(p, Decimal('2'))
1029 self.assertEqual(q, Decimal('1'))
1030 self.assertEqual(type(p), type(d1))
1031 self.assertEqual(type(q), type(d1))
1032
1033 #with other type, left
1034 (p, q) = divmod(d1, 4)
1035 self.assertEqual(p, Decimal('1'))
1036 self.assertEqual(q, Decimal('1'))
1037 self.assertEqual(type(p), type(d1))
1038 self.assertEqual(type(q), type(d1))
1039
1040 #with other type, right
1041 (p, q) = divmod(7, d1)
1042 self.assertEqual(p, Decimal('1'))
1043 self.assertEqual(q, Decimal('2'))
1044 self.assertEqual(type(p), type(d1))
1045 self.assertEqual(type(q), type(d1))
1046
1047 def test_unary_operators(self):
1048 self.assertEqual(+Decimal(45), Decimal(+45)) # +
1049 self.assertEqual(-Decimal(45), Decimal(-45)) # -
1050 self.assertEqual(abs(Decimal(45)), abs(Decimal(-45))) # abs
1051
Christian Heimes77c02eb2008-02-09 02:18:51 +00001052 def test_nan_comparisons(self):
1053 n = Decimal('NaN')
1054 s = Decimal('sNaN')
1055 i = Decimal('Inf')
1056 f = Decimal('2')
1057 for x, y in [(n, n), (n, i), (i, n), (n, f), (f, n),
1058 (s, n), (n, s), (s, i), (i, s), (s, f), (f, s), (s, s)]:
1059 self.assert_(x != y)
1060 self.assert_(not (x == y))
1061 self.assert_(not (x < y))
1062 self.assert_(not (x <= y))
1063 self.assert_(not (x > y))
1064 self.assert_(not (x >= y))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001065
1066# The following are two functions used to test threading in the next class
1067
1068def thfunc1(cls):
1069 d1 = Decimal(1)
1070 d3 = Decimal(3)
Christian Heimesfe337bf2008-03-23 21:54:12 +00001071 test1 = d1/d3
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001072 cls.synchro.wait()
Christian Heimesfe337bf2008-03-23 21:54:12 +00001073 test2 = d1/d3
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001074 cls.finish1.set()
Christian Heimesfe337bf2008-03-23 21:54:12 +00001075
Christian Heimes81ee3ef2008-05-04 22:42:01 +00001076 cls.assertEqual(test1, Decimal('0.3333333333333333333333333333'))
1077 cls.assertEqual(test2, Decimal('0.3333333333333333333333333333'))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001078 return
1079
1080def thfunc2(cls):
1081 d1 = Decimal(1)
1082 d3 = Decimal(3)
Christian Heimesfe337bf2008-03-23 21:54:12 +00001083 test1 = d1/d3
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001084 thiscontext = getcontext()
1085 thiscontext.prec = 18
Christian Heimesfe337bf2008-03-23 21:54:12 +00001086 test2 = d1/d3
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001087 cls.synchro.set()
1088 cls.finish2.set()
Christian Heimesfe337bf2008-03-23 21:54:12 +00001089
Christian Heimes81ee3ef2008-05-04 22:42:01 +00001090 cls.assertEqual(test1, Decimal('0.3333333333333333333333333333'))
Christian Heimesfe337bf2008-03-23 21:54:12 +00001091 cls.assertEqual(test2, Decimal('0.333333333333333333'))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001092 return
1093
1094
1095class DecimalUseOfContextTest(unittest.TestCase):
1096 '''Unit tests for Use of Context cases in Decimal.'''
1097
Raymond Hettinger7e71fa52004-12-18 19:07:19 +00001098 try:
1099 import threading
1100 except ImportError:
1101 threading = None
1102
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001103 # Take care executing this test from IDLE, there's an issue in threading
1104 # that hangs IDLE and I couldn't find it
1105
1106 def test_threading(self):
1107 #Test the "threading isolation" of a Context.
1108
1109 self.synchro = threading.Event()
1110 self.finish1 = threading.Event()
1111 self.finish2 = threading.Event()
1112
1113 th1 = threading.Thread(target=thfunc1, args=(self,))
1114 th2 = threading.Thread(target=thfunc2, args=(self,))
1115
1116 th1.start()
1117 th2.start()
1118
1119 self.finish1.wait()
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001120 self.finish2.wait()
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001121 return
1122
Raymond Hettinger7e71fa52004-12-18 19:07:19 +00001123 if threading is None:
1124 del test_threading
1125
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001126
1127class DecimalUsabilityTest(unittest.TestCase):
1128 '''Unit tests for Usability cases of Decimal.'''
1129
1130 def test_comparison_operators(self):
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001131
1132 da = Decimal('23.42')
1133 db = Decimal('23.42')
1134 dc = Decimal('45')
1135
1136 #two Decimals
1137 self.failUnless(dc > da)
1138 self.failUnless(dc >= da)
1139 self.failUnless(da < dc)
1140 self.failUnless(da <= dc)
Guido van Rossume61fd5b2007-07-11 12:20:59 +00001141 self.assertEqual(da, db)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001142 self.failUnless(da != dc)
1143 self.failUnless(da <= db)
1144 self.failUnless(da >= db)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001145
1146 #a Decimal and an int
1147 self.failUnless(dc > 23)
1148 self.failUnless(23 < dc)
Guido van Rossume61fd5b2007-07-11 12:20:59 +00001149 self.assertEqual(dc, 45)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001150
1151 #a Decimal and uncomparable
Raymond Hettinger0aeac102004-07-05 22:53:03 +00001152 self.assertNotEqual(da, 'ugly')
1153 self.assertNotEqual(da, 32.7)
1154 self.assertNotEqual(da, object())
1155 self.assertNotEqual(da, object)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001156
Raymond Hettinger0aeac102004-07-05 22:53:03 +00001157 # sortable
Guido van Rossumc1f779c2007-07-03 08:25:58 +00001158 a = list(map(Decimal, range(100)))
Raymond Hettinger0aeac102004-07-05 22:53:03 +00001159 b = a[:]
1160 random.shuffle(a)
1161 a.sort()
1162 self.assertEqual(a, b)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001163
1164 def test_copy_and_deepcopy_methods(self):
1165 d = Decimal('43.24')
1166 c = copy.copy(d)
1167 self.assertEqual(id(c), id(d))
1168 dc = copy.deepcopy(d)
1169 self.assertEqual(id(dc), id(d))
1170
1171 def test_hash_method(self):
1172 #just that it's hashable
1173 hash(Decimal(23))
Thomas Wouters8ce81f72007-09-20 18:22:40 +00001174
1175 test_values = [Decimal(sign*(2**m + n))
1176 for m in [0, 14, 15, 16, 17, 30, 31,
1177 32, 33, 62, 63, 64, 65, 66]
1178 for n in range(-10, 10)
1179 for sign in [-1, 1]]
1180 test_values.extend([
1181 Decimal("-0"), # zeros
1182 Decimal("0.00"),
1183 Decimal("-0.000"),
1184 Decimal("0E10"),
1185 Decimal("-0E12"),
1186 Decimal("10.0"), # negative exponent
1187 Decimal("-23.00000"),
1188 Decimal("1230E100"), # positive exponent
1189 Decimal("-4.5678E50"),
1190 # a value for which hash(n) != hash(n % (2**64-1))
1191 # in Python pre-2.6
1192 Decimal(2**64 + 2**32 - 1),
1193 # selection of values which fail with the old (before
1194 # version 2.6) long.__hash__
1195 Decimal("1.634E100"),
1196 Decimal("90.697E100"),
1197 Decimal("188.83E100"),
1198 Decimal("1652.9E100"),
1199 Decimal("56531E100"),
1200 ])
1201
1202 # check that hash(d) == hash(int(d)) for integral values
1203 for value in test_values:
1204 self.assertEqual(hash(value), hash(int(value)))
1205
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001206 #the same hash that to an int
1207 self.assertEqual(hash(Decimal(23)), hash(23))
Raymond Hettingerbea3f6f2005-03-15 04:59:17 +00001208 self.assertRaises(TypeError, hash, Decimal('NaN'))
1209 self.assert_(hash(Decimal('Inf')))
1210 self.assert_(hash(Decimal('-Inf')))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001211
Christian Heimes2380ac72008-01-09 00:17:24 +00001212 # check that the value of the hash doesn't depend on the
1213 # current context (issue #1757)
1214 c = getcontext()
1215 old_precision = c.prec
1216 x = Decimal("123456789.1")
1217
1218 c.prec = 6
1219 h1 = hash(x)
1220 c.prec = 10
1221 h2 = hash(x)
1222 c.prec = 16
1223 h3 = hash(x)
1224
1225 self.assertEqual(h1, h2)
1226 self.assertEqual(h1, h3)
1227 c.prec = old_precision
1228
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001229 def test_min_and_max_methods(self):
1230
1231 d1 = Decimal('15.32')
1232 d2 = Decimal('28.5')
1233 l1 = 15
1234 l2 = 28
1235
1236 #between Decimals
1237 self.failUnless(min(d1,d2) is d1)
1238 self.failUnless(min(d2,d1) is d1)
1239 self.failUnless(max(d1,d2) is d2)
1240 self.failUnless(max(d2,d1) is d2)
1241
1242 #between Decimal and long
1243 self.failUnless(min(d1,l2) is d1)
1244 self.failUnless(min(l2,d1) is d1)
1245 self.failUnless(max(l1,d2) is d2)
1246 self.failUnless(max(d2,l1) is d2)
1247
1248 def test_as_nonzero(self):
1249 #as false
1250 self.failIf(Decimal(0))
1251 #as true
1252 self.failUnless(Decimal('0.372'))
1253
1254 def test_tostring_methods(self):
1255 #Test str and repr methods.
1256
1257 d = Decimal('15.32')
1258 self.assertEqual(str(d), '15.32') # str
Christian Heimes68f5fbe2008-02-14 08:27:37 +00001259 self.assertEqual(repr(d), "Decimal('15.32')") # repr
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001260
1261 def test_tonum_methods(self):
1262 #Test float, int and long methods.
1263
1264 d1 = Decimal('66')
1265 d2 = Decimal('15.32')
1266
1267 #int
1268 self.assertEqual(int(d1), 66)
1269 self.assertEqual(int(d2), 15)
1270
1271 #long
Guido van Rossume2a383d2007-01-15 16:59:06 +00001272 self.assertEqual(int(d1), 66)
1273 self.assertEqual(int(d2), 15)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001274
1275 #float
1276 self.assertEqual(float(d1), 66)
1277 self.assertEqual(float(d2), 15.32)
1278
Mark Dickinsonb27406c2008-05-09 13:42:33 +00001279 #floor
1280 test_pairs = [
1281 ('123.00', 123),
1282 ('3.2', 3),
1283 ('3.54', 3),
1284 ('3.899', 3),
1285 ('-2.3', -3),
1286 ('-11.0', -11),
1287 ('0.0', 0),
1288 ('-0E3', 0),
1289 ]
1290 for d, i in test_pairs:
1291 self.assertEqual(math.floor(Decimal(d)), i)
1292 self.assertRaises(ValueError, math.floor, Decimal('-NaN'))
1293 self.assertRaises(ValueError, math.floor, Decimal('sNaN'))
1294 self.assertRaises(ValueError, math.floor, Decimal('NaN123'))
1295 self.assertRaises(OverflowError, math.floor, Decimal('Inf'))
1296 self.assertRaises(OverflowError, math.floor, Decimal('-Inf'))
1297
1298 #ceiling
1299 test_pairs = [
1300 ('123.00', 123),
1301 ('3.2', 4),
1302 ('3.54', 4),
1303 ('3.899', 4),
1304 ('-2.3', -2),
1305 ('-11.0', -11),
1306 ('0.0', 0),
1307 ('-0E3', 0),
1308 ]
1309 for d, i in test_pairs:
1310 self.assertEqual(math.ceil(Decimal(d)), i)
1311 self.assertRaises(ValueError, math.ceil, Decimal('-NaN'))
1312 self.assertRaises(ValueError, math.ceil, Decimal('sNaN'))
1313 self.assertRaises(ValueError, math.ceil, Decimal('NaN123'))
1314 self.assertRaises(OverflowError, math.ceil, Decimal('Inf'))
1315 self.assertRaises(OverflowError, math.ceil, Decimal('-Inf'))
1316
1317 #round, single argument
1318 test_pairs = [
1319 ('123.00', 123),
1320 ('3.2', 3),
1321 ('3.54', 4),
1322 ('3.899', 4),
1323 ('-2.3', -2),
1324 ('-11.0', -11),
1325 ('0.0', 0),
1326 ('-0E3', 0),
1327 ('-3.5', -4),
1328 ('-2.5', -2),
1329 ('-1.5', -2),
1330 ('-0.5', 0),
1331 ('0.5', 0),
1332 ('1.5', 2),
1333 ('2.5', 2),
1334 ('3.5', 4),
1335 ]
1336 for d, i in test_pairs:
1337 self.assertEqual(round(Decimal(d)), i)
1338 self.assertRaises(ValueError, round, Decimal('-NaN'))
1339 self.assertRaises(ValueError, round, Decimal('sNaN'))
1340 self.assertRaises(ValueError, round, Decimal('NaN123'))
1341 self.assertRaises(OverflowError, round, Decimal('Inf'))
1342 self.assertRaises(OverflowError, round, Decimal('-Inf'))
1343
1344 #round, two arguments; this is essentially equivalent
1345 #to quantize, which is already extensively tested
1346 test_triples = [
1347 ('123.456', -4, '0E+4'),
1348 ('123.456', -3, '0E+3'),
1349 ('123.456', -2, '1E+2'),
1350 ('123.456', -1, '1.2E+2'),
1351 ('123.456', 0, '123'),
1352 ('123.456', 1, '123.5'),
1353 ('123.456', 2, '123.46'),
1354 ('123.456', 3, '123.456'),
1355 ('123.456', 4, '123.4560'),
1356 ('123.455', 2, '123.46'),
1357 ('123.445', 2, '123.44'),
1358 ('Inf', 4, 'NaN'),
1359 ('-Inf', -23, 'NaN'),
1360 ('sNaN314', 3, 'NaN314'),
1361 ]
1362 for d, n, r in test_triples:
1363 self.assertEqual(str(round(Decimal(d), n)), r)
1364
1365
1366
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001367 def test_eval_round_trip(self):
1368
1369 #with zero
1370 d = Decimal( (0, (0,), 0) )
1371 self.assertEqual(d, eval(repr(d)))
1372
1373 #int
1374 d = Decimal( (1, (4, 5), 0) )
1375 self.assertEqual(d, eval(repr(d)))
1376
1377 #float
1378 d = Decimal( (0, (4, 5, 3, 4), -2) )
1379 self.assertEqual(d, eval(repr(d)))
1380
1381 #weird
1382 d = Decimal( (1, (4, 3, 4, 9, 1, 3, 5, 3, 4), -25) )
1383 self.assertEqual(d, eval(repr(d)))
1384
1385 def test_as_tuple(self):
1386
1387 #with zero
1388 d = Decimal(0)
1389 self.assertEqual(d.as_tuple(), (0, (0,), 0) )
1390
1391 #int
1392 d = Decimal(-45)
1393 self.assertEqual(d.as_tuple(), (1, (4, 5), 0) )
1394
1395 #complicated string
1396 d = Decimal("-4.34913534E-17")
1397 self.assertEqual(d.as_tuple(), (1, (4, 3, 4, 9, 1, 3, 5, 3, 4), -25) )
1398
1399 #inf
1400 d = Decimal("Infinity")
1401 self.assertEqual(d.as_tuple(), (0, (0,), 'F') )
1402
Guido van Rossum8ce8a782007-11-01 19:42:39 +00001403 #leading zeros in coefficient should be stripped
1404 d = Decimal( (0, (0, 0, 4, 0, 5, 3, 4), -2) )
1405 self.assertEqual(d.as_tuple(), (0, (4, 0, 5, 3, 4), -2) )
1406 d = Decimal( (1, (0, 0, 0), 37) )
1407 self.assertEqual(d.as_tuple(), (1, (0,), 37))
1408 d = Decimal( (1, (), 37) )
1409 self.assertEqual(d.as_tuple(), (1, (0,), 37))
1410
1411 #leading zeros in NaN diagnostic info should be stripped
1412 d = Decimal( (0, (0, 0, 4, 0, 5, 3, 4), 'n') )
1413 self.assertEqual(d.as_tuple(), (0, (4, 0, 5, 3, 4), 'n') )
1414 d = Decimal( (1, (0, 0, 0), 'N') )
1415 self.assertEqual(d.as_tuple(), (1, (), 'N') )
1416 d = Decimal( (1, (), 'n') )
1417 self.assertEqual(d.as_tuple(), (1, (), 'n') )
1418
1419 #coefficient in infinity should be ignored
1420 d = Decimal( (0, (4, 5, 3, 4), 'F') )
1421 self.assertEqual(d.as_tuple(), (0, (0,), 'F'))
1422 d = Decimal( (1, (0, 2, 7, 1), 'F') )
1423 self.assertEqual(d.as_tuple(), (1, (0,), 'F'))
1424
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001425 def test_immutability_operations(self):
1426 # Do operations and check that it didn't change change internal objects.
1427
1428 d1 = Decimal('-25e55')
1429 b1 = Decimal('-25e55')
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001430 d2 = Decimal('33e+33')
1431 b2 = Decimal('33e+33')
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001432
1433 def checkSameDec(operation, useOther=False):
1434 if useOther:
1435 eval("d1." + operation + "(d2)")
1436 self.assertEqual(d1._sign, b1._sign)
1437 self.assertEqual(d1._int, b1._int)
1438 self.assertEqual(d1._exp, b1._exp)
1439 self.assertEqual(d2._sign, b2._sign)
1440 self.assertEqual(d2._int, b2._int)
1441 self.assertEqual(d2._exp, b2._exp)
1442 else:
1443 eval("d1." + operation + "()")
1444 self.assertEqual(d1._sign, b1._sign)
1445 self.assertEqual(d1._int, b1._int)
1446 self.assertEqual(d1._exp, b1._exp)
1447 return
1448
1449 Decimal(d1)
1450 self.assertEqual(d1._sign, b1._sign)
1451 self.assertEqual(d1._int, b1._int)
1452 self.assertEqual(d1._exp, b1._exp)
1453
1454 checkSameDec("__abs__")
1455 checkSameDec("__add__", True)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001456 checkSameDec("__divmod__", True)
Christian Heimes77c02eb2008-02-09 02:18:51 +00001457 checkSameDec("__eq__", True)
1458 checkSameDec("__ne__", True)
1459 checkSameDec("__le__", True)
1460 checkSameDec("__lt__", True)
1461 checkSameDec("__ge__", True)
1462 checkSameDec("__gt__", True)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001463 checkSameDec("__float__")
1464 checkSameDec("__floordiv__", True)
1465 checkSameDec("__hash__")
1466 checkSameDec("__int__")
Christian Heimes969fe572008-01-25 11:23:10 +00001467 checkSameDec("__trunc__")
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001468 checkSameDec("__mod__", True)
1469 checkSameDec("__mul__", True)
1470 checkSameDec("__neg__")
Jack Diederich4dafcc42006-11-28 19:15:13 +00001471 checkSameDec("__bool__")
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001472 checkSameDec("__pos__")
1473 checkSameDec("__pow__", True)
1474 checkSameDec("__radd__", True)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001475 checkSameDec("__rdivmod__", True)
1476 checkSameDec("__repr__")
1477 checkSameDec("__rfloordiv__", True)
1478 checkSameDec("__rmod__", True)
1479 checkSameDec("__rmul__", True)
1480 checkSameDec("__rpow__", True)
1481 checkSameDec("__rsub__", True)
1482 checkSameDec("__str__")
1483 checkSameDec("__sub__", True)
1484 checkSameDec("__truediv__", True)
1485 checkSameDec("adjusted")
1486 checkSameDec("as_tuple")
1487 checkSameDec("compare", True)
1488 checkSameDec("max", True)
1489 checkSameDec("min", True)
1490 checkSameDec("normalize")
1491 checkSameDec("quantize", True)
1492 checkSameDec("remainder_near", True)
1493 checkSameDec("same_quantum", True)
1494 checkSameDec("sqrt")
1495 checkSameDec("to_eng_string")
1496 checkSameDec("to_integral")
1497
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001498 def test_subclassing(self):
1499 # Different behaviours when subclassing Decimal
1500
1501 class MyDecimal(Decimal):
1502 pass
1503
1504 d1 = MyDecimal(1)
1505 d2 = MyDecimal(2)
1506 d = d1 + d2
1507 self.assertTrue(type(d) is Decimal)
1508
1509 d = d1.max(d2)
1510 self.assertTrue(type(d) is Decimal)
1511
Christian Heimes0348fb62008-03-26 12:55:56 +00001512 def test_implicit_context(self):
1513 # Check results when context given implicitly. (Issue 2478)
1514 c = getcontext()
1515 self.assertEqual(str(Decimal(0).sqrt()),
1516 str(c.sqrt(Decimal(0))))
1517
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001518
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001519class DecimalPythonAPItests(unittest.TestCase):
1520
Raymond Hettinger82417ca2009-02-03 03:54:28 +00001521 def test_abc(self):
1522 self.assert_(issubclass(Decimal, numbers.Number))
1523 self.assert_(not issubclass(Decimal, numbers.Real))
1524 self.assert_(isinstance(Decimal(0), numbers.Number))
1525 self.assert_(not isinstance(Decimal(0), numbers.Real))
1526
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001527 def test_pickle(self):
1528 d = Decimal('-3.141590000')
1529 p = pickle.dumps(d)
1530 e = pickle.loads(p)
1531 self.assertEqual(d, e)
1532
Raymond Hettinger5548be22004-07-05 18:49:38 +00001533 def test_int(self):
Raymond Hettinger605ed022004-11-24 07:28:48 +00001534 for x in range(-250, 250):
1535 s = '%0.2f' % (x / 100.0)
Raymond Hettinger5548be22004-07-05 18:49:38 +00001536 # should work the same as for floats
1537 self.assertEqual(int(Decimal(s)), int(float(s)))
Raymond Hettinger605ed022004-11-24 07:28:48 +00001538 # should work the same as to_integral in the ROUND_DOWN mode
Raymond Hettinger5548be22004-07-05 18:49:38 +00001539 d = Decimal(s)
Raymond Hettinger605ed022004-11-24 07:28:48 +00001540 r = d.to_integral(ROUND_DOWN)
Raymond Hettinger5548be22004-07-05 18:49:38 +00001541 self.assertEqual(Decimal(int(d)), r)
1542
Christian Heimes969fe572008-01-25 11:23:10 +00001543 def test_trunc(self):
1544 for x in range(-250, 250):
1545 s = '%0.2f' % (x / 100.0)
1546 # should work the same as for floats
1547 self.assertEqual(int(Decimal(s)), int(float(s)))
1548 # should work the same as to_integral in the ROUND_DOWN mode
1549 d = Decimal(s)
1550 r = d.to_integral(ROUND_DOWN)
Christian Heimes400adb02008-02-01 08:12:03 +00001551 self.assertEqual(Decimal(math.trunc(d)), r)
Christian Heimes969fe572008-01-25 11:23:10 +00001552
Raymond Hettinger771ed762009-01-03 19:20:32 +00001553 def test_from_float(self):
1554
1555 class MyDecimal(Decimal):
1556 pass
1557
1558 r = MyDecimal.from_float(0.1)
1559 self.assertEqual(type(r), MyDecimal)
1560 self.assertEqual(str(r),
1561 '0.1000000000000000055511151231257827021181583404541015625')
1562 bigint = 12345678901234567890123456789
1563 self.assertEqual(MyDecimal.from_float(bigint), MyDecimal(bigint))
1564 self.assert_(MyDecimal.from_float(float('nan')).is_qnan())
1565 self.assert_(MyDecimal.from_float(float('inf')).is_infinite())
1566 self.assert_(MyDecimal.from_float(float('-inf')).is_infinite())
1567 self.assertEqual(str(MyDecimal.from_float(float('nan'))),
1568 str(Decimal('NaN')))
1569 self.assertEqual(str(MyDecimal.from_float(float('inf'))),
1570 str(Decimal('Infinity')))
1571 self.assertEqual(str(MyDecimal.from_float(float('-inf'))),
1572 str(Decimal('-Infinity')))
1573 self.assertRaises(TypeError, MyDecimal.from_float, 'abc')
1574 for i in range(200):
1575 x = random.expovariate(0.01) * (random.random() * 2.0 - 1.0)
1576 self.assertEqual(x, float(MyDecimal.from_float(x))) # roundtrip
1577
1578 def test_create_decimal_from_float(self):
1579 context = Context(prec=5, rounding=ROUND_DOWN)
1580 self.assertEqual(
1581 context.create_decimal_from_float(math.pi),
1582 Decimal('3.1415')
1583 )
1584 context = Context(prec=5, rounding=ROUND_UP)
1585 self.assertEqual(
1586 context.create_decimal_from_float(math.pi),
1587 Decimal('3.1416')
1588 )
1589 context = Context(prec=5, traps=[Inexact])
1590 self.assertRaises(
1591 Inexact,
1592 context.create_decimal_from_float,
1593 math.pi
1594 )
1595 self.assertEqual(repr(context.create_decimal_from_float(-0.0)),
1596 "Decimal('-0')")
1597 self.assertEqual(repr(context.create_decimal_from_float(1.0)),
1598 "Decimal('1')")
1599 self.assertEqual(repr(context.create_decimal_from_float(10)),
1600 "Decimal('10')")
1601
Raymond Hettingerd9c0a7a2004-07-03 10:02:28 +00001602class ContextAPItests(unittest.TestCase):
1603
1604 def test_pickle(self):
1605 c = Context()
1606 e = pickle.loads(pickle.dumps(c))
1607 for k in vars(c):
1608 v1 = vars(c)[k]
1609 v2 = vars(e)[k]
1610 self.assertEqual(v1, v2)
1611
Raymond Hettinger0aeac102004-07-05 22:53:03 +00001612 def test_equality_with_other_types(self):
1613 self.assert_(Decimal(10) in ['a', 1.0, Decimal(10), (1,2), {}])
1614 self.assert_(Decimal(10) not in ['a', 1.0, (1,2), {}])
1615
Raymond Hettinger955d2b22004-08-08 20:17:45 +00001616 def test_copy(self):
1617 # All copies should be deep
1618 c = Context()
1619 d = c.copy()
1620 self.assertNotEqual(id(c), id(d))
1621 self.assertNotEqual(id(c.flags), id(d.flags))
1622 self.assertNotEqual(id(c.traps), id(d.traps))
1623
Thomas Wouters89f507f2006-12-13 04:49:30 +00001624class WithStatementTest(unittest.TestCase):
1625 # Can't do these as docstrings until Python 2.6
1626 # as doctest can't handle __future__ statements
1627
1628 def test_localcontext(self):
1629 # Use a copy of the current context in the block
1630 orig_ctx = getcontext()
1631 with localcontext() as enter_ctx:
1632 set_ctx = getcontext()
1633 final_ctx = getcontext()
1634 self.assert_(orig_ctx is final_ctx, 'did not restore context correctly')
1635 self.assert_(orig_ctx is not set_ctx, 'did not copy the context')
1636 self.assert_(set_ctx is enter_ctx, '__enter__ returned wrong context')
1637
1638 def test_localcontextarg(self):
1639 # Use a copy of the supplied context in the block
1640 orig_ctx = getcontext()
1641 new_ctx = Context(prec=42)
1642 with localcontext(new_ctx) as enter_ctx:
1643 set_ctx = getcontext()
1644 final_ctx = getcontext()
1645 self.assert_(orig_ctx is final_ctx, 'did not restore context correctly')
1646 self.assert_(set_ctx.prec == new_ctx.prec, 'did not set correct context')
1647 self.assert_(new_ctx is not set_ctx, 'did not copy the context')
1648 self.assert_(set_ctx is enter_ctx, '__enter__ returned wrong context')
1649
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001650class ContextFlags(unittest.TestCase):
1651 def test_flags_irrelevant(self):
1652 # check that the result (numeric result + flags raised) of an
1653 # arithmetic operation doesn't depend on the current flags
1654
1655 context = Context(prec=9, Emin = -999999999, Emax = 999999999,
1656 rounding=ROUND_HALF_EVEN, traps=[], flags=[])
1657
1658 # operations that raise various flags, in the form (function, arglist)
1659 operations = [
1660 (context._apply, [Decimal("100E-1000000009")]),
1661 (context.sqrt, [Decimal(2)]),
1662 (context.add, [Decimal("1.23456789"), Decimal("9.87654321")]),
1663 (context.multiply, [Decimal("1.23456789"), Decimal("9.87654321")]),
1664 (context.subtract, [Decimal("1.23456789"), Decimal("9.87654321")]),
1665 ]
1666
1667 # try various flags individually, then a whole lot at once
1668 flagsets = [[Inexact], [Rounded], [Underflow], [Clamped], [Subnormal],
1669 [Inexact, Rounded, Underflow, Clamped, Subnormal]]
1670
1671 for fn, args in operations:
1672 # find answer and flags raised using a clean context
1673 context.clear_flags()
1674 ans = fn(*args)
1675 flags = [k for k, v in context.flags.items() if v]
1676
1677 for extra_flags in flagsets:
1678 # set flags, before calling operation
1679 context.clear_flags()
1680 for flag in extra_flags:
1681 context._raise_error(flag)
1682 new_ans = fn(*args)
1683
1684 # flags that we expect to be set after the operation
1685 expected_flags = list(flags)
1686 for flag in extra_flags:
1687 if flag not in expected_flags:
1688 expected_flags.append(flag)
1689 expected_flags.sort(key=id)
1690
1691 # flags we actually got
1692 new_flags = [k for k,v in context.flags.items() if v]
1693 new_flags.sort(key=id)
1694
1695 self.assertEqual(ans, new_ans,
1696 "operation produces different answers depending on flags set: " +
1697 "expected %s, got %s." % (ans, new_ans))
1698 self.assertEqual(new_flags, expected_flags,
1699 "operation raises different flags depending on flags set: " +
1700 "expected %s, got %s" % (expected_flags, new_flags))
1701
1702def test_main(arith=False, verbose=None, todo_tests=None, debug=None):
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001703 """ Execute the tests.
1704
Raymond Hettingered20ad82004-09-04 20:09:13 +00001705 Runs all arithmetic tests if arith is True or if the "decimal" resource
1706 is enabled in regrtest.py
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001707 """
Raymond Hettingered20ad82004-09-04 20:09:13 +00001708
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00001709 init()
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001710 global TEST_ALL, DEBUG
Raymond Hettingered20ad82004-09-04 20:09:13 +00001711 TEST_ALL = arith or is_resource_enabled('decimal')
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001712 DEBUG = debug
Raymond Hettingered20ad82004-09-04 20:09:13 +00001713
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001714 if todo_tests is None:
1715 test_classes = [
1716 DecimalExplicitConstructionTest,
1717 DecimalImplicitConstructionTest,
1718 DecimalArithmeticOperatorsTest,
Christian Heimesf16baeb2008-02-29 14:57:44 +00001719 DecimalFormatTest,
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001720 DecimalUseOfContextTest,
1721 DecimalUsabilityTest,
1722 DecimalPythonAPItests,
1723 ContextAPItests,
1724 DecimalTest,
1725 WithStatementTest,
1726 ContextFlags
1727 ]
1728 else:
1729 test_classes = [DecimalTest]
1730
1731 # Dynamically build custom test definition for each file in the test
1732 # directory and add the definitions to the DecimalTest class. This
1733 # procedure insures that new files do not get skipped.
1734 for filename in os.listdir(directory):
1735 if '.decTest' not in filename or filename.startswith("."):
1736 continue
1737 head, tail = filename.split('.')
1738 if todo_tests is not None and head not in todo_tests:
1739 continue
1740 tester = lambda self, f=filename: self.eval_file(directory + f)
1741 setattr(DecimalTest, 'test_' + head, tester)
1742 del filename, head, tail, tester
1743
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001744
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00001745 try:
1746 run_unittest(*test_classes)
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001747 if todo_tests is None:
1748 import decimal as DecimalModule
1749 run_doctest(DecimalModule, verbose)
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00001750 finally:
1751 setcontext(ORIGINAL_CONTEXT)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001752
1753if __name__ == '__main__':
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001754 import optparse
1755 p = optparse.OptionParser("test_decimal.py [--debug] [{--skip | test1 [test2 [...]]}]")
1756 p.add_option('--debug', '-d', action='store_true', help='shows the test number and context before each test')
1757 p.add_option('--skip', '-s', action='store_true', help='skip over 90% of the arithmetic tests')
1758 (opt, args) = p.parse_args()
1759
1760 if opt.skip:
1761 test_main(arith=False, verbose=True)
1762 elif args:
1763 test_main(arith=True, verbose=True, todo_tests=args, debug=opt.debug)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001764 else:
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001765 test_main(arith=True, verbose=True)