mirror of https://github.com/python/cpython.git
Make struct tests pass.
This commit is contained in:
parent
54ad523f02
commit
e625fd5444
|
@ -31,7 +31,13 @@
|
||||||
__version__ = '3.0'
|
__version__ = '3.0'
|
||||||
|
|
||||||
|
|
||||||
from _struct import Struct, error
|
from _struct import Struct as _Struct, error
|
||||||
|
|
||||||
|
class Struct(_Struct):
|
||||||
|
def __init__(self, fmt):
|
||||||
|
if isinstance(fmt, str):
|
||||||
|
fmt = str8(fmt)
|
||||||
|
_Struct.__init__(self, fmt)
|
||||||
|
|
||||||
_MAXCACHE = 100
|
_MAXCACHE = 100
|
||||||
_cache = {}
|
_cache = {}
|
||||||
|
@ -40,7 +46,7 @@ def _compile(fmt):
|
||||||
# Internal: compile struct pattern
|
# Internal: compile struct pattern
|
||||||
if len(_cache) >= _MAXCACHE:
|
if len(_cache) >= _MAXCACHE:
|
||||||
_cache.clear()
|
_cache.clear()
|
||||||
s = Struct(str8(fmt))
|
s = Struct(fmt)
|
||||||
_cache[fmt] = s
|
_cache[fmt] = s
|
||||||
return s
|
return s
|
||||||
|
|
||||||
|
@ -76,7 +82,7 @@ def pack_into(fmt, buf, offset, *args):
|
||||||
o = _cache[fmt]
|
o = _cache[fmt]
|
||||||
except KeyError:
|
except KeyError:
|
||||||
o = _compile(fmt)
|
o = _compile(fmt)
|
||||||
return bytes(o.pack_into(buf, offset, *args))
|
o.pack_into(buf, offset, *args)
|
||||||
|
|
||||||
def unpack(fmt, s):
|
def unpack(fmt, s):
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
import sys
|
import sys
|
||||||
ISBIGENDIAN = sys.byteorder == "big"
|
ISBIGENDIAN = sys.byteorder == "big"
|
||||||
del sys
|
del sys
|
||||||
verify((struct.pack('=i', 1)[0] == chr(0)) == ISBIGENDIAN,
|
verify((struct.pack('=i', 1)[0] == 0) == ISBIGENDIAN,
|
||||||
"bigendian determination appears wrong")
|
"bigendian determination appears wrong")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
@ -22,7 +22,7 @@
|
||||||
PY_STRUCT_FLOAT_COERCE = getattr(_struct, '_PY_STRUCT_FLOAT_COERCE', 0)
|
PY_STRUCT_FLOAT_COERCE = getattr(_struct, '_PY_STRUCT_FLOAT_COERCE', 0)
|
||||||
|
|
||||||
def string_reverse(s):
|
def string_reverse(s):
|
||||||
return "".join(reversed(s))
|
return s[::-1]
|
||||||
|
|
||||||
def bigendian_to_native(value):
|
def bigendian_to_native(value):
|
||||||
if ISBIGENDIAN:
|
if ISBIGENDIAN:
|
||||||
|
@ -168,6 +168,8 @@ def deprecated_err(func, *args):
|
||||||
]
|
]
|
||||||
|
|
||||||
for fmt, arg, big, lil, asy in tests:
|
for fmt, arg, big, lil, asy in tests:
|
||||||
|
big = bytes(big, "latin-1")
|
||||||
|
lil = bytes(lil, "latin-1")
|
||||||
if verbose:
|
if verbose:
|
||||||
print("%r %r %r %r" % (fmt, arg, big, lil))
|
print("%r %r %r %r" % (fmt, arg, big, lil))
|
||||||
for (xfmt, exp) in [('>'+fmt, big), ('!'+fmt, big), ('<'+fmt, lil),
|
for (xfmt, exp) in [('>'+fmt, big), ('!'+fmt, big), ('<'+fmt, lil),
|
||||||
|
@ -202,17 +204,18 @@ def deprecated_err(func, *args):
|
||||||
simple_err(struct.pack, "Q", "a") # ditto, but 'Q'
|
simple_err(struct.pack, "Q", "a") # ditto, but 'Q'
|
||||||
|
|
||||||
def test_native_qQ():
|
def test_native_qQ():
|
||||||
bytes = struct.calcsize('q')
|
nbytes = struct.calcsize('q')
|
||||||
# The expected values here are in big-endian format, primarily because
|
# 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
|
# I'm on a little-endian machine and so this is the clearest way (for
|
||||||
# me) to force the code to get exercised.
|
# me) to force the code to get exercised.
|
||||||
for format, input, expected in (
|
for format, input, expected in (
|
||||||
('q', -1, '\xff' * bytes),
|
('q', -1, '\xff' * nbytes),
|
||||||
('q', 0, '\x00' * bytes),
|
('q', 0, '\x00' * nbytes),
|
||||||
('Q', 0, '\x00' * bytes),
|
('Q', 0, '\x00' * nbytes),
|
||||||
('q', 1, '\x00' * (bytes-1) + '\x01'),
|
('q', 1, '\x00' * (nbytes-1) + '\x01'),
|
||||||
('Q', (1 << (8*bytes))-1, '\xff' * bytes),
|
('Q', (1 << (8*nbytes))-1, '\xff' * nbytes),
|
||||||
('q', (1 << (8*bytes-1))-1, '\x7f' + '\xff' * (bytes - 1))):
|
('q', (1 << (8*nbytes-1))-1, '\x7f' + '\xff' * (nbytes - 1))):
|
||||||
|
expected = bytes(expected, "latin-1")
|
||||||
got = struct.pack(format, input)
|
got = struct.pack(format, input)
|
||||||
native_expected = bigendian_to_native(expected)
|
native_expected = bigendian_to_native(expected)
|
||||||
verify(got == native_expected,
|
verify(got == native_expected,
|
||||||
|
@ -272,7 +275,7 @@ def test_one(self, x, pack=struct.pack,
|
||||||
if len(expected) & 1:
|
if len(expected) & 1:
|
||||||
expected = "0" + expected
|
expected = "0" + expected
|
||||||
expected = unhexlify(expected)
|
expected = unhexlify(expected)
|
||||||
expected = "\x00" * (self.bytesize - len(expected)) + expected
|
expected = b"\x00" * (self.bytesize - len(expected)) + expected
|
||||||
|
|
||||||
# Pack work?
|
# Pack work?
|
||||||
format = ">" + code
|
format = ">" + code
|
||||||
|
@ -288,7 +291,7 @@ def test_one(self, x, pack=struct.pack,
|
||||||
(format, got, retrieved, x))
|
(format, got, retrieved, x))
|
||||||
|
|
||||||
# Adding any byte should cause a "too big" error.
|
# Adding any byte should cause a "too big" error.
|
||||||
any_err(unpack, format, '\x01' + got)
|
any_err(unpack, format, b'\x01' + got)
|
||||||
|
|
||||||
# Try little-endian.
|
# Try little-endian.
|
||||||
format = "<" + code
|
format = "<" + code
|
||||||
|
@ -307,7 +310,7 @@ def test_one(self, x, pack=struct.pack,
|
||||||
(format, got, retrieved, x))
|
(format, got, retrieved, x))
|
||||||
|
|
||||||
# Adding any byte should cause a "too big" error.
|
# Adding any byte should cause a "too big" error.
|
||||||
any_err(unpack, format, '\x01' + got)
|
any_err(unpack, format, b'\x01' + got)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
# x is out of range -- verify pack realizes that.
|
# x is out of range -- verify pack realizes that.
|
||||||
|
@ -328,7 +331,7 @@ def test_one(self, x, pack=struct.pack,
|
||||||
if len(expected) & 1:
|
if len(expected) & 1:
|
||||||
expected = "0" + expected
|
expected = "0" + expected
|
||||||
expected = unhexlify(expected)
|
expected = unhexlify(expected)
|
||||||
expected = "\x00" * (self.bytesize - len(expected)) + expected
|
expected = b"\x00" * (self.bytesize - len(expected)) + expected
|
||||||
|
|
||||||
# Pack work?
|
# Pack work?
|
||||||
got = pack(format, x)
|
got = pack(format, x)
|
||||||
|
@ -343,7 +346,7 @@ def test_one(self, x, pack=struct.pack,
|
||||||
(format, got, retrieved, x))
|
(format, got, retrieved, x))
|
||||||
|
|
||||||
# Adding any byte should cause a "too big" error.
|
# Adding any byte should cause a "too big" error.
|
||||||
any_err(unpack, format, '\x01' + got)
|
any_err(unpack, format, b'\x01' + got)
|
||||||
|
|
||||||
# Try little-endian.
|
# Try little-endian.
|
||||||
format = "<" + code
|
format = "<" + code
|
||||||
|
@ -362,7 +365,7 @@ def test_one(self, x, pack=struct.pack,
|
||||||
(format, got, retrieved, x))
|
(format, got, retrieved, x))
|
||||||
|
|
||||||
# Adding any byte should cause a "too big" error.
|
# Adding any byte should cause a "too big" error.
|
||||||
any_err(unpack, format, '\x01' + got)
|
any_err(unpack, format, b'\x01' + got)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
# x is out of range -- verify pack realizes that.
|
# x is out of range -- verify pack realizes that.
|
||||||
|
@ -429,6 +432,7 @@ def test_p_code():
|
||||||
('5p', 'abc', '\x03abc\x00', 'abc'),
|
('5p', 'abc', '\x03abc\x00', 'abc'),
|
||||||
('6p', 'abc', '\x03abc\x00\x00', 'abc'),
|
('6p', 'abc', '\x03abc\x00\x00', 'abc'),
|
||||||
('1000p', 'x'*1000, '\xff' + 'x'*999, 'x'*255)]:
|
('1000p', 'x'*1000, '\xff' + 'x'*999, 'x'*255)]:
|
||||||
|
expected = bytes(expected, "latin-1")
|
||||||
got = struct.pack(code, input)
|
got = struct.pack(code, input)
|
||||||
if got != expected:
|
if got != expected:
|
||||||
raise TestFailed("pack(%r, %r) == %r but expected %r" %
|
raise TestFailed("pack(%r, %r) == %r but expected %r" %
|
||||||
|
@ -549,10 +553,12 @@ def assertRaises(excClass, callableObj, *args, **kwargs):
|
||||||
raise TestFailed("%s not raised." % excClass)
|
raise TestFailed("%s not raised." % excClass)
|
||||||
|
|
||||||
def test_unpack_from():
|
def test_unpack_from():
|
||||||
test_string = 'abcd01234'
|
test_string = b'abcd01234'
|
||||||
fmt = '4s'
|
fmt = '4s'
|
||||||
s = struct.Struct(fmt)
|
s = struct.Struct(fmt)
|
||||||
for cls in (str, buffer):
|
for cls in (str, str8, buffer, bytes):
|
||||||
|
if verbose:
|
||||||
|
print("test_unpack_from using", cls.__name__)
|
||||||
data = cls(test_string)
|
data = cls(test_string)
|
||||||
vereq(s.unpack_from(data), ('abcd',))
|
vereq(s.unpack_from(data), ('abcd',))
|
||||||
vereq(s.unpack_from(data, 2), ('cd01',))
|
vereq(s.unpack_from(data, 2), ('cd01',))
|
||||||
|
@ -615,8 +621,8 @@ def test_pack_into_fn():
|
||||||
|
|
||||||
def test_unpack_with_buffer():
|
def test_unpack_with_buffer():
|
||||||
# SF bug 1563759: struct.unpack doens't support buffer protocol objects
|
# SF bug 1563759: struct.unpack doens't support buffer protocol objects
|
||||||
data1 = array.array('B', '\x12\x34\x56\x78')
|
data1 = array.array('B', b'\x12\x34\x56\x78')
|
||||||
data2 = buffer('......\x12\x34\x56\x78......', 6, 4)
|
data2 = buffer(b'......\x12\x34\x56\x78......', 6, 4)
|
||||||
for data in [data1, data2]:
|
for data in [data1, data2]:
|
||||||
value, = struct.unpack('>I', data)
|
value, = struct.unpack('>I', data)
|
||||||
vereq(value, 0x12345678)
|
vereq(value, 0x12345678)
|
||||||
|
@ -668,7 +674,7 @@ def test_bool():
|
||||||
elif not prefix and verbose:
|
elif not prefix and verbose:
|
||||||
print('size of bool in native format is %i' % (len(packed)))
|
print('size of bool in native format is %i' % (len(packed)))
|
||||||
|
|
||||||
for c in '\x01\x7f\xff\x0f\xf0':
|
for c in str8('\x01\x7f\xff\x0f\xf0'):
|
||||||
if struct.unpack('>t', c)[0] is not True:
|
if struct.unpack('>t', c)[0] is not True:
|
||||||
raise TestFailed('%c did not unpack as True' % c)
|
raise TestFailed('%c did not unpack as True' % c)
|
||||||
|
|
||||||
|
|
|
@ -608,9 +608,14 @@ np_ubyte(char *p, PyObject *v, const formatdef *f)
|
||||||
static int
|
static int
|
||||||
np_char(char *p, PyObject *v, const formatdef *f)
|
np_char(char *p, PyObject *v, const formatdef *f)
|
||||||
{
|
{
|
||||||
|
if (PyUnicode_Check(v)) {
|
||||||
|
v = _PyUnicode_AsDefaultEncodedString(v, NULL);
|
||||||
|
if (v == NULL)
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
if (!PyString_Check(v) || PyString_Size(v) != 1) {
|
if (!PyString_Check(v) || PyString_Size(v) != 1) {
|
||||||
PyErr_SetString(StructError,
|
PyErr_SetString(StructError,
|
||||||
"char format require string of length 1");
|
"char format requires string of length 1");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
*p = *PyString_AsString(v);
|
*p = *PyString_AsString(v);
|
||||||
|
|
Loading…
Reference in New Issue