blob: 2777b225c5fbd1e621762deb1b403a0b96208f37 [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()
849 self.finish1.wait()
850 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))
913 #the same hash that to an int
914 self.assertEqual(hash(Decimal(23)), hash(23))
Raymond Hettingerbea3f6f2005-03-15 04:59:17 +0000915 self.assertRaises(TypeError, hash, Decimal('NaN'))
916 self.assert_(hash(Decimal('Inf')))
917 self.assert_(hash(Decimal('-Inf')))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000918
919 def test_min_and_max_methods(self):
920
921 d1 = Decimal('15.32')
922 d2 = Decimal('28.5')
923 l1 = 15
924 l2 = 28
925
926 #between Decimals
927 self.failUnless(min(d1,d2) is d1)
928 self.failUnless(min(d2,d1) is d1)
929 self.failUnless(max(d1,d2) is d2)
930 self.failUnless(max(d2,d1) is d2)
931
932 #between Decimal and long
933 self.failUnless(min(d1,l2) is d1)
934 self.failUnless(min(l2,d1) is d1)
935 self.failUnless(max(l1,d2) is d2)
936 self.failUnless(max(d2,l1) is d2)
937
938 def test_as_nonzero(self):
939 #as false
940 self.failIf(Decimal(0))
941 #as true
942 self.failUnless(Decimal('0.372'))
943
944 def test_tostring_methods(self):
945 #Test str and repr methods.
946
947 d = Decimal('15.32')
948 self.assertEqual(str(d), '15.32') # str
949 self.assertEqual(repr(d), 'Decimal("15.32")') # repr
950
951 def test_tonum_methods(self):
952 #Test float, int and long methods.
953
954 d1 = Decimal('66')
955 d2 = Decimal('15.32')
956
957 #int
958 self.assertEqual(int(d1), 66)
959 self.assertEqual(int(d2), 15)
960
961 #long
962 self.assertEqual(long(d1), 66)
963 self.assertEqual(long(d2), 15)
964
965 #float
966 self.assertEqual(float(d1), 66)
967 self.assertEqual(float(d2), 15.32)
968
969 def test_eval_round_trip(self):
970
971 #with zero
972 d = Decimal( (0, (0,), 0) )
973 self.assertEqual(d, eval(repr(d)))
974
975 #int
976 d = Decimal( (1, (4, 5), 0) )
977 self.assertEqual(d, eval(repr(d)))
978
979 #float
980 d = Decimal( (0, (4, 5, 3, 4), -2) )
981 self.assertEqual(d, eval(repr(d)))
982
983 #weird
984 d = Decimal( (1, (4, 3, 4, 9, 1, 3, 5, 3, 4), -25) )
985 self.assertEqual(d, eval(repr(d)))
986
987 def test_as_tuple(self):
988
989 #with zero
990 d = Decimal(0)
991 self.assertEqual(d.as_tuple(), (0, (0,), 0) )
992
993 #int
994 d = Decimal(-45)
995 self.assertEqual(d.as_tuple(), (1, (4, 5), 0) )
996
997 #complicated string
998 d = Decimal("-4.34913534E-17")
999 self.assertEqual(d.as_tuple(), (1, (4, 3, 4, 9, 1, 3, 5, 3, 4), -25) )
1000
1001 #inf
1002 d = Decimal("Infinity")
1003 self.assertEqual(d.as_tuple(), (0, (0,), 'F') )
1004
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001005 def test_immutability_operations(self):
1006 # Do operations and check that it didn't change change internal objects.
1007
1008 d1 = Decimal('-25e55')
1009 b1 = Decimal('-25e55')
Facundo Batista353750c2007-09-13 18:13:15 +00001010 d2 = Decimal('33e+33')
1011 b2 = Decimal('33e+33')
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001012
1013 def checkSameDec(operation, useOther=False):
1014 if useOther:
1015 eval("d1." + operation + "(d2)")
1016 self.assertEqual(d1._sign, b1._sign)
1017 self.assertEqual(d1._int, b1._int)
1018 self.assertEqual(d1._exp, b1._exp)
1019 self.assertEqual(d2._sign, b2._sign)
1020 self.assertEqual(d2._int, b2._int)
1021 self.assertEqual(d2._exp, b2._exp)
1022 else:
1023 eval("d1." + operation + "()")
1024 self.assertEqual(d1._sign, b1._sign)
1025 self.assertEqual(d1._int, b1._int)
1026 self.assertEqual(d1._exp, b1._exp)
1027 return
1028
1029 Decimal(d1)
1030 self.assertEqual(d1._sign, b1._sign)
1031 self.assertEqual(d1._int, b1._int)
1032 self.assertEqual(d1._exp, b1._exp)
1033
1034 checkSameDec("__abs__")
1035 checkSameDec("__add__", True)
1036 checkSameDec("__div__", True)
1037 checkSameDec("__divmod__", True)
1038 checkSameDec("__cmp__", True)
1039 checkSameDec("__float__")
1040 checkSameDec("__floordiv__", True)
1041 checkSameDec("__hash__")
1042 checkSameDec("__int__")
1043 checkSameDec("__long__")
1044 checkSameDec("__mod__", True)
1045 checkSameDec("__mul__", True)
1046 checkSameDec("__neg__")
1047 checkSameDec("__nonzero__")
1048 checkSameDec("__pos__")
1049 checkSameDec("__pow__", True)
1050 checkSameDec("__radd__", True)
1051 checkSameDec("__rdiv__", True)
1052 checkSameDec("__rdivmod__", True)
1053 checkSameDec("__repr__")
1054 checkSameDec("__rfloordiv__", True)
1055 checkSameDec("__rmod__", True)
1056 checkSameDec("__rmul__", True)
1057 checkSameDec("__rpow__", True)
1058 checkSameDec("__rsub__", True)
1059 checkSameDec("__str__")
1060 checkSameDec("__sub__", True)
1061 checkSameDec("__truediv__", True)
1062 checkSameDec("adjusted")
1063 checkSameDec("as_tuple")
1064 checkSameDec("compare", True)
1065 checkSameDec("max", True)
1066 checkSameDec("min", True)
1067 checkSameDec("normalize")
1068 checkSameDec("quantize", True)
1069 checkSameDec("remainder_near", True)
1070 checkSameDec("same_quantum", True)
1071 checkSameDec("sqrt")
1072 checkSameDec("to_eng_string")
1073 checkSameDec("to_integral")
1074
Facundo Batista6c398da2007-09-17 17:30:13 +00001075 def test_subclassing(self):
1076 # Different behaviours when subclassing Decimal
1077
1078 class MyDecimal(Decimal):
1079 pass
1080
1081 d1 = MyDecimal(1)
1082 d2 = MyDecimal(2)
1083 d = d1 + d2
1084 self.assertTrue(type(d) is Decimal)
1085
1086 d = d1.max(d2)
1087 self.assertTrue(type(d) is Decimal)
1088
1089
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001090class DecimalPythonAPItests(unittest.TestCase):
1091
1092 def test_pickle(self):
1093 d = Decimal('-3.141590000')
1094 p = pickle.dumps(d)
1095 e = pickle.loads(p)
1096 self.assertEqual(d, e)
1097
Raymond Hettinger5548be22004-07-05 18:49:38 +00001098 def test_int(self):
Raymond Hettinger605ed022004-11-24 07:28:48 +00001099 for x in range(-250, 250):
1100 s = '%0.2f' % (x / 100.0)
Raymond Hettinger5548be22004-07-05 18:49:38 +00001101 # should work the same as for floats
1102 self.assertEqual(int(Decimal(s)), int(float(s)))
Raymond Hettinger605ed022004-11-24 07:28:48 +00001103 # should work the same as to_integral in the ROUND_DOWN mode
Raymond Hettinger5548be22004-07-05 18:49:38 +00001104 d = Decimal(s)
Raymond Hettinger605ed022004-11-24 07:28:48 +00001105 r = d.to_integral(ROUND_DOWN)
Raymond Hettinger5548be22004-07-05 18:49:38 +00001106 self.assertEqual(Decimal(int(d)), r)
1107
Raymond Hettingerd9c0a7a2004-07-03 10:02:28 +00001108class ContextAPItests(unittest.TestCase):
1109
1110 def test_pickle(self):
1111 c = Context()
1112 e = pickle.loads(pickle.dumps(c))
1113 for k in vars(c):
1114 v1 = vars(c)[k]
1115 v2 = vars(e)[k]
1116 self.assertEqual(v1, v2)
1117
Raymond Hettinger0aeac102004-07-05 22:53:03 +00001118 def test_equality_with_other_types(self):
1119 self.assert_(Decimal(10) in ['a', 1.0, Decimal(10), (1,2), {}])
1120 self.assert_(Decimal(10) not in ['a', 1.0, (1,2), {}])
1121
Raymond Hettinger955d2b22004-08-08 20:17:45 +00001122 def test_copy(self):
1123 # All copies should be deep
1124 c = Context()
1125 d = c.copy()
1126 self.assertNotEqual(id(c), id(d))
1127 self.assertNotEqual(id(c.flags), id(d.flags))
1128 self.assertNotEqual(id(c.traps), id(d.traps))
1129
Nick Coghlan8b6999b2006-08-31 12:00:43 +00001130class WithStatementTest(unittest.TestCase):
1131 # Can't do these as docstrings until Python 2.6
1132 # as doctest can't handle __future__ statements
Nick Coghlan8b6999b2006-08-31 12:00:43 +00001133
1134 def test_localcontext(self):
Nick Coghlanced12182006-09-02 03:54:17 +00001135 # Use a copy of the current context in the block
Nick Coghlan8b6999b2006-08-31 12:00:43 +00001136 orig_ctx = getcontext()
1137 with localcontext() as enter_ctx:
1138 set_ctx = getcontext()
1139 final_ctx = getcontext()
1140 self.assert_(orig_ctx is final_ctx, 'did not restore context correctly')
1141 self.assert_(orig_ctx is not set_ctx, 'did not copy the context')
1142 self.assert_(set_ctx is enter_ctx, '__enter__ returned wrong context')
1143
1144 def test_localcontextarg(self):
Nick Coghlanced12182006-09-02 03:54:17 +00001145 # Use a copy of the supplied context in the block
Nick Coghlan8b6999b2006-08-31 12:00:43 +00001146 orig_ctx = getcontext()
1147 new_ctx = Context(prec=42)
1148 with localcontext(new_ctx) as enter_ctx:
1149 set_ctx = getcontext()
1150 final_ctx = getcontext()
1151 self.assert_(orig_ctx is final_ctx, 'did not restore context correctly')
1152 self.assert_(set_ctx.prec == new_ctx.prec, 'did not set correct context')
1153 self.assert_(new_ctx is not set_ctx, 'did not copy the context')
1154 self.assert_(set_ctx is enter_ctx, '__enter__ returned wrong context')
1155
Facundo Batista353750c2007-09-13 18:13:15 +00001156class ContextFlags(unittest.TestCase):
1157 def test_flags_irrelevant(self):
1158 # check that the result (numeric result + flags raised) of an
1159 # arithmetic operation doesn't depend on the current flags
1160
1161 context = Context(prec=9, Emin = -999999999, Emax = 999999999,
1162 rounding=ROUND_HALF_EVEN, traps=[], flags=[])
1163
1164 # operations that raise various flags, in the form (function, arglist)
1165 operations = [
1166 (context._apply, [Decimal("100E-1000000009")]),
1167 (context.sqrt, [Decimal(2)]),
1168 (context.add, [Decimal("1.23456789"), Decimal("9.87654321")]),
1169 (context.multiply, [Decimal("1.23456789"), Decimal("9.87654321")]),
1170 (context.subtract, [Decimal("1.23456789"), Decimal("9.87654321")]),
1171 ]
1172
1173 # try various flags individually, then a whole lot at once
1174 flagsets = [[Inexact], [Rounded], [Underflow], [Clamped], [Subnormal],
1175 [Inexact, Rounded, Underflow, Clamped, Subnormal]]
1176
1177 for fn, args in operations:
1178 # find answer and flags raised using a clean context
1179 context.clear_flags()
1180 ans = fn(*args)
1181 flags = [k for k, v in context.flags.items() if v]
1182
1183 for extra_flags in flagsets:
1184 # set flags, before calling operation
1185 context.clear_flags()
1186 for flag in extra_flags:
1187 context._raise_error(flag)
1188 new_ans = fn(*args)
1189
1190 # flags that we expect to be set after the operation
1191 expected_flags = list(flags)
1192 for flag in extra_flags:
1193 if flag not in expected_flags:
1194 expected_flags.append(flag)
1195 expected_flags.sort()
1196
1197 # flags we actually got
1198 new_flags = [k for k,v in context.flags.items() if v]
1199 new_flags.sort()
1200
1201 self.assertEqual(ans, new_ans,
1202 "operation produces different answers depending on flags set: " +
1203 "expected %s, got %s." % (ans, new_ans))
1204 self.assertEqual(new_flags, expected_flags,
1205 "operation raises different flags depending on flags set: " +
1206 "expected %s, got %s" % (expected_flags, new_flags))
1207
1208def test_main(arith=False, verbose=None, todo_tests=None, debug=None):
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001209 """ Execute the tests.
1210
Raymond Hettingered20ad82004-09-04 20:09:13 +00001211 Runs all arithmetic tests if arith is True or if the "decimal" resource
1212 is enabled in regrtest.py
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001213 """
Raymond Hettingered20ad82004-09-04 20:09:13 +00001214
Neal Norwitzce4a9c92006-04-09 08:36:46 +00001215 init()
Facundo Batista353750c2007-09-13 18:13:15 +00001216 global TEST_ALL, DEBUG
Raymond Hettingered20ad82004-09-04 20:09:13 +00001217 TEST_ALL = arith or is_resource_enabled('decimal')
Facundo Batista353750c2007-09-13 18:13:15 +00001218 DEBUG = debug
Raymond Hettingered20ad82004-09-04 20:09:13 +00001219
Facundo Batista353750c2007-09-13 18:13:15 +00001220 if todo_tests is None:
1221 test_classes = [
1222 DecimalExplicitConstructionTest,
1223 DecimalImplicitConstructionTest,
1224 DecimalArithmeticOperatorsTest,
1225 DecimalUseOfContextTest,
1226 DecimalUsabilityTest,
1227 DecimalPythonAPItests,
1228 ContextAPItests,
1229 DecimalTest,
1230 WithStatementTest,
1231 ContextFlags
1232 ]
1233 else:
1234 test_classes = [DecimalTest]
1235
1236 # Dynamically build custom test definition for each file in the test
1237 # directory and add the definitions to the DecimalTest class. This
1238 # procedure insures that new files do not get skipped.
1239 for filename in os.listdir(directory):
1240 if '.decTest' not in filename or filename.startswith("."):
1241 continue
1242 head, tail = filename.split('.')
1243 if todo_tests is not None and head not in todo_tests:
1244 continue
1245 tester = lambda self, f=filename: self.eval_file(directory + f)
1246 setattr(DecimalTest, 'test_' + head, tester)
1247 del filename, head, tail, tester
1248
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001249
Tim Peters46cc7022006-03-31 04:11:16 +00001250 try:
1251 run_unittest(*test_classes)
Facundo Batista353750c2007-09-13 18:13:15 +00001252 if todo_tests is None:
1253 import decimal as DecimalModule
1254 run_doctest(DecimalModule, verbose)
Tim Peters46cc7022006-03-31 04:11:16 +00001255 finally:
1256 setcontext(ORIGINAL_CONTEXT)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001257
1258if __name__ == '__main__':
Facundo Batista353750c2007-09-13 18:13:15 +00001259 import optparse
1260 p = optparse.OptionParser("test_decimal.py [--debug] [{--skip | test1 [test2 [...]]}]")
1261 p.add_option('--debug', '-d', action='store_true', help='shows the test number and context before each test')
1262 p.add_option('--skip', '-s', action='store_true', help='skip over 90% of the arithmetic tests')
1263 (opt, args) = p.parse_args()
1264
1265 if opt.skip:
1266 test_main(arith=False, verbose=True)
1267 elif args:
1268 test_main(arith=True, verbose=True, todo_tests=args, debug=opt.debug)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001269 else:
Facundo Batista353750c2007-09-13 18:13:15 +00001270 test_main(arith=True, verbose=True)