blob: 1647212fa9c16863ab515d3a1072c442efb7e14f [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"""
Nick Coghlan8b6999b2006-08-31 12:00:43 +000026from __future__ import with_statement
Raymond Hettinger7c85fa42004-07-01 11:01:35 +000027
Raymond Hettinger7c85fa42004-07-01 11:01:35 +000028import unittest
29import glob
30import os, sys
31import pickle, copy
32from decimal import *
Tim Peters46cc7022006-03-31 04:11:16 +000033from test.test_support import (TestSkipped, run_unittest, run_doctest,
34 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()
49 DefaultContext.prec = 9
50 DefaultContext.rounding = ROUND_HALF_EVEN
51 DefaultContext.traps = dict.fromkeys(Signals, 0)
52 setcontext(DefaultContext)
Raymond Hettinger6ea48452004-07-03 12:26:21 +000053
Raymond Hettinger7c85fa42004-07-01 11:01:35 +000054TESTDATADIR = 'decimaltestdata'
Raymond Hettingerd9c0a7a2004-07-03 10:02:28 +000055if __name__ == '__main__':
56 file = sys.argv[0]
57else:
58 file = __file__
59testdir = os.path.dirname(file) or os.curdir
Raymond Hettinger267b8682005-03-27 10:47:39 +000060directory = testdir + os.sep + TESTDATADIR + os.sep
Raymond Hettinger7c85fa42004-07-01 11:01:35 +000061
Raymond Hettinger267b8682005-03-27 10:47:39 +000062skip_expected = not os.path.isdir(directory)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +000063
64# Make sure it actually raises errors when not expected and caught in flags
65# Slower, since it runs some things several times.
66EXTENDEDERRORTEST = False
67
Raymond Hettinger7c85fa42004-07-01 11:01:35 +000068#Map the test cases' error names to the actual errors
Raymond Hettinger7c85fa42004-07-01 11:01:35 +000069ErrorNames = {'clamped' : Clamped,
Raymond Hettinger5aa478b2004-07-09 10:02:53 +000070 'conversion_syntax' : InvalidOperation,
Raymond Hettinger7c85fa42004-07-01 11:01:35 +000071 'division_by_zero' : DivisionByZero,
Raymond Hettinger5aa478b2004-07-09 10:02:53 +000072 'division_impossible' : InvalidOperation,
73 'division_undefined' : InvalidOperation,
Raymond Hettinger7c85fa42004-07-01 11:01:35 +000074 'inexact' : Inexact,
Raymond Hettinger5aa478b2004-07-09 10:02:53 +000075 'invalid_context' : InvalidOperation,
Raymond Hettinger7c85fa42004-07-01 11:01:35 +000076 'invalid_operation' : InvalidOperation,
77 'overflow' : Overflow,
78 'rounded' : Rounded,
79 'subnormal' : Subnormal,
80 'underflow' : Underflow}
81
82
83def Nonfunction(*args):
84 """Doesn't do anything."""
85 return None
86
87RoundingDict = {'ceiling' : ROUND_CEILING, #Maps test-case names to roundings.
88 'down' : ROUND_DOWN,
89 'floor' : ROUND_FLOOR,
90 'half_down' : ROUND_HALF_DOWN,
91 'half_even' : ROUND_HALF_EVEN,
92 'half_up' : ROUND_HALF_UP,
Facundo Batista353750c2007-09-13 18:13:15 +000093 'up' : ROUND_UP,
94 '05up' : ROUND_05UP}
Raymond Hettinger7c85fa42004-07-01 11:01:35 +000095
96# Name adapter to be able to change the Decimal and Context
97# interface without changing the test files from Cowlishaw
98nameAdapter = {'toeng':'to_eng_string',
99 'tosci':'to_sci_string',
100 'samequantum':'same_quantum',
Facundo Batista353750c2007-09-13 18:13:15 +0000101 'tointegral':'to_integral_value',
102 'tointegralx':'to_integral_exact',
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000103 'remaindernear':'remainder_near',
104 'divideint':'divide_int',
105 'squareroot':'sqrt',
106 'apply':'_apply',
Facundo Batista353750c2007-09-13 18:13:15 +0000107 'class':'number_class',
108 'comparesig':'compare_signal',
109 'comparetotal':'compare_total',
110 'comparetotmag':'compare_total_mag',
111 'copyabs':'copy_abs',
112 'copy':'copy_decimal',
113 'copynegate':'copy_negate',
114 'copysign':'copy_sign',
115 'and':'logical_and',
116 'or':'logical_or',
117 'xor':'logical_xor',
118 'invert':'logical_invert',
119 'maxmag':'max_mag',
120 'minmag':'min_mag',
121 'nextminus':'next_minus',
122 'nextplus':'next_plus',
123 'nexttoward':'next_toward',
124 'reduce':'normalize',
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000125 }
126
Facundo Batista353750c2007-09-13 18:13:15 +0000127# For some operations (currently exp, ln, log10, power), the decNumber
128# reference implementation imposes additional restrictions on the
129# context and operands. These restrictions are not part of the
130# specification; however, the effect of these restrictions does show
131# up in some of the testcases. We skip testcases that violate these
132# restrictions, since Decimal behaves differently from decNumber for
133# these testcases so these testcases would otherwise fail.
134
135decNumberRestricted = ('power', 'ln', 'log10', 'exp')
136DEC_MAX_MATH = 999999
137def outside_decNumber_bounds(v, context):
138 if (context.prec > DEC_MAX_MATH or
139 context.Emax > DEC_MAX_MATH or
140 -context.Emin > DEC_MAX_MATH):
141 return True
142 if not v._is_special and v and (
143 len(v._int) > DEC_MAX_MATH or
144 v.adjusted() > DEC_MAX_MATH or
145 v.adjusted() < 1-2*DEC_MAX_MATH):
146 return True
147 return False
148
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000149class DecimalTest(unittest.TestCase):
150 """Class which tests the Decimal class against the test cases.
151
152 Changed for unittest.
153 """
154 def setUp(self):
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000155 self.context = Context()
Raymond Hettingerbf440692004-07-10 14:14:37 +0000156 for key in DefaultContext.traps.keys():
157 DefaultContext.traps[key] = 1
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000158 self.ignore_list = ['#']
159 # Basically, a # means return NaN InvalidOperation.
160 # Different from a sNaN in trim
161
162 self.ChangeDict = {'precision' : self.change_precision,
163 'rounding' : self.change_rounding_method,
164 'maxexponent' : self.change_max_exponent,
165 'minexponent' : self.change_min_exponent,
166 'clamp' : self.change_clamp}
167
168 def tearDown(self):
169 """Cleaning up enviroment."""
170 # leaving context in original state
Raymond Hettingerbf440692004-07-10 14:14:37 +0000171 for key in DefaultContext.traps.keys():
172 DefaultContext.traps[key] = 0
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000173 return
174
175 def eval_file(self, file):
176 global skip_expected
177 if skip_expected:
178 raise TestSkipped
179 return
180 for line in open(file).xreadlines():
181 line = line.replace('\r\n', '').replace('\n', '')
Raymond Hettinger5aa478b2004-07-09 10:02:53 +0000182 #print line
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000183 try:
184 t = self.eval_line(line)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000185 except DecimalException, exception:
186 #Exception raised where there shoudn't have been one.
187 self.fail('Exception "'+exception.__class__.__name__ + '" raised on line '+line)
188
189 return
190
191 def eval_line(self, s):
192 if s.find(' -> ') >= 0 and s[:2] != '--' and not s.startswith(' --'):
193 s = (s.split('->')[0] + '->' +
194 s.split('->')[1].split('--')[0]).strip()
195 else:
196 s = s.split('--')[0].strip()
197
198 for ignore in self.ignore_list:
199 if s.find(ignore) >= 0:
200 #print s.split()[0], 'NotImplemented--', ignore
201 return
202 if not s:
203 return
204 elif ':' in s:
205 return self.eval_directive(s)
206 else:
207 return self.eval_equation(s)
208
209 def eval_directive(self, s):
210 funct, value = map(lambda x: x.strip().lower(), s.split(':'))
211 if funct == 'rounding':
212 value = RoundingDict[value]
213 else:
214 try:
215 value = int(value)
216 except ValueError:
217 pass
218
219 funct = self.ChangeDict.get(funct, Nonfunction)
220 funct(value)
221
222 def eval_equation(self, s):
223 #global DEFAULT_PRECISION
224 #print DEFAULT_PRECISION
Raymond Hettingered20ad82004-09-04 20:09:13 +0000225
226 if not TEST_ALL and random.random() < 0.90:
227 return
228
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000229 try:
230 Sides = s.split('->')
231 L = Sides[0].strip().split()
232 id = L[0]
Facundo Batista353750c2007-09-13 18:13:15 +0000233 if DEBUG:
234 print "Test ", id,
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000235 funct = L[1].lower()
236 valstemp = L[2:]
237 L = Sides[1].strip().split()
238 ans = L[0]
239 exceptions = L[1:]
240 except (TypeError, AttributeError, IndexError):
Raymond Hettingerd87ac8f2004-07-09 10:52:54 +0000241 raise InvalidOperation
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000242 def FixQuotes(val):
243 val = val.replace("''", 'SingleQuote').replace('""', 'DoubleQuote')
244 val = val.replace("'", '').replace('"', '')
245 val = val.replace('SingleQuote', "'").replace('DoubleQuote', '"')
246 return val
247 fname = nameAdapter.get(funct, funct)
248 if fname == 'rescale':
249 return
250 funct = getattr(self.context, fname)
251 vals = []
252 conglomerate = ''
253 quote = 0
254 theirexceptions = [ErrorNames[x.lower()] for x in exceptions]
255
Raymond Hettingerd9c0a7a2004-07-03 10:02:28 +0000256 for exception in Signals:
Raymond Hettingerbf440692004-07-10 14:14:37 +0000257 self.context.traps[exception] = 1 #Catch these bugs...
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000258 for exception in theirexceptions:
Raymond Hettingerbf440692004-07-10 14:14:37 +0000259 self.context.traps[exception] = 0
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000260 for i, val in enumerate(valstemp):
261 if val.count("'") % 2 == 1:
262 quote = 1 - quote
263 if quote:
264 conglomerate = conglomerate + ' ' + val
265 continue
266 else:
267 val = conglomerate + val
268 conglomerate = ''
269 v = FixQuotes(val)
270 if fname in ('to_sci_string', 'to_eng_string'):
271 if EXTENDEDERRORTEST:
272 for error in theirexceptions:
Raymond Hettingerbf440692004-07-10 14:14:37 +0000273 self.context.traps[error] = 1
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000274 try:
275 funct(self.context.create_decimal(v))
276 except error:
277 pass
Raymond Hettingerd9c0a7a2004-07-03 10:02:28 +0000278 except Signals, e:
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000279 self.fail("Raised %s in %s when %s disabled" % \
280 (e, s, error))
281 else:
282 self.fail("Did not raise %s in %s" % (error, s))
Raymond Hettingerbf440692004-07-10 14:14:37 +0000283 self.context.traps[error] = 0
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000284 v = self.context.create_decimal(v)
285 else:
Facundo Batista353750c2007-09-13 18:13:15 +0000286 v = Decimal(v, self.context)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000287 vals.append(v)
288
289 ans = FixQuotes(ans)
290
Facundo Batista353750c2007-09-13 18:13:15 +0000291 # skip tests that are related to bounds imposed in the decNumber
292 # reference implementation
293 if fname in decNumberRestricted:
294 if fname == 'power':
295 if not (vals[1]._isinteger() and
296 -1999999997 <= vals[1] <= 999999999):
297 if outside_decNumber_bounds(vals[0], self.context) or \
298 outside_decNumber_bounds(vals[1], self.context):
299 #print "Skipping test %s" % s
300 return
301 else:
302 if outside_decNumber_bounds(vals[0], self.context):
303 #print "Skipping test %s" % s
304 return
305
306
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000307 if EXTENDEDERRORTEST and fname not in ('to_sci_string', 'to_eng_string'):
308 for error in theirexceptions:
Raymond Hettingerbf440692004-07-10 14:14:37 +0000309 self.context.traps[error] = 1
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000310 try:
311 funct(*vals)
312 except error:
313 pass
Raymond Hettingerd9c0a7a2004-07-03 10:02:28 +0000314 except Signals, e:
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000315 self.fail("Raised %s in %s when %s disabled" % \
316 (e, s, error))
317 else:
318 self.fail("Did not raise %s in %s" % (error, s))
Raymond Hettingerbf440692004-07-10 14:14:37 +0000319 self.context.traps[error] = 0
Facundo Batista353750c2007-09-13 18:13:15 +0000320 if DEBUG:
321 print "--", self.context
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000322 try:
323 result = str(funct(*vals))
324 if fname == 'same_quantum':
325 result = str(int(eval(result))) # 'True', 'False' -> '1', '0'
Raymond Hettingerd9c0a7a2004-07-03 10:02:28 +0000326 except Signals, error:
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000327 self.fail("Raised %s in %s" % (error, s))
328 except: #Catch any error long enough to state the test case.
329 print "ERROR:", s
330 raise
331
332 myexceptions = self.getexceptions()
Raymond Hettingerbf440692004-07-10 14:14:37 +0000333 self.context.clear_flags()
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000334
335 myexceptions.sort()
336 theirexceptions.sort()
337
338 self.assertEqual(result, ans,
339 'Incorrect answer for ' + s + ' -- got ' + result)
340 self.assertEqual(myexceptions, theirexceptions,
Facundo Batista353750c2007-09-13 18:13:15 +0000341 'Incorrect flags set in ' + s + ' -- got ' + str(myexceptions))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000342 return
343
344 def getexceptions(self):
Raymond Hettingerf63ba432004-08-17 05:42:09 +0000345 return [e for e in Signals if self.context.flags[e]]
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000346
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000347 def change_precision(self, prec):
348 self.context.prec = prec
349 def change_rounding_method(self, rounding):
350 self.context.rounding = rounding
351 def change_min_exponent(self, exp):
352 self.context.Emin = exp
353 def change_max_exponent(self, exp):
354 self.context.Emax = exp
355 def change_clamp(self, clamp):
356 self.context._clamp = clamp
357
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000358
359
360# The following classes test the behaviour of Decimal according to PEP 327
361
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000362class DecimalExplicitConstructionTest(unittest.TestCase):
363 '''Unit tests for Explicit Construction cases of Decimal.'''
364
365 def test_explicit_empty(self):
366 self.assertEqual(Decimal(), Decimal("0"))
367
368 def test_explicit_from_None(self):
369 self.assertRaises(TypeError, Decimal, None)
370
371 def test_explicit_from_int(self):
372
373 #positive
374 d = Decimal(45)
375 self.assertEqual(str(d), '45')
376
377 #very large positive
378 d = Decimal(500000123)
379 self.assertEqual(str(d), '500000123')
380
381 #negative
382 d = Decimal(-45)
383 self.assertEqual(str(d), '-45')
384
385 #zero
386 d = Decimal(0)
387 self.assertEqual(str(d), '0')
388
389 def test_explicit_from_string(self):
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000390
391 #empty
392 self.assertEqual(str(Decimal('')), 'NaN')
393
394 #int
395 self.assertEqual(str(Decimal('45')), '45')
396
397 #float
398 self.assertEqual(str(Decimal('45.34')), '45.34')
399
400 #engineer notation
401 self.assertEqual(str(Decimal('45e2')), '4.5E+3')
402
403 #just not a number
404 self.assertEqual(str(Decimal('ugly')), 'NaN')
405
406 def test_explicit_from_tuples(self):
407
408 #zero
409 d = Decimal( (0, (0,), 0) )
410 self.assertEqual(str(d), '0')
411
412 #int
413 d = Decimal( (1, (4, 5), 0) )
414 self.assertEqual(str(d), '-45')
415
416 #float
417 d = Decimal( (0, (4, 5, 3, 4), -2) )
418 self.assertEqual(str(d), '45.34')
419
420 #weird
421 d = Decimal( (1, (4, 3, 4, 9, 1, 3, 5, 3, 4), -25) )
422 self.assertEqual(str(d), '-4.34913534E-17')
423
424 #wrong number of items
425 self.assertRaises(ValueError, Decimal, (1, (4, 3, 4, 9, 1)) )
426
427 #bad sign
428 self.assertRaises(ValueError, Decimal, (8, (4, 3, 4, 9, 1), 2) )
429
430 #bad exp
431 self.assertRaises(ValueError, Decimal, (1, (4, 3, 4, 9, 1), 'wrong!') )
432
433 #bad coefficients
434 self.assertRaises(ValueError, Decimal, (1, (4, 3, 4, None, 1), 2) )
435 self.assertRaises(ValueError, Decimal, (1, (4, -3, 4, 9, 1), 2) )
436
437 def test_explicit_from_Decimal(self):
438
439 #positive
440 d = Decimal(45)
441 e = Decimal(d)
442 self.assertEqual(str(e), '45')
443 self.assertNotEqual(id(d), id(e))
444
445 #very large positive
446 d = Decimal(500000123)
447 e = Decimal(d)
448 self.assertEqual(str(e), '500000123')
449 self.assertNotEqual(id(d), id(e))
450
451 #negative
452 d = Decimal(-45)
453 e = Decimal(d)
454 self.assertEqual(str(e), '-45')
455 self.assertNotEqual(id(d), id(e))
456
457 #zero
458 d = Decimal(0)
459 e = Decimal(d)
460 self.assertEqual(str(e), '0')
461 self.assertNotEqual(id(d), id(e))
462
463 def test_explicit_context_create_decimal(self):
464
465 nc = copy.copy(getcontext())
466 nc.prec = 3
467
468 # empty
Raymond Hettingerfed52962004-07-14 15:41:57 +0000469 d = Decimal()
470 self.assertEqual(str(d), '0')
471 d = nc.create_decimal()
472 self.assertEqual(str(d), '0')
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000473
474 # from None
475 self.assertRaises(TypeError, nc.create_decimal, None)
476
477 # from int
478 d = nc.create_decimal(456)
479 self.failUnless(isinstance(d, Decimal))
480 self.assertEqual(nc.create_decimal(45678),
481 nc.create_decimal('457E+2'))
482
483 # from string
484 d = Decimal('456789')
485 self.assertEqual(str(d), '456789')
486 d = nc.create_decimal('456789')
487 self.assertEqual(str(d), '4.57E+5')
488
489 # from tuples
490 d = Decimal( (1, (4, 3, 4, 9, 1, 3, 5, 3, 4), -25) )
491 self.assertEqual(str(d), '-4.34913534E-17')
492 d = nc.create_decimal( (1, (4, 3, 4, 9, 1, 3, 5, 3, 4), -25) )
493 self.assertEqual(str(d), '-4.35E-17')
494
495 # from Decimal
496 prevdec = Decimal(500000123)
497 d = Decimal(prevdec)
498 self.assertEqual(str(d), '500000123')
499 d = nc.create_decimal(prevdec)
500 self.assertEqual(str(d), '5.00E+8')
501
502
503class DecimalImplicitConstructionTest(unittest.TestCase):
504 '''Unit tests for Implicit Construction cases of Decimal.'''
505
506 def test_implicit_from_None(self):
507 self.assertRaises(TypeError, eval, 'Decimal(5) + None', globals())
508
509 def test_implicit_from_int(self):
510 #normal
511 self.assertEqual(str(Decimal(5) + 45), '50')
512 #exceeding precision
513 self.assertEqual(Decimal(5) + 123456789000, Decimal(123456789000))
514
515 def test_implicit_from_string(self):
516 self.assertRaises(TypeError, eval, 'Decimal(5) + "3"', globals())
517
518 def test_implicit_from_float(self):
519 self.assertRaises(TypeError, eval, 'Decimal(5) + 2.2', globals())
520
521 def test_implicit_from_Decimal(self):
522 self.assertEqual(Decimal(5) + Decimal(45), Decimal(50))
523
Raymond Hettinger267b8682005-03-27 10:47:39 +0000524 def test_rop(self):
525 # Allow other classes to be trained to interact with Decimals
526 class E:
527 def __divmod__(self, other):
528 return 'divmod ' + str(other)
529 def __rdivmod__(self, other):
530 return str(other) + ' rdivmod'
531 def __lt__(self, other):
532 return 'lt ' + str(other)
533 def __gt__(self, other):
534 return 'gt ' + str(other)
535 def __le__(self, other):
536 return 'le ' + str(other)
537 def __ge__(self, other):
538 return 'ge ' + str(other)
539 def __eq__(self, other):
540 return 'eq ' + str(other)
541 def __ne__(self, other):
542 return 'ne ' + str(other)
543
544 self.assertEqual(divmod(E(), Decimal(10)), 'divmod 10')
545 self.assertEqual(divmod(Decimal(10), E()), '10 rdivmod')
546 self.assertEqual(eval('Decimal(10) < E()'), 'gt 10')
547 self.assertEqual(eval('Decimal(10) > E()'), 'lt 10')
548 self.assertEqual(eval('Decimal(10) <= E()'), 'ge 10')
549 self.assertEqual(eval('Decimal(10) >= E()'), 'le 10')
550 self.assertEqual(eval('Decimal(10) == E()'), 'eq 10')
551 self.assertEqual(eval('Decimal(10) != E()'), 'ne 10')
552
553 # insert operator methods and then exercise them
Georg Brandl96c3f7f2006-03-28 08:06:35 +0000554 oplist = [
555 ('+', '__add__', '__radd__'),
556 ('-', '__sub__', '__rsub__'),
557 ('*', '__mul__', '__rmul__'),
558 ('%', '__mod__', '__rmod__'),
559 ('//', '__floordiv__', '__rfloordiv__'),
560 ('**', '__pow__', '__rpow__')
561 ]
562 if 1/2 == 0:
563 # testing with classic division, so add __div__
564 oplist.append(('/', '__div__', '__rdiv__'))
565 else:
566 # testing with -Qnew, so add __truediv__
567 oplist.append(('/', '__truediv__', '__rtruediv__'))
Anthony Baxter4ef3a232006-03-30 12:59:11 +0000568
Georg Brandl96c3f7f2006-03-28 08:06:35 +0000569 for sym, lop, rop in oplist:
Raymond Hettinger267b8682005-03-27 10:47:39 +0000570 setattr(E, lop, lambda self, other: 'str' + lop + str(other))
571 setattr(E, rop, lambda self, other: str(other) + rop + 'str')
572 self.assertEqual(eval('E()' + sym + 'Decimal(10)'),
573 'str' + lop + '10')
574 self.assertEqual(eval('Decimal(10)' + sym + 'E()'),
575 '10' + rop + 'str')
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000576
577class DecimalArithmeticOperatorsTest(unittest.TestCase):
578 '''Unit tests for all arithmetic operators, binary and unary.'''
579
580 def test_addition(self):
581
582 d1 = Decimal('-11.1')
583 d2 = Decimal('22.2')
584
585 #two Decimals
586 self.assertEqual(d1+d2, Decimal('11.1'))
587 self.assertEqual(d2+d1, Decimal('11.1'))
588
589 #with other type, left
590 c = d1 + 5
591 self.assertEqual(c, Decimal('-6.1'))
592 self.assertEqual(type(c), type(d1))
593
594 #with other type, right
595 c = 5 + d1
596 self.assertEqual(c, Decimal('-6.1'))
597 self.assertEqual(type(c), type(d1))
598
599 #inline with decimal
600 d1 += d2
601 self.assertEqual(d1, Decimal('11.1'))
602
603 #inline with other type
604 d1 += 5
605 self.assertEqual(d1, Decimal('16.1'))
606
607 def test_subtraction(self):
608
609 d1 = Decimal('-11.1')
610 d2 = Decimal('22.2')
611
612 #two Decimals
613 self.assertEqual(d1-d2, Decimal('-33.3'))
614 self.assertEqual(d2-d1, Decimal('33.3'))
615
616 #with other type, left
617 c = d1 - 5
618 self.assertEqual(c, Decimal('-16.1'))
619 self.assertEqual(type(c), type(d1))
620
621 #with other type, right
622 c = 5 - d1
623 self.assertEqual(c, Decimal('16.1'))
624 self.assertEqual(type(c), type(d1))
625
626 #inline with decimal
627 d1 -= d2
628 self.assertEqual(d1, Decimal('-33.3'))
629
630 #inline with other type
631 d1 -= 5
632 self.assertEqual(d1, Decimal('-38.3'))
633
634 def test_multiplication(self):
635
636 d1 = Decimal('-5')
637 d2 = Decimal('3')
638
639 #two Decimals
640 self.assertEqual(d1*d2, Decimal('-15'))
641 self.assertEqual(d2*d1, Decimal('-15'))
642
643 #with other type, left
644 c = d1 * 5
645 self.assertEqual(c, Decimal('-25'))
646 self.assertEqual(type(c), type(d1))
647
648 #with other type, right
649 c = 5 * d1
650 self.assertEqual(c, Decimal('-25'))
651 self.assertEqual(type(c), type(d1))
652
653 #inline with decimal
654 d1 *= d2
655 self.assertEqual(d1, Decimal('-15'))
656
657 #inline with other type
658 d1 *= 5
659 self.assertEqual(d1, Decimal('-75'))
660
661 def test_division(self):
662
663 d1 = Decimal('-5')
664 d2 = Decimal('2')
665
666 #two Decimals
667 self.assertEqual(d1/d2, Decimal('-2.5'))
668 self.assertEqual(d2/d1, Decimal('-0.4'))
669
670 #with other type, left
671 c = d1 / 4
672 self.assertEqual(c, Decimal('-1.25'))
673 self.assertEqual(type(c), type(d1))
674
675 #with other type, right
676 c = 4 / d1
677 self.assertEqual(c, Decimal('-0.8'))
678 self.assertEqual(type(c), type(d1))
679
680 #inline with decimal
681 d1 /= d2
682 self.assertEqual(d1, Decimal('-2.5'))
683
684 #inline with other type
685 d1 /= 4
686 self.assertEqual(d1, Decimal('-0.625'))
687
688 def test_floor_division(self):
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000689
690 d1 = Decimal('5')
691 d2 = Decimal('2')
692
693 #two Decimals
694 self.assertEqual(d1//d2, Decimal('2'))
695 self.assertEqual(d2//d1, Decimal('0'))
696
697 #with other type, left
698 c = d1 // 4
699 self.assertEqual(c, Decimal('1'))
700 self.assertEqual(type(c), type(d1))
701
702 #with other type, right
703 c = 7 // d1
704 self.assertEqual(c, Decimal('1'))
705 self.assertEqual(type(c), type(d1))
706
707 #inline with decimal
708 d1 //= d2
709 self.assertEqual(d1, Decimal('2'))
710
711 #inline with other type
712 d1 //= 2
713 self.assertEqual(d1, Decimal('1'))
714
715 def test_powering(self):
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000716
717 d1 = Decimal('5')
718 d2 = Decimal('2')
719
720 #two Decimals
721 self.assertEqual(d1**d2, Decimal('25'))
722 self.assertEqual(d2**d1, Decimal('32'))
723
724 #with other type, left
725 c = d1 ** 4
726 self.assertEqual(c, Decimal('625'))
727 self.assertEqual(type(c), type(d1))
728
729 #with other type, right
730 c = 7 ** d1
731 self.assertEqual(c, Decimal('16807'))
732 self.assertEqual(type(c), type(d1))
733
734 #inline with decimal
735 d1 **= d2
736 self.assertEqual(d1, Decimal('25'))
737
738 #inline with other type
739 d1 **= 4
740 self.assertEqual(d1, Decimal('390625'))
741
742 def test_module(self):
743
744 d1 = Decimal('5')
745 d2 = Decimal('2')
746
747 #two Decimals
748 self.assertEqual(d1%d2, Decimal('1'))
749 self.assertEqual(d2%d1, Decimal('2'))
750
751 #with other type, left
752 c = d1 % 4
753 self.assertEqual(c, Decimal('1'))
754 self.assertEqual(type(c), type(d1))
755
756 #with other type, right
757 c = 7 % d1
758 self.assertEqual(c, Decimal('2'))
759 self.assertEqual(type(c), type(d1))
760
761 #inline with decimal
762 d1 %= d2
763 self.assertEqual(d1, Decimal('1'))
764
765 #inline with other type
766 d1 %= 4
767 self.assertEqual(d1, Decimal('1'))
768
769 def test_floor_div_module(self):
770
771 d1 = Decimal('5')
772 d2 = Decimal('2')
773
774 #two Decimals
775 (p, q) = divmod(d1, d2)
776 self.assertEqual(p, Decimal('2'))
777 self.assertEqual(q, Decimal('1'))
778 self.assertEqual(type(p), type(d1))
779 self.assertEqual(type(q), type(d1))
780
781 #with other type, left
782 (p, q) = divmod(d1, 4)
783 self.assertEqual(p, Decimal('1'))
784 self.assertEqual(q, Decimal('1'))
785 self.assertEqual(type(p), type(d1))
786 self.assertEqual(type(q), type(d1))
787
788 #with other type, right
789 (p, q) = divmod(7, d1)
790 self.assertEqual(p, Decimal('1'))
791 self.assertEqual(q, Decimal('2'))
792 self.assertEqual(type(p), type(d1))
793 self.assertEqual(type(q), type(d1))
794
795 def test_unary_operators(self):
796 self.assertEqual(+Decimal(45), Decimal(+45)) # +
797 self.assertEqual(-Decimal(45), Decimal(-45)) # -
798 self.assertEqual(abs(Decimal(45)), abs(Decimal(-45))) # abs
799
800
801# The following are two functions used to test threading in the next class
802
803def thfunc1(cls):
804 d1 = Decimal(1)
805 d3 = Decimal(3)
806 cls.assertEqual(d1/d3, Decimal('0.333333333'))
807 cls.synchro.wait()
808 cls.assertEqual(d1/d3, Decimal('0.333333333'))
809 cls.finish1.set()
810 return
811
812def thfunc2(cls):
813 d1 = Decimal(1)
814 d3 = Decimal(3)
815 cls.assertEqual(d1/d3, Decimal('0.333333333'))
816 thiscontext = getcontext()
817 thiscontext.prec = 18
818 cls.assertEqual(d1/d3, Decimal('0.333333333333333333'))
819 cls.synchro.set()
820 cls.finish2.set()
821 return
822
823
824class DecimalUseOfContextTest(unittest.TestCase):
825 '''Unit tests for Use of Context cases in Decimal.'''
826
Raymond Hettinger7e71fa52004-12-18 19:07:19 +0000827 try:
828 import threading
829 except ImportError:
830 threading = None
831
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000832 # Take care executing this test from IDLE, there's an issue in threading
833 # that hangs IDLE and I couldn't find it
834
835 def test_threading(self):
836 #Test the "threading isolation" of a Context.
837
838 self.synchro = threading.Event()
839 self.finish1 = threading.Event()
840 self.finish2 = threading.Event()
841
842 th1 = threading.Thread(target=thfunc1, args=(self,))
843 th2 = threading.Thread(target=thfunc2, args=(self,))
844
845 th1.start()
846 th2.start()
847
848 self.finish1.wait()
Thomas Woutersb3e6e8c2007-09-19 17:27:29 +0000849 self.finish2.wait()
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000850 return
851
Raymond Hettinger7e71fa52004-12-18 19:07:19 +0000852 if threading is None:
853 del test_threading
854
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000855
856class DecimalUsabilityTest(unittest.TestCase):
857 '''Unit tests for Usability cases of Decimal.'''
858
859 def test_comparison_operators(self):
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000860
861 da = Decimal('23.42')
862 db = Decimal('23.42')
863 dc = Decimal('45')
864
865 #two Decimals
866 self.failUnless(dc > da)
867 self.failUnless(dc >= da)
868 self.failUnless(da < dc)
869 self.failUnless(da <= dc)
870 self.failUnless(da == db)
871 self.failUnless(da != dc)
872 self.failUnless(da <= db)
873 self.failUnless(da >= db)
874 self.assertEqual(cmp(dc,da), 1)
875 self.assertEqual(cmp(da,dc), -1)
876 self.assertEqual(cmp(da,db), 0)
877
878 #a Decimal and an int
879 self.failUnless(dc > 23)
880 self.failUnless(23 < dc)
881 self.failUnless(dc == 45)
882 self.assertEqual(cmp(dc,23), 1)
883 self.assertEqual(cmp(23,dc), -1)
884 self.assertEqual(cmp(dc,45), 0)
885
886 #a Decimal and uncomparable
Raymond Hettinger0aeac102004-07-05 22:53:03 +0000887 self.assertNotEqual(da, 'ugly')
888 self.assertNotEqual(da, 32.7)
889 self.assertNotEqual(da, object())
890 self.assertNotEqual(da, object)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000891
Raymond Hettinger0aeac102004-07-05 22:53:03 +0000892 # sortable
893 a = map(Decimal, xrange(100))
894 b = a[:]
895 random.shuffle(a)
896 a.sort()
897 self.assertEqual(a, b)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000898
Facundo Batista353750c2007-09-13 18:13:15 +0000899 # with None
900 self.assertFalse(Decimal(1) < None)
901 self.assertTrue(Decimal(1) > None)
902
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000903 def test_copy_and_deepcopy_methods(self):
904 d = Decimal('43.24')
905 c = copy.copy(d)
906 self.assertEqual(id(c), id(d))
907 dc = copy.deepcopy(d)
908 self.assertEqual(id(dc), id(d))
909
910 def test_hash_method(self):
911 #just that it's hashable
912 hash(Decimal(23))
Facundo Batista8c202442007-09-19 17:53:25 +0000913
914 test_values = [Decimal(sign*(2**m + n))
915 for m in [0, 14, 15, 16, 17, 30, 31,
916 32, 33, 62, 63, 64, 65, 66]
917 for n in range(-10, 10)
918 for sign in [-1, 1]]
919 test_values.extend([
920 Decimal("-0"), # zeros
921 Decimal("0.00"),
922 Decimal("-0.000"),
923 Decimal("0E10"),
924 Decimal("-0E12"),
925 Decimal("10.0"), # negative exponent
926 Decimal("-23.00000"),
927 Decimal("1230E100"), # positive exponent
928 Decimal("-4.5678E50"),
929 # a value for which hash(n) != hash(n % (2**64-1))
930 # in Python pre-2.6
931 Decimal(2**64 + 2**32 - 1),
932 # selection of values which fail with the old (before
933 # version 2.6) long.__hash__
934 Decimal("1.634E100"),
935 Decimal("90.697E100"),
936 Decimal("188.83E100"),
937 Decimal("1652.9E100"),
938 Decimal("56531E100"),
939 ])
940
941 # check that hash(d) == hash(int(d)) for integral values
942 for value in test_values:
943 self.assertEqual(hash(value), hash(int(value)))
944
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000945 #the same hash that to an int
946 self.assertEqual(hash(Decimal(23)), hash(23))
Raymond Hettingerbea3f6f2005-03-15 04:59:17 +0000947 self.assertRaises(TypeError, hash, Decimal('NaN'))
948 self.assert_(hash(Decimal('Inf')))
949 self.assert_(hash(Decimal('-Inf')))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000950
951 def test_min_and_max_methods(self):
952
953 d1 = Decimal('15.32')
954 d2 = Decimal('28.5')
955 l1 = 15
956 l2 = 28
957
958 #between Decimals
959 self.failUnless(min(d1,d2) is d1)
960 self.failUnless(min(d2,d1) is d1)
961 self.failUnless(max(d1,d2) is d2)
962 self.failUnless(max(d2,d1) is d2)
963
964 #between Decimal and long
965 self.failUnless(min(d1,l2) is d1)
966 self.failUnless(min(l2,d1) is d1)
967 self.failUnless(max(l1,d2) is d2)
968 self.failUnless(max(d2,l1) is d2)
969
970 def test_as_nonzero(self):
971 #as false
972 self.failIf(Decimal(0))
973 #as true
974 self.failUnless(Decimal('0.372'))
975
976 def test_tostring_methods(self):
977 #Test str and repr methods.
978
979 d = Decimal('15.32')
980 self.assertEqual(str(d), '15.32') # str
981 self.assertEqual(repr(d), 'Decimal("15.32")') # repr
982
983 def test_tonum_methods(self):
984 #Test float, int and long methods.
985
986 d1 = Decimal('66')
987 d2 = Decimal('15.32')
988
989 #int
990 self.assertEqual(int(d1), 66)
991 self.assertEqual(int(d2), 15)
992
993 #long
994 self.assertEqual(long(d1), 66)
995 self.assertEqual(long(d2), 15)
996
997 #float
998 self.assertEqual(float(d1), 66)
999 self.assertEqual(float(d2), 15.32)
1000
1001 def test_eval_round_trip(self):
1002
1003 #with zero
1004 d = Decimal( (0, (0,), 0) )
1005 self.assertEqual(d, eval(repr(d)))
1006
1007 #int
1008 d = Decimal( (1, (4, 5), 0) )
1009 self.assertEqual(d, eval(repr(d)))
1010
1011 #float
1012 d = Decimal( (0, (4, 5, 3, 4), -2) )
1013 self.assertEqual(d, eval(repr(d)))
1014
1015 #weird
1016 d = Decimal( (1, (4, 3, 4, 9, 1, 3, 5, 3, 4), -25) )
1017 self.assertEqual(d, eval(repr(d)))
1018
1019 def test_as_tuple(self):
1020
1021 #with zero
1022 d = Decimal(0)
1023 self.assertEqual(d.as_tuple(), (0, (0,), 0) )
1024
1025 #int
1026 d = Decimal(-45)
1027 self.assertEqual(d.as_tuple(), (1, (4, 5), 0) )
1028
1029 #complicated string
1030 d = Decimal("-4.34913534E-17")
1031 self.assertEqual(d.as_tuple(), (1, (4, 3, 4, 9, 1, 3, 5, 3, 4), -25) )
1032
1033 #inf
1034 d = Decimal("Infinity")
1035 self.assertEqual(d.as_tuple(), (0, (0,), 'F') )
1036
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001037 def test_immutability_operations(self):
1038 # Do operations and check that it didn't change change internal objects.
1039
1040 d1 = Decimal('-25e55')
1041 b1 = Decimal('-25e55')
Facundo Batista353750c2007-09-13 18:13:15 +00001042 d2 = Decimal('33e+33')
1043 b2 = Decimal('33e+33')
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001044
1045 def checkSameDec(operation, useOther=False):
1046 if useOther:
1047 eval("d1." + operation + "(d2)")
1048 self.assertEqual(d1._sign, b1._sign)
1049 self.assertEqual(d1._int, b1._int)
1050 self.assertEqual(d1._exp, b1._exp)
1051 self.assertEqual(d2._sign, b2._sign)
1052 self.assertEqual(d2._int, b2._int)
1053 self.assertEqual(d2._exp, b2._exp)
1054 else:
1055 eval("d1." + operation + "()")
1056 self.assertEqual(d1._sign, b1._sign)
1057 self.assertEqual(d1._int, b1._int)
1058 self.assertEqual(d1._exp, b1._exp)
1059 return
1060
1061 Decimal(d1)
1062 self.assertEqual(d1._sign, b1._sign)
1063 self.assertEqual(d1._int, b1._int)
1064 self.assertEqual(d1._exp, b1._exp)
1065
1066 checkSameDec("__abs__")
1067 checkSameDec("__add__", True)
1068 checkSameDec("__div__", True)
1069 checkSameDec("__divmod__", True)
1070 checkSameDec("__cmp__", True)
1071 checkSameDec("__float__")
1072 checkSameDec("__floordiv__", True)
1073 checkSameDec("__hash__")
1074 checkSameDec("__int__")
1075 checkSameDec("__long__")
1076 checkSameDec("__mod__", True)
1077 checkSameDec("__mul__", True)
1078 checkSameDec("__neg__")
1079 checkSameDec("__nonzero__")
1080 checkSameDec("__pos__")
1081 checkSameDec("__pow__", True)
1082 checkSameDec("__radd__", True)
1083 checkSameDec("__rdiv__", True)
1084 checkSameDec("__rdivmod__", True)
1085 checkSameDec("__repr__")
1086 checkSameDec("__rfloordiv__", True)
1087 checkSameDec("__rmod__", True)
1088 checkSameDec("__rmul__", True)
1089 checkSameDec("__rpow__", True)
1090 checkSameDec("__rsub__", True)
1091 checkSameDec("__str__")
1092 checkSameDec("__sub__", True)
1093 checkSameDec("__truediv__", True)
1094 checkSameDec("adjusted")
1095 checkSameDec("as_tuple")
1096 checkSameDec("compare", True)
1097 checkSameDec("max", True)
1098 checkSameDec("min", True)
1099 checkSameDec("normalize")
1100 checkSameDec("quantize", True)
1101 checkSameDec("remainder_near", True)
1102 checkSameDec("same_quantum", True)
1103 checkSameDec("sqrt")
1104 checkSameDec("to_eng_string")
1105 checkSameDec("to_integral")
1106
Facundo Batista6c398da2007-09-17 17:30:13 +00001107 def test_subclassing(self):
1108 # Different behaviours when subclassing Decimal
1109
1110 class MyDecimal(Decimal):
1111 pass
1112
1113 d1 = MyDecimal(1)
1114 d2 = MyDecimal(2)
1115 d = d1 + d2
1116 self.assertTrue(type(d) is Decimal)
1117
1118 d = d1.max(d2)
1119 self.assertTrue(type(d) is Decimal)
1120
1121
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001122class DecimalPythonAPItests(unittest.TestCase):
1123
1124 def test_pickle(self):
1125 d = Decimal('-3.141590000')
1126 p = pickle.dumps(d)
1127 e = pickle.loads(p)
1128 self.assertEqual(d, e)
1129
Raymond Hettinger5548be22004-07-05 18:49:38 +00001130 def test_int(self):
Raymond Hettinger605ed022004-11-24 07:28:48 +00001131 for x in range(-250, 250):
1132 s = '%0.2f' % (x / 100.0)
Raymond Hettinger5548be22004-07-05 18:49:38 +00001133 # should work the same as for floats
1134 self.assertEqual(int(Decimal(s)), int(float(s)))
Raymond Hettinger605ed022004-11-24 07:28:48 +00001135 # should work the same as to_integral in the ROUND_DOWN mode
Raymond Hettinger5548be22004-07-05 18:49:38 +00001136 d = Decimal(s)
Raymond Hettinger605ed022004-11-24 07:28:48 +00001137 r = d.to_integral(ROUND_DOWN)
Raymond Hettinger5548be22004-07-05 18:49:38 +00001138 self.assertEqual(Decimal(int(d)), r)
1139
Raymond Hettingerd9c0a7a2004-07-03 10:02:28 +00001140class ContextAPItests(unittest.TestCase):
1141
1142 def test_pickle(self):
1143 c = Context()
1144 e = pickle.loads(pickle.dumps(c))
1145 for k in vars(c):
1146 v1 = vars(c)[k]
1147 v2 = vars(e)[k]
1148 self.assertEqual(v1, v2)
1149
Raymond Hettinger0aeac102004-07-05 22:53:03 +00001150 def test_equality_with_other_types(self):
1151 self.assert_(Decimal(10) in ['a', 1.0, Decimal(10), (1,2), {}])
1152 self.assert_(Decimal(10) not in ['a', 1.0, (1,2), {}])
1153
Raymond Hettinger955d2b22004-08-08 20:17:45 +00001154 def test_copy(self):
1155 # All copies should be deep
1156 c = Context()
1157 d = c.copy()
1158 self.assertNotEqual(id(c), id(d))
1159 self.assertNotEqual(id(c.flags), id(d.flags))
1160 self.assertNotEqual(id(c.traps), id(d.traps))
1161
Nick Coghlan8b6999b2006-08-31 12:00:43 +00001162class WithStatementTest(unittest.TestCase):
1163 # Can't do these as docstrings until Python 2.6
1164 # as doctest can't handle __future__ statements
Nick Coghlan8b6999b2006-08-31 12:00:43 +00001165
1166 def test_localcontext(self):
Nick Coghlanced12182006-09-02 03:54:17 +00001167 # Use a copy of the current context in the block
Nick Coghlan8b6999b2006-08-31 12:00:43 +00001168 orig_ctx = getcontext()
1169 with localcontext() as enter_ctx:
1170 set_ctx = getcontext()
1171 final_ctx = getcontext()
1172 self.assert_(orig_ctx is final_ctx, 'did not restore context correctly')
1173 self.assert_(orig_ctx is not set_ctx, 'did not copy the context')
1174 self.assert_(set_ctx is enter_ctx, '__enter__ returned wrong context')
1175
1176 def test_localcontextarg(self):
Nick Coghlanced12182006-09-02 03:54:17 +00001177 # Use a copy of the supplied context in the block
Nick Coghlan8b6999b2006-08-31 12:00:43 +00001178 orig_ctx = getcontext()
1179 new_ctx = Context(prec=42)
1180 with localcontext(new_ctx) as enter_ctx:
1181 set_ctx = getcontext()
1182 final_ctx = getcontext()
1183 self.assert_(orig_ctx is final_ctx, 'did not restore context correctly')
1184 self.assert_(set_ctx.prec == new_ctx.prec, 'did not set correct context')
1185 self.assert_(new_ctx is not set_ctx, 'did not copy the context')
1186 self.assert_(set_ctx is enter_ctx, '__enter__ returned wrong context')
1187
Facundo Batista353750c2007-09-13 18:13:15 +00001188class ContextFlags(unittest.TestCase):
1189 def test_flags_irrelevant(self):
1190 # check that the result (numeric result + flags raised) of an
1191 # arithmetic operation doesn't depend on the current flags
1192
1193 context = Context(prec=9, Emin = -999999999, Emax = 999999999,
1194 rounding=ROUND_HALF_EVEN, traps=[], flags=[])
1195
1196 # operations that raise various flags, in the form (function, arglist)
1197 operations = [
1198 (context._apply, [Decimal("100E-1000000009")]),
1199 (context.sqrt, [Decimal(2)]),
1200 (context.add, [Decimal("1.23456789"), Decimal("9.87654321")]),
1201 (context.multiply, [Decimal("1.23456789"), Decimal("9.87654321")]),
1202 (context.subtract, [Decimal("1.23456789"), Decimal("9.87654321")]),
1203 ]
1204
1205 # try various flags individually, then a whole lot at once
1206 flagsets = [[Inexact], [Rounded], [Underflow], [Clamped], [Subnormal],
1207 [Inexact, Rounded, Underflow, Clamped, Subnormal]]
1208
1209 for fn, args in operations:
1210 # find answer and flags raised using a clean context
1211 context.clear_flags()
1212 ans = fn(*args)
1213 flags = [k for k, v in context.flags.items() if v]
1214
1215 for extra_flags in flagsets:
1216 # set flags, before calling operation
1217 context.clear_flags()
1218 for flag in extra_flags:
1219 context._raise_error(flag)
1220 new_ans = fn(*args)
1221
1222 # flags that we expect to be set after the operation
1223 expected_flags = list(flags)
1224 for flag in extra_flags:
1225 if flag not in expected_flags:
1226 expected_flags.append(flag)
1227 expected_flags.sort()
1228
1229 # flags we actually got
1230 new_flags = [k for k,v in context.flags.items() if v]
1231 new_flags.sort()
1232
1233 self.assertEqual(ans, new_ans,
1234 "operation produces different answers depending on flags set: " +
1235 "expected %s, got %s." % (ans, new_ans))
1236 self.assertEqual(new_flags, expected_flags,
1237 "operation raises different flags depending on flags set: " +
1238 "expected %s, got %s" % (expected_flags, new_flags))
1239
1240def test_main(arith=False, verbose=None, todo_tests=None, debug=None):
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001241 """ Execute the tests.
1242
Raymond Hettingered20ad82004-09-04 20:09:13 +00001243 Runs all arithmetic tests if arith is True or if the "decimal" resource
1244 is enabled in regrtest.py
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001245 """
Raymond Hettingered20ad82004-09-04 20:09:13 +00001246
Neal Norwitzce4a9c92006-04-09 08:36:46 +00001247 init()
Facundo Batista353750c2007-09-13 18:13:15 +00001248 global TEST_ALL, DEBUG
Raymond Hettingered20ad82004-09-04 20:09:13 +00001249 TEST_ALL = arith or is_resource_enabled('decimal')
Facundo Batista353750c2007-09-13 18:13:15 +00001250 DEBUG = debug
Raymond Hettingered20ad82004-09-04 20:09:13 +00001251
Facundo Batista353750c2007-09-13 18:13:15 +00001252 if todo_tests is None:
1253 test_classes = [
1254 DecimalExplicitConstructionTest,
1255 DecimalImplicitConstructionTest,
1256 DecimalArithmeticOperatorsTest,
1257 DecimalUseOfContextTest,
1258 DecimalUsabilityTest,
1259 DecimalPythonAPItests,
1260 ContextAPItests,
1261 DecimalTest,
1262 WithStatementTest,
1263 ContextFlags
1264 ]
1265 else:
1266 test_classes = [DecimalTest]
1267
1268 # Dynamically build custom test definition for each file in the test
1269 # directory and add the definitions to the DecimalTest class. This
1270 # procedure insures that new files do not get skipped.
1271 for filename in os.listdir(directory):
1272 if '.decTest' not in filename or filename.startswith("."):
1273 continue
1274 head, tail = filename.split('.')
1275 if todo_tests is not None and head not in todo_tests:
1276 continue
1277 tester = lambda self, f=filename: self.eval_file(directory + f)
1278 setattr(DecimalTest, 'test_' + head, tester)
1279 del filename, head, tail, tester
1280
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001281
Tim Peters46cc7022006-03-31 04:11:16 +00001282 try:
1283 run_unittest(*test_classes)
Facundo Batista353750c2007-09-13 18:13:15 +00001284 if todo_tests is None:
1285 import decimal as DecimalModule
1286 run_doctest(DecimalModule, verbose)
Tim Peters46cc7022006-03-31 04:11:16 +00001287 finally:
1288 setcontext(ORIGINAL_CONTEXT)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001289
1290if __name__ == '__main__':
Facundo Batista353750c2007-09-13 18:13:15 +00001291 import optparse
1292 p = optparse.OptionParser("test_decimal.py [--debug] [{--skip | test1 [test2 [...]]}]")
1293 p.add_option('--debug', '-d', action='store_true', help='shows the test number and context before each test')
1294 p.add_option('--skip', '-s', action='store_true', help='skip over 90% of the arithmetic tests')
1295 (opt, args) = p.parse_args()
1296
1297 if opt.skip:
1298 test_main(arith=False, verbose=True)
1299 elif args:
1300 test_main(arith=True, verbose=True, todo_tests=args, debug=opt.debug)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001301 else:
Facundo Batista353750c2007-09-13 18:13:15 +00001302 test_main(arith=True, verbose=True)