valgrind unit tests as check-local; add gst_deinit

Original commit message from CVS:
valgrind unit tests as check-local; add gst_deinit
This commit is contained in:
Thomas Vander Stichele 2005-07-11 15:10:40 +00:00
parent aff85422dc
commit a59215bb4e
18 changed files with 523 additions and 139 deletions

View file

@ -1,3 +1,30 @@
2005-07-11 Thomas Vander Stichele <thomas at apestaart dot org>
* configure.ac:
check for valgrind binary + some fixes
* check/gst.supp:
valgrind suppressions for the tests
* check/Makefile.am:
add a valgrind: target that valgrinds the unit tests
* check/gst/gst.c: (GST_START_TEST), (gst_suite):
* check/gst/gstbin.c: (pop_messages), (GST_START_TEST):
* check/gst/gstbuffer.c: (GST_START_TEST), (gst_test_suite):
* check/gst/gstghostpad.c:
added some cleanup
* check/gst/gstdata.c:
removed
* check/gst/gstminiobject.c: (GST_START_TEST), (thread_ref),
(thread_unref), (gst_mini_object_suite), (main):
added
* gst/gst.c: (gst_deinit):
* gst/gst.h:
add a method to clean up.
* gst/gstsystemclock.c: (gst_system_clock_dispose),
(gst_system_clock_obtain):
allow for disposing the system clock.
* tools/gst-launch.c: (main):
deinit
2005-07-11 Thomas Vander Stichele <thomas at apestaart dot org>
* docs/gst/tmpl/gstbasesrc.sgml:

View file

@ -15,6 +15,8 @@ install-pluginLTLIBRARIES:
# ths core dumps of some machines have PIDs appended
CLEANFILES = core.* test-registry.xml
EXTRA_DIST = gst.supp
clean-local:
for i in `find . -name ".libs" -type d`; do \
rm -rf $$i; \
@ -32,6 +34,7 @@ TESTS = $(top_builddir)/tools/gst-register \
gst/gstghostpad \
gst/gstiterator \
gst/gstmessage \
gst/gstminiobject \
gst/gstobject \
gst/gstpad \
gst/gstsystemclock \
@ -60,3 +63,59 @@ gst_libs_gdp_SOURCES = \
$(top_srcdir)/libs/gst/dataprotocol/dataprotocol.c
# remove GST_ENABLE_NEW when dataprotocol has been declared API-stable
gst_libs_gdp_CFLAGS = $(AM_CFLAGS) -DGST_ENABLE_NEW
# valgrind testing
# these just need fixing, period
TESTS_TO_FIX = \
gst/gstghostpad \
gst/gstiterator \
gst/gstmessage \
gst/gstpad \
gst/gstsystemclock \
gst/gststructure \
gst/gsttag \
gst/gstvalue \
elements/gstfakesrc \
pipelines/cleanup \
pipelines/simple_launch_lines \
gst-libs/gdp
# these need fixing because the threads cause segfaults under valgrind
TESTS_THREADED = \
gst/gstminiobject \
gst/gstobject
VALGRIND_TESTS_DISABLE = \
$(top_builddir)/tools/gst-register \
$(TESTS_THREADED) \
$(TESTS_TO_FIX)
if HAVE_VALGRIND
check-local:
make valgrind
else
check-local:
true
endif
valgrind:
@echo "Valgrinding tests ..."
$(TESTS_ENVIRONMENT) $(top_builddir)/tools/gst-register
@failed=0; \
for t in $(filter-out $(VALGRIND_TESTS_DISABLE),$(TESTS)); do \
$(TESTS_ENVIRONMENT) \
CK_FORK=no \
libtool --mode=execute \
$(VALGRIND_PATH) -q --suppressions=$(srcdir)/gst.supp \
--leak-check=yes $$t; \
if test "$$?" -ne 0; then \
echo "Valgrind error for test $$t"; \
failed=`expr $$failed + 1`; \
fi; \
done; \
if test "$$failed" -ne 0; then \
echo "$$failed tests had leaks under valgrind"; \
false; \
fi

68
check/gst.supp Normal file
View file

