PageRenderTime 76ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 0ms

/Lib/test/test_decimal.py

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