1# Copyright (c) 2004 Python Software Foundation. 2# All rights reserved. 3 4# Written by Eric Price <eprice at tjhsst.edu> 5# and Facundo Batista <facundo at taniquetil.com.ar> 6# and Raymond Hettinger <python at rcn.com> 7# and Aahz (aahz at pobox.com) 8# and Tim Peters 9 10""" 11These are the test cases for the Decimal and Cdecimal modules. 12 13There are two groups of tests, Arithmetic and Behaviour. The former test 14the Decimal arithmetic using the tests provided by Mike Cowlishaw. The latter 15test the pythonic behaviour according to PEP 327. 16 17Cowlishaw's tests can be downloaded from: 18 19 www2.hursley.ibm.com/decimal/dectest.zip 20 21This test module can be called from command line with one parameter (Arithmetic 22or Behaviour) to test each part, or without parameter to test both parts. If 23you're working through IDLE, you can import this test module and call test_main() 24with the corresponding argument. 25""" 26 27from __future__ import with_statement 28 29import math 30import os, sys 31import pickle, copy 32import unittest 33from cdecimal import * 34from test.test_support import (run_unittest, run_doctest, is_resource_enabled) 35import random 36try: 37 import threading 38except ImportError: 39 threading = None 40 41py_minor = sys.version_info[1] 42assert py_minor == 5, "These tests are for version 2.5 only." 43HAVE_CDECIMAL= True 44HAVE_CONFIG_64 = (MAX_EMAX == 999999999999999999) 45 46# Useful Test Constant 47Signals = getcontext().flags.keys() 48 49# Tests are built around these assumed context defaults. 50# test_main() restores the original context. 51def init(): 52 global ORIGINAL_CONTEXT 53 ORIGINAL_CONTEXT = getcontext().copy() 54 DefaultTestContext = Context( 55 prec = 9, 56 rounding = ROUND_HALF_EVEN, 57 traps = dict.fromkeys(Signals, 0) 58 ) 59 setcontext(DefaultTestContext) 60 61 62# The official limits for the 32-bit version are -425000000 63# and 425000000. The following values are safe for all tests 64# in the test suite. 65readcontext = Context() 66readcontext.unsafe_setprec(1070000000) 67readcontext.unsafe_setemax(1070000000) 68readcontext.unsafe_setemin(-1070000000) 69readcontext._traps = 0 70 71 72TESTDATADIR = 'decimaltestdata' 73if __name__ == '__main__': 74 file = sys.argv[0] 75else: 76 file = __file__ 77testdir = os.path.dirname(file) or os.curdir 78directory = testdir + os.sep + TESTDATADIR + os.sep 79 80skip_expected = not os.path.isdir(directory) 81 82# list of individual .decTest test ids that correspond to tests that 83# we're skipping for one reason or another. 84skipped_test_ids = [ 85 'scbx164', # skipping apparently implementation-specific scaleb 86 'scbx165', # tests, pending clarification of scaleb rules. 87] 88 89# XXX: BEGIN FASTDEC SKIPS 90status_cases = {} 91if HAVE_CONFIG_64: 92 # 64 bit version: With a reduced working precision in mpd_qpow() 93 # the status matches. 94 status_cases = { 95 "pwsx803": ([Inexact, Rounded, Subnormal, Underflow], [Inexact, Rounded]), 96 "pwsx805": ([Inexact, Rounded, Subnormal, Underflow], [Inexact, Rounded]) 97 } 98 99# These are skipped for decNumber, too. They might as well be added to 100# the ULP cases. 101skip_cases = { 102 "powx4302": ("1.000000", "1.000001"), 103 "powx4303": ("1.000000", "1.000001"), 104 "powx4342": ("1.000000", "0.9999999"), 105 "powx4343": ("1.000000", "0.9999999") 106} 107 108# Disagreements: 109# pwmx325 power 0 1 1234567890 -> NaN Invalid_operation -- got 0 110disagree = ['pwmx325', 'pwmx326'] 111# END FASTDEC SKIPS 112 113 114# Make sure it actually raises errors when not expected and caught in flags 115# Slower, since it runs some things several times. 116EXTENDEDERRORTEST = True 117 118#Map the test cases' error names to the actual errors 119ErrorNames = {'clamped' : Clamped, 120 'conversion_syntax' : InvalidOperation, 121 'division_by_zero' : DivisionByZero, 122 'division_impossible' : InvalidOperation, 123 'division_undefined' : InvalidOperation, 124 'inexact' : Inexact, 125 'invalid_context' : InvalidOperation, 126 'invalid_operation' : InvalidOperation, 127 'overflow' : Overflow, 128 'rounded' : Rounded, 129 'subnormal' : Subnormal, 130 'underflow' : Underflow} 131 132 133def Nonfunction(*args): 134 """Doesn't do anything.""" 135 return None 136 137RoundingDict = {'ceiling' : ROUND_CEILING, #Maps test-case names to roundings. 138 'down' : ROUND_DOWN, 139 'floor' : ROUND_FLOOR, 140 'half_down' : ROUND_HALF_DOWN, 141 'half_even' : ROUND_HALF_EVEN, 142 'half_up' : ROUND_HALF_UP, 143 'up' : ROUND_UP, 144 '05up' : ROUND_05UP} 145 146# Name adapter to be able to change the Decimal and Context 147# interface without changing the test files from Cowlishaw 148nameAdapter = {'and':'logical_and', 149 'apply':'_apply', 150 'class':'number_class', 151 'comparesig':'compare_signal', 152 'comparetotal':'compare_total', 153 'comparetotmag':'compare_total_mag', 154 'copy':'copy_decimal', 155 'copyabs':'copy_abs', 156 'copynegate':'copy_negate', 157 'copysign':'copy_sign', 158 'divideint':'divide_int', 159 'invert':'logical_invert', 160 'iscanonical':'is_canonical', 161 'isfinite':'is_finite', 162 'isinfinite':'is_infinite', 163 'isnan':'is_nan', 164 'isnormal':'is_normal', 165 'isqnan':'is_qnan', 166 'issigned':'is_signed', 167 'issnan':'is_snan', 168 'issubnormal':'is_subnormal', 169 'iszero':'is_zero', 170 'maxmag':'max_mag', 171 'minmag':'min_mag', 172 'nextminus':'next_minus', 173 'nextplus':'next_plus', 174 'nexttoward':'next_toward', 175 'or':'logical_or', 176 'reduce':'normalize', 177 'remaindernear':'remainder_near', 178 'samequantum':'same_quantum', 179 'squareroot':'sqrt', 180 'toeng':'to_eng_string', 181 'tointegral':'to_integral_value', 182 'tointegralx':'to_integral_exact', 183 'tosci':'to_sci_string', 184 'xor':'logical_xor', 185 } 186 187# The following functions return True/False rather than a Decimal instance 188 189LOGICAL_FUNCTIONS = ( 190 'is_canonical', 191 'is_finite', 192 'is_infinite', 193 'is_nan', 194 'is_normal', 195 'is_qnan', 196 'is_signed', 197 'is_snan', 198 'is_subnormal', 199 'is_zero', 200 'same_quantum', 201 ) 202 203# For some operations (currently exp, ln, log10, power), the decNumber 204# reference implementation imposes additional restrictions on the 205# context and operands. These restrictions are not part of the 206# specification; however, the effect of these restrictions does show 207# up in some of the testcases. We skip testcases that violate these 208# restrictions, since Decimal behaves differently from decNumber for 209# these testcases so these testcases would otherwise fail. 210 211decNumberRestricted = ('power', 'ln', 'log10', 'exp') 212DEC_MAX_MATH = 999999 213def outside_decNumber_bounds(v, context): 214 if (context.prec > DEC_MAX_MATH or 215 context.Emax > DEC_MAX_MATH or 216 -context.Emin > DEC_MAX_MATH): 217 return True 218 if not v.is_special() and v and ( 219 v.adjusted() > DEC_MAX_MATH or 220 v.adjusted() < 1-2*DEC_MAX_MATH): 221 return True 222 return False 223 224class DecimalTest(unittest.TestCase): 225 """Class which tests the Decimal class against the test cases. 226 227 Changed for unittest. 228 """ 229 def setUp(self): 230 self.context = Context() 231 self.ignore_list = ['#'] 232 # Basically, a # means return NaN InvalidOperation. 233 # Different from a sNaN in trim 234 235 self.ChangeDict = {'precision' : self.change_precision, 236 'rounding' : self.change_rounding_method, 237 'maxexponent' : self.change_max_exponent, 238 'minexponent' : self.change_min_exponent, 239 'clamp' : self.change_clamp} 240 241 def eval_file(self, file): 242 global skip_expected 243 if skip_expected: 244 raise unittest.SkipTest 245 return 246 with open(file) as f: 247 for line in f: 248 line = line.replace('\r\n', '').replace('\n', '') 249 #print line 250 try: 251 t = self.eval_line(line) 252 except DecimalException, exception: 253 #Exception raised where there shoudn't have been one. 254 self.fail('Exception "'+exception.__class__.__name__ + '" raised on line '+line) 255 256 return 257 258 def eval_line(self, s): 259 if s.find(' -> ') >= 0 and s[:2] != '--' and not s.startswith(' --'): 260 s = (s.split('->')[0] + '->' + 261 s.split('->')[1].split('--')[0]).strip() 262 else: 263 s = s.split('--')[0].strip() 264 265 for ignore in self.ignore_list: 266 if s.find(ignore) >= 0: 267 #print s.split()[0], 'NotImplemented--', ignore 268 return 269 if not s: 270 return 271 elif ':' in s: 272 return self.eval_directive(s) 273 else: 274 return self.eval_equation(s) 275 276 def eval_directive(self, s): 277 funct, value = map(lambda x: x.strip().lower(), s.split(':')) 278 if funct == 'rounding': 279 value = RoundingDict[value] 280 else: 281 try: 282 value = int(value) 283 except ValueError: 284 pass 285 286 funct = self.ChangeDict.get(funct, Nonfunction) 287 funct(value) 288 289 def eval_equation(self, s): 290 #global DEFAULT_PRECISION 291 #print DEFAULT_PRECISION 292 293 if not TEST_ALL and random.random() < 0.90: 294 return 295 296 try: 297 Sides = s.split('->') 298 L = Sides[0].strip().split() 299 id = L[0] 300 if DEBUG: 301 print "Test ", id, 302 funct = L[1].lower() 303 valstemp = L[2:] 304 L = Sides[1].strip().split() 305 ans = L[0] 306 exceptions = L[1:] 307 except (TypeError, AttributeError, IndexError): 308 raise InvalidOperation 309 def FixQuotes(val): 310 val = val.replace("''", 'SingleQuote').replace('""', 'DoubleQuote') 311 val = val.replace("'", '').replace('"', '') 312 val = val.replace('SingleQuote', "'").replace('DoubleQuote', '"') 313 return val 314 315 if id in skipped_test_ids: 316 return 317 318 fname = nameAdapter.get(funct, funct) 319 if fname == 'rescale': 320 return 321 funct = getattr(self.context, fname) 322 323 324 vals = [] 325 conglomerate = '' 326 quote = 0 327 theirexceptions = [ErrorNames[x.lower()] for x in exceptions] 328 # XXX STATUS CASES 329 if status_cases.has_key(id): 330 t = status_cases[id] 331 theirexceptions = t[0] 332 333 for exception in Signals: 334 self.context.traps[exception] = 1 #Catch these bugs... 335 for exception in theirexceptions: 336 self.context.traps[exception] = 0 337 for i, val in enumerate(valstemp): 338 if val.count("'") % 2 == 1: 339 quote = 1 - quote 340 if quote: 341 conglomerate = conglomerate + ' ' + val 342 continue 343 else: 344 val = conglomerate + val 345 conglomerate = '' 346 v = FixQuotes(val) 347 if fname in ('to_sci_string', 'to_eng_string'): 348 if EXTENDEDERRORTEST: 349 for error in theirexceptions: 350 self.context.traps[error] = 1 351 try: 352 funct(self.context.create_decimal(v)) 353 except error: 354 pass 355 except Signals, e: 356 self.fail("Raised %s in %s when %s disabled" % \ 357 (e, s, error)) 358 else: 359 self.fail("Did not raise %s in %s" % (error, s)) 360 self.context.traps[error] = 0 361 v = self.context.create_decimal(v) 362 else: 363 # 32-bit version has limits +-425000000 364 savetraps = self.context._traps 365 self.context._traps = 0 366 vv = v 367 v = Decimal(vv, self.context) 368 if self.context._flags & 0x100: # MPD_Invalid_operation 369 v = readcontext.create_decimal(vv) 370 self.context._flags = 0 371 self.context._traps = savetraps 372 vals.append(v) 373 374 ans = FixQuotes(ans) 375 376 # XXX: Shortcuts, disagreements between cdecimal and decimal 377 if id in disagree: 378 return 379 if fname == 'power' and len(vals) == 3: 380 # name is different 381 fname = 'powmod' 382 funct = getattr(self.context, fname) 383 384 # skip tests that are related to bounds imposed in the decNumber 385 # reference implementation 386 if fname in decNumberRestricted: 387 if fname == 'power': 388 if not (vals[1].is_integer() and 389 -1999999997 <= vals[1] <= 999999999): 390 if outside_decNumber_bounds(vals[0], self.context) or \ 391 outside_decNumber_bounds(vals[1], self.context): 392 #print "Skipping test %s" % s 393 return 394 else: 395 if outside_decNumber_bounds(vals[0], self.context): 396 #print "Skipping test %s" % s 397 return 398 399 400 if EXTENDEDERRORTEST and fname not in ('to_sci_string', 'to_eng_string'): 401 for error in theirexceptions: 402 self.context.traps[error] = 1 403 try: 404 funct(*vals) 405 except error: 406 pass 407 except Signals, e: 408 self.fail("Raised %s in %s when %s disabled" % \ 409 (e, s, error)) 410 else: 411 self.fail("Did not raise %s in %s" % (error, s)) 412 self.context.traps[error] = 0 413 if DEBUG: 414 print "--", self.context 415 try: 416 result = str(funct(*vals)) 417 if fname in LOGICAL_FUNCTIONS: 418 result = str(int(eval(result))) # 'True', 'False' -> '1', '0' 419 except Signals, error: 420 self.fail("Raised %s in %s" % (error, s)) 421 except: #Catch any error long enough to state the test case. 422 print "ERROR:", s 423 raise 424 425 myexceptions = self.getexceptions() 426 self.context.clear_flags() 427 428 myexceptions.sort() 429 theirexceptions.sort() 430 431 # XXX SKIPS 432 if skip_cases.has_key(id): 433 t = skip_cases[id] 434 self.assertTrue(result == t[0] and ans == t[1]) 435 else: 436 self.assertEqual(result, ans, 437 'Incorrect answer for ' + s + ' -- got ' + result) 438 439 self.assertEqual(myexceptions, theirexceptions, 440 'Incorrect flags set in ' + s + ' -- got ' + str(myexceptions)) 441 return 442 443 def getexceptions(self): 444 return [e for e in Signals if self.context.flags[e]] 445 446 def change_precision(self, prec): 447 if HAVE_CONFIG_64: 448 self.context.prec = prec 449 else: 450 self.context.unsafe_setprec(prec) 451 def change_rounding_method(self, rounding): 452 self.context.rounding = rounding 453 def change_min_exponent(self, exp): 454 if HAVE_CONFIG_64: 455 self.context.Emin = exp 456 else: 457 self.context.unsafe_setemin(exp) 458 def change_max_exponent(self, exp): 459 if HAVE_CONFIG_64: 460 self.context.Emax = exp 461 else: 462 self.context.unsafe_setemax(exp) 463 def change_clamp(self, clamp): 464 self.context._clamp = clamp 465 466 467 468# The following classes test the behaviour of Decimal according to PEP 327 469 470class DecimalExplicitConstructionTest(unittest.TestCase): 471 '''Unit tests for Explicit Construction cases of Decimal.''' 472 473 def test_explicit_empty(self): 474 self.assertEqual(Decimal(), Decimal("0")) 475 476 def test_explicit_from_None(self): 477 self.assertRaises(TypeError, Decimal, None) 478 479 def test_explicit_from_int(self): 480 481 #positive 482 d = Decimal(45) 483 self.assertEqual(str(d), '45') 484 485 #very large positive 486 d = Decimal(500000123) 487 self.assertEqual(str(d), '500000123') 488 489 #negative 490 d = Decimal(-45) 491 self.assertEqual(str(d), '-45') 492 493 #zero 494 d = Decimal(0) 495 self.assertEqual(str(d), '0') 496 497 def test_explicit_from_string(self): 498 499 #empty 500 self.assertEqual(str(Decimal('')), 'NaN') 501 502 #int 503 self.assertEqual(str(Decimal('45')), '45') 504 505 #float 506 self.assertEqual(str(Decimal('45.34')), '45.34') 507 508 #engineer notation 509 self.assertEqual(str(Decimal('45e2')), '4.5E+3') 510 511 #just not a number 512 self.assertEqual(str(Decimal('ugly')), 'NaN') 513 514 #leading and trailing whitespace permitted 515 self.assertEqual(str(Decimal('1.3E4 \n')), '1.3E+4') 516 self.assertEqual(str(Decimal(' -7.89')), '-7.89') 517 518 #unicode strings should be permitted 519 self.assertEqual(str(Decimal(u'0E-017')), '0E-17') 520 self.assertEqual(str(Decimal(u'45')), '45') 521 self.assertEqual(str(Decimal(u'-Inf')), '-Infinity') 522 self.assertEqual(str(Decimal(u'NaN123')), 'NaN123') 523 524 def test_explicit_from_tuples(self): 525 526 #zero 527 d = Decimal( (0, (0,), 0) ) 528 self.assertEqual(str(d), '0') 529 530 #int 531 d = Decimal( (1, (4, 5), 0) ) 532 self.assertEqual(str(d), '-45') 533 534 #float 535 d = Decimal( (0, (4, 5, 3, 4), -2) ) 536 self.assertEqual(str(d), '45.34') 537 538 #weird 539 d = Decimal( (1, (4, 3, 4, 9, 1, 3, 5, 3, 4), -25) ) 540 self.assertEqual(str(d), '-4.34913534E-17') 541 542 #wrong number of items 543 self.assertRaises(ValueError, Decimal, (1, (4, 3, 4, 9, 1)) ) 544 545 #bad sign 546 self.assertRaises(ValueError, Decimal, (8, (4, 3, 4, 9, 1), 2) ) 547 self.assertRaises(ValueError, Decimal, (0., (4, 3, 4, 9, 1), 2) ) 548 self.assertRaises(ValueError, Decimal, (Decimal(1), (4, 3, 4, 9, 1), 2)) 549 550 #bad exp 551 self.assertRaises(ValueError, Decimal, (1, (4, 3, 4, 9, 1), 'wrong!') ) 552 self.assertRaises(ValueError, Decimal, (1, (4, 3, 4, 9, 1), 0.) ) 553 self.assertRaises(ValueError, Decimal, (1, (4, 3, 4, 9, 1), '1') ) 554 555 #bad coefficients 556 self.assertRaises(ValueError, Decimal, (1, (4, 3, 4, None, 1), 2) ) 557 self.assertRaises(ValueError, Decimal, (1, (4, -3, 4, 9, 1), 2) ) 558 self.assertRaises(ValueError, Decimal, (1, (4, 10, 4, 9, 1), 2) ) 559 self.assertRaises(ValueError, Decimal, (1, (4, 3, 4, 'a', 1), 2) ) 560 561 def test_explicit_from_Decimal(self): 562 563 #positive 564 d = Decimal(45) 565 e = Decimal(d) 566 self.assertEqual(str(e), '45') 567 # XXX cdecimal has behaviour of int() 568 # self.assertNotEqual(id(d), id(e)) 569 self.assertEqual(id(d), id(e)) 570 571 #very large positive 572 d = Decimal(500000123) 573 e = Decimal(d) 574 self.assertEqual(str(e), '500000123') 575 self.assertEqual(id(d), id(e)) 576 577 #negative 578 d = Decimal(-45) 579 e = Decimal(d) 580 self.assertEqual(str(e), '-45') 581 self.assertEqual(id(d), id(e)) 582 583 #zero 584 d = Decimal(0) 585 e = Decimal(d) 586 self.assertEqual(str(e), '0') 587 self.assertEqual(id(d), id(e)) 588 589 def test_explicit_from_float(self): 590 if not float.__getformat__("double").startswith("IEEE"): 591 return 592 if HAVE_CDECIMAL: 593 if py_minor <= 6: 594 with localcontext() as c: 595 # TypeError in 2.6 596 c.clear_flags() 597 self.assertRaises(TypeError, Decimal, 7.5) 598 self.assertFalse(c.flags[FloatOperation]) 599 600 c.traps[FloatOperation] = True 601 self.assertRaises(TypeError, Decimal, 7.5) 602 self.assertFalse(c.flags[FloatOperation]) 603 return 604 else: 605 with localcontext() as c: 606 c.clear_flags() 607 self.assertEqual(Decimal(7.5), 7.5) 608 self.assertTrue(c.flags[FloatOperation]) 609 610 c.traps[FloatOperation] = True 611 self.assertRaises(FloatOperation, Decimal, 7.5) 612 self.assertTrue(c.flags[FloatOperation]) 613 614 r = Decimal(0.1) 615 self.assertEqual(type(r), Decimal) 616 self.assertEqual(str(r), 617 '0.1000000000000000055511151231257827021181583404541015625') 618 self.assertTrue(Decimal(float('nan')).is_qnan()) 619 self.assertTrue(Decimal(float('inf')).is_infinite()) 620 self.assertTrue(Decimal(float('-inf')).is_infinite()) 621 self.assertEqual(str(Decimal(float('nan'))), 622 str(Decimal('NaN'))) 623 self.assertEqual(str(Decimal(float('inf'))), 624 str(Decimal('Infinity'))) 625 self.assertEqual(str(Decimal(float('-inf'))), 626 str(Decimal('-Infinity'))) 627 self.assertEqual(str(Decimal(float('-0.0'))), 628 str(Decimal('-0'))) 629 for i in range(200): 630 x = random.expovariate(0.01) * (random.random() * 2.0 - 1.0) 631 self.assertEqual(x, float(Decimal(x))) # roundtrip 632 633 def test_explicit_context_create_decimal(self): 634 635 nc = copy.copy(getcontext()) 636 nc.prec = 3 637 638 # empty 639 d = Decimal() 640 self.assertEqual(str(d), '0') 641 d = nc.create_decimal() 642 self.assertEqual(str(d), '0') 643 644 # from None 645 self.assertRaises(TypeError, nc.create_decimal, None) 646 647 # from int 648 d = nc.create_decimal(456) 649 self.assertTrue(isinstance(d, Decimal)) 650 self.assertEqual(nc.create_decimal(45678), 651 nc.create_decimal('457E+2')) 652 653 # from string 654 d = Decimal('456789') 655 self.assertEqual(str(d), '456789') 656 d = nc.create_decimal('456789') 657 self.assertEqual(str(d), '4.57E+5') 658 # leading and trailing whitespace should result in a NaN; 659 # spaces are already checked in Cowlishaw's test-suite, so 660 # here we just check that a trailing newline results in a NaN 661 self.assertEqual(str(nc.create_decimal('3.14\n')), 'NaN') 662 663 # from tuples 664 d = Decimal( (1, (4, 3, 4, 9, 1, 3, 5, 3, 4), -25) ) 665 self.assertEqual(str(d), '-4.34913534E-17') 666 d = nc.create_decimal( (1, (4, 3, 4, 9, 1, 3, 5, 3, 4), -25) ) 667 self.assertEqual(str(d), '-4.35E-17') 668 669 # from Decimal 670 prevdec = Decimal(500000123) 671 d = Decimal(prevdec) 672 self.assertEqual(str(d), '500000123') 673 d = nc.create_decimal(prevdec) 674 self.assertEqual(str(d), '5.00E+8') 675 676 def test_unicode_digits(self): 677 test_values = { 678 u'\uff11': '1', 679 u'\u0660.\u0660\u0663\u0667\u0662e-\u0663' : '0.0000372', 680 u'-nan\u0c68\u0c6a\u0c66\u0c66' : '-NaN2400', 681 } 682 for input, expected in test_values.items(): 683 self.assertEqual(str(Decimal(input)), expected) 684 685 686class DecimalImplicitConstructionTest(unittest.TestCase): 687 '''Unit tests for Implicit Construction cases of Decimal.''' 688 689 def test_implicit_from_None(self): 690 self.assertRaises(TypeError, eval, 'Decimal(5) + None', globals()) 691 692 def test_implicit_from_int(self): 693 #normal 694 self.assertEqual(str(Decimal(5) + 45), '50') 695 #exceeding precision 696 self.assertEqual(Decimal(5) + 123456789000, Decimal(123456789000)) 697 698 def test_implicit_from_string(self): 699 self.assertRaises(TypeError, eval, 'Decimal(5) + "3"', globals()) 700 701 def test_implicit_from_float(self): 702 self.assertRaises(TypeError, eval, 'Decimal(5) + 2.2', globals()) 703 704 def test_implicit_from_Decimal(self): 705 self.assertEqual(Decimal(5) + Decimal(45), Decimal(50)) 706 707 def test_rop(self): 708 # Allow other classes to be trained to interact with Decimals 709 class E: 710 def __divmod__(self, other): 711 return 'divmod ' + str(other) 712 def __rdivmod__(self, other): 713 return str(other) + ' rdivmod' 714 def __lt__(self, other): 715 return 'lt ' + str(other) 716 def __gt__(self, other): 717 return 'gt ' + str(other) 718 def __le__(self, other): 719 return 'le ' + str(other) 720 def __ge__(self, other): 721 return 'ge ' + str(other) 722 def __eq__(self, other): 723 return 'eq ' + str(other) 724 def __ne__(self, other): 725 return 'ne ' + str(other) 726 727 self.assertEqual(divmod(E(), Decimal(10)), 'divmod 10') 728 self.assertEqual(divmod(Decimal(10), E()), '10 rdivmod') 729 self.assertEqual(eval('Decimal(10) < E()'), 'gt 10') 730 self.assertEqual(eval('Decimal(10) > E()'), 'lt 10') 731 self.assertEqual(eval('Decimal(10) <= E()'), 'ge 10') 732 self.assertEqual(eval('Decimal(10) >= E()'), 'le 10') 733 self.assertEqual(eval('Decimal(10) == E()'), 'eq 10') 734 self.assertEqual(eval('Decimal(10) != E()'), 'ne 10') 735 736 # insert operator methods and then exercise them 737 oplist = [ 738 ('+', '__add__', '__radd__'), 739 ('-', '__sub__', '__rsub__'), 740 ('*', '__mul__', '__rmul__'), 741 ('%', '__mod__', '__rmod__'), 742 ('//', '__floordiv__', '__rfloordiv__'), 743 ('**', '__pow__', '__rpow__') 744 ] 745 if 1/2 == 0: 746 # testing with classic division, so add __div__ 747 oplist.append(('/', '__div__', '__rdiv__')) 748 else: 749 # testing with -Qnew, so add __truediv__ 750 oplist.append(('/', '__truediv__', '__rtruediv__')) 751 752 for sym, lop, rop in oplist: 753 setattr(E, lop, lambda self, other: 'str' + lop + str(other)) 754 setattr(E, rop, lambda self, other: str(other) + rop + 'str') 755 self.assertEqual(eval('E()' + sym + 'Decimal(10)'), 756 'str' + lop + '10') 757 self.assertEqual(eval('Decimal(10)' + sym + 'E()'), 758 '10' + rop + 'str') 759 760class DecimalArithmeticOperatorsTest(unittest.TestCase): 761 '''Unit tests for all arithmetic operators, binary and unary.''' 762 763 def test_addition(self): 764 765 d1 = Decimal('-11.1') 766 d2 = Decimal('22.2') 767 768 #two Decimals 769 self.assertEqual(d1+d2, Decimal('11.1')) 770 self.assertEqual(d2+d1, Decimal('11.1')) 771 772 #with other type, left 773 c = d1 + 5 774 self.assertEqual(c, Decimal('-6.1')) 775 self.assertEqual(type(c), type(d1)) 776 777 #with other type, right 778 c = 5 + d1 779 self.assertEqual(c, Decimal('-6.1')) 780 self.assertEqual(type(c), type(d1)) 781 782 #inline with decimal 783 d1 += d2 784 self.assertEqual(d1, Decimal('11.1')) 785 786 #inline with other type 787 d1 += 5 788 self.assertEqual(d1, Decimal('16.1')) 789 790 def test_subtraction(self): 791 792 d1 = Decimal('-11.1') 793 d2 = Decimal('22.2') 794 795 #two Decimals 796 self.assertEqual(d1-d2, Decimal('-33.3')) 797 self.assertEqual(d2-d1, Decimal('33.3')) 798 799 #with other type, left 800 c = d1 - 5 801 self.assertEqual(c, Decimal('-16.1')) 802 self.assertEqual(type(c), type(d1)) 803 804 #with other type, right 805 c = 5 - d1 806 self.assertEqual(c, Decimal('16.1')) 807 self.assertEqual(type(c), type(d1)) 808 809 #inline with decimal 810 d1 -= d2 811 self.assertEqual(d1, Decimal('-33.3')) 812 813 #inline with other type 814 d1 -= 5 815 self.assertEqual(d1, Decimal('-38.3')) 816 817 def test_multiplication(self): 818 819 d1 = Decimal('-5') 820 d2 = Decimal('3') 821 822 #two Decimals 823 self.assertEqual(d1*d2, Decimal('-15')) 824 self.assertEqual(d2*d1, Decimal('-15')) 825 826 #with other type, left 827 c = d1 * 5 828 self.assertEqual(c, Decimal('-25')) 829 self.assertEqual(type(c), type(d1)) 830 831 #with other type, right 832 c = 5 * d1 833 self.assertEqual(c, Decimal('-25')) 834 self.assertEqual(type(c), type(d1)) 835 836 #inline with decimal 837 d1 *= d2 838 self.assertEqual(d1, Decimal('-15')) 839 840 #inline with other type 841 d1 *= 5 842 self.assertEqual(d1, Decimal('-75')) 843 844 def test_division(self): 845 846 d1 = Decimal('-5') 847 d2 = Decimal('2') 848 849 #two Decimals 850 self.assertEqual(d1/d2, Decimal('-2.5')) 851 self.assertEqual(d2/d1, Decimal('-0.4')) 852 853 #with other type, left 854 c = d1 / 4 855 self.assertEqual(c, Decimal('-1.25')) 856 self.assertEqual(type(c), type(d1)) 857 858 #with other type, right 859 c = 4 / d1 860 self.assertEqual(c, Decimal('-0.8')) 861 self.assertEqual(type(c), type(d1)) 862 863 #inline with decimal 864 d1 /= d2 865 self.assertEqual(d1, Decimal('-2.5')) 866 867 #inline with other type 868 d1 /= 4 869 self.assertEqual(d1, Decimal('-0.625')) 870 871 def test_floor_division(self): 872 873 d1 = Decimal('5') 874 d2 = Decimal('2') 875 876 #two Decimals 877 self.assertEqual(d1//d2, Decimal('2')) 878 self.assertEqual(d2//d1, Decimal('0')) 879 880 #with other type, left 881 c = d1 // 4 882 self.assertEqual(c, Decimal('1')) 883 self.assertEqual(type(c), type(d1)) 884 885 #with other type, right 886 c = 7 // d1 887 self.assertEqual(c, Decimal('1')) 888 self.assertEqual(type(c), type(d1)) 889 890 #inline with decimal 891 d1 //= d2 892 self.assertEqual(d1, Decimal('2')) 893 894 #inline with other type 895 d1 //= 2 896 self.assertEqual(d1, Decimal('1')) 897 898 def test_powering(self): 899 900 d1 = Decimal('5') 901 d2 = Decimal('2') 902 903 #two Decimals 904 self.assertEqual(d1**d2, Decimal('25')) 905 self.assertEqual(d2**d1, Decimal('32')) 906 907 #with other type, left 908 c = d1 ** 4 909 self.assertEqual(c, Decimal('625')) 910 self.assertEqual(type(c), type(d1)) 911 912 #with other type, right 913 c = 7 ** d1 914 self.assertEqual(c, Decimal('16807')) 915 self.assertEqual(type(c), type(d1)) 916 917 #inline with decimal 918 d1 **= d2 919 self.assertEqual(d1, Decimal('25')) 920 921 #inline with other type 922 d1 **= 4 923 self.assertEqual(d1, Decimal('390625')) 924 925 def test_module(self): 926 927 d1 = Decimal('5') 928 d2 = Decimal('2') 929 930 #two Decimals 931 self.assertEqual(d1%d2, Decimal('1')) 932 self.assertEqual(d2%d1, Decimal('2')) 933 934 #with other type, left 935 c = d1 % 4 936 self.assertEqual(c, Decimal('1')) 937 self.assertEqual(type(c), type(d1)) 938 939 #with other type, right 940 c = 7 % d1 941 self.assertEqual(c, Decimal('2')) 942 self.assertEqual(type(c), type(d1)) 943 944 #inline with decimal 945 d1 %= d2 946 self.assertEqual(d1, Decimal('1')) 947 948 #inline with other type 949 d1 %= 4 950 self.assertEqual(d1, Decimal('1')) 951 952 def test_floor_div_module(self): 953 954 d1 = Decimal('5') 955 d2 = Decimal('2') 956 957 #two Decimals 958 (p, q) = divmod(d1, d2) 959 self.assertEqual(p, Decimal('2')) 960 self.assertEqual(q, Decimal('1')) 961 self.assertEqual(type(p), type(d1)) 962 self.assertEqual(type(q), type(d1)) 963 964 #with other type, left 965 (p, q) = divmod(d1, 4) 966 self.assertEqual(p, Decimal('1')) 967 self.assertEqual(q, Decimal('1')) 968 self.assertEqual(type(p), type(d1)) 969 self.assertEqual(type(q), type(d1)) 970 971 #with other type, right 972 (p, q) = divmod(7, d1) 973 self.assertEqual(p, Decimal('1')) 974 self.assertEqual(q, Decimal('2')) 975 self.assertEqual(type(p), type(d1)) 976 self.assertEqual(type(q), type(d1)) 977 978 def test_unary_operators(self): 979 self.assertEqual(+Decimal(45), Decimal(+45)) # + 980 self.assertEqual(-Decimal(45), Decimal(-45)) # - 981 self.assertEqual(abs(Decimal(45)), abs(Decimal(-45))) # abs 982 983 def test_nan_comparisons(self): 984 n = Decimal('NaN') 985 s = Decimal('sNaN') 986 i = Decimal('Inf') 987 f = Decimal('2') 988 for x, y in [(n, n), (n, i), (i, n), (n, f), (f, n), 989 (s, n), (n, s), (s, i), (i, s), (s, f), (f, s), (s, s)]: 990 self.assertTrue(x != y) 991 self.assertTrue(not (x == y)) 992 self.assertTrue(not (x < y)) 993 self.assertTrue(not (x <= y)) 994 self.assertTrue(not (x > y)) 995 self.assertTrue(not (x >= y)) 996 997 def test_copy_sign(self): 998 d = Decimal(1).copy_sign(Decimal(-2)) 999 1000 self.assertEqual(Decimal(1).copy_sign(-2), d) 1001 self.assertRaises(TypeError, Decimal(1).copy_sign, '-2') 1002 1003# The following are two functions used to test threading in the next class 1004 1005def thfunc1(cls): 1006 d1 = Decimal(1) 1007 d3 = Decimal(3) 1008 test1 = d1/d3 1009 1010 cls.finish1.set() 1011 cls.synchro.wait() 1012 1013 test2 = d1/d3 1014 with localcontext() as c2: 1015 cls.assertTrue(c2.flags[Inexact]) 1016 cls.assertRaises(DivisionByZero, c2.divide, d1, 0) 1017 cls.assertTrue(c2.flags[DivisionByZero]) 1018 with localcontext() as c3: 1019 cls.assertTrue(c3.flags[Inexact]) 1020 cls.assertTrue(c3.flags[DivisionByZero]) 1021 cls.assertRaises(InvalidOperation, c3.compare, d1, Decimal('sNaN')) 1022 cls.assertTrue(c3.flags[InvalidOperation]) 1023 del c3 1024 cls.assertFalse(c2.flags[InvalidOperation]) 1025 del c2 1026 1027 cls.assertEqual(test1, Decimal('0.333333333333333333333333')) 1028 cls.assertEqual(test2, Decimal('0.333333333333333333333333')) 1029 1030 c1 = getcontext() 1031 cls.assertTrue(c1.flags[Inexact]) 1032 for sig in Overflow, Underflow, DivisionByZero, InvalidOperation: 1033 cls.assertFalse(c1.flags[sig]) 1034 return 1035 1036def thfunc2(cls): 1037 d1 = Decimal(1) 1038 d3 = Decimal(3) 1039 test1 = d1/d3 1040 1041 thiscontext = getcontext() 1042 thiscontext.prec = 18 1043 test2 = d1/d3 1044 1045 with localcontext() as c2: 1046 cls.assertTrue(c2.flags[Inexact]) 1047 cls.assertRaises(Overflow, c2.multiply, Decimal('1e425000000'), 999) 1048 cls.assertTrue(c2.flags[Overflow]) 1049 with localcontext(thiscontext) as c3: 1050 cls.assertTrue(c3.flags[Inexact]) 1051 cls.assertFalse(c3.flags[Overflow]) 1052 c3.traps[Underflow] = True 1053 cls.assertRaises(Underflow, c3.divide, Decimal('1e-425000000'), 999) 1054 cls.assertTrue(c3.flags[Underflow]) 1055 del c3 1056 cls.assertFalse(c2.flags[Underflow]) 1057 cls.assertFalse(c2.traps[Underflow]) 1058 del c2 1059 1060 cls.synchro.set() 1061 cls.finish2.set() 1062 1063 cls.assertEqual(test1, Decimal('0.333333333333333333333333')) 1064 cls.assertEqual(test2, Decimal('0.333333333333333333')) 1065 1066 cls.assertFalse(thiscontext.traps[Underflow]) 1067 cls.assertTrue(thiscontext.flags[Inexact]) 1068 for sig in Overflow, Underflow, DivisionByZero, InvalidOperation: 1069 cls.assertFalse(thiscontext.flags[sig]) 1070 return 1071 1072class DecimalUseOfContextTest(unittest.TestCase): 1073 '''Unit tests for Use of Context cases in Decimal.''' 1074 1075 # Take care executing this test from IDLE, there's an issue in threading 1076 # that hangs IDLE and I couldn't find it 1077 1078 def test_threading(self): 1079 if threading is None: 1080 return 1081 if not HAVE_THREADS: 1082 return 1083 # Test the "threading isolation" of a Context. Also test changing 1084 # the DefaultContext, which acts as a template for the thread-local 1085 # contexts. 1086 save_prec = DefaultContext.prec 1087 save_emax = DefaultContext.Emax 1088 save_emin = DefaultContext.Emin 1089 DefaultContext.prec = 24 1090 DefaultContext.Emax = 425000000 1091 DefaultContext.Emin = -425000000 1092 1093 self.synchro = threading.Event() 1094 self.finish1 = threading.Event() 1095 self.finish2 = threading.Event() 1096 1097 th1 = threading.Thread(target=thfunc1, args=(self,)) 1098 th2 = threading.Thread(target=thfunc2, args=(self,)) 1099 1100 th1.start() 1101 th2.start() 1102 1103 self.finish1.wait() 1104 self.finish2.wait() 1105 1106 for sig in (Inexact, Overflow, Underflow, DivisionByZero, 1107 InvalidOperation): 1108 self.assertFalse(DefaultContext.flags[sig]) 1109 1110 DefaultContext.prec = save_prec 1111 DefaultContext.Emax = save_emax 1112 DefaultContext.Emin = save_emin 1113 return 1114 1115class DecimalUsabilityTest(unittest.TestCase): 1116 '''Unit tests for Usability cases of Decimal.''' 1117 1118 def test_comparison_operators(self): 1119 1120 da = Decimal('23.42') 1121 db = Decimal('23.42') 1122 dc = Decimal('45') 1123 1124 #two Decimals 1125 self.assertTrue(dc > da) 1126 self.assertTrue(dc >= da) 1127 self.assertTrue(da < dc) 1128 self.assertTrue(da <= dc) 1129 self.assertTrue(da == db) 1130 self.assertTrue(da != dc) 1131 self.assertTrue(da <= db) 1132 self.assertTrue(da >= db) 1133 self.assertEqual(cmp(dc,da), 1) 1134 self.assertEqual(cmp(da,dc), -1) 1135 self.assertEqual(cmp(da,db), 0) 1136 1137 #a Decimal and an int 1138 self.assertTrue(dc > 23) 1139 self.assertTrue(23 < dc) 1140 self.assertTrue(dc == 45) 1141 self.assertEqual(cmp(dc,23), 1) 1142 self.assertEqual(cmp(23,dc), -1) 1143 self.assertEqual(cmp(dc,45), 0) 1144 1145 #a Decimal and uncomparable 1146 self.assertNotEqual(da, 'ugly') 1147 self.assertNotEqual(da, 32.7) 1148 self.assertNotEqual(da, object()) 1149 self.assertNotEqual(da, object) 1150 1151 # sortable 1152 a = map(Decimal, xrange(100)) 1153 b = a[:] 1154 random.shuffle(a) 1155 a.sort() 1156 self.assertEqual(a, b) 1157 1158 # with None 1159 self.assertFalse(Decimal(1) < None) 1160 self.assertTrue(Decimal(1) > None) 1161 1162 def test_decimal_float_comparison(self): 1163 def assert_attr(a, b, attr, context, signal=None): 1164 context.clear_flags() 1165 f = getattr(a, attr) 1166 if HAVE_CDECIMAL: 1167 if signal == FloatOperation: 1168 self.assertRaises(signal, f, b) 1169 elif py_minor <= 6: 1170 self.assertTrue(f(b) is NotImplemented) 1171 else: 1172 self.assertTrue(f(b) is True) 1173 self.assertTrue(context.flags[FloatOperation]) 1174 else: 1175 self.assertTrue(f(b) is True) 1176 1177 small_d = Decimal('0.25') 1178 big_d = Decimal('3.0') 1179 small_f = 0.25 1180 big_f = 3.0 1181 1182 zero_d = Decimal('0.0') 1183 neg_zero_d = Decimal('-0.0') 1184 zero_f = 0.0 1185 neg_zero_f = -0.0 1186 1187 inf_d = Decimal('Infinity') 1188 neg_inf_d = Decimal('-Infinity') 1189 inf_f = float('inf') 1190 neg_inf_f = float('-inf') 1191 1192 def doit(c, signal=None): 1193 # Order 1194 for attr in '__lt__', '__le__': 1195 assert_attr(small_d, big_f, attr, c, signal) 1196 1197 for attr in '__gt__', '__ge__': 1198 assert_attr(big_d, small_f, attr, c, signal) 1199 1200 # Equality 1201 assert_attr(small_d, small_f, '__eq__', c, None) 1202 1203 assert_attr(neg_zero_d, neg_zero_f, '__eq__', c, None) 1204 assert_attr(neg_zero_d, zero_f, '__eq__', c, None) 1205 1206 assert_attr(zero_d, neg_zero_f, '__eq__', c, None) 1207 assert_attr(zero_d, zero_f, '__eq__', c, None) 1208 1209 assert_attr(neg_inf_d, neg_inf_f, '__eq__', c, None) 1210 assert_attr(inf_d, inf_f, '__eq__', c, None) 1211 1212 # Inequality 1213 assert_attr(small_d, big_f, '__ne__', c, None) 1214 1215 assert_attr(Decimal('0.1'), 0.1, '__ne__', c, None) 1216 1217 assert_attr(neg_inf_d, inf_f, '__ne__', c, None) 1218 assert_attr(inf_d, neg_inf_f, '__ne__', c, None) 1219 1220 assert_attr(Decimal('NaN'), float('nan'), '__ne__', c, None) 1221 1222 def test_containers(c, signal): 1223 c.clear_flags() 1224 s = set([100.0, Decimal('100.0')]) 1225 expected_len = 2 if py_minor <= 6 else 1 1226 self.assertEqual(len(s), expected_len) 1227 self.assertTrue(c.flags[FloatOperation]) 1228 1229 c.clear_flags() 1230 if signal: 1231 self.assertRaises(signal, sorted, [1.0, Decimal('10.0')]) 1232 else: 1233 s = sorted([10.0, Decimal('10.0')]) 1234 self.assertTrue(c.flags[FloatOperation]) 1235 1236 c.clear_flags() 1237 b = 10.0 in [Decimal('10.0'), 1.0] 1238 self.assertTrue(c.flags[FloatOperation]) 1239 1240 c.clear_flags() 1241 b = 10.0 in {Decimal('10.0'):'a', 1.0:'b'} 1242 self.assertTrue(c.flags[FloatOperation]) 1243 1244 if HAVE_CDECIMAL: 1245 nc = Context() 1246 if py_minor <= 6: 1247 with localcontext(nc) as c: 1248 self.assertFalse(c.traps[FloatOperation]) 1249 doit(c, signal=None) 1250 test_containers(c, None) 1251 1252 c.traps[FloatOperation] = True 1253 doit(c, signal=FloatOperation) 1254 test_containers(c, FloatOperation) 1255 else: 1256 with localcontext(nc) as c: 1257 # In 3.2 the FloatOperation signal is off by default. 1258 self.assertFalse(c.traps[FloatOperation]) 1259 doit(c, signal=None) 1260 test_containers(c, None) 1261 1262 c.traps[FloatOperation] = True 1263 doit(c, signal=FloatOperation) 1264 test_containers(c, FloatOperation) 1265 else: 1266 # decimal.py does not have the FloatOperation signal. 1267 nc = Context() 1268 with localcontext(nc) as c: 1269 doit(c, signal=False) 1270 1271 def test_copy_and_deepcopy_methods(self): 1272 d = Decimal('43.24') 1273 c = copy.copy(d) 1274 self.assertEqual(id(c), id(d)) 1275 dc = copy.deepcopy(d) 1276 self.assertEqual(id(dc), id(d)) 1277 1278 def test_hash_method(self): 1279 def hashit(d): 1280 a = hash(d) 1281 b = d.__hash__() 1282 self.assertEqual(a, b) 1283 return a 1284 1285 #just that it's hashable 1286 hashit(Decimal(23)) 1287 hashit(Decimal('Infinity')) 1288 hashit(Decimal('-Infinity')) 1289 if py_minor >= 7: 1290 hashit(Decimal('nan123')) 1291 hashit(Decimal('-NaN')) 1292 1293 test_values = [Decimal(sign*(2**m + n)) 1294 for m in [0, 14, 15, 16, 17, 30, 31, 1295 32, 33, 61, 62, 63, 64, 65, 66] 1296 for n in range(-10, 10) 1297 for sign in [-1, 1]] 1298 test_values.extend([ 1299 Decimal("-1"), # ==> -2 1300 Decimal("-0"), # zeros 1301 Decimal("0.00"), 1302 Decimal("-0.000"), 1303 Decimal("0E10"), 1304 Decimal("-0E12"), 1305 Decimal("10.0"), # negative exponent 1306 Decimal("-23.00000"), 1307 Decimal("1230E100"), # positive exponent 1308 Decimal("-4.5678E50"), 1309 # a value for which hash(n) != hash(n % (2**64-1)) 1310 # in Python pre-2.6 1311 Decimal(2**64 + 2**32 - 1), 1312 # selection of values which fail with the old (before 1313 # version 2.6) long.__hash__ 1314 Decimal("1.634E100"), 1315 Decimal("90.697E100"), 1316 Decimal("188.83E100"), 1317 Decimal("1652.9E100"), 1318 Decimal("56531E100"), 1319 ]) 1320 1321 # check that hash(d) == hash(int(d)) for integral values 1322 for value in test_values: 1323 self.assertEqual(hashit(value), hashit(int(value))) 1324 1325 #the same hash that to an int 1326 self.assertEqual(hashit(Decimal(23)), hashit(23)) 1327 self.assertRaises(TypeError, hash, Decimal('sNaN')) 1328 self.assertTrue(hashit(Decimal('Inf'))) 1329 self.assertTrue(hashit(Decimal('-Inf'))) 1330 1331 if py_minor >= 7: 1332 # check that the hashes of a Decimal float match when they 1333 # represent exactly the same values 1334 test_strings = ['inf', '-Inf', '0.0', '-.0e1', 1335 '34.0', '2.5', '112390.625', '-0.515625'] 1336 for s in test_strings: 1337 f = float(s) 1338 d = Decimal(s) 1339 self.assertEqual(hashit(f), hashit(d)) 1340 1341 # check that the value of the hash doesn't depend on the 1342 # current context (issue #1757) 1343 c = getcontext() 1344 old_precision = c.prec 1345 x = Decimal("123456789.1") 1346 1347 c.prec = 6 1348 h1 = hashit(x) 1349 c.prec = 10 1350 h2 = hashit(x) 1351 c.prec = 16 1352 h3 = hashit(x) 1353 1354 self.assertEqual(h1, h2) 1355 self.assertEqual(h1, h3) 1356 c.prec = old_precision 1357 1358 def test_min_and_max_methods(self): 1359 1360 d1 = Decimal('15.32') 1361 d2 = Decimal('28.5') 1362 l1 = 15 1363 l2 = 28 1364 1365 #between Decimals 1366 self.assertTrue(min(d1,d2) is d1) 1367 self.assertTrue(min(d2,d1) is d1) 1368 self.assertTrue(max(d1,d2) is d2) 1369 self.assertTrue(max(d2,d1) is d2) 1370 1371 #between Decimal and long 1372 self.assertTrue(min(d1,l2) is d1) 1373 self.assertTrue(min(l2,d1) is d1) 1374 self.assertTrue(max(l1,d2) is d2) 1375 self.assertTrue(max(d2,l1) is d2) 1376 1377 def test_as_nonzero(self): 1378 #as false 1379 self.assertFalse(Decimal(0)) 1380 #as true 1381 self.assertTrue(Decimal('0.372')) 1382 1383 def test_tostring_methods(self): 1384 #Test str and repr methods. 1385 1386 d = Decimal('15.32') 1387 self.assertEqual(str(d), '15.32') # str 1388 self.assertEqual(repr(d), "Decimal('15.32')") # repr 1389 1390 # result type of string methods should be str, not unicode 1391 unicode_inputs = [u'123.4', u'0.5E2', u'Infinity', u'sNaN', 1392 u'-0.0E100', u'-NaN001', u'-Inf'] 1393 1394 for u in unicode_inputs: 1395 d = Decimal(u) 1396 self.assertEqual(type(str(d)), str) 1397 self.assertEqual(type(repr(d)), str) 1398 self.assertEqual(type(d.to_eng_string()), str) 1399 1400 def test_tonum_methods(self): 1401 #Test float, int and long methods. 1402 1403 d1 = Decimal('66') 1404 d2 = Decimal('15.32') 1405 1406 #int 1407 self.assertEqual(int(d1), 66) 1408 self.assertEqual(int(d2), 15) 1409 1410 #long 1411 self.assertEqual(long(d1), 66) 1412 self.assertEqual(long(d2), 15) 1413 1414 #float 1415 self.assertEqual(float(d1), 66) 1416 self.assertEqual(float(d2), 15.32) 1417 1418 def test_eval_round_trip(self): 1419 1420 #with zero 1421 d = Decimal( (0, (0,), 0) ) 1422 self.assertEqual(d, eval(repr(d))) 1423 1424 #int 1425 d = Decimal( (1, (4, 5), 0) ) 1426 self.assertEqual(d, eval(repr(d))) 1427 1428 #float 1429 d = Decimal( (0, (4, 5, 3, 4), -2) ) 1430 self.assertEqual(d, eval(repr(d))) 1431 1432 #weird 1433 d = Decimal( (1, (4, 3, 4, 9, 1, 3, 5, 3, 4), -25) ) 1434 self.assertEqual(d, eval(repr(d))) 1435 1436 def test_as_tuple(self): 1437 1438 #with zero 1439 d = Decimal(0) 1440 self.assertEqual(d.as_tuple(), (0, (0,), 0) ) 1441 1442 #int 1443 d = Decimal(-45) 1444 self.assertEqual(d.as_tuple(), (1, (4, 5), 0) ) 1445 1446 #complicated string 1447 d = Decimal("-4.34913534E-17") 1448 self.assertEqual(d.as_tuple(), (1, (4, 3, 4, 9, 1, 3, 5, 3, 4), -25) ) 1449 1450 # XXX empty tuple, like in the NaN case 1451 d = Decimal("Infinity") 1452 self.assertEqual(d.as_tuple(), (0, (0,), 'F') ) 1453 1454 #leading zeros in coefficient should be stripped 1455 d = Decimal( (0, (0, 0, 4, 0, 5, 3, 4), -2) ) 1456 self.assertEqual(d.as_tuple(), (0, (4, 0, 5, 3, 4), -2) ) 1457 d = Decimal( (1, (0, 0, 0), 37) ) 1458 self.assertEqual(d.as_tuple(), (1, (0,), 37)) 1459 d = Decimal( (1, (), 37) ) 1460 self.assertEqual(d.as_tuple(), (1, (0,), 37)) 1461 1462 #leading zeros in NaN diagnostic info should be stripped 1463 d = Decimal( (0, (0, 0, 4, 0, 5, 3, 4), 'n') ) 1464 self.assertEqual(d.as_tuple(), (0, (4, 0, 5, 3, 4), 'n') ) 1465 d = Decimal( (1, (0, 0, 0), 'N') ) 1466 self.assertEqual(d.as_tuple(), (1, (), 'N') ) 1467 d = Decimal( (1, (), 'n') ) 1468 self.assertEqual(d.as_tuple(), (1, (), 'n') ) 1469 1470 # XXX coefficient in infinity should raise an error 1471 # d = Decimal( (0, (4, 5, 3, 4), 'F') ) 1472 # self.assertEqual(d.as_tuple(), (0, (0,), 'F')) 1473 # d = Decimal( (1, (0, 2, 7, 1), 'F') ) 1474 # self.assertEqual(d.as_tuple(), (1, (0,), 'F')) 1475 1476 def XXX_test_immutability_operations(self): 1477 # XXX Checked extensively in the library runtest. 1478 # Do operations and check that it didn't change change internal objects. 1479 1480 d1 = Decimal('-25e55') 1481 b1 = Decimal('-25e55') 1482 d2 = Decimal('33e+33') 1483 b2 = Decimal('33e+33') 1484 1485 def checkSameDec(operation, useOther=False): 1486 if useOther: 1487 eval("d1." + operation + "(d2)") 1488 self.assertEqual(d1._sign, b1._sign) 1489 self.assertEqual(d1._int, b1._int) 1490 self.assertEqual(d1._exp, b1._exp) 1491 self.assertEqual(d2._sign, b2._sign) 1492 self.assertEqual(d2._int, b2._int) 1493 self.assertEqual(d2._exp, b2._exp) 1494 else: 1495 eval("d1." + operation + "()") 1496 self.assertEqual(d1._sign, b1._sign) 1497 self.assertEqual(d1._int, b1._int) 1498 self.assertEqual(d1._exp, b1._exp) 1499 return 1500 1501 Decimal(d1) 1502 self.assertEqual(d1._sign, b1._sign) 1503 self.assertEqual(d1._int, b1._int) 1504 self.assertEqual(d1._exp, b1._exp) 1505 1506 checkSameDec("__abs__") 1507 checkSameDec("__add__", True) 1508 checkSameDec("__div__", True) 1509 checkSameDec("__divmod__", True) 1510 checkSameDec("__eq__", True) 1511 checkSameDec("__ne__", True) 1512 checkSameDec("__le__", True) 1513 checkSameDec("__lt__", True) 1514 checkSameDec("__ge__", True) 1515 checkSameDec("__gt__", True) 1516 checkSameDec("__float__") 1517 checkSameDec("__floordiv__", True) 1518 checkSameDec("__hash__") 1519 checkSameDec("__int__") 1520 checkSameDec("__trunc__") 1521 checkSameDec("__long__") 1522 checkSameDec("__mod__", True) 1523 checkSameDec("__mul__", True) 1524 checkSameDec("__neg__") 1525 checkSameDec("__nonzero__") 1526 checkSameDec("__pos__") 1527 checkSameDec("__pow__", True) 1528 checkSameDec("__radd__", True) 1529 checkSameDec("__rdiv__", True) 1530 checkSameDec("__rdivmod__", True) 1531 checkSameDec("__repr__") 1532 checkSameDec("__rfloordiv__", True) 1533 checkSameDec("__rmod__", True) 1534 checkSameDec("__rmul__", True) 1535 checkSameDec("__rpow__", True) 1536 checkSameDec("__rsub__", True) 1537 checkSameDec("__str__") 1538 checkSameDec("__sub__", True) 1539 checkSameDec("__truediv__", True) 1540 checkSameDec("adjusted") 1541 checkSameDec("as_tuple") 1542 checkSameDec("compare", True) 1543 checkSameDec("max", True) 1544 checkSameDec("min", True) 1545 checkSameDec("normalize") 1546 checkSameDec("quantize", True) 1547 checkSameDec("remainder_near", True) 1548 checkSameDec("same_quantum", True) 1549 checkSameDec("sqrt") 1550 checkSameDec("to_eng_string") 1551 checkSameDec("to_integral") 1552 1553 def test_subclassing(self): 1554 # Different behaviours when subclassing Decimal 1555 1556 class MyDecimal(Decimal): 1557 pass 1558 1559 d1 = MyDecimal(1) 1560 d2 = MyDecimal(2) 1561 d = d1 + d2 1562 self.assertTrue(type(d) is Decimal) 1563 1564 d = d1.max(d2) 1565 self.assertTrue(type(d) is Decimal) 1566 1567 def test_implicit_context(self): 1568 # Check results when context given implicitly. (Issue 2478) 1569 c = getcontext() 1570 self.assertEqual(str(Decimal(0).sqrt()), 1571 str(c.sqrt(Decimal(0)))) 1572 1573 def test_conversions_from_int(self): 1574 # Check that methods taking a second Decimal argument will 1575 # always accept an integer in place of a Decimal. 1576 self.assertEqual(Decimal(4).compare(3), 1577 Decimal(4).compare(Decimal(3))) 1578 self.assertEqual(Decimal(4).compare_signal(3), 1579 Decimal(4).compare_signal(Decimal(3))) 1580 self.assertEqual(Decimal(4).compare_total(3), 1581 Decimal(4).compare_total(Decimal(3))) 1582 self.assertEqual(Decimal(4).compare_total_mag(3), 1583 Decimal(4).compare_total_mag(Decimal(3))) 1584 self.assertEqual(Decimal(10101).logical_and(1001), 1585 Decimal(10101).logical_and(Decimal(1001))) 1586 self.assertEqual(Decimal(10101).logical_or(1001), 1587 Decimal(10101).logical_or(Decimal(1001))) 1588 self.assertEqual(Decimal(10101).logical_xor(1001), 1589 Decimal(10101).logical_xor(Decimal(1001))) 1590 self.assertEqual(Decimal(567).max(123), 1591 Decimal(567).max(Decimal(123))) 1592 self.assertEqual(Decimal(567).max_mag(123), 1593 Decimal(567).max_mag(Decimal(123))) 1594 self.assertEqual(Decimal(567).min(123), 1595 Decimal(567).min(Decimal(123))) 1596 self.assertEqual(Decimal(567).min_mag(123), 1597 Decimal(567).min_mag(Decimal(123))) 1598 self.assertEqual(Decimal(567).next_toward(123), 1599 Decimal(567).next_toward(Decimal(123))) 1600 self.assertEqual(Decimal(1234).quantize(100), 1601 Decimal(1234).quantize(Decimal(100))) 1602 self.assertEqual(Decimal(768).remainder_near(1234), 1603 Decimal(768).remainder_near(Decimal(1234))) 1604 self.assertEqual(Decimal(123).rotate(1), 1605 Decimal(123).rotate(Decimal(1))) 1606 self.assertEqual(Decimal(1234).same_quantum(1000), 1607 Decimal(1234).same_quantum(Decimal(1000))) 1608 self.assertEqual(Decimal('9.123').scaleb(-100), 1609 Decimal('9.123').scaleb(Decimal(-100))) 1610 self.assertEqual(Decimal(456).shift(-1), 1611 Decimal(456).shift(Decimal(-1))) 1612 1613 self.assertEqual(Decimal(-12).fma(Decimal(45), 67), 1614 Decimal(-12).fma(Decimal(45), Decimal(67))) 1615 self.assertEqual(Decimal(-12).fma(45, 67), 1616 Decimal(-12).fma(Decimal(45), Decimal(67))) 1617 self.assertEqual(Decimal(-12).fma(45, Decimal(67)), 1618 Decimal(-12).fma(Decimal(45), Decimal(67))) 1619 1620class DecimalPythonAPItests(unittest.TestCase): 1621 1622 def test_pickle(self): 1623 d = Decimal('-3.141590000') 1624 p = pickle.dumps(d) 1625 e = pickle.loads(p) 1626 self.assertEqual(d, e) 1627 1628 def test_int(self): 1629 for x in range(-250, 250): 1630 s = '%0.2f' % (x / 100.0) 1631 # should work the same as for floats 1632 self.assertEqual(int(Decimal(s)), int(float(s))) 1633 # should work the same as to_integral in the ROUND_DOWN mode 1634 d = Decimal(s) 1635 r = d.to_integral(ROUND_DOWN) 1636 self.assertEqual(Decimal(int(d)), r) 1637 1638 self.assertRaises(ValueError, int, Decimal('-nan')) 1639 self.assertRaises(ValueError, int, Decimal('snan')) 1640 self.assertRaises(OverflowError, int, Decimal('inf')) 1641 self.assertRaises(OverflowError, int, Decimal('-inf')) 1642 1643 self.assertRaises(ValueError, long, Decimal('-nan')) 1644 self.assertRaises(ValueError, long, Decimal('snan')) 1645 self.assertRaises(OverflowError, long, Decimal('inf')) 1646 self.assertRaises(OverflowError, long, Decimal('-inf')) 1647 1648 def test_quantize(self): 1649 c = Context(Emax=99999, Emin=-99999) 1650 self.assertEqual( 1651 Decimal('7.335').quantize(Decimal('.01')), 1652 Decimal('7.34') 1653 ) 1654 self.assertEqual( 1655 Decimal('7.335').quantize(Decimal('.01'), rounding=ROUND_DOWN), 1656 Decimal('7.33') 1657 ) 1658 self.assertRaises( 1659 InvalidOperation, 1660 Decimal("10e99999").quantize, Decimal('1e100000'), context=c 1661 ) 1662 if HAVE_CDECIMAL: 1663 self.assertRaises( 1664 TypeError, 1665 Decimal("1.23456789").quantize, Decimal('1e-100000'), [] 1666 ) 1667 self.assertRaises( 1668 TypeError, 1669 Decimal("1.23456789").quantize, Decimal('1e-100000'), c 1670 ) 1671 self.assertRaises( 1672 TypeError, 1673 Decimal("1.23456789").quantize, Decimal('1e-100000'), 10 1674 ) 1675 self.assertRaises( 1676 TypeError, 1677 Decimal("1.23456789").quantize, Decimal('1e-100000'), ROUND_UP, 1000 1678 ) 1679 1680class ContextAPItests(unittest.TestCase): 1681 1682 def test_pickle(self): 1683 c = Context() 1684 e = pickle.loads(pickle.dumps(c)) 1685 # XXX some are getters/setters 1686 #for k in vars(c): 1687 # v1 = vars(c)[k] 1688 # v2 = vars(e)[k] 1689 # self.assertEqual(v1, v2) 1690 self.assertEqual(c.prec, e.prec) 1691 self.assertEqual(c.Emin, e.Emin) 1692 self.assertEqual(c.Emax, e.Emax) 1693 self.assertEqual(c.rounding, e.rounding) 1694 self.assertEqual(c.capitals, e.capitals) 1695 self.assertEqual(c.traps, e.traps) 1696 self.assertEqual(c.flags, e.flags) 1697 self.assertEqual(c._clamp, e._clamp) 1698 1699 def test_equality_with_other_types(self): 1700 self.assertTrue(Decimal(10) in ['a', 1.0, Decimal(10), (1,2), {}]) 1701 self.assertTrue(Decimal(10) not in ['a', 1.0, (1,2), {}]) 1702 1703 def test_copy(self): 1704 # All copies should be deep 1705 c = Context() 1706 d = c.copy() 1707 self.assertNotEqual(id(c), id(d)) 1708 self.assertNotEqual(id(c.flags), id(d.flags)) 1709 self.assertNotEqual(id(c.traps), id(d.traps)) 1710 self.assertEqual(c.flags, d.flags) 1711 1712 def test_abs(self): 1713 c = Context() 1714 d = c.abs(Decimal(-1)) 1715 self.assertEqual(c.abs(-1), d) 1716 self.assertRaises(TypeError, c.abs, '-1') 1717 1718 def test_add(self): 1719 c = Context() 1720 d = c.add(Decimal(1), Decimal(1)) 1721 self.assertEqual(c.add(1, 1), d) 1722 self.assertEqual(c.add(Decimal(1), 1), d) 1723 self.assertEqual(c.add(1, Decimal(1)), d) 1724 self.assertRaises(TypeError, c.add, '1', 1) 1725 self.assertRaises(TypeError, c.add, 1, '1') 1726 1727 def test_compare(self): 1728 c = Context() 1729 d = c.compare(Decimal(1), Decimal(1)) 1730 self.assertEqual(c.compare(1, 1), d) 1731 self.assertEqual(c.compare(Decimal(1), 1), d) 1732 self.assertEqual(c.compare(1, Decimal(1)), d) 1733 self.assertRaises(TypeError, c.compare, '1', 1) 1734 self.assertRaises(TypeError, c.compare, 1, '1') 1735 1736 def test_compare_signal(self): 1737 c = Context() 1738 d = c.compare_signal(Decimal(1), Decimal(1)) 1739 self.assertEqual(c.compare_signal(1, 1), d) 1740 self.assertEqual(c.compare_signal(Decimal(1), 1), d) 1741 self.assertEqual(c.compare_signal(1, Decimal(1)), d) 1742 self.assertRaises(TypeError, c.compare_signal, '1', 1) 1743 self.assertRaises(TypeError, c.compare_signal, 1, '1') 1744 1745 def test_compare_total(self): 1746 c = Context() 1747 d = c.compare_total(Decimal(1), Decimal(1)) 1748 self.assertEqual(c.compare_total(1, 1), d) 1749 self.assertEqual(c.compare_total(Decimal(1), 1), d) 1750 self.assertEqual(c.compare_total(1, Decimal(1)), d) 1751 self.assertRaises(TypeError, c.compare_total, '1', 1) 1752 self.assertRaises(TypeError, c.compare_total, 1, '1') 1753 1754 def test_compare_total_mag(self): 1755 c = Context() 1756 d = c.compare_total_mag(Decimal(1), Decimal(1)) 1757 self.assertEqual(c.compare_total_mag(1, 1), d) 1758 self.assertEqual(c.compare_total_mag(Decimal(1), 1), d) 1759 self.assertEqual(c.compare_total_mag(1, Decimal(1)), d) 1760 self.assertRaises(TypeError, c.compare_total_mag, '1', 1) 1761 self.assertRaises(TypeError, c.compare_total_mag, 1, '1') 1762 1763 def test_copy_abs(self): 1764 c = Context() 1765 d = c.copy_abs(Decimal(-1)) 1766 self.assertEqual(c.copy_abs(-1), d) 1767 self.assertRaises(TypeError, c.copy_abs, '-1') 1768 1769 def test_copy_decimal(self): 1770 c = Context() 1771 d = c.copy_decimal(Decimal(-1)) 1772 self.assertEqual(c.copy_decimal(-1), d) 1773 self.assertRaises(TypeError, c.copy_decimal, '-1') 1774 1775 def test_copy_negate(self): 1776 c = Context() 1777 d = c.copy_negate(Decimal(-1)) 1778 self.assertEqual(c.copy_negate(-1), d) 1779 self.assertRaises(TypeError, c.copy_negate, '-1') 1780 1781 def test_copy_sign(self): 1782 c = Context() 1783 d = c.copy_sign(Decimal(1), Decimal(-2)) 1784 self.assertEqual(c.copy_sign(1, -2), d) 1785 self.assertEqual(c.copy_sign(Decimal(1), -2), d) 1786 self.assertEqual(c.copy_sign(1, Decimal(-2)), d) 1787 self.assertRaises(TypeError, c.copy_sign, '1', -2) 1788 self.assertRaises(TypeError, c.copy_sign, 1, '-2') 1789 1790 def test_divide(self): 1791 c = Context() 1792 d = c.divide(Decimal(1), Decimal(2)) 1793 self.assertEqual(c.divide(1, 2), d) 1794 self.assertEqual(c.divide(Decimal(1), 2), d) 1795 self.assertEqual(c.divide(1, Decimal(2)), d) 1796 self.assertRaises(TypeError, c.divide, '1', 2) 1797 self.assertRaises(TypeError, c.divide, 1, '2') 1798 1799 def test_divide_int(self): 1800 c = Context() 1801 d = c.divide_int(Decimal(1), Decimal(2)) 1802 self.assertEqual(c.divide_int(1, 2), d) 1803 self.assertEqual(c.divide_int(Decimal(1), 2), d) 1804 self.assertEqual(c.divide_int(1, Decimal(2)), d) 1805 self.assertRaises(TypeError, c.divide_int, '1', 2) 1806 self.assertRaises(TypeError, c.divide_int, 1, '2') 1807 1808 def test_divmod(self): 1809 c = Context() 1810 d = c.divmod(Decimal(1), Decimal(2)) 1811 self.assertEqual(c.divmod(1, 2), d) 1812 self.assertEqual(c.divmod(Decimal(1), 2), d) 1813 self.assertEqual(c.divmod(1, Decimal(2)), d) 1814 self.assertRaises(TypeError, c.divmod, '1', 2) 1815 self.assertRaises(TypeError, c.divmod, 1, '2') 1816 1817 def test_exp(self): 1818 c = Context() 1819 d = c.exp(Decimal(10)) 1820 self.assertEqual(c.exp(10), d) 1821 self.assertRaises(TypeError, c.exp, '10') 1822 1823 def test_fma(self): 1824 c = Context() 1825 d = c.fma(Decimal(2), Decimal(3), Decimal(4)) 1826 self.assertEqual(c.fma(2, 3, 4), d) 1827 self.assertEqual(c.fma(Decimal(2), 3, 4), d) 1828 self.assertEqual(c.fma(2, Decimal(3), 4), d) 1829 self.assertEqual(c.fma(2, 3, Decimal(4)), d) 1830 self.assertEqual(c.fma(Decimal(2), Decimal(3), 4), d) 1831 self.assertRaises(TypeError, c.fma, '2', 3, 4) 1832 self.assertRaises(TypeError, c.fma, 2, '3', 4) 1833 self.assertRaises(TypeError, c.fma, 2, 3, '4') 1834 1835 def test_is_finite(self): 1836 c = Context() 1837 d = c.is_finite(Decimal(10)) 1838 self.assertEqual(c.is_finite(10), d) 1839 self.assertRaises(TypeError, c.is_finite, '10') 1840 1841 def test_is_infinite(self): 1842 c = Context() 1843 d = c.is_infinite(Decimal(10)) 1844 self.assertEqual(c.is_infinite(10), d) 1845 self.assertRaises(TypeError, c.is_infinite, '10') 1846 1847 def test_is_nan(self): 1848 c = Context() 1849 d = c.is_nan(Decimal(10)) 1850 self.assertEqual(c.is_nan(10), d) 1851 self.assertRaises(TypeError, c.is_nan, '10') 1852 1853 def test_is_normal(self): 1854 c = Context() 1855 d = c.is_normal(Decimal(10)) 1856 self.assertEqual(c.is_normal(10), d) 1857 self.assertRaises(TypeError, c.is_normal, '10') 1858 1859 def test_is_qnan(self): 1860 c = Context() 1861 d = c.is_qnan(Decimal(10)) 1862 self.assertEqual(c.is_qnan(10), d) 1863 self.assertRaises(TypeError, c.is_qnan, '10') 1864 1865 def test_is_signed(self): 1866 c = Context() 1867 d = c.is_signed(Decimal(10)) 1868 self.assertEqual(c.is_signed(10), d) 1869 self.assertRaises(TypeError, c.is_signed, '10') 1870 1871 def test_is_snan(self): 1872 c = Context() 1873 d = c.is_snan(Decimal(10)) 1874 self.assertEqual(c.is_snan(10), d) 1875 self.assertRaises(TypeError, c.is_snan, '10') 1876 1877 def test_is_subnormal(self): 1878 c = Context() 1879 d = c.is_subnormal(Decimal(10)) 1880 self.assertEqual(c.is_subnormal(10), d) 1881 self.assertRaises(TypeError, c.is_subnormal, '10') 1882 1883 def test_is_zero(self): 1884 c = Context() 1885 d = c.is_zero(Decimal(10)) 1886 self.assertEqual(c.is_zero(10), d) 1887 self.assertRaises(TypeError, c.is_zero, '10') 1888 1889 def test_ln(self): 1890 c = Context() 1891 d = c.ln(Decimal(10)) 1892 self.assertEqual(c.ln(10), d) 1893 self.assertRaises(TypeError, c.ln, '10') 1894 1895 def test_log10(self): 1896 c = Context() 1897 d = c.log10(Decimal(10)) 1898 self.assertEqual(c.log10(10), d) 1899 self.assertRaises(TypeError, c.log10, '10') 1900 1901 def test_logb(self): 1902 c = Context() 1903 d = c.logb(Decimal(10)) 1904 self.assertEqual(c.logb(10), d) 1905 self.assertRaises(TypeError, c.logb, '10') 1906 1907 def test_logical_and(self): 1908 c = Context() 1909 d = c.logical_and(Decimal(1), Decimal(1)) 1910 self.assertEqual(c.logical_and(1, 1), d) 1911 self.assertEqual(c.logical_and(Decimal(1), 1), d) 1912 self.assertEqual(c.logical_and(1, Decimal(1)), d) 1913 self.assertRaises(TypeError, c.logical_and, '1', 1) 1914 self.assertRaises(TypeError, c.logical_and, 1, '1') 1915 1916 def test_logical_invert(self): 1917 c = Context() 1918 d = c.logical_invert(Decimal(1000)) 1919 self.assertEqual(c.logical_invert(1000), d) 1920 self.assertRaises(TypeError, c.logical_invert, '1000') 1921 1922 def test_logical_or(self): 1923 c = Context() 1924 d = c.logical_or(Decimal(1), Decimal(1)) 1925 self.assertEqual(c.logical_or(1, 1), d) 1926 self.assertEqual(c.logical_or(Decimal(1), 1), d) 1927 self.assertEqual(c.logical_or(1, Decimal(1)), d) 1928 self.assertRaises(TypeError, c.logical_or, '1', 1) 1929 self.assertRaises(TypeError, c.logical_or, 1, '1') 1930 1931 def test_logical_xor(self): 1932 c = Context() 1933 d = c.logical_xor(Decimal(1), Decimal(1)) 1934 self.assertEqual(c.logical_xor(1, 1), d) 1935 self.assertEqual(c.logical_xor(Decimal(1), 1), d) 1936 self.assertEqual(c.logical_xor(1, Decimal(1)), d) 1937 self.assertRaises(TypeError, c.logical_xor, '1', 1) 1938 self.assertRaises(TypeError, c.logical_xor, 1, '1') 1939 1940 def test_max(self): 1941 c = Context() 1942 d = c.max(Decimal(1), Decimal(2)) 1943 self.assertEqual(c.max(1, 2), d) 1944 self.assertEqual(c.max(Decimal(1), 2), d) 1945 self.assertEqual(c.max(1, Decimal(2)), d) 1946 self.assertRaises(TypeError, c.max, '1', 2) 1947 self.assertRaises(TypeError, c.max, 1, '2') 1948 1949 def test_max_mag(self): 1950 c = Context() 1951 d = c.max_mag(Decimal(1), Decimal(2)) 1952 self.assertEqual(c.max_mag(1, 2), d) 1953 self.assertEqual(c.max_mag(Decimal(1), 2), d) 1954 self.assertEqual(c.max_mag(1, Decimal(2)), d) 1955 self.assertRaises(TypeError, c.max_mag, '1', 2) 1956 self.assertRaises(TypeError, c.max_mag, 1, '2') 1957 1958 def test_min(self): 1959 c = Context() 1960 d = c.min(Decimal(1), Decimal(2)) 1961 self.assertEqual(c.min(1, 2), d) 1962 self.assertEqual(c.min(Decimal(1), 2), d) 1963 self.assertEqual(c.min(1, Decimal(2)), d) 1964 self.assertRaises(TypeError, c.min, '1', 2) 1965 self.assertRaises(TypeError, c.min, 1, '2') 1966 1967 def test_min_mag(self): 1968 c = Context() 1969 d = c.min_mag(Decimal(1), Decimal(2)) 1970 self.assertEqual(c.min_mag(1, 2), d) 1971 self.assertEqual(c.min_mag(Decimal(1), 2), d) 1972 self.assertEqual(c.min_mag(1, Decimal(2)), d) 1973 self.assertRaises(TypeError, c.min_mag, '1', 2) 1974 self.assertRaises(TypeError, c.min_mag, 1, '2') 1975 1976 def test_minus(self): 1977 c = Context() 1978 d = c.minus(Decimal(10)) 1979 self.assertEqual(c.minus(10), d) 1980 self.assertRaises(TypeError, c.minus, '10') 1981 1982 def test_multiply(self): 1983 c = Context() 1984 d = c.multiply(Decimal(1), Decimal(2)) 1985 self.assertEqual(c.multiply(1, 2), d) 1986 self.assertEqual(c.multiply(Decimal(1), 2), d) 1987 self.assertEqual(c.multiply(1, Decimal(2)), d) 1988 self.assertRaises(TypeError, c.multiply, '1', 2) 1989 self.assertRaises(TypeError, c.multiply, 1, '2') 1990 1991 def test_next_minus(self): 1992 c = Context() 1993 d = c.next_minus(Decimal(10)) 1994 self.assertEqual(c.next_minus(10), d) 1995 self.assertRaises(TypeError, c.next_minus, '10') 1996 1997 def test_next_plus(self): 1998 c = Context() 1999 d = c.next_plus(Decimal(10)) 2000 self.assertEqual(c.next_plus(10), d) 2001 self.assertRaises(TypeError, c.next_plus, '10') 2002 2003 def test_next_toward(self): 2004 c = Context() 2005 d = c.next_toward(Decimal(1), Decimal(2)) 2006 self.assertEqual(c.next_toward(1, 2), d) 2007 self.assertEqual(c.next_toward(Decimal(1), 2), d) 2008 self.assertEqual(c.next_toward(1, Decimal(2)), d) 2009 self.assertRaises(TypeError, c.next_toward, '1', 2) 2010 self.assertRaises(TypeError, c.next_toward, 1, '2') 2011 2012 def test_normalize(self): 2013 c = Context() 2014 d = c.normalize(Decimal(10)) 2015 self.assertEqual(c.normalize(10), d) 2016 self.assertRaises(TypeError, c.normalize, '10') 2017 2018 def test_number_class(self): 2019 c = Context() 2020 self.assertEqual(c.number_class(123), c.number_class(Decimal(123))) 2021 self.assertEqual(c.number_class(0), c.number_class(Decimal(0))) 2022 self.assertEqual(c.number_class(-45), c.number_class(Decimal(-45))) 2023 2024 def test_powmod(self): 2025 c = Context() 2026 d = c.powmod(Decimal(1), Decimal(4), Decimal(2)) 2027 self.assertEqual(c.powmod(1, 4, 2), d) 2028 self.assertEqual(c.powmod(Decimal(1), 4, 2), d) 2029 self.assertEqual(c.powmod(1, Decimal(4), 2), d) 2030 self.assertEqual(c.powmod(1, 4, Decimal(2)), d) 2031 self.assertEqual(c.powmod(Decimal(1), Decimal(4), 2), d) 2032 self.assertRaises(TypeError, c.powmod, '1', 4, 2) 2033 self.assertRaises(TypeError, c.powmod, 1, '4', 2) 2034 self.assertRaises(TypeError, c.powmod, 1, 4, '2') 2035 2036 def test_plus(self): 2037 c = Context() 2038 d = c.plus(Decimal(10)) 2039 self.assertEqual(c.plus(10), d) 2040 self.assertRaises(TypeError, c.plus, '10') 2041 2042 def test_quantize(self): 2043 c = Context() 2044 d = c.quantize(Decimal(1), Decimal(2)) 2045 self.assertEqual(c.quantize(1, 2), d) 2046 self.assertEqual(c.quantize(Decimal(1), 2), d) 2047 self.assertEqual(c.quantize(1, Decimal(2)), d) 2048 self.assertRaises(TypeError, c.quantize, '1', 2) 2049 self.assertRaises(TypeError, c.quantize, 1, '2') 2050 2051 def test_remainder(self): 2052 c = Context() 2053 d = c.remainder(Decimal(1), Decimal(2)) 2054 self.assertEqual(c.remainder(1, 2), d) 2055 self.assertEqual(c.remainder(Decimal(1), 2), d) 2056 self.assertEqual(c.remainder(1, Decimal(2)), d) 2057 self.assertRaises(TypeError, c.remainder, '1', 2) 2058 self.assertRaises(TypeError, c.remainder, 1, '2') 2059 2060 def test_remainder_near(self): 2061 c = Context() 2062 d = c.remainder_near(Decimal(1), Decimal(2)) 2063 self.assertEqual(c.remainder_near(1, 2), d) 2064 self.assertEqual(c.remainder_near(Decimal(1), 2), d) 2065 self.assertEqual(c.remainder_near(1, Decimal(2)), d) 2066 self.assertRaises(TypeError, c.remainder_near, '1', 2) 2067 self.assertRaises(TypeError, c.remainder_near, 1, '2') 2068 2069 def test_rotate(self): 2070 c = Context() 2071 d = c.rotate(Decimal(1), Decimal(2)) 2072 self.assertEqual(c.rotate(1, 2), d) 2073 self.assertEqual(c.rotate(Decimal(1), 2), d) 2074 self.assertEqual(c.rotate(1, Decimal(2)), d) 2075 self.assertRaises(TypeError, c.rotate, '1', 2) 2076 self.assertRaises(TypeError, c.rotate, 1, '2') 2077 2078 def test_sqrt(self): 2079 c = Context() 2080 d = c.sqrt(Decimal(10)) 2081 self.assertEqual(c.sqrt(10), d) 2082 self.assertRaises(TypeError, c.sqrt, '10') 2083 2084 def test_same_quantum(self): 2085 c = Context() 2086 d = c.same_quantum(Decimal(1), Decimal(2)) 2087 self.assertEqual(c.same_quantum(1, 2), d) 2088 self.assertEqual(c.same_quantum(Decimal(1), 2), d) 2089 self.assertEqual(c.same_quantum(1, Decimal(2)), d) 2090 self.assertRaises(TypeError, c.same_quantum, '1', 2) 2091 self.assertRaises(TypeError, c.same_quantum, 1, '2') 2092 2093 def test_scaleb(self): 2094 c = Context() 2095 d = c.scaleb(Decimal(1), Decimal(2)) 2096 self.assertEqual(c.scaleb(1, 2), d) 2097 self.assertEqual(c.scaleb(Decimal(1), 2), d) 2098 self.assertEqual(c.scaleb(1, Decimal(2)), d) 2099 self.assertRaises(TypeError, c.scaleb, '1', 2) 2100 self.assertRaises(TypeError, c.scaleb, 1, '2') 2101 2102 def test_shift(self): 2103 c = Context() 2104 d = c.shift(Decimal(1), Decimal(2)) 2105 self.assertEqual(c.shift(1, 2), d) 2106 self.assertEqual(c.shift(Decimal(1), 2), d) 2107 self.assertEqual(c.shift(1, Decimal(2)), d) 2108 self.assertRaises(TypeError, c.shift, '1', 2) 2109 self.assertRaises(TypeError, c.shift, 1, '2') 2110 2111 def test_subtract(self): 2112 c = Context() 2113 d = c.subtract(Decimal(1), Decimal(2)) 2114 self.assertEqual(c.subtract(1, 2), d) 2115 self.assertEqual(c.subtract(Decimal(1), 2), d) 2116 self.assertEqual(c.subtract(1, Decimal(2)), d) 2117 self.assertRaises(TypeError, c.subtract, '1', 2) 2118 self.assertRaises(TypeError, c.subtract, 1, '2') 2119 2120 def test_to_eng_string(self): 2121 c = Context() 2122 d = c.to_eng_string(Decimal(10)) 2123 self.assertEqual(c.to_eng_string(10), d) 2124 self.assertRaises(TypeError, c.to_eng_string, '10') 2125 2126 def test_to_sci_string(self): 2127 c = Context() 2128 d = c.to_sci_string(Decimal(10)) 2129 self.assertEqual(c.to_sci_string(10), d) 2130 self.assertRaises(TypeError, c.to_sci_string, '10') 2131 2132 def test_to_integral_exact(self): 2133 c = Context() 2134 d = c.to_integral_exact(Decimal(10)) 2135 self.assertEqual(c.to_integral_exact(10), d) 2136 self.assertRaises(TypeError, c.to_integral_exact, '10') 2137 2138 def test_to_integral_value(self): 2139 c = Context() 2140 d = c.to_integral_value(Decimal(10)) 2141 self.assertEqual(c.to_integral_value(10), d) 2142 self.assertRaises(TypeError, c.to_integral_value, '10') 2143 2144class WithStatementTest(unittest.TestCase): 2145 # Can't do these as docstrings until Python 2.6 2146 # as doctest can't handle __future__ statements 2147 2148 def test_localcontext(self): 2149 # Use a copy of the current context in the block 2150 orig_ctx = getcontext() 2151 with localcontext() as enter_ctx: 2152 set_ctx = getcontext() 2153 final_ctx = getcontext() 2154 self.assertTrue(orig_ctx is final_ctx, 'did not restore context correctly') 2155 self.assertTrue(orig_ctx is not set_ctx, 'did not copy the context') 2156 self.assertTrue(set_ctx is enter_ctx, '__enter__ returned wrong context') 2157 2158 def test_localcontextarg(self): 2159 # Use a copy of the supplied context in the block 2160 orig_ctx = getcontext() 2161 new_ctx = Context(prec=42) 2162 with localcontext(new_ctx) as enter_ctx: 2163 set_ctx = getcontext() 2164 final_ctx = getcontext() 2165 self.assertTrue(orig_ctx is final_ctx, 'did not restore context correctly') 2166 self.assertTrue(set_ctx.prec == new_ctx.prec, 'did not set correct context') 2167 self.assertTrue(new_ctx is not set_ctx, 'did not copy the context') 2168 self.assertTrue(set_ctx is enter_ctx, '__enter__ returned wrong context') 2169 2170 def test_nested_with_statements(self): 2171 # Use a copy of the supplied context in the block 2172 orig_ctx = getcontext() 2173 orig_ctx.clear_flags() 2174 new_ctx = Context(Emax=384) 2175 with localcontext() as c1: 2176 self.assertEqual(c1.flags, orig_ctx.flags) 2177 self.assertEqual(c1.traps, orig_ctx.traps) 2178 c1.traps[Clamped] = True 2179 c1.Emin = -383 2180 self.assertRaises(Clamped, c1.create_decimal, '0e-999') 2181 self.assertTrue(c1.flags[Clamped]) 2182 with localcontext(new_ctx) as c2: 2183 self.assertEqual(c2.flags, new_ctx.flags) 2184 self.assertEqual(c2.traps, new_ctx.traps) 2185 self.assertRaises(Overflow, c2.power, Decimal('3.4e200'), 2) 2186 self.assertFalse(c2.flags[Clamped]) 2187 self.assertTrue(c2.flags[Overflow]) 2188 del c2 2189 self.assertFalse(c1.flags[Overflow]) 2190 del c1 2191 self.assertNotEqual(orig_ctx.Emin, -383) 2192 self.assertFalse(orig_ctx.flags[Clamped]) 2193 self.assertFalse(orig_ctx.flags[Overflow]) 2194 self.assertFalse(new_ctx.flags[Clamped]) 2195 self.assertFalse(new_ctx.flags[Overflow]) 2196 2197 def test_with_statements_gc1(self): 2198 with localcontext() as c1: 2199 del c1 2200 with localcontext() as c2: 2201 del c2 2202 with localcontext() as c3: 2203 del c3 2204 with localcontext() as c4: 2205 del c4 2206 2207 def test_with_statements_gc2(self): 2208 with localcontext() as c1: 2209 with localcontext(c1) as c2: 2210 del c1 2211 with localcontext(c2) as c3: 2212 del c2 2213 with localcontext(c3) as c4: 2214 del c3 2215 del c4 2216 2217 def test_with_statements_gc3(self): 2218 with localcontext() as c1: 2219 del c1 2220 n1 = Context(prec=1) 2221 setcontext(n1) 2222 with localcontext(n1) as c2: 2223 del n1 2224 self.assertEqual(c2.prec, 1) 2225 del c2 2226 n2 = Context(prec=2) 2227 setcontext(n2) 2228 del n2 2229 self.assertEqual(getcontext().prec, 2) 2230 n3 = Context(prec=3) 2231 setcontext(n3) 2232 self.assertEqual(getcontext().prec, 3) 2233 with localcontext(n3) as c3: 2234 del n3 2235 self.assertEqual(c3.prec, 3) 2236 del c3 2237 n4 = Context(prec=4) 2238 setcontext(n4) 2239 del n4 2240 self.assertEqual(getcontext().prec, 4) 2241 with localcontext() as c4: 2242 self.assertEqual(c4.prec, 4) 2243 del c4 2244 2245class ContextFlags(unittest.TestCase): 2246 def test_flags_irrelevant(self): 2247 # check that the result (numeric result + flags raised) of an 2248 # arithmetic operation doesn't depend on the current flags 2249 2250 # XXX 32-bit limits 2251 context = Context(prec=9, Emin=-425000000, Emax=425000000, 2252 rounding=ROUND_HALF_EVEN, traps=[], flags=[]) 2253 2254 # operations that raise various flags, in the form (function, arglist) 2255 operations = [ 2256 (context._apply, [Decimal("100E-425000010")]), 2257 (context.sqrt, [Decimal(2)]), 2258 (context.add, [Decimal("1.23456789"), Decimal("9.87654321")]), 2259 (context.multiply, [Decimal("1.23456789"), Decimal("9.87654321")]), 2260 (context.subtract, [Decimal("1.23456789"), Decimal("9.87654321")]), 2261 ] 2262 2263 # try various flags individually, then a whole lot at once 2264 flagsets = [[Inexact], [Rounded], [Underflow], [Clamped], [Subnormal], 2265 [Inexact, Rounded, Underflow, Clamped, Subnormal]] 2266 2267 for fn, args in operations: 2268 # find answer and flags raised using a clean context 2269 context.clear_flags() 2270 ans = fn(*args) 2271 flags = [k for k, v in context.flags.items() if v] 2272 2273 for extra_flags in flagsets: 2274 # set flags, before calling operation 2275 context.clear_flags() 2276 for flag in extra_flags: 2277 # XXX _raise_error 2278 # context._raise_error(flag) 2279 context.flags[flag] = True 2280 new_ans = fn(*args) 2281 2282 # flags that we expect to be set after the operation 2283 expected_flags = list(flags) 2284 for flag in extra_flags: 2285 if flag not in expected_flags: 2286 expected_flags.append(flag) 2287 expected_flags.sort() 2288 2289 # flags we actually got 2290 new_flags = [k for k,v in context.flags.items() if v] 2291 new_flags.sort() 2292 2293 self.assertEqual(ans, new_ans, 2294 "operation produces different answers depending on flags set: " + 2295 "expected %s, got %s." % (ans, new_ans)) 2296 self.assertEqual(new_flags, expected_flags, 2297 "operation raises different flags depending on flags set: " + 2298 "expected %s, got %s" % (expected_flags, new_flags)) 2299 2300class SpecialContexts(unittest.TestCase): 2301 def test_context_templates(self): 2302 self.assertEqual( 2303 BasicContext._traps, 2304 DecIEEEInvalidOperation|DecDivisionByZero|DecOverflow| 2305 DecUnderflow|DecClamped 2306 ) 2307 2308 basic_context_prec = BasicContext.prec 2309 extended_context_prec = ExtendedContext.prec 2310 2311 BasicContext.prec = ExtendedContext.prec = 441 2312 2313 for template in BasicContext, ExtendedContext: 2314 setcontext(template) 2315 c = getcontext() 2316 self.assertFalse(c is template) 2317 self.assertEqual(c.prec, 441) 2318 2319 BasicContext.prec = basic_context_prec 2320 ExtendedContext.prec = extended_context_prec 2321 2322 def test_default_context(self): 2323 self.assertEqual( 2324 DefaultContext._traps, 2325 DecIEEEInvalidOperation|DecDivisionByZero|DecOverflow 2326 ) 2327 2328 default_context_prec = DefaultContext.prec 2329 2330 c = getcontext() 2331 saveprec = c.prec 2332 2333 DefaultContext.prec = 961 2334 c = getcontext() 2335 self.assertEqual(c.prec, saveprec) 2336 2337 setcontext(DefaultContext) 2338 c = getcontext() 2339 self.assertFalse(c is DefaultContext) 2340 self.assertEqual(c.prec, 961) 2341 2342 DefaultContext.prec = default_context_prec 2343 2344 def test_ieee_context(self): 2345 def assert_rest(self, context): 2346 self.assertEqual(context.clamp, 1) 2347 for v in context.traps.values(): 2348 self.assertFalse(v) 2349 for v in context.flags.values(): 2350 self.assertFalse(v) 2351 2352 c = IEEEContext(DECIMAL32) 2353 self.assertEqual(c.prec, 7) 2354 self.assertEqual(c.Emax, 96) 2355 self.assertEqual(c.Emin, -95) 2356 assert_rest(self, c) 2357 2358 c = IEEEContext(DECIMAL64) 2359 self.assertEqual(c.prec, 16) 2360 self.assertEqual(c.Emax, 384) 2361 self.assertEqual(c.Emin, -383) 2362 assert_rest(self, c) 2363 2364 c = IEEEContext(DECIMAL128) 2365 self.assertEqual(c.prec, 34) 2366 self.assertEqual(c.Emax, 6144) 2367 self.assertEqual(c.Emin, -6143) 2368 assert_rest(self, c) 2369 2370class Coverage(unittest.TestCase): 2371 2372 def test_bignum(self): 2373 b1 = 10**35 2374 b2 = 10**36 2375 with localcontext() as c: 2376 c.prec = 1000000 2377 for i in range(5): 2378 a = random.randrange(b1, b2) 2379 b = random.randrange(1000, 1200) 2380 x = a ** b 2381 y = Decimal(a) ** Decimal(b) 2382 self.assertEqual(x, y) 2383 2384def test_main(arith=False, verbose=None, todo_tests=None, debug=None): 2385 """ Execute the tests. 2386 2387 Runs all arithmetic tests if arith is True or if the "decimal" resource 2388 is enabled in regrtest.py 2389 """ 2390 2391 init() 2392 global TEST_ALL, DEBUG 2393 TEST_ALL = arith or is_resource_enabled('decimal') 2394 DEBUG = debug 2395 2396 if todo_tests is None: 2397 test_classes = [ 2398 DecimalExplicitConstructionTest, 2399 DecimalImplicitConstructionTest, 2400 DecimalArithmeticOperatorsTest, 2401 DecimalUseOfContextTest, 2402 DecimalUsabilityTest, 2403 DecimalPythonAPItests, 2404 ContextAPItests, 2405 DecimalTest, 2406 WithStatementTest, 2407 ContextFlags, 2408 SpecialContexts, 2409 Coverage 2410 ] 2411 else: 2412 test_classes = [DecimalTest] 2413 2414 # Dynamically build custom test definition for each file in the test 2415 # directory and add the definitions to the DecimalTest class. This 2416 # procedure insures that new files do not get skipped. 2417 for filename in os.listdir(directory): 2418 if '.decTest' not in filename or filename.startswith("."): 2419 continue 2420 head, tail = filename.split('.') 2421 if todo_tests is not None and head not in todo_tests: 2422 continue 2423 tester = lambda self, f=filename: self.eval_file(directory + f) 2424 setattr(DecimalTest, 'test_' + head, tester) 2425 del filename, head, tail, tester 2426 2427 2428 try: 2429 run_unittest(*test_classes) 2430 if todo_tests is None: 2431 import cdecimal as DecimalModule 2432 finally: 2433 setcontext(ORIGINAL_CONTEXT) 2434 2435if __name__ == '__main__': 2436 import optparse 2437 p = optparse.OptionParser("test_decimal.py [--debug] [{--skip | test1 [test2 [...]]}]") 2438 p.add_option('--debug', '-d', action='store_true', help='shows the test number and context before each test') 2439 p.add_option('--skip', '-s', action='store_true', help='skip over 90% of the arithmetic tests') 2440 (opt, args) = p.parse_args() 2441 2442 if opt.skip: 2443 test_main(arith=False, verbose=True) 2444 elif args: 2445 test_main(arith=True, verbose=True, todo_tests=args, debug=opt.debug) 2446 else: 2447 test_main(arith=True, verbose=True) 2448