Skip to content

Commit 2091c90

Browse files
committed
Add tests on the Pointer API
1 parent d572dad commit 2091c90

1 file changed

Lines changed: 103 additions & 1 deletion

File tree

Modules/_testcapi/bytes.c

Lines changed: 103 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -353,12 +353,114 @@ byteswriter_highlevel(PyObject *Py_UNUSED(module), PyObject *Py_UNUSED(args))
353353
}
354354

355355

356+
static size_t
357+
pybyteswriter_small_buffer_size(void)
358+
{
359+
return offsetof(PyBytesWriter, obj);
360+
}
361+
362+
363+
// Test the "Pointer" API of PyBytesWriter
364+
static PyObject *
365+
test_byteswriter_ptr(PyObject *Py_UNUSED(module), PyObject *Py_UNUSED(args))
366+
{
367+
// Test PyBytesWriter_FinishWithPointer(): create the string "abc"
368+
PyBytesWriter *writer = PyBytesWriter_Create(3);
369+
if (writer == NULL) {
370+
return NULL;
371+
}
372+
char *str = PyBytesWriter_GetData(writer);
373+
memcpy(str, "abc", 3);
374+
str += 3;
375+
PyObject *result = PyBytesWriter_FinishWithPointer(writer, str);
376+
if (result == NULL) {
377+
return NULL;
378+
}
379+
assert(PyBytes_GET_SIZE(result) == 3);
380+
assert(memcmp(PyBytes_AS_STRING(result), "abc", 3) == 0);
381+
Py_DECREF(result);
382+
383+
// Test PyBytesWriter_GrowAndUpdatePointer().
384+
// Start by using the small buffer, and then resize to use a bytes object.
385+
writer = PyBytesWriter_Create(0);
386+
if (writer == NULL) {
387+
return NULL;
388+
}
389+
str = PyBytesWriter_GetData(writer);
390+
391+
str = PyBytesWriter_GrowAndUpdatePointer(writer, 100, str);
392+
if (str == NULL) {
393+
PyBytesWriter_Discard(writer);
394+
return NULL;
395+
}
396+
memset(str, 'x', 100);
397+
str += 100;
398+
399+
// make sure that the test switchs to a bytes object
400+
assert((100 + 200) > pybyteswriter_small_buffer_size());
401+
char *old_str = str;
402+
str = PyBytesWriter_GrowAndUpdatePointer(writer, 200, str);
403+
if (str == NULL) {
404+
PyBytesWriter_Discard(writer);
405+
return NULL;
406+
}
407+
// make sure that we moved from the small buffer to a bytes object
408+
assert(str != old_str);
409+
memset(str, 'y', 200);
410+
str += 200;
411+
412+
result = PyBytesWriter_FinishWithPointer(writer, str);
413+
if (result == NULL) {
414+
return NULL;
415+
}
416+
assert(PyBytes_GET_SIZE(result) == 300);
417+
str = PyBytes_AS_STRING(result);
418+
for (Py_ssize_t i=0; i < 100; i++) {
419+
assert(str[i] == 'x');
420+
}
421+
for (Py_ssize_t i=0; i < 200; i++) {
422+
assert(str[100 + i] == 'y');
423+
}
424+
Py_DECREF(result);
425+
426+
// Check that PyBytesWriter_FinishWithPointer() rejects pointer
427+
// after the buffer end (create a string larger than the allocated size)
428+
writer = PyBytesWriter_Create(3);
429+
if (writer == NULL) {
430+
return NULL;
431+
}
432+
str = PyBytesWriter_GetData(writer);
433+
memcpy(str, "abc", 3);
434+
str += 4; // off-by-one bug on purpose
435+
result = PyBytesWriter_FinishWithPointer(writer, str);
436+
assert(result == NULL);
437+
assert(PyErr_ExceptionMatches(PyExc_ValueError));
438+
PyErr_Clear();
439+
440+
// Check that PyBytesWriter_FinishWithPointer() rejects pointer
441+
// before the buffer start (negative size)
442+
writer = PyBytesWriter_Create(3);
443+
if (writer == NULL) {
444+
return NULL;
445+
}
446+
str = PyBytesWriter_GetData(writer);
447+
str--; // bug on purpose: go before the buffer start
448+
result = PyBytesWriter_FinishWithPointer(writer, str);
449+
assert(result == NULL);
450+
assert(PyErr_ExceptionMatches(PyExc_ValueError));
451+
PyErr_Clear();
452+
453+
Py_RETURN_NONE;
454+
}
455+
456+
356457
static PyMethodDef test_methods[] = {
357458
{"bytes_resize", bytes_resize, METH_VARARGS},
358459
{"bytes_join", bytes_join, METH_VARARGS},
359460
{"byteswriter_abc", byteswriter_abc, METH_NOARGS},
360461
{"byteswriter_resize", byteswriter_resize, METH_NOARGS},
361462
{"byteswriter_highlevel", byteswriter_highlevel, METH_NOARGS},
463+
{"test_byteswriter_ptr", test_byteswriter_ptr, METH_NOARGS},
362464
{NULL},
363465
};
364466

@@ -380,7 +482,7 @@ _PyTestCapi_Init_Bytes(PyObject *m)
380482
Py_DECREF(writer_type);
381483

382484
// PyBytesWriter.obj is the second member, small_buffer is the first member
383-
long size = (long)offsetof(PyBytesWriter, obj);
485+
long size = (long)pybyteswriter_small_buffer_size();
384486
if (PyModule_AddIntConstant(m, "PyBytesWriter_small_buffer", size) < 0) {
385487
Py_DECREF(writer_type);
386488
return -1;

0 commit comments

Comments
 (0)