3 * unit test for GstMiniObject
5 * Copyright (C) <2005> Thomas Vander Stichele <thomas at apestaart dot org>
6 * Copyright (C) <2005> Tim-Philipp Müller <tim centricular net>
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.
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.
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.
24 #include <gst/check/gstcheck.h>
26 GST_START_TEST (test_copy)
28 GstBuffer *buffer, *copy;
30 buffer = gst_buffer_new_and_alloc (4);
32 copy = GST_BUFFER (gst_mini_object_copy (GST_MINI_OBJECT_CAST (buffer)));
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");
38 gst_buffer_unref (buffer);
39 gst_buffer_unref (copy);
44 GST_START_TEST (test_is_writable)
49 buffer = gst_buffer_new_and_alloc (4);
50 mobj = GST_MINI_OBJECT_CAST (buffer);
52 fail_unless (gst_mini_object_is_writable (mobj),
53 "A buffer with one ref should be writable");
55 fail_if (gst_mini_object_ref (mobj) == NULL, "Could not ref the mobj");
57 fail_if (gst_mini_object_is_writable (mobj),
58 "A buffer with two refs should not be writable");
60 gst_buffer_unref (buffer);
61 gst_mini_object_unref (mobj);
66 GST_START_TEST (test_make_writable)
69 GstMiniObject *mobj, *mobj2, *mobj3;
71 buffer = gst_buffer_new_and_alloc (4);
72 mobj = GST_MINI_OBJECT_CAST (buffer);
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");
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");
85 fail_unless (GST_MINI_OBJECT_REFCOUNT_VALUE (mobj) == 1,
86 "refcount of original mobj object should be back to 1");
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");
93 gst_buffer_unref (buffer);
94 gst_mini_object_unref (mobj3);
99 static gint num_threads = 10;
100 static gint refs_per_thread = 10000;
102 /* test thread-safe refcounting of GstMiniObject */
104 thread_ref (GstMiniObject * mobj)
110 for (j = 0; j < refs_per_thread; ++j) {
111 gst_mini_object_ref (mobj);
113 if (j % num_threads == 0)
116 GST_DEBUG ("thread stopped");
119 GST_START_TEST (test_ref_threaded)
125 buffer = gst_buffer_new_and_alloc (4);
127 mobj = GST_MINI_OBJECT_CAST (buffer);
129 MAIN_START_THREADS (num_threads, thread_ref, mobj);
131 MAIN_STOP_THREADS ();
133 expected = num_threads * refs_per_thread + 1;
134 ASSERT_MINI_OBJECT_REFCOUNT (mobj, "miniobject", expected);
136 while (expected-- != 0)
137 gst_buffer_unref (buffer);
143 thread_unref (GstMiniObject * mobj)
149 for (j = 0; j < refs_per_thread; ++j) {
150 gst_mini_object_unref (mobj);
152 if (j % num_threads == 0)
157 GST_START_TEST (test_unref_threaded)
163 buffer = gst_buffer_new_and_alloc (4);
165 mobj = GST_MINI_OBJECT (buffer);
167 for (i = 0; i < num_threads * refs_per_thread; ++i)
168 gst_mini_object_ref (mobj);
170 MAIN_START_THREADS (num_threads, thread_unref, mobj);
172 MAIN_STOP_THREADS ();
174 ASSERT_MINI_OBJECT_REFCOUNT (mobj, "miniobject", 1);
177 gst_mini_object_unref (mobj);
182 /* ======== weak ref test ======== */
184 static gboolean weak_ref_notify_succeeded = FALSE;
187 on_weak_ref_notify (gpointer data, GstMiniObject * where_object_was)
189 weak_ref_notify_succeeded = TRUE;
192 GST_START_TEST (test_weak_ref)
196 buffer = gst_buffer_new_and_alloc (4);
198 gst_mini_object_weak_ref (GST_MINI_OBJECT (buffer), on_weak_ref_notify,
201 gst_buffer_unref (buffer);
203 fail_unless (weak_ref_notify_succeeded,
204 "No weak reference notification took place.");
210 /* ======== recycle test ======== */
212 static gint recycle_buffer_count = 10;
214 typedef struct _MyBufferPool MyBufferPool;
220 volatile gboolean is_closed;
223 static void my_recycle_buffer_destroy (MyRecycleBuffer * buf);
225 static MyBufferPool *
226 my_buffer_pool_new (void)
228 return g_new0 (MyBufferPool, 1);
232 my_buffer_pool_free (MyBufferPool * self)
234 while (self->buffers != NULL) {
235 my_recycle_buffer_destroy (self->buffers->data);
236 self->buffers = g_slist_delete_link (self->buffers, self->buffers);
243 my_buffer_pool_add (MyBufferPool * self, GstBuffer * buf)
245 g_mutex_lock (mutex);
246 self->buffers = g_slist_prepend (self->buffers, gst_buffer_ref (buf));
247 g_mutex_unlock (mutex);
251 my_buffer_pool_drain_one (MyBufferPool * self)
253 GstBuffer *buf = NULL;
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);
260 g_mutex_unlock (mutex);
266 my_recycle_buffer_finalize (GstMiniObject * mini_object)
268 GstBuffer *self = GST_BUFFER_CAST (mini_object);
270 if (self->pool != NULL) {
271 my_buffer_pool_add (self->pool, GST_BUFFER_CAST (self));
272 g_usleep (G_USEC_PER_SEC / 100);
274 GST_MINI_OBJECT_CLASS (my_recycle_buffer_parent_class)->finalize
280 my_recycle_buffer_new (MyBufferPool * pool)
284 buf = gst_buffer_new ();
288 return GST_BUFFER_CAST (buf);
292 my_recycle_buffer_destroy (MyRecycleBuffer * buf)
295 gst_buffer_unref (GST_BUFFER_CAST (buf));
299 thread_buffer_producer (MyBufferPool * pool)
305 for (j = 0; j < recycle_buffer_count; ++j) {
306 GstBuffer *buf = my_recycle_buffer_new (pool);
307 gst_buffer_unref (buf);
310 pool->is_closed = TRUE;
314 thread_buffer_consumer (MyBufferPool * pool)
321 buf = my_buffer_pool_drain_one (pool);
323 my_recycle_buffer_destroy (MY_RECYCLE_BUFFER_CAST (buf));
327 while (!pool->is_closed);
330 GST_START_TEST (test_recycle_threaded)
334 pool = my_buffer_pool_new ();
336 MAIN_START_THREADS (1, thread_buffer_producer, pool);
337 MAIN_START_THREADS (1, thread_buffer_consumer, pool);
339 MAIN_STOP_THREADS ();
341 my_buffer_pool_free (pool);
347 /* ======== value collection test ======== */
348 typedef struct _MyFoo
353 typedef struct _MyFooClass
355 GObjectClass gobject_class;
363 GType my_foo_get_type (void);
364 G_DEFINE_TYPE (MyFoo, my_foo, G_TYPE_OBJECT);
367 my_foo_init (MyFoo * foo)
372 my_foo_get_property (GObject * object, guint prop_id, GValue * value,
377 g_assert (prop_id == PROP_BUFFER);
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);
385 my_foo_set_property (GObject * object, guint prop_id, const GValue * value,
388 GstMiniObject *mini_obj;
390 g_assert (prop_id == PROP_BUFFER);
392 mini_obj = g_value_get_boxed (value);
393 g_assert (GST_IS_BUFFER (mini_obj));
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);
406 my_foo_class_init (MyFooClass * klass)
408 GObjectClass *gobject_klass = G_OBJECT_CLASS (klass);
410 gobject_klass->get_property = my_foo_get_property;
411 gobject_klass->set_property = my_foo_set_property;
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));
418 GST_START_TEST (test_value_collection)
420 GstBuffer *buf = NULL;
423 foo = (MyFoo *) g_object_new (my_foo_get_type (), NULL);
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);
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);
437 g_object_unref (foo);
443 GST_START_TEST (test_dup_null_mini_object)
445 GValue value = { 0, };
448 g_value_init (&value, GST_TYPE_BUFFER);
450 g_value_set_boxed (&value, NULL);
452 mo = GST_MINI_OBJECT_CAST (g_value_dup_boxed (&value));
453 g_assert (mo == NULL);
455 g_value_unset (&value);
461 gst_mini_object_suite (void)
463 Suite *s = suite_create ("GstMiniObject");
464 TCase *tc_chain = tcase_create ("general");
466 /* turn off timeout */
467 tcase_set_timeout (tc_chain, 60);
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);
482 GST_CHECK_MAIN (gst_mini_object);