Skip to content

Commit 2f62ff7

Browse files
authored
Increase test coverage (#144)
Work towards 100% code coverage in unit tests, fix segfaults encountered
1 parent befaddb commit 2f62ff7

File tree

12 files changed

+548
-64
lines changed

12 files changed

+548
-64
lines changed

.travis.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ install:
4040
- pip list
4141
script: coverage run -m pytest -v tests --color=yes
4242
after_success:
43-
- lcov --capture --directory . --output-file coverage.info
43+
- lcov --capture --no-external --directory . --output-file coverage.info
4444
- lcov --list coverage.info
4545
- bash <(curl -s https://codecov.io/bash) -f coverage.info
4646
before_deploy:

src/ds.c

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,11 +87,21 @@ static int PyXmlSec_SignatureContextKeySet(PyObject* self, PyObject* value, void
8787
PyXmlSec_Key* key;
8888

8989
PYXMLSEC_DEBUGF("%p, %p", self, value);
90+
91+
if (value == NULL) { // key deletion
92+
if (ctx->handle->signKey != NULL) {
93+
xmlSecKeyDestroy(ctx->handle->signKey);
94+
ctx->handle->signKey = NULL;
95+
}
96+
return 0;
97+
}
98+
9099
if (!PyObject_IsInstance(value, (PyObject*)PyXmlSec_KeyType)) {
91100
PyErr_SetString(PyExc_TypeError, "instance of *xmlsec.Key* expected.");
92101
return -1;
93102
}
94103
key = (PyXmlSec_Key*)value;
104+
95105
if (key->handle == NULL) {
96106
PyErr_SetString(PyExc_TypeError, "empty key.");
97107
return -1;
@@ -252,6 +262,7 @@ static int PyXmlSec_ProcessSignBinary(PyXmlSec_SignatureContext* ctx, const xmlS
252262

253263
if (ctx->handle->signKey == NULL) {
254264
PyErr_SetString(PyXmlSec_Error, "Sign key is not specified.");
265+
return -1;
255266
}
256267

257268
if (ctx->handle->signMethod != NULL) {

src/enc.c

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,15 @@ static int PyXmlSec_EncryptionContextKeySet(PyObject* self, PyObject* value, voi
9090
PyXmlSec_Key* key;
9191

9292
PYXMLSEC_DEBUGF("%p, %p", self, value);
93+
94+
if (value == NULL) { // key deletion
95+
if (ctx->handle->encKey != NULL) {
96+
xmlSecKeyDestroy(ctx->handle->encKey);
97+
ctx->handle->encKey = NULL;
98+
}
99+
return 0;
100+
}
101+
93102
if (!PyObject_IsInstance(value, (PyObject*)PyXmlSec_KeyType)) {
94103
PyErr_SetString(PyExc_TypeError, "instance of *xmlsec.Key* expected.");
95104
return -1;
@@ -224,7 +233,7 @@ static PyObject* PyXmlSec_EncryptionContextEncryptXml(PyObject* self, PyObject*
224233
}
225234
tmpType = xmlGetProp(template->_c_node, XSTR("Type"));
226235
if (tmpType == NULL || !(xmlStrEqual(tmpType, xmlSecTypeEncElement) || xmlStrEqual(tmpType, xmlSecTypeEncContent))) {
227-
PyErr_SetString(PyXmlSec_Error, "unsupported `Type`, it should be `element` or `content`)");
236+
PyErr_SetString(PyXmlSec_Error, "unsupported `Type`, it should be `element` or `content`");
228237
goto ON_FAIL;
229238
}
230239

src/keys.c

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -452,10 +452,21 @@ static int PyXmlSec_KeyNameSet(PyObject* self, PyObject* value, void* closure) {
452452
return -1;
453453
}
454454

455+
if (value == NULL) {
456+
if (xmlSecKeySetName(key->handle, value) < 0) {
457+
PyXmlSec_SetLastError("cannot delete name");
458+
return -1;
459+
}
460+
return 0;
461+
}
462+
455463
name = PyString_AsString(value);
456464
if (name == NULL) return -1;
457465

458-
xmlSecKeySetName(key->handle, XSTR(name));
466+
if (xmlSecKeySetName(key->handle, XSTR(name)) < 0) {
467+
PyXmlSec_SetLastError("cannot set name");
468+
return -1;
469+
}
459470
return 0;
460471
}
461472

tests/base.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@
77

88
import unittest
99

10+
if sys.version_info < (3, ):
11+
unittest.TestCase.assertRaisesRegex = unittest.TestCase.assertRaisesRegexp
12+
1013

1114
etype = type(etree.Element("test"))
1215

tests/conftest.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
def pytest_collection_modifyitems(items):
2+
"""
3+
Put the module init test first to implicitly check whether
4+
any subsequent test fails because of module reinitialization.
5+
"""
6+
7+
def module_init_tests_first(item):
8+
return int('test_xmlsec.py::TestModule::test_reinitialize_module' not in item.nodeid)
9+
10+
items.sort(key=module_init_tests_first)

tests/test_ds.py

Lines changed: 142 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
1-
from tests import base
2-
31
import xmlsec
4-
2+
from tests import base
53

64
consts = xmlsec.constants
75

@@ -11,18 +9,69 @@ def test_init(self):
119
ctx = xmlsec.SignatureContext(manager=xmlsec.KeysManager())
1210
del ctx
1311

14-
def test_key(self):
12+
def test_init_no_keys_manager(self):
13+
ctx = xmlsec.SignatureContext()
14+
del ctx
15+
16+
def test_init_bad_args(self):
17+
with self.assertRaisesRegex(TypeError, 'KeysManager required'):
18+
xmlsec.SignatureContext(manager='foo')
19+
20+
def test_no_key(self):
1521
ctx = xmlsec.SignatureContext(manager=xmlsec.KeysManager())
1622
self.assertIsNone(ctx.key)
23+
24+
def test_del_key(self):
25+
ctx = xmlsec.SignatureContext(manager=xmlsec.KeysManager())
26+
ctx.key = xmlsec.Key.from_file(self.path("rsakey.pem"), format=consts.KeyDataFormatPem)
27+
del ctx.key
28+
self.assertIsNone(ctx.key)
29+
30+
def test_set_key(self):
31+
ctx = xmlsec.SignatureContext(manager=xmlsec.KeysManager())
1732
ctx.key = xmlsec.Key.from_file(self.path("rsakey.pem"), format=consts.KeyDataFormatPem)
1833
self.assertIsNotNone(ctx.key)
1934

35+
def test_set_key_bad_type(self):
36+
ctx = xmlsec.SignatureContext(manager=xmlsec.KeysManager())
37+
with self.assertRaisesRegex(TypeError, r'instance of \*xmlsec.Key\* expected.'):
38+
ctx.key = ''
39+
40+
def test_set_invalid_key(self):
41+
ctx = xmlsec.SignatureContext(manager=xmlsec.KeysManager())
42+
with self.assertRaisesRegex(TypeError, 'empty key.'):
43+
ctx.key = xmlsec.Key()
44+
2045
def test_register_id(self):
2146
ctx = xmlsec.SignatureContext()
2247
root = self.load_xml("sign_template.xml")
2348
sign = xmlsec.template.create(root, consts.TransformExclC14N, consts.TransformRsaSha1, "Id")
2449
ctx.register_id(sign, "Id")
2550

51+
def test_register_id_bad_args(self):
52+
ctx = xmlsec.SignatureContext()
53+
with self.assertRaises(TypeError):
54+
ctx.register_id('')
55+
56+
def test_register_id_with_namespace_without_attribute(self):
57+
ctx = xmlsec.SignatureContext()
58+
root = self.load_xml("sign_template.xml")
59+
sign = xmlsec.template.create(root, consts.TransformExclC14N, consts.TransformRsaSha1, "Id")
60+
with self.assertRaisesRegex(xmlsec.Error, 'missing attribute.'):
61+
ctx.register_id(sign, "Id", id_ns='foo')
62+
63+
def test_sign_bad_args(self):
64+
ctx = xmlsec.SignatureContext()
65+
ctx.key = xmlsec.Key.from_file(self.path("rsakey.pem"), format=consts.KeyDataFormatPem)
66+
with self.assertRaises(TypeError):
67+
ctx.sign('')
68+
69+
def test_sign_fail(self):
70+
ctx = xmlsec.SignatureContext()
71+
ctx.key = xmlsec.Key.from_file(self.path("rsakey.pem"), format=consts.KeyDataFormatPem)
72+
with self.assertRaisesRegex(xmlsec.InternalError, 'failed to sign'):
73+
ctx.sign(self.load_xml('sign1-in.xml'))
74+
2675
def test_sign_case1(self):
2776
"""Should sign a pre-constructed template file using a key from a PEM file."""
2877
root = self.load_xml("sign1-in.xml")
@@ -134,6 +183,23 @@ def test_sign_case5(self):
134183
ctx.sign(sign)
135184
self.assertEqual(self.load_xml("sign5-out.xml"), root)
136185

186+
def test_sign_binary_bad_args(self):
187+
ctx = xmlsec.SignatureContext()
188+
ctx.key = xmlsec.Key.from_file(self.path("rsakey.pem"), format=consts.KeyDataFormatPem)
189+
with self.assertRaises(TypeError):
190+
ctx.sign_binary(bytes=1, transform='')
191+
192+
def test_sign_binary_no_key(self):
193+
ctx = xmlsec.SignatureContext()
194+
with self.assertRaisesRegex(xmlsec.Error, 'Sign key is not specified.'):
195+
ctx.sign_binary(bytes=b'', transform=consts.TransformRsaSha1)
196+
197+
def test_sign_binary_invalid_signature_method(self):
198+
ctx = xmlsec.SignatureContext()
199+
ctx.key = xmlsec.Key.from_file(self.path("rsakey.pem"), format=consts.KeyDataFormatPem)
200+
with self.assertRaisesRegex(xmlsec.Error, 'incompatible signature method'):
201+
ctx.sign_binary(bytes=b'', transform=consts.TransformXslt)
202+
137203
def test_sign_binary(self):
138204
ctx = xmlsec.SignatureContext()
139205
ctx.key = xmlsec.Key.from_file(self.path("rsakey.pem"), format=consts.KeyDataFormatPem)
@@ -144,6 +210,26 @@ def test_sign_binary(self):
144210
sign = ctx.sign_binary(self.load("sign6-in.bin"), consts.TransformRsaSha1)
145211
self.assertEqual(self.load("sign6-out.bin"), sign)
146212

213+
def test_sign_binary_twice_not_possible(self):
214+
ctx = xmlsec.SignatureContext()
215+
ctx.key = xmlsec.Key.from_file(self.path("rsakey.pem"), format=consts.KeyDataFormatPem)
216+
data = self.load('sign6-in.bin')
217+
ctx.sign_binary(data, consts.TransformRsaSha1)
218+
with self.assertRaisesRegex(xmlsec.Error, 'Signature context already used; it is designed for one use only.'):
219+
ctx.sign_binary(data, consts.TransformRsaSha1)
220+
221+
def test_verify_bad_args(self):
222+
ctx = xmlsec.SignatureContext()
223+
ctx.key = xmlsec.Key.from_file(self.path("rsakey.pem"), format=consts.KeyDataFormatPem)
224+
with self.assertRaises(TypeError):
225+
ctx.verify('')
226+
227+
def test_verify_fail(self):
228+
ctx = xmlsec.SignatureContext()
229+
ctx.key = xmlsec.Key.from_file(self.path("rsakey.pem"), format=consts.KeyDataFormatPem)
230+
with self.assertRaisesRegex(xmlsec.InternalError, 'failed to verify'):
231+
ctx.verify(self.load_xml('sign1-in.xml'))
232+
147233
def test_verify_case_1(self):
148234
self.check_verify(1)
149235

@@ -191,3 +277,55 @@ def test_validate_binary_sign_fail(self):
191277
self.assertEqual("rsakey.pem", ctx.key.name)
192278
with self.assertRaises(xmlsec.Error):
193279
ctx.verify_binary(self.load("sign6-in.bin"), consts.TransformRsaSha1, b"invalid")
280+
281+
def test_enable_reference_transform(self):
282+
ctx = xmlsec.SignatureContext()
283+
ctx.key = xmlsec.Key.from_file(self.path("rsakey.pem"), format=consts.KeyDataFormatPem)
284+
ctx.enable_reference_transform(consts.TransformRsaSha1)
285+
286+
def test_enable_reference_transform_bad_args(self):
287+
ctx = xmlsec.SignatureContext()
288+
ctx.key = xmlsec.Key.from_file(self.path('rsakey.pem'), format=consts.KeyDataFormatPem)
289+
with self.assertRaises(TypeError):
290+
ctx.enable_reference_transform('')
291+
with self.assertRaises(TypeError):
292+
ctx.enable_reference_transform(0)
293+
with self.assertRaises(TypeError):
294+
ctx.enable_reference_transform(consts.KeyDataAes)
295+
296+
def test_enable_signature_transform(self):
297+
ctx = xmlsec.SignatureContext()
298+
ctx.key = xmlsec.Key.from_file(self.path("rsakey.pem"), format=consts.KeyDataFormatPem)
299+
ctx.enable_signature_transform(consts.TransformRsaSha1)
300+
301+
def test_enable_signature_transform_bad_args(self):
302+
ctx = xmlsec.SignatureContext()
303+
ctx.key = xmlsec.Key.from_file(self.path('rsakey.pem'), format=consts.KeyDataFormatPem)
304+
with self.assertRaises(TypeError):
305+
ctx.enable_signature_transform('')
306+
with self.assertRaises(TypeError):
307+
ctx.enable_signature_transform(0)
308+
with self.assertRaises(TypeError):
309+
ctx.enable_signature_transform(consts.KeyDataAes)
310+
311+
def test_set_enabled_key_data(self):
312+
ctx = xmlsec.SignatureContext()
313+
ctx.key = xmlsec.Key.from_file(self.path("rsakey.pem"), format=consts.KeyDataFormatPem)
314+
ctx.set_enabled_key_data([consts.KeyDataAes])
315+
316+
def test_set_enabled_key_data_empty(self):
317+
ctx = xmlsec.SignatureContext()
318+
ctx.key = xmlsec.Key.from_file(self.path("rsakey.pem"), format=consts.KeyDataFormatPem)
319+
ctx.set_enabled_key_data([])
320+
321+
def test_set_enabled_key_data_bad_args(self):
322+
ctx = xmlsec.SignatureContext()
323+
ctx.key = xmlsec.Key.from_file(self.path('rsakey.pem'), format=consts.KeyDataFormatPem)
324+
with self.assertRaises(TypeError):
325+
ctx.set_enabled_key_data(0)
326+
327+
def test_set_enabled_key_data_bad_list(self):
328+
ctx = xmlsec.SignatureContext()
329+
ctx.key = xmlsec.Key.from_file(self.path('rsakey.pem'), format=consts.KeyDataFormatPem)
330+
with self.assertRaisesRegex(TypeError, 'expected list of KeyData constants.'):
331+
ctx.set_enabled_key_data('foo')

0 commit comments

Comments
 (0)