#### /Lib/test/test_decimal.py

Python | 1558 lines | 1361 code | 111 blank | 86 comment | 50 complexity | 69c12013d43ba66bc20d09a64ce264cd MD5 | raw file
```   1# Copyright (c) 2004 Python Software Foundation.
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
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:
39except ImportError:
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
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
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 (
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
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
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
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
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
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 = [
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
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:
997    except ImportError:
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
1004        #Test the "threading isolation" of a Context.
1005
1009
1012
1013        th1.start()
1014        th2.start()
1015
1016        self.finish1.wait()
1017        self.finish2.wait()
1018        return
1019
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)
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__")
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)
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)
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)
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()
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)]),
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                                  "operation raises different flags depending on flags set: " +
1493                                  "expected %s, got %s" % (expected_flags, new_flags))
1494
1495def test_main(arith=False, verbose=None, todo_tests=None, debug=None):
1496    """ Execute the tests.
1497
1498    Runs all arithmetic tests if arith is True or if the "decimal" resource
1499    is enabled in regrtest.py
1500    """
1501
1502    init()
1503    global TEST_ALL, DEBUG
1504    TEST_ALL = arith or is_resource_enabled('decimal')
1505    DEBUG = debug
1506
1507    if todo_tests is None:
1508        test_classes = [
1509            DecimalExplicitConstructionTest,
1510            DecimalImplicitConstructionTest,
1511            DecimalArithmeticOperatorsTest,
1512            DecimalFormatTest,
1513            DecimalUseOfContextTest,
1514            DecimalUsabilityTest,
1515            DecimalPythonAPItests,
1516            ContextAPItests,
1517            DecimalTest,
1518            WithStatementTest,
1519            ContextFlags
1520        ]
1521    else:
1522        test_classes = [DecimalTest]
1523
1524    # Dynamically build custom test definition for each file in the test
1525    # directory and add the definitions to the DecimalTest class.  This
1526    # procedure insures that new files do not get skipped.
1527    for filename in os.listdir(directory):
1528        if '.decTest' not in filename or filename.startswith("."):
1529            continue
1531        if todo_tests is not None and head not in todo_tests:
1532            continue
1533        tester = lambda self, f=filename: self.eval_file(directory + f)
1534        setattr(DecimalTest, 'test_' + head, tester)
1535        del filename, head, tail, tester
1536
1537
1538    try:
1539        run_unittest(*test_classes)
1540        if todo_tests is None:
1541            import decimal as DecimalModule
1542            run_doctest(DecimalModule, verbose)
1543    finally:
1544        setcontext(ORIGINAL_CONTEXT)
1545
1546if __name__ == '__main__':
1547    import optparse
1548    p = optparse.OptionParser("test_decimal.py [--debug] [{--skip | test1 [test2 [...]]}]")
1549    p.add_option('--debug', '-d', action='store_true', help='shows the test number and context before each test')
1550    p.add_option('--skip',  '-s', action='store_true', help='skip over 90% of the arithmetic tests')
1551    (opt, args) = p.parse_args()
1552
1553    if opt.skip:
1554        test_main(arith=False, verbose=True)
1555    elif args:
1556        test_main(arith=True, verbose=True, todo_tests=args, debug=opt.debug)
1557    else:
1558        test_main(arith=True, verbose=True)
```