[Python-checkins] python/nondist/sandbox/decimal test_Decimal.py,NONE,1.1 Decimal.py,1.5,1.6

eprice@users.sourceforge.net eprice@users.sourceforge.net
Wed, 21 May 2003 09:20:26 -0700


Update of /cvsroot/python/python/nondist/sandbox/decimal
In directory sc8-pr-cvs1:/tmp/cvs-serv12214

Modified Files:
	Decimal.py 
Added Files:
	test_Decimal.py 
Log Message:
Split Decimal tests off from the main module.
Converted to use unittest.



--- NEW FILE: test_Decimal.py ---
import unittest
import glob
from Decimal import *

import os

from test.test_support import TestSkipped, run_unittest

TESTDATADIR = 'tests'
dir = os.curdir + os.sep + TESTDATADIR + os.sep

skip_expected = not os.path.isdir(dir)

def Nonfunction(*args):
    """Doesn't do anything."""
    return None

RoundingDict = {'ceiling' : ROUND_CEILING, #Maps test-case names to roundings.
                'down' : ROUND_DOWN,
                'floor' : ROUND_FLOOR,
                'half_down' : ROUND_HALF_DOWN,
                'half_even' : ROUND_HALF_EVEN,
                'half_up' : ROUND_HALF_UP,
                'up' : ROUND_UP}

