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