#include <Python.h>
#include <talloc.h>
#include <pytalloc.h>
+#include "pytalloc_private.h"
static PyTypeObject TallocObject_Type;
#endif
};
+/**
+ * Default (but only slightly more useful than the default) implementation of Repr().
+ */
+static PyObject *pytalloc_base_default_repr(PyObject *obj)
+{
+ pytalloc_BaseObject *talloc_obj = (pytalloc_BaseObject *)obj;
+ PyTypeObject *type = (PyTypeObject*)PyObject_Type(obj);
+
+ return PyStr_FromFormat("<%s talloc based object at 0x%p>",
+ type->tp_name, talloc_obj->ptr);
+}
+
+/**
+ * Simple dealloc for talloc-wrapping PyObjects
+ */
+static void pytalloc_base_dealloc(PyObject* self)
+{
+ pytalloc_BaseObject *obj = (pytalloc_BaseObject *)self;
+ assert(talloc_unlink(NULL, obj->talloc_ctx) != -1);
+ obj->talloc_ctx = NULL;
+ self->ob_type->tp_free(self);
+}
+
+/**
+ * Default (but only slightly more useful than the default) implementation of cmp.
+ */
+#if PY_MAJOR_VERSION >= 3
+static PyObject *pytalloc_base_default_richcmp(PyObject *obj1, PyObject *obj2, int op)
+{
+ void *ptr1;
+ void *ptr2;
+ if (Py_TYPE(obj1) == Py_TYPE(obj2)) {
+ /* When types match, compare pointers */
+ ptr1 = pytalloc_get_ptr(obj1);
+ ptr2 = pytalloc_get_ptr(obj2);
+ } else if (PyObject_TypeCheck(obj2, &TallocObject_Type)) {
+ /* Otherwise, compare types */
+ ptr1 = Py_TYPE(obj1);
+ ptr2 = Py_TYPE(obj2);
+ } else {
+ Py_INCREF(Py_NotImplemented);
+ return Py_NotImplemented;
+ }
+ switch (op) {
+ case Py_EQ: return PyBool_FromLong(ptr1 == ptr2);
+ case Py_NE: return PyBool_FromLong(ptr1 != ptr2);
+ case Py_LT: return PyBool_FromLong(ptr1 < ptr2);
+ case Py_GT: return PyBool_FromLong(ptr1 > ptr2);
+ case Py_LE: return PyBool_FromLong(ptr1 <= ptr2);
+ case Py_GE: return PyBool_FromLong(ptr1 >= ptr2);
+ }
+ Py_INCREF(Py_NotImplemented);
+ return Py_NotImplemented;
+}
+#else
+static int pytalloc_base_default_cmp(PyObject *_obj1, PyObject *_obj2)
+{
+ pytalloc_BaseObject *obj1 = (pytalloc_BaseObject *)_obj1,
+ *obj2 = (pytalloc_BaseObject *)_obj2;
+ if (obj1->ob_type != obj2->ob_type)
+ return ((char *)obj1->ob_type - (char *)obj2->ob_type);
+
+ return ((char *)pytalloc_get_ptr(obj1) - (char *)pytalloc_get_ptr(obj2));
+}
+#endif
+
+static PyTypeObject TallocBaseObject_Type = {
+ .tp_name = "talloc.BaseObject",
+ .tp_doc = "Python wrapper for a talloc-maintained object.",
+ .tp_basicsize = sizeof(pytalloc_BaseObject),
+ .tp_dealloc = (destructor)pytalloc_base_dealloc,
+ .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
+ .tp_repr = pytalloc_base_default_repr,
+#if PY_MAJOR_VERSION >= 3
+ .tp_richcompare = pytalloc_base_default_richcmp,
+#else
+ .tp_compare = pytalloc_base_default_cmp,
+#endif
+};
+
#define MODULE_DOC PyDoc_STR("Python wrapping of talloc-maintained objects.")
#if PY_MAJOR_VERSION >= 3
if (PyType_Ready(&TallocObject_Type) < 0)
return NULL;
+ if (PyType_Ready(&TallocBaseObject_Type) < 0)
+ return NULL;
+
#if PY_MAJOR_VERSION >= 3
m = PyModule_Create(&moduledef);
#else
Py_INCREF(&TallocObject_Type);
PyModule_AddObject(m, "Object", (PyObject *)&TallocObject_Type);
+ Py_INCREF(&TallocBaseObject_Type);
+ PyModule_AddObject(m, "BaseObject", (PyObject *)&TallocBaseObject_Type);
return m;
}
typedef struct {
PyObject_HEAD
TALLOC_CTX *talloc_ctx;
- void *ptr;
+ void *ptr; /* eg the array element */
} pytalloc_Object;
/* Return the PyTypeObject for pytalloc_Object. Returns a new reference. */
PyTypeObject *pytalloc_GetObjectType(void);
+/* Return the PyTypeObject for pytalloc_BaseObject. Returns a new reference. */
+PyTypeObject *pytalloc_GetBaseObjectType(void);
+
/* Check whether a specific object is a talloc Object. */
int pytalloc_Check(PyObject *);
+int pytalloc_BaseObject_check(PyObject *);
+
/* Retrieve the pointer for a pytalloc_object. Like talloc_get_type()
* but for pytalloc_Objects. */
void *_pytalloc_get_type(PyObject *py_obj, const char *type_name);
PyObject *pytalloc_CObject_FromTallocPtr(void *);
#endif
+size_t pytalloc_BaseObject_size(void);
+
+
#endif /* _PYTALLOC_H_ */
To make a build for Python 3, configure with PYTHON=/usr/bin/python3.
.
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
-pytalloc_Object
+pytalloc_Object / pytalloc_BaseObject
This is the new base class that all Python objects that wrap talloc pointers
derive from. It is itself a subclass of the "Object" type that all objects
themselves (since there can be multiple objects that wrap the same talloc
pointer).
+It is preferred to use pytalloc_BaseObject as this implementation
+exposes less in the C ABI and correctly supports pointers in C arrays
+in the way needed by PIDL.
+
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
PyTypeObject *pytalloc_GetObjectType(void)
counter for the object will be incremented, so the caller will have to
decrement it when it no longer needs it (using `Py_DECREF`).
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+PyTypeObject *pytalloc_GetBaseObjectType(void)
+
+Obtain a reference to the PyTypeObject for `pytalloc_Object`. The reference
+counter for the object will be incremented, so the caller will have to
+decrement it when it no longer needs it (using `Py_DECREF`).
+
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-==-=-=-=-=-=-=-=-=-=-=-
int pytalloc_Check(PyObject *)
Check whether a specific object is a talloc Object. Returns non-zero if it is
a pytalloc_Object and zero otherwise.
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-==-=-=-=-=-=-=-=-=-=-=-
+int pytalloc_BaseObject_Check(PyObject *)
+
+Check whether a specific object is a talloc BaseObject. Returns non-zero if it is
+a pytalloc_BaseObject and zero otherwise.
+
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
type *pytalloc_get_type(PyObject *py_obj, type)
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
pytalloc_get_ptr(PyObject *py_obj)
-Retrieve the pointer from a `pytalloc_Object` py_obj. There is no
-type checking - use `pytalloc_get_type` if possible.
+Retrieve the pointer from a `pytalloc_Object` or `pytalloc_BaseObject`
+py_obj. There is no type checking - use `pytalloc_get_type` if
+possible.
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
TALLOC_CTX *pytalloc_get_mem_ctx(PyObject *py_obj)
-Retrieve the talloc context associated with a pytalloc_Object.
+Retrieve the talloc context associated with a pytalloc_Object or pytalloc_BaseObject.
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
PyObject *pytalloc_steal_ex(PyTypeObject *py_type, TALLOC_CTX *mem_ctx, void *ptr)
--- /dev/null
+/*
+ Unix SMB/CIFS implementation.
+ Samba utility functions
+ Copyright (C) Jelmer Vernooij <jelmer@samba.org> 2008
+ Copyright (C) Andrew Bartlett <abartlet@samba.org> 2016
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+typedef struct {
+ PyObject_HEAD
+ TALLOC_CTX *talloc_ctx;
+ TALLOC_CTX *talloc_ptr_ctx; /* eg the start of the array */
+ void *ptr; /* eg the array element */
+} pytalloc_BaseObject;
#include <talloc.h>
#include "pytalloc.h"
#include <assert.h>
+#include "pytalloc_private.h"
_PUBLIC_ PyTypeObject *pytalloc_GetObjectType(void)
{
return type;
}
+_PUBLIC_ PyTypeObject *pytalloc_GetBaseObjectType(void)
+{
+ static PyTypeObject *type = NULL;
+ PyObject *mod;
+
+ if (type != NULL) {
+ return type;
+ }
+
+ mod = PyImport_ImportModule("talloc");
+ if (mod == NULL) {
+ return NULL;
+ }
+
+ type = (PyTypeObject *)PyObject_GetAttrString(mod, "BaseObject");
+ Py_DECREF(mod);
+
+ return type;
+}
+
/**
* Import an existing talloc pointer into a Python object.
*/
_PUBLIC_ PyObject *pytalloc_steal_ex(PyTypeObject *py_type, TALLOC_CTX *mem_ctx,
- void *ptr)
+ void *ptr)
{
- pytalloc_Object *ret = (pytalloc_Object *)py_type->tp_alloc(py_type, 0);
- ret->talloc_ctx = talloc_new(NULL);
- if (ret->talloc_ctx == NULL) {
- return NULL;
+ PyTypeObject *BaseObjectType = pytalloc_GetBaseObjectType();
+ PyTypeObject *ObjectType = pytalloc_GetObjectType();
+
+ if (mem_ctx == NULL) {
+ return PyErr_NoMemory();
}
- if (talloc_steal(ret->talloc_ctx, mem_ctx) == NULL) {
+
+ if (PyType_IsSubtype(py_type, BaseObjectType)) {
+ pytalloc_BaseObject *ret
+ = (pytalloc_BaseObject *)py_type->tp_alloc(py_type, 0);
+
+ ret->talloc_ctx = talloc_new(NULL);
+ if (ret->talloc_ctx == NULL) {
+ return NULL;
+ }
+
+ /*
+ * This allows us to keep multiple references to this object -
+ * we only reference this context, which is per ptr, not the
+ * talloc_ctx, which is per pytalloc_Object
+ */
+ if (talloc_steal(ret->talloc_ctx, mem_ctx) == NULL) {
+ return NULL;
+ }
+ ret->talloc_ptr_ctx = mem_ctx;
+ talloc_set_name_const(ret->talloc_ctx, py_type->tp_name);
+ ret->ptr = ptr;
+ return (PyObject *)ret;
+
+ } else if (PyType_IsSubtype(py_type, ObjectType)) {
+ pytalloc_Object *ret
+ = (pytalloc_Object *)py_type->tp_alloc(py_type, 0);
+
+ ret->talloc_ctx = talloc_new(NULL);
+ if (ret->talloc_ctx == NULL) {
+ return NULL;
+ }
+
+ if (talloc_steal(ret->talloc_ctx, mem_ctx) == NULL) {
+ return NULL;
+ }
+ talloc_set_name_const(ret->talloc_ctx, py_type->tp_name);
+ ret->ptr = ptr;
+ return (PyObject *)ret;
+ } else {
+ PyErr_SetString(PyExc_RuntimeError,
+ "pytalloc_steal_ex() called for object type "
+ "not based on talloc");
return NULL;
}
- talloc_set_name_const(ret->talloc_ctx, py_type->tp_name);
- ret->ptr = ptr;
- return (PyObject *)ret;
}
/**
/**
* Import an existing talloc pointer into a Python object, leaving the
* original parent, and creating a reference to the object in the python
- * object
+ * object.
+ *
+ * We remember the object we hold the reference to (a
+ * possibly-non-talloc pointer), the existing parent (typically the
+ * start of the array) and the new referenced parent. That way we can
+ * cope with the fact that we will have multiple parents, one per time
+ * python sees the object.
*/
-_PUBLIC_ PyObject *pytalloc_reference_ex(PyTypeObject *py_type, TALLOC_CTX *mem_ctx, void *ptr)
+_PUBLIC_ PyObject *pytalloc_reference_ex(PyTypeObject *py_type,
+ TALLOC_CTX *mem_ctx, void *ptr)
{
- pytalloc_Object *ret;
+ PyTypeObject *BaseObjectType = pytalloc_GetBaseObjectType();
+ PyTypeObject *ObjectType = pytalloc_GetObjectType();
- if (ptr == NULL) {
- Py_RETURN_NONE;
+ if (mem_ctx == NULL) {
+ return PyErr_NoMemory();
}
- ret = (pytalloc_Object *)py_type->tp_alloc(py_type, 0);
- ret->talloc_ctx = talloc_new(NULL);
- if (ret->talloc_ctx == NULL) {
- return NULL;
- }
- if (talloc_reference(ret->talloc_ctx, mem_ctx) == NULL) {
+ if (PyType_IsSubtype(py_type, BaseObjectType)) {
+ pytalloc_BaseObject *ret
+ = (pytalloc_BaseObject *)py_type->tp_alloc(py_type, 0);
+ ret->talloc_ctx = talloc_new(NULL);
+ if (ret->talloc_ctx == NULL) {
+ return NULL;
+ }
+ if (talloc_reference(ret->talloc_ctx, mem_ctx) == NULL) {
+ return NULL;
+ }
+ talloc_set_name_const(ret->talloc_ctx, py_type->tp_name);
+ ret->talloc_ptr_ctx = mem_ctx;
+ ret->ptr = ptr;
+ return (PyObject *)ret;
+ } else if (PyType_IsSubtype(py_type, ObjectType)) {
+ pytalloc_Object *ret
+ = (pytalloc_Object *)py_type->tp_alloc(py_type, 0);
+ ret->talloc_ctx = talloc_new(NULL);
+ if (ret->talloc_ctx == NULL) {
+ return NULL;
+ }
+ if (talloc_reference(ret->talloc_ctx, mem_ctx) == NULL) {
+ return NULL;
+ }
+ talloc_set_name_const(ret->talloc_ctx, py_type->tp_name);
+ ret->ptr = ptr;
+ return (PyObject *)ret;
+ } else {
+ PyErr_SetString(PyExc_RuntimeError,
+ "pytalloc_reference_ex() called for object type "
+ "not based on talloc");
return NULL;
}
- talloc_set_name_const(ret->talloc_ctx, py_type->tp_name);
- ret->ptr = ptr;
- return (PyObject *)ret;
}
#if PY_MAJOR_VERSION < 3
return PyObject_TypeCheck(obj, tp);
}
+_PUBLIC_ int pytalloc_BaseObject_check(PyObject *obj)
+{
+ PyTypeObject *tp = pytalloc_GetBaseObjectType();
+
+ return PyObject_TypeCheck(obj, tp);
+}
+
+_PUBLIC_ size_t pytalloc_BaseObject_size(void)
+{
+ return sizeof(pytalloc_BaseObject);
+}
+
_PUBLIC_ void *_pytalloc_get_type(PyObject *py_obj, const char *type_name)
{
void *ptr = _pytalloc_get_ptr(py_obj);
_PUBLIC_ void *_pytalloc_get_ptr(PyObject *py_obj)
{
- return ((pytalloc_Object *)py_obj)->ptr;
+ if (pytalloc_BaseObject_check(py_obj)) {
+ return ((pytalloc_BaseObject *)py_obj)->ptr;
+ }
+ if (pytalloc_Check(py_obj)) {
+ return ((pytalloc_Object *)py_obj)->ptr;
+ }
+ return NULL;
}
_PUBLIC_ TALLOC_CTX *_pytalloc_get_mem_ctx(PyObject *py_obj)
{
- return ((pytalloc_Object *)py_obj)->talloc_ctx;
+ if (pytalloc_BaseObject_check(py_obj)) {
+ return ((pytalloc_BaseObject *)py_obj)->talloc_ptr_ctx;
+ }
+ if (pytalloc_Check(py_obj)) {
+ return ((pytalloc_Object *)py_obj)->talloc_ctx;
+ }
+ return NULL;
}
return type;
}
+static PyObject *testpytalloc_base_new(PyTypeObject *mod)
+{
+ char *obj = talloc_strdup(NULL, "This is a test string for a BaseObject");;
+ return pytalloc_steal(pytalloc_GetBaseObjectType(), obj);
+}
+
+static PyObject *testpytalloc_base_get_object_type(PyObject *mod) {
+ PyObject *type = (PyObject *)pytalloc_GetBaseObjectType();
+ Py_INCREF(type);
+ return type;
+}
+
static PyObject *testpytalloc_reference(PyObject *mod, PyObject *args) {
PyObject *source = NULL;
void *ptr;
return pytalloc_reference_ex(pytalloc_GetObjectType(), ptr, ptr);
}
+static PyObject *testpytalloc_base_reference(PyObject *mod, PyObject *args) {
+ PyObject *source = NULL;
+ void *mem_ctx;
+
+ if (!PyArg_ParseTuple(args, "O!", pytalloc_GetBaseObjectType(), &source)) {
+ return NULL;
+ }
+ mem_ctx = pytalloc_get_mem_ctx(source);
+ return pytalloc_reference_ex(pytalloc_GetBaseObjectType(), mem_ctx, mem_ctx);
+}
+
static PyMethodDef test_talloc_methods[] = {
{ "new", (PyCFunction)testpytalloc_new, METH_NOARGS,
"create a talloc Object with a testing string"},
{ "get_object_type", (PyCFunction)testpytalloc_get_object_type, METH_NOARGS,
"call pytalloc_GetObjectType"},
+ { "base_new", (PyCFunction)testpytalloc_base_new, METH_NOARGS,
+ "create a talloc BaseObject with a testing string"},
+ { "base_get_object_type", (PyCFunction)testpytalloc_base_get_object_type, METH_NOARGS,
+ "call pytalloc_GetBaseObjectType"},
{ "reference", (PyCFunction)testpytalloc_reference, METH_VARARGS,
"call pytalloc_reference_ex"},
+ { "base_reference", (PyCFunction)testpytalloc_base_reference, METH_VARARGS,
+ "call pytalloc_reference_ex"},
{ NULL }
};
.tp_doc = "test talloc object that calls a function when underlying data is freed\n",
};
+static PyTypeObject DBaseObject_Type;
+
+static int d_base_object_destructor(void *ptr)
+{
+ PyObject *destructor_func = *talloc_get_type(ptr, PyObject*);
+ PyObject *ret;
+ ret = PyObject_CallObject(destructor_func, NULL);
+ Py_DECREF(destructor_func);
+ if (ret == NULL) {
+ PyErr_Print();
+ } else {
+ Py_DECREF(ret);
+ }
+ return 0;
+}
+
+static PyObject *d_base_object_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
+{
+ PyObject *destructor_func = NULL;
+ PyObject **obj;
+
+ if (!PyArg_ParseTuple(args, "O", &destructor_func))
+ return NULL;
+ Py_INCREF(destructor_func);
+
+ obj = talloc(NULL, PyObject*);
+ *obj = destructor_func;
+
+ talloc_set_destructor((void*)obj, d_base_object_destructor);
+ return pytalloc_steal(&DBaseObject_Type, obj);
+}
+
+static PyTypeObject DBaseObject_Type = {
+ .tp_name = "_test_pytalloc.DBaseObject",
+ .tp_methods = NULL,
+ .tp_new = d_base_object_new,
+ .tp_flags = Py_TPFLAGS_DEFAULT,
+ .tp_doc = "test talloc object that calls a function when underlying data is freed\n",
+};
+
#define MODULE_DOC PyDoc_STR("Test utility module for pytalloc")
#if PY_MAJOR_VERSION >= 3
return NULL;
}
+ DBaseObject_Type.tp_basicsize = pytalloc_BaseObject_size();
+ DBaseObject_Type.tp_base = pytalloc_GetBaseObjectType();
+ if (PyType_Ready(&DBaseObject_Type) < 0) {
+ return NULL;
+ }
+
#if PY_MAJOR_VERSION >= 3
m = PyModule_Create(&moduledef);
#else
Py_INCREF(DObject_Type.tp_base);
PyModule_AddObject(m, "DObject", (PyObject *)&DObject_Type);
+ Py_INCREF(&DBaseObject_Type);
+ Py_INCREF(DBaseObject_Type.tp_base);
+ PyModule_AddObject(m, "DBaseObject", (PyObject *)&DBaseObject_Type);
+
return m;
}
self.assertTrue(repr(obj).startswith(prefix))
self.assertEqual(repr(obj), str(obj))
+ def test_base_repr(self):
+ obj = _test_pytalloc.base_new()
+ prefix = '<talloc.BaseObject talloc based object at'
+ self.assertTrue(repr(obj).startswith(prefix))
+ self.assertEqual(repr(obj), str(obj))
+
def test_destructor(self):
# Check correct lifetime of the talloc'd data
lst = []
gc.collect()
self.assertEqual(lst, ['dead'])
+ def test_base_destructor(self):
+ # Check correct lifetime of the talloc'd data
+ lst = []
+ obj = _test_pytalloc.DBaseObject(lambda: lst.append('dead'))
+ self.assertEqual(lst, [])
+ del obj
+ gc.collect()
+ self.assertEqual(lst, ['dead'])
+
class TallocComparisonTests(unittest.TestCase):
self.assertFalse(obj1 >= obj2)
self.assertFalse(obj1 > obj2)
+class TallocBaseComparisonTests(unittest.TestCase):
+
+ def test_compare_same(self):
+ obj1 = _test_pytalloc.base_new()
+ self.assertTrue(obj1 == obj1)
+ self.assertFalse(obj1 != obj1)
+ self.assertTrue(obj1 <= obj1)
+ self.assertFalse(obj1 < obj1)
+ self.assertTrue(obj1 >= obj1)
+ self.assertFalse(obj1 > obj1)
+
+ def test_compare_different(self):
+ # object comparison is consistent
+ obj1, obj2 = sorted([
+ _test_pytalloc.base_new(),
+ _test_pytalloc.base_new()])
+ self.assertFalse(obj1 == obj2)
+ self.assertTrue(obj1 != obj2)
+ self.assertTrue(obj1 <= obj2)
+ self.assertTrue(obj1 < obj2)
+ self.assertFalse(obj1 >= obj2)
+ self.assertFalse(obj1 > obj2)
+
+ def test_compare_different_types(self):
+ # object comparison falls back to comparing types
+ if sys.version_info >= (3, 0):
+ # In Python 3, types are unorderable -- nothing to test
+ return
+ if talloc.BaseObject < _test_pytalloc.DBaseObject:
+ obj1 = _test_pytalloc.base_new()
+ obj2 = _test_pytalloc.DBaseObject(dummy_func)
+ else:
+ obj2 = _test_pytalloc.base_new()
+ obj1 = _test_pytalloc.DBaseObject(dummy_func)
+ self.assertFalse(obj1 == obj2)
+ self.assertTrue(obj1 != obj2)
+ self.assertTrue(obj1 <= obj2)
+ self.assertTrue(obj1 < obj2)
+ self.assertFalse(obj1 >= obj2)
+ self.assertFalse(obj1 > obj2)
+
class TallocUtilTests(unittest.TestCase):
def test_get_type(self):
self.assertTrue(talloc.Object is _test_pytalloc.get_object_type())
- def test_refrence(self):
+ def test_reference(self):
# Check correct lifetime of the talloc'd data with multiple references
lst = []
obj = _test_pytalloc.DObject(lambda: lst.append('dead'))
gc.collect()
self.assertEqual(lst, ['dead'])
+ def test_get_base_type(self):
+ self.assertTrue(talloc.BaseObject is _test_pytalloc.base_get_object_type())
+
+ def test_base_reference(self):
+ # Check correct lifetime of the talloc'd data with multiple references
+ lst = []
+ obj = _test_pytalloc.DBaseObject(lambda: lst.append('dead'))
+ ref = _test_pytalloc.base_reference(obj)
+ del obj
+ gc.collect()
+ self.assertEqual(lst, [])
+ del ref
+ gc.collect()
+ self.assertEqual(lst, ['dead'])
+
if __name__ == '__main__':
unittest.TestProgram()