Kaydet (Commit) 747e8b3f authored tarafından Antoine Pitrou's avatar Antoine Pitrou

Merged revisions 77528 via svnmerge from

svn+ssh://pythondev@svn.python.org/python/trunk

........
  r77528 | antoine.pitrou | 2010-01-16 18:45:56 +0100 (sam., 16 janv. 2010) | 4 lines

  Followup to #7703: a2b_hqx() didn't follow the new buffer API (neither in trunk
  nor in py3k).  Patch by Florent Xicluna as well as additional tests.
........
üst 73fa727e
...@@ -5,6 +5,14 @@ import unittest ...@@ -5,6 +5,14 @@ import unittest
import binascii import binascii
import array import array
# Note: "*_hex" functions are aliases for "(un)hexlify"
b2a_functions = ['b2a_base64', 'b2a_hex', 'b2a_hqx', 'b2a_qp', 'b2a_uu',
'hexlify', 'rlecode_hqx']
a2b_functions = ['a2b_base64', 'a2b_hex', 'a2b_hqx', 'a2b_qp', 'a2b_uu',
'unhexlify', 'rledecode_hqx']
all_functions = a2b_functions + b2a_functions + ['crc32', 'crc_hqx']
class BinASCIITest(unittest.TestCase): class BinASCIITest(unittest.TestCase):
type2test = bytes type2test = bytes
...@@ -24,30 +32,45 @@ class BinASCIITest(unittest.TestCase): ...@@ -24,30 +32,45 @@ class BinASCIITest(unittest.TestCase):
def test_functions(self): def test_functions(self):
# Check presence of all functions # Check presence of all functions
funcs = [] for name in all_functions:
for suffix in "base64", "hqx", "uu", "hex":
prefixes = ["a2b_", "b2a_"]
if suffix == "hqx":
prefixes.extend(["crc_", "rlecode_", "rledecode_"])
for prefix in prefixes:
name = prefix + suffix
self.assertTrue(hasattr(getattr(binascii, name), '__call__'))
self.assertRaises(TypeError, getattr(binascii, name))
for name in ("hexlify", "unhexlify"):
self.assertTrue(hasattr(getattr(binascii, name), '__call__')) self.assertTrue(hasattr(getattr(binascii, name), '__call__'))
self.assertRaises(TypeError, getattr(binascii, name)) self.assertRaises(TypeError, getattr(binascii, name))
def test_returned_value(self):
# Limit to the minimum of all limits (b2a_uu)
MAX_ALL = 45
raw = self.rawdata[:MAX_ALL]
for fa, fb in zip(a2b_functions, b2a_functions):
a2b = getattr(binascii, fa)
b2a = getattr(binascii, fb)
try:
a = b2a(self.type2test(raw))
res = a2b(self.type2test(a))
except Exception as err:
self.fail("{}/{} conversion raises {!r}".format(fb, fa, err))
if fb == 'b2a_hqx':
# b2a_hqx returns a tuple
res, _ = res
self.assertEqual(res, raw, "{}/{} conversion: "
"{!r} != {!r}".format(fb, fa, res, raw))
self.assertIsInstance(res, bytes)
self.assertIsInstance(a, bytes)
self.assertLess(max(c for c in a), 128)
self.assertIsInstance(binascii.crc_hqx(raw, 0), int)
self.assertIsInstance(binascii.crc32(raw), int)
def test_base64valid(self): def test_base64valid(self):
# Test base64 with valid data # Test base64 with valid data
MAX_BASE64 = 57 MAX_BASE64 = 57
lines = [] lines = []
for i in range(0, len(self.data), MAX_BASE64): for i in range(0, len(self.rawdata), MAX_BASE64):
b = self.data[i:i+MAX_BASE64] b = self.type2test(self.rawdata[i:i+MAX_BASE64])
a = binascii.b2a_base64(b) a = binascii.b2a_base64(b)
lines.append(a) lines.append(a)
res = bytes() res = bytes()
for line in lines: for line in lines:
b = binascii.a2b_base64(line) a = self.type2test(line)
b = binascii.a2b_base64(a)
res += b res += b
self.assertEqual(res, self.rawdata) self.assertEqual(res, self.rawdata)
...@@ -57,7 +80,7 @@ class BinASCIITest(unittest.TestCase): ...@@ -57,7 +80,7 @@ class BinASCIITest(unittest.TestCase):
MAX_BASE64 = 57 MAX_BASE64 = 57
lines = [] lines = []
for i in range(0, len(self.data), MAX_BASE64): for i in range(0, len(self.data), MAX_BASE64):
b = self.data[i:i+MAX_BASE64] b = self.type2test(self.rawdata[i:i+MAX_BASE64])
a = binascii.b2a_base64(b) a = binascii.b2a_base64(b)
lines.append(a) lines.append(a)
...@@ -79,24 +102,26 @@ class BinASCIITest(unittest.TestCase): ...@@ -79,24 +102,26 @@ class BinASCIITest(unittest.TestCase):
return res + noise + line return res + noise + line
res = bytearray() res = bytearray()
for line in map(addnoise, lines): for line in map(addnoise, lines):
b = binascii.a2b_base64(line) a = self.type2test(line)
b = binascii.a2b_base64(a)
res += b res += b
self.assertEqual(res, self.rawdata) self.assertEqual(res, self.rawdata)
# Test base64 with just invalid characters, which should return # Test base64 with just invalid characters, which should return
# empty strings. TBD: shouldn't it raise an exception instead ? # empty strings. TBD: shouldn't it raise an exception instead ?
self.assertEqual(binascii.a2b_base64(fillers), b'') self.assertEqual(binascii.a2b_base64(self.type2test(fillers)), b'')
def test_uu(self): def test_uu(self):
MAX_UU = 45 MAX_UU = 45
lines = [] lines = []
for i in range(0, len(self.data), MAX_UU): for i in range(0, len(self.data), MAX_UU):
b = self.data[i:i+MAX_UU] b = self.type2test(self.rawdata[i:i+MAX_UU])
a = binascii.b2a_uu(b) a = binascii.b2a_uu(b)
lines.append(a) lines.append(a)
res = bytes() res = bytes()
for line in lines: for line in lines:
b = binascii.a2b_uu(line) a = self.type2test(line)
b = binascii.a2b_uu(a)
res += b res += b
self.assertEqual(res, self.rawdata) self.assertEqual(res, self.rawdata)
...@@ -112,19 +137,27 @@ class BinASCIITest(unittest.TestCase): ...@@ -112,19 +137,27 @@ class BinASCIITest(unittest.TestCase):
self.assertEqual(binascii.b2a_uu(b'x'), b'!> \n') self.assertEqual(binascii.b2a_uu(b'x'), b'!> \n')
def test_crc32(self): def test_crc32(self):
crc = binascii.crc32(b"Test the CRC-32 of") crc = binascii.crc32(self.type2test(b"Test the CRC-32 of"))
crc = binascii.crc32(b" this string.", crc) crc = binascii.crc32(self.type2test(b" this string."), crc)
self.assertEqual(crc, 1571220330) self.assertEqual(crc, 1571220330)
self.assertRaises(TypeError, binascii.crc32) self.assertRaises(TypeError, binascii.crc32)
# The hqx test is in test_binhex.py def test_hqx(self):
# Perform binhex4 style RLE-compression
# Then calculate the hexbin4 binary-to-ASCII translation
rle = binascii.rlecode_hqx(self.data)
a = binascii.b2a_hqx(self.type2test(rle))
b, _ = binascii.a2b_hqx(self.type2test(a))
res = binascii.rledecode_hqx(b)
self.assertEqual(res, self.rawdata)
def test_hex(self): def test_hex(self):
# test hexlification # test hexlification
s = b'{s\005\000\000\000worldi\002\000\000\000s\005\000\000\000helloi\001\000\000\0000' s = b'{s\005\000\000\000worldi\002\000\000\000s\005\000\000\000helloi\001\000\000\0000'
t = binascii.b2a_hex(s) t = binascii.b2a_hex(self.type2test(s))
u = binascii.a2b_hex(t) u = binascii.a2b_hex(self.type2test(t))
self.assertEqual(s, u) self.assertEqual(s, u)
self.assertRaises(binascii.Error, binascii.a2b_hex, t[:-1]) self.assertRaises(binascii.Error, binascii.a2b_hex, t[:-1])
self.assertRaises(binascii.Error, binascii.a2b_hex, t[:-1] + b'q') self.assertRaises(binascii.Error, binascii.a2b_hex, t[:-1] + b'q')
...@@ -165,16 +198,17 @@ class BinASCIITest(unittest.TestCase): ...@@ -165,16 +198,17 @@ class BinASCIITest(unittest.TestCase):
def test_empty_string(self): def test_empty_string(self):
# A test for SF bug #1022953. Make sure SystemError is not raised. # A test for SF bug #1022953. Make sure SystemError is not raised.
for n in ['b2a_qp', 'a2b_hex', 'b2a_base64', 'a2b_uu', 'a2b_qp', empty = self.type2test(b'')
'b2a_hex', 'unhexlify', 'hexlify', 'crc32', 'b2a_hqx', for func in all_functions:
'a2b_hqx', 'a2b_base64', 'rlecode_hqx', 'b2a_uu', if func == 'crc_hqx':
'rledecode_hqx']: # crc_hqx needs 2 arguments
f = getattr(binascii, n) binascii.crc_hqx(empty, 0)
continue
f = getattr(binascii, func)
try: try:
f(b'') f(empty)
except SystemError as err: except Exception as err:
self.fail("%s(b'') raises SystemError: %s" % (n, err)) self.fail("{}({!r}) raises {!r}".format(func, empty, err))
binascii.crc_hqx(b'', 0)
def test_no_binary_strings(self): def test_no_binary_strings(self):
# b2a_ must not accept strings # b2a_ must not accept strings
...@@ -190,6 +224,10 @@ class ArrayBinASCIITest(BinASCIITest): ...@@ -190,6 +224,10 @@ class ArrayBinASCIITest(BinASCIITest):
return array.array('B', list(s)) return array.array('B', list(s))
class BytearrayBinASCIITest(BinASCIITest):
type2test = bytearray
class MemoryviewBinASCIITest(BinASCIITest): class MemoryviewBinASCIITest(BinASCIITest):
type2test = memoryview type2test = memoryview
...@@ -197,6 +235,7 @@ class MemoryviewBinASCIITest(BinASCIITest): ...@@ -197,6 +235,7 @@ class MemoryviewBinASCIITest(BinASCIITest):
def test_main(): def test_main():
support.run_unittest(BinASCIITest, support.run_unittest(BinASCIITest,
ArrayBinASCIITest, ArrayBinASCIITest,
BytearrayBinASCIITest,
MemoryviewBinASCIITest) MemoryviewBinASCIITest)
if __name__ == "__main__": if __name__ == "__main__":
......
...@@ -213,6 +213,9 @@ C-API ...@@ -213,6 +213,9 @@ C-API
Library Library
------- -------
- Issue #7703: Add support for the new buffer API to `binascii.a2bhqx`.
Patch by Florent Xicluna, along with some additional tests.
- Issue #7701: Fix crash in binascii.b2a_uu() in debug mode when given a - Issue #7701: Fix crash in binascii.b2a_uu() in debug mode when given a
1-byte argument. Patch by Victor Stinner. 1-byte argument. Patch by Victor Stinner.
......
...@@ -537,6 +537,7 @@ PyDoc_STRVAR(doc_a2b_hqx, "ascii -> bin, done. Decode .hqx coding"); ...@@ -537,6 +537,7 @@ PyDoc_STRVAR(doc_a2b_hqx, "ascii -> bin, done. Decode .hqx coding");
static PyObject * static PyObject *
binascii_a2b_hqx(PyObject *self, PyObject *args) binascii_a2b_hqx(PyObject *self, PyObject *args)
{ {
Py_buffer pascii;
unsigned char *ascii_data, *bin_data; unsigned char *ascii_data, *bin_data;
int leftbits = 0; int leftbits = 0;
unsigned char this_ch; unsigned char this_ch;
...@@ -545,19 +546,26 @@ binascii_a2b_hqx(PyObject *self, PyObject *args) ...@@ -545,19 +546,26 @@ binascii_a2b_hqx(PyObject *self, PyObject *args)
Py_ssize_t len; Py_ssize_t len;
int done = 0; int done = 0;
if ( !PyArg_ParseTuple(args, "t#:a2b_hqx", &ascii_data, &len) ) if ( !PyArg_ParseTuple(args, "s*:a2b_hqx", &pascii) )
return NULL; return NULL;
ascii_data = pascii.buf;
len = pascii.len;
assert(len >= 0); assert(len >= 0);
if (len > PY_SSIZE_T_MAX - 2) if (len > PY_SSIZE_T_MAX - 2) {
PyBuffer_Release(&pascii);
return PyErr_NoMemory(); return PyErr_NoMemory();
}
/* Allocate a string that is too big (fixed later) /* Allocate a string that is too big (fixed later)
Add two to the initial length to prevent interning which Add two to the initial length to prevent interning which
would preclude subsequent resizing. */ would preclude subsequent resizing. */
if ( (rv=PyBytes_FromStringAndSize(NULL, len+2)) == NULL ) if ( (rv=PyBytes_FromStringAndSize(NULL, len+2)) == NULL )
if ( (rv=PyBytes_FromStringAndSize(NULL, len+2)) == NULL ) {
PyBuffer_Release(&pascii);
return NULL; return NULL;
}
bin_data = (unsigned char *)PyBytes_AS_STRING(rv); bin_data = (unsigned char *)PyBytes_AS_STRING(rv);
for( ; len > 0 ; len--, ascii_data++ ) { for( ; len > 0 ; len--, ascii_data++ ) {
...@@ -567,6 +575,7 @@ binascii_a2b_hqx(PyObject *self, PyObject *args) ...@@ -567,6 +575,7 @@ binascii_a2b_hqx(PyObject *self, PyObject *args)
continue; continue;
if ( this_ch == FAIL ) { if ( this_ch == FAIL ) {
PyErr_SetString(Error, "Illegal char"); PyErr_SetString(Error, "Illegal char");
PyBuffer_Release(&pascii);
Py_DECREF(rv); Py_DECREF(rv);
return NULL; return NULL;
} }
...@@ -589,6 +598,7 @@ binascii_a2b_hqx(PyObject *self, PyObject *args) ...@@ -589,6 +598,7 @@ binascii_a2b_hqx(PyObject *self, PyObject *args)
if ( leftbits && !done ) { if ( leftbits && !done ) {
PyErr_SetString(Incomplete, PyErr_SetString(Incomplete,
"String has incomplete number of bytes"); "String has incomplete number of bytes");
PyBuffer_Release(&pascii);
Py_DECREF(rv); Py_DECREF(rv);
return NULL; return NULL;
} }
...@@ -600,10 +610,12 @@ binascii_a2b_hqx(PyObject *self, PyObject *args) ...@@ -600,10 +610,12 @@ binascii_a2b_hqx(PyObject *self, PyObject *args)
} }
if (rv) { if (rv) {
PyObject *rrv = Py_BuildValue("Oi", rv, done); PyObject *rrv = Py_BuildValue("Oi", rv, done);
PyBuffer_Release(&pascii);
Py_DECREF(rv); Py_DECREF(rv);
return rrv; return rrv;
} }
PyBuffer_Release(&pascii);
return NULL; return NULL;
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment