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