miniobject: fix ref count leaks in tests
[platform/upstream/gstreamer.git] / tests / check / gst / gstminiobject.c
1 /* GStreamer
2  *
3  * unit test for GstMiniObject
4  *
5  * Copyright (C) <2005> Thomas Vander Stichele <thomas at apestaart dot org>
6  * Copyright (C) <2005> Tim-Philipp Müller <tim centricular net>
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Library General Public
10  * License as published by the Free Software Foundation; either
11  * version 2 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Library General Public License for more details.
17  *
18  * You should have received a copy of the GNU Library General Public
19  * License along with this library; if not, write to the
20  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
21  * Boston, MA 02110-1301, USA.
22  */
23
24 #include <gst/check/gstcheck.h>
25
26 GST_START_TEST (test_copy)
27 {
28   GstBuffer *buffer, *copy;
29
30   buffer = gst_buffer_new_and_alloc (4);
31
32   copy = GST_BUFFER (gst_mini_object_copy (GST_MINI_OBJECT_CAST (buffer)));
33
34   fail_if (copy == NULL, "Copy of buffer returned NULL");
35   fail_unless (gst_buffer_get_size (copy) == 4,
36       "Copy of buffer has different size");
37
38   gst_buffer_unref (buffer);
39   gst_buffer_unref (copy);
40 }
41
42 GST_END_TEST;
43
44 GST_START_TEST (test_is_writable)
45 {
46   GstBuffer *buffer;
47   GstMiniObject *mobj;
48
49   buffer = gst_buffer_new_and_alloc (4);
50   mobj = GST_MINI_OBJECT_CAST (buffer);
51
52   fail_unless (gst_mini_object_is_writable (mobj),
53       "A buffer with one ref should be writable");
54
55   fail_if (gst_mini_object_ref (mobj) == NULL, "Could not ref the mobj");
56
57   fail_if (gst_mini_object_is_writable (mobj),
58       "A buffer with two refs should not be writable");
59
60   gst_buffer_unref (buffer);
61   gst_mini_object_unref (mobj);
62 }
63
64 GST_END_TEST;
65
66 GST_START_TEST (test_make_writable)
67 {
68   GstBuffer *buffer;
69   GstMiniObject *mobj, *mobj2, *mobj3;
70
71   buffer = gst_buffer_new_and_alloc (4);
72   mobj = GST_MINI_OBJECT_CAST (buffer);
73
74   mobj2 = gst_mini_object_make_writable (mobj);
75   fail_unless (GST_IS_BUFFER (mobj2), "make_writable did not return a buffer");
76   fail_unless (mobj == mobj2,
77       "make_writable returned a copy for a buffer with refcount 1");
78
79   mobj2 = gst_mini_object_ref (mobj);
80   mobj3 = gst_mini_object_make_writable (mobj);
81   fail_unless (GST_IS_BUFFER (mobj3), "make_writable did not return a buffer");
82   fail_if (mobj == mobj3,
83       "make_writable returned same object for a buffer with refcount > 1");
84
85   fail_unless (GST_MINI_OBJECT_REFCOUNT_VALUE (mobj) == 1,
86       "refcount of original mobj object should be back to 1");
87
88   mobj2 = gst_mini_object_make_writable (mobj);
89   fail_unless (GST_IS_BUFFER (mobj2), "make_writable did not return a buffer");
90   fail_unless (mobj == mobj2,
91       "make_writable returned a copy for a buffer with refcount 1");
92
93   gst_buffer_unref (buffer);
94   gst_mini_object_unref (mobj3);
95 }
96
97 GST_END_TEST;
98
99 static gint num_threads = 10;
100 static gint refs_per_thread = 10000;
101
102 /* test thread-safe refcounting of GstMiniObject */
103 static void
104 thread_ref (GstMiniObject * mobj)
105 {
106   int j;
107
108   THREAD_START ();
109
110   for (j = 0; j < refs_per_thread; ++j) {
111     gst_mini_object_ref (mobj);
112
113     if (j % num_threads == 0)
114       THREAD_SWITCH ();
115   }
116   GST_DEBUG ("thread stopped");
117 }
118
119 GST_START_TEST (test_ref_threaded)
120 {
121   GstBuffer *buffer;
122   GstMiniObject *mobj;
123   gint expected;
124
125   buffer = gst_buffer_new_and_alloc (4);
126
127   mobj = GST_MINI_OBJECT_CAST (buffer);
128
129   MAIN_START_THREADS (num_threads, thread_ref, mobj);
130
131   MAIN_STOP_THREADS ();
132
133   expected = num_threads * refs_per_thread + 1;
134   ASSERT_MINI_OBJECT_REFCOUNT (mobj, "miniobject", expected);
135
136   while (expected-- != 0)
137     gst_buffer_unref (buffer);
138 }
139
140 GST_END_TEST;
141
142 static void
143 thread_unref (GstMiniObject * mobj)
144 {
145   int j;
146
147   THREAD_START ();
148
149   for (j = 0; j < refs_per_thread; ++j) {
150     gst_mini_object_unref (mobj);
151
152     if (j % num_threads == 0)
153       THREAD_SWITCH ();
154   }
155 }
156
157 GST_START_TEST (test_unref_threaded)
158 {
159   GstBuffer *buffer;
160   GstMiniObject *mobj;
161   int i;
162
163   buffer = gst_buffer_new_and_alloc (4);
164
165   mobj = GST_MINI_OBJECT (buffer);
166
167   for (i = 0; i < num_threads * refs_per_thread; ++i)
168     gst_mini_object_ref (mobj);
169
170   MAIN_START_THREADS (num_threads, thread_unref, mobj);
171
172   MAIN_STOP_THREADS ();
173
174   ASSERT_MINI_OBJECT_REFCOUNT (mobj, "miniobject", 1);
175
176   /* final unref */
177   gst_mini_object_unref (mobj);
178 }
179
180 GST_END_TEST;
181
182 /* ======== weak ref test ======== */
183
184 static gboolean weak_ref_notify_succeeded = FALSE;
185
186 static void
187 on_weak_ref_notify (gpointer data, GstMiniObject * where_object_was)
188 {
189   weak_ref_notify_succeeded = TRUE;
190 }
191
192 GST_START_TEST (test_weak_ref)
193 {
194   GstBuffer *buffer;
195
196   buffer = gst_buffer_new_and_alloc (4);
197
198   gst_mini_object_weak_ref (GST_MINI_OBJECT (buffer), on_weak_ref_notify,
199       &buffer);
200
201   gst_buffer_unref (buffer);
202
203   fail_unless (weak_ref_notify_succeeded,
204       "No weak reference notification took place.");
205 }
206
207 GST_END_TEST;
208
209 #if 0
210 /* ======== recycle test ======== */
211
212 static gint recycle_buffer_count = 10;
213
214 typedef struct _MyBufferPool MyBufferPool;
215
216 struct _MyBufferPool
217 {
218   GSList *buffers;
219
220   volatile gboolean is_closed;
221 };
222
223 static void my_recycle_buffer_destroy (MyRecycleBuffer * buf);
224
225 static MyBufferPool *
226 my_buffer_pool_new (void)
227 {
228   return g_new0 (MyBufferPool, 1);
229 }
230
231 static void
232 my_buffer_pool_free (MyBufferPool * self)
233 {
234   while (self->buffers != NULL) {
235     my_recycle_buffer_destroy (self->buffers->data);
236     self->buffers = g_slist_delete_link (self->buffers, self->buffers);
237   }
238
239   g_free (self);
240 }
241
242 static void
243 my_buffer_pool_add (MyBufferPool * self, GstBuffer * buf)
244 {
245   g_mutex_lock (mutex);
246   self->buffers = g_slist_prepend (self->buffers, gst_buffer_ref (buf));
247   g_mutex_unlock (mutex);
248 }
249
250 static GstBuffer *
251 my_buffer_pool_drain_one (MyBufferPool * self)
252 {
253   GstBuffer *buf = NULL;
254
255   g_mutex_lock (mutex);
256   if (self->buffers != NULL) {
257     buf = self->buffers->data;
258     self->buffers = g_slist_delete_link (self->buffers, self->buffers);
259   }
260   g_mutex_unlock (mutex);
261
262   return buf;
263 }
264
265 static void
266 my_recycle_buffer_finalize (GstMiniObject * mini_object)
267 {
268   GstBuffer *self = GST_BUFFER_CAST (mini_object);
269
270   if (self->pool != NULL) {
271     my_buffer_pool_add (self->pool, GST_BUFFER_CAST (self));
272     g_usleep (G_USEC_PER_SEC / 100);
273   } else {
274     GST_MINI_OBJECT_CLASS (my_recycle_buffer_parent_class)->finalize
275         (mini_object);
276   }
277 }
278
279 static GstBuffer *
280 my_recycle_buffer_new (MyBufferPool * pool)
281 {
282   GstBuffer *buf;
283
284   buf = gst_buffer_new ();
285
286   //buf->pool = pool;
287
288   return GST_BUFFER_CAST (buf);
289 }
290
291 static void
292 my_recycle_buffer_destroy (MyRecycleBuffer * buf)
293 {
294   buf->pool = NULL;
295   gst_buffer_unref (GST_BUFFER_CAST (buf));
296 }
297
298 static void
299 thread_buffer_producer (MyBufferPool * pool)
300 {
301   int j;
302
303   THREAD_START ();
304
305   for (j = 0; j < recycle_buffer_count; ++j) {
306     GstBuffer *buf = my_recycle_buffer_new (pool);
307     gst_buffer_unref (buf);
308   }
309
310   pool->is_closed = TRUE;
311 }
312
313 static void
314 thread_buffer_consumer (MyBufferPool * pool)
315 {
316   THREAD_START ();
317
318   do {
319     GstBuffer *buf;
320
321     buf = my_buffer_pool_drain_one (pool);
322     if (buf != NULL)
323       my_recycle_buffer_destroy (MY_RECYCLE_BUFFER_CAST (buf));
324
325     THREAD_SWITCH ();
326   }
327   while (!pool->is_closed);
328 }
329
330 GST_START_TEST (test_recycle_threaded)
331 {
332   MyBufferPool *pool;
333
334   pool = my_buffer_pool_new ();
335
336   MAIN_START_THREADS (1, thread_buffer_producer, pool);
337   MAIN_START_THREADS (1, thread_buffer_consumer, pool);
338
339   MAIN_STOP_THREADS ();
340
341   my_buffer_pool_free (pool);
342 }
343
344 GST_END_TEST;
345 #endif
346
347 /* ======== value collection test ======== */
348 typedef struct _MyFoo
349 {
350   GObject object;
351 } MyFoo;
352
353 typedef struct _MyFooClass
354 {
355   GObjectClass gobject_class;
356 } MyFooClass;
357
358 enum
359 {
360   PROP_BUFFER = 1
361 };
362
363 GType my_foo_get_type (void);
364 G_DEFINE_TYPE (MyFoo, my_foo, G_TYPE_OBJECT);
365
366 static void
367 my_foo_init (MyFoo * foo)
368 {
369 }
370
371 static void
372 my_foo_get_property (GObject * object, guint prop_id, GValue * value,
373     GParamSpec * pspec)
374 {
375   GstBuffer *new_buf;
376
377   g_assert (prop_id == PROP_BUFFER);
378
379   new_buf = gst_buffer_new_and_alloc (1024);
380   g_value_set_boxed (value, GST_MINI_OBJECT (new_buf));
381   gst_buffer_unref (new_buf);
382 }
383
384 static void
385 my_foo_set_property (GObject * object, guint prop_id, const GValue * value,
386     GParamSpec * pspec)
387 {
388   GstMiniObject *mini_obj;
389
390   g_assert (prop_id == PROP_BUFFER);
391
392   mini_obj = g_value_get_boxed (value);
393   g_assert (GST_IS_BUFFER (mini_obj));
394
395 #if 0
396   /* gst_value_dup_mini_object() does not exist yet */
397   mini_obj = gst_value_dup_mini_object (value);
398   g_assert (GST_IS_MINI_OBJECT (mini_obj));
399   g_assert (GST_IS_BUFFER (mini_obj));
400   gst_mini_object_unref (mini_obj);
401 #endif
402 }
403
404
405 static void
406 my_foo_class_init (MyFooClass * klass)
407 {
408   GObjectClass *gobject_klass = G_OBJECT_CLASS (klass);
409
410   gobject_klass->get_property = my_foo_get_property;
411   gobject_klass->set_property = my_foo_set_property;
412
413   g_object_class_install_property (gobject_klass, PROP_BUFFER,
414       g_param_spec_boxed ("buffer", "Buffer",
415           "a newly created GstBuffer", GST_TYPE_BUFFER, G_PARAM_READWRITE));
416 }
417
418 GST_START_TEST (test_value_collection)
419 {
420   GstBuffer *buf = NULL;
421   MyFoo *foo;
422
423   foo = (MyFoo *) g_object_new (my_foo_get_type (), NULL);
424
425   /* test g_object_get() refcounting */
426   g_object_get (foo, "buffer", &buf, NULL);
427   g_assert (GST_IS_BUFFER (buf));
428   g_assert (GST_MINI_OBJECT_REFCOUNT_VALUE (GST_MINI_OBJECT_CAST (buf)) == 1);
429   gst_buffer_unref (buf);
430
431   /* test g_object_set() refcounting */
432   buf = gst_buffer_new_and_alloc (1024);
433   g_object_set (foo, "buffer", buf, NULL);
434   g_assert (GST_MINI_OBJECT_REFCOUNT_VALUE (GST_MINI_OBJECT_CAST (buf)) == 1);
435   gst_buffer_unref (buf);
436
437   g_object_unref (foo);
438 }
439
440 GST_END_TEST;
441
442
443 GST_START_TEST (test_dup_null_mini_object)
444 {
445   GValue value = { 0, };
446   GstMiniObject *mo;
447
448   g_value_init (&value, GST_TYPE_BUFFER);
449
450   g_value_set_boxed (&value, NULL);
451
452   mo = GST_MINI_OBJECT_CAST (g_value_dup_boxed (&value));
453   g_assert (mo == NULL);
454
455   g_value_unset (&value);
456 }
457
458 GST_END_TEST;
459
460 static Suite *
461 gst_mini_object_suite (void)
462 {
463   Suite *s = suite_create ("GstMiniObject");
464   TCase *tc_chain = tcase_create ("general");
465
466   /* turn off timeout */
467   tcase_set_timeout (tc_chain, 60);
468
469   suite_add_tcase (s, tc_chain);
470   tcase_add_test (tc_chain, test_copy);
471   tcase_add_test (tc_chain, test_is_writable);
472   tcase_add_test (tc_chain, test_make_writable);
473   tcase_add_test (tc_chain, test_ref_threaded);
474   tcase_add_test (tc_chain, test_unref_threaded);
475   tcase_add_test (tc_chain, test_weak_ref);
476   //tcase_add_test (tc_chain, test_recycle_threaded);
477   tcase_add_test (tc_chain, test_value_collection);
478   tcase_add_test (tc_chain, test_dup_null_mini_object);
479   return s;
480 }
481
482 GST_CHECK_MAIN (gst_mini_object);