[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 ----