Skip to content
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
73 changes: 68 additions & 5 deletions Lib/test/test_capi/test_sys.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,6 @@
NULL = None

class CAPITest(unittest.TestCase):
# TODO: Test the following functions:
#
# PySys_Audit()
# PySys_AuditTuple()

maxDiff = None

@unittest.skipIf(_testlimitedcapi is None, 'need _testlimitedcapi module')
Expand Down Expand Up @@ -211,6 +206,74 @@ def test_sys_writestderr(self):
# Test PySys_WriteStderr()
self._test_sys_writestream('PySys_WriteStderr', 'stderr')

@unittest.skipIf(_testlimitedcapi is None, 'need _testlimitedcapi module')
def test_sys_audit(self):
# Test PySys_Audit()
sys_audit = _testlimitedcapi.sys_audit
audit_events = []
def audit_hook(event, args):
audit_events.append((event, args))
return None

sys.addaudithook(audit_hook)
try:
result = sys_audit("test.event", "OO", 1, "a")
self.assertEqual(result, 0)
self.assertEqual(audit_events[-1][0], "test.event")
self.assertEqual(audit_events[-1][1], (1, "a"))

result = sys_audit("test.no_args", "")
self.assertEqual(result, 0)
self.assertEqual(audit_events[-1][0], "test.no_args")
self.assertEqual(audit_events[-1][1], ())

with self.assertRaises(TypeError):
sys_audit(123, "O", 1)

result = sys_audit("テスト.イベント", "O", 42)
self.assertEqual(result, 0)
self.assertEqual(audit_events[-1][0], "テスト.イベント")
self.assertEqual(audit_events[-1][1], (42,))

with self.assertRaises(UnicodeDecodeError):
sys_audit(b"test.non_utf8\xff", "O", 1)
finally:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add also tests for sys_audit("test.event", "("), sys_audit("test.event", "&"), sys_audit("test.event", b"\xff") and sys_audit("test.event", "{OO}", [], []).

Add also tests for sys_audit(NULL, "O", 1) and sys_audit("test.event", NULL). If they crash, just add comments.

sys.audit_hooks = []

@unittest.skipIf(_testlimitedcapi is None, 'need _testlimitedcapi module')
def test_sys_audittuple(self):
# Test PySys_AuditTuple()
sys_audittuple = _testlimitedcapi.sys_audittuple
audit_events = []
def audit_hook(event, args):
audit_events.append((event, args))
return None
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is redundant.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
return None


sys.addaudithook(audit_hook)
try:
result = sys_audittuple("test.event", (1, "a"))
self.assertEqual(result, 0)
self.assertEqual(audit_events[-1][0], "test.event")
self.assertEqual(audit_events[-1][1], (1, "a"))

result = sys_audittuple("test.null_tuple")
self.assertEqual(result, 0)
self.assertEqual(audit_events[-1][0], "test.null_tuple")
self.assertEqual(audit_events[-1][1], ())

with self.assertRaises(TypeError):
sys_audittuple("test.bad_tuple", [1, 2])

result = sys_audittuple("テスト.イベント", (42,))
self.assertEqual(result, 0)
self.assertEqual(audit_events[-1][0], "テスト.イベント")
self.assertEqual(audit_events[-1][1], (42,))

with self.assertRaises(UnicodeDecodeError):
sys_audittuple(b"test.non_utf8\xff", (1,))
finally:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add also test for sys_audittuple(NULL, (1,)). If it crashes, just add a comment, like in other tests above.

sys.audit_hooks = []
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unfortunately, this does not work. There is no way to remove the audit hook. This is why these functions remained untested -- because the only way to test them is to use a subprocess. Look like other audit tests are implemented.



if __name__ == "__main__":
unittest.main()
56 changes: 56 additions & 0 deletions Modules/_testlimitedcapi/sys.c
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#endif
#include "parts.h"
#include "util.h"
#include "audit.h"


static PyObject *
Expand Down Expand Up @@ -106,6 +107,59 @@ sys_getxoptions(PyObject *Py_UNUSED(module), PyObject *Py_UNUSED(ignored))
return Py_XNewRef(result);
}

static PyObject *
sys_audit(PyObject *Py_UNUSED(module), PyObject *args)
{
const char *event;
Py_ssize_t event_len;
const char *argFormat;
Py_ssize_t format_len;
PyObject *arg1 = NULL, *arg2 = NULL, *arg3 = NULL;

if (!PyArg_ParseTuple(args, "z#z#|OOO", &event, &event_len, &argFormat, &format_len, &arg1, &arg2, &arg3)) {
return NULL;
}

if (event == NULL) {
RETURN_INT(0);
}

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if (event == NULL) {
RETURN_INT(0);
}

int result;
if (arg1 == NULL) {
result = PySys_Audit(event, argFormat);
} else if (arg2 == NULL) {
result = PySys_Audit(event, argFormat, arg1);
} else if (arg3 == NULL) {
result = PySys_Audit(event, argFormat, arg1, arg2);
} else {
result = PySys_Audit(event, argFormat, arg1, arg2, arg3);
}

RETURN_INT(result);
}

static PyObject *
sys_audittuple(PyObject *Py_UNUSED(module), PyObject *args)
{
const char *event;
Py_ssize_t event_len;
PyObject *tuple_args = NULL;

if (!PyArg_ParseTuple(args, "z#|O", &event, &event_len, &tuple_args)) {
return NULL;
}

if (event == NULL) {
RETURN_INT(0);
}

if (tuple_args != NULL && !PyTuple_Check(tuple_args)) {
PyErr_SetString(PyExc_TypeError, "second argument must be a tuple");
return NULL;
}

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should test how PySys_AuditTuple() handles this.

Suggested change
if (event == NULL) {
RETURN_INT(0);
}
if (tuple_args != NULL && !PyTuple_Check(tuple_args)) {
PyErr_SetString(PyExc_TypeError, "second argument must be a tuple");
return NULL;
}

RETURN_INT(PySys_AuditTuple(event, tuple_args));
}

static PyMethodDef test_methods[] = {
{"sys_getattr", sys_getattr, METH_O},
Expand All @@ -115,6 +169,8 @@ static PyMethodDef test_methods[] = {
{"sys_getobject", sys_getobject, METH_O},
{"sys_setobject", sys_setobject, METH_VARARGS},
{"sys_getxoptions", sys_getxoptions, METH_NOARGS},
{"sys_audit", sys_audit, METH_VARARGS},
{"sys_audittuple", sys_audittuple, METH_VARARGS},
{NULL},
};

Expand Down
Loading