class DecimalTest(unittest.TestCase):
    """Class which tests the Decimal class against the test cases.

    Changed for unittest.
    """
    def setUp(self):
        global dir
        self.context = Context()
        #self.filelist = glob.glob(dir+'*.decTest')
        for key in DefaultContext.trap_enablers.keys():
            DefaultContext.trap_enablers[key] = 1
        self.ignore_list = ['#']
        # Basically, a # means return NaN InvalidOperation.
        # Different from a sNaN in trim

        self.ChangeDict = {'precision' : self.change_precision,
                      'rounding' : self.change_rounding_method,
                      'maxexponent' : self.change_max_exponent,
                      'minexponent' : self.change_min_exponent,
                      'clamp' : self.change_clamp}
    def eval_file(self, file):
        global skip_expected
        if skip_expected:
            raise TestSkipped
            return
        for line in open(file).xreadlines():
            line = line.replace('\r\n', '').replace('\n', '')
            try:
                t = self.eval_line(line)
            except ConversionSyntax:
                print 'Error in test cases:'
                print line
                continue
            except DecimalException, exception:
                #Exception raised where there shoudn't have been one.
                self.fail('Exception "'+exception.__class__.__name__ + '" raised on line '+line)
                
        return

    def eval_line(self, s):
        if s.find(' -> ') >= 0 and s[:2] != '--' and not s.startswith('  --'):
            s = (s.split('->')[0] + '->' +
                 s.split('->')[1].split('--')[0]).strip()
        else:
            s = s.split('--')[0].strip()

        for ignore in self.ignore_list:
            if s.find(ignore) >= 0:
                #print s.split()[0], 'NotImplemented--', ignore
                return
        if not s:
            return
        elif ':' in s:
            return self.eval_directive(s)
        else:
            return self.eval_equation(s)

    def eval_directive(self, s):
        funct, value = map(lambda x: x.strip().lower(), s.split(':'))
        if funct == 'rounding':
            value = RoundingDict[value]
        else:
            try:
                value = int(value)
            except ValueError:
                pass

        funct = self.ChangeDict.get(funct, Nonfunction)
        funct(value)

    def eval_equation(self, s):
        #global DEFAULT_PRECISION
        #print DEFAULT_PRECISION
        try:
            Sides = s.split('->')
            L = Sides[0].strip().split()
            id = L[0]
            #print id,
            funct = L[1]
            valstemp = L[2:]
            L = Sides[1].strip().split()
            ans = L[0]
            exceptions = L[1:]
        except (TypeError, AttributeError, IndexError):
            raise ConversionSyntax
        def FixQuotes(val):
            val = val.replace("''", 'SingleQuote').replace('""', 'DoubleQuote')
            val = val.replace("'", '').replace('"', '')
            val = val.replace('SingleQuote', "'").replace('DoubleQuote', '"')
            return val
        fname = funct
        funct = getattr(self.context, funct)
        vals = []
        conglomerate = ''
        quote = 0
        theirexceptions = map(lambda x: ErrorNames[x.lower()], exceptions)

        for exception in ExceptionList:
            self.context.trap_enablers[exception] = 1 #Catch these bugs...
        for exception in theirexceptions:
            self.context.trap_enablers[exception] = 0
        for val in valstemp:
            if val.count("'") % 2 == 1:
                quote = 1 - quote
            if quote:
                conglomerate = conglomerate + ' ' + val
                continue
            else:
                val = conglomerate + val
                conglomerate = ''
            v = FixQuotes(val)
            if fname in ('toSci', 'toEng'):
                v = self.context.new(v)
            else:
                v = Decimal(v)
            vals.append(v)

        ans = FixQuotes(ans)

        try:
            result = str(funct(*vals))
        except: #Catch any error long enough to state the test case.
            #print "ERROR:", s
            raise

        myexceptions = self.getexceptions()
        self.resetflags()

        myexceptions.sort()
        theirexceptions.sort()

        self.assertEqual(result, ans, 'Incorrect answer for ' + s + ' -- got ' + result)
        self.assertEqual(myexceptions, theirexceptions, 'Incorrect flags set in ' + s + ' -- got '
                         + str(myexceptions))


    def getexceptions(self):
        return self.context.all_flags()
        L = []
        for exception in ExceptionList:
            if self.context.flags[exception]:
                L.append(exception)
        return L

    def resetflags(self):
        for exception in ExceptionList:
            self.context.flags[exception] = 0

    def change_precision(self, prec):
        self.context.prec = prec
    def change_rounding_method(self, rounding):
        self.context.rounding = rounding
    def change_min_exponent(self, exp):
        self.context.Emin = exp
    def change_max_exponent(self, exp):
        self.context.Emax = exp
    def change_clamp(self, clamp):
        self.context.clamp = clamp

    def test_add(self):
        """Tests the Decimal class on Cowlishaw's add tests.

        See www2.hursley.ibm.com/decimal/decTest.zip to download the suite.
        """
        self.eval_file(dir + 'add' + '.decTest')

    def test_abs(self):
        """Tests the Decimal class on Cowlishaw's abs tests.

        See www2.hursley.ibm.com/decimal/decTest.zip to download the suite.
        """
        self.eval_file(dir + 'abs' + '.decTest')

    def test_base(self):
        """Tests the Decimal class on Cowlishaw's base tests.

        See www2.hursley.ibm.com/decimal/decTest.zip to download the suite.
        """
        self.eval_file(dir + 'base' + '.decTest')

    def test_clamp(self):
        """Tests the Decimal class on Cowlishaw's clamp tests.

        See www2.hursley.ibm.com/decimal/decTest.zip to download the suite.
        """
        self.eval_file(dir + 'clamp' + '.decTest')

    def test_compare(self):
        """Tests the Decimal class on Cowlishaw's compare tests.

        See www2.hursley.ibm.com/decimal/decTest.zip to download the suite.
        """
        self.eval_file(dir + 'compare' + '.decTest')

    def test_divide(self):
        """Tests the Decimal class on Cowlishaw's divide tests.

        See www2.hursley.ibm.com/decimal/decTest.zip to download the suite.
        """
        self.eval_file(dir + 'divide' + '.decTest')

    def test_divideint(self):
        """Tests the Decimal class on Cowlishaw's divideint tests.

        See www2.hursley.ibm.com/decimal/decTest.zip to download the suite.
        """
        self.eval_file(dir + 'divideint' + '.decTest')

    def test_inexact(self):
        """Tests the Decimal class on Cowlishaw's inexact tests.

        See www2.hursley.ibm.com/decimal/decTest.zip to download the suite.
        """
        self.eval_file(dir + 'inexact' + '.decTest')

    def test_integer(self):
        """Tests the Decimal class on Cowlishaw's integer tests.

        See www2.hursley.ibm.com/decimal/decTest.zip to download the suite.
        """
        self.eval_file(dir + 'integer' + '.decTest')

    def test_max(self):
        """Tests the Decimal class on Cowlishaw's max tests.

        See www2.hursley.ibm.com/decimal/decTest.zip to download the suite.
        """
        self.eval_file(dir + 'max' + '.decTest')

    def test_min(self):
        """Tests the Decimal class on Cowlishaw's min tests.

        See www2.hursley.ibm.com/decimal/decTest.zip to download the suite.
        """
        self.eval_file(dir + 'min' + '.decTest')

    def test_minus(self):
        """Tests the Decimal class on Cowlishaw's minus tests.

        See www2.hursley.ibm.com/decimal/decTest.zip to download the suite.
        """
        self.eval_file(dir + 'minus' + '.decTest')

    def test_multiply(self):
        """Tests the Decimal class on Cowlishaw's multiply tests.

        See www2.hursley.ibm.com/decimal/decTest.zip to download the suite.
        """
        self.eval_file(dir+'multiply'+'.decTest')

    def test_normalize(self):
        """Tests the Decimal class on Cowlishaw's normalize tests.

        See www2.hursley.ibm.com/decimal/decTest.zip to download the suite.
        """
        self.eval_file(dir + 'normalize' + '.decTest')

    def test_plus(self):
        """Tests the Decimal class on Cowlishaw's plus tests.

        See www2.hursley.ibm.com/decimal/decTest.zip to download the suite.
        """
        self.eval_file(dir + 'plus' + '.decTest')

    def test_power(self):
        """Tests the Decimal class on Cowlishaw's power tests.

        See www2.hursley.ibm.com/decimal/decTest.zip to download the suite.
        """
        self.eval_file(dir + 'power' + '.decTest')

    def test_randomBound32(self):
        """Tests the Decimal class on Cowlishaw's randomBound32 tests.

        See www2.hursley.ibm.com/decimal/decTest.zip to download the suite.
        """
        self.eval_file(dir + 'randomBound32' + '.decTest')

    def test_randoms(self):
        """Tests the Decimal class on Cowlishaw's randoms tests.

        See www2.hursley.ibm.com/decimal/decTest.zip to download the suite.
        """
        self.eval_file(dir + 'randoms' + '.decTest')

    def test_remainder(self):
        """Tests the Decimal class on Cowlishaw's remainder tests.

        See www2.hursley.ibm.com/decimal/decTest.zip to download the suite.
        """
        self.eval_file(dir + 'remainder' + '.decTest')

    def test_remainderNear(self):
        """Tests the Decimal class on Cowlishaw's remainderNear tests.

        See www2.hursley.ibm.com/decimal/decTest.zip to download the suite.
        """
        self.eval_file(dir + 'remainderNear' + '.decTest')

    def test_rescale(self):
        """Tests the Decimal class on Cowlishaw's rescale tests.

        See www2.hursley.ibm.com/decimal/decTest.zip to download the suite.
        """
        self.eval_file(dir + 'rescale' + '.decTest')

    def test_rounding(self):
        """Tests the Decimal class on Cowlishaw's rounding tests.

        See www2.hursley.ibm.com/decimal/decTest.zip to download the suite.
        """
        self.eval_file(dir + 'rounding' + '.decTest')

    def test_squareroot(self):
        """Tests the Decimal class on Cowlishaw's squareroot tests.

        See www2.hursley.ibm.com/decimal/decTest.zip to download the suite.
        """
        self.eval_file(dir + 'squareroot' + '.decTest')

    def test_subtract(self):
        """Tests the Decimal class on Cowlishaw's subtract tests.

        See www2.hursley.ibm.com/decimal/decTest.zip to download the suite.
        """
        self.eval_file(dir + 'subtract' + '.decTest')

    def test_trim(self):
        """Tests the Decimal class on Cowlishaw's trim tests.

        See www2.hursley.ibm.com/decimal/decTest.zip to download the suite.
        """
        self.eval_file(dir + 'trim' + '.decTest')






