Skip to content

Commit 06d1bb9

Browse files
committed
corner cases tests and fixes
1 parent 36234db commit 06d1bb9

File tree

3 files changed

+140
-15
lines changed

3 files changed

+140
-15
lines changed

cbitstruct/_cbitstruct.c

+11-14
Original file line numberDiff line numberDiff line change
@@ -605,10 +605,7 @@ static PyObject* parsed_elements_to_python(ParsedElement* elements, CompiledForm
605605
};
606606

607607
if (!v) {
608-
if (!PyErr_Occurred()) {
609-
// Set our own exception
610-
PyErr_SetString(PyExc_TypeError, "to-python conversion error");
611-
}
608+
// An exception has been set
612609
Py_DECREF(result);
613610
return NULL;
614611
}
@@ -650,9 +647,9 @@ static Py_ssize_t PyArg_ParseTupleAndKeywordsFirstN(
650647

651648
if (PyArg_VaParseTupleAndKeywords(
652649
actual_args, kwargs, format, keywords, varargs)) {
650+
return_value = n_actual_args;
653651
}
654652
Py_DECREF(actual_args);
655-
return_value = n_actual_args;
656653

657654
exit:
658655
va_end(varargs);
@@ -1689,13 +1686,6 @@ byteswap_impl(PyObject *module, PyObject *fmt, Py_buffer *data,
16891686
goto exit;
16901687
}
16911688

1692-
return_value = PyBytes_FromStringAndSize(
1693-
((const char*)data->buf) + offset, data->len - offset);
1694-
if (!return_value) {
1695-
PyErr_NoMemory();
1696-
goto exit;
1697-
}
1698-
16991689
count_iter = PyMem_RawMalloc(length * sizeof(int));
17001690
if (!count_iter) {
17011691
PyErr_NoMemory();
@@ -1727,21 +1717,28 @@ byteswap_impl(PyObject *module, PyObject *fmt, Py_buffer *data,
17271717
}
17281718
}
17291719

1730-
if (sum > PyBytes_Size(return_value)) {
1720+
if (sum > data->len) {
17311721
PyErr_Format(
17321722
PyExc_TypeError,
17331723
"byteswap() requires a buffer of at least %d bytes",
17341724
sum);
17351725
goto exit;
17361726
}
17371727

1738-
uint8_t* buf = (uint8_t*)PyBytes_AS_STRING(return_value);
1728+
uint8_t* buf = (uint8_t*)data->buf + offset;
17391729
for (int i = 0; i < length; ++i) {
17401730
int nbytes = count_iter[i];
17411731
c_byteswitch(buf, nbytes);
17421732
buf += nbytes;
17431733
}
17441734

1735+
return_value = PyBytes_FromStringAndSize(
1736+
((const char*)data->buf) + offset, data->len - offset);
1737+
if (!return_value) {
1738+
PyErr_NoMemory();
1739+
goto exit;
1740+
}
1741+
17451742
exit:
17461743
if (count_iter) {
17471744
PyMem_RawFree(count_iter);

cbitstruct/tests/test_cornercase.py

+128
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
import unittest
2+
import cbitstruct
3+
4+
5+
NAMES = ["foo"]
6+
FMT = "u32"
7+
DICT = {"foo": 42}
8+
9+
10+
class BitstructApiTest(unittest.TestCase):
11+
def test_no_args(self):
12+
self.assertRaises(Exception, cbitstruct.CompiledFormat)
13+
self.assertRaises(Exception, cbitstruct.CompiledFormatDict)
14+
self.assertRaises(Exception, cbitstruct.compile)
15+
16+
def test_not_unicode(self):
17+
self.assertRaises(UnicodeDecodeError, cbitstruct.unpack, "t8", b"\xff")
18+
19+
def test_unpack_too_small(self):
20+
self.assertRaises(TypeError, cbitstruct.unpack, FMT, b"")
21+
22+
def test_unpack_bad_args(self):
23+
self.assertRaises(TypeError, cbitstruct.unpack)
24+
self.assertRaises(TypeError, cbitstruct.unpack, None)
25+
self.assertRaises(TypeError, cbitstruct.unpack, FMT)
26+
self.assertRaises(TypeError, cbitstruct.unpack, FMT, None)
27+
self.assertRaises(TypeError, cbitstruct.unpack, None, bytes(4))
28+
29+
def test_unpack_dict_too_small(self):
30+
self.assertRaises(TypeError, cbitstruct.unpack_dict, FMT, NAMES, b"")
31+
32+
def test_unpack_dict_bad_args(self):
33+
self.assertRaises(TypeError, cbitstruct.unpack_dict)
34+
self.assertRaises(TypeError, cbitstruct.unpack_dict, None)
35+
self.assertRaises(TypeError, cbitstruct.unpack_dict, FMT, None)
36+
self.assertRaises(TypeError, cbitstruct.unpack_dict, FMT, NAMES, None)
37+
self.assertRaises(TypeError, cbitstruct.unpack_dict, None, NAMES, bytes(4))
38+
self.assertRaises(
39+
TypeError, cbitstruct.unpack_dict, FMT, NAMES + ["extra"], bytes(4)
40+
)
41+
42+
def test_unpack_from_too_small(self):
43+
self.assertRaises(TypeError, cbitstruct.unpack_from, FMT, b"")
44+
45+
def test_unpack_from_bad_args(self):
46+
self.assertRaises(TypeError, cbitstruct.unpack_from)
47+
self.assertRaises(TypeError, cbitstruct.unpack_from, FMT)
48+
self.assertRaises(TypeError, cbitstruct.unpack_from, None, bytes(4))
49+
self.assertRaises(TypeError, cbitstruct.unpack_from, FMT, None)
50+
51+
def test_unpack_from_dict_too_small(self):
52+
self.assertRaises(TypeError, cbitstruct.unpack_from_dict, FMT, NAMES, b"")
53+
54+
def test_unpack_from_dict_bad_args(self):
55+
self.assertRaises(TypeError, cbitstruct.unpack_from_dict)
56+
self.assertRaises(TypeError, cbitstruct.unpack_from_dict, FMT)
57+
self.assertRaises(TypeError, cbitstruct.unpack_from_dict, FMT, None)
58+
self.assertRaises(TypeError, cbitstruct.unpack_from_dict, None, NAMES)
59+
self.assertRaises(TypeError, cbitstruct.unpack_from_dict, FMT, None, bytes(4))
60+
self.assertRaises(TypeError, cbitstruct.unpack_from_dict, None, NAMES, bytes(4))
61+
self.assertRaises(
62+
TypeError, cbitstruct.unpack_from_dict, "g32", NAMES, bytes(4)
63+
)
64+
self.assertRaises(
65+
TypeError, cbitstruct.unpack_from_dict, FMT, NAMES + ["extra"], bytes(4)
66+
)
67+
self.assertRaises(TypeError, cbitstruct.unpack_from_dict, FMT, NAMES, None)
68+
69+
def test_pack_bad_args(self):
70+
self.assertRaises(TypeError, cbitstruct.pack)
71+
self.assertRaises(TypeError, cbitstruct.pack, 0)
72+
73+
def test_pack_into_too_small(self):
74+
self.assertRaises(TypeError, cbitstruct.pack_into, FMT, b"", 12)
75+
76+
def test_pack_into_bad_args(self):
77+
self.assertRaises(TypeError, cbitstruct.pack_into)
78+
self.assertRaises(TypeError, cbitstruct.pack_into, FMT)
79+
self.assertRaises(TypeError, cbitstruct.pack_into, FMT, bytes(4))
80+
self.assertRaises(TypeError, cbitstruct.pack_into, FMT, bytes(4), 0)
81+
self.assertRaises(TypeError, cbitstruct.pack_into, None, bytes(4), 0, 12)
82+
self.assertRaises(TypeError, cbitstruct.pack_into, "g32", bytes(4), 0, 12)
83+
84+
def test_pack_into_dict_too_small(self):
85+
self.assertRaises(
86+
TypeError, cbitstruct.pack_into_dict, FMT, NAMES, bytes(0), 0, DICT
87+
)
88+
89+
def test_pack_into_dict_bad_args(self):
90+
self.assertRaises(TypeError, cbitstruct.pack_into_dict)
91+
self.assertRaises(TypeError, cbitstruct.pack_into_dict, FMT)
92+
self.assertRaises(TypeError, cbitstruct.pack_into_dict, FMT, None)
93+
self.assertRaises(TypeError, cbitstruct.pack_into_dict, None, NAMES)
94+
self.assertRaises(TypeError, cbitstruct.pack_into_dict, FMT, NAMES, bytes(4), 0)
95+
self.assertRaises(
96+
TypeError, cbitstruct.pack_into_dict, FMT, None, bytes(4), 0, DICT
97+
)
98+
self.assertRaises(
99+
TypeError, cbitstruct.pack_into_dict, None, NAMES, bytes(4), 0, DICT
100+
)
101+
self.assertRaises(
102+
TypeError, cbitstruct.pack_into_dict, "g32", NAMES, bytes(4), 0, DICT
103+
)
104+
105+
def test_pack_dict_bad_args(self):
106+
self.assertRaises(TypeError, cbitstruct.pack_dict)
107+
self.assertRaises(TypeError, cbitstruct.pack_dict, FMT)
108+
self.assertRaises(TypeError, cbitstruct.pack_dict, FMT, None)
109+
self.assertRaises(TypeError, cbitstruct.pack_dict, None, NAMES)
110+
self.assertRaises(TypeError, cbitstruct.pack_dict, FMT, NAMES)
111+
self.assertRaises(TypeError, cbitstruct.pack_dict, FMT, None, DICT)
112+
self.assertRaises(TypeError, cbitstruct.pack_dict, None, NAMES, DICT)
113+
self.assertRaises(TypeError, cbitstruct.pack_dict, "g32", NAMES, DICT)
114+
115+
def test_byteswap_bad_args(self):
116+
self.assertRaises(TypeError, cbitstruct.byteswap, "23", b"")
117+
self.assertRaises(TypeError, cbitstruct.byteswap, None, b"\xff")
118+
self.assertRaises(TypeError, cbitstruct.byteswap, "23")
119+
self.assertRaises(TypeError, cbitstruct.byteswap)
120+
121+
def test_calcsize_bad_args(self):
122+
self.assertRaises(TypeError, cbitstruct.calcsize, "g32")
123+
self.assertRaises(TypeError, cbitstruct.calcsize, None)
124+
self.assertRaises(TypeError, cbitstruct.calcsize)
125+
126+
127+
if __name__ == "__main__":
128+
unittest.main()

setup.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525

2626
setup(
2727
name="cbitstruct",
28-
version="1.0.1",
28+
version="1.0.2",
2929
author="Quentin CHATEAU",
3030
author_email="[email protected]",
3131
license="GPLv3",

0 commit comments

Comments
 (0)