PageRenderTime 1186ms CodeModel.GetById 101ms app.highlight 821ms RepoModel.GetById 143ms app.codeStats 1ms

/Lib/test/test_decimal.py

http://unladen-swallow.googlecode.com/
Python | 1558 lines | 1361 code | 111 blank | 86 comment | 50 complexity | 69c12013d43ba66bc20d09a64ce264cd MD5 | raw file

Large files files are truncated, but you can click here to view the full file

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

Large files files are truncated, but you can click here to view the full file