3 * unit test for GstObject
5 * Copyright (C) <2004> Thomas Vander Stichele <thomas at apestaart dot org>
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Library General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Library General Public License for more details.
17 * You should have received a copy of the GNU Library General Public
18 * License along with this library; if not, write to the
19 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20 * Boston, MA 02111-1307, USA.
27 #include <gst/check/gstcheck.h>
30 Create a fake subclass
32 typedef struct _GstFakeObjectClass GstFakeObjectClass;
33 typedef struct _GstFakeObject GstFakeObject;
40 struct _GstFakeObjectClass
42 GstObjectClass parent_class;
45 //static GstObjectClass *parent_class = NULL;
46 //static guint gst_fake_object_signals[LAST_SIGNAL] = { 0 };
49 gst_fake_object_get_type (void)
51 static volatile gsize fake_object_type = 0;
53 if (g_once_init_enter (&fake_object_type)) {
55 static const GTypeInfo fake_object_info = {
56 sizeof (GstFakeObjectClass),
57 NULL, //gst_fake_object_base_class_init,
58 NULL, //gst_fake_object_base_class_finalize,
59 NULL, //(GClassInitFunc) gst_fake_object_class_init,
62 sizeof (GstFakeObject),
64 NULL, //(GInstanceInitFunc) gst_fake_object_init,
68 type = g_type_register_static (GST_TYPE_OBJECT,
69 "GstFakeObject", &fake_object_info, 0);
70 g_once_init_leave (&fake_object_type, type);
72 return fake_object_type;
76 /* g_object_new on abstract GstObject should fail */
77 GST_START_TEST (test_fail_abstract_new)
81 ASSERT_CRITICAL (object = g_object_new (gst_object_get_type (), NULL));
82 fail_unless (object == NULL, "Created an instance of abstract GstObject");
88 /* g_object_new on GstFakeObject should succeed */
89 GST_START_TEST (test_fake_object_new)
93 object = g_object_new (gst_fake_object_get_type (), NULL);
94 fail_if (object == NULL, "Failed to create instance of GstFakeObject");
95 fail_unless (GST_IS_OBJECT (object),
96 "GstFakeObject instance is not a GstObject");
97 gst_object_unref (object);
102 /* GstFakeObject name tests */
103 GST_START_TEST (test_fake_object_name)
109 object = g_object_new (gst_fake_object_get_type (), NULL);
111 name = gst_object_get_name (object);
112 fail_if (name == NULL, "Newly created object has no name");
113 fail_if (strncmp (name, "fakeobject", 10) != 0,
114 "Random name %s does not start with Gst", name);
117 /* give a random name by setting with NULL;
118 * GstFakeObject class -> fakeobject%d */
119 gst_object_set_name (object, NULL);
120 name = gst_object_get_name (object);
121 fail_if (name == NULL, "Random name was not assigned");
122 fail_if (strncmp (name, "fakeobject", 10) != 0,
123 "Random name %s does not start with Gst", name);
126 gst_object_set_name (object, "fake");
127 name = gst_object_get_name (object);
128 fail_if (name == NULL, "Failed to get name of GstFakeObject");
129 fail_if (strcmp (name, "fake") != 0, "Name of GstFakeObject is not 'fake'");
131 /* change the gotten name to see that it's a copy and not the original */
133 name2 = gst_object_get_name (object);
134 fail_if (strcmp (name2, "fake") != 0,
135 "Copy of object name affected actual object name");
139 gst_object_unref (object);
144 /* thread function for threaded name change test */
146 thread_name_object (GstObject * object)
148 gchar *thread_id = g_strdup_printf ("%p", g_thread_self ());
152 /* give main thread a head start */
155 /* write our name repeatedly */
156 g_message ("THREAD %s: starting loop\n", thread_id);
157 while (THREAD_TEST_RUNNING ()) {
158 gst_object_set_name (object, thread_id);
159 /* a minimal sleep invokes a thread switch */
163 /* thread is done, so let's return */
164 g_message ("THREAD %s: set name\n", thread_id);
171 GST_START_TEST (test_fake_object_name_threaded_wrong)
176 gboolean expected_failure = FALSE;
178 g_message ("\nTEST: set/get without lock\n");
180 object = g_object_new (gst_fake_object_get_type (), NULL);
181 gst_object_set_name (object, "main");
183 MAIN_START_THREADS (5, thread_name_object, object);
185 /* start looping and set/get name repeatedly */
186 for (i = 0; i < 1000; ++i) {
187 gst_object_set_name (object, "main");
189 name = gst_object_get_name (object);
190 if (strcmp (name, "main") != 0) {
191 g_message ("MAIN: expected failure during run %d\n", i);
192 expected_failure = TRUE;
198 MAIN_STOP_THREADS ();
200 gst_object_unref (object);
202 fail_unless (expected_failure, "name did not get changed");
209 * main thread sets and gets name directly on struct inside the object lock
210 * succeed because lock is held during set/get, and threads are locked out
212 GST_START_TEST (test_fake_object_name_threaded_right)
218 g_message ("\nTEST: set/get inside lock\n");
220 object = g_object_new (gst_fake_object_get_type (), NULL);
221 gst_object_set_name (object, "main");
223 MAIN_START_THREADS (5, thread_name_object, object);
225 /* start looping and set/get name repeatedly */
226 for (i = 0; i < 1000; ++i) {
227 GST_OBJECT_LOCK (object);
228 g_free (GST_OBJECT_NAME (object));
229 GST_OBJECT_NAME (object) = g_strdup ("main");
231 name = g_strdup (GST_OBJECT_NAME (object));
232 GST_OBJECT_UNLOCK (object);
234 fail_unless (strcmp (name, "main") == 0,
235 "Name got changed while lock held during run %d", i);
238 MAIN_STOP_THREADS ();
239 gst_object_unref (object);
244 * main thread creates lots of objects
245 * child threads sets default names on objects
246 * then main thread checks uniqueness of object names
249 static GList *object_list = NULL;
250 static gint num_objects = 1000;
251 static gint num_threads = 5;
253 /* thread function for threaded default name change test */
255 thread_name_object_default (int *i)
261 for (j = *i; j < num_objects; j += num_threads) {
262 GstObject *o = GST_OBJECT (g_list_nth_data (object_list, j));
264 /* g_message ("THREAD %p: setting default name on object %d\n",
265 g_thread_self (), j); */
266 gst_object_set_name (o, NULL);
270 /* thread is done, so let's return */
271 g_message ("THREAD %p: set name\n", g_thread_self ());
278 gst_object_name_compare (GstObject * o, GstObject * p)
285 if (o->name == NULL && p->name == NULL) {
287 } else if (o->name == NULL) {
289 } else if (p->name == NULL) {
292 result = strcmp (o->name, p->name);
295 GST_OBJECT_UNLOCK (p);
296 GST_OBJECT_UNLOCK (o);
301 GST_START_TEST (test_fake_object_name_threaded_unique)
306 gchar *name1, *name2;
309 g_message ("\nTEST: uniqueness of default names\n");
311 for (i = 0; i < num_objects; ++i) {
312 object = g_object_new (gst_fake_object_get_type (), NULL);
313 object_list = g_list_append (object_list, object);
319 for (i = 0; i < num_threads; ++i) {
320 ip = g_new (gint, 1);
322 MAIN_START_THREAD_FUNCTION (i, thread_name_object_default, ip);
328 MAIN_STOP_THREADS ();
330 /* sort GList based on object name */
331 /* FIXME: sort and test */
333 g_list_sort (object_list, (GCompareFunc) gst_object_name_compare);
335 name1 = gst_object_get_name (GST_OBJECT (object_list->data));
336 for (l = object_list->next; l->next; l = l->next) {
337 g_message ("object with name %s\n", name1);
338 name2 = gst_object_get_name (GST_OBJECT (l->data));
339 fail_if (strcmp (name1, name2) == 0, "Two objects with name %s", name2);
346 g_list_foreach (object_list, (GFunc) g_object_unref, NULL);
351 /* parentage test on GstFakeObject */
352 GST_START_TEST (test_fake_object_parentage)
354 GstObject *object1, *object2;
358 /* create new object */
359 object1 = g_object_new (gst_fake_object_get_type (), NULL);
360 fail_if (object1 == NULL, "Failed to create instance of GstFakeObject");
361 fail_unless (GST_IS_OBJECT (object1),
362 "GstFakeObject instance is not a GstObject");
363 fail_unless (g_object_is_floating (object1),
364 "GstFakeObject instance is not floating");
366 /* check the parent */
367 parent = gst_object_get_parent (object1);
368 fail_if (parent != NULL, "GstFakeObject has parent");
369 /* try to set a NULL parent, this should give a warning */
370 ASSERT_CRITICAL (result = gst_object_set_parent (object1, NULL));
371 fail_if (result == TRUE, "GstFakeObject accepted NULL parent");
372 /* try to set itself as parent, we expect a warning here */
373 ASSERT_CRITICAL (result = gst_object_set_parent (object1, object1));
374 fail_if (result == TRUE, "GstFakeObject accepted itself as parent");
376 /* should still be floating */
377 fail_unless (g_object_is_floating (object1),
378 "GstFakeObject instance is not floating");
380 /* create another object */
381 object2 = g_object_new (gst_fake_object_get_type (), NULL);
382 fail_if (object2 == NULL,
383 "Failed to create another instance of GstFakeObject");
384 fail_unless (GST_IS_OBJECT (object2),
385 "second GstFakeObject instance is not a GstObject");
386 fail_unless (g_object_is_floating (object1),
387 "GstFakeObject instance is not floating");
389 /* try to set other object as parent */
390 result = gst_object_set_parent (object1, object2);
391 fail_if (result == FALSE,
392 "GstFakeObject could not accept other object as parent");
394 /* should not be floating anymore */
395 fail_if (g_object_is_floating (object1),
396 "GstFakeObject instance is still floating");
397 /* parent should still be floating */
398 fail_unless (g_object_is_floating (object2),
399 "GstFakeObject instance is not floating");
401 /* check the parent */
402 parent = gst_object_get_parent (object1);
403 fail_if (parent != object2, "GstFakeObject has wrong parent");
404 gst_object_unref (parent);
405 /* try to set other object as parent again */
406 result = gst_object_set_parent (object1, object2);
407 fail_if (result == TRUE, "GstFakeObject could set parent twice");
409 /* ref before unparenting */
410 gst_object_ref (object1);
411 /* clear parent of object */
412 gst_object_unparent (object1);
414 /* check the parent */
415 parent = gst_object_get_parent (object1);
416 fail_if (parent != NULL, "GstFakeObject has parent");
418 /* object should not be floating */
419 fail_if (g_object_is_floating (object1),
420 "GstFakeObject instance is floating again");
422 gst_object_unref (object1);
423 gst_object_unref (object2);
428 /* parentage test dispose on GstFakeObject, since our testcase
429 * does not handle the parent relation completely, the parent does
430 * not hold a ref to the child, we cannot dispose the parent to
431 * dipose the child as well. This test needs to be run with DEBUG
432 * info to check if the finalize methods are called correctly. */
433 GST_START_TEST (test_fake_object_parentage_dispose)
435 GstObject *object1, *object2;
438 object1 = g_object_new (gst_fake_object_get_type (), NULL);
439 fail_if (object1 == NULL, "Failed to create instance of GstFakeObject");
441 object2 = g_object_new (gst_fake_object_get_type (), NULL);
442 fail_if (object2 == NULL, "Failed to create instance of GstFakeObject");
444 /* try to set other object as parent */
445 result = gst_object_set_parent (object1, object2);
446 fail_if (result == FALSE,
447 "GstFakeObject could not accept other object as parent");
449 /* clear parent of object */
450 gst_object_unparent (object1);
452 /* now dispose parent */
453 gst_object_unref (object2);
458 GST_START_TEST (test_fake_object_has_ancestor)
460 GstObject *object1, *object2, *object3, *object4;
463 object1 = g_object_new (gst_fake_object_get_type (), NULL);
464 fail_if (object1 == NULL, "Failed to create instance of GstFakeObject");
466 object2 = g_object_new (gst_fake_object_get_type (), NULL);
467 fail_if (object2 == NULL, "Failed to create instance of GstFakeObject");
469 object3 = g_object_new (gst_fake_object_get_type (), NULL);
470 fail_if (object3 == NULL, "Failed to create instance of GstFakeObject");
472 object4 = g_object_new (gst_fake_object_get_type (), NULL);
473 fail_if (object4 == NULL, "Failed to create instance of GstFakeObject");
475 /* try to set other object as parent */
476 result = gst_object_set_parent (object1, object3);
477 fail_if (result == FALSE,
478 "GstFakeObject could not accept other object as parent");
479 result = gst_object_set_parent (object2, object3);
480 fail_if (result == FALSE,
481 "GstFakeObject could not accept other object as parent");
482 result = gst_object_set_parent (object3, object4);
483 fail_if (result == FALSE,
484 "GstFakeObject could not accept other object as parent");
486 fail_unless (gst_object_has_ancestor (object1, object1));
487 fail_if (gst_object_has_ancestor (object1, object2));
488 fail_unless (gst_object_has_ancestor (object1, object3));
489 fail_unless (gst_object_has_ancestor (object1, object4));
490 fail_if (gst_object_has_ancestor (object3, object1));
491 fail_if (gst_object_has_ancestor (object4, object1));
492 fail_unless (gst_object_has_ancestor (object3, object4));
493 fail_if (gst_object_has_ancestor (object4, object3));
494 fail_unless (gst_object_has_ancestor (object4, object4));
496 /* unparent everything */
497 gst_object_unparent (object3);
498 gst_object_unparent (object2);
499 gst_object_unparent (object1);
501 /* now dispose objects */
502 gst_object_unref (object4);
507 /* test: try renaming a parented object, make sure it fails */
510 gst_object_suite (void)
512 Suite *s = suite_create ("GstObject");
513 TCase *tc_chain = tcase_create ("general");
515 /* turn off timeout */
516 tcase_set_timeout (tc_chain, 60);
518 suite_add_tcase (s, tc_chain);
519 tcase_add_test (tc_chain, test_fake_object_new);
520 tcase_add_test (tc_chain, test_fake_object_name);
522 tcase_add_test (tc_chain, test_fake_object_name_threaded_wrong);
524 tcase_add_test (tc_chain, test_fake_object_name_threaded_right);
525 tcase_add_test (tc_chain, test_fake_object_name_threaded_unique);
526 tcase_add_test (tc_chain, test_fake_object_parentage);
527 tcase_add_test (tc_chain, test_fake_object_parentage_dispose);
529 tcase_add_test (tc_chain, test_fake_object_has_ancestor);
530 //tcase_add_checked_fixture (tc_chain, setup, teardown);
532 /* FIXME: GLib shouldn't crash here, but issue a warning and return a NULL
533 * object, or at least g_error() and then abort properly ... (tpm) */
535 /* Disabled for OS/X because a) it's a pretty silly test anyway and
536 * b) different OS/X versions raise different signals and it isn't worth
537 * the effort to try and detect which one should be producing which
539 /* SEGV tests go last so we can debug the others */
540 if (g_getenv ("CK_FORK") == NULL || strcmp (g_getenv ("CK_FORK"), "no") != 0)
541 tcase_add_test_raise_signal (tc_chain, test_fail_abstract_new, SIGSEGV);
547 GST_CHECK_MAIN (gst_object);