python-2.5.2/win32/Lib/test/test_decimal.py
changeset 0 ae805ac0140d
equal deleted inserted replaced
-1:000000000000 0:ae805ac0140d
       
     1 # 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 """
       
    11 These are the test cases for the Decimal module.
       
    12 
       
    13 There are two groups of tests, Arithmetic and Behaviour. The former test
       
    14 the Decimal arithmetic using the tests provided by Mike Cowlishaw. The latter
       
    15 test the pythonic behaviour according to PEP 327.
       
    16 
       
    17 Cowlishaw's tests can be downloaded from:
       
    18 
       
    19    www2.hursley.ibm.com/decimal/dectest.zip
       
    20 
       
    21 This test module can be called from command line with one parameter (Arithmetic
       
    22 or Behaviour) to test each part, or without parameter to test both parts. If
       
    23 you're working through IDLE, you can import this test module and call test_main()
       
    24 with the corresponding argument.
       
    25 """
       
    26 from __future__ import with_statement
       
    27 
       
    28 import unittest
       
    29 import glob
       
    30 import os, sys
       
    31 import pickle, copy
       
    32 from decimal import *
       
    33 from test.test_support import (TestSkipped, run_unittest, run_doctest,
       
    34                                is_resource_enabled)
       
    35 import random
       
    36 try:
       
    37     import threading
       
    38 except ImportError:
       
    39     threading = None
       
    40 
       
    41 # Useful Test Constant
       
    42 Signals = getcontext().flags.keys()
       
    43 
       
    44 # Tests are built around these assumed context defaults.
       
    45 # test_main() restores the original context.
       
    46 def 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)
       
    53 
       
    54 TESTDATADIR = 'decimaltestdata'
       
    55 if __name__ == '__main__':
       
    56     file = sys.argv[0]
       
    57 else:
       
    58     file = __file__
       
    59 testdir = os.path.dirname(file) or os.curdir
       
    60 directory = testdir + os.sep + TESTDATADIR + os.sep
       
    61 
       
    62 skip_expected = not os.path.isdir(directory)
       
    63 
       
    64 # Make sure it actually raises errors when not expected and caught in flags
       
    65 # Slower, since it runs some things several times.
       
    66 EXTENDEDERRORTEST = False
       
    67 
       
    68 #Map the test cases' error names to the actual errors
       
    69 ErrorNames = {'clamped' : Clamped,
       
    70               'conversion_syntax' : InvalidOperation,
       
    71               'division_by_zero' : DivisionByZero,
       
    72               'division_impossible' : InvalidOperation,
       
    73               'division_undefined' : InvalidOperation,
       
    74               'inexact' : Inexact,
       
    75               'invalid_context' : InvalidOperation,
       
    76               'invalid_operation' : InvalidOperation,
       
    77               'overflow' : Overflow,
       
    78               'rounded' : Rounded,
       
    79               'subnormal' : Subnormal,
       
    80               'underflow' : Underflow}
       
    81 
       
    82 
       
    83 def Nonfunction(*args):
       
    84     """Doesn't do anything."""
       
    85     return None
       
    86 
       
    87 RoundingDict = {'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,
       
    93                 'up' : ROUND_UP,
       
    94                 '05up' : ROUND_05UP}
       
    95 
       
    96 # Name adapter to be able to change the Decimal and Context
       
    97 # interface without changing the test files from Cowlishaw
       
    98 nameAdapter = {'and':'logical_and',
       
    99                'apply':'_apply',
       
   100                'class':'number_class',
       
   101                'comparesig':'compare_signal',
       
   102                'comparetotal':'compare_total',
       
   103                'comparetotmag':'compare_total_mag',
       
   104                'copy':'copy_decimal',
       
   105                'copyabs':'copy_abs',
       
   106                'copynegate':'copy_negate',
       
   107                'copysign':'copy_sign',
       
   108                'divideint':'divide_int',
       
   109                'invert':'logical_invert',
       
   110                'iscanonical':'is_canonical',
       
   111                'isfinite':'is_finite',
       
   112                'isinfinite':'is_infinite',
       
   113                'isnan':'is_nan',
       
   114                'isnormal':'is_normal',
       
   115                'isqnan':'is_qnan',
       
   116                'issigned':'is_signed',
       
   117                'issnan':'is_snan',
       
   118                'issubnormal':'is_subnormal',
       
   119                'iszero':'is_zero',
       
   120                'maxmag':'max_mag',
       
   121                'minmag':'min_mag',
       
   122                'nextminus':'next_minus',
       
   123                'nextplus':'next_plus',
       
   124                'nexttoward':'next_toward',
       
   125                'or':'logical_or',
       
   126                'reduce':'normalize',
       
   127                'remaindernear':'remainder_near',
       
   128                'samequantum':'same_quantum',
       
   129                'squareroot':'sqrt',
       
   130                'toeng':'to_eng_string',
       
   131                'tointegral':'to_integral_value',
       
   132                'tointegralx':'to_integral_exact',
       
   133                'tosci':'to_sci_string',
       
   134                'xor':'logical_xor',
       
   135               }
       
   136 
       
   137 # The following functions return True/False rather than a Decimal instance
       
   138 
       
   139 LOGICAL_FUNCTIONS = (
       
   140     'is_canonical',
       
   141     'is_finite',
       
   142     'is_infinite',
       
   143     'is_nan',
       
   144     'is_normal',
       
   145     'is_qnan',
       
   146     'is_signed',
       
   147     'is_snan',
       
   148     'is_subnormal',
       
   149     'is_zero',
       
   150     'same_quantum',
       
   151     )
       
   152 
       
   153 # For some operations (currently exp, ln, log10, power), the decNumber
       
   154 # reference implementation imposes additional restrictions on the
       
   155 # context and operands.  These restrictions are not part of the
       
   156 # specification; however, the effect of these restrictions does show
       
   157 # up in some of the testcases.  We skip testcases that violate these
       
   158 # restrictions, since Decimal behaves differently from decNumber for
       
   159 # these testcases so these testcases would otherwise fail.
       
   160 
       
   161 decNumberRestricted = ('power', 'ln', 'log10', 'exp')
       
   162 DEC_MAX_MATH = 999999
       
   163 def outside_decNumber_bounds(v, context):
       
   164     if (context.prec > DEC_MAX_MATH or
       
   165         context.Emax > DEC_MAX_MATH or
       
   166         -context.Emin > DEC_MAX_MATH):
       
   167         return True
       
   168     if not v._is_special and v and (
       
   169         len(v._int) > DEC_MAX_MATH or
       
   170         v.adjusted() > DEC_MAX_MATH or
       
   171         v.adjusted() < 1-2*DEC_MAX_MATH):
       
   172         return True
       
   173     return False
       
   174 
       
   175 class DecimalTest(unittest.TestCase):
       
   176     """Class which tests the Decimal class against the test cases.
       
   177 
       
   178     Changed for unittest.
       
   179     """
       
   180     def setUp(self):
       
   181         self.context = Context()
       
   182         for key in DefaultContext.traps.keys():
       
   183             DefaultContext.traps[key] = 1
       
   184         self.ignore_list = ['#']
       
   185         # Basically, a # means return NaN InvalidOperation.
       
   186         # Different from a sNaN in trim
       
   187 
       
   188         self.ChangeDict = {'precision' : self.change_precision,
       
   189                       'rounding' : self.change_rounding_method,
       
   190                       'maxexponent' : self.change_max_exponent,
       
   191                       'minexponent' : self.change_min_exponent,
       
   192                       'clamp' : self.change_clamp}
       
   193 
       
   194     def tearDown(self):
       
   195         """Cleaning up enviroment."""
       
   196         # leaving context in original state
       
   197         for key in DefaultContext.traps.keys():
       
   198             DefaultContext.traps[key] = 0
       
   199         return
       
   200 
       
   201     def eval_file(self, file):
       
   202         global skip_expected
       
   203         if skip_expected:
       
   204             raise TestSkipped
       
   205             return
       
   206         for line in open(file).xreadlines():
       
   207             line = line.replace('\r\n', '').replace('\n', '')
       
   208             #print line
       
   209             try:
       
   210                 t = self.eval_line(line)
       
   211             except DecimalException, exception:
       
   212                 #Exception raised where there shoudn't have been one.
       
   213                 self.fail('Exception "'+exception.__class__.__name__ + '" raised on line '+line)
       
   214 
       
   215         return
       
   216 
       
   217     def eval_line(self, s):
       
   218         if s.find(' -> ') >= 0 and s[:2] != '--' and not s.startswith('  --'):
       
   219             s = (s.split('->')[0] + '->' +
       
   220                  s.split('->')[1].split('--')[0]).strip()
       
   221         else:
       
   222             s = s.split('--')[0].strip()
       
   223 
       
   224         for ignore in self.ignore_list:
       
   225             if s.find(ignore) >= 0:
       
   226                 #print s.split()[0], 'NotImplemented--', ignore
       
   227                 return
       
   228         if not s:
       
   229             return
       
   230         elif ':' in s:
       
   231             return self.eval_directive(s)
       
   232         else:
       
   233             return self.eval_equation(s)
       
   234 
       
   235     def eval_directive(self, s):
       
   236         funct, value = map(lambda x: x.strip().lower(), s.split(':'))
       
   237         if funct == 'rounding':
       
   238             value = RoundingDict[value]
       
   239         else:
       
   240             try:
       
   241                 value = int(value)
       
   242             except ValueError:
       
   243                 pass
       
   244 
       
   245         funct = self.ChangeDict.get(funct, Nonfunction)
       
   246         funct(value)
       
   247 
       
   248     def eval_equation(self, s):
       
   249         #global DEFAULT_PRECISION
       
   250         #print DEFAULT_PRECISION
       
   251 
       
   252         if not TEST_ALL and random.random() < 0.90:
       
   253             return
       
   254 
       
   255         try:
       
   256             Sides = s.split('->')
       
   257             L = Sides[0].strip().split()
       
   258             id = L[0]
       
   259             if DEBUG:
       
   260                 print "Test ", id,
       
   261             funct = L[1].lower()
       
   262             valstemp = L[2:]
       
   263             L = Sides[1].strip().split()
       
   264             ans = L[0]
       
   265             exceptions = L[1:]
       
   266         except (TypeError, AttributeError, IndexError):
       
   267             raise InvalidOperation
       
   268         def FixQuotes(val):
       
   269             val = val.replace("''", 'SingleQuote').replace('""', 'DoubleQuote')
       
   270             val = val.replace("'", '').replace('"', '')
       
   271             val = val.replace('SingleQuote', "'").replace('DoubleQuote', '"')
       
   272             return val
       
   273         fname = nameAdapter.get(funct, funct)
       
   274         if fname == 'rescale':
       
   275             return
       
   276         funct = getattr(self.context, fname)
       
   277         vals = []
       
   278         conglomerate = ''
       
   279         quote = 0
       
   280         theirexceptions = [ErrorNames[x.lower()] for x in exceptions]
       
   281 
       
   282         for exception in Signals:
       
   283             self.context.traps[exception] = 1 #Catch these bugs...
       
   284         for exception in theirexceptions:
       
   285             self.context.traps[exception] = 0
       
   286         for i, val in enumerate(valstemp):
       
   287             if val.count("'") % 2 == 1:
       
   288                 quote = 1 - quote
       
   289             if quote:
       
   290                 conglomerate = conglomerate + ' ' + val
       
   291                 continue
       
   292             else:
       
   293                 val = conglomerate + val
       
   294                 conglomerate = ''
       
   295             v = FixQuotes(val)
       
   296             if fname in ('to_sci_string', 'to_eng_string'):
       
   297                 if EXTENDEDERRORTEST:
       
   298                     for error in theirexceptions:
       
   299                         self.context.traps[error] = 1
       
   300                         try:
       
   301                             funct(self.context.create_decimal(v))
       
   302                         except error:
       
   303                             pass
       
   304                         except Signals, e:
       
   305                             self.fail("Raised %s in %s when %s disabled" % \
       
   306                                       (e, s, error))
       
   307                         else:
       
   308                             self.fail("Did not raise %s in %s" % (error, s))
       
   309                         self.context.traps[error] = 0
       
   310                 v = self.context.create_decimal(v)
       
   311             else:
       
   312                 v = Decimal(v, self.context)
       
   313             vals.append(v)
       
   314 
       
   315         ans = FixQuotes(ans)
       
   316 
       
   317         # skip tests that are related to bounds imposed in the decNumber
       
   318         # reference implementation
       
   319         if fname in decNumberRestricted:
       
   320             if fname == 'power':
       
   321                 if not (vals[1]._isinteger() and
       
   322                         -1999999997 <= vals[1] <= 999999999):
       
   323                     if outside_decNumber_bounds(vals[0], self.context) or \
       
   324                             outside_decNumber_bounds(vals[1], self.context):
       
   325                         #print "Skipping test %s" % s
       
   326                         return
       
   327             else:
       
   328                 if outside_decNumber_bounds(vals[0], self.context):
       
   329                     #print "Skipping test %s" % s
       
   330                     return
       
   331 
       
   332 
       
   333         if EXTENDEDERRORTEST and fname not in ('to_sci_string', 'to_eng_string'):
       
   334             for error in theirexceptions:
       
   335                 self.context.traps[error] = 1
       
   336                 try:
       
   337                     funct(*vals)
       
   338                 except error:
       
   339                     pass
       
   340                 except Signals, e:
       
   341                     self.fail("Raised %s in %s when %s disabled" % \
       
   342                               (e, s, error))
       
   343                 else:
       
   344                     self.fail("Did not raise %s in %s" % (error, s))
       
   345                 self.context.traps[error] = 0
       
   346         if DEBUG:
       
   347             print "--", self.context
       
   348         try:
       
   349             result = str(funct(*vals))
       
   350             if fname in LOGICAL_FUNCTIONS:
       
   351                 result = str(int(eval(result))) # 'True', 'False' -> '1', '0'
       
   352         except Signals, error:
       
   353             self.fail("Raised %s in %s" % (error, s))
       
   354         except: #Catch any error long enough to state the test case.
       
   355             print "ERROR:", s
       
   356             raise
       
   357 
       
   358         myexceptions = self.getexceptions()
       
   359         self.context.clear_flags()
       
   360 
       
   361         myexceptions.sort()
       
   362         theirexceptions.sort()
       
   363 
       
   364         self.assertEqual(result, ans,
       
   365                          'Incorrect answer for ' + s + ' -- got ' + result)
       
   366         self.assertEqual(myexceptions, theirexceptions,
       
   367               'Incorrect flags set in ' + s + ' -- got ' + str(myexceptions))
       
   368         return
       
   369 
       
   370     def getexceptions(self):
       
   371         return [e for e in Signals if self.context.flags[e]]
       
   372 
       
   373     def change_precision(self, prec):
       
   374         self.context.prec = prec
       
   375     def change_rounding_method(self, rounding):
       
   376         self.context.rounding = rounding
       
   377     def change_min_exponent(self, exp):
       
   378         self.context.Emin = exp
       
   379     def change_max_exponent(self, exp):
       
   380         self.context.Emax = exp
       
   381     def change_clamp(self, clamp):
       
   382         self.context._clamp = clamp
       
   383 
       
   384 
       
   385 
       
   386 # The following classes test the behaviour of Decimal according to PEP 327
       
   387 
       
   388 class DecimalExplicitConstructionTest(unittest.TestCase):
       
   389     '''Unit tests for Explicit Construction cases of Decimal.'''
       
   390 
       
   391     def test_explicit_empty(self):
       
   392         self.assertEqual(Decimal(), Decimal("0"))
       
   393 
       
   394     def test_explicit_from_None(self):
       
   395         self.assertRaises(TypeError, Decimal, None)
       
   396 
       
   397     def test_explicit_from_int(self):
       
   398 
       
   399         #positive
       
   400         d = Decimal(45)
       
   401         self.assertEqual(str(d), '45')
       
   402 
       
   403         #very large positive
       
   404         d = Decimal(500000123)
       
   405         self.assertEqual(str(d), '500000123')
       
   406 
       
   407         #negative
       
   408         d = Decimal(-45)
       
   409         self.assertEqual(str(d), '-45')
       
   410 
       
   411         #zero
       
   412         d = Decimal(0)
       
   413         self.assertEqual(str(d), '0')
       
   414 
       
   415     def test_explicit_from_string(self):
       
   416 
       
   417         #empty
       
   418         self.assertEqual(str(Decimal('')), 'NaN')
       
   419 
       
   420         #int
       
   421         self.assertEqual(str(Decimal('45')), '45')
       
   422 
       
   423         #float
       
   424         self.assertEqual(str(Decimal('45.34')), '45.34')
       
   425 
       
   426         #engineer notation
       
   427         self.assertEqual(str(Decimal('45e2')), '4.5E+3')
       
   428 
       
   429         #just not a number
       
   430         self.assertEqual(str(Decimal('ugly')), 'NaN')
       
   431 
       
   432     def test_explicit_from_tuples(self):
       
   433 
       
   434         #zero
       
   435         d = Decimal( (0, (0,), 0) )
       
   436         self.assertEqual(str(d), '0')
       
   437 
       
   438         #int
       
   439         d = Decimal( (1, (4, 5), 0) )
       
   440         self.assertEqual(str(d), '-45')
       
   441 
       
   442         #float
       
   443         d = Decimal( (0, (4, 5, 3, 4), -2) )
       
   444         self.assertEqual(str(d), '45.34')
       
   445 
       
   446         #weird
       
   447         d = Decimal( (1, (4, 3, 4, 9, 1, 3, 5, 3, 4), -25) )
       
   448         self.assertEqual(str(d), '-4.34913534E-17')
       
   449 
       
   450         #wrong number of items
       
   451         self.assertRaises(ValueError, Decimal, (1, (4, 3, 4, 9, 1)) )
       
   452 
       
   453         #bad sign
       
   454         self.assertRaises(ValueError, Decimal, (8, (4, 3, 4, 9, 1), 2) )
       
   455         self.assertRaises(ValueError, Decimal, (0., (4, 3, 4, 9, 1), 2) )
       
   456         self.assertRaises(ValueError, Decimal, (Decimal(1), (4, 3, 4, 9, 1), 2))
       
   457 
       
   458         #bad exp
       
   459         self.assertRaises(ValueError, Decimal, (1, (4, 3, 4, 9, 1), 'wrong!') )
       
   460         self.assertRaises(ValueError, Decimal, (1, (4, 3, 4, 9, 1), 0.) )
       
   461         self.assertRaises(ValueError, Decimal, (1, (4, 3, 4, 9, 1), '1') )
       
   462 
       
   463         #bad coefficients
       
   464         self.assertRaises(ValueError, Decimal, (1, (4, 3, 4, None, 1), 2) )
       
   465         self.assertRaises(ValueError, Decimal, (1, (4, -3, 4, 9, 1), 2) )
       
   466         self.assertRaises(ValueError, Decimal, (1, (4, 10, 4, 9, 1), 2) )
       
   467         self.assertRaises(ValueError, Decimal, (1, (4, 3, 4, 'a', 1), 2) )
       
   468 
       
   469     def test_explicit_from_Decimal(self):
       
   470 
       
   471         #positive
       
   472         d = Decimal(45)
       
   473         e = Decimal(d)
       
   474         self.assertEqual(str(e), '45')
       
   475         self.assertNotEqual(id(d), id(e))
       
   476 
       
   477         #very large positive
       
   478         d = Decimal(500000123)
       
   479         e = Decimal(d)
       
   480         self.assertEqual(str(e), '500000123')
       
   481         self.assertNotEqual(id(d), id(e))
       
   482 
       
   483         #negative
       
   484         d = Decimal(-45)
       
   485         e = Decimal(d)
       
   486         self.assertEqual(str(e), '-45')
       
   487         self.assertNotEqual(id(d), id(e))
       
   488 
       
   489         #zero
       
   490         d = Decimal(0)
       
   491         e = Decimal(d)
       
   492         self.assertEqual(str(e), '0')
       
   493         self.assertNotEqual(id(d), id(e))
       
   494 
       
   495     def test_explicit_context_create_decimal(self):
       
   496 
       
   497         nc = copy.copy(getcontext())
       
   498         nc.prec = 3
       
   499 
       
   500         # empty
       
   501         d = Decimal()
       
   502         self.assertEqual(str(d), '0')
       
   503         d = nc.create_decimal()
       
   504         self.assertEqual(str(d), '0')
       
   505 
       
   506         # from None
       
   507         self.assertRaises(TypeError, nc.create_decimal, None)
       
   508 
       
   509         # from int
       
   510         d = nc.create_decimal(456)
       
   511         self.failUnless(isinstance(d, Decimal))
       
   512         self.assertEqual(nc.create_decimal(45678),
       
   513                          nc.create_decimal('457E+2'))
       
   514 
       
   515         # from string
       
   516         d = Decimal('456789')
       
   517         self.assertEqual(str(d), '456789')
       
   518         d = nc.create_decimal('456789')
       
   519         self.assertEqual(str(d), '4.57E+5')
       
   520 
       
   521         # from tuples
       
   522         d = Decimal( (1, (4, 3, 4, 9, 1, 3, 5, 3, 4), -25) )
       
   523         self.assertEqual(str(d), '-4.34913534E-17')
       
   524         d = nc.create_decimal( (1, (4, 3, 4, 9, 1, 3, 5, 3, 4), -25) )
       
   525         self.assertEqual(str(d), '-4.35E-17')
       
   526 
       
   527         # from Decimal
       
   528         prevdec = Decimal(500000123)
       
   529         d = Decimal(prevdec)
       
   530         self.assertEqual(str(d), '500000123')
       
   531         d = nc.create_decimal(prevdec)
       
   532         self.assertEqual(str(d), '5.00E+8')
       
   533 
       
   534 
       
   535 class DecimalImplicitConstructionTest(unittest.TestCase):
       
   536     '''Unit tests for Implicit Construction cases of Decimal.'''
       
   537 
       
   538     def test_implicit_from_None(self):
       
   539         self.assertRaises(TypeError, eval, 'Decimal(5) + None', globals())
       
   540 
       
   541     def test_implicit_from_int(self):
       
   542         #normal
       
   543         self.assertEqual(str(Decimal(5) + 45), '50')
       
   544         #exceeding precision
       
   545         self.assertEqual(Decimal(5) + 123456789000, Decimal(123456789000))
       
   546 
       
   547     def test_implicit_from_string(self):
       
   548         self.assertRaises(TypeError, eval, 'Decimal(5) + "3"', globals())
       
   549 
       
   550     def test_implicit_from_float(self):
       
   551         self.assertRaises(TypeError, eval, 'Decimal(5) + 2.2', globals())
       
   552 
       
   553     def test_implicit_from_Decimal(self):
       
   554         self.assertEqual(Decimal(5) + Decimal(45), Decimal(50))
       
   555 
       
   556     def test_rop(self):
       
   557         # Allow other classes to be trained to interact with Decimals
       
   558         class E:
       
   559             def __divmod__(self, other):
       
   560                 return 'divmod ' + str(other)
       
   561             def __rdivmod__(self, other):
       
   562                 return str(other) + ' rdivmod'
       
   563             def __lt__(self, other):
       
   564                 return 'lt ' + str(other)
       
   565             def __gt__(self, other):
       
   566                 return 'gt ' + str(other)
       
   567             def __le__(self, other):
       
   568                 return 'le ' + str(other)
       
   569             def __ge__(self, other):
       
   570                 return 'ge ' + str(other)
       
   571             def __eq__(self, other):
       
   572                 return 'eq ' + str(other)
       
   573             def __ne__(self, other):
       
   574                 return 'ne ' + str(other)
       
   575 
       
   576         self.assertEqual(divmod(E(), Decimal(10)), 'divmod 10')
       
   577         self.assertEqual(divmod(Decimal(10), E()), '10 rdivmod')
       
   578         self.assertEqual(eval('Decimal(10) < E()'), 'gt 10')
       
   579         self.assertEqual(eval('Decimal(10) > E()'), 'lt 10')
       
   580         self.assertEqual(eval('Decimal(10) <= E()'), 'ge 10')
       
   581         self.assertEqual(eval('Decimal(10) >= E()'), 'le 10')
       
   582         self.assertEqual(eval('Decimal(10) == E()'), 'eq 10')
       
   583         self.assertEqual(eval('Decimal(10) != E()'), 'ne 10')
       
   584 
       
   585         # insert operator methods and then exercise them
       
   586         oplist = [
       
   587             ('+', '__add__', '__radd__'),
       
   588             ('-', '__sub__', '__rsub__'),
       
   589             ('*', '__mul__', '__rmul__'),
       
   590             ('%', '__mod__', '__rmod__'),
       
   591             ('//', '__floordiv__', '__rfloordiv__'),
       
   592             ('**', '__pow__', '__rpow__')
       
   593         ]
       
   594         if 1/2 == 0:
       
   595             # testing with classic division, so add __div__
       
   596             oplist.append(('/', '__div__', '__rdiv__'))
       
   597         else:
       
   598             # testing with -Qnew, so add __truediv__
       
   599             oplist.append(('/', '__truediv__', '__rtruediv__'))
       
   600 
       
   601         for sym, lop, rop in oplist:
       
   602             setattr(E, lop, lambda self, other: 'str' + lop + str(other))
       
   603             setattr(E, rop, lambda self, other: str(other) + rop + 'str')
       
   604             self.assertEqual(eval('E()' + sym + 'Decimal(10)'),
       
   605                              'str' + lop + '10')
       
   606             self.assertEqual(eval('Decimal(10)' + sym + 'E()'),
       
   607                              '10' + rop + 'str')
       
   608 
       
   609 class DecimalArithmeticOperatorsTest(unittest.TestCase):
       
   610     '''Unit tests for all arithmetic operators, binary and unary.'''
       
   611 
       
   612     def test_addition(self):
       
   613 
       
   614         d1 = Decimal('-11.1')
       
   615         d2 = Decimal('22.2')
       
   616 
       
   617         #two Decimals
       
   618         self.assertEqual(d1+d2, Decimal('11.1'))
       
   619         self.assertEqual(d2+d1, Decimal('11.1'))
       
   620 
       
   621         #with other type, left
       
   622         c = d1 + 5
       
   623         self.assertEqual(c, Decimal('-6.1'))
       
   624         self.assertEqual(type(c), type(d1))
       
   625 
       
   626         #with other type, right
       
   627         c = 5 + d1
       
   628         self.assertEqual(c, Decimal('-6.1'))
       
   629         self.assertEqual(type(c), type(d1))
       
   630 
       
   631         #inline with decimal
       
   632         d1 += d2
       
   633         self.assertEqual(d1, Decimal('11.1'))
       
   634 
       
   635         #inline with other type
       
   636         d1 += 5
       
   637         self.assertEqual(d1, Decimal('16.1'))
       
   638 
       
   639     def test_subtraction(self):
       
   640 
       
   641         d1 = Decimal('-11.1')
       
   642         d2 = Decimal('22.2')
       
   643 
       
   644         #two Decimals
       
   645         self.assertEqual(d1-d2, Decimal('-33.3'))
       
   646         self.assertEqual(d2-d1, Decimal('33.3'))
       
   647 
       
   648         #with other type, left
       
   649         c = d1 - 5
       
   650         self.assertEqual(c, Decimal('-16.1'))
       
   651         self.assertEqual(type(c), type(d1))
       
   652 
       
   653         #with other type, right
       
   654         c = 5 - d1
       
   655         self.assertEqual(c, Decimal('16.1'))
       
   656         self.assertEqual(type(c), type(d1))
       
   657 
       
   658         #inline with decimal
       
   659         d1 -= d2
       
   660         self.assertEqual(d1, Decimal('-33.3'))
       
   661 
       
   662         #inline with other type
       
   663         d1 -= 5
       
   664         self.assertEqual(d1, Decimal('-38.3'))
       
   665 
       
   666     def test_multiplication(self):
       
   667 
       
   668         d1 = Decimal('-5')
       
   669         d2 = Decimal('3')
       
   670 
       
   671         #two Decimals
       
   672         self.assertEqual(d1*d2, Decimal('-15'))
       
   673         self.assertEqual(d2*d1, Decimal('-15'))
       
   674 
       
   675         #with other type, left
       
   676         c = d1 * 5
       
   677         self.assertEqual(c, Decimal('-25'))
       
   678         self.assertEqual(type(c), type(d1))
       
   679 
       
   680         #with other type, right
       
   681         c = 5 * d1
       
   682         self.assertEqual(c, Decimal('-25'))
       
   683         self.assertEqual(type(c), type(d1))
       
   684 
       
   685         #inline with decimal
       
   686         d1 *= d2
       
   687         self.assertEqual(d1, Decimal('-15'))
       
   688 
       
   689         #inline with other type
       
   690         d1 *= 5
       
   691         self.assertEqual(d1, Decimal('-75'))
       
   692 
       
   693     def test_division(self):
       
   694 
       
   695         d1 = Decimal('-5')
       
   696         d2 = Decimal('2')
       
   697 
       
   698         #two Decimals
       
   699         self.assertEqual(d1/d2, Decimal('-2.5'))
       
   700         self.assertEqual(d2/d1, Decimal('-0.4'))
       
   701 
       
   702         #with other type, left
       
   703         c = d1 / 4
       
   704         self.assertEqual(c, Decimal('-1.25'))
       
   705         self.assertEqual(type(c), type(d1))
       
   706 
       
   707         #with other type, right
       
   708         c = 4 / d1
       
   709         self.assertEqual(c, Decimal('-0.8'))
       
   710         self.assertEqual(type(c), type(d1))
       
   711 
       
   712         #inline with decimal
       
   713         d1 /= d2
       
   714         self.assertEqual(d1, Decimal('-2.5'))
       
   715 
       
   716         #inline with other type
       
   717         d1 /= 4
       
   718         self.assertEqual(d1, Decimal('-0.625'))
       
   719 
       
   720     def test_floor_division(self):
       
   721 
       
   722         d1 = Decimal('5')
       
   723         d2 = Decimal('2')
       
   724 
       
   725         #two Decimals
       
   726         self.assertEqual(d1//d2, Decimal('2'))
       
   727         self.assertEqual(d2//d1, Decimal('0'))
       
   728 
       
   729         #with other type, left
       
   730         c = d1 // 4
       
   731         self.assertEqual(c, Decimal('1'))
       
   732         self.assertEqual(type(c), type(d1))
       
   733 
       
   734         #with other type, right
       
   735         c = 7 // d1
       
   736         self.assertEqual(c, Decimal('1'))
       
   737         self.assertEqual(type(c), type(d1))
       
   738 
       
   739         #inline with decimal
       
   740         d1 //= d2
       
   741         self.assertEqual(d1, Decimal('2'))
       
   742 
       
   743         #inline with other type
       
   744         d1 //= 2
       
   745         self.assertEqual(d1, Decimal('1'))
       
   746 
       
   747     def test_powering(self):
       
   748 
       
   749         d1 = Decimal('5')
       
   750         d2 = Decimal('2')
       
   751 
       
   752         #two Decimals
       
   753         self.assertEqual(d1**d2, Decimal('25'))
       
   754         self.assertEqual(d2**d1, Decimal('32'))
       
   755 
       
   756         #with other type, left
       
   757         c = d1 ** 4
       
   758         self.assertEqual(c, Decimal('625'))
       
   759         self.assertEqual(type(c), type(d1))
       
   760 
       
   761         #with other type, right
       
   762         c = 7 ** d1
       
   763         self.assertEqual(c, Decimal('16807'))
       
   764         self.assertEqual(type(c), type(d1))
       
   765 
       
   766         #inline with decimal
       
   767         d1 **= d2
       
   768         self.assertEqual(d1, Decimal('25'))
       
   769 
       
   770         #inline with other type
       
   771         d1 **= 4
       
   772         self.assertEqual(d1, Decimal('390625'))
       
   773 
       
   774     def test_module(self):
       
   775 
       
   776         d1 = Decimal('5')
       
   777         d2 = Decimal('2')
       
   778 
       
   779         #two Decimals
       
   780         self.assertEqual(d1%d2, Decimal('1'))
       
   781         self.assertEqual(d2%d1, Decimal('2'))
       
   782 
       
   783         #with other type, left
       
   784         c = d1 % 4
       
   785         self.assertEqual(c, Decimal('1'))
       
   786         self.assertEqual(type(c), type(d1))
       
   787 
       
   788         #with other type, right
       
   789         c = 7 % d1
       
   790         self.assertEqual(c, Decimal('2'))
       
   791         self.assertEqual(type(c), type(d1))
       
   792 
       
   793         #inline with decimal
       
   794         d1 %= d2
       
   795         self.assertEqual(d1, Decimal('1'))
       
   796 
       
   797         #inline with other type
       
   798         d1 %= 4
       
   799         self.assertEqual(d1, Decimal('1'))
       
   800 
       
   801     def test_floor_div_module(self):
       
   802 
       
   803         d1 = Decimal('5')
       
   804         d2 = Decimal('2')
       
   805 
       
   806         #two Decimals
       
   807         (p, q) = divmod(d1, d2)
       
   808         self.assertEqual(p, Decimal('2'))
       
   809         self.assertEqual(q, Decimal('1'))
       
   810         self.assertEqual(type(p), type(d1))
       
   811         self.assertEqual(type(q), type(d1))
       
   812 
       
   813         #with other type, left
       
   814         (p, q) = divmod(d1, 4)
       
   815         self.assertEqual(p, Decimal('1'))
       
   816         self.assertEqual(q, Decimal('1'))
       
   817         self.assertEqual(type(p), type(d1))
       
   818         self.assertEqual(type(q), type(d1))
       
   819 
       
   820         #with other type, right
       
   821         (p, q) = divmod(7, d1)
       
   822         self.assertEqual(p, Decimal('1'))
       
   823         self.assertEqual(q, Decimal('2'))
       
   824         self.assertEqual(type(p), type(d1))
       
   825         self.assertEqual(type(q), type(d1))
       
   826 
       
   827     def test_unary_operators(self):
       
   828         self.assertEqual(+Decimal(45), Decimal(+45))           #  +
       
   829         self.assertEqual(-Decimal(45), Decimal(-45))           #  -
       
   830         self.assertEqual(abs(Decimal(45)), abs(Decimal(-45)))  # abs
       
   831 
       
   832 
       
   833 # The following are two functions used to test threading in the next class
       
   834 
       
   835 def thfunc1(cls):
       
   836     d1 = Decimal(1)
       
   837     d3 = Decimal(3)
       
   838     cls.assertEqual(d1/d3, Decimal('0.333333333'))
       
   839     cls.synchro.wait()
       
   840     cls.assertEqual(d1/d3, Decimal('0.333333333'))
       
   841     cls.finish1.set()
       
   842     return
       
   843 
       
   844 def thfunc2(cls):
       
   845     d1 = Decimal(1)
       
   846     d3 = Decimal(3)
       
   847     cls.assertEqual(d1/d3, Decimal('0.333333333'))
       
   848     thiscontext = getcontext()
       
   849     thiscontext.prec = 18
       
   850     cls.assertEqual(d1/d3, Decimal('0.333333333333333333'))
       
   851     cls.synchro.set()
       
   852     cls.finish2.set()
       
   853     return
       
   854 
       
   855 
       
   856 class DecimalUseOfContextTest(unittest.TestCase):
       
   857     '''Unit tests for Use of Context cases in Decimal.'''
       
   858 
       
   859     try:
       
   860         import threading
       
   861     except ImportError:
       
   862         threading = None
       
   863 
       
   864     # Take care executing this test from IDLE, there's an issue in threading
       
   865     # that hangs IDLE and I couldn't find it
       
   866 
       
   867     def test_threading(self):
       
   868         #Test the "threading isolation" of a Context.
       
   869 
       
   870         self.synchro = threading.Event()
       
   871         self.finish1 = threading.Event()
       
   872         self.finish2 = threading.Event()
       
   873 
       
   874         th1 = threading.Thread(target=thfunc1, args=(self,))
       
   875         th2 = threading.Thread(target=thfunc2, args=(self,))
       
   876 
       
   877         th1.start()
       
   878         th2.start()
       
   879 
       
   880         self.finish1.wait()
       
   881         self.finish2.wait()
       
   882         return
       
   883 
       
   884     if threading is None:
       
   885         del test_threading
       
   886 
       
   887 
       
   888 class DecimalUsabilityTest(unittest.TestCase):
       
   889     '''Unit tests for Usability cases of Decimal.'''
       
   890 
       
   891     def test_comparison_operators(self):
       
   892 
       
   893         da = Decimal('23.42')
       
   894         db = Decimal('23.42')
       
   895         dc = Decimal('45')
       
   896 
       
   897         #two Decimals
       
   898         self.failUnless(dc > da)
       
   899         self.failUnless(dc >= da)
       
   900         self.failUnless(da < dc)
       
   901         self.failUnless(da <= dc)
       
   902         self.failUnless(da == db)
       
   903         self.failUnless(da != dc)
       
   904         self.failUnless(da <= db)
       
   905         self.failUnless(da >= db)
       
   906         self.assertEqual(cmp(dc,da), 1)
       
   907         self.assertEqual(cmp(da,dc), -1)
       
   908         self.assertEqual(cmp(da,db), 0)
       
   909 
       
   910         #a Decimal and an int
       
   911         self.failUnless(dc > 23)
       
   912         self.failUnless(23 < dc)
       
   913         self.failUnless(dc == 45)
       
   914         self.assertEqual(cmp(dc,23), 1)
       
   915         self.assertEqual(cmp(23,dc), -1)
       
   916         self.assertEqual(cmp(dc,45), 0)
       
   917 
       
   918         #a Decimal and uncomparable
       
   919         self.assertNotEqual(da, 'ugly')
       
   920         self.assertNotEqual(da, 32.7)
       
   921         self.assertNotEqual(da, object())
       
   922         self.assertNotEqual(da, object)
       
   923 
       
   924         # sortable
       
   925         a = map(Decimal, xrange(100))
       
   926         b =  a[:]
       
   927         random.shuffle(a)
       
   928         a.sort()
       
   929         self.assertEqual(a, b)
       
   930 
       
   931         # with None
       
   932         self.assertFalse(Decimal(1) < None)
       
   933         self.assertTrue(Decimal(1) > None)
       
   934 
       
   935     def test_copy_and_deepcopy_methods(self):
       
   936         d = Decimal('43.24')
       
   937         c = copy.copy(d)
       
   938         self.assertEqual(id(c), id(d))
       
   939         dc = copy.deepcopy(d)
       
   940         self.assertEqual(id(dc), id(d))
       
   941 
       
   942     def test_hash_method(self):
       
   943         #just that it's hashable
       
   944         hash(Decimal(23))
       
   945 
       
   946         test_values = [Decimal(sign*(2**m + n))
       
   947                        for m in [0, 14, 15, 16, 17, 30, 31,
       
   948                                  32, 33, 62, 63, 64, 65, 66]
       
   949                        for n in range(-10, 10)
       
   950                        for sign in [-1, 1]]
       
   951         test_values.extend([
       
   952                 Decimal("-0"), # zeros
       
   953                 Decimal("0.00"),
       
   954                 Decimal("-0.000"),
       
   955                 Decimal("0E10"),
       
   956                 Decimal("-0E12"),
       
   957                 Decimal("10.0"), # negative exponent
       
   958                 Decimal("-23.00000"),
       
   959                 Decimal("1230E100"), # positive exponent
       
   960                 Decimal("-4.5678E50"),
       
   961                 # a value for which hash(n) != hash(n % (2**64-1))
       
   962                 # in Python pre-2.6
       
   963                 Decimal(2**64 + 2**32 - 1),
       
   964                 # selection of values which fail with the Python 2.6
       
   965                 # version of Decimal.__hash__ and the Python 2.5
       
   966                 # version of long.__hash__.  Included here to prevent
       
   967                 # an accidental backport of the Decimal.__hash__ from
       
   968                 # Python 2.6 to Python 2.5.
       
   969                 Decimal("1.634E100"),
       
   970                 Decimal("90.697E100"),
       
   971                 Decimal("188.83E100"),
       
   972                 Decimal("1652.9E100"),
       
   973                 Decimal("56531E100"),
       
   974                 ])
       
   975 
       
   976         # check that hash(d) == hash(int(d)) for integral values
       
   977         for value in test_values:
       
   978             self.assertEqual(hash(value), hash(int(value)))
       
   979 
       
   980         #the same hash that to an int
       
   981         self.assertEqual(hash(Decimal(23)), hash(23))
       
   982         self.assertRaises(TypeError, hash, Decimal('NaN'))
       
   983         self.assert_(hash(Decimal('Inf')))
       
   984         self.assert_(hash(Decimal('-Inf')))
       
   985 
       
   986         # check that the value of the hash doesn't depend on the
       
   987         # current context (issue #1757)
       
   988         c = getcontext()
       
   989         old_precision = c.prec
       
   990         x = Decimal("123456789.1")
       
   991 
       
   992         c.prec = 6
       
   993         h1 = hash(x)
       
   994         c.prec = 10
       
   995         h2 = hash(x)
       
   996         c.prec = 16
       
   997         h3 = hash(x)
       
   998 
       
   999         self.assertEqual(h1, h2)
       
  1000         self.assertEqual(h1, h3)
       
  1001         c.prec = old_precision
       
  1002 
       
  1003     def test_min_and_max_methods(self):
       
  1004 
       
  1005         d1 = Decimal('15.32')
       
  1006         d2 = Decimal('28.5')
       
  1007         l1 = 15
       
  1008         l2 = 28
       
  1009 
       
  1010         #between Decimals
       
  1011         self.failUnless(min(d1,d2) is d1)
       
  1012         self.failUnless(min(d2,d1) is d1)
       
  1013         self.failUnless(max(d1,d2) is d2)
       
  1014         self.failUnless(max(d2,d1) is d2)
       
  1015 
       
  1016         #between Decimal and long
       
  1017         self.failUnless(min(d1,l2) is d1)
       
  1018         self.failUnless(min(l2,d1) is d1)
       
  1019         self.failUnless(max(l1,d2) is d2)
       
  1020         self.failUnless(max(d2,l1) is d2)
       
  1021 
       
  1022     def test_as_nonzero(self):
       
  1023         #as false
       
  1024         self.failIf(Decimal(0))
       
  1025         #as true
       
  1026         self.failUnless(Decimal('0.372'))
       
  1027 
       
  1028     def test_tostring_methods(self):
       
  1029         #Test str and repr methods.
       
  1030 
       
  1031         d = Decimal('15.32')
       
  1032         self.assertEqual(str(d), '15.32')               # str
       
  1033         self.assertEqual(repr(d), 'Decimal("15.32")')   # repr
       
  1034 
       
  1035     def test_tonum_methods(self):
       
  1036         #Test float, int and long methods.
       
  1037 
       
  1038         d1 = Decimal('66')
       
  1039         d2 = Decimal('15.32')
       
  1040 
       
  1041         #int
       
  1042         self.assertEqual(int(d1), 66)
       
  1043         self.assertEqual(int(d2), 15)
       
  1044 
       
  1045         #long
       
  1046         self.assertEqual(long(d1), 66)
       
  1047         self.assertEqual(long(d2), 15)
       
  1048 
       
  1049         #float
       
  1050         self.assertEqual(float(d1), 66)
       
  1051         self.assertEqual(float(d2), 15.32)
       
  1052 
       
  1053     def test_eval_round_trip(self):
       
  1054 
       
  1055         #with zero
       
  1056         d = Decimal( (0, (0,), 0) )
       
  1057         self.assertEqual(d, eval(repr(d)))
       
  1058 
       
  1059         #int
       
  1060         d = Decimal( (1, (4, 5), 0) )
       
  1061         self.assertEqual(d, eval(repr(d)))
       
  1062 
       
  1063         #float
       
  1064         d = Decimal( (0, (4, 5, 3, 4), -2) )
       
  1065         self.assertEqual(d, eval(repr(d)))
       
  1066 
       
  1067         #weird
       
  1068         d = Decimal( (1, (4, 3, 4, 9, 1, 3, 5, 3, 4), -25) )
       
  1069         self.assertEqual(d, eval(repr(d)))
       
  1070 
       
  1071     def test_as_tuple(self):
       
  1072 
       
  1073         #with zero
       
  1074         d = Decimal(0)
       
  1075         self.assertEqual(d.as_tuple(), (0, (0,), 0) )
       
  1076 
       
  1077         #int
       
  1078         d = Decimal(-45)
       
  1079         self.assertEqual(d.as_tuple(), (1, (4, 5), 0) )
       
  1080 
       
  1081         #complicated string
       
  1082         d = Decimal("-4.34913534E-17")
       
  1083         self.assertEqual(d.as_tuple(), (1, (4, 3, 4, 9, 1, 3, 5, 3, 4), -25) )
       
  1084 
       
  1085         #inf
       
  1086         d = Decimal("Infinity")
       
  1087         self.assertEqual(d.as_tuple(), (0, (0,), 'F') )
       
  1088 
       
  1089         #leading zeros in coefficient should be stripped
       
  1090         d = Decimal( (0, (0, 0, 4, 0, 5, 3, 4), -2) )
       
  1091         self.assertEqual(d.as_tuple(), (0, (4, 0, 5, 3, 4), -2) )
       
  1092         d = Decimal( (1, (0, 0, 0), 37) )
       
  1093         self.assertEqual(d.as_tuple(), (1, (0,), 37))
       
  1094         d = Decimal( (1, (), 37) )
       
  1095         self.assertEqual(d.as_tuple(), (1, (0,), 37))
       
  1096 
       
  1097         #leading zeros in NaN diagnostic info should be stripped
       
  1098         d = Decimal( (0, (0, 0, 4, 0, 5, 3, 4), 'n') )
       
  1099         self.assertEqual(d.as_tuple(), (0, (4, 0, 5, 3, 4), 'n') )
       
  1100         d = Decimal( (1, (0, 0, 0), 'N') )
       
  1101         self.assertEqual(d.as_tuple(), (1, (), 'N') )
       
  1102         d = Decimal( (1, (), 'n') )
       
  1103         self.assertEqual(d.as_tuple(), (1, (), 'n') )
       
  1104 
       
  1105         #coefficient in infinity should be ignored
       
  1106         d = Decimal( (0, (4, 5, 3, 4), 'F') )
       
  1107         self.assertEqual(d.as_tuple(), (0, (0,), 'F'))
       
  1108         d = Decimal( (1, (0, 2, 7, 1), 'F') )
       
  1109         self.assertEqual(d.as_tuple(), (1, (0,), 'F'))
       
  1110 
       
  1111     def test_immutability_operations(self):
       
  1112         # Do operations and check that it didn't change change internal objects.
       
  1113 
       
  1114         d1 = Decimal('-25e55')
       
  1115         b1 = Decimal('-25e55')
       
  1116         d2 = Decimal('33e+33')
       
  1117         b2 = Decimal('33e+33')
       
  1118 
       
  1119         def checkSameDec(operation, useOther=False):
       
  1120             if useOther:
       
  1121                 eval("d1." + operation + "(d2)")
       
  1122                 self.assertEqual(d1._sign, b1._sign)
       
  1123                 self.assertEqual(d1._int, b1._int)
       
  1124                 self.assertEqual(d1._exp, b1._exp)
       
  1125                 self.assertEqual(d2._sign, b2._sign)
       
  1126                 self.assertEqual(d2._int, b2._int)
       
  1127                 self.assertEqual(d2._exp, b2._exp)
       
  1128             else:
       
  1129                 eval("d1." + operation + "()")
       
  1130                 self.assertEqual(d1._sign, b1._sign)
       
  1131                 self.assertEqual(d1._int, b1._int)
       
  1132                 self.assertEqual(d1._exp, b1._exp)
       
  1133             return
       
  1134 
       
  1135         Decimal(d1)
       
  1136         self.assertEqual(d1._sign, b1._sign)
       
  1137         self.assertEqual(d1._int, b1._int)
       
  1138         self.assertEqual(d1._exp, b1._exp)
       
  1139 
       
  1140         checkSameDec("__abs__")
       
  1141         checkSameDec("__add__", True)
       
  1142         checkSameDec("__div__", True)
       
  1143         checkSameDec("__divmod__", True)
       
  1144         checkSameDec("__cmp__", True)
       
  1145         checkSameDec("__float__")
       
  1146         checkSameDec("__floordiv__", True)
       
  1147         checkSameDec("__hash__")
       
  1148         checkSameDec("__int__")
       
  1149         checkSameDec("__long__")
       
  1150         checkSameDec("__mod__", True)
       
  1151         checkSameDec("__mul__", True)
       
  1152         checkSameDec("__neg__")
       
  1153         checkSameDec("__nonzero__")
       
  1154         checkSameDec("__pos__")
       
  1155         checkSameDec("__pow__", True)
       
  1156         checkSameDec("__radd__", True)
       
  1157         checkSameDec("__rdiv__", True)
       
  1158         checkSameDec("__rdivmod__", True)
       
  1159         checkSameDec("__repr__")
       
  1160         checkSameDec("__rfloordiv__", True)
       
  1161         checkSameDec("__rmod__", True)
       
  1162         checkSameDec("__rmul__", True)
       
  1163         checkSameDec("__rpow__", True)
       
  1164         checkSameDec("__rsub__", True)
       
  1165         checkSameDec("__str__")
       
  1166         checkSameDec("__sub__", True)
       
  1167         checkSameDec("__truediv__", True)
       
  1168         checkSameDec("adjusted")
       
  1169         checkSameDec("as_tuple")
       
  1170         checkSameDec("compare", True)
       
  1171         checkSameDec("max", True)
       
  1172         checkSameDec("min", True)
       
  1173         checkSameDec("normalize")
       
  1174         checkSameDec("quantize", True)
       
  1175         checkSameDec("remainder_near", True)
       
  1176         checkSameDec("same_quantum", True)
       
  1177         checkSameDec("sqrt")
       
  1178         checkSameDec("to_eng_string")
       
  1179         checkSameDec("to_integral")
       
  1180 
       
  1181     def test_subclassing(self):
       
  1182         # Different behaviours when subclassing Decimal
       
  1183 
       
  1184         class MyDecimal(Decimal):
       
  1185             pass
       
  1186 
       
  1187         d1 = MyDecimal(1)
       
  1188         d2 = MyDecimal(2)
       
  1189         d = d1 + d2
       
  1190         self.assertTrue(type(d) is Decimal)
       
  1191 
       
  1192         d = d1.max(d2)
       
  1193         self.assertTrue(type(d) is Decimal)
       
  1194 
       
  1195 
       
  1196 class DecimalPythonAPItests(unittest.TestCase):
       
  1197 
       
  1198     def test_pickle(self):
       
  1199         d = Decimal('-3.141590000')
       
  1200         p = pickle.dumps(d)
       
  1201         e = pickle.loads(p)
       
  1202         self.assertEqual(d, e)
       
  1203 
       
  1204     def test_int(self):
       
  1205         for x in range(-250, 250):
       
  1206             s = '%0.2f' % (x / 100.0)
       
  1207             # should work the same as for floats
       
  1208             self.assertEqual(int(Decimal(s)), int(float(s)))
       
  1209             # should work the same as to_integral in the ROUND_DOWN mode
       
  1210             d = Decimal(s)
       
  1211             r = d.to_integral(ROUND_DOWN)
       
  1212             self.assertEqual(Decimal(int(d)), r)
       
  1213 
       
  1214 class ContextAPItests(unittest.TestCase):
       
  1215 
       
  1216     def test_pickle(self):
       
  1217         c = Context()
       
  1218         e = pickle.loads(pickle.dumps(c))
       
  1219         for k in vars(c):
       
  1220             v1 = vars(c)[k]
       
  1221             v2 = vars(e)[k]
       
  1222             self.assertEqual(v1, v2)
       
  1223 
       
  1224     def test_equality_with_other_types(self):
       
  1225         self.assert_(Decimal(10) in ['a', 1.0, Decimal(10), (1,2), {}])
       
  1226         self.assert_(Decimal(10) not in ['a', 1.0, (1,2), {}])
       
  1227 
       
  1228     def test_copy(self):
       
  1229         # All copies should be deep
       
  1230         c = Context()
       
  1231         d = c.copy()
       
  1232         self.assertNotEqual(id(c), id(d))
       
  1233         self.assertNotEqual(id(c.flags), id(d.flags))
       
  1234         self.assertNotEqual(id(c.traps), id(d.traps))
       
  1235 
       
  1236 class WithStatementTest(unittest.TestCase):
       
  1237     # Can't do these as docstrings until Python 2.6
       
  1238     # as doctest can't handle __future__ statements
       
  1239 
       
  1240     def test_localcontext(self):
       
  1241         # Use a copy of the current context in the block
       
  1242         orig_ctx = getcontext()
       
  1243         with localcontext() as enter_ctx:
       
  1244             set_ctx = getcontext()
       
  1245         final_ctx = getcontext()
       
  1246         self.assert_(orig_ctx is final_ctx, 'did not restore context correctly')
       
  1247         self.assert_(orig_ctx is not set_ctx, 'did not copy the context')
       
  1248         self.assert_(set_ctx is enter_ctx, '__enter__ returned wrong context')
       
  1249 
       
  1250     def test_localcontextarg(self):
       
  1251         # Use a copy of the supplied context in the block
       
  1252         orig_ctx = getcontext()
       
  1253         new_ctx = Context(prec=42)
       
  1254         with localcontext(new_ctx) as enter_ctx:
       
  1255             set_ctx = getcontext()
       
  1256         final_ctx = getcontext()
       
  1257         self.assert_(orig_ctx is final_ctx, 'did not restore context correctly')
       
  1258         self.assert_(set_ctx.prec == new_ctx.prec, 'did not set correct context')
       
  1259         self.assert_(new_ctx is not set_ctx, 'did not copy the context')
       
  1260         self.assert_(set_ctx is enter_ctx, '__enter__ returned wrong context')
       
  1261 
       
  1262 class ContextFlags(unittest.TestCase):
       
  1263     def test_flags_irrelevant(self):
       
  1264         # check that the result (numeric result + flags raised) of an
       
  1265         # arithmetic operation doesn't depend on the current flags
       
  1266 
       
  1267         context = Context(prec=9, Emin = -999999999, Emax = 999999999,
       
  1268                     rounding=ROUND_HALF_EVEN, traps=[], flags=[])
       
  1269 
       
  1270         # operations that raise various flags, in the form (function, arglist)
       
  1271         operations = [
       
  1272             (context._apply, [Decimal("100E-1000000009")]),
       
  1273             (context.sqrt, [Decimal(2)]),
       
  1274             (context.add, [Decimal("1.23456789"), Decimal("9.87654321")]),
       
  1275             (context.multiply, [Decimal("1.23456789"), Decimal("9.87654321")]),
       
  1276             (context.subtract, [Decimal("1.23456789"), Decimal("9.87654321")]),
       
  1277             ]
       
  1278 
       
  1279         # try various flags individually, then a whole lot at once
       
  1280         flagsets = [[Inexact], [Rounded], [Underflow], [Clamped], [Subnormal],
       
  1281                     [Inexact, Rounded, Underflow, Clamped, Subnormal]]
       
  1282 
       
  1283         for fn, args in operations:
       
  1284             # find answer and flags raised using a clean context
       
  1285             context.clear_flags()
       
  1286             ans = fn(*args)
       
  1287             flags = [k for k, v in context.flags.items() if v]
       
  1288 
       
  1289             for extra_flags in flagsets:
       
  1290                 # set flags, before calling operation
       
  1291                 context.clear_flags()
       
  1292                 for flag in extra_flags:
       
  1293                     context._raise_error(flag)
       
  1294                 new_ans = fn(*args)
       
  1295 
       
  1296                 # flags that we expect to be set after the operation
       
  1297                 expected_flags = list(flags)
       
  1298                 for flag in extra_flags:
       
  1299                     if flag not in expected_flags:
       
  1300                         expected_flags.append(flag)
       
  1301                 expected_flags.sort()
       
  1302 
       
  1303                 # flags we actually got
       
  1304                 new_flags = [k for k,v in context.flags.items() if v]
       
  1305                 new_flags.sort()
       
  1306 
       
  1307                 self.assertEqual(ans, new_ans,
       
  1308                                  "operation produces different answers depending on flags set: " +
       
  1309                                  "expected %s, got %s." % (ans, new_ans))
       
  1310                 self.assertEqual(new_flags, expected_flags,
       
  1311                                   "operation raises different flags depending on flags set: " +
       
  1312                                   "expected %s, got %s" % (expected_flags, new_flags))
       
  1313 
       
  1314 def test_main(arith=False, verbose=None, todo_tests=None, debug=None):
       
  1315     """ Execute the tests.
       
  1316 
       
  1317     Runs all arithmetic tests if arith is True or if the "decimal" resource
       
  1318     is enabled in regrtest.py
       
  1319     """
       
  1320 
       
  1321     init()
       
  1322     global TEST_ALL, DEBUG
       
  1323     TEST_ALL = arith or is_resource_enabled('decimal')
       
  1324     DEBUG = debug
       
  1325 
       
  1326     if todo_tests is None:
       
  1327         test_classes = [
       
  1328             DecimalExplicitConstructionTest,
       
  1329             DecimalImplicitConstructionTest,
       
  1330             DecimalArithmeticOperatorsTest,
       
  1331             DecimalUseOfContextTest,
       
  1332             DecimalUsabilityTest,
       
  1333             DecimalPythonAPItests,
       
  1334             ContextAPItests,
       
  1335             DecimalTest,
       
  1336             WithStatementTest,
       
  1337             ContextFlags
       
  1338         ]
       
  1339     else:
       
  1340         test_classes = [DecimalTest]
       
  1341 
       
  1342     # Dynamically build custom test definition for each file in the test
       
  1343     # directory and add the definitions to the DecimalTest class.  This
       
  1344     # procedure insures that new files do not get skipped.
       
  1345     for filename in os.listdir(directory):
       
  1346         if '.decTest' not in filename or filename.startswith("."):
       
  1347             continue
       
  1348         head, tail = filename.split('.')
       
  1349         if todo_tests is not None and head not in todo_tests:
       
  1350             continue
       
  1351         tester = lambda self, f=filename: self.eval_file(directory + f)
       
  1352         setattr(DecimalTest, 'test_' + head, tester)
       
  1353         del filename, head, tail, tester
       
  1354 
       
  1355 
       
  1356     try:
       
  1357         run_unittest(*test_classes)
       
  1358         if todo_tests is None:
       
  1359             import decimal as DecimalModule
       
  1360             run_doctest(DecimalModule, verbose)
       
  1361     finally:
       
  1362         setcontext(ORIGINAL_CONTEXT)
       
  1363 
       
  1364 if __name__ == '__main__':
       
  1365     import optparse
       
  1366     p = optparse.OptionParser("test_decimal.py [--debug] [{--skip | test1 [test2 [...]]}]")
       
  1367     p.add_option('--debug', '-d', action='store_true', help='shows the test number and context before each test')
       
  1368     p.add_option('--skip',  '-s', action='store_true', help='skip over 90% of the arithmetic tests')
       
  1369     (opt, args) = p.parse_args()
       
  1370 
       
  1371     if opt.skip:
       
  1372         test_main(arith=False, verbose=True)
       
  1373     elif args:
       
  1374         test_main(arith=True, verbose=True, todo_tests=args, debug=opt.debug)
       
  1375     else:
       
  1376         test_main(arith=True, verbose=True)