diff --git a/ChangeLog b/ChangeLog index 6fb3640059..43f299132b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,17 @@ +2005-09-28 Thomas Vander Stichele + + * gst/gst.defs: + parse_launch also owns the return ref + * gst/gstbin.override: + fix a leak in get_by_name() + * testsuite/common.py: + loop when garbage collecting; necessary when deleting, say, + a pipeline, that contains elements, to ensure the elements + also get collected + * testsuite/test_element.py: + * testsuite/test_pipeline.py: + test for garbage collection + 2005-09-28 Thomas Vander Stichele * testsuite/common.py: diff --git a/gst/gst.defs b/gst/gst.defs index dd33dd5d09..978368a333 100644 --- a/gst/gst.defs +++ b/gst/gst.defs @@ -3686,6 +3686,7 @@ (define-function parse_launch (c-name "gst_parse_launch") (return-type "GstElement*") + (caller-owns-return #t) (parameters '("const-gchar*" "pipeline_description") '("GError**" "error") @@ -3695,6 +3696,7 @@ (define-function parse_launchv (c-name "gst_parse_launchv") (return-type "GstElement*") + (caller-owns-return #t) (parameters '("const-gchar**" "argv") '("GError**" "error") diff --git a/gst/gstbin.override b/gst/gstbin.override index 30a3f9898b..d4aa200098 100644 --- a/gst/gstbin.override +++ b/gst/gstbin.override @@ -139,17 +139,21 @@ _wrap_gst_bin_get_by_name(PyGObject *self, PyObject *args, PyObject *kwargs) static char *kwlist[] = { "name", "recurse", NULL }; char *name; gboolean recurse = FALSE; - GstElement *ret; + GstElement *el; + PyObject *ret; if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s|b:GstBin.get_by_name", kwlist, &name, &recurse)) return NULL; if (recurse) - ret = gst_bin_get_by_name_recurse_up(GST_BIN(self->obj), name); + el = gst_bin_get_by_name_recurse_up(GST_BIN(self->obj), name); else - ret = gst_bin_get_by_name(GST_BIN(self->obj), name); + el = gst_bin_get_by_name(GST_BIN(self->obj), name); /* pygobject_new handles NULL checking */ - return pygstobject_new((GObject *)ret); + ret = pygstobject_new((GObject *)el); + + gst_object_unref (el); /* from _get_by_name */ + return ret; } diff --git a/testsuite/common.py b/testsuite/common.py index 4e519f470d..43384bebda 100644 --- a/testsuite/common.py +++ b/testsuite/common.py @@ -114,9 +114,14 @@ def run_silent(function, *args, **kwargs): class TestCase(unittest.TestCase): def gccollect(self): # run the garbage collector + ret = 0 gst.debug('garbage collecting') - gc.collect() + while True: + c = gc.collect() + ret += c + if c == 0: break gst.debug('done garbage collecting') + return ret def gctrack(self): # store all gst objects in the gc in a tracking dict diff --git a/testsuite/test_element.py b/testsuite/test_element.py index fedaf73671..c9bcc876af 100644 --- a/testsuite/test_element.py +++ b/testsuite/test_element.py @@ -20,10 +20,9 @@ # License along with this library; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -from common import gst, unittest +from common import gst, unittest, TestCase import sys -import gc # since I can't subclass gst.Element for some reason, I use a bin here # it don't matter to Jesus @@ -165,18 +164,36 @@ class ElementName(unittest.TestCase): assert get_name(-1) == 'UNKNOWN!(-1)' self.assertRaises(TypeError, get_name, '') -class QueryTest(unittest.TestCase): +class QueryTest(TestCase): def setUp(self): + self.gctrack() self.pipeline = gst.parse_launch('fakesrc name=source ! fakesink') + self.assertEquals(self.pipeline.__gstrefcount__, 1) + self.element = self.pipeline.get_by_name('source') + self.assertEquals(self.pipeline.__gstrefcount__, 1) + self.assertEquals(self.element.__gstrefcount__, 2) + self.assertEquals(sys.getrefcount(self.element), 3) + + def tearDown(self): + del self.pipeline + del self.element + self.gccollect() + self.gcverify() def testQuery(self): + gst.debug('querying fakesrc in FORMAT_BYTES') res = self.element.query_position(gst.FORMAT_BYTES) + self.assertEquals(self.pipeline.__gstrefcount__, 1) + self.assertEquals(sys.getrefcount(self.pipeline), 3) + self.assertEquals(self.element.__gstrefcount__, 2) + self.assertEquals(sys.getrefcount(self.element), 3) assert res assert res[0] == 0 assert res[1] == -1 res = self.element.query_position(gst.FORMAT_TIME) assert not res + self.gccollect() class QueueTest(unittest.TestCase): def testConstruct(self): diff --git a/testsuite/test_pipeline.py b/testsuite/test_pipeline.py index b9c51b4bc2..b4a7070364 100644 --- a/testsuite/test_pipeline.py +++ b/testsuite/test_pipeline.py @@ -22,20 +22,37 @@ import time -from common import gst, unittest +from common import gst, unittest, TestCase import gobject -class PipelineConstructor(unittest.TestCase): +class TestConstruction(TestCase): + def setUp(self): + self.gctrack() + + def tearDown(self): + self.gccollect() + self.gcverify() + def testGoodConstructor(self): name = 'test-pipeline' pipeline = gst.Pipeline(name) + self.assertEquals(pipeline.__gstrefcount__, 1) assert pipeline is not None, 'pipeline is None' - assert isinstance(pipeline, gst.Pipeline), 'pipeline is not a GstPipline' + self.failUnless(isinstance(pipeline, gst.Pipeline), + 'pipeline is not a GstPipline') assert pipeline.get_name() == name, 'pipelines name is wrong' + self.assertEquals(pipeline.__gstrefcount__, 1) + + def testParseLaunch(self): + pipeline = gst.parse_launch('fakesrc ! fakesink') + del pipeline + pass + -class Pipeline(unittest.TestCase): +class Pipeline(TestCase): def setUp(self): + self.gctrack() self.pipeline = gst.Pipeline('test-pipeline') source = gst.element_factory_make('fakesrc', 'source') source.set_property('num-buffers', 5) @@ -43,6 +60,11 @@ class Pipeline(unittest.TestCase): self.pipeline.add_many(source, sink) gst.element_link_many(source, sink) + def tearDown(self): + del self.pipeline + self.gccollect() + self.gcverify() + def testRun(self): self.assertEqual(self.pipeline.get_state(None)[1], gst.STATE_NULL) self.pipeline.set_state(gst.STATE_PLAYING) @@ -54,8 +76,9 @@ class Pipeline(unittest.TestCase): self.pipeline.set_state(gst.STATE_NULL) self.assertEqual(self.pipeline.get_state(None)[1], gst.STATE_NULL) -class PipelineAndBus(unittest.TestCase): +class PipelineAndBus(TestCase): def setUp(self): + self.gctrack() self.pipeline = gst.Pipeline('test-pipeline') self.pipeline.set_property('play-timeout', 0L) source = gst.element_factory_make('fakesrc', 'source') @@ -68,6 +91,13 @@ class PipelineAndBus(unittest.TestCase): self.loop = gobject.MainLoop() + def tearDown(self): + # FIXME: fix the refcount issues with the bus/pipeline + #del self.pipeline + #del self.bus + self.gccollect() + #self.gcverify() + def _message_received(self, bus, message): gst.debug('received message: %s, %s' % ( message.src.get_path_string(), message.type.value_nicks[1]))