@ -0,0 +1,68 @@
### this file contains suppressions for valgrind when running
### the gstreamer unit tests
### it might be useful for wider use as well
### glibc suppressions
# glibc does not deallocate thread-local storage
{
<tls>
Memcheck:Leak
fun:calloc
fun:_dl_allocate_tls
fun:pthread_create@@GLIBC_2.1
}
{
<pthread strstr>
Memcheck:Cond
fun:strstr
fun:__pthread_initialize_minimal
obj:/lib/libpthread-*.so
obj:/lib/libpthread-*.so
fun:call_init
fun:_dl_init
obj:/lib/ld-*.so
}
### glib suppressions
{
<g_type_init>
Memcheck:Leak
fun:calloc
fun:g_malloc0
obj:/usr/lib/libgobject-2.0.so.*
obj:/usr/lib/libgobject-2.0.so.*
fun:g_type_init_with_debug_flags
fun:g_type_init
fun:init_pre
fun:init_popt_callback
obj:/usr/lib/libpopt.so.*
obj:/usr/lib/libpopt.so.*
fun:poptGetContext
fun:gst_init_check_with_popt_table
}
### GStreamer suppressions
# ds is saying he's rewriting the registry anyway
{
<registry>
Memcheck:Leak
fun:malloc
fun:g_malloc
fun:g_strdup
fun:read_string
fun:load_plugin
fun:gst_xml_registry_load
fun:gst_registry_load
fun:_registry_load_func
fun:g_list_foreach
fun:gst_registry_pool_load_all
fun:init_post
fun:init_popt_callback
}

View file

@ -31,6 +31,30 @@ GST_START_TEST (test_init)
GST_END_TEST;
GST_START_TEST (test_deinit)
{
gst_init (NULL, NULL);
gst_deinit ();
}
GST_END_TEST;
GST_START_TEST (test_deinit_sysclock)
{
GstClock *clock;
gst_init (NULL, NULL);
clock = gst_system_clock_obtain ();
gst_object_unref (clock);
gst_deinit ();
}
GST_END_TEST;
Suite *
gst_suite (void)
{
@ -39,6 +63,8 @@ gst_suite (void)
suite_add_tcase (s, tc_chain);
tcase_add_test (tc_chain, test_init);
tcase_add_test (tc_chain, test_deinit);
tcase_add_test (tc_chain, test_deinit_sysclock);
return s;
}

View file

@ -28,6 +28,7 @@ GST_START_TEST (test_subbuffer)
int rc;
buffer = gst_buffer_new_and_alloc (4);
memset (GST_BUFFER_DATA (buffer), 0, 4);
sub = gst_buffer_create_sub (buffer, 1, 2);
@ -38,6 +39,9 @@ GST_START_TEST (test_subbuffer)
rc = GST_MINI_OBJECT_REFCOUNT_VALUE (buffer);
fail_unless (rc == 2, "parent refcount is %d instead of 3", rc);
/* clean up */
gst_buffer_unref (sub);
gst_buffer_unref (buffer);
}
@ -62,6 +66,11 @@ GST_START_TEST (test_is_span_fast)
fail_if (gst_buffer_is_span_fast (sub1, sub2) == FALSE,
"two subbuffers next to each other should be span_fast");
/* clean up */
gst_buffer_unref (sub1);
gst_buffer_unref (sub2);
gst_buffer_unref (buffer);
}
GST_END_TEST Suite *
gst_test_suite (void)

View file

