forked from python-greenlet/greenlet
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add an optional test for greenlet C++ exceptions
- Loading branch information
Showing
3 changed files
with
144 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,118 @@ | ||
/* This is a set of functions used to test C++ exceptions are not | ||
* broken during greenlet switches | ||
*/ | ||
|
||
#include "../greenlet.h" | ||
|
||
struct exception_t | ||
{ | ||
int depth; | ||
exception_t(int depth) : depth(depth) { } | ||
}; | ||
|
||
/* Functions are called via pointers to prevent inlining */ | ||
static void (*p_test_exception_throw)(int depth); | ||
static PyObject* (*p_test_exception_switch_recurse)(int depth, int left); | ||
|
||
static void test_exception_throw(int depth) | ||
{ | ||
throw exception_t(depth); | ||
} | ||
|
||
static PyObject* test_exception_switch_recurse(int depth, int left) | ||
{ | ||
if (left > 0) { | ||
return p_test_exception_switch_recurse(depth, left - 1); | ||
} | ||
|
||
PyObject* result = NULL; | ||
PyGreenlet* self = PyGreenlet_GetCurrent(); | ||
if (self == NULL) | ||
return NULL; | ||
|
||
try { | ||
PyGreenlet_Switch(self->parent, NULL, NULL); | ||
p_test_exception_throw(depth); | ||
PyErr_SetString(PyExc_RuntimeError, "throwing C++ exception didn't work"); | ||
} catch(exception_t& e) { | ||
if (e.depth != depth) | ||
PyErr_SetString(PyExc_AssertionError, "depth mismatch"); | ||
else | ||
result = PyLong_FromLong(depth); | ||
} catch(...) { | ||
PyErr_SetString(PyExc_RuntimeError, "unexpected C++ exception"); | ||
} | ||
|
||
Py_DECREF(self); | ||
return result; | ||
} | ||
|
||
/* test_exception_switch(int depth) | ||
* - recurses depth times | ||
* - switches to parent inside try/catch block | ||
* - throws an exception that (expected to be caught in the same function) | ||
* - verifies depth matches (exceptions shouldn't be caught in other greenlets) | ||
*/ | ||
static PyObject * | ||
test_exception_switch(PyObject *self, PyObject *args) | ||
{ | ||
int depth; | ||
if (!PyArg_ParseTuple(args, "i", &depth)) | ||
return NULL; | ||
return p_test_exception_switch_recurse(depth, depth); | ||
} | ||
|
||
static PyMethodDef test_methods[] = { | ||
{"test_exception_switch", (PyCFunction)&test_exception_switch, METH_VARARGS, | ||
"Switches to parent twice, to test exception handling and greenlet switching."}, | ||
{NULL, NULL, 0, NULL} | ||
}; | ||
|
||
|
||
#if PY_MAJOR_VERSION >= 3 | ||
#define INITERROR return NULL | ||
|
||
static struct PyModuleDef moduledef = { | ||
PyModuleDef_HEAD_INIT, | ||
"_test_extension_cpp", | ||
NULL, | ||
0, | ||
test_methods, | ||
NULL, | ||
NULL, | ||
NULL, | ||
NULL | ||
}; | ||
|
||
PyMODINIT_FUNC | ||
PyInit__test_extension_cpp(void) | ||
#else | ||
#define INITERROR return | ||
PyMODINIT_FUNC | ||
init_test_extension_cpp(void) | ||
#endif | ||
{ | ||
PyObject *module = NULL; | ||
|
||
#if PY_MAJOR_VERSION >= 3 | ||
module = PyModule_Create(&moduledef); | ||
#else | ||
module = Py_InitModule("_test_extension_cpp", test_methods); | ||
#endif | ||
|
||
if (module == NULL) { | ||
INITERROR; | ||
} | ||
|
||
PyGreenlet_Import(); | ||
if (_PyGreenlet_API == NULL) { | ||
INITERROR; | ||
} | ||
|
||
p_test_exception_throw = test_exception_throw; | ||
p_test_exception_switch_recurse = test_exception_switch_recurse; | ||
|
||
#if PY_MAJOR_VERSION >= 3 | ||
return module; | ||
#endif | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
import unittest | ||
|
||
import greenlet | ||
import _test_extension_cpp | ||
|
||
class CPPTests(unittest.TestCase): | ||
def test_exception_switch(self): | ||
greenlets = [] | ||
for i in range(4): | ||
g = greenlet.greenlet(_test_extension_cpp.test_exception_switch) | ||
g.switch(i) | ||
greenlets.append(g) | ||
for i,g in enumerate(greenlets): | ||
self.assertEqual(g.switch(), i) |