blob: 219348c616a7a6e142dc63a7164b77527b10fbe9 [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 Petersonee8712c2008-05-20 21:35:26 +000034from test.support import (TestSkipped, run_unittest, run_doctest,
Thomas Wouters49fd7fa2006-04-21 10:40:58 +000035 is_resource_enabled)
Raymond Hettinger0aeac102004-07-05 22:53:03 +000036import random
Raymond Hettinger7e71fa52004-12-18 19:07:19 +000037try:
38 import threading
39except ImportError:
40 threading = None
Raymond Hettinger7c85fa42004-07-01 11:01:35 +000041
Raymond Hettingerfed52962004-07-14 15:41:57 +000042# Useful Test Constant
Guido van Rossumc1f779c2007-07-03 08:25:58 +000043Signals = tuple(getcontext().flags.keys())
Raymond Hettingerfed52962004-07-14 15:41:57 +000044
Thomas Wouters49fd7fa2006-04-21 10:40:58 +000045# Tests are built around these assumed context defaults.
46# test_main() restores the original context.
47def init():
48 global ORIGINAL_CONTEXT
49 ORIGINAL_CONTEXT = getcontext().copy()
Christian Heimes81ee3ef2008-05-04 22:42:01 +000050 DefaultTestContext = Context(
51 prec = 9,
52 rounding = ROUND_HALF_EVEN,
53 traps = dict.fromkeys(Signals, 0)
54 )
55 setcontext(DefaultTestContext)
Raymond Hettinger6ea48452004-07-03 12:26:21 +000056
Raymond Hettinger7c85fa42004-07-01 11:01:35 +000057TESTDATADIR = 'decimaltestdata'
Raymond Hettingerd9c0a7a2004-07-03 10:02:28 +000058if __name__ == '__main__':
59 file = sys.argv[0]
60else:
61 file = __file__
62testdir = os.path.dirname(file) or os.curdir
Raymond Hettinger267b8682005-03-27 10:47:39 +000063directory = testdir + os.sep + TESTDATADIR + os.sep
Raymond Hettinger7c85fa42004-07-01 11:01:35 +000064
Raymond Hettinger267b8682005-03-27 10:47:39 +000065skip_expected = not os.path.isdir(directory)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +000066
67# Make sure it actually raises errors when not expected and caught in flags
68# Slower, since it runs some things several times.
69EXTENDEDERRORTEST = False
70
Raymond Hettinger7c85fa42004-07-01 11:01:35 +000071#Map the test cases' error names to the actual errors
Raymond Hettinger7c85fa42004-07-01 11:01:35 +000072ErrorNames = {'clamped' : Clamped,
Raymond Hettinger5aa478b2004-07-09 10:02:53 +000073 'conversion_syntax' : InvalidOperation,
Raymond Hettinger7c85fa42004-07-01 11:01:35 +000074 'division_by_zero' : DivisionByZero,
Raymond Hettinger5aa478b2004-07-09 10:02:53 +000075 'division_impossible' : InvalidOperation,
76 'division_undefined' : InvalidOperation,
Raymond Hettinger7c85fa42004-07-01 11:01:35 +000077 'inexact' : Inexact,
Raymond Hettinger5aa478b2004-07-09 10:02:53 +000078 'invalid_context' : InvalidOperation,
Raymond Hettinger7c85fa42004-07-01 11:01:35 +000079 'invalid_operation' : InvalidOperation,
80 'overflow' : Overflow,
81 'rounded' : Rounded,
82 'subnormal' : Subnormal,
83 'underflow' : Underflow}
84
85
86def Nonfunction(*args):
87 """Doesn't do anything."""
88 return None
89
90RoundingDict = {'ceiling' : ROUND_CEILING, #Maps test-case names to roundings.
91 'down' : ROUND_DOWN,
92 'floor' : ROUND_FLOOR,
93 'half_down' : ROUND_HALF_DOWN,
94 'half_even' : ROUND_HALF_EVEN,
95 'half_up' : ROUND_HALF_UP,
Thomas Wouters1b7f8912007-09-19 03:06:30 +000096 'up' : ROUND_UP,
97 '05up' : ROUND_05UP}
Raymond Hettinger7c85fa42004-07-01 11:01:35 +000098
99# Name adapter to be able to change the Decimal and Context
100# interface without changing the test files from Cowlishaw
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000101nameAdapter = {'and':'logical_and',
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000102 'apply':'_apply',
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000103 'class':'number_class',
104 'comparesig':'compare_signal',
105 'comparetotal':'compare_total',
106 'comparetotmag':'compare_total_mag',
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000107 'copy':'copy_decimal',
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000108 'copyabs':'copy_abs',
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000109 'copynegate':'copy_negate',
110 'copysign':'copy_sign',
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000111 'divideint':'divide_int',
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000112 'invert':'logical_invert',
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000113 'iscanonical':'is_canonical',
114 'isfinite':'is_finite',
115 'isinfinite':'is_infinite',
116 'isnan':'is_nan',
117 'isnormal':'is_normal',
118 'isqnan':'is_qnan',
119 'issigned':'is_signed',
120 'issnan':'is_snan',
121 'issubnormal':'is_subnormal',
122 'iszero':'is_zero',
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000123 'maxmag':'max_mag',
124 'minmag':'min_mag',
125 'nextminus':'next_minus',
126 'nextplus':'next_plus',
127 'nexttoward':'next_toward',
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000128 'or':'logical_or',
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000129 'reduce':'normalize',
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000130 'remaindernear':'remainder_near',
131 'samequantum':'same_quantum',
132 'squareroot':'sqrt',
133 'toeng':'to_eng_string',
134 'tointegral':'to_integral_value',
135 'tointegralx':'to_integral_exact',
136 'tosci':'to_sci_string',
137 'xor':'logical_xor',
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000138 }
139
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000140# The following functions return True/False rather than a Decimal instance
141
142LOGICAL_FUNCTIONS = (
143 'is_canonical',
144 'is_finite',
145 'is_infinite',
146 'is_nan',
147 'is_normal',
148 'is_qnan',
149 'is_signed',
150 'is_snan',
151 'is_subnormal',
152 'is_zero',
153 'same_quantum',
154 )
155
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000156# For some operations (currently exp, ln, log10, power), the decNumber
157# reference implementation imposes additional restrictions on the
158# context and operands. These restrictions are not part of the
159# specification; however, the effect of these restrictions does show
160# up in some of the testcases. We skip testcases that violate these
161# restrictions, since Decimal behaves differently from decNumber for
162# these testcases so these testcases would otherwise fail.
163
164decNumberRestricted = ('power', 'ln', 'log10', 'exp')
165DEC_MAX_MATH = 999999
166def outside_decNumber_bounds(v, context):
167 if (context.prec > DEC_MAX_MATH or
168 context.Emax > DEC_MAX_MATH or
169 -context.Emin > DEC_MAX_MATH):
170 return True
171 if not v._is_special and v and (
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000172 v.adjusted() > DEC_MAX_MATH or
173 v.adjusted() < 1-2*DEC_MAX_MATH):
174 return True
175 return False
176
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000177class DecimalTest(unittest.TestCase):
178 """Class which tests the Decimal class against the test cases.
179
180 Changed for unittest.
181 """
182 def setUp(self):
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000183 self.context = Context()
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000184 self.ignore_list = ['#']
185 # Basically, a # means return NaN InvalidOperation.
186 # Different from a sNaN in trim
187
188 self.ChangeDict = {'precision' : self.change_precision,
189 'rounding' : self.change_rounding_method,
190 'maxexponent' : self.change_max_exponent,
191 'minexponent' : self.change_min_exponent,
192 'clamp' : self.change_clamp}
193
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000194 def eval_file(self, file):
195 global skip_expected
196 if skip_expected:
197 raise TestSkipped
198 return
Neal Norwitz70967602006-03-17 08:29:44 +0000199 for line in open(file):
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000200 line = line.replace('\r\n', '').replace('\n', '')
Raymond Hettinger5aa478b2004-07-09 10:02:53 +0000201 #print line
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000202 try:
203 t = self.eval_line(line)
Guido van Rossumb940e112007-01-10 16:19:56 +0000204 except DecimalException as exception:
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000205 #Exception raised where there shoudn't have been one.
206 self.fail('Exception "'+exception.__class__.__name__ + '" raised on line '+line)
207
208 return
209
210 def eval_line(self, s):
211 if s.find(' -> ') >= 0 and s[:2] != '--' and not s.startswith(' --'):
212 s = (s.split('->')[0] + '->' +
213 s.split('->')[1].split('--')[0]).strip()
214 else:
215 s = s.split('--')[0].strip()
216
217 for ignore in self.ignore_list:
218 if s.find(ignore) >= 0:
219 #print s.split()[0], 'NotImplemented--', ignore
220 return
221 if not s:
222 return
223 elif ':' in s:
224 return self.eval_directive(s)
225 else:
226 return self.eval_equation(s)
227
228 def eval_directive(self, s):
Guido van Rossumc1f779c2007-07-03 08:25:58 +0000229 funct, value = (x.strip().lower() for x in s.split(':'))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000230 if funct == 'rounding':
231 value = RoundingDict[value]
232 else:
233 try:
234 value = int(value)
235 except ValueError:
236 pass
237
238 funct = self.ChangeDict.get(funct, Nonfunction)
239 funct(value)
240
241 def eval_equation(self, s):
242 #global DEFAULT_PRECISION
243 #print DEFAULT_PRECISION
Raymond Hettingered20ad82004-09-04 20:09:13 +0000244
245 if not TEST_ALL and random.random() < 0.90:
246 return
247
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000248 try:
249 Sides = s.split('->')
250 L = Sides[0].strip().split()
251 id = L[0]
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000252 if DEBUG:
253 print("Test ", id, end=" ")
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000254 funct = L[1].lower()
255 valstemp = L[2:]
256 L = Sides[1].strip().split()
257 ans = L[0]
258 exceptions = L[1:]
259 except (TypeError, AttributeError, IndexError):
Raymond Hettingerd87ac8f2004-07-09 10:52:54 +0000260 raise InvalidOperation
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000261 def FixQuotes(val):
262 val = val.replace("''", 'SingleQuote').replace('""', 'DoubleQuote')
263 val = val.replace("'", '').replace('"', '')
264 val = val.replace('SingleQuote', "'").replace('DoubleQuote', '"')
265 return val
266 fname = nameAdapter.get(funct, funct)
267 if fname == 'rescale':
268 return
269 funct = getattr(self.context, fname)
270 vals = []
271 conglomerate = ''
272 quote = 0
273 theirexceptions = [ErrorNames[x.lower()] for x in exceptions]
274
Raymond Hettingerd9c0a7a2004-07-03 10:02:28 +0000275 for exception in Signals:
Raymond Hettingerbf440692004-07-10 14:14:37 +0000276 self.context.traps[exception] = 1 #Catch these bugs...
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000277 for exception in theirexceptions:
Raymond Hettingerbf440692004-07-10 14:14:37 +0000278 self.context.traps[exception] = 0
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000279 for i, val in enumerate(valstemp):
280 if val.count("'") % 2 == 1:
281 quote = 1 - quote
282 if quote:
283 conglomerate = conglomerate + ' ' + val
284 continue
285 else:
286 val = conglomerate + val
287 conglomerate = ''
288 v = FixQuotes(val)
289 if fname in ('to_sci_string', 'to_eng_string'):
290 if EXTENDEDERRORTEST:
291 for error in theirexceptions:
Raymond Hettingerbf440692004-07-10 14:14:37 +0000292 self.context.traps[error] = 1
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000293 try:
294 funct(self.context.create_decimal(v))
295 except error:
296 pass
Guido van Rossumb940e112007-01-10 16:19:56 +0000297 except Signals as e:
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000298 self.fail("Raised %s in %s when %s disabled" % \
299 (e, s, error))
300 else:
301 self.fail("Did not raise %s in %s" % (error, s))
Raymond Hettingerbf440692004-07-10 14:14:37 +0000302 self.context.traps[error] = 0
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000303 v = self.context.create_decimal(v)
304 else:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000305 v = Decimal(v, self.context)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000306 vals.append(v)
307
308 ans = FixQuotes(ans)
309
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000310 # skip tests that are related to bounds imposed in the decNumber
311 # reference implementation
312 if fname in decNumberRestricted:
313 if fname == 'power':
314 if not (vals[1]._isinteger() and
315 -1999999997 <= vals[1] <= 999999999):
316 if outside_decNumber_bounds(vals[0], self.context) or \
317 outside_decNumber_bounds(vals[1], self.context):
318 #print "Skipping test %s" % s
319 return
320 else:
321 if outside_decNumber_bounds(vals[0], self.context):
322 #print "Skipping test %s" % s
323 return
324
325
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000326 if EXTENDEDERRORTEST and fname not in ('to_sci_string', 'to_eng_string'):
327 for error in theirexceptions:
Raymond Hettingerbf440692004-07-10 14:14:37 +0000328 self.context.traps[error] = 1
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000329 try:
330 funct(*vals)
331 except error:
332 pass
Guido van Rossumb940e112007-01-10 16:19:56 +0000333 except Signals as e:
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000334 self.fail("Raised %s in %s when %s disabled" % \
335 (e, s, error))
336 else:
337 self.fail("Did not raise %s in %s" % (error, s))
Raymond Hettingerbf440692004-07-10 14:14:37 +0000338 self.context.traps[error] = 0
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000339 if DEBUG:
340 print("--", self.context)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000341 try:
342 result = str(funct(*vals))
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000343 if fname in LOGICAL_FUNCTIONS:
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000344 result = str(int(eval(result))) # 'True', 'False' -> '1', '0'
Guido van Rossumb940e112007-01-10 16:19:56 +0000345 except Signals as error:
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000346 self.fail("Raised %s in %s" % (error, s))
347 except: #Catch any error long enough to state the test case.
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000348 print("ERROR:", s)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000349 raise
350
351 myexceptions = self.getexceptions()
Raymond Hettingerbf440692004-07-10 14:14:37 +0000352 self.context.clear_flags()
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000353
Guido van Rossum47b9ff62006-08-24 00:41:19 +0000354 myexceptions.sort(key=repr)
355 theirexceptions.sort(key=repr)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000356
357 self.assertEqual(result, ans,
358 'Incorrect answer for ' + s + ' -- got ' + result)
359 self.assertEqual(myexceptions, theirexceptions,
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000360 'Incorrect flags set in ' + s + ' -- got ' + str(myexceptions))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000361 return
362
363 def getexceptions(self):
Raymond Hettingerf63ba432004-08-17 05:42:09 +0000364 return [e for e in Signals if self.context.flags[e]]
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000365
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000366 def change_precision(self, prec):
367 self.context.prec = prec
368 def change_rounding_method(self, rounding):
369 self.context.rounding = rounding
370 def change_min_exponent(self, exp):
371 self.context.Emin = exp
372 def change_max_exponent(self, exp):
373 self.context.Emax = exp
374 def change_clamp(self, clamp):
375 self.context._clamp = clamp
376
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000377
378
379# The following classes test the behaviour of Decimal according to PEP 327
380
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000381class DecimalExplicitConstructionTest(unittest.TestCase):
382 '''Unit tests for Explicit Construction cases of Decimal.'''
383
384 def test_explicit_empty(self):
385 self.assertEqual(Decimal(), Decimal("0"))
386
387 def test_explicit_from_None(self):
388 self.assertRaises(TypeError, Decimal, None)
389
390 def test_explicit_from_int(self):
391
392 #positive
393 d = Decimal(45)
394 self.assertEqual(str(d), '45')
395
396 #very large positive
397 d = Decimal(500000123)
398 self.assertEqual(str(d), '500000123')
399
400 #negative
401 d = Decimal(-45)
402 self.assertEqual(str(d), '-45')
403
404 #zero
405 d = Decimal(0)
406 self.assertEqual(str(d), '0')
407
408 def test_explicit_from_string(self):
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000409
410 #empty
411 self.assertEqual(str(Decimal('')), 'NaN')
412
413 #int
414 self.assertEqual(str(Decimal('45')), '45')
415
416 #float
417 self.assertEqual(str(Decimal('45.34')), '45.34')
418
419 #engineer notation
420 self.assertEqual(str(Decimal('45e2')), '4.5E+3')
421
422 #just not a number
423 self.assertEqual(str(Decimal('ugly')), 'NaN')
424
Christian Heimesa62da1d2008-01-12 19:39:10 +0000425 #leading and trailing whitespace permitted
426 self.assertEqual(str(Decimal('1.3E4 \n')), '1.3E+4')
427 self.assertEqual(str(Decimal(' -7.89')), '-7.89')
428
Benjamin Peterson41181742008-07-02 20:22:54 +0000429 #but alternate unicode digits should not
430 self.assertEqual(str(Decimal('\uff11')), 'NaN')
431
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000432 def test_explicit_from_tuples(self):
433
434 #zero
435 d = Decimal( (0, (0,), 0) )
436 self.assertEqual(str(d), '0')
437
438 #int
439 d = Decimal( (1, (4, 5), 0) )
440 self.assertEqual(str(d), '-45')
441
442 #float
443 d = Decimal( (0, (4, 5, 3, 4), -2) )
444 self.assertEqual(str(d), '45.34')
445
446 #weird
447 d = Decimal( (1, (4, 3, 4, 9, 1, 3, 5, 3, 4), -25) )
448 self.assertEqual(str(d), '-4.34913534E-17')
449
450 #wrong number of items
451 self.assertRaises(ValueError, Decimal, (1, (4, 3, 4, 9, 1)) )
452
453 #bad sign
454 self.assertRaises(ValueError, Decimal, (8, (4, 3, 4, 9, 1), 2) )
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000455 self.assertRaises(ValueError, Decimal, (0., (4, 3, 4, 9, 1), 2) )
456 self.assertRaises(ValueError, Decimal, (Decimal(1), (4, 3, 4, 9, 1), 2))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000457
458 #bad exp
459 self.assertRaises(ValueError, Decimal, (1, (4, 3, 4, 9, 1), 'wrong!') )
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000460 self.assertRaises(ValueError, Decimal, (1, (4, 3, 4, 9, 1), 0.) )
461 self.assertRaises(ValueError, Decimal, (1, (4, 3, 4, 9, 1), '1') )
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000462
463 #bad coefficients
464 self.assertRaises(ValueError, Decimal, (1, (4, 3, 4, None, 1), 2) )
465 self.assertRaises(ValueError, Decimal, (1, (4, -3, 4, 9, 1), 2) )
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000466 self.assertRaises(ValueError, Decimal, (1, (4, 10, 4, 9, 1), 2) )
Guido van Rossum0d3fb8a2007-11-26 23:23:18 +0000467 self.assertRaises(ValueError, Decimal, (1, (4, 3, 4, 'a', 1), 2) )
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000468
469 def test_explicit_from_Decimal(self):
470
471 #positive
472 d = Decimal(45)
473 e = Decimal(d)
474 self.assertEqual(str(e), '45')
475 self.assertNotEqual(id(d), id(e))
476
477 #very large positive
478 d = Decimal(500000123)
479 e = Decimal(d)
480 self.assertEqual(str(e), '500000123')
481 self.assertNotEqual(id(d), id(e))
482
483 #negative
484 d = Decimal(-45)
485 e = Decimal(d)
486 self.assertEqual(str(e), '-45')
487 self.assertNotEqual(id(d), id(e))
488
489 #zero
490 d = Decimal(0)
491 e = Decimal(d)
492 self.assertEqual(str(e), '0')
493 self.assertNotEqual(id(d), id(e))
494
495 def test_explicit_context_create_decimal(self):
496
497 nc = copy.copy(getcontext())
498 nc.prec = 3
499
500 # empty
Raymond Hettingerfed52962004-07-14 15:41:57 +0000501 d = Decimal()
502 self.assertEqual(str(d), '0')
503 d = nc.create_decimal()
504 self.assertEqual(str(d), '0')
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000505
506 # from None
507 self.assertRaises(TypeError, nc.create_decimal, None)
508
509 # from int
510 d = nc.create_decimal(456)
511 self.failUnless(isinstance(d, Decimal))
512 self.assertEqual(nc.create_decimal(45678),
513 nc.create_decimal('457E+2'))
514
515 # from string
516 d = Decimal('456789')
517 self.assertEqual(str(d), '456789')
518 d = nc.create_decimal('456789')
519 self.assertEqual(str(d), '4.57E+5')
Christian Heimesa62da1d2008-01-12 19:39:10 +0000520 # leading and trailing whitespace should result in a NaN;
521 # spaces are already checked in Cowlishaw's test-suite, so
522 # here we just check that a trailing newline results in a NaN
523 self.assertEqual(str(nc.create_decimal('3.14\n')), 'NaN')
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000524
525 # from tuples
526 d = Decimal( (1, (4, 3, 4, 9, 1, 3, 5, 3, 4), -25) )
527 self.assertEqual(str(d), '-4.34913534E-17')
528 d = nc.create_decimal( (1, (4, 3, 4, 9, 1, 3, 5, 3, 4), -25) )
529 self.assertEqual(str(d), '-4.35E-17')
530
531 # from Decimal
532 prevdec = Decimal(500000123)
533 d = Decimal(prevdec)
534 self.assertEqual(str(d), '500000123')
535 d = nc.create_decimal(prevdec)
536 self.assertEqual(str(d), '5.00E+8')
537
538
539class DecimalImplicitConstructionTest(unittest.TestCase):
540 '''Unit tests for Implicit Construction cases of Decimal.'''
541
542 def test_implicit_from_None(self):
543 self.assertRaises(TypeError, eval, 'Decimal(5) + None', globals())
544
545 def test_implicit_from_int(self):
546 #normal
547 self.assertEqual(str(Decimal(5) + 45), '50')
548 #exceeding precision
549 self.assertEqual(Decimal(5) + 123456789000, Decimal(123456789000))
550
551 def test_implicit_from_string(self):
552 self.assertRaises(TypeError, eval, 'Decimal(5) + "3"', globals())
553
554 def test_implicit_from_float(self):
555 self.assertRaises(TypeError, eval, 'Decimal(5) + 2.2', globals())
556
557 def test_implicit_from_Decimal(self):
558 self.assertEqual(Decimal(5) + Decimal(45), Decimal(50))
559
Raymond Hettinger267b8682005-03-27 10:47:39 +0000560 def test_rop(self):
561 # Allow other classes to be trained to interact with Decimals
562 class E:
563 def __divmod__(self, other):
564 return 'divmod ' + str(other)
565 def __rdivmod__(self, other):
566 return str(other) + ' rdivmod'
567 def __lt__(self, other):
568 return 'lt ' + str(other)
569 def __gt__(self, other):
570 return 'gt ' + str(other)
571 def __le__(self, other):
572 return 'le ' + str(other)
573 def __ge__(self, other):
574 return 'ge ' + str(other)
575 def __eq__(self, other):
576 return 'eq ' + str(other)
577 def __ne__(self, other):
578 return 'ne ' + str(other)
579
580 self.assertEqual(divmod(E(), Decimal(10)), 'divmod 10')
581 self.assertEqual(divmod(Decimal(10), E()), '10 rdivmod')
582 self.assertEqual(eval('Decimal(10) < E()'), 'gt 10')
583 self.assertEqual(eval('Decimal(10) > E()'), 'lt 10')
584 self.assertEqual(eval('Decimal(10) <= E()'), 'ge 10')
585 self.assertEqual(eval('Decimal(10) >= E()'), 'le 10')
586 self.assertEqual(eval('Decimal(10) == E()'), 'eq 10')
587 self.assertEqual(eval('Decimal(10) != E()'), 'ne 10')
588
589 # insert operator methods and then exercise them
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000590 oplist = [
591 ('+', '__add__', '__radd__'),
592 ('-', '__sub__', '__rsub__'),
593 ('*', '__mul__', '__rmul__'),
Thomas Woutersdcc6d322006-04-21 11:30:52 +0000594 ('/', '__truediv__', '__rtruediv__'),
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000595 ('%', '__mod__', '__rmod__'),
596 ('//', '__floordiv__', '__rfloordiv__'),
597 ('**', '__pow__', '__rpow__')
598 ]
Raymond Hettinger267b8682005-03-27 10:47:39 +0000599
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000600 for sym, lop, rop in oplist:
Raymond Hettinger267b8682005-03-27 10:47:39 +0000601 setattr(E, lop, lambda self, other: 'str' + lop + str(other))
602 setattr(E, rop, lambda self, other: str(other) + rop + 'str')
603 self.assertEqual(eval('E()' + sym + 'Decimal(10)'),
604 'str' + lop + '10')
605 self.assertEqual(eval('Decimal(10)' + sym + 'E()'),
606 '10' + rop + 'str')
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000607
Mark Dickinson79f52032009-03-17 23:12:51 +0000608
Christian Heimesf16baeb2008-02-29 14:57:44 +0000609class DecimalFormatTest(unittest.TestCase):
610 '''Unit tests for the format function.'''
611 def test_formatting(self):
612 # triples giving a format, a Decimal, and the expected result
613 test_values = [
614 ('e', '0E-15', '0e-15'),
615 ('e', '2.3E-15', '2.3e-15'),
616 ('e', '2.30E+2', '2.30e+2'), # preserve significant zeros
617 ('e', '2.30000E-15', '2.30000e-15'),
618 ('e', '1.23456789123456789e40', '1.23456789123456789e+40'),
619 ('e', '1.5', '1.5e+0'),
620 ('e', '0.15', '1.5e-1'),
621 ('e', '0.015', '1.5e-2'),
622 ('e', '0.0000000000015', '1.5e-12'),
623 ('e', '15.0', '1.50e+1'),
624 ('e', '-15', '-1.5e+1'),
625 ('e', '0', '0e+0'),
626 ('e', '0E1', '0e+1'),
627 ('e', '0.0', '0e-1'),
628 ('e', '0.00', '0e-2'),
629 ('.6e', '0E-15', '0.000000e-9'),
630 ('.6e', '0', '0.000000e+6'),
631 ('.6e', '9.999999', '9.999999e+0'),
632 ('.6e', '9.9999999', '1.000000e+1'),
633 ('.6e', '-1.23e5', '-1.230000e+5'),
634 ('.6e', '1.23456789e-3', '1.234568e-3'),
635 ('f', '0', '0'),
636 ('f', '0.0', '0.0'),
637 ('f', '0E-2', '0.00'),
638 ('f', '0.00E-8', '0.0000000000'),
639 ('f', '0E1', '0'), # loses exponent information
640 ('f', '3.2E1', '32'),
641 ('f', '3.2E2', '320'),
642 ('f', '3.20E2', '320'),
643 ('f', '3.200E2', '320.0'),
644 ('f', '3.2E-6', '0.0000032'),
645 ('.6f', '0E-15', '0.000000'), # all zeros treated equally
646 ('.6f', '0E1', '0.000000'),
647 ('.6f', '0', '0.000000'),
648 ('.0f', '0', '0'), # no decimal point
649 ('.0f', '0e-2', '0'),
650 ('.0f', '3.14159265', '3'),
651 ('.1f', '3.14159265', '3.1'),
652 ('.4f', '3.14159265', '3.1416'),
653 ('.6f', '3.14159265', '3.141593'),
654 ('.7f', '3.14159265', '3.1415926'), # round-half-even!
655 ('.8f', '3.14159265', '3.14159265'),
656 ('.9f', '3.14159265', '3.141592650'),
657
658 ('g', '0', '0'),
659 ('g', '0.0', '0.0'),
660 ('g', '0E1', '0e+1'),
661 ('G', '0E1', '0E+1'),
662 ('g', '0E-5', '0.00000'),
663 ('g', '0E-6', '0.000000'),
664 ('g', '0E-7', '0e-7'),
665 ('g', '-0E2', '-0e+2'),
666 ('.0g', '3.14159265', '3'), # 0 sig fig -> 1 sig fig
667 ('.1g', '3.14159265', '3'),
668 ('.2g', '3.14159265', '3.1'),
669 ('.5g', '3.14159265', '3.1416'),
670 ('.7g', '3.14159265', '3.141593'),
671 ('.8g', '3.14159265', '3.1415926'), # round-half-even!
672 ('.9g', '3.14159265', '3.14159265'),
673 ('.10g', '3.14159265', '3.14159265'), # don't pad
674
675 ('%', '0E1', '0%'),
676 ('%', '0E0', '0%'),
677 ('%', '0E-1', '0%'),
678 ('%', '0E-2', '0%'),
679 ('%', '0E-3', '0.0%'),
680 ('%', '0E-4', '0.00%'),
681
682 ('.3%', '0', '0.000%'), # all zeros treated equally
683 ('.3%', '0E10', '0.000%'),
684 ('.3%', '0E-10', '0.000%'),
685 ('.3%', '2.34', '234.000%'),
686 ('.3%', '1.234567', '123.457%'),
687 ('.0%', '1.23', '123%'),
688
689 ('e', 'NaN', 'NaN'),
690 ('f', '-NaN123', '-NaN123'),
691 ('+g', 'NaN456', '+NaN456'),
692 ('.3e', 'Inf', 'Infinity'),
693 ('.16f', '-Inf', '-Infinity'),
694 ('.0g', '-sNaN', '-sNaN'),
695
696 ('', '1.00', '1.00'),
Mark Dickinsonad416342009-03-17 18:10:15 +0000697
Mark Dickinson79f52032009-03-17 23:12:51 +0000698 # test alignment and padding
Mark Dickinsonad416342009-03-17 18:10:15 +0000699 ('<6', '123', '123 '),
700 ('>6', '123', ' 123'),
701 ('^6', '123', ' 123 '),
702 ('=+6', '123', '+ 123'),
Mark Dickinson79f52032009-03-17 23:12:51 +0000703 ('#<10', 'NaN', 'NaN#######'),
704 ('#<10', '-4.3', '-4.3######'),
705 ('#<+10', '0.0130', '+0.0130###'),
706 ('#< 10', '0.0130', ' 0.0130###'),
707 ('@>10', '-Inf', '@-Infinity'),
708 ('#>5', '-Inf', '-Infinity'),
709 ('?^5', '123', '?123?'),
710 ('%^6', '123', '%123%%'),
711 (' ^6', '-45.6', '-45.6 '),
712 ('/=10', '-45.6', '-/////45.6'),
713 ('/=+10', '45.6', '+/////45.6'),
714 ('/= 10', '45.6', ' /////45.6'),
715
716 # thousands separator
717 (',', '1234567', '1,234,567'),
718 (',', '123456', '123,456'),
719 (',', '12345', '12,345'),
720 (',', '1234', '1,234'),
721 (',', '123', '123'),
722 (',', '12', '12'),
723 (',', '1', '1'),
724 (',', '0', '0'),
725 (',', '-1234567', '-1,234,567'),
726 (',', '-123456', '-123,456'),
727 ('7,', '123456', '123,456'),
728 ('8,', '123456', '123,456 '),
729 ('08,', '123456', '0,123,456'), # special case: extra 0 needed
730 ('+08,', '123456', '+123,456'), # but not if there's a sign
731 (' 08,', '123456', ' 123,456'),
732 ('08,', '-123456', '-123,456'),
733 ('+09,', '123456', '+0,123,456'),
734 # ... with fractional part...
735 ('07,', '1234.56', '1,234.56'),
736 ('08,', '1234.56', '1,234.56'),
737 ('09,', '1234.56', '01,234.56'),
738 ('010,', '1234.56', '001,234.56'),
739 ('011,', '1234.56', '0,001,234.56'),
740 ('012,', '1234.56', '0,001,234.56'),
741 ('08,.1f', '1234.5', '01,234.5'),
742 # no thousands separators in fraction part
743 (',', '1.23456789', '1.23456789'),
744 (',%', '123.456789', '12,345.6789%'),
745 (',e', '123456', '1.23456e+5'),
746 (',E', '123456', '1.23456E+5'),
Christian Heimesf16baeb2008-02-29 14:57:44 +0000747 ]
748 for fmt, d, result in test_values:
749 self.assertEqual(format(Decimal(d), fmt), result)
750
Mark Dickinson79f52032009-03-17 23:12:51 +0000751 def test_n_format(self):
752 try:
753 from locale import CHAR_MAX
754 except ImportError:
755 return
756
757 # Set up some localeconv-like dictionaries
758 en_US = {
759 'decimal_point' : '.',
760 'grouping' : [3, 3, 0],
761 'thousands_sep': ','
762 }
763
764 fr_FR = {
765 'decimal_point' : ',',
766 'grouping' : [CHAR_MAX],
767 'thousands_sep' : ''
768 }
769
770 ru_RU = {
771 'decimal_point' : ',',
772 'grouping' : [3, 3, 0],
773 'thousands_sep' : ' '
774 }
775
776 crazy = {
777 'decimal_point' : '&',
778 'grouping' : [1, 4, 2, CHAR_MAX],
779 'thousands_sep' : '-'
780 }
781
782
783 def get_fmt(x, locale, fmt='n'):
784 return Decimal.__format__(Decimal(x), fmt, _localeconv=locale)
785
786 self.assertEqual(get_fmt(Decimal('12.7'), en_US), '12.7')
787 self.assertEqual(get_fmt(Decimal('12.7'), fr_FR), '12,7')
788 self.assertEqual(get_fmt(Decimal('12.7'), ru_RU), '12,7')
789 self.assertEqual(get_fmt(Decimal('12.7'), crazy), '1-2&7')
790
791 self.assertEqual(get_fmt(123456789, en_US), '123,456,789')
792 self.assertEqual(get_fmt(123456789, fr_FR), '123456789')
793 self.assertEqual(get_fmt(123456789, ru_RU), '123 456 789')
794 self.assertEqual(get_fmt(1234567890123, crazy), '123456-78-9012-3')
795
796 self.assertEqual(get_fmt(123456789, en_US, '.6n'), '1.23457e+8')
797 self.assertEqual(get_fmt(123456789, fr_FR, '.6n'), '1,23457e+8')
798 self.assertEqual(get_fmt(123456789, ru_RU, '.6n'), '1,23457e+8')
799 self.assertEqual(get_fmt(123456789, crazy, '.6n'), '1&23457e+8')
800
Mark Dickinson7303b592009-03-18 08:25:36 +0000801 # zero padding
802 self.assertEqual(get_fmt(1234, fr_FR, '03n'), '1234')
803 self.assertEqual(get_fmt(1234, fr_FR, '04n'), '1234')
804 self.assertEqual(get_fmt(1234, fr_FR, '05n'), '01234')
805 self.assertEqual(get_fmt(1234, fr_FR, '06n'), '001234')
806
807 self.assertEqual(get_fmt(12345, en_US, '05n'), '12,345')
808 self.assertEqual(get_fmt(12345, en_US, '06n'), '12,345')
809 self.assertEqual(get_fmt(12345, en_US, '07n'), '012,345')
810 self.assertEqual(get_fmt(12345, en_US, '08n'), '0,012,345')
811 self.assertEqual(get_fmt(12345, en_US, '09n'), '0,012,345')
812 self.assertEqual(get_fmt(12345, en_US, '010n'), '00,012,345')
813
814 self.assertEqual(get_fmt(123456, crazy, '06n'), '1-2345-6')
815 self.assertEqual(get_fmt(123456, crazy, '07n'), '1-2345-6')
816 self.assertEqual(get_fmt(123456, crazy, '08n'), '1-2345-6')
817 self.assertEqual(get_fmt(123456, crazy, '09n'), '01-2345-6')
818 self.assertEqual(get_fmt(123456, crazy, '010n'), '0-01-2345-6')
819 self.assertEqual(get_fmt(123456, crazy, '011n'), '0-01-2345-6')
820 self.assertEqual(get_fmt(123456, crazy, '012n'), '00-01-2345-6')
821 self.assertEqual(get_fmt(123456, crazy, '013n'), '000-01-2345-6')
822
Mark Dickinson79f52032009-03-17 23:12:51 +0000823
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000824class DecimalArithmeticOperatorsTest(unittest.TestCase):
825 '''Unit tests for all arithmetic operators, binary and unary.'''
826
827 def test_addition(self):
828
829 d1 = Decimal('-11.1')
830 d2 = Decimal('22.2')
831
832 #two Decimals
833 self.assertEqual(d1+d2, Decimal('11.1'))
834 self.assertEqual(d2+d1, Decimal('11.1'))
835
836 #with other type, left
837 c = d1 + 5
838 self.assertEqual(c, Decimal('-6.1'))
839 self.assertEqual(type(c), type(d1))
840
841 #with other type, right
842 c = 5 + d1
843 self.assertEqual(c, Decimal('-6.1'))
844 self.assertEqual(type(c), type(d1))
845
846 #inline with decimal
847 d1 += d2
848 self.assertEqual(d1, Decimal('11.1'))
849
850 #inline with other type
851 d1 += 5
852 self.assertEqual(d1, Decimal('16.1'))
853
854 def test_subtraction(self):
855
856 d1 = Decimal('-11.1')
857 d2 = Decimal('22.2')
858
859 #two Decimals
860 self.assertEqual(d1-d2, Decimal('-33.3'))
861 self.assertEqual(d2-d1, Decimal('33.3'))
862
863 #with other type, left
864 c = d1 - 5
865 self.assertEqual(c, Decimal('-16.1'))
866 self.assertEqual(type(c), type(d1))
867
868 #with other type, right
869 c = 5 - d1
870 self.assertEqual(c, Decimal('16.1'))
871 self.assertEqual(type(c), type(d1))
872
873 #inline with decimal
874 d1 -= d2
875 self.assertEqual(d1, Decimal('-33.3'))
876
877 #inline with other type
878 d1 -= 5
879 self.assertEqual(d1, Decimal('-38.3'))
880
881 def test_multiplication(self):
882
883 d1 = Decimal('-5')
884 d2 = Decimal('3')
885
886 #two Decimals
887 self.assertEqual(d1*d2, Decimal('-15'))
888 self.assertEqual(d2*d1, Decimal('-15'))
889
890 #with other type, left
891 c = d1 * 5
892 self.assertEqual(c, Decimal('-25'))
893 self.assertEqual(type(c), type(d1))
894
895 #with other type, right
896 c = 5 * d1
897 self.assertEqual(c, Decimal('-25'))
898 self.assertEqual(type(c), type(d1))
899
900 #inline with decimal
901 d1 *= d2
902 self.assertEqual(d1, Decimal('-15'))
903
904 #inline with other type
905 d1 *= 5
906 self.assertEqual(d1, Decimal('-75'))
907
908 def test_division(self):
909
910 d1 = Decimal('-5')
911 d2 = Decimal('2')
912
913 #two Decimals
914 self.assertEqual(d1/d2, Decimal('-2.5'))
915 self.assertEqual(d2/d1, Decimal('-0.4'))
916
917 #with other type, left
918 c = d1 / 4
919 self.assertEqual(c, Decimal('-1.25'))
920 self.assertEqual(type(c), type(d1))
921
922 #with other type, right
923 c = 4 / d1
924 self.assertEqual(c, Decimal('-0.8'))
925 self.assertEqual(type(c), type(d1))
926
927 #inline with decimal
928 d1 /= d2
929 self.assertEqual(d1, Decimal('-2.5'))
930
931 #inline with other type
932 d1 /= 4
933 self.assertEqual(d1, Decimal('-0.625'))
934
935 def test_floor_division(self):
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000936
937 d1 = Decimal('5')
938 d2 = Decimal('2')
939
940 #two Decimals
941 self.assertEqual(d1//d2, Decimal('2'))
942 self.assertEqual(d2//d1, Decimal('0'))
943
944 #with other type, left
945 c = d1 // 4
946 self.assertEqual(c, Decimal('1'))
947 self.assertEqual(type(c), type(d1))
948
949 #with other type, right
950 c = 7 // d1
951 self.assertEqual(c, Decimal('1'))
952 self.assertEqual(type(c), type(d1))
953
954 #inline with decimal
955 d1 //= d2
956 self.assertEqual(d1, Decimal('2'))
957
958 #inline with other type
959 d1 //= 2
960 self.assertEqual(d1, Decimal('1'))
961
962 def test_powering(self):
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000963
964 d1 = Decimal('5')
965 d2 = Decimal('2')
966
967 #two Decimals
968 self.assertEqual(d1**d2, Decimal('25'))
969 self.assertEqual(d2**d1, Decimal('32'))
970
971 #with other type, left
972 c = d1 ** 4
973 self.assertEqual(c, Decimal('625'))
974 self.assertEqual(type(c), type(d1))
975
976 #with other type, right
977 c = 7 ** d1
978 self.assertEqual(c, Decimal('16807'))
979 self.assertEqual(type(c), type(d1))
980
981 #inline with decimal
982 d1 **= d2
983 self.assertEqual(d1, Decimal('25'))
984
985 #inline with other type
986 d1 **= 4
987 self.assertEqual(d1, Decimal('390625'))
988
989 def test_module(self):
990
991 d1 = Decimal('5')
992 d2 = Decimal('2')
993
994 #two Decimals
995 self.assertEqual(d1%d2, Decimal('1'))
996 self.assertEqual(d2%d1, Decimal('2'))
997
998 #with other type, left
999 c = d1 % 4
1000 self.assertEqual(c, Decimal('1'))
1001 self.assertEqual(type(c), type(d1))
1002
1003 #with other type, right
1004 c = 7 % d1
1005 self.assertEqual(c, Decimal('2'))
1006 self.assertEqual(type(c), type(d1))
1007
1008 #inline with decimal
1009 d1 %= d2
1010 self.assertEqual(d1, Decimal('1'))
1011
1012 #inline with other type
1013 d1 %= 4
1014 self.assertEqual(d1, Decimal('1'))
1015
1016 def test_floor_div_module(self):
1017
1018 d1 = Decimal('5')
1019 d2 = Decimal('2')
1020
1021 #two Decimals
1022 (p, q) = divmod(d1, d2)
1023 self.assertEqual(p, Decimal('2'))
1024 self.assertEqual(q, Decimal('1'))
1025 self.assertEqual(type(p), type(d1))
1026 self.assertEqual(type(q), type(d1))
1027
1028 #with other type, left
1029 (p, q) = divmod(d1, 4)
1030 self.assertEqual(p, Decimal('1'))
1031 self.assertEqual(q, Decimal('1'))
1032 self.assertEqual(type(p), type(d1))
1033 self.assertEqual(type(q), type(d1))
1034
1035 #with other type, right
1036 (p, q) = divmod(7, d1)
1037 self.assertEqual(p, Decimal('1'))
1038 self.assertEqual(q, Decimal('2'))
1039 self.assertEqual(type(p), type(d1))
1040 self.assertEqual(type(q), type(d1))
1041
1042 def test_unary_operators(self):
1043 self.assertEqual(+Decimal(45), Decimal(+45)) # +
1044 self.assertEqual(-Decimal(45), Decimal(-45)) # -
1045 self.assertEqual(abs(Decimal(45)), abs(Decimal(-45))) # abs
1046
Christian Heimes77c02eb2008-02-09 02:18:51 +00001047 def test_nan_comparisons(self):
1048 n = Decimal('NaN')
1049 s = Decimal('sNaN')
1050 i = Decimal('Inf')
1051 f = Decimal('2')
1052 for x, y in [(n, n), (n, i), (i, n), (n, f), (f, n),
1053 (s, n), (n, s), (s, i), (i, s), (s, f), (f, s), (s, s)]:
1054 self.assert_(x != y)
1055 self.assert_(not (x == y))
1056 self.assert_(not (x < y))
1057 self.assert_(not (x <= y))
1058 self.assert_(not (x > y))
1059 self.assert_(not (x >= y))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001060
1061# The following are two functions used to test threading in the next class
1062
1063def thfunc1(cls):
1064 d1 = Decimal(1)
1065 d3 = Decimal(3)
Christian Heimesfe337bf2008-03-23 21:54:12 +00001066 test1 = d1/d3
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001067 cls.synchro.wait()
Christian Heimesfe337bf2008-03-23 21:54:12 +00001068 test2 = d1/d3
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001069 cls.finish1.set()
Christian Heimesfe337bf2008-03-23 21:54:12 +00001070
Christian Heimes81ee3ef2008-05-04 22:42:01 +00001071 cls.assertEqual(test1, Decimal('0.3333333333333333333333333333'))
1072 cls.assertEqual(test2, Decimal('0.3333333333333333333333333333'))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001073 return
1074
1075def thfunc2(cls):
1076 d1 = Decimal(1)
1077 d3 = Decimal(3)
Christian Heimesfe337bf2008-03-23 21:54:12 +00001078 test1 = d1/d3
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001079 thiscontext = getcontext()
1080 thiscontext.prec = 18
Christian Heimesfe337bf2008-03-23 21:54:12 +00001081 test2 = d1/d3
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001082 cls.synchro.set()
1083 cls.finish2.set()
Christian Heimesfe337bf2008-03-23 21:54:12 +00001084
Christian Heimes81ee3ef2008-05-04 22:42:01 +00001085 cls.assertEqual(test1, Decimal('0.3333333333333333333333333333'))
Christian Heimesfe337bf2008-03-23 21:54:12 +00001086 cls.assertEqual(test2, Decimal('0.333333333333333333'))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001087 return
1088
1089
1090class DecimalUseOfContextTest(unittest.TestCase):
1091 '''Unit tests for Use of Context cases in Decimal.'''
1092
Raymond Hettinger7e71fa52004-12-18 19:07:19 +00001093 try:
1094 import threading
1095 except ImportError:
1096 threading = None
1097
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001098 # Take care executing this test from IDLE, there's an issue in threading
1099 # that hangs IDLE and I couldn't find it
1100
1101 def test_threading(self):
1102 #Test the "threading isolation" of a Context.
1103
1104 self.synchro = threading.Event()
1105 self.finish1 = threading.Event()
1106 self.finish2 = threading.Event()
1107
1108 th1 = threading.Thread(target=thfunc1, args=(self,))
1109 th2 = threading.Thread(target=thfunc2, args=(self,))
1110
1111 th1.start()
1112 th2.start()
1113
1114 self.finish1.wait()
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001115 self.finish2.wait()
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001116 return
1117
Raymond Hettinger7e71fa52004-12-18 19:07:19 +00001118 if threading is None:
1119 del test_threading
1120
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001121
1122class DecimalUsabilityTest(unittest.TestCase):
1123 '''Unit tests for Usability cases of Decimal.'''
1124
1125 def test_comparison_operators(self):
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001126
1127 da = Decimal('23.42')
1128 db = Decimal('23.42')
1129 dc = Decimal('45')
1130
1131 #two Decimals
1132 self.failUnless(dc > da)
1133 self.failUnless(dc >= da)
1134 self.failUnless(da < dc)
1135 self.failUnless(da <= dc)
Guido van Rossume61fd5b2007-07-11 12:20:59 +00001136 self.assertEqual(da, db)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001137 self.failUnless(da != dc)
1138 self.failUnless(da <= db)
1139 self.failUnless(da >= db)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001140
1141 #a Decimal and an int
1142 self.failUnless(dc > 23)
1143 self.failUnless(23 < dc)
Guido van Rossume61fd5b2007-07-11 12:20:59 +00001144 self.assertEqual(dc, 45)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001145
1146 #a Decimal and uncomparable
Raymond Hettinger0aeac102004-07-05 22:53:03 +00001147 self.assertNotEqual(da, 'ugly')
1148 self.assertNotEqual(da, 32.7)
1149 self.assertNotEqual(da, object())
1150 self.assertNotEqual(da, object)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001151
Raymond Hettinger0aeac102004-07-05 22:53:03 +00001152 # sortable
Guido van Rossumc1f779c2007-07-03 08:25:58 +00001153 a = list(map(Decimal, range(100)))
Raymond Hettinger0aeac102004-07-05 22:53:03 +00001154 b = a[:]
1155 random.shuffle(a)
1156 a.sort()
1157 self.assertEqual(a, b)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001158
1159 def test_copy_and_deepcopy_methods(self):
1160 d = Decimal('43.24')
1161 c = copy.copy(d)
1162 self.assertEqual(id(c), id(d))
1163 dc = copy.deepcopy(d)
1164 self.assertEqual(id(dc), id(d))
1165
1166 def test_hash_method(self):
1167 #just that it's hashable
1168 hash(Decimal(23))
Thomas Wouters8ce81f72007-09-20 18:22:40 +00001169
1170 test_values = [Decimal(sign*(2**m + n))
1171 for m in [0, 14, 15, 16, 17, 30, 31,
1172 32, 33, 62, 63, 64, 65, 66]
1173 for n in range(-10, 10)
1174 for sign in [-1, 1]]
1175 test_values.extend([
1176 Decimal("-0"), # zeros
1177 Decimal("0.00"),
1178 Decimal("-0.000"),
1179 Decimal("0E10"),
1180 Decimal("-0E12"),
1181 Decimal("10.0"), # negative exponent
1182 Decimal("-23.00000"),
1183 Decimal("1230E100"), # positive exponent
1184 Decimal("-4.5678E50"),
1185 # a value for which hash(n) != hash(n % (2**64-1))
1186 # in Python pre-2.6
1187 Decimal(2**64 + 2**32 - 1),
1188 # selection of values which fail with the old (before
1189 # version 2.6) long.__hash__
1190 Decimal("1.634E100"),
1191 Decimal("90.697E100"),
1192 Decimal("188.83E100"),
1193 Decimal("1652.9E100"),
1194 Decimal("56531E100"),
1195 ])
1196
1197 # check that hash(d) == hash(int(d)) for integral values
1198 for value in test_values:
1199 self.assertEqual(hash(value), hash(int(value)))
1200
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001201 #the same hash that to an int
1202 self.assertEqual(hash(Decimal(23)), hash(23))
Raymond Hettingerbea3f6f2005-03-15 04:59:17 +00001203 self.assertRaises(TypeError, hash, Decimal('NaN'))
1204 self.assert_(hash(Decimal('Inf')))
1205 self.assert_(hash(Decimal('-Inf')))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001206
Christian Heimes2380ac72008-01-09 00:17:24 +00001207 # check that the value of the hash doesn't depend on the
1208 # current context (issue #1757)
1209 c = getcontext()
1210 old_precision = c.prec
1211 x = Decimal("123456789.1")
1212
1213 c.prec = 6
1214 h1 = hash(x)
1215 c.prec = 10
1216 h2 = hash(x)
1217 c.prec = 16
1218 h3 = hash(x)
1219
1220 self.assertEqual(h1, h2)
1221 self.assertEqual(h1, h3)
1222 c.prec = old_precision
1223
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001224 def test_min_and_max_methods(self):
1225
1226 d1 = Decimal('15.32')
1227 d2 = Decimal('28.5')
1228 l1 = 15
1229 l2 = 28
1230
1231 #between Decimals
1232 self.failUnless(min(d1,d2) is d1)
1233 self.failUnless(min(d2,d1) is d1)
1234 self.failUnless(max(d1,d2) is d2)
1235 self.failUnless(max(d2,d1) is d2)
1236
1237 #between Decimal and long
1238 self.failUnless(min(d1,l2) is d1)
1239 self.failUnless(min(l2,d1) is d1)
1240 self.failUnless(max(l1,d2) is d2)
1241 self.failUnless(max(d2,l1) is d2)
1242
1243 def test_as_nonzero(self):
1244 #as false
1245 self.failIf(Decimal(0))
1246 #as true
1247 self.failUnless(Decimal('0.372'))
1248
1249 def test_tostring_methods(self):
1250 #Test str and repr methods.
1251
1252 d = Decimal('15.32')
1253 self.assertEqual(str(d), '15.32') # str
Christian Heimes68f5fbe2008-02-14 08:27:37 +00001254 self.assertEqual(repr(d), "Decimal('15.32')") # repr
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001255
1256 def test_tonum_methods(self):
1257 #Test float, int and long methods.
1258
1259 d1 = Decimal('66')
1260 d2 = Decimal('15.32')
1261
1262 #int
1263 self.assertEqual(int(d1), 66)
1264 self.assertEqual(int(d2), 15)
1265
1266 #long
Guido van Rossume2a383d2007-01-15 16:59:06 +00001267 self.assertEqual(int(d1), 66)
1268 self.assertEqual(int(d2), 15)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001269
1270 #float
1271 self.assertEqual(float(d1), 66)
1272 self.assertEqual(float(d2), 15.32)
1273
Mark Dickinsonb27406c2008-05-09 13:42:33 +00001274 #floor
1275 test_pairs = [
1276 ('123.00', 123),
1277 ('3.2', 3),
1278 ('3.54', 3),
1279 ('3.899', 3),
1280 ('-2.3', -3),
1281 ('-11.0', -11),
1282 ('0.0', 0),
1283 ('-0E3', 0),
1284 ]
1285 for d, i in test_pairs:
1286 self.assertEqual(math.floor(Decimal(d)), i)
1287 self.assertRaises(ValueError, math.floor, Decimal('-NaN'))
1288 self.assertRaises(ValueError, math.floor, Decimal('sNaN'))
1289 self.assertRaises(ValueError, math.floor, Decimal('NaN123'))
1290 self.assertRaises(OverflowError, math.floor, Decimal('Inf'))
1291 self.assertRaises(OverflowError, math.floor, Decimal('-Inf'))
1292
1293 #ceiling
1294 test_pairs = [
1295 ('123.00', 123),
1296 ('3.2', 4),
1297 ('3.54', 4),
1298 ('3.899', 4),
1299 ('-2.3', -2),
1300 ('-11.0', -11),
1301 ('0.0', 0),
1302 ('-0E3', 0),
1303 ]
1304 for d, i in test_pairs:
1305 self.assertEqual(math.ceil(Decimal(d)), i)
1306 self.assertRaises(ValueError, math.ceil, Decimal('-NaN'))
1307 self.assertRaises(ValueError, math.ceil, Decimal('sNaN'))
1308 self.assertRaises(ValueError, math.ceil, Decimal('NaN123'))
1309 self.assertRaises(OverflowError, math.ceil, Decimal('Inf'))
1310 self.assertRaises(OverflowError, math.ceil, Decimal('-Inf'))
1311
1312 #round, single argument
1313 test_pairs = [
1314 ('123.00', 123),
1315 ('3.2', 3),
1316 ('3.54', 4),
1317 ('3.899', 4),
1318 ('-2.3', -2),
1319 ('-11.0', -11),
1320 ('0.0', 0),
1321 ('-0E3', 0),
1322 ('-3.5', -4),
1323 ('-2.5', -2),
1324 ('-1.5', -2),
1325 ('-0.5', 0),
1326 ('0.5', 0),
1327 ('1.5', 2),
1328 ('2.5', 2),
1329 ('3.5', 4),
1330 ]
1331 for d, i in test_pairs:
1332 self.assertEqual(round(Decimal(d)), i)
1333 self.assertRaises(ValueError, round, Decimal('-NaN'))
1334 self.assertRaises(ValueError, round, Decimal('sNaN'))
1335 self.assertRaises(ValueError, round, Decimal('NaN123'))
1336 self.assertRaises(OverflowError, round, Decimal('Inf'))
1337 self.assertRaises(OverflowError, round, Decimal('-Inf'))
1338
1339 #round, two arguments; this is essentially equivalent
1340 #to quantize, which is already extensively tested
1341 test_triples = [
1342 ('123.456', -4, '0E+4'),
1343 ('123.456', -3, '0E+3'),
1344 ('123.456', -2, '1E+2'),
1345 ('123.456', -1, '1.2E+2'),
1346 ('123.456', 0, '123'),
1347 ('123.456', 1, '123.5'),
1348 ('123.456', 2, '123.46'),
1349 ('123.456', 3, '123.456'),
1350 ('123.456', 4, '123.4560'),
1351 ('123.455', 2, '123.46'),
1352 ('123.445', 2, '123.44'),
1353 ('Inf', 4, 'NaN'),
1354 ('-Inf', -23, 'NaN'),
1355 ('sNaN314', 3, 'NaN314'),
1356 ]
1357 for d, n, r in test_triples:
1358 self.assertEqual(str(round(Decimal(d), n)), r)
1359
1360
1361
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001362 def test_eval_round_trip(self):
1363
1364 #with zero
1365 d = Decimal( (0, (0,), 0) )
1366 self.assertEqual(d, eval(repr(d)))
1367
1368 #int
1369 d = Decimal( (1, (4, 5), 0) )
1370 self.assertEqual(d, eval(repr(d)))
1371
1372 #float
1373 d = Decimal( (0, (4, 5, 3, 4), -2) )
1374 self.assertEqual(d, eval(repr(d)))
1375
1376 #weird
1377 d = Decimal( (1, (4, 3, 4, 9, 1, 3, 5, 3, 4), -25) )
1378 self.assertEqual(d, eval(repr(d)))
1379
1380 def test_as_tuple(self):
1381
1382 #with zero
1383 d = Decimal(0)
1384 self.assertEqual(d.as_tuple(), (0, (0,), 0) )
1385
1386 #int
1387 d = Decimal(-45)
1388 self.assertEqual(d.as_tuple(), (1, (4, 5), 0) )
1389
1390 #complicated string
1391 d = Decimal("-4.34913534E-17")
1392 self.assertEqual(d.as_tuple(), (1, (4, 3, 4, 9, 1, 3, 5, 3, 4), -25) )
1393
1394 #inf
1395 d = Decimal("Infinity")
1396 self.assertEqual(d.as_tuple(), (0, (0,), 'F') )
1397
Guido van Rossum8ce8a782007-11-01 19:42:39 +00001398 #leading zeros in coefficient should be stripped
1399 d = Decimal( (0, (0, 0, 4, 0, 5, 3, 4), -2) )
1400 self.assertEqual(d.as_tuple(), (0, (4, 0, 5, 3, 4), -2) )
1401 d = Decimal( (1, (0, 0, 0), 37) )
1402 self.assertEqual(d.as_tuple(), (1, (0,), 37))
1403 d = Decimal( (1, (), 37) )
1404 self.assertEqual(d.as_tuple(), (1, (0,), 37))
1405
1406 #leading zeros in NaN diagnostic info should be stripped
1407 d = Decimal( (0, (0, 0, 4, 0, 5, 3, 4), 'n') )
1408 self.assertEqual(d.as_tuple(), (0, (4, 0, 5, 3, 4), 'n') )
1409 d = Decimal( (1, (0, 0, 0), 'N') )
1410 self.assertEqual(d.as_tuple(), (1, (), 'N') )
1411 d = Decimal( (1, (), 'n') )
1412 self.assertEqual(d.as_tuple(), (1, (), 'n') )
1413
1414 #coefficient in infinity should be ignored
1415 d = Decimal( (0, (4, 5, 3, 4), 'F') )
1416 self.assertEqual(d.as_tuple(), (0, (0,), 'F'))
1417 d = Decimal( (1, (0, 2, 7, 1), 'F') )
1418 self.assertEqual(d.as_tuple(), (1, (0,), 'F'))
1419
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001420 def test_immutability_operations(self):
1421 # Do operations and check that it didn't change change internal objects.
1422
1423 d1 = Decimal('-25e55')
1424 b1 = Decimal('-25e55')
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001425 d2 = Decimal('33e+33')
1426 b2 = Decimal('33e+33')
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001427
1428 def checkSameDec(operation, useOther=False):
1429 if useOther:
1430 eval("d1." + operation + "(d2)")
1431 self.assertEqual(d1._sign, b1._sign)
1432 self.assertEqual(d1._int, b1._int)
1433 self.assertEqual(d1._exp, b1._exp)
1434 self.assertEqual(d2._sign, b2._sign)
1435 self.assertEqual(d2._int, b2._int)
1436 self.assertEqual(d2._exp, b2._exp)
1437 else:
1438 eval("d1." + operation + "()")
1439 self.assertEqual(d1._sign, b1._sign)
1440 self.assertEqual(d1._int, b1._int)
1441 self.assertEqual(d1._exp, b1._exp)
1442 return
1443
1444 Decimal(d1)
1445 self.assertEqual(d1._sign, b1._sign)
1446 self.assertEqual(d1._int, b1._int)
1447 self.assertEqual(d1._exp, b1._exp)
1448
1449 checkSameDec("__abs__")
1450 checkSameDec("__add__", True)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001451 checkSameDec("__divmod__", True)
Christian Heimes77c02eb2008-02-09 02:18:51 +00001452 checkSameDec("__eq__", True)
1453 checkSameDec("__ne__", True)
1454 checkSameDec("__le__", True)
1455 checkSameDec("__lt__", True)
1456 checkSameDec("__ge__", True)
1457 checkSameDec("__gt__", True)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001458 checkSameDec("__float__")
1459 checkSameDec("__floordiv__", True)
1460 checkSameDec("__hash__")
1461 checkSameDec("__int__")
Christian Heimes969fe572008-01-25 11:23:10 +00001462 checkSameDec("__trunc__")
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001463 checkSameDec("__mod__", True)
1464 checkSameDec("__mul__", True)
1465 checkSameDec("__neg__")
Jack Diederich4dafcc42006-11-28 19:15:13 +00001466 checkSameDec("__bool__")
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001467 checkSameDec("__pos__")
1468 checkSameDec("__pow__", True)
1469 checkSameDec("__radd__", True)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001470 checkSameDec("__rdivmod__", True)
1471 checkSameDec("__repr__")
1472 checkSameDec("__rfloordiv__", True)
1473 checkSameDec("__rmod__", True)
1474 checkSameDec("__rmul__", True)
1475 checkSameDec("__rpow__", True)
1476 checkSameDec("__rsub__", True)
1477 checkSameDec("__str__")
1478 checkSameDec("__sub__", True)
1479 checkSameDec("__truediv__", True)
1480 checkSameDec("adjusted")
1481 checkSameDec("as_tuple")
1482 checkSameDec("compare", True)
1483 checkSameDec("max", True)
1484 checkSameDec("min", True)
1485 checkSameDec("normalize")
1486 checkSameDec("quantize", True)
1487 checkSameDec("remainder_near", True)
1488 checkSameDec("same_quantum", True)
1489 checkSameDec("sqrt")
1490 checkSameDec("to_eng_string")
1491 checkSameDec("to_integral")
1492
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001493 def test_subclassing(self):
1494 # Different behaviours when subclassing Decimal
1495
1496 class MyDecimal(Decimal):
1497 pass
1498
1499 d1 = MyDecimal(1)
1500 d2 = MyDecimal(2)
1501 d = d1 + d2
1502 self.assertTrue(type(d) is Decimal)
1503
1504 d = d1.max(d2)
1505 self.assertTrue(type(d) is Decimal)
1506
Christian Heimes0348fb62008-03-26 12:55:56 +00001507 def test_implicit_context(self):
1508 # Check results when context given implicitly. (Issue 2478)
1509 c = getcontext()
1510 self.assertEqual(str(Decimal(0).sqrt()),
1511 str(c.sqrt(Decimal(0))))
1512
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001513
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001514class DecimalPythonAPItests(unittest.TestCase):
1515
Raymond Hettinger82417ca2009-02-03 03:54:28 +00001516 def test_abc(self):
1517 self.assert_(issubclass(Decimal, numbers.Number))
1518 self.assert_(not issubclass(Decimal, numbers.Real))
1519 self.assert_(isinstance(Decimal(0), numbers.Number))
1520 self.assert_(not isinstance(Decimal(0), numbers.Real))
1521
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001522 def test_pickle(self):
1523 d = Decimal('-3.141590000')
1524 p = pickle.dumps(d)
1525 e = pickle.loads(p)
1526 self.assertEqual(d, e)
1527
Raymond Hettinger5548be22004-07-05 18:49:38 +00001528 def test_int(self):
Raymond Hettinger605ed022004-11-24 07:28:48 +00001529 for x in range(-250, 250):
1530 s = '%0.2f' % (x / 100.0)
Raymond Hettinger5548be22004-07-05 18:49:38 +00001531 # should work the same as for floats
1532 self.assertEqual(int(Decimal(s)), int(float(s)))
Raymond Hettinger605ed022004-11-24 07:28:48 +00001533 # should work the same as to_integral in the ROUND_DOWN mode
Raymond Hettinger5548be22004-07-05 18:49:38 +00001534 d = Decimal(s)
Raymond Hettinger605ed022004-11-24 07:28:48 +00001535 r = d.to_integral(ROUND_DOWN)
Raymond Hettinger5548be22004-07-05 18:49:38 +00001536 self.assertEqual(Decimal(int(d)), r)
1537
Christian Heimes969fe572008-01-25 11:23:10 +00001538 def test_trunc(self):
1539 for x in range(-250, 250):
1540 s = '%0.2f' % (x / 100.0)
1541 # should work the same as for floats
1542 self.assertEqual(int(Decimal(s)), int(float(s)))
1543 # should work the same as to_integral in the ROUND_DOWN mode
1544 d = Decimal(s)
1545 r = d.to_integral(ROUND_DOWN)
Christian Heimes400adb02008-02-01 08:12:03 +00001546 self.assertEqual(Decimal(math.trunc(d)), r)
Christian Heimes969fe572008-01-25 11:23:10 +00001547
Raymond Hettinger771ed762009-01-03 19:20:32 +00001548 def test_from_float(self):
1549
1550 class MyDecimal(Decimal):
1551 pass
1552
1553 r = MyDecimal.from_float(0.1)
1554 self.assertEqual(type(r), MyDecimal)
1555 self.assertEqual(str(r),
1556 '0.1000000000000000055511151231257827021181583404541015625')
1557 bigint = 12345678901234567890123456789
1558 self.assertEqual(MyDecimal.from_float(bigint), MyDecimal(bigint))
1559 self.assert_(MyDecimal.from_float(float('nan')).is_qnan())
1560 self.assert_(MyDecimal.from_float(float('inf')).is_infinite())
1561 self.assert_(MyDecimal.from_float(float('-inf')).is_infinite())
1562 self.assertEqual(str(MyDecimal.from_float(float('nan'))),
1563 str(Decimal('NaN')))
1564 self.assertEqual(str(MyDecimal.from_float(float('inf'))),
1565 str(Decimal('Infinity')))
1566 self.assertEqual(str(MyDecimal.from_float(float('-inf'))),
1567 str(Decimal('-Infinity')))
1568 self.assertRaises(TypeError, MyDecimal.from_float, 'abc')
1569 for i in range(200):
1570 x = random.expovariate(0.01) * (random.random() * 2.0 - 1.0)
1571 self.assertEqual(x, float(MyDecimal.from_float(x))) # roundtrip
1572
1573 def test_create_decimal_from_float(self):
1574 context = Context(prec=5, rounding=ROUND_DOWN)
1575 self.assertEqual(
1576 context.create_decimal_from_float(math.pi),
1577 Decimal('3.1415')
1578 )
1579 context = Context(prec=5, rounding=ROUND_UP)
1580 self.assertEqual(
1581 context.create_decimal_from_float(math.pi),
1582 Decimal('3.1416')
1583 )
1584 context = Context(prec=5, traps=[Inexact])
1585 self.assertRaises(
1586 Inexact,
1587 context.create_decimal_from_float,
1588 math.pi
1589 )
1590 self.assertEqual(repr(context.create_decimal_from_float(-0.0)),
1591 "Decimal('-0')")
1592 self.assertEqual(repr(context.create_decimal_from_float(1.0)),
1593 "Decimal('1')")
1594 self.assertEqual(repr(context.create_decimal_from_float(10)),
1595 "Decimal('10')")
1596
Raymond Hettingerd9c0a7a2004-07-03 10:02:28 +00001597class ContextAPItests(unittest.TestCase):
1598
1599 def test_pickle(self):
1600 c = Context()
1601 e = pickle.loads(pickle.dumps(c))
1602 for k in vars(c):
1603 v1 = vars(c)[k]
1604 v2 = vars(e)[k]
1605 self.assertEqual(v1, v2)
1606
Raymond Hettinger0aeac102004-07-05 22:53:03 +00001607 def test_equality_with_other_types(self):
1608 self.assert_(Decimal(10) in ['a', 1.0, Decimal(10), (1,2), {}])
1609 self.assert_(Decimal(10) not in ['a', 1.0, (1,2), {}])
1610
Raymond Hettinger955d2b22004-08-08 20:17:45 +00001611 def test_copy(self):
1612 # All copies should be deep
1613 c = Context()
1614 d = c.copy()
1615 self.assertNotEqual(id(c), id(d))
1616 self.assertNotEqual(id(c.flags), id(d.flags))
1617 self.assertNotEqual(id(c.traps), id(d.traps))
1618
Thomas Wouters89f507f2006-12-13 04:49:30 +00001619class WithStatementTest(unittest.TestCase):
1620 # Can't do these as docstrings until Python 2.6
1621 # as doctest can't handle __future__ statements
1622
1623 def test_localcontext(self):
1624 # Use a copy of the current context in the block
1625 orig_ctx = getcontext()
1626 with localcontext() as enter_ctx:
1627 set_ctx = getcontext()
1628 final_ctx = getcontext()
1629 self.assert_(orig_ctx is final_ctx, 'did not restore context correctly')
1630 self.assert_(orig_ctx is not set_ctx, 'did not copy the context')
1631 self.assert_(set_ctx is enter_ctx, '__enter__ returned wrong context')
1632
1633 def test_localcontextarg(self):
1634 # Use a copy of the supplied context in the block
1635 orig_ctx = getcontext()
1636 new_ctx = Context(prec=42)
1637 with localcontext(new_ctx) as enter_ctx:
1638 set_ctx = getcontext()
1639 final_ctx = getcontext()
1640 self.assert_(orig_ctx is final_ctx, 'did not restore context correctly')
1641 self.assert_(set_ctx.prec == new_ctx.prec, 'did not set correct context')
1642 self.assert_(new_ctx is not set_ctx, 'did not copy the context')
1643 self.assert_(set_ctx is enter_ctx, '__enter__ returned wrong context')
1644
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001645class ContextFlags(unittest.TestCase):
1646 def test_flags_irrelevant(self):
1647 # check that the result (numeric result + flags raised) of an
1648 # arithmetic operation doesn't depend on the current flags
1649
1650 context = Context(prec=9, Emin = -999999999, Emax = 999999999,
1651 rounding=ROUND_HALF_EVEN, traps=[], flags=[])
1652
1653 # operations that raise various flags, in the form (function, arglist)
1654 operations = [
1655 (context._apply, [Decimal("100E-1000000009")]),
1656 (context.sqrt, [Decimal(2)]),
1657 (context.add, [Decimal("1.23456789"), Decimal("9.87654321")]),
1658 (context.multiply, [Decimal("1.23456789"), Decimal("9.87654321")]),
1659 (context.subtract, [Decimal("1.23456789"), Decimal("9.87654321")]),
1660 ]
1661
1662 # try various flags individually, then a whole lot at once
1663 flagsets = [[Inexact], [Rounded], [Underflow], [Clamped], [Subnormal],
1664 [Inexact, Rounded, Underflow, Clamped, Subnormal]]
1665
1666 for fn, args in operations:
1667 # find answer and flags raised using a clean context
1668 context.clear_flags()
1669 ans = fn(*args)
1670 flags = [k for k, v in context.flags.items() if v]
1671
1672 for extra_flags in flagsets:
1673 # set flags, before calling operation
1674 context.clear_flags()
1675 for flag in extra_flags:
1676 context._raise_error(flag)
1677 new_ans = fn(*args)
1678
1679 # flags that we expect to be set after the operation
1680 expected_flags = list(flags)
1681 for flag in extra_flags:
1682 if flag not in expected_flags:
1683 expected_flags.append(flag)
1684 expected_flags.sort(key=id)
1685
1686 # flags we actually got
1687 new_flags = [k for k,v in context.flags.items() if v]
1688 new_flags.sort(key=id)
1689
1690 self.assertEqual(ans, new_ans,
1691 "operation produces different answers depending on flags set: " +
1692 "expected %s, got %s." % (ans, new_ans))
1693 self.assertEqual(new_flags, expected_flags,
1694 "operation raises different flags depending on flags set: " +
1695 "expected %s, got %s" % (expected_flags, new_flags))
1696
1697def test_main(arith=False, verbose=None, todo_tests=None, debug=None):
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001698 """ Execute the tests.
1699
Raymond Hettingered20ad82004-09-04 20:09:13 +00001700 Runs all arithmetic tests if arith is True or if the "decimal" resource
1701 is enabled in regrtest.py
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001702 """
Raymond Hettingered20ad82004-09-04 20:09:13 +00001703
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00001704 init()
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001705 global TEST_ALL, DEBUG
Raymond Hettingered20ad82004-09-04 20:09:13 +00001706 TEST_ALL = arith or is_resource_enabled('decimal')
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001707 DEBUG = debug
Raymond Hettingered20ad82004-09-04 20:09:13 +00001708
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001709 if todo_tests is None:
1710 test_classes = [
1711 DecimalExplicitConstructionTest,
1712 DecimalImplicitConstructionTest,
1713 DecimalArithmeticOperatorsTest,
Christian Heimesf16baeb2008-02-29 14:57:44 +00001714 DecimalFormatTest,
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001715 DecimalUseOfContextTest,
1716 DecimalUsabilityTest,
1717 DecimalPythonAPItests,
1718 ContextAPItests,
1719 DecimalTest,
1720 WithStatementTest,
1721 ContextFlags
1722 ]
1723 else:
1724 test_classes = [DecimalTest]
1725
1726 # Dynamically build custom test definition for each file in the test
1727 # directory and add the definitions to the DecimalTest class. This
1728 # procedure insures that new files do not get skipped.
1729 for filename in os.listdir(directory):
1730 if '.decTest' not in filename or filename.startswith("."):
1731 continue
1732 head, tail = filename.split('.')
1733 if todo_tests is not None and head not in todo_tests:
1734 continue
1735 tester = lambda self, f=filename: self.eval_file(directory + f)
1736 setattr(DecimalTest, 'test_' + head, tester)
1737 del filename, head, tail, tester
1738
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001739
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00001740 try:
1741 run_unittest(*test_classes)
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001742 if todo_tests is None:
1743 import decimal as DecimalModule
1744 run_doctest(DecimalModule, verbose)
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00001745 finally:
1746 setcontext(ORIGINAL_CONTEXT)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001747
1748if __name__ == '__main__':
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001749 import optparse
1750 p = optparse.OptionParser("test_decimal.py [--debug] [{--skip | test1 [test2 [...]]}]")
1751 p.add_option('--debug', '-d', action='store_true', help='shows the test number and context before each test')
1752 p.add_option('--skip', '-s', action='store_true', help='skip over 90% of the arithmetic tests')
1753 (opt, args) = p.parse_args()
1754
1755 if opt.skip:
1756 test_main(arith=False, verbose=True)
1757 elif args:
1758 test_main(arith=True, verbose=True, todo_tests=args, debug=opt.debug)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001759 else:
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001760 test_main(arith=True, verbose=True)