Skip to content

Commit

Permalink
gh-94808: add tests covering PySequence_{Set,Del}Slice (GH-99123)
Browse files Browse the repository at this point in the history
  • Loading branch information
sobolevn authored Nov 5, 2022
1 parent 67ade40 commit c5c4077
Show file tree
Hide file tree
Showing 2 changed files with 113 additions and 0 deletions.
80 changes: 80 additions & 0 deletions Lib/test/test_capi.py
Original file line number Diff line number Diff line change
Expand Up @@ -416,6 +416,86 @@ class SubDict(dict):
self.assertTrue(_testcapi.mapping_has_key(dct2, 'a'))
self.assertFalse(_testcapi.mapping_has_key(dct2, 'b'))

def test_sequence_set_slice(self):
# Correct case:
data = [1, 2, 3, 4, 5]
data_copy = data.copy()

_testcapi.sequence_set_slice(data, 1, 3, [8, 9])
data_copy[1:3] = [8, 9]
self.assertEqual(data, data_copy)
self.assertEqual(data, [1, 8, 9, 4, 5])

# Custom class:
class Custom:
def __setitem__(self, index, value):
self.index = index
self.value = value

c = Custom()
_testcapi.sequence_set_slice(c, 0, 5, 'abc')
self.assertEqual(c.index, slice(0, 5))
self.assertEqual(c.value, 'abc')

# Immutable sequences must raise:
bad_seq1 = (1, 2, 3, 4)
with self.assertRaises(TypeError):
_testcapi.sequence_set_slice(bad_seq1, 1, 3, (8, 9))
self.assertEqual(bad_seq1, (1, 2, 3, 4))

bad_seq2 = 'abcd'
with self.assertRaises(TypeError):
_testcapi.sequence_set_slice(bad_seq2, 1, 3, 'xy')
self.assertEqual(bad_seq2, 'abcd')

# Not a sequence:
with self.assertRaises(TypeError):
_testcapi.sequence_set_slice(None, 1, 3, 'xy')

mapping = {1: 'a', 2: 'b', 3: 'c'}
with self.assertRaises(TypeError):
_testcapi.sequence_set_slice(mapping, 1, 3, 'xy')
self.assertEqual(mapping, {1: 'a', 2: 'b', 3: 'c'})

def test_sequence_del_slice(self):
# Correct case:
data = [1, 2, 3, 4, 5]
data_copy = data.copy()

_testcapi.sequence_del_slice(data, 1, 3)
del data_copy[1:3]
self.assertEqual(data, data_copy)
self.assertEqual(data, [1, 4, 5])

# Custom class:
class Custom:
def __delitem__(self, index):
self.index = index

c = Custom()
_testcapi.sequence_del_slice(c, 0, 5)
self.assertEqual(c.index, slice(0, 5))

# Immutable sequences must raise:
bad_seq1 = (1, 2, 3, 4)
with self.assertRaises(TypeError):
_testcapi.sequence_del_slice(bad_seq1, 1, 3)
self.assertEqual(bad_seq1, (1, 2, 3, 4))

bad_seq2 = 'abcd'
with self.assertRaises(TypeError):
_testcapi.sequence_del_slice(bad_seq2, 1, 3)
self.assertEqual(bad_seq2, 'abcd')

# Not a sequence:
with self.assertRaises(TypeError):
_testcapi.sequence_del_slice(None, 1, 3)

mapping = {1: 'a', 2: 'b', 3: 'c'}
with self.assertRaises(TypeError):
_testcapi.sequence_del_slice(mapping, 1, 3)
self.assertEqual(mapping, {1: 'a', 2: 'b', 3: 'c'})

@unittest.skipUnless(hasattr(_testcapi, 'negative_refcount'),
'need _testcapi.negative_refcount')
def test_negative_refcount(self):
Expand Down
33 changes: 33 additions & 0 deletions Modules/_testcapimodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -4794,6 +4794,37 @@ mapping_has_key(PyObject* self, PyObject *args)
return PyLong_FromLong(PyMapping_HasKey(context, key));
}

static PyObject *
sequence_set_slice(PyObject* self, PyObject *args)
{
PyObject *sequence, *obj;
Py_ssize_t i1, i2;
if (!PyArg_ParseTuple(args, "OnnO", &sequence, &i1, &i2, &obj)) {
return NULL;
}

int res = PySequence_SetSlice(sequence, i1, i2, obj);
if (res == -1) {
return NULL;
}
Py_RETURN_NONE;
}

static PyObject *
sequence_del_slice(PyObject* self, PyObject *args)
{
PyObject *sequence;
Py_ssize_t i1, i2;
if (!PyArg_ParseTuple(args, "Onn", &sequence, &i1, &i2)) {
return NULL;
}

int res = PySequence_DelSlice(sequence, i1, i2);
if (res == -1) {
return NULL;
}
Py_RETURN_NONE;
}

static PyObject *
test_pythread_tss_key_state(PyObject *self, PyObject *args)
Expand Down Expand Up @@ -6196,6 +6227,8 @@ static PyMethodDef TestMethods[] = {
{"get_mapping_items", get_mapping_items, METH_O},
{"test_mapping_has_key_string", test_mapping_has_key_string, METH_NOARGS},
{"mapping_has_key", mapping_has_key, METH_VARARGS},
{"sequence_set_slice", sequence_set_slice, METH_VARARGS},
{"sequence_del_slice", sequence_del_slice, METH_VARARGS},
{"test_pythread_tss_key_state", test_pythread_tss_key_state, METH_VARARGS},
{"hamt", new_hamt, METH_NOARGS},
{"bad_get", _PyCFunction_CAST(bad_get), METH_FASTCALL},
Expand Down

0 comments on commit c5c4077

Please sign in to comment.