Skip to content

Commit 77c0675

Browse files
authored
gh-158451: Add _PyUnicodeWriter_FinishWithSize() test (#158481)
1 parent b7b4f3e commit 77c0675

3 files changed

Lines changed: 41 additions & 1 deletion

File tree

‎Include/internal/pycore_unicodeobject.h‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -189,7 +189,8 @@ _PyUnicodeWriter_WriteCharInline(_PyUnicodeWriter *writer, Py_UCS4 ch)
189189
return 0;
190190
}
191191

192-
extern PyObject* _PyUnicodeWriter_FinishWithSize(
192+
// Export for '_testcapi' shared extension
193+
PyAPI_FUNC(PyObject*) _PyUnicodeWriter_FinishWithSize(
193194
_PyUnicodeWriter *writer,
194195
Py_ssize_t size);
195196

‎Lib/test/test_capi/test_unicode.py‎

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2322,6 +2322,19 @@ def test_readonly_optim_large_int(self):
23222322
self.assertEqual(writer.get_buffer(), expected)
23232323
self.assertEqual(writer.finish(), large_int_str)
23242324

2325+
def test_finish_with_size(self):
2326+
# Test _PyUnicodeWriter_FinishWithSize(). Truncate text requires
2327+
# to change the buffer kind.
2328+
text = 'a\xff\u20ac\U0010ffff'
2329+
expected = (0x10ffff, False) # do not test the buffer size
2330+
for size in range(len(text) + 1):
2331+
writer = self.create_writer(0)
2332+
writer.write_utf8(text.encode(), -1)
2333+
self.assertEqual(writer.get_buffer()[1:], expected)
2334+
self.assertEqual(writer.finish_with_size(size), text[:size])
2335+
2336+
# CRASHES writer.finish_with_size(len(text) + 1)
2337+
23252338

23262339
# Test PyUnicodeWriter_Format()
23272340
@unittest.skipIf(ctypes is None, 'need ctypes')

‎Modules/_testcapi/unicode.c‎

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -795,6 +795,31 @@ writer_finish(PyObject *self_raw, PyObject *Py_UNUSED(args))
795795
}
796796

797797

798+
static PyObject*
799+
writer_finish_with_size(PyObject *self_raw, PyObject *args)
800+
{
801+
PyAPI_FUNC(PyObject*) _PyUnicodeWriter_FinishWithSize(
802+
_PyUnicodeWriter *writer,
803+
Py_ssize_t size);
804+
805+
WriterObject *self = (WriterObject *)self_raw;
806+
if (writer_check(self) < 0) {
807+
return NULL;
808+
}
809+
810+
Py_ssize_t size;
811+
if (!PyArg_ParseTuple(args, "n", &size)) {
812+
return NULL;
813+
}
814+
815+
_PyUnicodeWriter *writer = (_PyUnicodeWriter*)self->writer;
816+
PyObject *str = _PyUnicodeWriter_FinishWithSize(writer, size);
817+
PyUnicodeWriter_Discard(self->writer);
818+
self->writer = NULL;
819+
return str;
820+
}
821+
822+
798823
static PyMethodDef writer_methods[] = {
799824
{"write_char", _PyCFunction_CAST(writer_write_char), METH_VARARGS},
800825
{"write_utf8", _PyCFunction_CAST(writer_write_utf8), METH_VARARGS},
@@ -809,6 +834,7 @@ static PyMethodDef writer_methods[] = {
809834
{"get_pointer", _PyCFunction_CAST(writer_get_pointer), METH_VARARGS},
810835
{"get_buffer", _PyCFunction_CAST(writer_get_buffer), METH_VARARGS},
811836
{"finish", _PyCFunction_CAST(writer_finish), METH_NOARGS},
837+
{"finish_with_size", _PyCFunction_CAST(writer_finish_with_size), METH_VARARGS},
812838
{NULL, NULL} /* sentinel */
813839
};
814840

0 commit comments

Comments
 (0)