@ -124,7 +124,10 @@ GST_START_TEST (test_ghost_pads)
gst_object_unref (gisink);
assert_gstrefcount (fsink, 1);
}
GST_END_TEST Suite *
GST_END_TEST;
Suite *
gst_ghost_pad_suite (void)
{
Suite *s = suite_create ("GstGhostPad");

View file

@ -1,8 +1,8 @@
/* GStreamer
*
* unit test for GstData
* unit test for GstMiniObject
*
* Copyright (C) <2004> Thomas Vander Stichele <thomas at apestaart dot org>
* Copyright (C) <2005> Thomas Vander Stichele <thomas at apestaart dot org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
@ -28,7 +28,7 @@ GST_START_TEST (test_copy)
buffer = gst_buffer_new_and_alloc (4);
copy = GST_BUFFER (gst_data_copy (GST_DATA (buffer)));
copy = GST_BUFFER (gst_mini_object_copy (GST_MINI_OBJECT (buffer)));
fail_if (copy == NULL, "Copy of buffer returned NULL");
fail_unless (GST_BUFFER_SIZE (copy) == 4,
@ -39,70 +39,71 @@ GST_END_TEST
GST_START_TEST (test_is_writable)
{
GstBuffer *buffer;
GstData *data;
GstMiniObject *mobj;
buffer = gst_buffer_new_and_alloc (4);
data = GST_DATA (buffer);
mobj = GST_MINI_OBJECT (buffer);
fail_unless (gst_data_is_writable (data),
fail_unless (gst_mini_object_is_writable (mobj),
"A buffer with one ref should be writable");
GST_DATA_FLAG_SET (data, GST_DATA_READONLY);
fail_if (gst_data_is_writable (data),
GST_MINI_OBJECT_FLAG_SET (mobj, GST_MINI_OBJECT_FLAG_READONLY);
fail_if (gst_mini_object_is_writable (mobj),
"A buffer with READONLY set should not be writable");
GST_DATA_FLAG_UNSET (data, GST_DATA_READONLY);
fail_unless (gst_data_is_writable (data),
GST_MINI_OBJECT_FLAG_UNSET (mobj, GST_MINI_OBJECT_FLAG_READONLY);
fail_unless (gst_mini_object_is_writable (mobj),
"A buffer with one ref and READONLY not set should be writable");
fail_if (gst_data_ref (data) == NULL, "Could not ref the data");
fail_if (gst_mini_object_ref (mobj) == NULL, "Could not ref the mobj");
fail_if (gst_data_is_writable (data),
fail_if (gst_mini_object_is_writable (mobj),
"A buffer with two refs should not be writable");
}
GST_END_TEST
GST_START_TEST (test_copy_on_write)
GST_START_TEST (test_make_writable)
{
GstBuffer *buffer;
GstData *data, *data2, *data3;
GstMiniObject *mobj, *mobj2, *mobj3;
buffer = gst_buffer_new_and_alloc (4);
data = GST_DATA (buffer);
mobj = GST_MINI_OBJECT (buffer);
data2 = gst_data_copy_on_write (data);
fail_unless (GST_IS_BUFFER (data2), "copy_on_write did not return a buffer");
fail_unless (data == data2,
"copy_on_write returned a copy for a buffer with refcount 1");
mobj2 = gst_mini_object_make_writable (mobj);
fail_unless (GST_IS_BUFFER (mobj2), "make_writable did not return a buffer");
fail_unless (mobj == mobj2,
"make_writable returned a copy for a buffer with refcount 1");
data2 = gst_data_ref (data);
data3 = gst_data_copy_on_write (data);
fail_unless (GST_IS_BUFFER (data3), "copy_on_write did not return a buffer");
fail_if (data == data3,
"copy_on_write returned same object for a buffer with refcount > 1");
mobj2 = gst_mini_object_ref (mobj);
mobj3 = gst_mini_object_make_writable (mobj);
fail_unless (GST_IS_BUFFER (mobj3), "make_writable did not return a buffer");
fail_if (mobj == mobj3,
"make_writable returned same object for a buffer with refcount > 1");
fail_unless (GST_DATA_REFCOUNT_VALUE (data) == 1,
"refcount of original data object should be back to 1");
fail_unless (GST_MINI_OBJECT_REFCOUNT_VALUE (mobj) == 1,
"refcount of original mobj object should be back to 1");
data2 = gst_data_copy_on_write (data);
fail_unless (GST_IS_BUFFER (data2), "copy_on_write did not return a buffer");
fail_unless (data == data2,
"copy_on_write returned a copy for a buffer with refcount 1");
mobj2 = gst_mini_object_make_writable (mobj);
fail_unless (GST_IS_BUFFER (mobj2), "make_writable did not return a buffer");
fail_unless (mobj == mobj2,
"make_writable returned a copy for a buffer with refcount 1");
}
GST_END_TEST gint num_threads = 10;
gint refs_per_thread = 10000;
/* test thread-safe refcounting of GstData */
/* test thread-safe refcounting of GstMiniObject */
void
thread_ref (GstData * data)
thread_ref (GstMiniObject * mobj)
{
int j;
THREAD_START ();
for (j = 0; j < refs_per_thread; ++j) {
fail_if (gst_data_ref (data) == NULL, "Could not ref data from thread");
fail_if (gst_mini_object_ref (mobj) == NULL,
"Could not ref mobj from thread");
if (j % num_threads == 0)
THREAD_SWITCH ();
@ -113,30 +114,31 @@ thread_ref (GstData * data)
GST_START_TEST (test_ref_threaded)
{
GstBuffer *buffer;
GstData *data;
GstMiniObject *mobj;
gint expected;
buffer = gst_buffer_new_and_alloc (4);
data = GST_DATA (buffer);
mobj = GST_MINI_OBJECT (buffer);
MAIN_START_THREADS (num_threads, thread_ref, data);
MAIN_START_THREADS (num_threads, thread_ref, mobj);
MAIN_STOP_THREADS ();
expected = num_threads * refs_per_thread + 1;
fail_unless (GST_DATA_REFCOUNT_VALUE (data) == expected,
"Refcount of data is %d != %d", GST_DATA_REFCOUNT_VALUE (data), expected);
fail_unless (GST_MINI_OBJECT_REFCOUNT_VALUE (mobj) == expected,
"Refcount of mobj is %d != %d", GST_MINI_OBJECT_REFCOUNT_VALUE (mobj),
expected);
}
GST_END_TEST void
thread_unref (GstData * data)
thread_unref (GstMiniObject * mobj)
{
int j;
THREAD_START ();
for (j = 0; j < refs_per_thread; ++j) {
gst_data_unref (data);
gst_mini_object_unref (mobj);
if (j % num_threads == 0)
THREAD_SWITCH ();
@ -146,28 +148,30 @@ thread_unref (GstData * data)
GST_START_TEST (test_unref_threaded)
{
GstBuffer *buffer;
GstData *data;
GstMiniObject *mobj;
int i;
buffer = gst_buffer_new_and_alloc (4);
data = GST_DATA (buffer);
mobj = GST_MINI_OBJECT (buffer);
gst_data_ref_by_count (data, num_threads * refs_per_thread);
for (i = 0; i < num_threads * refs_per_thread; ++i)
gst_mini_object_ref (mobj);
MAIN_START_THREADS (num_threads, thread_unref, data);
MAIN_START_THREADS (num_threads, thread_unref, mobj);
MAIN_STOP_THREADS ();
fail_unless (GST_DATA_REFCOUNT_VALUE (data) == 1,
"Refcount of data is %d != %d", GST_DATA_REFCOUNT_VALUE (data), 1);
fail_unless (GST_MINI_OBJECT_REFCOUNT_VALUE (mobj) == 1,
"Refcount of mobj is %d != %d", GST_MINI_OBJECT_REFCOUNT_VALUE (mobj), 1);
/* final unref */
gst_data_unref (data);
gst_mini_object_unref (mobj);
}
GST_END_TEST Suite *
gst_data_suite (void)
gst_mini_object_suite (void)
{
Suite *s = suite_create ("GstData");
Suite *s = suite_create ("GstMiniObject");
TCase *tc_chain = tcase_create ("general");
/* turn off timeout */
@ -176,7 +180,7 @@ gst_data_suite (void)
suite_add_tcase (s, tc_chain);
tcase_add_test (tc_chain, test_copy);
tcase_add_test (tc_chain, test_is_writable);
tcase_add_test (tc_chain, test_copy_on_write);
tcase_add_test (tc_chain, test_make_writable);
tcase_add_test (tc_chain, test_ref_threaded);
tcase_add_test (tc_chain, test_unref_threaded);
return s;
@ -187,7 +191,7 @@ main (int argc, char **argv)
{
int nf;
Suite *s = gst_data_suite ();
Suite *s = gst_mini_object_suite ();
SRunner *sr = srunner_create (s);
gst_check_init (&argc, &argv);

View file

@ -445,6 +445,9 @@ fi
AC_SUBST(VALGRIND_CFLAGS)
AC_SUBST(VALGRIND_LIBS)
AC_PATH_PROG(VALGRIND_PATH, valgrind, no)
AM_CONDITIONAL(HAVE_VALGRIND, test ! "x$VALGRIND_PATH" = "xno")
dnl ################################################
dnl # Set defines according to variables set above #
dnl ################################################
@ -498,8 +501,8 @@ dnl #############################
dnl These should be "USE_*" instead of "HAVE_*", but some packages expect
dnl HAVE_ and it is likely to be easier to stick with the old name
AM_CONDITIONAL(EXPERIMENTAL, test "$EXPERIMENTAL" = "$xyes")
AM_CONDITIONAL(BROKEN, test "$BROKEN" = "$xyes")
AM_CONDITIONAL(EXPERIMENTAL, test "x$EXPERIMENTAL" = "yes")
AM_CONDITIONAL(BROKEN, test "x$BROKEN" = "yes")
AM_CONDITIONAL(PLUGINS_USE_BUILDDIR, test "x$PLUGINS_USE_BUILDDIR" = "xyes")

View file

@ -806,6 +806,25 @@ init_popt_callback (poptContext context, enum poptCallbackReason reason,
}
}
/**
* gst_deinit:
*
* Clean up.
* Call only once, before exiting.
* After this call GStreamer should not be used anymore.
*/
void
gst_deinit (void)
{
GstClock *clock;
clock = gst_system_clock_obtain ();
gst_object_unref (clock);
gst_object_unref (clock);
gst_initialized = FALSE;
}
/**
* gst_version:
* @major: pointer to a guint to store the major version number

View file

@ -99,6 +99,7 @@ gboolean gst_init_check_with_popt_table (int *argc, char **argv[],
*popt_options);
const GstPoptOption * gst_init_get_popt_table (void);
void gst_deinit (void);
G_END_DECLS

View file

@ -131,36 +131,34 @@ gst_system_clock_dispose (GObject * object)
{
GstClock *clock = (GstClock *) object;
/* there are subclasses of GstSystemClock running around... */
GstSystemClock *sysclock = GST_SYSTEM_CLOCK (clock);
GList *entries;
/* else we have to stop the thread */
GST_LOCK (clock);
sysclock->stopping = TRUE;
/* unschedule all entries */
for (entries = clock->entries; entries; entries = g_list_next (entries)) {
GstClockEntry *entry = (GstClockEntry *) entries->data;
GST_CAT_DEBUG (GST_CAT_CLOCK, "unscheduling entry %p", entry);
entry->status = GST_CLOCK_UNSCHEDULED;
}
g_list_free (clock->entries);
clock->entries = NULL;
GST_CLOCK_BROADCAST (clock);
GST_UNLOCK (clock);
if (sysclock->thread)
g_thread_join (sysclock->thread);
sysclock->thread = NULL;
GST_CAT_DEBUG (GST_CAT_CLOCK, "joined thread");
G_OBJECT_CLASS (parent_class)->dispose (object);
if (_the_system_clock == clock) {
g_warning ("disposing systemclock!");
/* no parent dispose here, this is bad enough already */
} else {
GstSystemClock *sysclock = GST_SYSTEM_CLOCK (clock);
GList *entries;
/* else we have to stop the thread */
GST_LOCK (clock);
sysclock->stopping = TRUE;
/* unschedule all entries */
for (entries = clock->entries; entries; entries = g_list_next (entries)) {
GstClockEntry *entry = (GstClockEntry *) entries->data;
GST_CAT_DEBUG (GST_CAT_CLOCK, "unscheduling entry %p", entry);
entry->status = GST_CLOCK_UNSCHEDULED;
}
g_list_free (clock->entries);
clock->entries = NULL;
GST_CLOCK_BROADCAST (clock);
GST_UNLOCK (clock);
if (sysclock->thread)
g_thread_join (sysclock->thread);
sysclock->thread = NULL;
GST_CAT_DEBUG (GST_CAT_CLOCK, "joined thread");
G_OBJECT_CLASS (parent_class)->dispose (object);
_the_system_clock = NULL;
GST_CAT_DEBUG (GST_CAT_CLOCK, "disposed system clock");
}
}
@ -168,7 +166,7 @@ gst_system_clock_dispose (GObject * object)
* gst_system_clock_obtain:
*
* Get a handle to the default system clock. The refcount of the
* clock will be increased so you need to unref the clock after
* clock will be increased so you need to unref the clock after
* usage.
*
* Returns: the default clock.
@ -185,9 +183,6 @@ gst_system_clock_obtain (void)
if (clock == NULL) {
GST_CAT_DEBUG (GST_CAT_CLOCK, "creating new static system clock");
/* FIXME: the only way to clean this up is to have a gst_exit()
* function; until then, the program will always end with the sysclock
* at refcount 1 */
clock = g_object_new (GST_TYPE_SYSTEM_CLOCK,
"name", "GstSystemClock", NULL);

View file

@ -15,6 +15,8 @@ install-pluginLTLIBRARIES:
# ths core dumps of some machines have PIDs appended
CLEANFILES = core.* test-registry.xml
EXTRA_DIST = gst.supp
clean-local:
for i in `find . -name ".libs" -type d`; do \
rm -rf $$i; \
@ -32,6 +34,7 @@ TESTS = $(top_builddir)/tools/gst-register \
gst/gstghostpad \
gst/gstiterator \
gst/gstmessage \
gst/gstminiobject \
gst/gstobject \
gst/gstpad \
gst/gstsystemclock \
@ -60,3 +63,59 @@ gst_libs_gdp_SOURCES = \
$(top_srcdir)/libs/gst/dataprotocol/dataprotocol.c
# remove GST_ENABLE_NEW when dataprotocol has been declared API-stable
gst_libs_gdp_CFLAGS = $(AM_CFLAGS) -DGST_ENABLE_NEW
# valgrind testing
# these just need fixing, period
TESTS_TO_FIX = \
gst/gstghostpad \
gst/gstiterator \
gst/gstmessage \
gst/gstpad \
gst/gstsystemclock \
gst/gststructure \
gst/gsttag \
gst/gstvalue \
elements/gstfakesrc \
pipelines/cleanup \
pipelines/simple_launch_lines \
gst-libs/gdp
# these need fixing because the threads cause segfaults under valgrind
TESTS_THREADED = \
gst/gstminiobject \
gst/gstobject
VALGRIND_TESTS_DISABLE = \
$(top_builddir)/tools/gst-register \
$(TESTS_THREADED) \
$(TESTS_TO_FIX)
if HAVE_VALGRIND
check-local:
make valgrind
else
check-local:
true
endif
valgrind:
@echo "Valgrinding tests ..."
$(TESTS_ENVIRONMENT) $(top_builddir)/tools/gst-register
@failed=0; \
for t in $(filter-out $(VALGRIND_TESTS_DISABLE),$(TESTS)); do \
$(TESTS_ENVIRONMENT) \
CK_FORK=no \
libtool --mode=execute \
$(VALGRIND_PATH) -q --suppressions=$(srcdir)/gst.supp \
--leak-check=yes $$t; \
if test "$$?" -ne 0; then \
echo "Valgrind error for test $$t"; \
failed=`expr $$failed + 1`; \
fi; \
done; \
if test "$$failed" -ne 0; then \
echo "$$failed tests had leaks under valgrind"; \
false; \
fi

68
tests/check/gst.supp Normal file
View file

@ -0,0 +1,68 @@
### this file contains suppressions for valgrind when running
### the gstreamer unit tests
### it might be useful for wider use as well
### glibc suppressions
# glibc does not deallocate thread-local storage
{
<tls>
Memcheck:Leak
fun:calloc
fun:_dl_allocate_tls
fun:pthread_create@@GLIBC_2.1
}
{
<pthread strstr>
Memcheck:Cond
fun:strstr
fun:__pthread_initialize_minimal
obj:/lib/libpthread-*.so
obj:/lib/libpthread-*.so
fun:call_init
fun:_dl_init
obj:/lib/ld-*.so
}
### glib suppressions
{
<g_type_init>
Memcheck:Leak
fun:calloc
fun:g_malloc0
obj:/usr/lib/libgobject-2.0.so.*
obj:/usr/lib/libgobject-2.0.so.*
fun:g_type_init_with_debug_flags
fun:g_type_init
fun:init_pre
fun:init_popt_callback
obj:/usr/lib/libpopt.so.*
obj:/usr/lib/libpopt.so.*
fun:poptGetContext
fun:gst_init_check_with_popt_table
}
### GStreamer suppressions
# ds is saying he's rewriting the registry anyway
{
<registry>
Memcheck:Leak
fun:malloc
fun:g_malloc
fun:g_strdup
fun:read_string
fun:load_plugin
fun:gst_xml_registry_load
fun:gst_registry_load
fun:_registry_load_func
fun:g_list_foreach
fun:gst_registry_pool_load_all
fun:init_post
fun:init_popt_callback
}

View file

@ -31,6 +31,30 @@ GST_START_TEST (test_init)
GST_END_TEST;
GST_START_TEST (test_deinit)
{
gst_init (NULL, NULL);
gst_deinit ();
}
GST_END_TEST;
GST_START_TEST (test_deinit_sysclock)
{
GstClock *clock;
gst_init (NULL, NULL);
clock = gst_system_clock_obtain ();
gst_object_unref (clock);
gst_deinit ();
}
GST_END_TEST;
Suite *
gst_suite (void)
{
@ -39,6 +63,8 @@ gst_suite (void)
suite_add_tcase (s, tc_chain);
tcase_add_test (tc_chain, test_init);
tcase_add_test (tc_chain, test_deinit);
tcase_add_test (tc_chain, test_deinit_sysclock);
return s;
}

View file

@ -28,6 +28,7 @@ GST_START_TEST (test_subbuffer)
int rc;
buffer = gst_buffer_new_and_alloc (4);
memset (GST_BUFFER_DATA (buffer), 0, 4);
sub = gst_buffer_create_sub (buffer, 1, 2);
@ -38,6 +39,9 @@ GST_START_TEST (test_subbuffer)
rc = GST_MINI_OBJECT_REFCOUNT_VALUE (buffer);
fail_unless (rc == 2, "parent refcount is %d instead of 3", rc);
/* clean up */
gst_buffer_unref (sub);
gst_buffer_unref (buffer);
}
@ -62,6 +66,11 @@ GST_START_TEST (test_is_span_fast)
fail_if (gst_buffer_is_span_fast (sub1, sub2) == FALSE,
"two subbuffers next to each other should be span_fast");
/* clean up */
gst_buffer_unref (sub1);
gst_buffer_unref (sub2);
gst_buffer_unref (buffer);
}
GST_END_TEST Suite *
gst_test_suite (void)

View file

@ -124,7 +124,10 @@ GST_START_TEST (test_ghost_pads)
gst_object_unref (gisink);
assert_gstrefcount (fsink, 1);
}
GST_END_TEST Suite *
GST_END_TEST;
Suite *
gst_ghost_pad_suite (void)
{
Suite *s = suite_create ("GstGhostPad");

View file

@ -1,8 +1,8 @@
/* GStreamer
*
* unit test for GstData
* unit test for GstMiniObject
*
* Copyright (C) <2004> Thomas Vander Stichele <thomas at apestaart dot org>
* Copyright (C) <2005> Thomas Vander Stichele <thomas at apestaart dot org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
@ -28,7 +28,7 @@ GST_START_TEST (test_copy)
buffer = gst_buffer_new_and_alloc (4);
copy = GST_BUFFER (gst_data_copy (GST_DATA (buffer)));
copy = GST_BUFFER (gst_mini_object_copy (GST_MINI_OBJECT (buffer)));
fail_if (copy == NULL, "Copy of buffer returned NULL");
fail_unless (GST_BUFFER_SIZE (copy) == 4,
@ -39,70 +39,71 @@ GST_END_TEST
GST_START_TEST (test_is_writable)
{
GstBuffer *buffer;
GstData *data;
GstMiniObject *mobj;
buffer = gst_buffer_new_and_alloc (4);
data = GST_DATA (buffer);
mobj = GST_MINI_OBJECT (buffer);
fail_unless (gst_data_is_writable (data),
fail_unless (gst_mini_object_is_writable (mobj),
"A buffer with one ref should be writable");
GST_DATA_FLAG_SET (data, GST_DATA_READONLY);
fail_if (gst_data_is_writable (data),
GST_MINI_OBJECT_FLAG_SET (mobj, GST_MINI_OBJECT_FLAG_READONLY);
fail_if (gst_mini_object_is_writable (mobj),
"A buffer with READONLY set should not be writable");
GST_DATA_FLAG_UNSET (data, GST_DATA_READONLY);
fail_unless (gst_data_is_writable (data),
GST_MINI_OBJECT_FLAG_UNSET (mobj, GST_MINI_OBJECT_FLAG_READONLY);
fail_unless (gst_mini_object_is_writable (mobj),
"A buffer with one ref and READONLY not set should be writable");
fail_if (gst_data_ref (data) == NULL, "Could not ref the data");
fail_if (gst_mini_object_ref (mobj) == NULL, "Could not ref the mobj");
fail_if (gst_data_is_writable (data),
fail_if (gst_mini_object_is_writable (mobj),
"A buffer with two refs should not be writable");
}
GST_END_TEST
GST_START_TEST (test_copy_on_write)
GST_START_TEST (test_make_writable)
{
GstBuffer *buffer;
GstData *data, *data2, *data3;
GstMiniObject *mobj, *mobj2, *mobj3;
buffer = gst_buffer_new_and_alloc (4);
data = GST_DATA (buffer);
mobj = GST_MINI_OBJECT (buffer);
data2 = gst_data_copy_on_write (data);
fail_unless (GST_IS_BUFFER (data2), "copy_on_write did not return a buffer");
fail_unless (data == data2,
"copy_on_write returned a copy for a buffer with refcount 1");
mobj2 = gst_mini_object_make_writable (mobj);
fail_unless (GST_IS_BUFFER (mobj2), "make_writable did not return a buffer");
fail_unless (mobj == mobj2,
"make_writable returned a copy for a buffer with refcount 1");
data2 = gst_data_ref (data);
data3 = gst_data_copy_on_write (data);
fail_unless (GST_IS_BUFFER (data3), "copy_on_write did not return a buffer");
fail_if (data == data3,
"copy_on_write returned same object for a buffer with refcount > 1");
mobj2 = gst_mini_object_ref (mobj);
mobj3 = gst_mini_object_make_writable (mobj);
fail_unless (GST_IS_BUFFER (mobj3), "make_writable did not return a buffer");
fail_if (mobj == mobj3,
"make_writable returned same object for a buffer with refcount > 1");
fail_unless (GST_DATA_REFCOUNT_VALUE (data) == 1,
"refcount of original data object should be back to 1");
fail_unless (GST_MINI_OBJECT_REFCOUNT_VALUE (mobj) == 1,
"refcount of original mobj object should be back to 1");
data2 = gst_data_copy_on_write (data);
fail_unless (GST_IS_BUFFER (data2), "copy_on_write did not return a buffer");
fail_unless (data == data2,
"copy_on_write returned a copy for a buffer with refcount 1");
mobj2 = gst_mini_object_make_writable (mobj);
fail_unless (GST_IS_BUFFER (mobj2), "make_writable did not return a buffer");
fail_unless (mobj == mobj2,
"make_writable returned a copy for a buffer with refcount 1");
}
GST_END_TEST gint num_threads = 10;
gint refs_per_thread = 10000;
/* test thread-safe refcounting of GstData */
/* test thread-safe refcounting of GstMiniObject */
void
thread_ref (GstData * data)
thread_ref (GstMiniObject * mobj)
{
int j;
THREAD_START ();
for (j = 0; j < refs_per_thread; ++j) {
fail_if (gst_data_ref (data) == NULL, "Could not ref data from thread");
fail_if (gst_mini_object_ref (mobj) == NULL,
"Could not ref mobj from thread");
if (j % num_threads == 0)
THREAD_SWITCH ();
@ -113,30 +114,31 @@ thread_ref (GstData * data)
GST_START_TEST (test_ref_threaded)
{
GstBuffer *buffer;
GstData *data;
GstMiniObject *mobj;
gint expected;
buffer = gst_buffer_new_and_alloc (4);
data = GST_DATA (buffer);
mobj = GST_MINI_OBJECT (buffer);
MAIN_START_THREADS (num_threads, thread_ref, data);
MAIN_START_THREADS (num_threads, thread_ref, mobj);
MAIN_STOP_THREADS ();
expected = num_threads * refs_per_thread + 1;
fail_unless (GST_DATA_REFCOUNT_VALUE (data) == expected,
"Refcount of data is %d != %d", GST_DATA_REFCOUNT_VALUE (data), expected);
fail_unless (GST_MINI_OBJECT_REFCOUNT_VALUE (mobj) == expected,
"Refcount of mobj is %d != %d", GST_MINI_OBJECT_REFCOUNT_VALUE (mobj),
expected);
}
GST_END_TEST void
thread_unref (GstData * data)
thread_unref (GstMiniObject * mobj)
{
int j;
THREAD_START ();
for (j = 0; j < refs_per_thread; ++j) {
gst_data_unref (data);
gst_mini_object_unref (mobj);
if (j % num_threads == 0)
THREAD_SWITCH ();
@ -146,28 +148,30 @@ thread_unref (GstData * data)
GST_START_TEST (test_unref_threaded)
{
GstBuffer *buffer;
GstData *data;
GstMiniObject *mobj;
int i;
buffer = gst_buffer_new_and_alloc (4);
data = GST_DATA (buffer);
mobj = GST_MINI_OBJECT (buffer);
gst_data_ref_by_count (data, num_threads * refs_per_thread);
for (i = 0; i < num_threads * refs_per_thread; ++i)
gst_mini_object_ref (mobj);
MAIN_START_THREADS (num_threads, thread_unref, data);
MAIN_START_THREADS (num_threads, thread_unref, mobj);
MAIN_STOP_THREADS ();
fail_unless (GST_DATA_REFCOUNT_VALUE (data) == 1,
"Refcount of data is %d != %d", GST_DATA_REFCOUNT_VALUE (data), 1);
fail_unless (GST_MINI_OBJECT_REFCOUNT_VALUE (mobj) == 1,
"Refcount of mobj is %d != %d", GST_MINI_OBJECT_REFCOUNT_VALUE (mobj), 1);
/* final unref */
gst_data_unref (data);
gst_mini_object_unref (mobj);
}
GST_END_TEST Suite *
gst_data_suite (void)
gst_mini_object_suite (void)
{
Suite *s = suite_create ("GstData");
Suite *s = suite_create ("GstMiniObject");
TCase *tc_chain = tcase_create ("general");
/* turn off timeout */
@ -176,7 +180,7 @@ gst_data_suite (void)
suite_add_tcase (s, tc_chain);
tcase_add_test (tc_chain, test_copy);
tcase_add_test (tc_chain, test_is_writable);
tcase_add_test (tc_chain, test_copy_on_write);
tcase_add_test (tc_chain, test_make_writable);
tcase_add_test (tc_chain, test_ref_threaded);
tcase_add_test (tc_chain, test_unref_threaded);
return s;
@ -187,7 +191,7 @@ main (int argc, char **argv)
{
int nf;
Suite *s = gst_data_suite ();
Suite *s = gst_mini_object_suite ();
SRunner *sr = srunner_create (s);
gst_check_init (&argc, &argv);

View file

@ -648,6 +648,7 @@ end:
fprintf (stderr, _("FREEING pipeline ...\n"));
gst_object_unref (pipeline);
gst_deinit ();
if (trace)
gst_alloc_trace_print_live ();