def test_main():
    run_unittest(DecimalTest)

if __name__ == '__main__':
    test_main()

Index: Decimal.py
===================================================================
RCS file: /cvsroot/python/python/nondist/sandbox/decimal/Decimal.py,v
retrieving revision 1.5
retrieving revision 1.6
diff -C2 -d -r1.5 -r1.6
*** Decimal.py	15 May 2003 19:06:01 -0000	1.5
--- Decimal.py	21 May 2003 16:20:23 -0000	1.6
***************
*** 431,434 ****
--- 431,437 ----
              return
  
+         if isinstance(value, type(1)) or isinstance(value, type(1L)):
+             self._convertString(str(value), context)
+             return
          # tuple/list conversion (possibly from repr())
          try:
***************
*** 467,474 ****
  
  
-         if isinstance(value, type(1)) or isinstance(value, type(1L)):
-             self._convertString(str(value), context)
-             return
- 
          if isinstance(value, type(1.0)):
  
--- 470,473 ----
***************
*** 1476,1489 ****
  
          # Okay, let's round and lose data
-         # get rounding method function:
-         rounding_functions = filter(lambda name: name[:6] == '_round',
-                                     self.__class__.__dict__.keys())
-         def value(name):
-             """Find the global value associated with the name of a function."""
-             return globals()[name[1:].upper()]
  
