blob: 50a855e9d1df622b45cde5baa37a5bdd23af22d9 [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
Jeffrey Yasskinca2b69f2008-02-01 06:22:46 +000028import math
Raymond Hettinger7c85fa42004-07-01 11:01:35 +000029import os, sys
30import pickle, copy
Jeffrey Yasskinca2b69f2008-02-01 06:22:46 +000031import unittest
Raymond Hettinger7c85fa42004-07-01 11:01:35 +000032from decimal import *
Raymond Hettinger2c8585b2009-02-03 03:37:03 +000033import numbers
Benjamin Petersonbec087f2009-03-26 21:10:30 +000034from test.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
42Signals = getcontext().flags.keys()
43
Tim Peters46cc7022006-03-31 04:11:16 +000044# Tests are built around these assumed context defaults.
45# test_main() restores the original context.
Neal Norwitzce4a9c92006-04-09 08:36:46 +000046def init():
47 global ORIGINAL_CONTEXT
48 ORIGINAL_CONTEXT = getcontext().copy()
Facundo Batistaee340e52008-05-02 17:39:00 +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,
Facundo Batista353750c2007-09-13 18:13:15 +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
Facundo Batista1a191df2007-10-02 17:01:24 +0000100nameAdapter = {'and':'logical_and',
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000101 'apply':'_apply',
Facundo Batista353750c2007-09-13 18:13:15 +0000102 'class':'number_class',
103 'comparesig':'compare_signal',
104 'comparetotal':'compare_total',
105 'comparetotmag':'compare_total_mag',
Facundo Batista353750c2007-09-13 18:13:15 +0000106 'copy':'copy_decimal',
Facundo Batista1a191df2007-10-02 17:01:24 +0000107 'copyabs':'copy_abs',
Facundo Batista353750c2007-09-13 18:13:15 +0000108 'copynegate':'copy_negate',
109 'copysign':'copy_sign',
Facundo Batista1a191df2007-10-02 17:01:24 +0000110 'divideint':'divide_int',
Facundo Batista353750c2007-09-13 18:13:15 +0000111 'invert':'logical_invert',
Facundo Batista1a191df2007-10-02 17:01:24 +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',
Facundo Batista353750c2007-09-13 18:13:15 +0000122 'maxmag':'max_mag',
123 'minmag':'min_mag',
124 'nextminus':'next_minus',
125 'nextplus':'next_plus',
126 'nexttoward':'next_toward',
Facundo Batista1a191df2007-10-02 17:01:24 +0000127 'or':'logical_or',
Facundo Batista353750c2007-09-13 18:13:15 +0000128 'reduce':'normalize',
Facundo Batista1a191df2007-10-02 17:01:24 +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
Facundo Batista1a191df2007-10-02 17:01:24 +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
Facundo Batista353750c2007-09-13 18:13:15 +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 (
Facundo Batista353750c2007-09-13 18:13:15 +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 Petersonbec087f2009-03-26 21:10:30 +0000196 raise unittest.SkipTest
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000197 return
198 for line in open(file).xreadlines():
199 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)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000203 except DecimalException, exception:
204 #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):
228 funct, value = map(lambda x: x.strip().lower(), s.split(':'))
229 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]
Facundo Batista353750c2007-09-13 18:13:15 +0000251 if DEBUG:
252 print "Test ", id,
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
Raymond Hettingerd9c0a7a2004-07-03 10:02:28 +0000296 except Signals, 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:
Facundo Batista353750c2007-09-13 18:13:15 +0000304 v = Decimal(v, self.context)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000305 vals.append(v)
306
307 ans = FixQuotes(ans)
308
Facundo Batista353750c2007-09-13 18:13:15 +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
Raymond Hettingerd9c0a7a2004-07-03 10:02:28 +0000332 except Signals, 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
Facundo Batista353750c2007-09-13 18:13:15 +0000338 if DEBUG:
339 print "--", self.context
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000340 try:
341 result = str(funct(*vals))
Facundo Batista1a191df2007-10-02 17:01:24 +0000342 if fname in LOGICAL_FUNCTIONS:
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000343 result = str(int(eval(result))) # 'True', 'False' -> '1', '0'
Raymond Hettingerd9c0a7a2004-07-03 10:02:28 +0000344 except Signals, 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.
347 print "ERROR:", s
348 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
353 myexceptions.sort()
354 theirexceptions.sort()
355
356 self.assertEqual(result, ans,
357 'Incorrect answer for ' + s + ' -- got ' + result)
358 self.assertEqual(myexceptions, theirexceptions,
Facundo Batista353750c2007-09-13 18:13:15 +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
Mark Dickinson59bc20b2008-01-12 01:56:00 +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
Mark Dickinson8e85ffa2008-03-25 18:47:59 +0000428 #unicode strings should be permitted
429 self.assertEqual(str(Decimal(u'0E-017')), '0E-17')
430 self.assertEqual(str(Decimal(u'45')), '45')
431 self.assertEqual(str(Decimal(u'-Inf')), '-Infinity')
432 self.assertEqual(str(Decimal(u'NaN123')), 'NaN123')
433
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000434 def test_explicit_from_tuples(self):
435
436 #zero
437 d = Decimal( (0, (0,), 0) )
438 self.assertEqual(str(d), '0')
439
440 #int
441 d = Decimal( (1, (4, 5), 0) )
442 self.assertEqual(str(d), '-45')
443
444 #float
445 d = Decimal( (0, (4, 5, 3, 4), -2) )
446 self.assertEqual(str(d), '45.34')
447
448 #weird
449 d = Decimal( (1, (4, 3, 4, 9, 1, 3, 5, 3, 4), -25) )
450 self.assertEqual(str(d), '-4.34913534E-17')
451
452 #wrong number of items
453 self.assertRaises(ValueError, Decimal, (1, (4, 3, 4, 9, 1)) )
454
455 #bad sign
456 self.assertRaises(ValueError, Decimal, (8, (4, 3, 4, 9, 1), 2) )
Facundo Batista9b5e2312007-10-19 19:25:57 +0000457 self.assertRaises(ValueError, Decimal, (0., (4, 3, 4, 9, 1), 2) )
458 self.assertRaises(ValueError, Decimal, (Decimal(1), (4, 3, 4, 9, 1), 2))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000459
460 #bad exp
461 self.assertRaises(ValueError, Decimal, (1, (4, 3, 4, 9, 1), 'wrong!') )
Facundo Batista9b5e2312007-10-19 19:25:57 +0000462 self.assertRaises(ValueError, Decimal, (1, (4, 3, 4, 9, 1), 0.) )
463 self.assertRaises(ValueError, Decimal, (1, (4, 3, 4, 9, 1), '1') )
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000464
465 #bad coefficients
466 self.assertRaises(ValueError, Decimal, (1, (4, 3, 4, None, 1), 2) )
467 self.assertRaises(ValueError, Decimal, (1, (4, -3, 4, 9, 1), 2) )
Facundo Batista9b5e2312007-10-19 19:25:57 +0000468 self.assertRaises(ValueError, Decimal, (1, (4, 10, 4, 9, 1), 2) )
Facundo Batista72bc54f2007-11-23 17:59:00 +0000469 self.assertRaises(ValueError, Decimal, (1, (4, 3, 4, 'a', 1), 2) )
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000470
471 def test_explicit_from_Decimal(self):
472
473 #positive
474 d = Decimal(45)
475 e = Decimal(d)
476 self.assertEqual(str(e), '45')
477 self.assertNotEqual(id(d), id(e))
478
479 #very large positive
480 d = Decimal(500000123)
481 e = Decimal(d)
482 self.assertEqual(str(e), '500000123')
483 self.assertNotEqual(id(d), id(e))
484
485 #negative
486 d = Decimal(-45)
487 e = Decimal(d)
488 self.assertEqual(str(e), '-45')
489 self.assertNotEqual(id(d), id(e))
490
491 #zero
492 d = Decimal(0)
493 e = Decimal(d)
494 self.assertEqual(str(e), '0')
495 self.assertNotEqual(id(d), id(e))
496
497 def test_explicit_context_create_decimal(self):
498
499 nc = copy.copy(getcontext())
500 nc.prec = 3
501
502 # empty
Raymond Hettingerfed52962004-07-14 15:41:57 +0000503 d = Decimal()
504 self.assertEqual(str(d), '0')
505 d = nc.create_decimal()
506 self.assertEqual(str(d), '0')
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000507
508 # from None
509 self.assertRaises(TypeError, nc.create_decimal, None)
510
511 # from int
512 d = nc.create_decimal(456)
Benjamin Peterson5c8da862009-06-30 22:57:08 +0000513 self.assertTrue(isinstance(d, Decimal))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000514 self.assertEqual(nc.create_decimal(45678),
515 nc.create_decimal('457E+2'))
516
517 # from string
518 d = Decimal('456789')
519 self.assertEqual(str(d), '456789')
520 d = nc.create_decimal('456789')
521 self.assertEqual(str(d), '4.57E+5')
Mark Dickinson59bc20b2008-01-12 01:56:00 +0000522 # leading and trailing whitespace should result in a NaN;
523 # spaces are already checked in Cowlishaw's test-suite, so
524 # here we just check that a trailing newline results in a NaN
525 self.assertEqual(str(nc.create_decimal('3.14\n')), 'NaN')
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000526
527 # from tuples
528 d = Decimal( (1, (4, 3, 4, 9, 1, 3, 5, 3, 4), -25) )
529 self.assertEqual(str(d), '-4.34913534E-17')
530 d = nc.create_decimal( (1, (4, 3, 4, 9, 1, 3, 5, 3, 4), -25) )
531 self.assertEqual(str(d), '-4.35E-17')
532
533 # from Decimal
534 prevdec = Decimal(500000123)
535 d = Decimal(prevdec)
536 self.assertEqual(str(d), '500000123')
537 d = nc.create_decimal(prevdec)
538 self.assertEqual(str(d), '5.00E+8')
539
Mark Dickinson4326ad82009-08-02 10:59:36 +0000540 def test_unicode_digits(self):
541 test_values = {
542 u'\uff11': '1',
543 u'\u0660.\u0660\u0663\u0667\u0662e-\u0663' : '0.0000372',
544 u'-nan\u0c68\u0c6a\u0c66\u0c66' : '-NaN2400',
545 }
546 for input, expected in test_values.items():
547 self.assertEqual(str(Decimal(input)), expected)
548
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000549
550class DecimalImplicitConstructionTest(unittest.TestCase):
551 '''Unit tests for Implicit Construction cases of Decimal.'''
552
553 def test_implicit_from_None(self):
554 self.assertRaises(TypeError, eval, 'Decimal(5) + None', globals())
555
556 def test_implicit_from_int(self):
557 #normal
558 self.assertEqual(str(Decimal(5) + 45), '50')
559 #exceeding precision
560 self.assertEqual(Decimal(5) + 123456789000, Decimal(123456789000))
561
562 def test_implicit_from_string(self):
563 self.assertRaises(TypeError, eval, 'Decimal(5) + "3"', globals())
564
565 def test_implicit_from_float(self):
566 self.assertRaises(TypeError, eval, 'Decimal(5) + 2.2', globals())
567
568 def test_implicit_from_Decimal(self):
569 self.assertEqual(Decimal(5) + Decimal(45), Decimal(50))
570
Raymond Hettinger267b8682005-03-27 10:47:39 +0000571 def test_rop(self):
572 # Allow other classes to be trained to interact with Decimals
573 class E:
574 def __divmod__(self, other):
575 return 'divmod ' + str(other)
576 def __rdivmod__(self, other):
577 return str(other) + ' rdivmod'
578 def __lt__(self, other):
579 return 'lt ' + str(other)
580 def __gt__(self, other):
581 return 'gt ' + str(other)
582 def __le__(self, other):
583 return 'le ' + str(other)
584 def __ge__(self, other):
585 return 'ge ' + str(other)
586 def __eq__(self, other):
587 return 'eq ' + str(other)
588 def __ne__(self, other):
589 return 'ne ' + str(other)
590
591 self.assertEqual(divmod(E(), Decimal(10)), 'divmod 10')
592 self.assertEqual(divmod(Decimal(10), E()), '10 rdivmod')
593 self.assertEqual(eval('Decimal(10) < E()'), 'gt 10')
594 self.assertEqual(eval('Decimal(10) > E()'), 'lt 10')
595 self.assertEqual(eval('Decimal(10) <= E()'), 'ge 10')
596 self.assertEqual(eval('Decimal(10) >= E()'), 'le 10')
597 self.assertEqual(eval('Decimal(10) == E()'), 'eq 10')
598 self.assertEqual(eval('Decimal(10) != E()'), 'ne 10')
599
600 # insert operator methods and then exercise them
Georg Brandl96c3f7f2006-03-28 08:06:35 +0000601 oplist = [
602 ('+', '__add__', '__radd__'),
603 ('-', '__sub__', '__rsub__'),
604 ('*', '__mul__', '__rmul__'),
605 ('%', '__mod__', '__rmod__'),
606 ('//', '__floordiv__', '__rfloordiv__'),
607 ('**', '__pow__', '__rpow__')
608 ]
609 if 1/2 == 0:
610 # testing with classic division, so add __div__
611 oplist.append(('/', '__div__', '__rdiv__'))
612 else:
613 # testing with -Qnew, so add __truediv__
614 oplist.append(('/', '__truediv__', '__rtruediv__'))
Anthony Baxter4ef3a232006-03-30 12:59:11 +0000615
Georg Brandl96c3f7f2006-03-28 08:06:35 +0000616 for sym, lop, rop in oplist:
Raymond Hettinger267b8682005-03-27 10:47:39 +0000617 setattr(E, lop, lambda self, other: 'str' + lop + str(other))
618 setattr(E, rop, lambda self, other: str(other) + rop + 'str')
619 self.assertEqual(eval('E()' + sym + 'Decimal(10)'),
620 'str' + lop + '10')
621 self.assertEqual(eval('Decimal(10)' + sym + 'E()'),
622 '10' + rop + 'str')
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000623
Mark Dickinson277859d2009-03-17 23:03:46 +0000624
Mark Dickinson1ddf1d82008-02-29 02:16:37 +0000625class DecimalFormatTest(unittest.TestCase):
626 '''Unit tests for the format function.'''
627 def test_formatting(self):
628 # triples giving a format, a Decimal, and the expected result
629 test_values = [
630 ('e', '0E-15', '0e-15'),
631 ('e', '2.3E-15', '2.3e-15'),
632 ('e', '2.30E+2', '2.30e+2'), # preserve significant zeros
633 ('e', '2.30000E-15', '2.30000e-15'),
634 ('e', '1.23456789123456789e40', '1.23456789123456789e+40'),
635 ('e', '1.5', '1.5e+0'),
636 ('e', '0.15', '1.5e-1'),
637 ('e', '0.015', '1.5e-2'),
638 ('e', '0.0000000000015', '1.5e-12'),
639 ('e', '15.0', '1.50e+1'),
640 ('e', '-15', '-1.5e+1'),
641 ('e', '0', '0e+0'),
642 ('e', '0E1', '0e+1'),
643 ('e', '0.0', '0e-1'),
644 ('e', '0.00', '0e-2'),
645 ('.6e', '0E-15', '0.000000e-9'),
646 ('.6e', '0', '0.000000e+6'),
647 ('.6e', '9.999999', '9.999999e+0'),
648 ('.6e', '9.9999999', '1.000000e+1'),
649 ('.6e', '-1.23e5', '-1.230000e+5'),
650 ('.6e', '1.23456789e-3', '1.234568e-3'),
651 ('f', '0', '0'),
652 ('f', '0.0', '0.0'),
653 ('f', '0E-2', '0.00'),
654 ('f', '0.00E-8', '0.0000000000'),
655 ('f', '0E1', '0'), # loses exponent information
656 ('f', '3.2E1', '32'),
657 ('f', '3.2E2', '320'),
658 ('f', '3.20E2', '320'),
659 ('f', '3.200E2', '320.0'),
660 ('f', '3.2E-6', '0.0000032'),
661 ('.6f', '0E-15', '0.000000'), # all zeros treated equally
662 ('.6f', '0E1', '0.000000'),
663 ('.6f', '0', '0.000000'),
664 ('.0f', '0', '0'), # no decimal point
665 ('.0f', '0e-2', '0'),
666 ('.0f', '3.14159265', '3'),
667 ('.1f', '3.14159265', '3.1'),
668 ('.4f', '3.14159265', '3.1416'),
669 ('.6f', '3.14159265', '3.141593'),
670 ('.7f', '3.14159265', '3.1415926'), # round-half-even!
671 ('.8f', '3.14159265', '3.14159265'),
672 ('.9f', '3.14159265', '3.141592650'),
673
674 ('g', '0', '0'),
675 ('g', '0.0', '0.0'),
676 ('g', '0E1', '0e+1'),
677 ('G', '0E1', '0E+1'),
678 ('g', '0E-5', '0.00000'),
679 ('g', '0E-6', '0.000000'),
680 ('g', '0E-7', '0e-7'),
681 ('g', '-0E2', '-0e+2'),
682 ('.0g', '3.14159265', '3'), # 0 sig fig -> 1 sig fig
683 ('.1g', '3.14159265', '3'),
684 ('.2g', '3.14159265', '3.1'),
685 ('.5g', '3.14159265', '3.1416'),
686 ('.7g', '3.14159265', '3.141593'),
687 ('.8g', '3.14159265', '3.1415926'), # round-half-even!
688 ('.9g', '3.14159265', '3.14159265'),
689 ('.10g', '3.14159265', '3.14159265'), # don't pad
690
691 ('%', '0E1', '0%'),
692 ('%', '0E0', '0%'),
693 ('%', '0E-1', '0%'),
694 ('%', '0E-2', '0%'),
695 ('%', '0E-3', '0.0%'),
696 ('%', '0E-4', '0.00%'),
697
698 ('.3%', '0', '0.000%'), # all zeros treated equally
699 ('.3%', '0E10', '0.000%'),
700 ('.3%', '0E-10', '0.000%'),
701 ('.3%', '2.34', '234.000%'),
702 ('.3%', '1.234567', '123.457%'),
703 ('.0%', '1.23', '123%'),
704
705 ('e', 'NaN', 'NaN'),
706 ('f', '-NaN123', '-NaN123'),
707 ('+g', 'NaN456', '+NaN456'),
708 ('.3e', 'Inf', 'Infinity'),
709 ('.16f', '-Inf', '-Infinity'),
710 ('.0g', '-sNaN', '-sNaN'),
711
712 ('', '1.00', '1.00'),
Mark Dickinsonb065e522009-03-17 18:01:03 +0000713
Mark Dickinson277859d2009-03-17 23:03:46 +0000714 # test alignment and padding
Mark Dickinsonb065e522009-03-17 18:01:03 +0000715 ('<6', '123', '123 '),
716 ('>6', '123', ' 123'),
717 ('^6', '123', ' 123 '),
718 ('=+6', '123', '+ 123'),
Mark Dickinson277859d2009-03-17 23:03:46 +0000719 ('#<10', 'NaN', 'NaN#######'),
720 ('#<10', '-4.3', '-4.3######'),
721 ('#<+10', '0.0130', '+0.0130###'),
722 ('#< 10', '0.0130', ' 0.0130###'),
723 ('@>10', '-Inf', '@-Infinity'),
724 ('#>5', '-Inf', '-Infinity'),
725 ('?^5', '123', '?123?'),
726 ('%^6', '123', '%123%%'),
727 (' ^6', '-45.6', '-45.6 '),
728 ('/=10', '-45.6', '-/////45.6'),
729 ('/=+10', '45.6', '+/////45.6'),
730 ('/= 10', '45.6', ' /////45.6'),
731
732 # thousands separator
733 (',', '1234567', '1,234,567'),
734 (',', '123456', '123,456'),
735 (',', '12345', '12,345'),
736 (',', '1234', '1,234'),
737 (',', '123', '123'),
738 (',', '12', '12'),
739 (',', '1', '1'),
740 (',', '0', '0'),
741 (',', '-1234567', '-1,234,567'),
742 (',', '-123456', '-123,456'),
743 ('7,', '123456', '123,456'),
744 ('8,', '123456', '123,456 '),
745 ('08,', '123456', '0,123,456'), # special case: extra 0 needed
746 ('+08,', '123456', '+123,456'), # but not if there's a sign
747 (' 08,', '123456', ' 123,456'),
748 ('08,', '-123456', '-123,456'),
749 ('+09,', '123456', '+0,123,456'),
750 # ... with fractional part...
751 ('07,', '1234.56', '1,234.56'),
752 ('08,', '1234.56', '1,234.56'),
753 ('09,', '1234.56', '01,234.56'),
754 ('010,', '1234.56', '001,234.56'),
755 ('011,', '1234.56', '0,001,234.56'),
756 ('012,', '1234.56', '0,001,234.56'),
757 ('08,.1f', '1234.5', '01,234.5'),
758 # no thousands separators in fraction part
759 (',', '1.23456789', '1.23456789'),
760 (',%', '123.456789', '12,345.6789%'),
761 (',e', '123456', '1.23456e+5'),
762 (',E', '123456', '1.23456E+5'),
Mark Dickinson491ea552009-09-07 16:17:41 +0000763
764 # issue 6850
765 ('a=-7.0', '0.12345', 'aaaa0.1'),
Mark Dickinson1ddf1d82008-02-29 02:16:37 +0000766 ]
767 for fmt, d, result in test_values:
768 self.assertEqual(format(Decimal(d), fmt), result)
769
Mark Dickinson277859d2009-03-17 23:03:46 +0000770 def test_n_format(self):
771 try:
772 from locale import CHAR_MAX
773 except ImportError:
774 return
775
776 # Set up some localeconv-like dictionaries
777 en_US = {
778 'decimal_point' : '.',
779 'grouping' : [3, 3, 0],
780 'thousands_sep': ','
781 }
782
783 fr_FR = {
784 'decimal_point' : ',',
785 'grouping' : [CHAR_MAX],
786 'thousands_sep' : ''
787 }
788
789 ru_RU = {
790 'decimal_point' : ',',
791 'grouping' : [3, 3, 0],
792 'thousands_sep' : ' '
793 }
794
795 crazy = {
796 'decimal_point' : '&',
797 'grouping' : [1, 4, 2, CHAR_MAX],
798 'thousands_sep' : '-'
799 }
800
801
802 def get_fmt(x, locale, fmt='n'):
803 return Decimal.__format__(Decimal(x), fmt, _localeconv=locale)
804
805 self.assertEqual(get_fmt(Decimal('12.7'), en_US), '12.7')
806 self.assertEqual(get_fmt(Decimal('12.7'), fr_FR), '12,7')
807 self.assertEqual(get_fmt(Decimal('12.7'), ru_RU), '12,7')
808 self.assertEqual(get_fmt(Decimal('12.7'), crazy), '1-2&7')
809
810 self.assertEqual(get_fmt(123456789, en_US), '123,456,789')
811 self.assertEqual(get_fmt(123456789, fr_FR), '123456789')
812 self.assertEqual(get_fmt(123456789, ru_RU), '123 456 789')
813 self.assertEqual(get_fmt(1234567890123, crazy), '123456-78-9012-3')
814
815 self.assertEqual(get_fmt(123456789, en_US, '.6n'), '1.23457e+8')
816 self.assertEqual(get_fmt(123456789, fr_FR, '.6n'), '1,23457e+8')
817 self.assertEqual(get_fmt(123456789, ru_RU, '.6n'), '1,23457e+8')
818 self.assertEqual(get_fmt(123456789, crazy, '.6n'), '1&23457e+8')
819
Mark Dickinsonb14514a2009-03-18 08:22:51 +0000820 # zero padding
821 self.assertEqual(get_fmt(1234, fr_FR, '03n'), '1234')
822 self.assertEqual(get_fmt(1234, fr_FR, '04n'), '1234')
823 self.assertEqual(get_fmt(1234, fr_FR, '05n'), '01234')
824 self.assertEqual(get_fmt(1234, fr_FR, '06n'), '001234')
825
826 self.assertEqual(get_fmt(12345, en_US, '05n'), '12,345')
827 self.assertEqual(get_fmt(12345, en_US, '06n'), '12,345')
828 self.assertEqual(get_fmt(12345, en_US, '07n'), '012,345')
829 self.assertEqual(get_fmt(12345, en_US, '08n'), '0,012,345')
830 self.assertEqual(get_fmt(12345, en_US, '09n'), '0,012,345')
831 self.assertEqual(get_fmt(12345, en_US, '010n'), '00,012,345')
832
833 self.assertEqual(get_fmt(123456, crazy, '06n'), '1-2345-6')
834 self.assertEqual(get_fmt(123456, crazy, '07n'), '1-2345-6')
835 self.assertEqual(get_fmt(123456, crazy, '08n'), '1-2345-6')
836 self.assertEqual(get_fmt(123456, crazy, '09n'), '01-2345-6')
837 self.assertEqual(get_fmt(123456, crazy, '010n'), '0-01-2345-6')
838 self.assertEqual(get_fmt(123456, crazy, '011n'), '0-01-2345-6')
839 self.assertEqual(get_fmt(123456, crazy, '012n'), '00-01-2345-6')
840 self.assertEqual(get_fmt(123456, crazy, '013n'), '000-01-2345-6')
841
Mark Dickinson277859d2009-03-17 23:03:46 +0000842
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000843class DecimalArithmeticOperatorsTest(unittest.TestCase):
844 '''Unit tests for all arithmetic operators, binary and unary.'''
845
846 def test_addition(self):
847
848 d1 = Decimal('-11.1')
849 d2 = Decimal('22.2')
850
851 #two Decimals
852 self.assertEqual(d1+d2, Decimal('11.1'))
853 self.assertEqual(d2+d1, Decimal('11.1'))
854
855 #with other type, left
856 c = d1 + 5
857 self.assertEqual(c, Decimal('-6.1'))
858 self.assertEqual(type(c), type(d1))
859
860 #with other type, right
861 c = 5 + d1
862 self.assertEqual(c, Decimal('-6.1'))
863 self.assertEqual(type(c), type(d1))
864
865 #inline with decimal
866 d1 += d2
867 self.assertEqual(d1, Decimal('11.1'))
868
869 #inline with other type
870 d1 += 5
871 self.assertEqual(d1, Decimal('16.1'))
872
873 def test_subtraction(self):
874
875 d1 = Decimal('-11.1')
876 d2 = Decimal('22.2')
877
878 #two Decimals
879 self.assertEqual(d1-d2, Decimal('-33.3'))
880 self.assertEqual(d2-d1, Decimal('33.3'))
881
882 #with other type, left
883 c = d1 - 5
884 self.assertEqual(c, Decimal('-16.1'))
885 self.assertEqual(type(c), type(d1))
886
887 #with other type, right
888 c = 5 - d1
889 self.assertEqual(c, Decimal('16.1'))
890 self.assertEqual(type(c), type(d1))
891
892 #inline with decimal
893 d1 -= d2
894 self.assertEqual(d1, Decimal('-33.3'))
895
896 #inline with other type
897 d1 -= 5
898 self.assertEqual(d1, Decimal('-38.3'))
899
900 def test_multiplication(self):
901
902 d1 = Decimal('-5')
903 d2 = Decimal('3')
904
905 #two Decimals
906 self.assertEqual(d1*d2, Decimal('-15'))
907 self.assertEqual(d2*d1, Decimal('-15'))
908
909 #with other type, left
910 c = d1 * 5
911 self.assertEqual(c, Decimal('-25'))
912 self.assertEqual(type(c), type(d1))
913
914 #with other type, right
915 c = 5 * d1
916 self.assertEqual(c, Decimal('-25'))
917 self.assertEqual(type(c), type(d1))
918
919 #inline with decimal
920 d1 *= d2
921 self.assertEqual(d1, Decimal('-15'))
922
923 #inline with other type
924 d1 *= 5
925 self.assertEqual(d1, Decimal('-75'))
926
927 def test_division(self):
928
929 d1 = Decimal('-5')
930 d2 = Decimal('2')
931
932 #two Decimals
933 self.assertEqual(d1/d2, Decimal('-2.5'))
934 self.assertEqual(d2/d1, Decimal('-0.4'))
935
936 #with other type, left
937 c = d1 / 4
938 self.assertEqual(c, Decimal('-1.25'))
939 self.assertEqual(type(c), type(d1))
940
941 #with other type, right
942 c = 4 / d1
943 self.assertEqual(c, Decimal('-0.8'))
944 self.assertEqual(type(c), type(d1))
945
946 #inline with decimal
947 d1 /= d2
948 self.assertEqual(d1, Decimal('-2.5'))
949
950 #inline with other type
951 d1 /= 4
952 self.assertEqual(d1, Decimal('-0.625'))
953
954 def test_floor_division(self):
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000955
956 d1 = Decimal('5')
957 d2 = Decimal('2')
958
959 #two Decimals
960 self.assertEqual(d1//d2, Decimal('2'))
961 self.assertEqual(d2//d1, Decimal('0'))
962
963 #with other type, left
964 c = d1 // 4
965 self.assertEqual(c, Decimal('1'))
966 self.assertEqual(type(c), type(d1))
967
968 #with other type, right
969 c = 7 // d1
970 self.assertEqual(c, Decimal('1'))
971 self.assertEqual(type(c), type(d1))
972
973 #inline with decimal
974 d1 //= d2
975 self.assertEqual(d1, Decimal('2'))
976
977 #inline with other type
978 d1 //= 2
979 self.assertEqual(d1, Decimal('1'))
980
981 def test_powering(self):
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000982
983 d1 = Decimal('5')
984 d2 = Decimal('2')
985
986 #two Decimals
987 self.assertEqual(d1**d2, Decimal('25'))
988 self.assertEqual(d2**d1, Decimal('32'))
989
990 #with other type, left
991 c = d1 ** 4
992 self.assertEqual(c, Decimal('625'))
993 self.assertEqual(type(c), type(d1))
994
995 #with other type, right
996 c = 7 ** d1
997 self.assertEqual(c, Decimal('16807'))
998 self.assertEqual(type(c), type(d1))
999
1000 #inline with decimal
1001 d1 **= d2
1002 self.assertEqual(d1, Decimal('25'))
1003
1004 #inline with other type
1005 d1 **= 4
1006 self.assertEqual(d1, Decimal('390625'))
1007
1008 def test_module(self):
1009
1010 d1 = Decimal('5')
1011 d2 = Decimal('2')
1012
1013 #two Decimals
1014 self.assertEqual(d1%d2, Decimal('1'))
1015 self.assertEqual(d2%d1, Decimal('2'))
1016
1017 #with other type, left
1018 c = d1 % 4
1019 self.assertEqual(c, Decimal('1'))
1020 self.assertEqual(type(c), type(d1))
1021
1022 #with other type, right
1023 c = 7 % d1
1024 self.assertEqual(c, Decimal('2'))
1025 self.assertEqual(type(c), type(d1))
1026
1027 #inline with decimal
1028 d1 %= d2
1029 self.assertEqual(d1, Decimal('1'))
1030
1031 #inline with other type
1032 d1 %= 4
1033 self.assertEqual(d1, Decimal('1'))
1034
1035 def test_floor_div_module(self):
1036
1037 d1 = Decimal('5')
1038 d2 = Decimal('2')
1039
1040 #two Decimals
1041 (p, q) = divmod(d1, d2)
1042 self.assertEqual(p, Decimal('2'))
1043 self.assertEqual(q, Decimal('1'))
1044 self.assertEqual(type(p), type(d1))
1045 self.assertEqual(type(q), type(d1))
1046
1047 #with other type, left
1048 (p, q) = divmod(d1, 4)
1049 self.assertEqual(p, Decimal('1'))
1050 self.assertEqual(q, Decimal('1'))
1051 self.assertEqual(type(p), type(d1))
1052 self.assertEqual(type(q), type(d1))
1053
1054 #with other type, right
1055 (p, q) = divmod(7, d1)
1056 self.assertEqual(p, Decimal('1'))
1057 self.assertEqual(q, Decimal('2'))
1058 self.assertEqual(type(p), type(d1))
1059 self.assertEqual(type(q), type(d1))
1060
1061 def test_unary_operators(self):
1062 self.assertEqual(+Decimal(45), Decimal(+45)) # +
1063 self.assertEqual(-Decimal(45), Decimal(-45)) # -
1064 self.assertEqual(abs(Decimal(45)), abs(Decimal(-45))) # abs
1065
Mark Dickinson2fc92632008-02-06 22:10:50 +00001066 def test_nan_comparisons(self):
1067 n = Decimal('NaN')
1068 s = Decimal('sNaN')
1069 i = Decimal('Inf')
1070 f = Decimal('2')
1071 for x, y in [(n, n), (n, i), (i, n), (n, f), (f, n),
1072 (s, n), (n, s), (s, i), (i, s), (s, f), (f, s), (s, s)]:
Benjamin Peterson5c8da862009-06-30 22:57:08 +00001073 self.assertTrue(x != y)
1074 self.assertTrue(not (x == y))
1075 self.assertTrue(not (x < y))
1076 self.assertTrue(not (x <= y))
1077 self.assertTrue(not (x > y))
1078 self.assertTrue(not (x >= y))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001079
1080# The following are two functions used to test threading in the next class
1081
1082def thfunc1(cls):
1083 d1 = Decimal(1)
1084 d3 = Decimal(3)
Facundo Batista64156672008-03-22 02:45:37 +00001085 test1 = d1/d3
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001086 cls.synchro.wait()
Facundo Batista64156672008-03-22 02:45:37 +00001087 test2 = d1/d3
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001088 cls.finish1.set()
Facundo Batista64156672008-03-22 02:45:37 +00001089
Facundo Batistaee340e52008-05-02 17:39:00 +00001090 cls.assertEqual(test1, Decimal('0.3333333333333333333333333333'))
1091 cls.assertEqual(test2, Decimal('0.3333333333333333333333333333'))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001092 return
1093
1094def thfunc2(cls):
1095 d1 = Decimal(1)
1096 d3 = Decimal(3)
Facundo Batista64156672008-03-22 02:45:37 +00001097 test1 = d1/d3
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001098 thiscontext = getcontext()
1099 thiscontext.prec = 18
Facundo Batista64156672008-03-22 02:45:37 +00001100 test2 = d1/d3
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001101 cls.synchro.set()
1102 cls.finish2.set()
Facundo Batista64156672008-03-22 02:45:37 +00001103
Facundo Batistaee340e52008-05-02 17:39:00 +00001104 cls.assertEqual(test1, Decimal('0.3333333333333333333333333333'))
Facundo Batista64156672008-03-22 02:45:37 +00001105 cls.assertEqual(test2, Decimal('0.333333333333333333'))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001106 return
1107
1108
1109class DecimalUseOfContextTest(unittest.TestCase):
1110 '''Unit tests for Use of Context cases in Decimal.'''
1111
Raymond Hettinger7e71fa52004-12-18 19:07:19 +00001112 try:
1113 import threading
1114 except ImportError:
1115 threading = None
1116
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001117 # Take care executing this test from IDLE, there's an issue in threading
1118 # that hangs IDLE and I couldn't find it
1119
1120 def test_threading(self):
1121 #Test the "threading isolation" of a Context.
1122
1123 self.synchro = threading.Event()
1124 self.finish1 = threading.Event()
1125 self.finish2 = threading.Event()
1126
1127 th1 = threading.Thread(target=thfunc1, args=(self,))
1128 th2 = threading.Thread(target=thfunc2, args=(self,))
1129
1130 th1.start()
1131 th2.start()
1132
1133 self.finish1.wait()
Thomas Woutersb3e6e8c2007-09-19 17:27:29 +00001134 self.finish2.wait()
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001135 return
1136
Raymond Hettinger7e71fa52004-12-18 19:07:19 +00001137 if threading is None:
1138 del test_threading
1139
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001140
1141class DecimalUsabilityTest(unittest.TestCase):
1142 '''Unit tests for Usability cases of Decimal.'''
1143
1144 def test_comparison_operators(self):
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001145
1146 da = Decimal('23.42')
1147 db = Decimal('23.42')
1148 dc = Decimal('45')
1149
1150 #two Decimals
Benjamin Peterson5c8da862009-06-30 22:57:08 +00001151 self.assertTrue(dc > da)
1152 self.assertTrue(dc >= da)
1153 self.assertTrue(da < dc)
1154 self.assertTrue(da <= dc)
1155 self.assertTrue(da == db)
1156 self.assertTrue(da != dc)
1157 self.assertTrue(da <= db)
1158 self.assertTrue(da >= db)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001159 self.assertEqual(cmp(dc,da), 1)
1160 self.assertEqual(cmp(da,dc), -1)
1161 self.assertEqual(cmp(da,db), 0)
1162
1163 #a Decimal and an int
Benjamin Peterson5c8da862009-06-30 22:57:08 +00001164 self.assertTrue(dc > 23)
1165 self.assertTrue(23 < dc)
1166 self.assertTrue(dc == 45)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001167 self.assertEqual(cmp(dc,23), 1)
1168 self.assertEqual(cmp(23,dc), -1)
1169 self.assertEqual(cmp(dc,45), 0)
1170
1171 #a Decimal and uncomparable
Raymond Hettinger0aeac102004-07-05 22:53:03 +00001172 self.assertNotEqual(da, 'ugly')
1173 self.assertNotEqual(da, 32.7)
1174 self.assertNotEqual(da, object())
1175 self.assertNotEqual(da, object)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001176
Raymond Hettinger0aeac102004-07-05 22:53:03 +00001177 # sortable
1178 a = map(Decimal, xrange(100))
1179 b = a[:]
1180 random.shuffle(a)
1181 a.sort()
1182 self.assertEqual(a, b)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001183
Facundo Batista353750c2007-09-13 18:13:15 +00001184 # with None
1185 self.assertFalse(Decimal(1) < None)
1186 self.assertTrue(Decimal(1) > None)
1187
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001188 def test_copy_and_deepcopy_methods(self):
1189 d = Decimal('43.24')
1190 c = copy.copy(d)
1191 self.assertEqual(id(c), id(d))
1192 dc = copy.deepcopy(d)
1193 self.assertEqual(id(dc), id(d))
1194
1195 def test_hash_method(self):
1196 #just that it's hashable
1197 hash(Decimal(23))
Facundo Batista8c202442007-09-19 17:53:25 +00001198
1199 test_values = [Decimal(sign*(2**m + n))
1200 for m in [0, 14, 15, 16, 17, 30, 31,
1201 32, 33, 62, 63, 64, 65, 66]
1202 for n in range(-10, 10)
1203 for sign in [-1, 1]]
1204 test_values.extend([
1205 Decimal("-0"), # zeros
1206 Decimal("0.00"),
1207 Decimal("-0.000"),
1208 Decimal("0E10"),
1209 Decimal("-0E12"),
1210 Decimal("10.0"), # negative exponent
1211 Decimal("-23.00000"),
1212 Decimal("1230E100"), # positive exponent
1213 Decimal("-4.5678E50"),
1214 # a value for which hash(n) != hash(n % (2**64-1))
1215 # in Python pre-2.6
1216 Decimal(2**64 + 2**32 - 1),
1217 # selection of values which fail with the old (before
1218 # version 2.6) long.__hash__
1219 Decimal("1.634E100"),
1220 Decimal("90.697E100"),
1221 Decimal("188.83E100"),
1222 Decimal("1652.9E100"),
1223 Decimal("56531E100"),
1224 ])
1225
1226 # check that hash(d) == hash(int(d)) for integral values
1227 for value in test_values:
1228 self.assertEqual(hash(value), hash(int(value)))
1229
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001230 #the same hash that to an int
1231 self.assertEqual(hash(Decimal(23)), hash(23))
Raymond Hettingerbea3f6f2005-03-15 04:59:17 +00001232 self.assertRaises(TypeError, hash, Decimal('NaN'))
Benjamin Peterson5c8da862009-06-30 22:57:08 +00001233 self.assertTrue(hash(Decimal('Inf')))
1234 self.assertTrue(hash(Decimal('-Inf')))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001235
Facundo Batista52b25792008-01-08 12:25:20 +00001236 # check that the value of the hash doesn't depend on the
1237 # current context (issue #1757)
1238 c = getcontext()
1239 old_precision = c.prec
1240 x = Decimal("123456789.1")
1241
1242 c.prec = 6
1243 h1 = hash(x)
1244 c.prec = 10
1245 h2 = hash(x)
1246 c.prec = 16
1247 h3 = hash(x)
1248
1249 self.assertEqual(h1, h2)
1250 self.assertEqual(h1, h3)
1251 c.prec = old_precision
1252
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001253 def test_min_and_max_methods(self):
1254
1255 d1 = Decimal('15.32')
1256 d2 = Decimal('28.5')
1257 l1 = 15
1258 l2 = 28
1259
1260 #between Decimals
Benjamin Peterson5c8da862009-06-30 22:57:08 +00001261 self.assertTrue(min(d1,d2) is d1)
1262 self.assertTrue(min(d2,d1) is d1)
1263 self.assertTrue(max(d1,d2) is d2)
1264 self.assertTrue(max(d2,d1) is d2)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001265
1266 #between Decimal and long
Benjamin Peterson5c8da862009-06-30 22:57:08 +00001267 self.assertTrue(min(d1,l2) is d1)
1268 self.assertTrue(min(l2,d1) is d1)
1269 self.assertTrue(max(l1,d2) is d2)
1270 self.assertTrue(max(d2,l1) is d2)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001271
1272 def test_as_nonzero(self):
1273 #as false
Benjamin Peterson5c8da862009-06-30 22:57:08 +00001274 self.assertFalse(Decimal(0))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001275 #as true
Benjamin Peterson5c8da862009-06-30 22:57:08 +00001276 self.assertTrue(Decimal('0.372'))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001277
1278 def test_tostring_methods(self):
1279 #Test str and repr methods.
1280
1281 d = Decimal('15.32')
1282 self.assertEqual(str(d), '15.32') # str
Raymond Hettingerabe32372008-02-14 02:41:22 +00001283 self.assertEqual(repr(d), "Decimal('15.32')") # repr
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001284
Mark Dickinson8e85ffa2008-03-25 18:47:59 +00001285 # result type of string methods should be str, not unicode
1286 unicode_inputs = [u'123.4', u'0.5E2', u'Infinity', u'sNaN',
1287 u'-0.0E100', u'-NaN001', u'-Inf']
1288
1289 for u in unicode_inputs:
1290 d = Decimal(u)
1291 self.assertEqual(type(str(d)), str)
1292 self.assertEqual(type(repr(d)), str)
1293 self.assertEqual(type(d.to_eng_string()), str)
1294
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001295 def test_tonum_methods(self):
1296 #Test float, int and long methods.
1297
1298 d1 = Decimal('66')
1299 d2 = Decimal('15.32')
1300
1301 #int
1302 self.assertEqual(int(d1), 66)
1303 self.assertEqual(int(d2), 15)
1304
1305 #long
1306 self.assertEqual(long(d1), 66)
1307 self.assertEqual(long(d2), 15)
1308
1309 #float
1310 self.assertEqual(float(d1), 66)
1311 self.assertEqual(float(d2), 15.32)
1312
1313 def test_eval_round_trip(self):
1314
1315 #with zero
1316 d = Decimal( (0, (0,), 0) )
1317 self.assertEqual(d, eval(repr(d)))
1318
1319 #int
1320 d = Decimal( (1, (4, 5), 0) )
1321 self.assertEqual(d, eval(repr(d)))
1322
1323 #float
1324 d = Decimal( (0, (4, 5, 3, 4), -2) )
1325 self.assertEqual(d, eval(repr(d)))
1326
1327 #weird
1328 d = Decimal( (1, (4, 3, 4, 9, 1, 3, 5, 3, 4), -25) )
1329 self.assertEqual(d, eval(repr(d)))
1330
1331 def test_as_tuple(self):
1332
1333 #with zero
1334 d = Decimal(0)
1335 self.assertEqual(d.as_tuple(), (0, (0,), 0) )
1336
1337 #int
1338 d = Decimal(-45)
1339 self.assertEqual(d.as_tuple(), (1, (4, 5), 0) )
1340
1341 #complicated string
1342 d = Decimal("-4.34913534E-17")
1343 self.assertEqual(d.as_tuple(), (1, (4, 3, 4, 9, 1, 3, 5, 3, 4), -25) )
1344
1345 #inf
1346 d = Decimal("Infinity")
1347 self.assertEqual(d.as_tuple(), (0, (0,), 'F') )
1348
Facundo Batista9b5e2312007-10-19 19:25:57 +00001349 #leading zeros in coefficient should be stripped
1350 d = Decimal( (0, (0, 0, 4, 0, 5, 3, 4), -2) )
1351 self.assertEqual(d.as_tuple(), (0, (4, 0, 5, 3, 4), -2) )
1352 d = Decimal( (1, (0, 0, 0), 37) )
1353 self.assertEqual(d.as_tuple(), (1, (0,), 37))
1354 d = Decimal( (1, (), 37) )
1355 self.assertEqual(d.as_tuple(), (1, (0,), 37))
1356
1357 #leading zeros in NaN diagnostic info should be stripped
1358 d = Decimal( (0, (0, 0, 4, 0, 5, 3, 4), 'n') )
1359 self.assertEqual(d.as_tuple(), (0, (4, 0, 5, 3, 4), 'n') )
1360 d = Decimal( (1, (0, 0, 0), 'N') )
1361 self.assertEqual(d.as_tuple(), (1, (), 'N') )
1362 d = Decimal( (1, (), 'n') )
1363 self.assertEqual(d.as_tuple(), (1, (), 'n') )
1364
1365 #coefficient in infinity should be ignored
1366 d = Decimal( (0, (4, 5, 3, 4), 'F') )
1367 self.assertEqual(d.as_tuple(), (0, (0,), 'F'))
1368 d = Decimal( (1, (0, 2, 7, 1), 'F') )
1369 self.assertEqual(d.as_tuple(), (1, (0,), 'F'))
1370
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001371 def test_immutability_operations(self):
1372 # Do operations and check that it didn't change change internal objects.
1373
1374 d1 = Decimal('-25e55')
1375 b1 = Decimal('-25e55')
Facundo Batista353750c2007-09-13 18:13:15 +00001376 d2 = Decimal('33e+33')
1377 b2 = Decimal('33e+33')
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001378
1379 def checkSameDec(operation, useOther=False):
1380 if useOther:
1381 eval("d1." + operation + "(d2)")
1382 self.assertEqual(d1._sign, b1._sign)
1383 self.assertEqual(d1._int, b1._int)
1384 self.assertEqual(d1._exp, b1._exp)
1385 self.assertEqual(d2._sign, b2._sign)
1386 self.assertEqual(d2._int, b2._int)
1387 self.assertEqual(d2._exp, b2._exp)
1388 else:
1389 eval("d1." + operation + "()")
1390 self.assertEqual(d1._sign, b1._sign)
1391 self.assertEqual(d1._int, b1._int)
1392 self.assertEqual(d1._exp, b1._exp)
1393 return
1394
1395 Decimal(d1)
1396 self.assertEqual(d1._sign, b1._sign)
1397 self.assertEqual(d1._int, b1._int)
1398 self.assertEqual(d1._exp, b1._exp)
1399
1400 checkSameDec("__abs__")
1401 checkSameDec("__add__", True)
1402 checkSameDec("__div__", True)
1403 checkSameDec("__divmod__", True)
Mark Dickinson2fc92632008-02-06 22:10:50 +00001404 checkSameDec("__eq__", True)
1405 checkSameDec("__ne__", True)
1406 checkSameDec("__le__", True)
1407 checkSameDec("__lt__", True)
1408 checkSameDec("__ge__", True)
1409 checkSameDec("__gt__", True)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001410 checkSameDec("__float__")
1411 checkSameDec("__floordiv__", True)
1412 checkSameDec("__hash__")
1413 checkSameDec("__int__")
Raymond Hettinger5a053642008-01-24 19:05:29 +00001414 checkSameDec("__trunc__")
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001415 checkSameDec("__long__")
1416 checkSameDec("__mod__", True)
1417 checkSameDec("__mul__", True)
1418 checkSameDec("__neg__")
1419 checkSameDec("__nonzero__")
1420 checkSameDec("__pos__")
1421 checkSameDec("__pow__", True)
1422 checkSameDec("__radd__", True)
1423 checkSameDec("__rdiv__", True)
1424 checkSameDec("__rdivmod__", True)
1425 checkSameDec("__repr__")
1426 checkSameDec("__rfloordiv__", True)
1427 checkSameDec("__rmod__", True)
1428 checkSameDec("__rmul__", True)
1429 checkSameDec("__rpow__", True)
1430 checkSameDec("__rsub__", True)
1431 checkSameDec("__str__")
1432 checkSameDec("__sub__", True)
1433 checkSameDec("__truediv__", True)
1434 checkSameDec("adjusted")
1435 checkSameDec("as_tuple")
1436 checkSameDec("compare", True)
1437 checkSameDec("max", True)
1438 checkSameDec("min", True)
1439 checkSameDec("normalize")
1440 checkSameDec("quantize", True)
1441 checkSameDec("remainder_near", True)
1442 checkSameDec("same_quantum", True)
1443 checkSameDec("sqrt")
1444 checkSameDec("to_eng_string")
1445 checkSameDec("to_integral")
1446
Facundo Batista6c398da2007-09-17 17:30:13 +00001447 def test_subclassing(self):
1448 # Different behaviours when subclassing Decimal
1449
1450 class MyDecimal(Decimal):
1451 pass
1452
1453 d1 = MyDecimal(1)
1454 d2 = MyDecimal(2)
1455 d = d1 + d2
1456 self.assertTrue(type(d) is Decimal)
1457
1458 d = d1.max(d2)
1459 self.assertTrue(type(d) is Decimal)
1460
Mark Dickinson3b24ccb2008-03-25 14:33:23 +00001461 def test_implicit_context(self):
1462 # Check results when context given implicitly. (Issue 2478)
1463 c = getcontext()
1464 self.assertEqual(str(Decimal(0).sqrt()),
1465 str(c.sqrt(Decimal(0))))
1466
Facundo Batista6c398da2007-09-17 17:30:13 +00001467
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001468class DecimalPythonAPItests(unittest.TestCase):
1469
Raymond Hettinger2c8585b2009-02-03 03:37:03 +00001470 def test_abc(self):
Benjamin Peterson5c8da862009-06-30 22:57:08 +00001471 self.assertTrue(issubclass(Decimal, numbers.Number))
1472 self.assertTrue(not issubclass(Decimal, numbers.Real))
1473 self.assertTrue(isinstance(Decimal(0), numbers.Number))
1474 self.assertTrue(not isinstance(Decimal(0), numbers.Real))
Raymond Hettinger2c8585b2009-02-03 03:37:03 +00001475
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001476 def test_pickle(self):
1477 d = Decimal('-3.141590000')
1478 p = pickle.dumps(d)
1479 e = pickle.loads(p)
1480 self.assertEqual(d, e)
1481
Raymond Hettinger5548be22004-07-05 18:49:38 +00001482 def test_int(self):
Raymond Hettinger605ed022004-11-24 07:28:48 +00001483 for x in range(-250, 250):
1484 s = '%0.2f' % (x / 100.0)
Raymond Hettinger5548be22004-07-05 18:49:38 +00001485 # should work the same as for floats
1486 self.assertEqual(int(Decimal(s)), int(float(s)))
Raymond Hettinger605ed022004-11-24 07:28:48 +00001487 # should work the same as to_integral in the ROUND_DOWN mode
Raymond Hettinger5548be22004-07-05 18:49:38 +00001488 d = Decimal(s)
Raymond Hettinger605ed022004-11-24 07:28:48 +00001489 r = d.to_integral(ROUND_DOWN)
Raymond Hettinger5548be22004-07-05 18:49:38 +00001490 self.assertEqual(Decimal(int(d)), r)
1491
Mark Dickinson968f1692009-09-07 18:04:58 +00001492 self.assertRaises(ValueError, int, Decimal('-nan'))
1493 self.assertRaises(ValueError, int, Decimal('snan'))
1494 self.assertRaises(OverflowError, int, Decimal('inf'))
1495 self.assertRaises(OverflowError, int, Decimal('-inf'))
1496
1497 self.assertRaises(ValueError, long, Decimal('-nan'))
1498 self.assertRaises(ValueError, long, Decimal('snan'))
1499 self.assertRaises(OverflowError, long, Decimal('inf'))
1500 self.assertRaises(OverflowError, long, Decimal('-inf'))
1501
Raymond Hettinger5a053642008-01-24 19:05:29 +00001502 def test_trunc(self):
1503 for x in range(-250, 250):
1504 s = '%0.2f' % (x / 100.0)
1505 # should work the same as for floats
1506 self.assertEqual(int(Decimal(s)), int(float(s)))
1507 # should work the same as to_integral in the ROUND_DOWN mode
1508 d = Decimal(s)
1509 r = d.to_integral(ROUND_DOWN)
Jeffrey Yasskinca2b69f2008-02-01 06:22:46 +00001510 self.assertEqual(Decimal(math.trunc(d)), r)
Raymond Hettinger5a053642008-01-24 19:05:29 +00001511
Raymond Hettingerf4d85972009-01-03 19:02:23 +00001512 def test_from_float(self):
1513
1514 class MyDecimal(Decimal):
1515 pass
1516
1517 r = MyDecimal.from_float(0.1)
1518 self.assertEqual(type(r), MyDecimal)
1519 self.assertEqual(str(r),
1520 '0.1000000000000000055511151231257827021181583404541015625')
1521 bigint = 12345678901234567890123456789
1522 self.assertEqual(MyDecimal.from_float(bigint), MyDecimal(bigint))
Benjamin Peterson5c8da862009-06-30 22:57:08 +00001523 self.assertTrue(MyDecimal.from_float(float('nan')).is_qnan())
1524 self.assertTrue(MyDecimal.from_float(float('inf')).is_infinite())
1525 self.assertTrue(MyDecimal.from_float(float('-inf')).is_infinite())
Raymond Hettingerf4d85972009-01-03 19:02:23 +00001526 self.assertEqual(str(MyDecimal.from_float(float('nan'))),
1527 str(Decimal('NaN')))
1528 self.assertEqual(str(MyDecimal.from_float(float('inf'))),
1529 str(Decimal('Infinity')))
1530 self.assertEqual(str(MyDecimal.from_float(float('-inf'))),
1531 str(Decimal('-Infinity')))
1532 self.assertRaises(TypeError, MyDecimal.from_float, 'abc')
1533 for i in range(200):
1534 x = random.expovariate(0.01) * (random.random() * 2.0 - 1.0)
1535 self.assertEqual(x, float(MyDecimal.from_float(x))) # roundtrip
1536
1537 def test_create_decimal_from_float(self):
1538 context = Context(prec=5, rounding=ROUND_DOWN)
1539 self.assertEqual(
1540 context.create_decimal_from_float(math.pi),
1541 Decimal('3.1415')
1542 )
1543 context = Context(prec=5, rounding=ROUND_UP)
1544 self.assertEqual(
1545 context.create_decimal_from_float(math.pi),
1546 Decimal('3.1416')
1547 )
1548 context = Context(prec=5, traps=[Inexact])
1549 self.assertRaises(
1550 Inexact,
1551 context.create_decimal_from_float,
1552 math.pi
1553 )
1554 self.assertEqual(repr(context.create_decimal_from_float(-0.0)),
1555 "Decimal('-0')")
1556 self.assertEqual(repr(context.create_decimal_from_float(1.0)),
1557 "Decimal('1')")
1558 self.assertEqual(repr(context.create_decimal_from_float(10)),
1559 "Decimal('10')")
1560
Raymond Hettingerd9c0a7a2004-07-03 10:02:28 +00001561class ContextAPItests(unittest.TestCase):
1562
1563 def test_pickle(self):
1564 c = Context()
1565 e = pickle.loads(pickle.dumps(c))
1566 for k in vars(c):
1567 v1 = vars(c)[k]
1568 v2 = vars(e)[k]
1569 self.assertEqual(v1, v2)
1570
Raymond Hettinger0aeac102004-07-05 22:53:03 +00001571 def test_equality_with_other_types(self):
Benjamin Peterson5c8da862009-06-30 22:57:08 +00001572 self.assertTrue(Decimal(10) in ['a', 1.0, Decimal(10), (1,2), {}])
1573 self.assertTrue(Decimal(10) not in ['a', 1.0, (1,2), {}])
Raymond Hettinger0aeac102004-07-05 22:53:03 +00001574
Raymond Hettinger955d2b22004-08-08 20:17:45 +00001575 def test_copy(self):
1576 # All copies should be deep
1577 c = Context()
1578 d = c.copy()
1579 self.assertNotEqual(id(c), id(d))
1580 self.assertNotEqual(id(c.flags), id(d.flags))
1581 self.assertNotEqual(id(c.traps), id(d.traps))
1582
Nick Coghlan8b6999b2006-08-31 12:00:43 +00001583class WithStatementTest(unittest.TestCase):
1584 # Can't do these as docstrings until Python 2.6
1585 # as doctest can't handle __future__ statements
Nick Coghlan8b6999b2006-08-31 12:00:43 +00001586
1587 def test_localcontext(self):
Nick Coghlanced12182006-09-02 03:54:17 +00001588 # Use a copy of the current context in the block
Nick Coghlan8b6999b2006-08-31 12:00:43 +00001589 orig_ctx = getcontext()
1590 with localcontext() as enter_ctx:
1591 set_ctx = getcontext()
1592 final_ctx = getcontext()
Benjamin Peterson5c8da862009-06-30 22:57:08 +00001593 self.assertTrue(orig_ctx is final_ctx, 'did not restore context correctly')
1594 self.assertTrue(orig_ctx is not set_ctx, 'did not copy the context')
1595 self.assertTrue(set_ctx is enter_ctx, '__enter__ returned wrong context')
Nick Coghlan8b6999b2006-08-31 12:00:43 +00001596
1597 def test_localcontextarg(self):
Nick Coghlanced12182006-09-02 03:54:17 +00001598 # Use a copy of the supplied context in the block
Nick Coghlan8b6999b2006-08-31 12:00:43 +00001599 orig_ctx = getcontext()
1600 new_ctx = Context(prec=42)
1601 with localcontext(new_ctx) as enter_ctx:
1602 set_ctx = getcontext()
1603 final_ctx = getcontext()
Benjamin Peterson5c8da862009-06-30 22:57:08 +00001604 self.assertTrue(orig_ctx is final_ctx, 'did not restore context correctly')
1605 self.assertTrue(set_ctx.prec == new_ctx.prec, 'did not set correct context')
1606 self.assertTrue(new_ctx is not set_ctx, 'did not copy the context')
1607 self.assertTrue(set_ctx is enter_ctx, '__enter__ returned wrong context')
Nick Coghlan8b6999b2006-08-31 12:00:43 +00001608
Facundo Batista353750c2007-09-13 18:13:15 +00001609class ContextFlags(unittest.TestCase):
1610 def test_flags_irrelevant(self):
1611 # check that the result (numeric result + flags raised) of an
1612 # arithmetic operation doesn't depend on the current flags
1613
1614 context = Context(prec=9, Emin = -999999999, Emax = 999999999,
1615 rounding=ROUND_HALF_EVEN, traps=[], flags=[])
1616
1617 # operations that raise various flags, in the form (function, arglist)
1618 operations = [
1619 (context._apply, [Decimal("100E-1000000009")]),
1620 (context.sqrt, [Decimal(2)]),
1621 (context.add, [Decimal("1.23456789"), Decimal("9.87654321")]),
1622 (context.multiply, [Decimal("1.23456789"), Decimal("9.87654321")]),
1623 (context.subtract, [Decimal("1.23456789"), Decimal("9.87654321")]),
1624 ]
1625
1626 # try various flags individually, then a whole lot at once
1627 flagsets = [[Inexact], [Rounded], [Underflow], [Clamped], [Subnormal],
1628 [Inexact, Rounded, Underflow, Clamped, Subnormal]]
1629
1630 for fn, args in operations:
1631 # find answer and flags raised using a clean context
1632 context.clear_flags()
1633 ans = fn(*args)
1634 flags = [k for k, v in context.flags.items() if v]
1635
1636 for extra_flags in flagsets:
1637 # set flags, before calling operation
1638 context.clear_flags()
1639 for flag in extra_flags:
1640 context._raise_error(flag)
1641 new_ans = fn(*args)
1642
1643 # flags that we expect to be set after the operation
1644 expected_flags = list(flags)
1645 for flag in extra_flags:
1646 if flag not in expected_flags:
1647 expected_flags.append(flag)
1648 expected_flags.sort()
1649
1650 # flags we actually got
1651 new_flags = [k for k,v in context.flags.items() if v]
1652 new_flags.sort()
1653
1654 self.assertEqual(ans, new_ans,
1655 "operation produces different answers depending on flags set: " +
1656 "expected %s, got %s." % (ans, new_ans))
1657 self.assertEqual(new_flags, expected_flags,
1658 "operation raises different flags depending on flags set: " +
1659 "expected %s, got %s" % (expected_flags, new_flags))
1660
1661def test_main(arith=False, verbose=None, todo_tests=None, debug=None):
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001662 """ Execute the tests.
1663
Raymond Hettingered20ad82004-09-04 20:09:13 +00001664 Runs all arithmetic tests if arith is True or if the "decimal" resource
1665 is enabled in regrtest.py
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001666 """
Raymond Hettingered20ad82004-09-04 20:09:13 +00001667
Neal Norwitzce4a9c92006-04-09 08:36:46 +00001668 init()
Facundo Batista353750c2007-09-13 18:13:15 +00001669 global TEST_ALL, DEBUG
Raymond Hettingered20ad82004-09-04 20:09:13 +00001670 TEST_ALL = arith or is_resource_enabled('decimal')
Facundo Batista353750c2007-09-13 18:13:15 +00001671 DEBUG = debug
Raymond Hettingered20ad82004-09-04 20:09:13 +00001672
Facundo Batista353750c2007-09-13 18:13:15 +00001673 if todo_tests is None:
1674 test_classes = [
1675 DecimalExplicitConstructionTest,
1676 DecimalImplicitConstructionTest,
1677 DecimalArithmeticOperatorsTest,
Mark Dickinson1ddf1d82008-02-29 02:16:37 +00001678 DecimalFormatTest,
Facundo Batista353750c2007-09-13 18:13:15 +00001679 DecimalUseOfContextTest,
1680 DecimalUsabilityTest,
1681 DecimalPythonAPItests,
1682 ContextAPItests,
1683 DecimalTest,
1684 WithStatementTest,
1685 ContextFlags
1686 ]
1687 else:
1688 test_classes = [DecimalTest]
1689
1690 # Dynamically build custom test definition for each file in the test
1691 # directory and add the definitions to the DecimalTest class. This
1692 # procedure insures that new files do not get skipped.
1693 for filename in os.listdir(directory):
1694 if '.decTest' not in filename or filename.startswith("."):
1695 continue
1696 head, tail = filename.split('.')
1697 if todo_tests is not None and head not in todo_tests:
1698 continue
1699 tester = lambda self, f=filename: self.eval_file(directory + f)
1700 setattr(DecimalTest, 'test_' + head, tester)
1701 del filename, head, tail, tester
1702
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001703
Tim Peters46cc7022006-03-31 04:11:16 +00001704 try:
1705 run_unittest(*test_classes)
Facundo Batista353750c2007-09-13 18:13:15 +00001706 if todo_tests is None:
1707 import decimal as DecimalModule
1708 run_doctest(DecimalModule, verbose)
Tim Peters46cc7022006-03-31 04:11:16 +00001709 finally:
1710 setcontext(ORIGINAL_CONTEXT)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001711
1712if __name__ == '__main__':
Facundo Batista353750c2007-09-13 18:13:15 +00001713 import optparse
1714 p = optparse.OptionParser("test_decimal.py [--debug] [{--skip | test1 [test2 [...]]}]")
1715 p.add_option('--debug', '-d', action='store_true', help='shows the test number and context before each test')
1716 p.add_option('--skip', '-s', action='store_true', help='skip over 90% of the arithmetic tests')
1717 (opt, args) = p.parse_args()
1718
1719 if opt.skip:
1720 test_main(arith=False, verbose=True)
1721 elif args:
1722 test_main(arith=True, verbose=True, todo_tests=args, debug=opt.debug)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001723 else:
Facundo Batista353750c2007-09-13 18:13:15 +00001724 test_main(arith=True, verbose=True)