diff options
Diffstat (limited to 'Lib/test/test_long.py')
| -rw-r--r-- | Lib/test/test_long.py | 765 |
1 files changed, 420 insertions, 345 deletions
diff --git a/Lib/test/test_long.py b/Lib/test/test_long.py index 9c2bac7..04066ec 100644 --- a/Lib/test/test_long.py +++ b/Lib/test/test_long.py @@ -1,9 +1,11 @@ import unittest from test import support + import sys import random import math +import array # Used for lazy formatting of failure messages class Frm(object): @@ -35,25 +37,41 @@ del p2 # add complements & negations special += [~x for x in special] + [-x for x in special] -L = [ - ('0', 0), - ('1', 1), - ('9', 9), - ('10', 10), - ('99', 99), - ('100', 100), - ('314', 314), - (' 314', 314), - ('314 ', 314), - (' \t\t 314 \t\t ', 314), - (repr(sys.maxsize), sys.maxsize), - (' 1x', ValueError), - (' 1 ', 1), - (' 1\02 ', ValueError), - ('', ValueError), - (' ', ValueError), - (' \t\t ', ValueError) -] +DBL_MAX = sys.float_info.max +DBL_MAX_EXP = sys.float_info.max_exp +DBL_MIN_EXP = sys.float_info.min_exp +DBL_MANT_DIG = sys.float_info.mant_dig +DBL_MIN_OVERFLOW = 2**DBL_MAX_EXP - 2**(DBL_MAX_EXP - DBL_MANT_DIG - 1) + +# pure Python version of correctly-rounded true division +def truediv(a, b): + """Correctly-rounded true division for integers.""" + negative = a^b < 0 + a, b = abs(a), abs(b) + + # exceptions: division by zero, overflow + if not b: + raise ZeroDivisionError("division by zero") + if a >= DBL_MIN_OVERFLOW * b: + raise OverflowError("int/int too large to represent as a float") + + # find integer d satisfying 2**(d - 1) <= a/b < 2**d + d = a.bit_length() - b.bit_length() + if d >= 0 and a >= 2**d * b or d < 0 and a * 2**-d >= b: + d += 1 + + # compute 2**-exp * a / b for suitable exp + exp = max(d, DBL_MIN_EXP) - DBL_MANT_DIG + a, b = a << max(-exp, 0), b << max(exp, 0) + q, r = divmod(a, b) + + # round-half-to-even: fractional part is r/b, which is > 0.5 iff + # 2*r > b, and == 0.5 iff 2*r == b. + if 2*r > b or 2*r == b and q % 2 == 1: + q += 1 + + result = math.ldexp(q, exp) + return -result if negative else result class LongTest(unittest.TestCase): @@ -254,7 +272,7 @@ class LongTest(unittest.TestCase): digits = digits or [0] return '-'[:sign] + \ {2: '0b', 8: '0o', 10: '', 16: '0x'}[base] + \ - "".join(map(lambda i: "0123456789abcdef"[i], digits)) + "".join("0123456789abcdef"[i] for i in digits) def check_format_1(self, x): for base, mapper in (8, oct), (10, repr), (16, hex): @@ -263,7 +281,7 @@ class LongTest(unittest.TestCase): msg = Frm("%s returned %r but expected %r for %r", mapper.__name__, got, expected, x) self.assertEqual(got, expected, msg) - self.assertEqual(int(got, 0), x, Frm('long("%s", 0) != %r', got, x)) + self.assertEqual(int(got, 0), x, Frm('int("%s", 0) != %r', got, x)) # str() has to be checked a little differently since there's no # trailing "L" got = str(x) @@ -281,25 +299,12 @@ class LongTest(unittest.TestCase): self.check_format_1(x) def test_long(self): - self.assertEqual(int(314), 314) - self.assertEqual(int(3.14), 3) - self.assertEqual(int(314), 314) - # Check that conversion from float truncates towards zero - self.assertEqual(int(-3.14), -3) - self.assertEqual(int(3.9), 3) - self.assertEqual(int(-3.9), -3) - self.assertEqual(int(3.5), 3) - self.assertEqual(int(-3.5), -3) - self.assertEqual(int("-3"), -3) - # Different base: - self.assertEqual(int("10",16), 16) - # Check conversions from string (same test set as for int(), and then some) + # Check conversions from string LL = [ ('1' + '0'*20, 10**20), ('1' + '0'*100, 10**100) ] - L2 = L[:] - for s, v in L2 + LL: + for s, v in LL: for sign in "", "+", "-": for prefix in "", " ", "\t", " \t\t ": ss = prefix + sign + s @@ -307,12 +312,10 @@ class LongTest(unittest.TestCase): if sign == "-" and v is not ValueError: vv = -v try: - self.assertEqual(int(ss), int(vv)) + self.assertEqual(int(ss), vv) except ValueError: pass - self.assertRaises(ValueError, int, '123\0') - self.assertRaises(ValueError, int, '53', 40) # trailing L should no longer be accepted... self.assertRaises(ValueError, int, '123L') self.assertRaises(ValueError, int, '123l') @@ -323,87 +326,6 @@ class LongTest(unittest.TestCase): # ... but it's just a normal digit if base >= 22 self.assertEqual(int('1L', 22), 43) - self.assertRaises(TypeError, int, 1, 12) - - # SF patch #1638879: embedded NULs were not detected with - # explicit base - self.assertRaises(ValueError, int, '123\0', 10) - self.assertRaises(ValueError, int, '123\x00 245', 20) - - self.assertEqual(int('100000000000000000000000000000000', 2), - 4294967296) - self.assertEqual(int('102002022201221111211', 3), 4294967296) - self.assertEqual(int('10000000000000000', 4), 4294967296) - self.assertEqual(int('32244002423141', 5), 4294967296) - self.assertEqual(int('1550104015504', 6), 4294967296) - self.assertEqual(int('211301422354', 7), 4294967296) - self.assertEqual(int('40000000000', 8), 4294967296) - self.assertEqual(int('12068657454', 9), 4294967296) - self.assertEqual(int('4294967296', 10), 4294967296) - self.assertEqual(int('1904440554', 11), 4294967296) - self.assertEqual(int('9ba461594', 12), 4294967296) - self.assertEqual(int('535a79889', 13), 4294967296) - self.assertEqual(int('2ca5b7464', 14), 4294967296) - self.assertEqual(int('1a20dcd81', 15), 4294967296) - self.assertEqual(int('100000000', 16), 4294967296) - self.assertEqual(int('a7ffda91', 17), 4294967296) - self.assertEqual(int('704he7g4', 18), 4294967296) - self.assertEqual(int('4f5aff66', 19), 4294967296) - self.assertEqual(int('3723ai4g', 20), 4294967296) - self.assertEqual(int('281d55i4', 21), 4294967296) - self.assertEqual(int('1fj8b184', 22), 4294967296) - self.assertEqual(int('1606k7ic', 23), 4294967296) - self.assertEqual(int('mb994ag', 24), 4294967296) - self.assertEqual(int('hek2mgl', 25), 4294967296) - self.assertEqual(int('dnchbnm', 26), 4294967296) - self.assertEqual(int('b28jpdm', 27), 4294967296) - self.assertEqual(int('8pfgih4', 28), 4294967296) - self.assertEqual(int('76beigg', 29), 4294967296) - self.assertEqual(int('5qmcpqg', 30), 4294967296) - self.assertEqual(int('4q0jto4', 31), 4294967296) - self.assertEqual(int('4000000', 32), 4294967296) - self.assertEqual(int('3aokq94', 33), 4294967296) - self.assertEqual(int('2qhxjli', 34), 4294967296) - self.assertEqual(int('2br45qb', 35), 4294967296) - self.assertEqual(int('1z141z4', 36), 4294967296) - - self.assertEqual(int('100000000000000000000000000000001', 2), - 4294967297) - self.assertEqual(int('102002022201221111212', 3), 4294967297) - self.assertEqual(int('10000000000000001', 4), 4294967297) - self.assertEqual(int('32244002423142', 5), 4294967297) - self.assertEqual(int('1550104015505', 6), 4294967297) - self.assertEqual(int('211301422355', 7), 4294967297) - self.assertEqual(int('40000000001', 8), 4294967297) - self.assertEqual(int('12068657455', 9), 4294967297) - self.assertEqual(int('4294967297', 10), 4294967297) - self.assertEqual(int('1904440555', 11), 4294967297) - self.assertEqual(int('9ba461595', 12), 4294967297) - self.assertEqual(int('535a7988a', 13), 4294967297) - self.assertEqual(int('2ca5b7465', 14), 4294967297) - self.assertEqual(int('1a20dcd82', 15), 4294967297) - self.assertEqual(int('100000001', 16), 4294967297) - self.assertEqual(int('a7ffda92', 17), 4294967297) - self.assertEqual(int('704he7g5', 18), 4294967297) - self.assertEqual(int('4f5aff67', 19), 4294967297) - self.assertEqual(int('3723ai4h', 20), 4294967297) - self.assertEqual(int('281d55i5', 21), 4294967297) - self.assertEqual(int('1fj8b185', 22), 4294967297) - self.assertEqual(int('1606k7id', 23), 4294967297) - self.assertEqual(int('mb994ah', 24), 4294967297) - self.assertEqual(int('hek2mgm', 25), 4294967297) - self.assertEqual(int('dnchbnn', 26), 4294967297) - self.assertEqual(int('b28jpdn', 27), 4294967297) - self.assertEqual(int('8pfgih5', 28), 4294967297) - self.assertEqual(int('76beigh', 29), 4294967297) - self.assertEqual(int('5qmcpqh', 30), 4294967297) - self.assertEqual(int('4q0jto5', 31), 4294967297) - self.assertEqual(int('4000001', 32), 4294967297) - self.assertEqual(int('3aokq95', 33), 4294967297) - self.assertEqual(int('2qhxjlj', 34), 4294967297) - self.assertEqual(int('2br45qc', 35), 4294967297) - self.assertEqual(int('1z141z5', 36), 4294967297) - # tests with base 0 self.assertEqual(int('000', 0), 0) self.assertEqual(int('0o123', 0), 83) @@ -419,228 +341,34 @@ class LongTest(unittest.TestCase): self.assertRaises(ValueError, int, '08', 0) self.assertRaises(ValueError, int, '-012395', 0) - def test_conversion(self): - # Test __int__() - class ClassicMissingMethods: - pass - self.assertRaises(TypeError, int, ClassicMissingMethods()) - - class MissingMethods(object): - pass - self.assertRaises(TypeError, int, MissingMethods()) + # invalid bases + invalid_bases = [-909, + 2**31-1, 2**31, -2**31, -2**31-1, + 2**63-1, 2**63, -2**63, -2**63-1, + 2**100, -2**100, + ] + for base in invalid_bases: + self.assertRaises(ValueError, int, '42', base) - class Foo0: - def __int__(self): - return 42 - class Foo1(object): - def __int__(self): - return 42 + def test_conversion(self): - class Foo2(int): - def __int__(self): + class JustLong: + # test that __long__ no longer used in 3.x + def __long__(self): return 42 + self.assertRaises(TypeError, int, JustLong()) - class Foo3(int): - def __int__(self): - return self - - class Foo4(int): - def __int__(self): + class LongTrunc: + # __long__ should be ignored in 3.x + def __long__(self): return 42 + def __trunc__(self): + return 1729 + self.assertEqual(int(LongTrunc()), 1729) - class Foo5(int): - def __int__(self): - return 42. - - self.assertEqual(int(Foo0()), 42) - self.assertEqual(int(Foo1()), 42) - self.assertEqual(int(Foo2()), 42) - self.assertEqual(int(Foo3()), 0) - self.assertEqual(int(Foo4()), 42) - self.assertRaises(TypeError, int, Foo5()) - - class Classic: - pass - for base in (object, Classic): - class IntOverridesTrunc(base): - def __int__(self): - return 42 - def __trunc__(self): - return -12 - self.assertEqual(int(IntOverridesTrunc()), 42) - - class JustTrunc(base): - def __trunc__(self): - return 42 - self.assertEqual(int(JustTrunc()), 42) - - class JustLong(base): - # test that __long__ no longer used in 3.x - def __long__(self): - return 42 - self.assertRaises(TypeError, int, JustLong()) - - class LongTrunc(base): - # __long__ should be ignored in 3.x - def __long__(self): - return 42 - def __trunc__(self): - return 1729 - self.assertEqual(int(LongTrunc()), 1729) - - for trunc_result_base in (object, Classic): - class Integral(trunc_result_base): - def __int__(self): - return 42 - - class TruncReturnsNonLong(base): - def __trunc__(self): - return Integral() - self.assertEqual(int(TruncReturnsNonLong()), 42) - - class NonIntegral(trunc_result_base): - def __trunc__(self): - # Check that we avoid infinite recursion. - return NonIntegral() - - class TruncReturnsNonIntegral(base): - def __trunc__(self): - return NonIntegral() - try: - int(TruncReturnsNonIntegral()) - except TypeError as e: - self.assertEqual(str(e), - "__trunc__ returned non-Integral" - " (type NonIntegral)") - else: - self.fail("Failed to raise TypeError with %s" % - ((base, trunc_result_base),)) - - def test_misc(self): - - # check the extremes in int<->long conversion - hugepos = sys.maxsize - hugeneg = -hugepos - 1 - hugepos_aslong = int(hugepos) - hugeneg_aslong = int(hugeneg) - self.assertEqual(hugepos, hugepos_aslong, "long(sys.maxsize) != sys.maxsize") - self.assertEqual(hugeneg, hugeneg_aslong, - "long(-sys.maxsize-1) != -sys.maxsize-1") - - # long -> int should not fail for hugepos_aslong or hugeneg_aslong - x = int(hugepos_aslong) - try: - self.assertEqual(x, hugepos, - "converting sys.maxsize to long and back to int fails") - except OverflowError: - self.fail("int(long(sys.maxsize)) overflowed!") - if not isinstance(x, int): - raise TestFailed("int(long(sys.maxsize)) should have returned int") - x = int(hugeneg_aslong) - try: - self.assertEqual(x, hugeneg, - "converting -sys.maxsize-1 to long and back to int fails") - except OverflowError: - self.fail("int(long(-sys.maxsize-1)) overflowed!") - if not isinstance(x, int): - raise TestFailed("int(long(-sys.maxsize-1)) should have " - "returned int") - # but long -> int should overflow for hugepos+1 and hugeneg-1 - x = hugepos_aslong + 1 - try: - y = int(x) - except OverflowError: - self.fail("int(long(sys.maxsize) + 1) mustn't overflow") - self.assertTrue(isinstance(y, int), - "int(long(sys.maxsize) + 1) should have returned long") - - x = hugeneg_aslong - 1 - try: - y = int(x) - except OverflowError: - self.fail("int(long(-sys.maxsize-1) - 1) mustn't overflow") - self.assertTrue(isinstance(y, int), - "int(long(-sys.maxsize-1) - 1) should have returned long") - - class long2(int): - pass - x = long2(1<<100) - y = int(x) - self.assertTrue(type(y) is int, - "overflowing int conversion must return long not long subtype") - -# ----------------------------------- tests of auto int->long conversion - - def test_auto_overflow(self): - import math, sys - - special = [0, 1, 2, 3, sys.maxsize-1, sys.maxsize, sys.maxsize+1] - sqrt = int(math.sqrt(sys.maxsize)) - special.extend([sqrt-1, sqrt, sqrt+1]) - special.extend([-i for i in special]) - - def checkit(*args): - # Heavy use of nested scopes here! - self.assertEqual(got, expected, - Frm("for %r expected %r got %r", args, expected, got)) - - for x in special: - longx = int(x) - - expected = -longx - got = -x - checkit('-', x) - - for y in special: - longy = int(y) - - expected = longx + longy - got = x + y - checkit(x, '+', y) - - expected = longx - longy - got = x - y - checkit(x, '-', y) - - expected = longx * longy - got = x * y - checkit(x, '*', y) - - if y: - expected = longx / longy - got = x / y - checkit(x, '/', y) - - expected = longx // longy - got = x // y - checkit(x, '//', y) - - expected = divmod(longx, longy) - got = divmod(longx, longy) - checkit(x, 'divmod', y) - - if abs(y) < 5 and not (x == 0 and y < 0): - expected = longx ** longy - got = x ** y - checkit(x, '**', y) - - for z in special: - if z != 0 : - if y >= 0: - expected = pow(longx, longy, int(z)) - got = pow(x, y, z) - checkit('pow', x, y, '%', z) - else: - self.assertRaises(TypeError, pow,longx, longy, int(z)) - - @unittest.skipUnless(float.__getformat__("double").startswith("IEEE"), - "test requires IEEE 754 doubles") + @support.requires_IEEE_754 def test_float_conversion(self): - import sys - DBL_MAX = sys.float_info.max - DBL_MAX_EXP = sys.float_info.max_exp - DBL_MANT_DIG = sys.float_info.mant_dig exact_values = [0, 1, 2, 2**53-3, @@ -694,8 +422,6 @@ class LongTest(unittest.TestCase): self.assertEqual(int(float(x)), y) def test_float_overflow(self): - import math - for x in -2.0, -1.0, 0.0, 1.0, 2.0: self.assertEqual(float(int(x)), x) @@ -721,14 +447,12 @@ class LongTest(unittest.TestCase): self.assertRaises(OverflowError, eval, test, namespace) - # XXX Perhaps float(shuge) can raise OverflowError on some box? - # The comparison should not. - self.assertNotEqual(float(shuge), int(shuge), - "float(shuge) should not equal int(shuge)") + # XXX Perhaps float(shuge) can raise OverflowError on some box? + # The comparison should not. + self.assertNotEqual(float(shuge), int(shuge), + "float(shuge) should not equal int(shuge)") def test_logs(self): - import math - LOG10E = math.log10(math.e) for exp in list(range(10)) + [100, 1000, 10000]: @@ -748,7 +472,6 @@ class LongTest(unittest.TestCase): def test_mixed_compares(self): eq = self.assertEqual - import math # We're mostly concerned with that mixing floats and longs does the # right stuff, even when longs are too large to fit in a float. @@ -794,7 +517,7 @@ class LongTest(unittest.TestCase): self.d = d assert float(n) / float(d) == value else: - raise TypeError("can't deal with %r" % val) + raise TypeError("can't deal with %r" % value) def _cmp__(self, other): if not isinstance(other, Rat): @@ -821,7 +544,7 @@ class LongTest(unittest.TestCase): cases.extend([t - 1.0, t - 0.3, t, t + 0.3, t + 1.0, int(t-1), int(t), int(t+1)]) cases.extend([0, 1, 2, sys.maxsize, float(sys.maxsize)]) - # 1L<<20000 should exceed all double formats. long(1e200) is to + # 1 << 20000 should exceed all double formats. int(1e200) is to # check that we get equality with 1e200 above. t = int(1e200) cases.extend([0, 1, 2, 1 << 20000, t-1, t, t+1]) @@ -945,6 +668,127 @@ class LongTest(unittest.TestCase): for zero in ["huge / 0", "mhuge / 0"]: self.assertRaises(ZeroDivisionError, eval, zero, namespace) + def check_truediv(self, a, b, skip_small=True): + """Verify that the result of a/b is correctly rounded, by + comparing it with a pure Python implementation of correctly + rounded division. b should be nonzero.""" + + # skip check for small a and b: in this case, the current + # implementation converts the arguments to float directly and + # then applies a float division. This can give doubly-rounded + # results on x87-using machines (particularly 32-bit Linux). + if skip_small and max(abs(a), abs(b)) < 2**DBL_MANT_DIG: + return + + try: + # use repr so that we can distinguish between -0.0 and 0.0 + expected = repr(truediv(a, b)) + except OverflowError: + expected = 'overflow' + except ZeroDivisionError: + expected = 'zerodivision' + + try: + got = repr(a / b) + except OverflowError: + got = 'overflow' + except ZeroDivisionError: + got = 'zerodivision' + + self.assertEqual(expected, got, "Incorrectly rounded division {}/{}: " + "expected {}, got {}".format(a, b, expected, got)) + + @support.requires_IEEE_754 + def test_correctly_rounded_true_division(self): + # more stringent tests than those above, checking that the + # result of true division of ints is always correctly rounded. + # This test should probably be considered CPython-specific. + + # Exercise all the code paths not involving Gb-sized ints. + # ... divisions involving zero + self.check_truediv(123, 0) + self.check_truediv(-456, 0) + self.check_truediv(0, 3) + self.check_truediv(0, -3) + self.check_truediv(0, 0) + # ... overflow or underflow by large margin + self.check_truediv(671 * 12345 * 2**DBL_MAX_EXP, 12345) + self.check_truediv(12345, 345678 * 2**(DBL_MANT_DIG - DBL_MIN_EXP)) + # ... a much larger or smaller than b + self.check_truediv(12345*2**100, 98765) + self.check_truediv(12345*2**30, 98765*7**81) + # ... a / b near a boundary: one of 1, 2**DBL_MANT_DIG, 2**DBL_MIN_EXP, + # 2**DBL_MAX_EXP, 2**(DBL_MIN_EXP-DBL_MANT_DIG) + bases = (0, DBL_MANT_DIG, DBL_MIN_EXP, + DBL_MAX_EXP, DBL_MIN_EXP - DBL_MANT_DIG) + for base in bases: + for exp in range(base - 15, base + 15): + self.check_truediv(75312*2**max(exp, 0), 69187*2**max(-exp, 0)) + self.check_truediv(69187*2**max(exp, 0), 75312*2**max(-exp, 0)) + + # overflow corner case + for m in [1, 2, 7, 17, 12345, 7**100, + -1, -2, -5, -23, -67891, -41**50]: + for n in range(-10, 10): + self.check_truediv(m*DBL_MIN_OVERFLOW + n, m) + self.check_truediv(m*DBL_MIN_OVERFLOW + n, -m) + + # check detection of inexactness in shifting stage + for n in range(250): + # (2**DBL_MANT_DIG+1)/(2**DBL_MANT_DIG) lies halfway + # between two representable floats, and would usually be + # rounded down under round-half-to-even. The tiniest of + # additions to the numerator should cause it to be rounded + # up instead. + self.check_truediv((2**DBL_MANT_DIG + 1)*12345*2**200 + 2**n, + 2**DBL_MANT_DIG*12345) + + # 1/2731 is one of the smallest division cases that's subject + # to double rounding on IEEE 754 machines working internally with + # 64-bit precision. On such machines, the next check would fail, + # were it not explicitly skipped in check_truediv. + self.check_truediv(1, 2731) + + # a particularly bad case for the old algorithm: gives an + # error of close to 3.5 ulps. + self.check_truediv(295147931372582273023, 295147932265116303360) + for i in range(1000): + self.check_truediv(10**(i+1), 10**i) + self.check_truediv(10**i, 10**(i+1)) + + # test round-half-to-even behaviour, normal result + for m in [1, 2, 4, 7, 8, 16, 17, 32, 12345, 7**100, + -1, -2, -5, -23, -67891, -41**50]: + for n in range(-10, 10): + self.check_truediv(2**DBL_MANT_DIG*m + n, m) + + # test round-half-to-even, subnormal result + for n in range(-20, 20): + self.check_truediv(n, 2**1076) + + # largeish random divisions: a/b where |a| <= |b| <= + # 2*|a|; |ans| is between 0.5 and 1.0, so error should + # always be bounded by 2**-54 with equality possible only + # if the least significant bit of q=ans*2**53 is zero. + for M in [10**10, 10**100, 10**1000]: + for i in range(1000): + a = random.randrange(1, M) + b = random.randrange(a, 2*a+1) + self.check_truediv(a, b) + self.check_truediv(-a, b) + self.check_truediv(a, -b) + self.check_truediv(-a, -b) + + # and some (genuinely) random tests + for _ in range(10000): + a_bits = random.randrange(1000) + b_bits = random.randrange(1, 1000) + x = random.randrange(2**a_bits) + y = random.randrange(1, 2**b_bits) + self.check_truediv(x, y) + self.check_truediv(x, -y) + self.check_truediv(-x, y) + self.check_truediv(-x, -y) def test_small_ints(self): for i in range(-5, 257): @@ -1072,6 +916,237 @@ class LongTest(unittest.TestCase): for e in bad_exponents: self.assertRaises(TypeError, round, 3, e) + def test_to_bytes(self): + def check(tests, byteorder, signed=False): + for test, expected in tests.items(): + try: + self.assertEqual( + test.to_bytes(len(expected), byteorder, signed=signed), + expected) + except Exception as err: + raise AssertionError( + "failed to convert {0} with byteorder={1} and signed={2}" + .format(test, byteorder, signed)) from err + + # Convert integers to signed big-endian byte arrays. + tests1 = { + 0: b'\x00', + 1: b'\x01', + -1: b'\xff', + -127: b'\x81', + -128: b'\x80', + -129: b'\xff\x7f', + 127: b'\x7f', + 129: b'\x00\x81', + -255: b'\xff\x01', + -256: b'\xff\x00', + 255: b'\x00\xff', + 256: b'\x01\x00', + 32767: b'\x7f\xff', + -32768: b'\xff\x80\x00', + 65535: b'\x00\xff\xff', + -65536: b'\xff\x00\x00', + -8388608: b'\x80\x00\x00' + } + check(tests1, 'big', signed=True) + + # Convert integers to signed little-endian byte arrays. + tests2 = { + 0: b'\x00', + 1: b'\x01', + -1: b'\xff', + -127: b'\x81', + -128: b'\x80', + -129: b'\x7f\xff', + 127: b'\x7f', + 129: b'\x81\x00', + -255: b'\x01\xff', + -256: b'\x00\xff', + 255: b'\xff\x00', + 256: b'\x00\x01', + 32767: b'\xff\x7f', + -32768: b'\x00\x80', + 65535: b'\xff\xff\x00', + -65536: b'\x00\x00\xff', + -8388608: b'\x00\x00\x80' + } + check(tests2, 'little', signed=True) + + # Convert integers to unsigned big-endian byte arrays. + tests3 = { + 0: b'\x00', + 1: b'\x01', + 127: b'\x7f', + 128: b'\x80', + 255: b'\xff', + 256: b'\x01\x00', + 32767: b'\x7f\xff', + 32768: b'\x80\x00', + 65535: b'\xff\xff', + 65536: b'\x01\x00\x00' + } + check(tests3, 'big', signed=False) + + # Convert integers to unsigned little-endian byte arrays. + tests4 = { + 0: b'\x00', + 1: b'\x01', + 127: b'\x7f', + 128: b'\x80', + 255: b'\xff', + 256: b'\x00\x01', + 32767: b'\xff\x7f', + 32768: b'\x00\x80', + 65535: b'\xff\xff', + 65536: b'\x00\x00\x01' + } + check(tests4, 'little', signed=False) + + self.assertRaises(OverflowError, (256).to_bytes, 1, 'big', signed=False) + self.assertRaises(OverflowError, (256).to_bytes, 1, 'big', signed=True) + self.assertRaises(OverflowError, (256).to_bytes, 1, 'little', signed=False) + self.assertRaises(OverflowError, (256).to_bytes, 1, 'little', signed=True) + self.assertRaises(OverflowError, (-1).to_bytes, 2, 'big', signed=False), + self.assertRaises(OverflowError, (-1).to_bytes, 2, 'little', signed=False) + self.assertEqual((0).to_bytes(0, 'big'), b'') + self.assertEqual((1).to_bytes(5, 'big'), b'\x00\x00\x00\x00\x01') + self.assertEqual((0).to_bytes(5, 'big'), b'\x00\x00\x00\x00\x00') + self.assertEqual((-1).to_bytes(5, 'big', signed=True), + b'\xff\xff\xff\xff\xff') + self.assertRaises(OverflowError, (1).to_bytes, 0, 'big') + + def test_from_bytes(self): + def check(tests, byteorder, signed=False): + for test, expected in tests.items(): + try: + self.assertEqual( + int.from_bytes(test, byteorder, signed=signed), + expected) + except Exception as err: + raise AssertionError( + "failed to convert {0} with byteorder={1!r} and signed={2}" + .format(test, byteorder, signed)) from err + + # Convert signed big-endian byte arrays to integers. + tests1 = { + b'': 0, + b'\x00': 0, + b'\x00\x00': 0, + b'\x01': 1, + b'\x00\x01': 1, + b'\xff': -1, + b'\xff\xff': -1, + b'\x81': -127, + b'\x80': -128, + b'\xff\x7f': -129, + b'\x7f': 127, + b'\x00\x81': 129, + b'\xff\x01': -255, + b'\xff\x00': -256, + b'\x00\xff': 255, + b'\x01\x00': 256, + b'\x7f\xff': 32767, + b'\x80\x00': -32768, + b'\x00\xff\xff': 65535, + b'\xff\x00\x00': -65536, + b'\x80\x00\x00': -8388608 + } + check(tests1, 'big', signed=True) + + # Convert signed little-endian byte arrays to integers. + tests2 = { + b'': 0, + b'\x00': 0, + b'\x00\x00': 0, + b'\x01': 1, + b'\x00\x01': 256, + b'\xff': -1, + b'\xff\xff': -1, + b'\x81': -127, + b'\x80': -128, + b'\x7f\xff': -129, + b'\x7f': 127, + b'\x81\x00': 129, + b'\x01\xff': -255, + b'\x00\xff': -256, + b'\xff\x00': 255, + b'\x00\x01': 256, + b'\xff\x7f': 32767, + b'\x00\x80': -32768, + b'\xff\xff\x00': 65535, + b'\x00\x00\xff': -65536, + b'\x00\x00\x80': -8388608 + } + check(tests2, 'little', signed=True) + + # Convert unsigned big-endian byte arrays to integers. + tests3 = { + b'': 0, + b'\x00': 0, + b'\x01': 1, + b'\x7f': 127, + b'\x80': 128, + b'\xff': 255, + b'\x01\x00': 256, + b'\x7f\xff': 32767, + b'\x80\x00': 32768, + b'\xff\xff': 65535, + b'\x01\x00\x00': 65536, + } + check(tests3, 'big', signed=False) + + # Convert integers to unsigned little-endian byte arrays. + tests4 = { + b'': 0, + b'\x00': 0, + b'\x01': 1, + b'\x7f': 127, + b'\x80': 128, + b'\xff': 255, + b'\x00\x01': 256, + b'\xff\x7f': 32767, + b'\x00\x80': 32768, + b'\xff\xff': 65535, + b'\x00\x00\x01': 65536, + } + check(tests4, 'little', signed=False) + + class myint(int): + pass + + self.assertTrue(type(myint.from_bytes(b'\x00', 'big')) is myint) + self.assertEqual(myint.from_bytes(b'\x01', 'big'), 1) + self.assertTrue( + type(myint.from_bytes(b'\x00', 'big', signed=False)) is myint) + self.assertEqual(myint.from_bytes(b'\x01', 'big', signed=False), 1) + self.assertTrue(type(myint.from_bytes(b'\x00', 'little')) is myint) + self.assertEqual(myint.from_bytes(b'\x01', 'little'), 1) + self.assertTrue(type(myint.from_bytes( + b'\x00', 'little', signed=False)) is myint) + self.assertEqual(myint.from_bytes(b'\x01', 'little', signed=False), 1) + self.assertEqual( + int.from_bytes([255, 0, 0], 'big', signed=True), -65536) + self.assertEqual( + int.from_bytes((255, 0, 0), 'big', signed=True), -65536) + self.assertEqual(int.from_bytes( + bytearray(b'\xff\x00\x00'), 'big', signed=True), -65536) + self.assertEqual(int.from_bytes( + bytearray(b'\xff\x00\x00'), 'big', signed=True), -65536) + self.assertEqual(int.from_bytes( + array.array('B', b'\xff\x00\x00'), 'big', signed=True), -65536) + self.assertEqual(int.from_bytes( + memoryview(b'\xff\x00\x00'), 'big', signed=True), -65536) + self.assertRaises(ValueError, int.from_bytes, [256], 'big') + self.assertRaises(ValueError, int.from_bytes, [0], 'big\x00') + self.assertRaises(ValueError, int.from_bytes, [0], 'little\x00') + self.assertRaises(TypeError, int.from_bytes, "", 'big') + self.assertRaises(TypeError, int.from_bytes, "\x00", 'big') + self.assertRaises(TypeError, int.from_bytes, 0, 'big') + self.assertRaises(TypeError, int.from_bytes, 0, 'big', True) + self.assertRaises(TypeError, myint.from_bytes, "", 'big') + self.assertRaises(TypeError, myint.from_bytes, "\x00", 'big') + self.assertRaises(TypeError, myint.from_bytes, 0, 'big') + self.assertRaises(TypeError, int.from_bytes, 0, 'big', True) def test_main(): |