!         this_function = filter(lambda name, value=value, rounding=rounding:
!                                value(name) == rounding, rounding_functions)[0]
!         this_function = getattr(temp, this_function)
          #Now we've got the rounding function
  
--- 1475,1480 ----
  
          # Okay, let's round and lose data
  
!         this_function = getattr(temp, self.pick_rounding_function[rounding])
          #Now we've got the rounding function
  
***************
*** 1497,1500 ****
--- 1488,1493 ----
          return ans
  
+     pick_rounding_function = {}
+ 
      def _round_down(self, prec, expdiff, context):
          """Also known as round-towards-0, truncate."""
***************
*** 1990,1993 ****
--- 1983,1994 ----
              return 0
  
+ # get rounding method function:
+ rounding_functions = [name for name in Decimal.__dict__.keys() if name.startswith('_round')]
+ for name in rounding_functions:
+     #name is like _round_half_even, goes to the global ROUND_HALF_EVEN value.
+     globalname = name[1:].upper()
+     val = globals()[globalname]
+     Decimal.pick_rounding_function[val] = name
+ 
  
  class Context:
***************
*** 2678,2911 ****
  
  
- def Nonfunction(*args):
-     """Doesn't do anything."""
-     return None
- 
- RoundingDict = {'ceiling' : ROUND_CEILING, #Maps test-case names to roundings.
-                 'down' : ROUND_DOWN,
-                 'floor' : ROUND_FLOOR,
-                 'half_down' : ROUND_HALF_DOWN,
-                 'half_even' : ROUND_HALF_EVEN,
-                 'half_up' : ROUND_HALF_UP,
-                 'up' : ROUND_UP}
- 
- class Test:
-     """Class which tests the Decimal class against the test cases.
- 
-     Example:
-     t = Test('decimal/testcases/')
-     t.test()
- 
-     The testcases should be unzipped in that directory (with names ending in
-     .decTest)
- 
-     When run, test() stops for incorrect answers and gives a summary of
-     results at the end.
- 
-     Changes DefaultContext to ensure no leaking (failure to pass the context)
-     so watch out if you start a new thread!
-     """
-     def __init__(self, dir='./'):
-         import glob
-         self.filelist = glob.glob(dir+'*.decTest')
-         if len(self.filelist) > 15:
-             self.filelist.append(self.filelist[15])
-             #So the slow one is at the end.
-             self.filelist[15:16] = []
- 
-         self.context = Context()
-         for key in DefaultContext.trap_enablers.keys():
-             DefaultContext.trap_enablers[key] = 1
- 
-         self.unknown_list = ['#']
-         # Basically, a # means return NaN InvalidOperation.
-         # Different from a sNaN in trim
- 
-         self.ChangeDict = {'precision' : self.change_precision,
-               'rounding' : self.change_rounding_method,
-               'maxexponent' : self.change_max_exponent,
-               'minexponent' : self.change_min_exponent,
-               'clamp' : self.change_clamp}
- 
-     def test(self, start=0):
-         wrong = 0
-         notdone = 0
-         total = 0
-         t = time.time()
-         for file in self.filelist[start:]:
-             tup = self.eval_file(file)
-             wrong += tup[0]
-             notdone += tup[1]
-             total += tup[2]
- 
-             #The clamp: directive only set in clamp cases, which leave it on.
-             self.change_clamp(0)
-         print 'The run-through took', time.time()-t, 'seconds.'
-         print 'A total of', notdone, 'were skipped. (# ones)'
-         print 'A total of', wrong, 'were incorrect.'
-         print 'A total of', total-wrong, 'test cases were correct.'
-     def eval_file(self, file):
-         count = 0
-         ndone = 0
-         total = 0
-         for line in open(file).xreadlines():
-             line = line.replace('\r\n', '').replace('\n', '')
-             #print '*', line, '*'
-             try:
-                 t = self.eval_line(line)
-             except ConversionSyntax:
-                 print 'PROBLEM WITH:'
-                 print line
-                 raw_input()
-                 continue
-             count += t[0]
-             ndone += t[1]
-             total += t[2]
-             #time.sleep(0.1)
-         return count, ndone, total
- 
-     def eval_line(self, s):
-         if s.find(' -> ') >= 0 and s[:2] != '--' and not s.startswith('  --'):
-             s = (s.split('->')[0] + '->' +
-                  s.split('->')[1].split('--')[0]).strip()
-         else:
-             s = s.split('--')[0].strip()
- 
-         for unknown in self.unknown_list:
-             if s.find(unknown) >= 0:
-                 print s.split()[0], 'NotImplemented--', unknown
-                 return (0, 1, 0)
-         if not s:
-             return (0, 0, 0)
-         if ':' in s:
-             return self.eval_directive(s)
-         else:
-             return self.eval_equation(s)
- 
-     def eval_directive(self, s):
-         funct, value = map(lambda x: x.strip().lower(), s.split(':'))
-         if funct == 'rounding':
-             value = RoundingDict[value]
-         else:
-             try:
-                 value = int(value)
-             except ValueError:
-                 pass
- 
-         funct = self.ChangeDict.get(funct, Nonfunction)
-         funct(value)
-         return (0, 0, 0)
- 
-     def eval_equation(self, s):
-         #global DEFAULT_PRECISION
-         #print DEFAULT_PRECISION
-         try:
-             Sides = s.split('->')
-             L = Sides[0].strip().split()
-             id = L[0]
-             print id,
-             funct = L[1]
-             valstemp = L[2:]
-             L = Sides[1].strip().split()
-             ans = L[0]
-             exceptions = L[1:]
-         except (TypeError, AttributeError, IndexError):
-             raise ConversionSyntax
-         def FixQuotes(val):
-             val = val.replace("''", 'SingleQuote').replace('""', 'DoubleQuote')
-             val = val.replace("'", '').replace('"', '')
-             val = val.replace('SingleQuote', "'").replace('DoubleQuote', '"')
-             return val
-         fname = funct
-         funct = getattr(self.context, funct)
-         vals = []
-         conglomerate = ''
-         quote = 0
-         theirexceptions = map(lambda x: ErrorNames[x.lower()], exceptions)
- 
-         for exception in ExceptionList:
-             self.context.trap_enablers[exception] = 1 #Catch these bugs...
-         for exception in theirexceptions:
-             self.context.trap_enablers[exception] = 0
-         for val in valstemp:
-             if val.count("'") % 2 == 1:
-                 quote = 1 - quote
-             if quote:
-                 conglomerate = conglomerate + ' ' + val
-                 continue
-             else:
-                 val = conglomerate + val
-                 conglomerate = ''
-             v = FixQuotes(val)
-             if fname in ('toSci', 'toEng'):
-                 v = self.context.new(v)
-             else:
-                 v = Decimal(v)
-             vals.append(v)
- 
-         ans = FixQuotes(ans)
- 
-         try:
-             result = str(funct(*vals))
-         except: #Catch any error long enough to state the test case.
-             print "ERROR:", s
-             raise
- 
-         myexceptions = self.getexceptions()
-         self.resetflags()
- 
-         myexceptions.sort()
-         theirexceptions.sort()
-         #if s.count('pow') and result != ans:
-         #    #Maybe just the one digit..
-         #    spot = result.find('E')
-         #    if abs(long(result[:spot].replace('.', '')) -
-         #           long(ans[:spot].replace('.', ''))) == 1:
-         #
-         #        result = ans[:spot] + result[spot:]
-         #        print 'OFF BY ONE IN LAST DIGIT OTHERWISE',
- 
-         if result != ans or myexceptions != theirexceptions:
-             print 'INCORRECT **********'
-             print 'PROBLEM:'
-             print s
-             print 'YOUR RESULT:'
-             print result, ' '.join(map(lambda x: x.__name__, myexceptions))
-             raw_input()
-             return (1, 0, 1)
-         else:
-             print 'CORRECT!'
-         return (0, 0, 1)
- 
-     def getexceptions(self):
-         return self.context.all_flags()
-         L = []
-         for exception in ExceptionList:
-             if self.context.flags[exception]:
-                 L.append(exception)
-         return L
- 
-     def resetflags(self):
-         for exception in ExceptionList:
-             self.context.flags[exception] = 0
- 
-     def change_precision(self, prec):
-         self.context.prec = prec
-     def change_rounding_method(self, rounding):
-         self.context.rounding = rounding
-     def change_min_exponent(self, exp):
-         self.context.Emin = exp
-     def change_max_exponent(self, exp):
-         self.context.Emax = exp
-     def change_clamp(self, clamp):
-         self.context.clamp = clamp
- 
- 
- 
- 
- def _test():
-     t = Test('./tests/')
-     t.test()
- 
- if __name__ == '__main__':
-     _test()
--- 2679,2680 ----