diff options
| author | Jason Madden <jamadden@gmail.com> | 2020-11-12 11:49:12 -0600 |
|---|---|---|
| committer | Jason Madden <jamadden@gmail.com> | 2020-11-12 11:49:12 -0600 |
| commit | 8448b094d1b81788ac9cbaf86a184712f1daf5e0 (patch) | |
| tree | 34e07251b520b94f44fd40136687bb059a08e256 /tests | |
| parent | c80fab93073603289f41df8e32b7ecc25f37763e (diff) | |
| download | greenlet-issue184.tar.gz | |
Move to the src/ layout, and make greenlet a package.issue184
Make 'tests' become 'greenlet.tests', and be compatible with 'python -m unittest discover'.
Fixes #184. Fixes #184. Fixes #189.
Diffstat (limited to 'tests')
| -rw-r--r-- | tests/__init__.py | 14 | ||||
| -rw-r--r-- | tests/_test_extension.c | 208 | ||||
| -rw-r--r-- | tests/_test_extension_cpp.cpp | 118 | ||||
| -rw-r--r-- | tests/test_contextvars.py | 265 | ||||
| -rw-r--r-- | tests/test_cpp.py | 15 | ||||
| -rw-r--r-- | tests/test_extension_interface.py | 71 | ||||
| -rw-r--r-- | tests/test_gc.py | 77 | ||||
| -rw-r--r-- | tests/test_generator.py | 59 | ||||
| -rw-r--r-- | tests/test_generator_nested.py | 165 | ||||
| -rw-r--r-- | tests/test_greenlet.py | 542 | ||||
| -rw-r--r-- | tests/test_leaks.py | 85 | ||||
| -rw-r--r-- | tests/test_stack_saved.py | 19 | ||||
| -rw-r--r-- | tests/test_throw.py | 100 | ||||
| -rw-r--r-- | tests/test_tracing.py | 52 | ||||
| -rwxr-xr-x | tests/test_version.py | 20 | ||||
| -rw-r--r-- | tests/test_weakref.py | 34 |
16 files changed, 0 insertions, 1844 deletions
diff --git a/tests/__init__.py b/tests/__init__.py deleted file mode 100644 index 3ea15d8..0000000 --- a/tests/__init__.py +++ /dev/null @@ -1,14 +0,0 @@ -import os -import glob -import unittest - -def test_collector(): - """Collect all tests under the tests directory and return a - unittest.TestSuite - """ - tests_dir = os.path.realpath(os.path.dirname(__file__)) - test_module_list = [ - 'tests.%s' % os.path.splitext(os.path.basename(t))[0] - for t in glob.glob(os.path.join(tests_dir, 'test_*.py')) - ] - return unittest.TestLoader().loadTestsFromNames(test_module_list) diff --git a/tests/_test_extension.c b/tests/_test_extension.c deleted file mode 100644 index ec8b70c..0000000 --- a/tests/_test_extension.c +++ /dev/null @@ -1,208 +0,0 @@ -/* This is a set of functions used by test_extension_interface.py to test the - * Greenlet C API. - */ - -#include "../greenlet.h" - -#ifndef Py_RETURN_NONE -#define Py_RETURN_NONE return Py_INCREF(Py_None), Py_None -#endif - -#define TEST_MODULE_NAME "_test_extension" - -static PyObject * -test_switch(PyObject *self, PyObject *greenlet) -{ - PyObject *result = NULL; - - if (greenlet == NULL || !PyGreenlet_Check(greenlet)) { - PyErr_BadArgument(); - return NULL; - } - - result = PyGreenlet_Switch((PyGreenlet *) greenlet, NULL, NULL); - if (result == NULL) { - if (!PyErr_Occurred()) { - PyErr_SetString( - PyExc_AssertionError, - "greenlet.switch() failed for some reason."); - } - return NULL; - } - Py_INCREF(result); - return result; -} - -static PyObject * -test_switch_kwargs(PyObject *self, PyObject *args, PyObject *kwargs) -{ - PyGreenlet *g = NULL; - PyObject *result = NULL; - - PyArg_ParseTuple(args, "O!", &PyGreenlet_Type, &g); - - if (g == NULL || !PyGreenlet_Check(g)) { - PyErr_BadArgument(); - return NULL; - } - - result = PyGreenlet_Switch(g, NULL, kwargs); - if (result == NULL) { - if (!PyErr_Occurred()) { - PyErr_SetString( - PyExc_AssertionError, - "greenlet.switch() failed for some reason."); - } - return NULL; - } - Py_XINCREF(result); - return result; -} - -static PyObject * -test_getcurrent(PyObject *self) -{ - PyGreenlet *g = PyGreenlet_GetCurrent(); - if (g == NULL || !PyGreenlet_Check(g) || !PyGreenlet_ACTIVE(g)) { - PyErr_SetString( - PyExc_AssertionError, - "getcurrent() returned an invalid greenlet"); - Py_XDECREF(g); - return NULL; - } - Py_DECREF(g); - Py_RETURN_NONE; -} - -static PyObject * -test_setparent(PyObject *self, PyObject *arg) -{ - PyGreenlet *current; - PyGreenlet *greenlet = NULL; - - if (arg == NULL || !PyGreenlet_Check(arg)) - { - PyErr_BadArgument(); - return NULL; - } - if ((current = PyGreenlet_GetCurrent()) == NULL) { - return NULL; - } - greenlet = (PyGreenlet *) arg; - if (PyGreenlet_SetParent(greenlet, current)) { - Py_DECREF(current); - return NULL; - } - Py_DECREF(current); - if (PyGreenlet_Switch(greenlet, NULL, NULL) == NULL) { - return NULL; - } - Py_RETURN_NONE; -} - -static PyObject * -test_new_greenlet(PyObject *self, PyObject *callable) -{ - PyObject *result = NULL; - PyGreenlet *greenlet = PyGreenlet_New(callable, NULL); - - if (!greenlet) { - return NULL; - } - - result = PyGreenlet_Switch(greenlet, NULL, NULL); - if (result == NULL) { - return NULL; - } - - Py_INCREF(result); - return result; -} - -static PyObject * -test_raise_dead_greenlet(PyObject *self) -{ - PyErr_SetString(PyExc_GreenletExit, "test GreenletExit exception."); - return NULL; -} - -static PyObject * -test_raise_greenlet_error(PyObject *self) -{ - PyErr_SetString(PyExc_GreenletError, "test greenlet.error exception"); - return NULL; -} - -static PyObject * -test_throw(PyObject *self, PyGreenlet *g) -{ - const char msg[] = "take that sucka!"; - PyObject *msg_obj = Py_BuildValue("s", msg); - PyGreenlet_Throw(g, PyExc_ValueError, msg_obj, NULL); - Py_DECREF(msg_obj); - Py_RETURN_NONE; -} - -static PyMethodDef test_methods[] = { - {"test_switch", (PyCFunction) test_switch, METH_O, - "Switch to the provided greenlet sending provided arguments, and \n" - "return the results."}, - {"test_switch_kwargs", (PyCFunction) test_switch_kwargs, - METH_VARARGS | METH_KEYWORDS, - "Switch to the provided greenlet sending the provided keyword args."}, - {"test_getcurrent", (PyCFunction) test_getcurrent, METH_NOARGS, - "Test PyGreenlet_GetCurrent()"}, - {"test_setparent", (PyCFunction) test_setparent, METH_O, - "Se the parent of the provided greenlet and switch to it."}, - {"test_new_greenlet", (PyCFunction) test_new_greenlet, METH_O, - "Test PyGreenlet_New()"}, - {"test_raise_dead_greenlet", (PyCFunction) test_raise_dead_greenlet, - METH_NOARGS, "Just raise greenlet.GreenletExit"}, - {"test_raise_greenlet_error", (PyCFunction) test_raise_greenlet_error, - METH_NOARGS, "Just raise greenlet.error"}, - {"test_throw", (PyCFunction) test_throw, METH_O, - "Throw a ValueError at the provided greenlet"}, - {NULL, NULL, 0, NULL} -}; - -#if PY_MAJOR_VERSION >= 3 -#define INITERROR return NULL - -static struct PyModuleDef moduledef = { - PyModuleDef_HEAD_INIT, - TEST_MODULE_NAME, - NULL, - 0, - test_methods, - NULL, - NULL, - NULL, - NULL -}; - -PyMODINIT_FUNC -PyInit__test_extension(void) -#else -#define INITERROR return -PyMODINIT_FUNC -init_test_extension(void) -#endif -{ - PyObject *module = NULL; - -#if PY_MAJOR_VERSION >= 3 - module = PyModule_Create(&moduledef); -#else - module = Py_InitModule(TEST_MODULE_NAME, test_methods); -#endif - - if (module == NULL) { - INITERROR; - } - - PyGreenlet_Import(); - -#if PY_MAJOR_VERSION >= 3 - return module; -#endif -} diff --git a/tests/_test_extension_cpp.cpp b/tests/_test_extension_cpp.cpp deleted file mode 100644 index 3b26571..0000000 --- a/tests/_test_extension_cpp.cpp +++ /dev/null @@ -1,118 +0,0 @@ -/* 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 -} diff --git a/tests/test_contextvars.py b/tests/test_contextvars.py deleted file mode 100644 index 02873c5..0000000 --- a/tests/test_contextvars.py +++ /dev/null @@ -1,265 +0,0 @@ -import unittest -import gc -import sys - -from functools import partial - -from greenlet import greenlet -from greenlet import getcurrent -from greenlet import GREENLET_USE_CONTEXT_VARS - -try: - from contextvars import Context - from contextvars import ContextVar - from contextvars import copy_context -except ImportError: - Context = ContextVar = copy_context = None - -@unittest.skipUnless(GREENLET_USE_CONTEXT_VARS, "ContextVar not supported") -class ContextVarsTests(unittest.TestCase): - def _new_ctx_run(self, *args, **kwargs): - return copy_context().run(*args, **kwargs) - - def _increment(self, greenlet_id, ctx_var, callback, counts, expect): - if expect is None: - self.assertIsNone(ctx_var.get()) - else: - self.assertEqual(ctx_var.get(), expect) - ctx_var.set(greenlet_id) - for _ in range(2): - counts[ctx_var.get()] += 1 - callback() - - def _test_context(self, propagate_by): - id_var = ContextVar("id", default=None) - id_var.set(0) - - callback = getcurrent().switch - counts = dict((i, 0) for i in range(5)) - - lets = [ - greenlet(partial( - partial( - copy_context().run, - self._increment - ) if propagate_by == "run" else self._increment, - greenlet_id=i, - ctx_var=id_var, - callback=callback, - counts=counts, - expect=( - i - 1 if propagate_by == "share" else - 0 if propagate_by in ("set", "run") else None - ) - )) - for i in range(1, 5) - ] - - for let in lets: - if propagate_by == "set": - let.gr_context = copy_context() - elif propagate_by == "share": - let.gr_context = getcurrent().gr_context - - for i in range(2): - counts[id_var.get()] += 1 - for let in lets: - let.switch() - - if propagate_by == "run": - # Must leave each context.run() in reverse order of entry - for let in reversed(lets): - let.switch() - else: - # No context.run(), so fine to exit in any order. - for let in lets: - let.switch() - - for let in lets: - self.assertTrue(let.dead) - # When using run(), we leave the run() as the greenlet dies, - # and there's no context "underneath". When not using run(), - # gr_context still reflects the context the greenlet was - # running in. - self.assertEqual(let.gr_context is None, propagate_by == "run") - - if propagate_by == "share": - self.assertEqual(counts, {0: 1, 1: 1, 2: 1, 3: 1, 4: 6}) - else: - self.assertEqual(set(counts.values()), set([2])) - - def test_context_propagated_by_context_run(self): - self._new_ctx_run(self._test_context, "run") - - def test_context_propagated_by_setting_attribute(self): - self._new_ctx_run(self._test_context, "set") - - def test_context_not_propagated(self): - self._new_ctx_run(self._test_context, None) - - def test_context_shared(self): - self._new_ctx_run(self._test_context, "share") - - def test_break_ctxvars(self): - let1 = greenlet(copy_context().run) - let2 = greenlet(copy_context().run) - let1.switch(getcurrent().switch) - let2.switch(getcurrent().switch) - # Since let2 entered the current context and let1 exits its own, the - # interpreter emits: - # RuntimeError: cannot exit context: thread state references a different context object - let1.switch() - - def test_not_broken_if_using_attribute_instead_of_context_run(self): - let1 = greenlet(getcurrent().switch) - let2 = greenlet(getcurrent().switch) - let1.gr_context = copy_context() - let2.gr_context = copy_context() - let1.switch() - let2.switch() - let1.switch() - let2.switch() - - def test_context_assignment_while_running(self): - id_var = ContextVar("id", default=None) - - def target(): - self.assertIsNone(id_var.get()) - self.assertIsNone(gr.gr_context) - - # Context is created on first use - id_var.set(1) - self.assertIsInstance(gr.gr_context, Context) - self.assertEqual(id_var.get(), 1) - self.assertEqual(gr.gr_context[id_var], 1) - - # Clearing the context makes it get re-created as another - # empty context when next used - old_context = gr.gr_context - gr.gr_context = None # assign None while running - self.assertIsNone(id_var.get()) - self.assertIsNone(gr.gr_context) - id_var.set(2) - self.assertIsInstance(gr.gr_context, Context) - self.assertEqual(id_var.get(), 2) - self.assertEqual(gr.gr_context[id_var], 2) - - new_context = gr.gr_context - getcurrent().parent.switch((old_context, new_context)) - # parent switches us back to old_context - - self.assertEqual(id_var.get(), 1) - gr.gr_context = new_context # assign non-None while running - self.assertEqual(id_var.get(), 2) - - getcurrent().parent.switch() - # parent switches us back to no context - self.assertIsNone(id_var.get()) - self.assertIsNone(gr.gr_context) - gr.gr_context = old_context - self.assertEqual(id_var.get(), 1) - - getcurrent().parent.switch() - # parent switches us back to no context - self.assertIsNone(id_var.get()) - self.assertIsNone(gr.gr_context) - - gr = greenlet(target) - - with self.assertRaisesRegex(AttributeError, "can't delete attr"): - del gr.gr_context - - self.assertIsNone(gr.gr_context) - old_context, new_context = gr.switch() - self.assertIs(new_context, gr.gr_context) - self.assertEqual(old_context[id_var], 1) - self.assertEqual(new_context[id_var], 2) - self.assertEqual(new_context.run(id_var.get), 2) - gr.gr_context = old_context # assign non-None while suspended - gr.switch() - self.assertIs(gr.gr_context, new_context) - gr.gr_context = None # assign None while suspended - gr.switch() - self.assertIs(gr.gr_context, old_context) - gr.gr_context = None - gr.switch() - self.assertIsNone(gr.gr_context) - - # Make sure there are no reference leaks - gr = None - gc.collect() - self.assertEqual(sys.getrefcount(old_context), 2) - self.assertEqual(sys.getrefcount(new_context), 2) - - def test_context_assignment_different_thread(self): - import threading - - ctx = Context() - var = ContextVar("var", default=None) - is_running = threading.Event() - should_suspend = threading.Event() - did_suspend = threading.Event() - should_exit = threading.Event() - holder = [] - - def greenlet_in_thread_fn(): - var.set(1) - is_running.set() - should_suspend.wait() - var.set(2) - getcurrent().parent.switch() - holder.append(var.get()) - - def thread_fn(): - gr = greenlet(greenlet_in_thread_fn) - gr.gr_context = ctx - holder.append(gr) - gr.switch() - did_suspend.set() - should_exit.wait() - gr.switch() - - thread = threading.Thread(target=thread_fn, daemon=True) - thread.start() - is_running.wait() - gr = holder[0] - - # Can't access or modify context if the greenlet is running - # in a different thread - with self.assertRaisesRegex(ValueError, "running in a different"): - getattr(gr, 'gr_context') - with self.assertRaisesRegex(ValueError, "running in a different"): - gr.gr_context = None - - should_suspend.set() - did_suspend.wait() - - # OK to access and modify context if greenlet is suspended - self.assertIs(gr.gr_context, ctx) - self.assertEqual(gr.gr_context[var], 2) - gr.gr_context = None - - should_exit.set() - thread.join() - - self.assertEqual(holder, [gr, None]) - - # Context can still be accessed/modified when greenlet is dead: - self.assertIsNone(gr.gr_context) - gr.gr_context = ctx - self.assertIs(gr.gr_context, ctx) - -@unittest.skipIf(GREENLET_USE_CONTEXT_VARS, "ContextVar supported") -class NoContextVarsTests(unittest.TestCase): - def test_contextvars_errors(self): - let1 = greenlet(getcurrent().switch) - self.assertFalse(hasattr(let1, 'gr_context')) - with self.assertRaises(AttributeError): - getattr(let1, 'gr_context') - with self.assertRaises(AttributeError): - let1.gr_context = None - let1.switch() - with self.assertRaises(AttributeError): - getattr(let1, 'gr_context') - with self.assertRaises(AttributeError): - let1.gr_context = None diff --git a/tests/test_cpp.py b/tests/test_cpp.py deleted file mode 100644 index ad1888f..0000000 --- a/tests/test_cpp.py +++ /dev/null @@ -1,15 +0,0 @@ -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) diff --git a/tests/test_extension_interface.py b/tests/test_extension_interface.py deleted file mode 100644 index e7bfbfd..0000000 --- a/tests/test_extension_interface.py +++ /dev/null @@ -1,71 +0,0 @@ -import sys -import unittest - -import greenlet -import _test_extension - - -class CAPITests(unittest.TestCase): - def test_switch(self): - self.assertEqual( - 50, _test_extension.test_switch(greenlet.greenlet(lambda: 50))) - - def test_switch_kwargs(self): - def foo(x, y): - return x * y - g = greenlet.greenlet(foo) - self.assertEqual(6, _test_extension.test_switch_kwargs(g, x=3, y=2)) - - def test_setparent(self): - def foo(): - def bar(): - greenlet.getcurrent().parent.switch() - - # This final switch should go back to the main greenlet, since - # the test_setparent() function in the C extension should have - # reparented this greenlet. - greenlet.getcurrent().parent.switch() - raise AssertionError("Should never have reached this code") - child = greenlet.greenlet(bar) - child.switch() - greenlet.getcurrent().parent.switch(child) - greenlet.getcurrent().parent.throw( - AssertionError("Should never reach this code")) - foo_child = greenlet.greenlet(foo).switch() - self.assertEqual(None, _test_extension.test_setparent(foo_child)) - - def test_getcurrent(self): - _test_extension.test_getcurrent() - - def test_new_greenlet(self): - self.assertEqual(-15, _test_extension.test_new_greenlet(lambda: -15)) - - def test_raise_greenlet_dead(self): - self.assertRaises( - greenlet.GreenletExit, _test_extension.test_raise_dead_greenlet) - - def test_raise_greenlet_error(self): - self.assertRaises( - greenlet.error, _test_extension.test_raise_greenlet_error) - - def test_throw(self): - seen = [] - - def foo(): - try: - greenlet.getcurrent().parent.switch() - except ValueError: - seen.append(sys.exc_info()[1]) - except greenlet.GreenletExit: - raise AssertionError - g = greenlet.greenlet(foo) - g.switch() - _test_extension.test_throw(g) - self.assertEqual(len(seen), 1) - self.assertTrue( - isinstance(seen[0], ValueError), - "ValueError was not raised in foo()") - self.assertEqual( - str(seen[0]), - 'take that sucka!', - "message doesn't match") diff --git a/tests/test_gc.py b/tests/test_gc.py deleted file mode 100644 index a2a41ca..0000000 --- a/tests/test_gc.py +++ /dev/null @@ -1,77 +0,0 @@ -import gc -import sys -import unittest -import weakref - -import greenlet - - -class GCTests(unittest.TestCase): - def test_dead_circular_ref(self): - o = weakref.ref(greenlet.greenlet(greenlet.getcurrent).switch()) - gc.collect() - self.assertTrue(o() is None) - self.assertFalse(gc.garbage, gc.garbage) - - if greenlet.GREENLET_USE_GC: - # These only work with greenlet gc support - - def test_circular_greenlet(self): - class circular_greenlet(greenlet.greenlet): - pass - o = circular_greenlet() - o.self = o - o = weakref.ref(o) - gc.collect() - self.assertTrue(o() is None) - self.assertFalse(gc.garbage, gc.garbage) - - def test_inactive_ref(self): - class inactive_greenlet(greenlet.greenlet): - def __init__(self): - greenlet.greenlet.__init__(self, run=self.run) - - def run(self): - pass - o = inactive_greenlet() - o = weakref.ref(o) - gc.collect() - self.assertTrue(o() is None) - self.assertFalse(gc.garbage, gc.garbage) - - def test_finalizer_crash(self): - # This test is designed to crash when active greenlets - # are made garbage collectable, until the underlying - # problem is resolved. How does it work: - # - order of object creation is important - # - array is created first, so it is moved to unreachable first - # - we create a cycle between a greenlet and this array - # - we create an object that participates in gc, is only - # referenced by a greenlet, and would corrupt gc lists - # on destruction, the easiest is to use an object with - # a finalizer - # - because array is the first object in unreachable it is - # cleared first, which causes all references to greenlet - # to disappear and causes greenlet to be destroyed, but since - # it is still live it causes a switch during gc, which causes - # an object with finalizer to be destroyed, which causes stack - # corruption and then a crash - class object_with_finalizer(object): - def __del__(self): - pass - array = [] - parent = greenlet.getcurrent() - def greenlet_body(): - greenlet.getcurrent().object = object_with_finalizer() - try: - parent.switch() - finally: - del greenlet.getcurrent().object - g = greenlet.greenlet(greenlet_body) - g.array = array - array.append(g) - g.switch() - del array - del g - greenlet.getcurrent() - gc.collect() diff --git a/tests/test_generator.py b/tests/test_generator.py deleted file mode 100644 index 62f9f26..0000000 --- a/tests/test_generator.py +++ /dev/null @@ -1,59 +0,0 @@ -import unittest -from greenlet import greenlet - - -class genlet(greenlet): - - def __init__(self, *args, **kwds): - self.args = args - self.kwds = kwds - - def run(self): - fn, = self.fn - fn(*self.args, **self.kwds) - - def __iter__(self): - return self - - def __next__(self): - self.parent = greenlet.getcurrent() - result = self.switch() - if self: - return result - else: - raise StopIteration - - # Hack: Python < 2.6 compatibility - next = __next__ - - -def Yield(value): - g = greenlet.getcurrent() - while not isinstance(g, genlet): - if g is None: - raise RuntimeError('yield outside a genlet') - g = g.parent - g.parent.switch(value) - - -def generator(func): - class generator(genlet): - fn = (func,) - return generator - -# ____________________________________________________________ - - -class GeneratorTests(unittest.TestCase): - def test_generator(self): - seen = [] - - def g(n): - for i in range(n): - seen.append(i) - Yield(i) - g = generator(g) - for k in range(3): - for j in g(5): - seen.append(j) - self.assertEqual(seen, 3 * [0, 0, 1, 1, 2, 2, 3, 3, 4, 4]) diff --git a/tests/test_generator_nested.py b/tests/test_generator_nested.py deleted file mode 100644 index 6b4f023..0000000 --- a/tests/test_generator_nested.py +++ /dev/null @@ -1,165 +0,0 @@ -import unittest -from greenlet import greenlet - - -class genlet(greenlet): - - def __init__(self, *args, **kwds): - self.args = args - self.kwds = kwds - self.child = None - - def run(self): - fn, = self.fn - fn(*self.args, **self.kwds) - - def __iter__(self): - return self - - def set_child(self, child): - self.child = child - - def __next__(self): - if self.child: - child = self.child - while child.child: - tmp = child - child = child.child - tmp.child = None - - result = child.switch() - else: - self.parent = greenlet.getcurrent() - result = self.switch() - - if self: - return result - else: - raise StopIteration - - # Hack: Python < 2.6 compatibility - next = __next__ - - -def Yield(value, level=1): - g = greenlet.getcurrent() - - while level != 0: - if not isinstance(g, genlet): - raise RuntimeError('yield outside a genlet') - if level > 1: - g.parent.set_child(g) - g = g.parent - level -= 1 - - g.switch(value) - - -def Genlet(func): - class Genlet(genlet): - fn = (func,) - return Genlet - -# ____________________________________________________________ - - -def g1(n, seen): - for i in range(n): - seen.append(i + 1) - yield i - - -def g2(n, seen): - for i in range(n): - seen.append(i + 1) - Yield(i) - -g2 = Genlet(g2) - - -def nested(i): - Yield(i) - - -def g3(n, seen): - for i in range(n): - seen.append(i + 1) - nested(i) -g3 = Genlet(g3) - - -def a(n): - if n == 0: - return - for ii in ax(n - 1): - Yield(ii) - Yield(n) -ax = Genlet(a) - - -def perms(l): - if len(l) > 1: - for e in l: - # No syntactical sugar for generator expressions - [Yield([e] + p) for p in perms([x for x in l if x != e])] - else: - Yield(l) -perms = Genlet(perms) - - -def gr1(n): - for ii in range(1, n): - Yield(ii) - Yield(ii * ii, 2) - -gr1 = Genlet(gr1) - - -def gr2(n, seen): - for ii in gr1(n): - seen.append(ii) - -gr2 = Genlet(gr2) - - -class NestedGeneratorTests(unittest.TestCase): - def test_layered_genlets(self): - seen = [] - for ii in gr2(5, seen): - seen.append(ii) - self.assertEqual(seen, [1, 1, 2, 4, 3, 9, 4, 16]) - - def test_permutations(self): - gen_perms = perms(list(range(4))) - permutations = list(gen_perms) - self.assertEqual(len(permutations), 4 * 3 * 2 * 1) - self.assertTrue([0, 1, 2, 3] in permutations) - self.assertTrue([3, 2, 1, 0] in permutations) - res = [] - for ii in zip(perms(list(range(4))), perms(list(range(3)))): - res.append(ii) - self.assertEqual( - res, - [([0, 1, 2, 3], [0, 1, 2]), ([0, 1, 3, 2], [0, 2, 1]), - ([0, 2, 1, 3], [1, 0, 2]), ([0, 2, 3, 1], [1, 2, 0]), - ([0, 3, 1, 2], [2, 0, 1]), ([0, 3, 2, 1], [2, 1, 0])]) - # XXX Test to make sure we are working as a generator expression - - def test_genlet_simple(self): - for g in [g1, g2, g3]: - seen = [] - for k in range(3): - for j in g(5, seen): - seen.append(j) - self.assertEqual(seen, 3 * [1, 0, 2, 1, 3, 2, 4, 3, 5, 4]) - - def test_genlet_bad(self): - try: - Yield(10) - except RuntimeError: - pass - - def test_nested_genlets(self): - seen = [] - for ii in ax(5): - seen.append(ii) diff --git a/tests/test_greenlet.py b/tests/test_greenlet.py deleted file mode 100644 index 5a3fe10..0000000 --- a/tests/test_greenlet.py +++ /dev/null @@ -1,542 +0,0 @@ -import gc -import sys -import time -import threading -import unittest - -from greenlet import greenlet - -try: - from abc import ABCMeta, abstractmethod -except ImportError: - ABCMeta = None - abstractmethod = None - - -class SomeError(Exception): - pass - - -def fmain(seen): - try: - greenlet.getcurrent().parent.switch() - except: - seen.append(sys.exc_info()[0]) - raise - raise SomeError - - -def send_exception(g, exc): - # note: send_exception(g, exc) can be now done with g.throw(exc). - # the purpose of this test is to explicitely check the propagation rules. - def crasher(exc): - raise exc - g1 = greenlet(crasher, parent=g) - g1.switch(exc) - - -class GreenletTests(unittest.TestCase): - def test_simple(self): - lst = [] - - def f(): - lst.append(1) - greenlet.getcurrent().parent.switch() - lst.append(3) - g = greenlet(f) - lst.append(0) - g.switch() - lst.append(2) - g.switch() - lst.append(4) - self.assertEqual(lst, list(range(5))) - - def test_parent_equals_None(self): - g = greenlet(parent=None) - - def test_run_equals_None(self): - g = greenlet(run=None) - - def test_two_children(self): - lst = [] - - def f(): - lst.append(1) - greenlet.getcurrent().parent.switch() - lst.extend([1, 1]) - g = greenlet(f) - h = greenlet(f) - g.switch() - self.assertEqual(len(lst), 1) - h.switch() - self.assertEqual(len(lst), 2) - h.switch() - self.assertEqual(len(lst), 4) - self.assertEqual(h.dead, True) - g.switch() - self.assertEqual(len(lst), 6) - self.assertEqual(g.dead, True) - - def test_two_recursive_children(self): - lst = [] - - def f(): - lst.append(1) - greenlet.getcurrent().parent.switch() - - def g(): - lst.append(1) - g = greenlet(f) - g.switch() - lst.append(1) - g = greenlet(g) - g.switch() - self.assertEqual(len(lst), 3) - self.assertEqual(sys.getrefcount(g), 2) - - def test_threads(self): - success = [] - - def f(): - self.test_simple() - success.append(True) - ths = [threading.Thread(target=f) for i in range(10)] - for th in ths: - th.start() - for th in ths: - th.join() - self.assertEqual(len(success), len(ths)) - - def test_exception(self): - seen = [] - g1 = greenlet(fmain) - g2 = greenlet(fmain) - g1.switch(seen) - g2.switch(seen) - g2.parent = g1 - self.assertEqual(seen, []) - self.assertRaises(SomeError, g2.switch) - self.assertEqual(seen, [SomeError]) - g2.switch() - self.assertEqual(seen, [SomeError]) - - def test_send_exception(self): - seen = [] - g1 = greenlet(fmain) - g1.switch(seen) - self.assertRaises(KeyError, send_exception, g1, KeyError) - self.assertEqual(seen, [KeyError]) - - def test_dealloc(self): - seen = [] - g1 = greenlet(fmain) - g2 = greenlet(fmain) - g1.switch(seen) - g2.switch(seen) - self.assertEqual(seen, []) - del g1 - gc.collect() - self.assertEqual(seen, [greenlet.GreenletExit]) - del g2 - gc.collect() - self.assertEqual(seen, [greenlet.GreenletExit, greenlet.GreenletExit]) - - def test_dealloc_other_thread(self): - seen = [] - someref = [] - lock = threading.Lock() - lock.acquire() - lock2 = threading.Lock() - lock2.acquire() - - def f(): - g1 = greenlet(fmain) - g1.switch(seen) - someref.append(g1) - del g1 - gc.collect() - lock.release() - lock2.acquire() - greenlet() # trigger release - lock.release() - lock2.acquire() - t = threading.Thread(target=f) - t.start() - lock.acquire() - self.assertEqual(seen, []) - self.assertEqual(len(someref), 1) - del someref[:] - gc.collect() - # g1 is not released immediately because it's from another thread - self.assertEqual(seen, []) - lock2.release() - lock.acquire() - self.assertEqual(seen, [greenlet.GreenletExit]) - lock2.release() - t.join() - - def test_frame(self): - def f1(): - f = sys._getframe(0) - self.assertEqual(f.f_back, None) - greenlet.getcurrent().parent.switch(f) - return "meaning of life" - g = greenlet(f1) - frame = g.switch() - self.assertTrue(frame is g.gr_frame) - self.assertTrue(g) - next = g.switch() - self.assertFalse(g) - self.assertEqual(next, 'meaning of life') - self.assertEqual(g.gr_frame, None) - - def test_thread_bug(self): - def runner(x): - g = greenlet(lambda: time.sleep(x)) - g.switch() - t1 = threading.Thread(target=runner, args=(0.2,)) - t2 = threading.Thread(target=runner, args=(0.3,)) - t1.start() - t2.start() - t1.join() - t2.join() - - def test_switch_kwargs(self): - def foo(a, b): - self.assertEqual(a, 4) - self.assertEqual(b, 2) - greenlet(foo).switch(a=4, b=2) - - def test_switch_kwargs_to_parent(self): - def foo(x): - greenlet.getcurrent().parent.switch(x=x) - greenlet.getcurrent().parent.switch(2, x=3) - return x, x ** 2 - g = greenlet(foo) - self.assertEqual({'x': 3}, g.switch(3)) - self.assertEqual(((2,), {'x': 3}), g.switch()) - self.assertEqual((3, 9), g.switch()) - - def test_switch_to_another_thread(self): - data = {} - error = None - created_event = threading.Event() - done_event = threading.Event() - - def foo(): - data['g'] = greenlet(lambda: None) - created_event.set() - done_event.wait() - thread = threading.Thread(target=foo) - thread.start() - created_event.wait() - try: - data['g'].switch() - except greenlet.error: - error = sys.exc_info()[1] - self.assertTrue(error != None, "greenlet.error was not raised!") - done_event.set() - thread.join() - - def test_exc_state(self): - def f(): - try: - raise ValueError('fun') - except: - exc_info = sys.exc_info() - greenlet(h).switch() - self.assertEqual(exc_info, sys.exc_info()) - - def h(): - self.assertEqual(sys.exc_info(), (None, None, None)) - - greenlet(f).switch() - - def test_instance_dict(self): - def f(): - greenlet.getcurrent().test = 42 - def deldict(g): - del g.__dict__ - def setdict(g, value): - g.__dict__ = value - g = greenlet(f) - self.assertEqual(g.__dict__, {}) - g.switch() - self.assertEqual(g.test, 42) - self.assertEqual(g.__dict__, {'test': 42}) - g.__dict__ = g.__dict__ - self.assertEqual(g.__dict__, {'test': 42}) - self.assertRaises(TypeError, deldict, g) - self.assertRaises(TypeError, setdict, g, 42) - - def test_threaded_reparent(self): - data = {} - created_event = threading.Event() - done_event = threading.Event() - - def foo(): - data['g'] = greenlet(lambda: None) - created_event.set() - done_event.wait() - - def blank(): - greenlet.getcurrent().parent.switch() - - def setparent(g, value): - g.parent = value - - thread = threading.Thread(target=foo) - thread.start() - created_event.wait() - g = greenlet(blank) - g.switch() - self.assertRaises(ValueError, setparent, g, data['g']) - done_event.set() - thread.join() - - def test_deepcopy(self): - import copy - self.assertRaises(TypeError, copy.copy, greenlet()) - self.assertRaises(TypeError, copy.deepcopy, greenlet()) - - def test_parent_restored_on_kill(self): - hub = greenlet(lambda: None) - main = greenlet.getcurrent() - result = [] - def worker(): - try: - # Wait to be killed - main.switch() - except greenlet.GreenletExit: - # Resurrect and switch to parent - result.append(greenlet.getcurrent().parent) - result.append(greenlet.getcurrent()) - hub.switch() - g = greenlet(worker, parent=hub) - g.switch() - del g - self.assertTrue(result) - self.assertEqual(result[0], main) - self.assertEqual(result[1].parent, hub) - - def test_parent_return_failure(self): - # No run causes AttributeError on switch - g1 = greenlet() - # Greenlet that implicitly switches to parent - g2 = greenlet(lambda: None, parent=g1) - # AttributeError should propagate to us, no fatal errors - self.assertRaises(AttributeError, g2.switch) - - def test_throw_exception_not_lost(self): - class mygreenlet(greenlet): - def __getattribute__(self, name): - try: - raise Exception() - except: - pass - return greenlet.__getattribute__(self, name) - g = mygreenlet(lambda: None) - self.assertRaises(SomeError, g.throw, SomeError()) - - def test_throw_doesnt_crash(self): - result = [] - def worker(): - greenlet.getcurrent().parent.switch() - def creator(): - g = greenlet(worker) - g.switch() - result.append(g) - t = threading.Thread(target=creator) - t.start() - t.join() - self.assertRaises(greenlet.error, result[0].throw, SomeError()) - - def test_recursive_startup(self): - class convoluted(greenlet): - def __init__(self): - greenlet.__init__(self) - self.count = 0 - def __getattribute__(self, name): - if name == 'run' and self.count == 0: - self.count = 1 - self.switch(43) - return greenlet.__getattribute__(self, name) - def run(self, value): - while True: - self.parent.switch(value) - g = convoluted() - self.assertEqual(g.switch(42), 43) - - def test_unexpected_reparenting(self): - another = [] - def worker(): - g = greenlet(lambda: None) - another.append(g) - g.switch() - t = threading.Thread(target=worker) - t.start() - t.join() - class convoluted(greenlet): - def __getattribute__(self, name): - if name == 'run': - self.parent = another[0] - return greenlet.__getattribute__(self, name) - g = convoluted(lambda: None) - self.assertRaises(greenlet.error, g.switch) - - def test_threaded_updatecurrent(self): - # released when main thread should execute - lock1 = threading.Lock() - lock1.acquire() - # released when another thread should execute - lock2 = threading.Lock() - lock2.acquire() - class finalized(object): - def __del__(self): - # happens while in green_updatecurrent() in main greenlet - # should be very careful not to accidentally call it again - # at the same time we must make sure another thread executes - lock2.release() - lock1.acquire() - # now ts_current belongs to another thread - def deallocator(): - greenlet.getcurrent().parent.switch() - def fthread(): - lock2.acquire() - greenlet.getcurrent() - del g[0] - lock1.release() - lock2.acquire() - greenlet.getcurrent() - lock1.release() - main = greenlet.getcurrent() - g = [greenlet(deallocator)] - g[0].bomb = finalized() - g[0].switch() - t = threading.Thread(target=fthread) - t.start() - # let another thread grab ts_current and deallocate g[0] - lock2.release() - lock1.acquire() - # this is the corner stone - # getcurrent() will notice that ts_current belongs to another thread - # and start the update process, which would notice that g[0] should - # be deallocated, and that will execute an object's finalizer. Now, - # that object will let another thread run so it can grab ts_current - # again, which would likely crash the interpreter if there's no - # check for this case at the end of green_updatecurrent(). This test - # passes if getcurrent() returns correct result, but it's likely - # to randomly crash if it's not anyway. - self.assertEqual(greenlet.getcurrent(), main) - # wait for another thread to complete, just in case - t.join() - - def test_dealloc_switch_args_not_lost(self): - seen = [] - def worker(): - # wait for the value - value = greenlet.getcurrent().parent.switch() - # delete all references to ourself - del worker[0] - initiator.parent = greenlet.getcurrent().parent - # switch to main with the value, but because - # ts_current is the last reference to us we - # return immediately - try: - greenlet.getcurrent().parent.switch(value) - finally: - seen.append(greenlet.getcurrent()) - def initiator(): - return 42 # implicitly falls thru to parent - worker = [greenlet(worker)] - worker[0].switch() # prime worker - initiator = greenlet(initiator, worker[0]) - value = initiator.switch() - self.assertTrue(seen) - self.assertEqual(value, 42) - - if sys.version_info[0] == 2: - # There's no apply in Python 3.x - def test_tuple_subclass(self): - class mytuple(tuple): - def __len__(self): - greenlet.getcurrent().switch() - return tuple.__len__(self) - args = mytuple() - kwargs = dict(a=42) - def switchapply(): - apply(greenlet.getcurrent().parent.switch, args, kwargs) - g = greenlet(switchapply) - self.assertEqual(g.switch(), kwargs) - - if ABCMeta is not None and abstractmethod is not None: - def test_abstract_subclasses(self): - AbstractSubclass = ABCMeta( - 'AbstractSubclass', - (greenlet,), - {'run': abstractmethod(lambda self: None)}) - - class BadSubclass(AbstractSubclass): - pass - - class GoodSubclass(AbstractSubclass): - def run(self): - pass - - GoodSubclass() # should not raise - self.assertRaises(TypeError, BadSubclass) - - def test_implicit_parent_with_threads(self): - if not gc.isenabled(): - return # cannot test with disabled gc - N = gc.get_threshold()[0] - if N < 50: - return # cannot test with such a small N - def attempt(): - lock1 = threading.Lock() - lock1.acquire() - lock2 = threading.Lock() - lock2.acquire() - recycled = [False] - def another_thread(): - lock1.acquire() # wait for gc - greenlet.getcurrent() # update ts_current - lock2.release() # release gc - t = threading.Thread(target=another_thread) - t.start() - class gc_callback(object): - def __del__(self): - lock1.release() - lock2.acquire() - recycled[0] = True - class garbage(object): - def __init__(self): - self.cycle = self - self.callback = gc_callback() - l = [] - x = range(N*2) - current = greenlet.getcurrent() - g = garbage() - for i in x: - g = None # lose reference to garbage - if recycled[0]: - # gc callback called prematurely - t.join() - return False - last = greenlet() - if recycled[0]: - break # yes! gc called in green_new - l.append(last) # increase allocation counter - else: - # gc callback not called when expected - gc.collect() - if recycled[0]: - t.join() - return False - self.assertEqual(last.parent, current) - for g in l: - self.assertEqual(g.parent, current) - return True - for i in range(5): - if attempt(): - break diff --git a/tests/test_leaks.py b/tests/test_leaks.py deleted file mode 100644 index 2b24ea0..0000000 --- a/tests/test_leaks.py +++ /dev/null @@ -1,85 +0,0 @@ -import unittest -import sys -import gc - -import time -import weakref -import greenlet -import threading - - -class ArgRefcountTests(unittest.TestCase): - def test_arg_refs(self): - args = ('a', 'b', 'c') - refcount_before = sys.getrefcount(args) - g = greenlet.greenlet( - lambda *args: greenlet.getcurrent().parent.switch(*args)) - for i in range(100): - g.switch(*args) - self.assertEqual(sys.getrefcount(args), refcount_before) - - def test_kwarg_refs(self): - kwargs = {} - g = greenlet.greenlet( - lambda **kwargs: greenlet.getcurrent().parent.switch(**kwargs)) - for i in range(100): - g.switch(**kwargs) - self.assertEqual(sys.getrefcount(kwargs), 2) - - if greenlet.GREENLET_USE_GC: - # These only work with greenlet gc support - - def recycle_threads(self): - # By introducing a thread that does sleep we allow other threads, - # that have triggered their __block condition, but did not have a - # chance to deallocate their thread state yet, to finally do so. - # The way it works is by requiring a GIL switch (different thread), - # which does a GIL release (sleep), which might do a GIL switch - # to finished threads and allow them to clean up. - def worker(): - time.sleep(0.001) - t = threading.Thread(target=worker) - t.start() - time.sleep(0.001) - t.join() - - def test_threaded_leak(self): - gg = [] - def worker(): - # only main greenlet present - gg.append(weakref.ref(greenlet.getcurrent())) - for i in range(2): - t = threading.Thread(target=worker) - t.start() - t.join() - del t - greenlet.getcurrent() # update ts_current - self.recycle_threads() - greenlet.getcurrent() # update ts_current - gc.collect() - greenlet.getcurrent() # update ts_current - for g in gg: - self.assertTrue(g() is None) - - def test_threaded_adv_leak(self): - gg = [] - def worker(): - # main and additional *finished* greenlets - ll = greenlet.getcurrent().ll = [] - def additional(): - ll.append(greenlet.getcurrent()) - for i in range(2): - greenlet.greenlet(additional).switch() - gg.append(weakref.ref(greenlet.getcurrent())) - for i in range(2): - t = threading.Thread(target=worker) - t.start() - t.join() - del t - greenlet.getcurrent() # update ts_current - self.recycle_threads() - greenlet.getcurrent() # update ts_current - gc.collect() - greenlet.getcurrent() # update ts_current - for g in gg: - self.assertTrue(g() is None) diff --git a/tests/test_stack_saved.py b/tests/test_stack_saved.py deleted file mode 100644 index 6c7353b..0000000 --- a/tests/test_stack_saved.py +++ /dev/null @@ -1,19 +0,0 @@ -import greenlet -import unittest - - -class Test(unittest.TestCase): - - def test_stack_saved(self): - main = greenlet.getcurrent() - self.assertEqual(main._stack_saved, 0) - - def func(): - main.switch(main._stack_saved) - - g = greenlet.greenlet(func) - x = g.switch() - assert x > 0, x - assert g._stack_saved > 0, g._stack_saved - g.switch() - assert g._stack_saved == 0, g._stack_saved diff --git a/tests/test_throw.py b/tests/test_throw.py deleted file mode 100644 index a2014a9..0000000 --- a/tests/test_throw.py +++ /dev/null @@ -1,100 +0,0 @@ -import sys -import unittest - -from greenlet import greenlet - - -def switch(*args): - return greenlet.getcurrent().parent.switch(*args) - - -class ThrowTests(unittest.TestCase): - def test_class(self): - def f(): - try: - switch("ok") - except RuntimeError: - switch("ok") - return - switch("fail") - g = greenlet(f) - res = g.switch() - self.assertEqual(res, "ok") - res = g.throw(RuntimeError) - self.assertEqual(res, "ok") - - def test_val(self): - def f(): - try: - switch("ok") - except RuntimeError: - val = sys.exc_info()[1] - if str(val) == "ciao": - switch("ok") - return - switch("fail") - - g = greenlet(f) - res = g.switch() - self.assertEqual(res, "ok") - res = g.throw(RuntimeError("ciao")) - self.assertEqual(res, "ok") - - g = greenlet(f) - res = g.switch() - self.assertEqual(res, "ok") - res = g.throw(RuntimeError, "ciao") - self.assertEqual(res, "ok") - - def test_kill(self): - def f(): - switch("ok") - switch("fail") - g = greenlet(f) - res = g.switch() - self.assertEqual(res, "ok") - res = g.throw() - self.assertTrue(isinstance(res, greenlet.GreenletExit)) - self.assertTrue(g.dead) - res = g.throw() # immediately eaten by the already-dead greenlet - self.assertTrue(isinstance(res, greenlet.GreenletExit)) - - def test_throw_goes_to_original_parent(self): - main = greenlet.getcurrent() - - def f1(): - try: - main.switch("f1 ready to catch") - except IndexError: - return "caught" - else: - return "normal exit" - - def f2(): - main.switch("from f2") - - g1 = greenlet(f1) - g2 = greenlet(f2, parent=g1) - self.assertRaises(IndexError, g2.throw, IndexError) - self.assertTrue(g2.dead) - self.assertTrue(g1.dead) - - g1 = greenlet(f1) - g2 = greenlet(f2, parent=g1) - res = g1.switch() - self.assertEqual(res, "f1 ready to catch") - res = g2.throw(IndexError) - self.assertEqual(res, "caught") - self.assertTrue(g2.dead) - self.assertTrue(g1.dead) - - g1 = greenlet(f1) - g2 = greenlet(f2, parent=g1) - res = g1.switch() - self.assertEqual(res, "f1 ready to catch") - res = g2.switch() - self.assertEqual(res, "from f2") - res = g2.throw(IndexError) - self.assertEqual(res, "caught") - self.assertTrue(g2.dead) - self.assertTrue(g1.dead) diff --git a/tests/test_tracing.py b/tests/test_tracing.py deleted file mode 100644 index 4f34b15..0000000 --- a/tests/test_tracing.py +++ /dev/null @@ -1,52 +0,0 @@ -import unittest -import threading -import greenlet - -class SomeError(Exception): - pass - -class TracingTests(unittest.TestCase): - if greenlet.GREENLET_USE_TRACING: - def test_greenlet_tracing(self): - main = greenlet.getcurrent() - actions = [] - def trace(*args): - actions.append(args) - def dummy(): - pass - def dummyexc(): - raise SomeError() - oldtrace = greenlet.settrace(trace) - try: - g1 = greenlet.greenlet(dummy) - g1.switch() - g2 = greenlet.greenlet(dummyexc) - self.assertRaises(SomeError, g2.switch) - finally: - greenlet.settrace(oldtrace) - self.assertEqual(actions, [ - ('switch', (main, g1)), - ('switch', (g1, main)), - ('switch', (main, g2)), - ('throw', (g2, main)), - ]) - - def test_exception_disables_tracing(self): - main = greenlet.getcurrent() - actions = [] - def trace(*args): - actions.append(args) - raise SomeError() - def dummy(): - main.switch() - g = greenlet.greenlet(dummy) - g.switch() - oldtrace = greenlet.settrace(trace) - try: - self.assertRaises(SomeError, g.switch) - self.assertEqual(greenlet.gettrace(), None) - finally: - greenlet.settrace(oldtrace) - self.assertEqual(actions, [ - ('switch', (main, g)), - ]) diff --git a/tests/test_version.py b/tests/test_version.py deleted file mode 100755 index 5870e52..0000000 --- a/tests/test_version.py +++ /dev/null @@ -1,20 +0,0 @@ -#! /usr/bin/env python - -import sys, os, re, unittest, greenlet - -def readclose(f): - try: - return f.read() - finally: - f.close() - -def readfile(filename): - return readclose(open(filename)) - -class VersionTests(unittest.TestCase): - def test_version(self): - upfile = lambda p: os.path.join(os.path.dirname(__file__), "..", p) - hversion, = re.findall('GREENLET_VERSION "(.*)"', readfile(upfile("greenlet.h"))) - sversion = readclose(os.popen("%s %s --version" % (sys.executable, upfile("setup.py")))).strip() - self.assertFalse(sversion != hversion) - self.assertFalse(sversion != greenlet.__version__) diff --git a/tests/test_weakref.py b/tests/test_weakref.py deleted file mode 100644 index 6a2ff06..0000000 --- a/tests/test_weakref.py +++ /dev/null @@ -1,34 +0,0 @@ -import gc -import greenlet -import weakref -import unittest - - -class WeakRefTests(unittest.TestCase): - def test_dead_weakref(self): - def _dead_greenlet(): - g = greenlet.greenlet(lambda: None) - g.switch() - return g - o = weakref.ref(_dead_greenlet()) - gc.collect() - self.assertEqual(o(), None) - - def test_inactive_weakref(self): - o = weakref.ref(greenlet.greenlet()) - gc.collect() - self.assertEqual(o(), None) - - def test_dealloc_weakref(self): - seen = [] - def worker(): - try: - greenlet.getcurrent().parent.switch() - finally: - seen.append(g()) - g = greenlet.greenlet(worker) - g.switch() - g2 = greenlet.greenlet(lambda: None, g) - g = weakref.ref(g2) - g2 = None - self.assertEqual(seen, [None]) |
