mirror of
https://github.com/python/cpython.git
synced 2025-09-26 18:29:57 +00:00
Clean up integer tests in test_struct, and bring them more in line with the trunk tests.
This commit is contained in:
parent
6607d51160
commit
b9f751ad91
1 changed files with 122 additions and 165 deletions
|
@ -8,6 +8,18 @@ from test.support import run_unittest
|
||||||
ISBIGENDIAN = sys.byteorder == "big"
|
ISBIGENDIAN = sys.byteorder == "big"
|
||||||
IS32BIT = sys.maxsize == 0x7fffffff
|
IS32BIT = sys.maxsize == 0x7fffffff
|
||||||
|
|
||||||
|
integer_codes = 'b', 'B', 'h', 'H', 'i', 'I', 'l', 'L', 'q', 'Q'
|
||||||
|
byteorders = '', '@', '=', '<', '>', '!'
|
||||||
|
|
||||||
|
# Native 'q' packing isn't available on systems that don't have the C
|
||||||
|
# long long type.
|
||||||
|
try:
|
||||||
|
struct.pack('q', 5)
|
||||||
|
except struct.error:
|
||||||
|
HAVE_LONG_LONG = False
|
||||||
|
else:
|
||||||
|
HAVE_LONG_LONG = True
|
||||||
|
|
||||||
def string_reverse(s):
|
def string_reverse(s):
|
||||||
return s[::-1]
|
return s[::-1]
|
||||||
|
|
||||||
|
@ -125,93 +137,89 @@ class StructTest(unittest.TestCase):
|
||||||
if rev != arg:
|
if rev != arg:
|
||||||
self.assertTrue(asy)
|
self.assertTrue(asy)
|
||||||
|
|
||||||
def test_native_qQ(self):
|
def test_calcsize(self):
|
||||||
# can't pack -1 as unsigned regardless
|
expected_size = {
|
||||||
self.assertRaises((struct.error, OverflowError), struct.pack, "Q", -1)
|
'b': 1, 'B': 1,
|
||||||
# can't pack string as 'q' regardless
|
'h': 2, 'H': 2,
|
||||||
self.assertRaises(struct.error, struct.pack, "q", "a")
|
'i': 4, 'I': 4,
|
||||||
# ditto, but 'Q'
|
'l': 4, 'L': 4,
|
||||||
self.assertRaises(struct.error, struct.pack, "Q", "a")
|
'q': 8, 'Q': 8,
|
||||||
|
}
|
||||||
|
|
||||||
try:
|
# standard integer sizes
|
||||||
struct.pack("q", 5)
|
for code in integer_codes:
|
||||||
except struct.error:
|
for byteorder in '=', '<', '>', '!':
|
||||||
# does not have native q/Q
|
format = byteorder+code
|
||||||
pass
|
size = struct.calcsize(format)
|
||||||
else:
|
self.assertEqual(size, expected_size[code])
|
||||||
nbytes = struct.calcsize('q')
|
|
||||||
# The expected values here are in big-endian format, primarily
|
|
||||||
# because I'm on a little-endian machine and so this is the
|
|
||||||
# clearest way (for me) to force the code to get exercised.
|
|
||||||
for format, input, expected in (
|
|
||||||
('q', -1, '\xff' * nbytes),
|
|
||||||
('q', 0, '\x00' * nbytes),
|
|
||||||
('Q', 0, '\x00' * nbytes),
|
|
||||||
('q', 1, '\x00' * (nbytes-1) + '\x01'),
|
|
||||||
('Q', (1 << (8*nbytes))-1, '\xff' * nbytes),
|
|
||||||
('q', (1 << (8*nbytes-1))-1, '\x7f' + '\xff' * (nbytes - 1))):
|
|
||||||
expected = bytes(expected, "latin-1")
|
|
||||||
got = struct.pack(format, input)
|
|
||||||
native_expected = bigendian_to_native(expected)
|
|
||||||
self.assertEqual(got, native_expected)
|
|
||||||
retrieved = struct.unpack(format, got)[0]
|
|
||||||
self.assertEqual(retrieved, input)
|
|
||||||
|
|
||||||
def test_standard_integers(self):
|
# native integer sizes
|
||||||
# Standard integer tests (bBhHiIlLqQ).
|
native_pairs = 'bB', 'hH', 'iI', 'lL'
|
||||||
|
if HAVE_LONG_LONG:
|
||||||
|
native_pairs += 'qQ',
|
||||||
|
for format_pair in native_pairs:
|
||||||
|
for byteorder in '', '@':
|
||||||
|
signed_size = struct.calcsize(byteorder + format_pair[0])
|
||||||
|
unsigned_size = struct.calcsize(byteorder + format_pair[1])
|
||||||
|
self.assertEqual(signed_size, unsigned_size)
|
||||||
|
|
||||||
|
# bounds for native integer sizes
|
||||||
|
self.assertTrue(struct.calcsize('b')==1)
|
||||||
|
self.assertTrue(2 <= struct.calcsize('h'))
|
||||||
|
self.assertTrue(4 <= struct.calcsize('l'))
|
||||||
|
self.assertTrue(struct.calcsize('h') <= struct.calcsize('i'))
|
||||||
|
self.assertTrue(struct.calcsize('i') <= struct.calcsize('l'))
|
||||||
|
if HAVE_LONG_LONG:
|
||||||
|
self.assertTrue(8 <= struct.calcsize('q'))
|
||||||
|
self.assertTrue(struct.calcsize('l') <= struct.calcsize('q'))
|
||||||
|
|
||||||
|
def test_integers(self):
|
||||||
|
# Integer tests (bBhHiIlLqQ).
|
||||||
import binascii
|
import binascii
|
||||||
|
|
||||||
class IntTester(unittest.TestCase):
|
class IntTester(unittest.TestCase):
|
||||||
|
def __init__(self, format):
|
||||||
def __init__(self, formatpair, bytesize):
|
|
||||||
super(IntTester, self).__init__(methodName='test_one')
|
super(IntTester, self).__init__(methodName='test_one')
|
||||||
self.assertEqual(len(formatpair), 2)
|
self.format = format
|
||||||
self.formatpair = formatpair
|
self.code = format[-1]
|
||||||
for direction in "<>!=":
|
self.byteorder = format[:-1]
|
||||||
for code in formatpair:
|
if not self.byteorder in byteorders:
|
||||||
format = direction + code
|
raise ValueError("unrecognized packing byteorder: %s" %
|
||||||
self.assertEqual(struct.calcsize(format), bytesize)
|
self.byteorder)
|
||||||
self.bytesize = bytesize
|
self.bytesize = struct.calcsize(format)
|
||||||
self.bitsize = bytesize * 8
|
self.bitsize = self.bytesize * 8
|
||||||
self.signed_code, self.unsigned_code = formatpair
|
if self.code in tuple('bhilq'):
|
||||||
self.unsigned_min = 0
|
self.signed = True
|
||||||
self.unsigned_max = 2**self.bitsize - 1
|
self.min_value = -(2**(self.bitsize-1))
|
||||||
self.signed_min = -(2**(self.bitsize-1))
|
self.max_value = 2**(self.bitsize-1) - 1
|
||||||
self.signed_max = 2**(self.bitsize-1) - 1
|
elif self.code in tuple('BHILQ'):
|
||||||
|
self.signed = False
|
||||||
|
self.min_value = 0
|
||||||
|
self.max_value = 2**self.bitsize - 1
|
||||||
|
else:
|
||||||
|
raise ValueError("unrecognized format code: %s" %
|
||||||
|
self.code)
|
||||||
|
|
||||||
def test_one(self, x, pack=struct.pack,
|
def test_one(self, x, pack=struct.pack,
|
||||||
unpack=struct.unpack,
|
unpack=struct.unpack,
|
||||||
unhexlify=binascii.unhexlify):
|
unhexlify=binascii.unhexlify):
|
||||||
# Try signed.
|
|
||||||
code = self.signed_code
|
format = self.format
|
||||||
if self.signed_min <= x <= self.signed_max:
|
if self.min_value <= x <= self.max_value:
|
||||||
# Try big-endian.
|
|
||||||
expected = x
|
expected = x
|
||||||
if x < 0:
|
if self.signed and x < 0:
|
||||||
expected += 1 << self.bitsize
|
expected += 1 << self.bitsize
|
||||||
self.assertTrue(expected > 0)
|
self.assertTrue(expected >= 0)
|
||||||
expected = hex(expected)[2:] # chop "0x"
|
expected = '%x' % expected
|
||||||
if len(expected) & 1:
|
if len(expected) & 1:
|
||||||
expected = "0" + expected
|
expected = "0" + expected
|
||||||
expected = unhexlify(expected)
|
expected = unhexlify(expected)
|
||||||
expected = b"\x00" * (self.bytesize - len(expected)) + expected
|
expected = (b"\x00" * (self.bytesize - len(expected)) +
|
||||||
|
expected)
|
||||||
# Pack work?
|
if (self.byteorder == '<' or
|
||||||
format = ">" + code
|
self.byteorder in ('', '@', '=') and not ISBIGENDIAN):
|
||||||
got = pack(format, x)
|
|
||||||
self.assertEqual(got, expected)
|
|
||||||
|
|
||||||
# Unpack work?
|
|
||||||
retrieved = unpack(format, got)[0]
|
|
||||||
self.assertEqual(x, retrieved)
|
|
||||||
|
|
||||||
# Adding any byte should cause a "too big" error.
|
|
||||||
self.assertRaises((struct.error, TypeError),
|
|
||||||
unpack, format, b'\x01' + got)
|
|
||||||
|
|
||||||
# Try little-endian.
|
|
||||||
format = "<" + code
|
|
||||||
expected = string_reverse(expected)
|
expected = string_reverse(expected)
|
||||||
|
self.assertEqual(len(expected), self.bytesize)
|
||||||
|
|
||||||
# Pack work?
|
# Pack work?
|
||||||
got = pack(format, x)
|
got = pack(format, x)
|
||||||
|
@ -222,58 +230,11 @@ class StructTest(unittest.TestCase):
|
||||||
self.assertEqual(x, retrieved)
|
self.assertEqual(x, retrieved)
|
||||||
|
|
||||||
# Adding any byte should cause a "too big" error.
|
# Adding any byte should cause a "too big" error.
|
||||||
self.assertRaises((struct.error, TypeError),
|
self.assertRaises((struct.error, TypeError), unpack, format,
|
||||||
unpack, format, b'\x01' + got)
|
b'\x01' + got)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
# x is out of range -- verify pack realizes that.
|
# x is out of range -- verify pack realizes that.
|
||||||
self.assertRaises(struct.error, pack, ">" + code, x)
|
self.assertRaises(struct.error, pack, format, x)
|
||||||
self.assertRaises(struct.error, pack, "<" + code, x)
|
|
||||||
|
|
||||||
# Much the same for unsigned.
|
|
||||||
code = self.unsigned_code
|
|
||||||
if self.unsigned_min <= x <= self.unsigned_max:
|
|
||||||
# Try big-endian.
|
|
||||||
format = ">" + code
|
|
||||||
expected = x
|
|
||||||
expected = hex(expected)[2:] # chop "0x"
|
|
||||||
if len(expected) & 1:
|
|
||||||
expected = "0" + expected
|
|
||||||
expected = unhexlify(expected)
|
|
||||||
expected = b"\x00" * (self.bytesize - len(expected)) + expected
|
|
||||||
|
|
||||||
# Pack work?
|
|
||||||
got = pack(format, x)
|
|
||||||
self.assertEqual(got, expected)
|
|
||||||
|
|
||||||
# Unpack work?
|
|
||||||
retrieved = unpack(format, got)[0]
|
|
||||||
self.assertEqual(x, retrieved)
|
|
||||||
|
|
||||||
# Adding any byte should cause a "too big" error.
|
|
||||||
self.assertRaises((struct.error, TypeError),
|
|
||||||
unpack, format, b'\x01' + got)
|
|
||||||
|
|
||||||
# Try little-endian.
|
|
||||||
format = "<" + code
|
|
||||||
expected = string_reverse(expected)
|
|
||||||
|
|
||||||
# Pack work?
|
|
||||||
got = pack(format, x)
|
|
||||||
self.assertEqual(got, expected)
|
|
||||||
|
|
||||||
# Unpack work?
|
|
||||||
retrieved = unpack(format, got)[0]
|
|
||||||
self.assertEqual(x, retrieved)
|
|
||||||
|
|
||||||
# Adding any byte should cause a "too big" error.
|
|
||||||
self.assertRaises((struct.error, TypeError),
|
|
||||||
unpack, format, b'\x01' + got)
|
|
||||||
|
|
||||||
else:
|
|
||||||
# x is out of range -- verify pack realizes that.
|
|
||||||
self.assertRaises(struct.error, pack, ">" + code, x)
|
|
||||||
self.assertRaises(struct.error, pack, "<" + code, x)
|
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
from random import randrange
|
from random import randrange
|
||||||
|
@ -290,33 +251,44 @@ class StructTest(unittest.TestCase):
|
||||||
val = (val << 8) | randrange(256)
|
val = (val << 8) | randrange(256)
|
||||||
values.append(val)
|
values.append(val)
|
||||||
|
|
||||||
# Try all those, and their negations, and +-1 from them. Note
|
# Values absorbed from other tests
|
||||||
# that this tests all power-of-2 boundaries in range, and a few out
|
values.extend([300, 700000, sys.maxsize*4])
|
||||||
# of range, plus +-(2**n +- 1).
|
|
||||||
|
# Try all those, and their negations, and +-1 from
|
||||||
|
# them. Note that this tests all power-of-2
|
||||||
|
# boundaries in range, and a few out of range, plus
|
||||||
|
# +-(2**n +- 1).
|
||||||
for base in values:
|
for base in values:
|
||||||
for val in -base, base:
|
for val in -base, base:
|
||||||
for incr in -1, 0, 1:
|
for incr in -1, 0, 1:
|
||||||
x = val + incr
|
x = val + incr
|
||||||
try:
|
|
||||||
x = int(x)
|
|
||||||
except OverflowError:
|
|
||||||
pass
|
|
||||||
self.test_one(x)
|
self.test_one(x)
|
||||||
|
|
||||||
# Some error cases.
|
# Some error cases.
|
||||||
for direction in "<>":
|
class NotAnInt:
|
||||||
for code in self.formatpair:
|
def __int__(self):
|
||||||
for badobject in "a string", 3+42j, randrange, -1729.0:
|
return 42
|
||||||
self.assertRaises(struct.error,
|
|
||||||
struct.pack, direction + code,
|
|
||||||
badobject)
|
|
||||||
|
|
||||||
for args in [("bB", 1),
|
self.assertRaises((TypeError, struct.error),
|
||||||
("hH", 2),
|
struct.pack, self.format,
|
||||||
("iI", 4),
|
"a string")
|
||||||
("lL", 4),
|
self.assertRaises((TypeError, struct.error),
|
||||||
("qQ", 8)]:
|
struct.pack, self.format,
|
||||||
t = IntTester(*args)
|
randrange)
|
||||||
|
self.assertRaises((TypeError, struct.error),
|
||||||
|
struct.pack, self.format,
|
||||||
|
3+42j)
|
||||||
|
self.assertRaises((TypeError, struct.error),
|
||||||
|
struct.pack, self.format,
|
||||||
|
NotAnInt)
|
||||||
|
|
||||||
|
for code in integer_codes:
|
||||||
|
for byteorder in byteorders:
|
||||||
|
if (byteorder in ('', '@') and code in ('q', 'Q') and
|
||||||
|
not HAVE_LONG_LONG):
|
||||||
|
continue
|
||||||
|
format = byteorder+code
|
||||||
|
t = IntTester(format)
|
||||||
t.run()
|
t.run()
|
||||||
|
|
||||||
def test_p_code(self):
|
def test_p_code(self):
|
||||||
|
@ -371,33 +343,18 @@ class StructTest(unittest.TestCase):
|
||||||
big = math.ldexp(big, 127 - 24)
|
big = math.ldexp(big, 127 - 24)
|
||||||
self.assertRaises(OverflowError, struct.pack, ">f", big)
|
self.assertRaises(OverflowError, struct.pack, ">f", big)
|
||||||
|
|
||||||
def test_1229380(self):
|
|
||||||
# SF bug 1229380. No struct.pack exception for some out of
|
|
||||||
# range integers
|
|
||||||
for endian in ('', '>', '<'):
|
|
||||||
for fmt in ('B', 'H', 'I', 'L'):
|
|
||||||
self.assertRaises((struct.error, OverflowError), struct.pack,
|
|
||||||
endian + fmt, -1)
|
|
||||||
|
|
||||||
self.assertRaises((struct.error, OverflowError), struct.pack,
|
|
||||||
endian + 'B', 300)
|
|
||||||
self.assertRaises((struct.error, OverflowError), struct.pack,
|
|
||||||
endian + 'H', 70000)
|
|
||||||
|
|
||||||
self.assertRaises((struct.error, OverflowError), struct.pack,
|
|
||||||
endian + 'I', sys.maxsize * 4)
|
|
||||||
self.assertRaises((struct.error, OverflowError), struct.pack,
|
|
||||||
endian + 'L', sys.maxsize * 4)
|
|
||||||
|
|
||||||
def test_1530559(self):
|
def test_1530559(self):
|
||||||
for endian in ('', '>', '<'):
|
for byteorder in '', '@', '=', '<', '>', '!':
|
||||||
for fmt in ('B', 'H', 'I', 'L', 'Q', 'b', 'h', 'i', 'l', 'q'):
|
for code in integer_codes:
|
||||||
self.assertRaises(struct.error, struct.pack, endian + fmt, 1.0)
|
if (byteorder in ('', '@') and code in ('q', 'Q') and
|
||||||
self.assertRaises(struct.error, struct.pack, endian + fmt, 1.5)
|
not HAVE_LONG_LONG):
|
||||||
|
continue
|
||||||
|
format = byteorder + code
|
||||||
|
self.assertRaises(struct.error, struct.pack, format, 1.0)
|
||||||
|
self.assertRaises(struct.error, struct.pack, format, 1.5)
|
||||||
self.assertRaises(struct.error, struct.pack, 'P', 1.0)
|
self.assertRaises(struct.error, struct.pack, 'P', 1.0)
|
||||||
self.assertRaises(struct.error, struct.pack, 'P', 1.5)
|
self.assertRaises(struct.error, struct.pack, 'P', 1.5)
|
||||||
|
|
||||||
|
|
||||||
def test_unpack_from(self):
|
def test_unpack_from(self):
|
||||||
test_string = b'abcd01234'
|
test_string = b'abcd01234'
|
||||||
fmt = '4s'
|
fmt = '4s'
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue