blob: 0be901abb13087b5763928cd83a7f4df01cac67c [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 Dickinson1ddf1d82008-02-29 02:16:37 +0000763 ]
764 for fmt, d, result in test_values:
765 self.assertEqual(format(Decimal(d), fmt), result)
766
Mark Dickinson277859d2009-03-17 23:03:46 +0000767 def test_n_format(self):
768 try:
769 from locale import CHAR_MAX
770 except ImportError:
771 return
772
773 # Set up some localeconv-like dictionaries
774 en_US = {
775 'decimal_point' : '.',
776 'grouping' : [3, 3, 0],
777 'thousands_sep': ','
778 }
779
780 fr_FR = {
781 'decimal_point' : ',',
782 'grouping' : [CHAR_MAX],
783 'thousands_sep' : ''
784 }
785
786 ru_RU = {
787 'decimal_point' : ',',
788 'grouping' : [3, 3, 0],
789 'thousands_sep' : ' '
790 }
791
792 crazy = {
793 'decimal_point' : '&',
794 'grouping' : [1, 4, 2, CHAR_MAX],
795 'thousands_sep' : '-'
796 }
797
798
799 def get_fmt(x, locale, fmt='n'):
800 return Decimal.__format__(Decimal(x), fmt, _localeconv=locale)
801
802 self.assertEqual(get_fmt(Decimal('12.7'), en_US), '12.7')
803 self.assertEqual(get_fmt(Decimal('12.7'), fr_FR), '12,7')
804 self.assertEqual(get_fmt(Decimal('12.7'), ru_RU), '12,7')
805 self.assertEqual(get_fmt(Decimal('12.7'), crazy), '1-2&7')
806
807 self.assertEqual(get_fmt(123456789, en_US), '123,456,789')
808 self.assertEqual(get_fmt(123456789, fr_FR), '123456789')
809 self.assertEqual(get_fmt(123456789, ru_RU), '123 456 789')
810 self.assertEqual(get_fmt(1234567890123, crazy), '123456-78-9012-3')
811
812 self.assertEqual(get_fmt(123456789, en_US, '.6n'), '1.23457e+8')
813 self.assertEqual(get_fmt(123456789, fr_FR, '.6n'), '1,23457e+8')
814 self.assertEqual(get_fmt(123456789, ru_RU, '.6n'), '1,23457e+8')
815 self.assertEqual(get_fmt(123456789, crazy, '.6n'), '1&23457e+8')
816
Mark Dickinsonb14514a2009-03-18 08:22:51 +0000817 # zero padding
818 self.assertEqual(get_fmt(1234, fr_FR, '03n'), '1234')
819 self.assertEqual(get_fmt(1234, fr_FR, '04n'), '1234')
820 self.assertEqual(get_fmt(1234, fr_FR, '05n'), '01234')
821 self.assertEqual(get_fmt(1234, fr_FR, '06n'), '001234')
822
823 self.assertEqual(get_fmt(12345, en_US, '05n'), '12,345')
824 self.assertEqual(get_fmt(12345, en_US, '06n'), '12,345')
825 self.assertEqual(get_fmt(12345, en_US, '07n'), '012,345')
826 self.assertEqual(get_fmt(12345, en_US, '08n'), '0,012,345')
827 self.assertEqual(get_fmt(12345, en_US, '09n'), '0,012,345')
828 self.assertEqual(get_fmt(12345, en_US, '010n'), '00,012,345')
829
830 self.assertEqual(get_fmt(123456, crazy, '06n'), '1-2345-6')
831 self.assertEqual(get_fmt(123456, crazy, '07n'), '1-2345-6')
832 self.assertEqual(get_fmt(123456, crazy, '08n'), '1-2345-6')
833 self.assertEqual(get_fmt(123456, crazy, '09n'), '01-2345-6')
834 self.assertEqual(get_fmt(123456, crazy, '010n'), '0-01-2345-6')
835 self.assertEqual(get_fmt(123456, crazy, '011n'), '0-01-2345-6')
836 self.assertEqual(get_fmt(123456, crazy, '012n'), '00-01-2345-6')
837 self.assertEqual(get_fmt(123456, crazy, '013n'), '000-01-2345-6')
838
Mark Dickinson277859d2009-03-17 23:03:46 +0000839
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000840class DecimalArithmeticOperatorsTest(unittest.TestCase):
841 '''Unit tests for all arithmetic operators, binary and unary.'''
842
843 def test_addition(self):
844
845 d1 = Decimal('-11.1')
846 d2 = Decimal('22.2')
847
848 #two Decimals
849 self.assertEqual(d1+d2, Decimal('11.1'))
850 self.assertEqual(d2+d1, Decimal('11.1'))
851
852 #with other type, left
853 c = d1 + 5
854 self.assertEqual(c, Decimal('-6.1'))
855 self.assertEqual(type(c), type(d1))
856
857 #with other type, right
858 c = 5 + d1
859 self.assertEqual(c, Decimal('-6.1'))
860 self.assertEqual(type(c), type(d1))
861
862 #inline with decimal
863 d1 += d2
864 self.assertEqual(d1, Decimal('11.1'))
865
866 #inline with other type
867 d1 += 5
868 self.assertEqual(d1, Decimal('16.1'))
869
870 def test_subtraction(self):
871
872 d1 = Decimal('-11.1')
873 d2 = Decimal('22.2')
874
875 #two Decimals
876 self.assertEqual(d1-d2, Decimal('-33.3'))
877 self.assertEqual(d2-d1, Decimal('33.3'))
878
879 #with other type, left
880 c = d1 - 5
881 self.assertEqual(c, Decimal('-16.1'))
882 self.assertEqual(type(c), type(d1))
883
884 #with other type, right
885 c = 5 - d1
886 self.assertEqual(c, Decimal('16.1'))
887 self.assertEqual(type(c), type(d1))
888
889 #inline with decimal
890 d1 -= d2
891 self.assertEqual(d1, Decimal('-33.3'))
892
893 #inline with other type
894 d1 -= 5
895 self.assertEqual(d1, Decimal('-38.3'))
896
897 def test_multiplication(self):
898
899 d1 = Decimal('-5')
900 d2 = Decimal('3')
901
902 #two Decimals
903 self.assertEqual(d1*d2, Decimal('-15'))
904 self.assertEqual(d2*d1, Decimal('-15'))
905
906 #with other type, left
907 c = d1 * 5
908 self.assertEqual(c, Decimal('-25'))
909 self.assertEqual(type(c), type(d1))
910
911 #with other type, right
912 c = 5 * d1
913 self.assertEqual(c, Decimal('-25'))
914 self.assertEqual(type(c), type(d1))
915
916 #inline with decimal
917 d1 *= d2
918 self.assertEqual(d1, Decimal('-15'))
919
920 #inline with other type
921 d1 *= 5
922 self.assertEqual(d1, Decimal('-75'))
923
924 def test_division(self):
925
926 d1 = Decimal('-5')
927 d2 = Decimal('2')
928
929 #two Decimals
930 self.assertEqual(d1/d2, Decimal('-2.5'))
931 self.assertEqual(d2/d1, Decimal('-0.4'))
932
933 #with other type, left
934 c = d1 / 4
935 self.assertEqual(c, Decimal('-1.25'))
936 self.assertEqual(type(c), type(d1))
937
938 #with other type, right
939 c = 4 / d1
940 self.assertEqual(c, Decimal('-0.8'))
941 self.assertEqual(type(c), type(d1))
942
943 #inline with decimal
944 d1 /= d2
945 self.assertEqual(d1, Decimal('-2.5'))
946
947 #inline with other type
948 d1 /= 4
949 self.assertEqual(d1, Decimal('-0.625'))
950
951 def test_floor_division(self):
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000952
953 d1 = Decimal('5')
954 d2 = Decimal('2')
955
956 #two Decimals
957 self.assertEqual(d1//d2, Decimal('2'))
958 self.assertEqual(d2//d1, Decimal('0'))
959
960 #with other type, left
961 c = d1 // 4
962 self.assertEqual(c, Decimal('1'))
963 self.assertEqual(type(c), type(d1))
964
965 #with other type, right
966 c = 7 // d1
967 self.assertEqual(c, Decimal('1'))
968 self.assertEqual(type(c), type(d1))
969
970 #inline with decimal
971 d1 //= d2
972 self.assertEqual(d1, Decimal('2'))
973
974 #inline with other type
975 d1 //= 2
976 self.assertEqual(d1, Decimal('1'))
977
978 def test_powering(self):
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000979
980 d1 = Decimal('5')
981 d2 = Decimal('2')
982
983 #two Decimals
984 self.assertEqual(d1**d2, Decimal('25'))
985 self.assertEqual(d2**d1, Decimal('32'))
986
987 #with other type, left
988 c = d1 ** 4
989 self.assertEqual(c, Decimal('625'))
990 self.assertEqual(type(c), type(d1))
991
992 #with other type, right
993 c = 7 ** d1
994 self.assertEqual(c, Decimal('16807'))
995 self.assertEqual(type(c), type(d1))
996
997 #inline with decimal
998 d1 **= d2
999 self.assertEqual(d1, Decimal('25'))
1000
1001 #inline with other type
1002 d1 **= 4
1003 self.assertEqual(d1, Decimal('390625'))
1004
1005 def test_module(self):
1006
1007 d1 = Decimal('5')
1008 d2 = Decimal('2')
1009
1010 #two Decimals
1011 self.assertEqual(d1%d2, Decimal('1'))
1012 self.assertEqual(d2%d1, Decimal('2'))
1013
1014 #with other type, left
1015 c = d1 % 4
1016 self.assertEqual(c, Decimal('1'))
1017 self.assertEqual(type(c), type(d1))
1018
1019 #with other type, right
1020 c = 7 % d1
1021 self.assertEqual(c, Decimal('2'))
1022 self.assertEqual(type(c), type(d1))
1023
1024 #inline with decimal
1025 d1 %= d2
1026 self.assertEqual(d1, Decimal('1'))
1027
1028 #inline with other type
1029 d1 %= 4
1030 self.assertEqual(d1, Decimal('1'))
1031
1032 def test_floor_div_module(self):
1033
1034 d1 = Decimal('5')
1035 d2 = Decimal('2')
1036
1037 #two Decimals
1038 (p, q) = divmod(d1, d2)
1039 self.assertEqual(p, Decimal('2'))
1040 self.assertEqual(q, Decimal('1'))
1041 self.assertEqual(type(p), type(d1))
1042 self.assertEqual(type(q), type(d1))
1043
1044 #with other type, left
1045 (p, q) = divmod(d1, 4)
1046 self.assertEqual(p, Decimal('1'))
1047 self.assertEqual(q, Decimal('1'))
1048 self.assertEqual(type(p), type(d1))
1049 self.assertEqual(type(q), type(d1))
1050
1051 #with other type, right
1052 (p, q) = divmod(7, d1)
1053 self.assertEqual(p, Decimal('1'))
1054 self.assertEqual(q, Decimal('2'))
1055 self.assertEqual(type(p), type(d1))
1056 self.assertEqual(type(q), type(d1))
1057
1058 def test_unary_operators(self):
1059 self.assertEqual(+Decimal(45), Decimal(+45)) # +
1060 self.assertEqual(-Decimal(45), Decimal(-45)) # -
1061 self.assertEqual(abs(Decimal(45)), abs(Decimal(-45))) # abs
1062
Mark Dickinson2fc92632008-02-06 22:10:50 +00001063 def test_nan_comparisons(self):
1064 n = Decimal('NaN')
1065 s = Decimal('sNaN')
1066 i = Decimal('Inf')
1067 f = Decimal('2')
1068 for x, y in [(n, n), (n, i), (i, n), (n, f), (f, n),
1069 (s, n), (n, s), (s, i), (i, s), (s, f), (f, s), (s, s)]:
Benjamin Peterson5c8da862009-06-30 22:57:08 +00001070 self.assertTrue(x != y)
1071 self.assertTrue(not (x == y))
1072 self.assertTrue(not (x < y))
1073 self.assertTrue(not (x <= y))
1074 self.assertTrue(not (x > y))
1075 self.assertTrue(not (x >= y))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001076
1077# The following are two functions used to test threading in the next class
1078
1079def thfunc1(cls):
1080 d1 = Decimal(1)
1081 d3 = Decimal(3)
Facundo Batista64156672008-03-22 02:45:37 +00001082 test1 = d1/d3
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001083 cls.synchro.wait()
Facundo Batista64156672008-03-22 02:45:37 +00001084 test2 = d1/d3
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001085 cls.finish1.set()
Facundo Batista64156672008-03-22 02:45:37 +00001086
Facundo Batistaee340e52008-05-02 17:39:00 +00001087 cls.assertEqual(test1, Decimal('0.3333333333333333333333333333'))
1088 cls.assertEqual(test2, Decimal('0.3333333333333333333333333333'))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001089 return
1090
1091def thfunc2(cls):
1092 d1 = Decimal(1)
1093 d3 = Decimal(3)
Facundo Batista64156672008-03-22 02:45:37 +00001094 test1 = d1/d3
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001095 thiscontext = getcontext()
1096 thiscontext.prec = 18
Facundo Batista64156672008-03-22 02:45:37 +00001097 test2 = d1/d3
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001098 cls.synchro.set()
1099 cls.finish2.set()
Facundo Batista64156672008-03-22 02:45:37 +00001100
Facundo Batistaee340e52008-05-02 17:39:00 +00001101 cls.assertEqual(test1, Decimal('0.3333333333333333333333333333'))
Facundo Batista64156672008-03-22 02:45:37 +00001102 cls.assertEqual(test2, Decimal('0.333333333333333333'))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001103 return
1104
1105
1106class DecimalUseOfContextTest(unittest.TestCase):
1107 '''Unit tests for Use of Context cases in Decimal.'''
1108
Raymond Hettinger7e71fa52004-12-18 19:07:19 +00001109 try:
1110 import threading
1111 except ImportError:
1112 threading = None
1113
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001114 # Take care executing this test from IDLE, there's an issue in threading
1115 # that hangs IDLE and I couldn't find it
1116
1117 def test_threading(self):
1118 #Test the "threading isolation" of a Context.
1119
1120 self.synchro = threading.Event()
1121 self.finish1 = threading.Event()
1122 self.finish2 = threading.Event()
1123
1124 th1 = threading.Thread(target=thfunc1, args=(self,))
1125 th2 = threading.Thread(target=thfunc2, args=(self,))
1126
1127 th1.start()
1128 th2.start()
1129
1130 self.finish1.wait()
Thomas Woutersb3e6e8c2007-09-19 17:27:29 +00001131 self.finish2.wait()
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001132 return
1133
Raymond Hettinger7e71fa52004-12-18 19:07:19 +00001134 if threading is None:
1135 del test_threading
1136
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001137
1138class DecimalUsabilityTest(unittest.TestCase):
1139 '''Unit tests for Usability cases of Decimal.'''
1140
1141 def test_comparison_operators(self):
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001142
1143 da = Decimal('23.42')
1144 db = Decimal('23.42')
1145 dc = Decimal('45')
1146
1147 #two Decimals
Benjamin Peterson5c8da862009-06-30 22:57:08 +00001148 self.assertTrue(dc > da)
1149 self.assertTrue(dc >= da)
1150 self.assertTrue(da < dc)
1151 self.assertTrue(da <= dc)
1152 self.assertTrue(da == db)
1153 self.assertTrue(da != dc)
1154 self.assertTrue(da <= db)
1155 self.assertTrue(da >= db)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001156 self.assertEqual(cmp(dc,da), 1)
1157 self.assertEqual(cmp(da,dc), -1)
1158 self.assertEqual(cmp(da,db), 0)
1159
1160 #a Decimal and an int
Benjamin Peterson5c8da862009-06-30 22:57:08 +00001161 self.assertTrue(dc > 23)
1162 self.assertTrue(23 < dc)
1163 self.assertTrue(dc == 45)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001164 self.assertEqual(cmp(dc,23), 1)
1165 self.assertEqual(cmp(23,dc), -1)
1166 self.assertEqual(cmp(dc,45), 0)
1167
1168 #a Decimal and uncomparable
Raymond Hettinger0aeac102004-07-05 22:53:03 +00001169 self.assertNotEqual(da, 'ugly')
1170 self.assertNotEqual(da, 32.7)
1171 self.assertNotEqual(da, object())
1172 self.assertNotEqual(da, object)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001173
Raymond Hettinger0aeac102004-07-05 22:53:03 +00001174 # sortable
1175 a = map(Decimal, xrange(100))
1176 b = a[:]
1177 random.shuffle(a)
1178 a.sort()
1179 self.assertEqual(a, b)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001180
Facundo Batista353750c2007-09-13 18:13:15 +00001181 # with None
1182 self.assertFalse(Decimal(1) < None)
1183 self.assertTrue(Decimal(1) > None)
1184
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001185 def test_copy_and_deepcopy_methods(self):
1186 d = Decimal('43.24')
1187 c = copy.copy(d)
1188 self.assertEqual(id(c), id(d))
1189 dc = copy.deepcopy(d)
1190 self.assertEqual(id(dc), id(d))
1191
1192 def test_hash_method(self):
1193 #just that it's hashable
1194 hash(Decimal(23))
Facundo Batista8c202442007-09-19 17:53:25 +00001195
1196 test_values = [Decimal(sign*(2**m + n))
1197 for m in [0, 14, 15, 16, 17, 30, 31,
1198 32, 33, 62, 63, 64, 65, 66]
1199 for n in range(-10, 10)
1200 for sign in [-1, 1]]
1201 test_values.extend([
1202 Decimal("-0"), # zeros
1203 Decimal("0.00"),
1204 Decimal("-0.000"),
1205 Decimal("0E10"),
1206 Decimal("-0E12"),
1207 Decimal("10.0"), # negative exponent
1208 Decimal("-23.00000"),
1209 Decimal("1230E100"), # positive exponent
1210 Decimal("-4.5678E50"),
1211 # a value for which hash(n) != hash(n % (2**64-1))
1212 # in Python pre-2.6
1213 Decimal(2**64 + 2**32 - 1),
1214 # selection of values which fail with the old (before
1215 # version 2.6) long.__hash__
1216 Decimal("1.634E100"),
1217 Decimal("90.697E100"),
1218 Decimal("188.83E100"),
1219 Decimal("1652.9E100"),
1220 Decimal("56531E100"),
1221 ])
1222
1223 # check that hash(d) == hash(int(d)) for integral values
1224 for value in test_values:
1225 self.assertEqual(hash(value), hash(int(value)))
1226
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001227 #the same hash that to an int
1228 self.assertEqual(hash(Decimal(23)), hash(23))
Raymond Hettingerbea3f6f2005-03-15 04:59:17 +00001229 self.assertRaises(TypeError, hash, Decimal('NaN'))
Benjamin Peterson5c8da862009-06-30 22:57:08 +00001230 self.assertTrue(hash(Decimal('Inf')))
1231 self.assertTrue(hash(Decimal('-Inf')))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001232
Facundo Batista52b25792008-01-08 12:25:20 +00001233 # check that the value of the hash doesn't depend on the
1234 # current context (issue #1757)
1235 c = getcontext()
1236 old_precision = c.prec
1237 x = Decimal("123456789.1")
1238
1239 c.prec = 6
1240 h1 = hash(x)
1241 c.prec = 10
1242 h2 = hash(x)
1243 c.prec = 16
1244 h3 = hash(x)
1245
1246 self.assertEqual(h1, h2)
1247 self.assertEqual(h1, h3)
1248 c.prec = old_precision
1249
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001250 def test_min_and_max_methods(self):
1251
1252 d1 = Decimal('15.32')
1253 d2 = Decimal('28.5')
1254 l1 = 15
1255 l2 = 28
1256
1257 #between Decimals
Benjamin Peterson5c8da862009-06-30 22:57:08 +00001258 self.assertTrue(min(d1,d2) is d1)
1259 self.assertTrue(min(d2,d1) is d1)
1260 self.assertTrue(max(d1,d2) is d2)
1261 self.assertTrue(max(d2,d1) is d2)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001262
1263 #between Decimal and long
Benjamin Peterson5c8da862009-06-30 22:57:08 +00001264 self.assertTrue(min(d1,l2) is d1)
1265 self.assertTrue(min(l2,d1) is d1)
1266 self.assertTrue(max(l1,d2) is d2)
1267 self.assertTrue(max(d2,l1) is d2)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001268
1269 def test_as_nonzero(self):
1270 #as false
Benjamin Peterson5c8da862009-06-30 22:57:08 +00001271 self.assertFalse(Decimal(0))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001272 #as true
Benjamin Peterson5c8da862009-06-30 22:57:08 +00001273 self.assertTrue(Decimal('0.372'))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001274
1275 def test_tostring_methods(self):
1276 #Test str and repr methods.
1277
1278 d = Decimal('15.32')
1279 self.assertEqual(str(d), '15.32') # str
Raymond Hettingerabe32372008-02-14 02:41:22 +00001280 self.assertEqual(repr(d), "Decimal('15.32')") # repr
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001281
Mark Dickinson8e85ffa2008-03-25 18:47:59 +00001282 # result type of string methods should be str, not unicode
1283 unicode_inputs = [u'123.4', u'0.5E2', u'Infinity', u'sNaN',
1284 u'-0.0E100', u'-NaN001', u'-Inf']
1285
1286 for u in unicode_inputs:
1287 d = Decimal(u)
1288 self.assertEqual(type(str(d)), str)
1289 self.assertEqual(type(repr(d)), str)
1290 self.assertEqual(type(d.to_eng_string()), str)
1291
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001292 def test_tonum_methods(self):
1293 #Test float, int and long methods.
1294
1295 d1 = Decimal('66')
1296 d2 = Decimal('15.32')
1297
1298 #int
1299 self.assertEqual(int(d1), 66)
1300 self.assertEqual(int(d2), 15)
1301
1302 #long
1303 self.assertEqual(long(d1), 66)
1304 self.assertEqual(long(d2), 15)
1305
1306 #float
1307 self.assertEqual(float(d1), 66)
1308 self.assertEqual(float(d2), 15.32)
1309
1310 def test_eval_round_trip(self):
1311
1312 #with zero
1313 d = Decimal( (0, (0,), 0) )
1314 self.assertEqual(d, eval(repr(d)))
1315
1316 #int
1317 d = Decimal( (1, (4, 5), 0) )
1318 self.assertEqual(d, eval(repr(d)))
1319
1320 #float
1321 d = Decimal( (0, (4, 5, 3, 4), -2) )
1322 self.assertEqual(d, eval(repr(d)))
1323
1324 #weird
1325 d = Decimal( (1, (4, 3, 4, 9, 1, 3, 5, 3, 4), -25) )
1326 self.assertEqual(d, eval(repr(d)))
1327
1328 def test_as_tuple(self):
1329
1330 #with zero
1331 d = Decimal(0)
1332 self.assertEqual(d.as_tuple(), (0, (0,), 0) )
1333
1334 #int
1335 d = Decimal(-45)
1336 self.assertEqual(d.as_tuple(), (1, (4, 5), 0) )
1337
1338 #complicated string
1339 d = Decimal("-4.34913534E-17")
1340 self.assertEqual(d.as_tuple(), (1, (4, 3, 4, 9, 1, 3, 5, 3, 4), -25) )
1341
1342 #inf
1343 d = Decimal("Infinity")
1344 self.assertEqual(d.as_tuple(), (0, (0,), 'F') )
1345
Facundo Batista9b5e2312007-10-19 19:25:57 +00001346 #leading zeros in coefficient should be stripped
1347 d = Decimal( (0, (0, 0, 4, 0, 5, 3, 4), -2) )
1348 self.assertEqual(d.as_tuple(), (0, (4, 0, 5, 3, 4), -2) )
1349 d = Decimal( (1, (0, 0, 0), 37) )
1350 self.assertEqual(d.as_tuple(), (1, (0,), 37))
1351 d = Decimal( (1, (), 37) )
1352 self.assertEqual(d.as_tuple(), (1, (0,), 37))
1353
1354 #leading zeros in NaN diagnostic info should be stripped
1355 d = Decimal( (0, (0, 0, 4, 0, 5, 3, 4), 'n') )
1356 self.assertEqual(d.as_tuple(), (0, (4, 0, 5, 3, 4), 'n') )
1357 d = Decimal( (1, (0, 0, 0), 'N') )
1358 self.assertEqual(d.as_tuple(), (1, (), 'N') )
1359 d = Decimal( (1, (), 'n') )
1360 self.assertEqual(d.as_tuple(), (1, (), 'n') )
1361
1362 #coefficient in infinity should be ignored
1363 d = Decimal( (0, (4, 5, 3, 4), 'F') )
1364 self.assertEqual(d.as_tuple(), (0, (0,), 'F'))
1365 d = Decimal( (1, (0, 2, 7, 1), 'F') )
1366 self.assertEqual(d.as_tuple(), (1, (0,), 'F'))
1367
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001368 def test_immutability_operations(self):
1369 # Do operations and check that it didn't change change internal objects.
1370
1371 d1 = Decimal('-25e55')
1372 b1 = Decimal('-25e55')
Facundo Batista353750c2007-09-13 18:13:15 +00001373 d2 = Decimal('33e+33')
1374 b2 = Decimal('33e+33')
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001375
1376 def checkSameDec(operation, useOther=False):
1377 if useOther:
1378 eval("d1." + operation + "(d2)")
1379 self.assertEqual(d1._sign, b1._sign)
1380 self.assertEqual(d1._int, b1._int)
1381 self.assertEqual(d1._exp, b1._exp)
1382 self.assertEqual(d2._sign, b2._sign)
1383 self.assertEqual(d2._int, b2._int)
1384 self.assertEqual(d2._exp, b2._exp)
1385 else:
1386 eval("d1." + operation + "()")
1387 self.assertEqual(d1._sign, b1._sign)
1388 self.assertEqual(d1._int, b1._int)
1389 self.assertEqual(d1._exp, b1._exp)
1390 return
1391
1392 Decimal(d1)
1393 self.assertEqual(d1._sign, b1._sign)
1394 self.assertEqual(d1._int, b1._int)
1395 self.assertEqual(d1._exp, b1._exp)
1396
1397 checkSameDec("__abs__")
1398 checkSameDec("__add__", True)
1399 checkSameDec("__div__", True)
1400 checkSameDec("__divmod__", True)
Mark Dickinson2fc92632008-02-06 22:10:50 +00001401 checkSameDec("__eq__", True)
1402 checkSameDec("__ne__", True)
1403 checkSameDec("__le__", True)
1404 checkSameDec("__lt__", True)
1405 checkSameDec("__ge__", True)
1406 checkSameDec("__gt__", True)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001407 checkSameDec("__float__")
1408 checkSameDec("__floordiv__", True)
1409 checkSameDec("__hash__")
1410 checkSameDec("__int__")
Raymond Hettinger5a053642008-01-24 19:05:29 +00001411 checkSameDec("__trunc__")
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001412 checkSameDec("__long__")
1413 checkSameDec("__mod__", True)
1414 checkSameDec("__mul__", True)
1415 checkSameDec("__neg__")
1416 checkSameDec("__nonzero__")
1417 checkSameDec("__pos__")
1418 checkSameDec("__pow__", True)
1419 checkSameDec("__radd__", True)
1420 checkSameDec("__rdiv__", True)
1421 checkSameDec("__rdivmod__", True)
1422 checkSameDec("__repr__")
1423 checkSameDec("__rfloordiv__", True)
1424 checkSameDec("__rmod__", True)
1425 checkSameDec("__rmul__", True)
1426 checkSameDec("__rpow__", True)
1427 checkSameDec("__rsub__", True)
1428 checkSameDec("__str__")
1429 checkSameDec("__sub__", True)
1430 checkSameDec("__truediv__", True)
1431 checkSameDec("adjusted")
1432 checkSameDec("as_tuple")
1433 checkSameDec("compare", True)
1434 checkSameDec("max", True)
1435 checkSameDec("min", True)
1436 checkSameDec("normalize")
1437 checkSameDec("quantize", True)
1438 checkSameDec("remainder_near", True)
1439 checkSameDec("same_quantum", True)
1440 checkSameDec("sqrt")
1441 checkSameDec("to_eng_string")
1442 checkSameDec("to_integral")
1443
Facundo Batista6c398da2007-09-17 17:30:13 +00001444 def test_subclassing(self):
1445 # Different behaviours when subclassing Decimal
1446
1447 class MyDecimal(Decimal):
1448 pass
1449
1450 d1 = MyDecimal(1)
1451 d2 = MyDecimal(2)
1452 d = d1 + d2
1453 self.assertTrue(type(d) is Decimal)
1454
1455 d = d1.max(d2)
1456 self.assertTrue(type(d) is Decimal)
1457
Mark Dickinson3b24ccb2008-03-25 14:33:23 +00001458 def test_implicit_context(self):
1459 # Check results when context given implicitly. (Issue 2478)
1460 c = getcontext()
1461 self.assertEqual(str(Decimal(0).sqrt()),
1462 str(c.sqrt(Decimal(0))))
1463
Facundo Batista6c398da2007-09-17 17:30:13 +00001464
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001465class DecimalPythonAPItests(unittest.TestCase):
1466
Raymond Hettinger2c8585b2009-02-03 03:37:03 +00001467 def test_abc(self):
Benjamin Peterson5c8da862009-06-30 22:57:08 +00001468 self.assertTrue(issubclass(Decimal, numbers.Number))
1469 self.assertTrue(not issubclass(Decimal, numbers.Real))
1470 self.assertTrue(isinstance(Decimal(0), numbers.Number))
1471 self.assertTrue(not isinstance(Decimal(0), numbers.Real))
Raymond Hettinger2c8585b2009-02-03 03:37:03 +00001472
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001473 def test_pickle(self):
1474 d = Decimal('-3.141590000')
1475 p = pickle.dumps(d)
1476 e = pickle.loads(p)
1477 self.assertEqual(d, e)
1478
Raymond Hettinger5548be22004-07-05 18:49:38 +00001479 def test_int(self):
Raymond Hettinger605ed022004-11-24 07:28:48 +00001480 for x in range(-250, 250):
1481 s = '%0.2f' % (x / 100.0)
Raymond Hettinger5548be22004-07-05 18:49:38 +00001482 # should work the same as for floats
1483 self.assertEqual(int(Decimal(s)), int(float(s)))
Raymond Hettinger605ed022004-11-24 07:28:48 +00001484 # should work the same as to_integral in the ROUND_DOWN mode
Raymond Hettinger5548be22004-07-05 18:49:38 +00001485 d = Decimal(s)
Raymond Hettinger605ed022004-11-24 07:28:48 +00001486 r = d.to_integral(ROUND_DOWN)
Raymond Hettinger5548be22004-07-05 18:49:38 +00001487 self.assertEqual(Decimal(int(d)), r)
1488
Raymond Hettinger5a053642008-01-24 19:05:29 +00001489 def test_trunc(self):
1490 for x in range(-250, 250):
1491 s = '%0.2f' % (x / 100.0)
1492 # should work the same as for floats
1493 self.assertEqual(int(Decimal(s)), int(float(s)))
1494 # should work the same as to_integral in the ROUND_DOWN mode
1495 d = Decimal(s)
1496 r = d.to_integral(ROUND_DOWN)
Jeffrey Yasskinca2b69f2008-02-01 06:22:46 +00001497 self.assertEqual(Decimal(math.trunc(d)), r)
Raymond Hettinger5a053642008-01-24 19:05:29 +00001498
Raymond Hettingerf4d85972009-01-03 19:02:23 +00001499 def test_from_float(self):
1500
1501 class MyDecimal(Decimal):
1502 pass
1503
1504 r = MyDecimal.from_float(0.1)
1505 self.assertEqual(type(r), MyDecimal)
1506 self.assertEqual(str(r),
1507 '0.1000000000000000055511151231257827021181583404541015625')
1508 bigint = 12345678901234567890123456789
1509 self.assertEqual(MyDecimal.from_float(bigint), MyDecimal(bigint))
Benjamin Peterson5c8da862009-06-30 22:57:08 +00001510 self.assertTrue(MyDecimal.from_float(float('nan')).is_qnan())
1511 self.assertTrue(MyDecimal.from_float(float('inf')).is_infinite())
1512 self.assertTrue(MyDecimal.from_float(float('-inf')).is_infinite())
Raymond Hettingerf4d85972009-01-03 19:02:23 +00001513 self.assertEqual(str(MyDecimal.from_float(float('nan'))),
1514 str(Decimal('NaN')))
1515 self.assertEqual(str(MyDecimal.from_float(float('inf'))),
1516 str(Decimal('Infinity')))
1517 self.assertEqual(str(MyDecimal.from_float(float('-inf'))),
1518 str(Decimal('-Infinity')))
1519 self.assertRaises(TypeError, MyDecimal.from_float, 'abc')
1520 for i in range(200):
1521 x = random.expovariate(0.01) * (random.random() * 2.0 - 1.0)
1522 self.assertEqual(x, float(MyDecimal.from_float(x))) # roundtrip
1523
1524 def test_create_decimal_from_float(self):
1525 context = Context(prec=5, rounding=ROUND_DOWN)
1526 self.assertEqual(
1527 context.create_decimal_from_float(math.pi),
1528 Decimal('3.1415')
1529 )
1530 context = Context(prec=5, rounding=ROUND_UP)
1531 self.assertEqual(
1532 context.create_decimal_from_float(math.pi),
1533 Decimal('3.1416')
1534 )
1535 context = Context(prec=5, traps=[Inexact])
1536 self.assertRaises(
1537 Inexact,
1538 context.create_decimal_from_float,
1539 math.pi
1540 )
1541 self.assertEqual(repr(context.create_decimal_from_float(-0.0)),
1542 "Decimal('-0')")
1543 self.assertEqual(repr(context.create_decimal_from_float(1.0)),
1544 "Decimal('1')")
1545 self.assertEqual(repr(context.create_decimal_from_float(10)),
1546 "Decimal('10')")
1547
Raymond Hettingerd9c0a7a2004-07-03 10:02:28 +00001548class ContextAPItests(unittest.TestCase):
1549
1550 def test_pickle(self):
1551 c = Context()
1552 e = pickle.loads(pickle.dumps(c))
1553 for k in vars(c):
1554 v1 = vars(c)[k]
1555 v2 = vars(e)[k]
1556 self.assertEqual(v1, v2)
1557
Raymond Hettinger0aeac102004-07-05 22:53:03 +00001558 def test_equality_with_other_types(self):
Benjamin Peterson5c8da862009-06-30 22:57:08 +00001559 self.assertTrue(Decimal(10) in ['a', 1.0, Decimal(10), (1,2), {}])
1560 self.assertTrue(Decimal(10) not in ['a', 1.0, (1,2), {}])
Raymond Hettinger0aeac102004-07-05 22:53:03 +00001561
Raymond Hettinger955d2b22004-08-08 20:17:45 +00001562 def test_copy(self):
1563 # All copies should be deep
1564 c = Context()
1565 d = c.copy()
1566 self.assertNotEqual(id(c), id(d))
1567 self.assertNotEqual(id(c.flags), id(d.flags))
1568 self.assertNotEqual(id(c.traps), id(d.traps))
1569
Nick Coghlan8b6999b2006-08-31 12:00:43 +00001570class WithStatementTest(unittest.TestCase):
1571 # Can't do these as docstrings until Python 2.6
1572 # as doctest can't handle __future__ statements
Nick Coghlan8b6999b2006-08-31 12:00:43 +00001573
1574 def test_localcontext(self):
Nick Coghlanced12182006-09-02 03:54:17 +00001575 # Use a copy of the current context in the block
Nick Coghlan8b6999b2006-08-31 12:00:43 +00001576 orig_ctx = getcontext()
1577 with localcontext() as enter_ctx:
1578 set_ctx = getcontext()
1579 final_ctx = getcontext()
Benjamin Peterson5c8da862009-06-30 22:57:08 +00001580 self.assertTrue(orig_ctx is final_ctx, 'did not restore context correctly')
1581 self.assertTrue(orig_ctx is not set_ctx, 'did not copy the context')
1582 self.assertTrue(set_ctx is enter_ctx, '__enter__ returned wrong context')
Nick Coghlan8b6999b2006-08-31 12:00:43 +00001583
1584 def test_localcontextarg(self):
Nick Coghlanced12182006-09-02 03:54:17 +00001585 # Use a copy of the supplied context in the block
Nick Coghlan8b6999b2006-08-31 12:00:43 +00001586 orig_ctx = getcontext()
1587 new_ctx = Context(prec=42)
1588 with localcontext(new_ctx) as enter_ctx:
1589 set_ctx = getcontext()
1590 final_ctx = getcontext()
Benjamin Peterson5c8da862009-06-30 22:57:08 +00001591 self.assertTrue(orig_ctx is final_ctx, 'did not restore context correctly')
1592 self.assertTrue(set_ctx.prec == new_ctx.prec, 'did not set correct context')
1593 self.assertTrue(new_ctx is not set_ctx, 'did not copy the context')
1594 self.assertTrue(set_ctx is enter_ctx, '__enter__ returned wrong context')
Nick Coghlan8b6999b2006-08-31 12:00:43 +00001595
Facundo Batista353750c2007-09-13 18:13:15 +00001596class ContextFlags(unittest.TestCase):
1597 def test_flags_irrelevant(self):
1598 # check that the result (numeric result + flags raised) of an
1599 # arithmetic operation doesn't depend on the current flags
1600
1601 context = Context(prec=9, Emin = -999999999, Emax = 999999999,
1602 rounding=ROUND_HALF_EVEN, traps=[], flags=[])
1603
1604 # operations that raise various flags, in the form (function, arglist)
1605 operations = [
1606 (context._apply, [Decimal("100E-1000000009")]),
1607 (context.sqrt, [Decimal(2)]),
1608 (context.add, [Decimal("1.23456789"), Decimal("9.87654321")]),
1609 (context.multiply, [Decimal("1.23456789"), Decimal("9.87654321")]),
1610 (context.subtract, [Decimal("1.23456789"), Decimal("9.87654321")]),
1611 ]
1612
1613 # try various flags individually, then a whole lot at once
1614 flagsets = [[Inexact], [Rounded], [Underflow], [Clamped], [Subnormal],
1615 [Inexact, Rounded, Underflow, Clamped, Subnormal]]
1616
1617 for fn, args in operations:
1618 # find answer and flags raised using a clean context
1619 context.clear_flags()
1620 ans = fn(*args)
1621 flags = [k for k, v in context.flags.items() if v]
1622
1623 for extra_flags in flagsets:
1624 # set flags, before calling operation
1625 context.clear_flags()
1626 for flag in extra_flags:
1627 context._raise_error(flag)
1628 new_ans = fn(*args)
1629
1630 # flags that we expect to be set after the operation
1631 expected_flags = list(flags)
1632 for flag in extra_flags:
1633 if flag not in expected_flags:
1634 expected_flags.append(flag)
1635 expected_flags.sort()
1636
1637 # flags we actually got
1638 new_flags = [k for k,v in context.flags.items() if v]
1639 new_flags.sort()
1640
1641 self.assertEqual(ans, new_ans,
1642 "operation produces different answers depending on flags set: " +
1643 "expected %s, got %s." % (ans, new_ans))
1644 self.assertEqual(new_flags, expected_flags,
1645 "operation raises different flags depending on flags set: " +
1646 "expected %s, got %s" % (expected_flags, new_flags))
1647
1648def test_main(arith=False, verbose=None, todo_tests=None, debug=None):
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001649 """ Execute the tests.
1650
Raymond Hettingered20ad82004-09-04 20:09:13 +00001651 Runs all arithmetic tests if arith is True or if the "decimal" resource
1652 is enabled in regrtest.py
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001653 """
Raymond Hettingered20ad82004-09-04 20:09:13 +00001654
Neal Norwitzce4a9c92006-04-09 08:36:46 +00001655 init()
Facundo Batista353750c2007-09-13 18:13:15 +00001656 global TEST_ALL, DEBUG
Raymond Hettingered20ad82004-09-04 20:09:13 +00001657 TEST_ALL = arith or is_resource_enabled('decimal')
Facundo Batista353750c2007-09-13 18:13:15 +00001658 DEBUG = debug
Raymond Hettingered20ad82004-09-04 20:09:13 +00001659
Facundo Batista353750c2007-09-13 18:13:15 +00001660 if todo_tests is None:
1661 test_classes = [
1662 DecimalExplicitConstructionTest,
1663 DecimalImplicitConstructionTest,
1664 DecimalArithmeticOperatorsTest,
Mark Dickinson1ddf1d82008-02-29 02:16:37 +00001665 DecimalFormatTest,
Facundo Batista353750c2007-09-13 18:13:15 +00001666 DecimalUseOfContextTest,
1667 DecimalUsabilityTest,
1668 DecimalPythonAPItests,
1669 ContextAPItests,
1670 DecimalTest,
1671 WithStatementTest,
1672 ContextFlags
1673 ]
1674 else:
1675 test_classes = [DecimalTest]
1676
1677 # Dynamically build custom test definition for each file in the test
1678 # directory and add the definitions to the DecimalTest class. This
1679 # procedure insures that new files do not get skipped.
1680 for filename in os.listdir(directory):
1681 if '.decTest' not in filename or filename.startswith("."):
1682 continue
1683 head, tail = filename.split('.')
1684 if todo_tests is not None and head not in todo_tests:
1685 continue
1686 tester = lambda self, f=filename: self.eval_file(directory + f)
1687 setattr(DecimalTest, 'test_' + head, tester)
1688 del filename, head, tail, tester
1689
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001690
Tim Peters46cc7022006-03-31 04:11:16 +00001691 try:
1692 run_unittest(*test_classes)
Facundo Batista353750c2007-09-13 18:13:15 +00001693 if todo_tests is None:
1694 import decimal as DecimalModule
1695 run_doctest(DecimalModule, verbose)
Tim Peters46cc7022006-03-31 04:11:16 +00001696 finally:
1697 setcontext(ORIGINAL_CONTEXT)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001698
1699if __name__ == '__main__':
Facundo Batista353750c2007-09-13 18:13:15 +00001700 import optparse
1701 p = optparse.OptionParser("test_decimal.py [--debug] [{--skip | test1 [test2 [...]]}]")
1702 p.add_option('--debug', '-d', action='store_true', help='shows the test number and context before each test')
1703 p.add_option('--skip', '-s', action='store_true', help='skip over 90% of the arithmetic tests')
1704 (opt, args) = p.parse_args()
1705
1706 if opt.skip:
1707 test_main(arith=False, verbose=True)
1708 elif args:
1709 test_main(arith=True, verbose=True, todo_tests=args, debug=opt.debug)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001710 else:
Facundo Batista353750c2007-09-13 18:13:15 +00001711 test_main(arith=True, verbose=True)