diff --git a/ChangeLog b/ChangeLog index 82a13b845a..cf54a6fb3d 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,16 @@ +2008-06-20 Wim Taymans + + * tests/check/Makefile.am: + * tests/check/libs/test_transform.c: (gst_test_trans_base_init), + (gst_test_trans_class_init), (gst_test_trans_init), + (gst_test_trans_set_data), (result_sink_chain), + (gst_test_trans_new), (gst_test_trans_free), (gst_test_trans_push), + (gst_test_trans_pop): + * tests/check/libs/transform1.c: (GST_START_TEST), + (transform_ip_1), (set_caps_1), (gst_basetransform_suite): + Add some test basetransform element and the beginnings of various + unit tests for it. + 2008-06-20 Wim Taymans * libs/gst/base/gsttypefindhelper.c: (helper_find_peek): diff --git a/tests/check/Makefile.am b/tests/check/Makefile.am index 20ddedab3a..5904a9ffe1 100644 --- a/tests/check/Makefile.am +++ b/tests/check/Makefile.am @@ -100,7 +100,8 @@ check_PROGRAMS = \ libs/gdp \ libs/adapter \ libs/gstnetclientclock \ - libs/gstnettimeprovider + libs/gstnettimeprovider \ + libs/transform1 # failing tests # queue : tests is unstable (race conditions) @@ -163,6 +164,9 @@ libs_gstnettimeprovider_LDADD = \ libs_typefindhelper_LDADD = \ $(top_builddir)/libs/gst/base/libgstbase-@GST_MAJORMINOR@.la \ $(LDADD) +libs_transform1_LDADD = \ + $(top_builddir)/libs/gst/base/libgstbase-@GST_MAJORMINOR@.la \ + $(LDADD) # valgrind testing # these just need valgrind fixing, period diff --git a/tests/check/libs/test_transform.c b/tests/check/libs/test_transform.c new file mode 100644 index 0000000000..ccb8d01dd3 --- /dev/null +++ b/tests/check/libs/test_transform.c @@ -0,0 +1,199 @@ + +#include + +typedef struct +{ + GstPad *srcpad; + GstPad *sinkpad; + GList *events; + GList *buffers; + GstElement *trans; + GstBaseTransformClass *klass; +} TestTransData; + +static GstStaticPadTemplate gst_test_trans_src_template = +GST_STATIC_PAD_TEMPLATE ("src", + GST_PAD_SRC, + GST_PAD_ALWAYS, + GST_STATIC_CAPS ("foo/x-bar") + ); + +static GstStaticPadTemplate gst_test_trans_sink_template = +GST_STATIC_PAD_TEMPLATE ("sink", + GST_PAD_SINK, + GST_PAD_ALWAYS, + GST_STATIC_CAPS ("foo/x-bar") + ); + +typedef struct _GstTestTrans GstTestTrans; +typedef struct _GstTestTransClass GstTestTransClass; + +#define GST_TYPE_TEST_TRANS \ + (gst_test_trans_get_type()) +#define GST_TEST_TRANS(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_TEST_TRANS,GstTestTrans)) +#define GST_TEST_TRANS_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_TEST_TRANS,GstTestTransClass)) +#define GST_TEST_TRANS_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS((obj), GST_TYPE_TEST_TRANS, GstTestTransClass)) +#define GST_IS_TEST_TRANS(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_TEST_TRANS)) +#define GST_IS_TEST_TRANS_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_TEST_TRANS)) + +struct _GstTestTrans +{ + GstBaseTransform element; + + TestTransData *data; +}; + +struct _GstTestTransClass +{ + GstBaseTransformClass parent_class; +}; + +GST_BOILERPLATE (GstTestTrans, gst_test_trans, GstBaseTransform, + GST_TYPE_BASE_TRANSFORM); + +static void +gst_test_trans_base_init (gpointer g_class) +{ + GstElementClass *element_class; + + element_class = GST_ELEMENT_CLASS (g_class); + + gst_element_class_set_details_simple (element_class, "TestTrans", + "Filter/Test", "Test transform", "Wim Taymans "); + + gst_element_class_add_pad_template (element_class, + gst_static_pad_template_get (&gst_test_trans_sink_template)); + gst_element_class_add_pad_template (element_class, + gst_static_pad_template_get (&gst_test_trans_src_template)); +} + +static GstFlowReturn (*klass_transform) (GstBaseTransform * trans, + GstBuffer * inbuf, GstBuffer * outbuf) = NULL; +static GstFlowReturn (*klass_transform_ip) (GstBaseTransform * trans, + GstBuffer * buf) = NULL; +static gboolean (*klass_set_caps) (GstBaseTransform * trans, GstCaps * incaps, + GstCaps * outcaps) = NULL; + +static void +gst_test_trans_class_init (GstTestTransClass * klass) +{ + GObjectClass *gobject_class; + GstBaseTransformClass *trans_class; + + gobject_class = (GObjectClass *) klass; + trans_class = (GstBaseTransformClass *) klass; + + trans_class->transform_ip = klass_transform_ip; + trans_class->transform = klass_transform; + trans_class->set_caps = klass_set_caps; +} + +static void +gst_test_trans_init (GstTestTrans * this, GstTestTransClass * g_class) +{ +} + +static void +gst_test_trans_set_data (GstTestTrans * this, TestTransData * data) +{ + this->data = data; +} + +static GstFlowReturn +result_sink_chain (GstPad * pad, GstBuffer * buffer) +{ + TestTransData *data; + + data = gst_pad_get_element_private (pad); + + data->buffers = g_list_append (data->buffers, buffer); + + return GST_FLOW_OK; +} + +static TestTransData * +gst_test_trans_new (void) +{ + TestTransData *res; + GstPad *tmp; + + res = g_new0 (TestTransData, 1); + res->trans = g_object_new (GST_TYPE_TEST_TRANS, NULL); + res->srcpad = + gst_pad_new_from_static_template (&gst_test_trans_src_template, "src"); + res->sinkpad = + gst_pad_new_from_static_template (&gst_test_trans_sink_template, "sink"); + res->klass = GST_BASE_TRANSFORM_GET_CLASS (res->trans); + + gst_test_trans_set_data (GST_TEST_TRANS (res->trans), res); + gst_pad_set_element_private (res->sinkpad, res); + + gst_pad_set_chain_function (res->sinkpad, result_sink_chain); + + tmp = gst_element_get_static_pad (res->trans, "sink"); + gst_pad_link (res->srcpad, tmp); + gst_object_unref (tmp); + + tmp = gst_element_get_static_pad (res->trans, "src"); + gst_pad_link (tmp, res->sinkpad); + gst_object_unref (tmp); + + gst_pad_set_active (res->sinkpad, TRUE); + gst_element_set_state (res->trans, GST_STATE_PAUSED); + gst_pad_set_active (res->srcpad, TRUE); + + return res; +} + +static void +gst_test_trans_free (TestTransData * data) +{ + GstPad *tmp; + + gst_pad_set_active (data->sinkpad, FALSE); + gst_element_set_state (data->trans, GST_STATE_NULL); + gst_pad_set_active (data->srcpad, FALSE); + + tmp = gst_element_get_static_pad (data->trans, "src"); + gst_pad_unlink (tmp, data->sinkpad); + gst_object_unref (tmp); + + tmp = gst_element_get_static_pad (data->trans, "sink"); + gst_pad_link (data->srcpad, tmp); + gst_object_unref (tmp); + + gst_object_unref (data->srcpad); + gst_object_unref (data->sinkpad); + gst_object_unref (data->trans); + + g_free (data); +} + +static GstFlowReturn +gst_test_trans_push (TestTransData * data, GstBuffer * buffer) +{ + GstFlowReturn ret; + + ret = gst_pad_push (data->srcpad, buffer); + + return ret; +} + +static GstBuffer * +gst_test_trans_pop (TestTransData * data) +{ + GstBuffer *ret; + + if (data->buffers) { + ret = data->buffers->data; + data->buffers = g_list_delete_link (data->buffers, data->buffers); + } else { + ret = NULL; + } + return ret; +} diff --git a/tests/check/libs/transform1.c b/tests/check/libs/transform1.c new file mode 100644 index 0000000000..592aa8c2a4 --- /dev/null +++ b/tests/check/libs/transform1.c @@ -0,0 +1,310 @@ +/* GStreamer + * + * some unit tests for GstBaseTransform + * + * Copyright (C) 2008 Wim Taymans + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#include +#include +#include + +#undef FAILING_TESTS + +#include "test_transform.c" + +/* basic passthrough, we don't have any transform functions so we can only + * perform passthrough. We also don't have caps, which is fine */ +GST_START_TEST (basetransform_chain_pt1) +{ + TestTransData *trans; + GstBuffer *buffer; + GstFlowReturn res; + + trans = gst_test_trans_new (); + + buffer = gst_buffer_new_and_alloc (20); + + res = gst_test_trans_push (trans, buffer); + fail_unless (res == GST_FLOW_OK); + + buffer = gst_test_trans_pop (trans); + fail_unless (buffer != NULL); + fail_unless (GST_BUFFER_SIZE (buffer) == 20); + /* caps should not have been set */ + fail_unless (GST_BUFFER_CAPS (buffer) == NULL); + + gst_buffer_unref (buffer); + + buffer = gst_buffer_new_and_alloc (10); + res = gst_test_trans_push (trans, buffer); + fail_unless (res == GST_FLOW_OK); + + buffer = gst_test_trans_pop (trans); + fail_unless (buffer != NULL); + fail_unless (GST_BUFFER_SIZE (buffer) == 10); + /* caps should not have been set */ + fail_unless (GST_BUFFER_CAPS (buffer) == NULL); + + gst_buffer_unref (buffer); + + gst_test_trans_free (trans); +} + +GST_END_TEST; + +/* basic passthrough, we don't have any transform functions so we can only + * perform passthrough with same caps */ +GST_START_TEST (basetransform_chain_pt2) +{ + TestTransData *trans; + GstBuffer *buffer; + GstCaps *caps; + GstFlowReturn res; + + trans = gst_test_trans_new (); + + /* first buffer */ + caps = gst_caps_new_simple ("foo/x-bar", NULL); + + buffer = gst_buffer_new_and_alloc (20); + gst_buffer_set_caps (buffer, caps); + + res = gst_test_trans_push (trans, buffer); + fail_unless (res == GST_FLOW_OK); + + buffer = gst_test_trans_pop (trans); + fail_unless (buffer != NULL); + fail_unless (GST_BUFFER_SIZE (buffer) == 20); + fail_unless (GST_BUFFER_CAPS (buffer) == caps); + + gst_buffer_unref (buffer); + gst_caps_unref (caps); + + /* second buffer, renegotiates, keeps extra type arg in caps */ + caps = gst_caps_new_simple ("foo/x-bar", "type", G_TYPE_INT, 1, NULL); + + buffer = gst_buffer_new_and_alloc (10); + gst_buffer_set_caps (buffer, caps); + + res = gst_test_trans_push (trans, buffer); + fail_unless (res == GST_FLOW_OK); + + buffer = gst_test_trans_pop (trans); + fail_unless (buffer != NULL); + fail_unless (GST_BUFFER_SIZE (buffer) == 10); + fail_unless (GST_BUFFER_CAPS (buffer) == caps); + + gst_buffer_unref (buffer); + gst_caps_unref (caps); + + gst_test_trans_free (trans); +} + +GST_END_TEST; + +static gboolean transform_ip_1_called; +static gboolean transform_ip_1_writable; + +static GstFlowReturn +transform_ip_1 (GstBaseTransform * trans, GstBuffer * buf) +{ + GST_DEBUG_OBJECT (trans, "transform called"); + + transform_ip_1_called = TRUE; + transform_ip_1_writable = gst_buffer_is_writable (buf); + + GST_DEBUG_OBJECT (trans, "writable: %d", transform_ip_1_writable); + + return GST_FLOW_OK; +} + +/* basic in-place, check if the _ip function is called, buffer should + * be writable. no setcaps is set */ +GST_START_TEST (basetransform_chain_ip1) +{ + TestTransData *trans; + GstBuffer *buffer; + GstFlowReturn res; + + klass_transform_ip = transform_ip_1; + trans = gst_test_trans_new (); + + buffer = gst_buffer_new_and_alloc (20); + + transform_ip_1_called = FALSE;; + transform_ip_1_writable = TRUE;; + res = gst_test_trans_push (trans, buffer); + fail_unless (res == GST_FLOW_OK); + fail_unless (transform_ip_1_called == TRUE); + fail_unless (transform_ip_1_writable == TRUE); + + buffer = gst_test_trans_pop (trans); + fail_unless (buffer != NULL); + fail_unless (GST_BUFFER_SIZE (buffer) == 20); + gst_buffer_unref (buffer); + + buffer = gst_buffer_new_and_alloc (20); + /* take additional ref to make it non-writable */ + gst_buffer_ref (buffer); + + fail_unless (GST_MINI_OBJECT_REFCOUNT_VALUE (buffer) == 2); + + transform_ip_1_called = FALSE;; + transform_ip_1_writable = FALSE;; + res = gst_test_trans_push (trans, buffer); + fail_unless (res == GST_FLOW_OK); + fail_unless (transform_ip_1_called == TRUE); + /* copy should have been taken */ + fail_unless (transform_ip_1_writable == TRUE); + /* after push, get rid of the final ref we had */ + gst_buffer_unref (buffer); + + buffer = gst_test_trans_pop (trans); + fail_unless (buffer != NULL); + fail_unless (GST_BUFFER_SIZE (buffer) == 20); + + /* output buffer has refcount 1 */ + fail_unless (GST_MINI_OBJECT_REFCOUNT_VALUE (buffer) == 1); + gst_buffer_unref (buffer); + + gst_test_trans_free (trans); +} + +GST_END_TEST; + +static gboolean set_caps_1_called; + +static gboolean +set_caps_1 (GstBaseTransform * trans, GstCaps * incaps, GstCaps * outcaps) +{ + GstCaps *caps; + + GST_DEBUG_OBJECT (trans, "set_caps called"); + + set_caps_1_called = TRUE; + + caps = gst_caps_new_simple ("foo/x-bar", NULL); + + fail_unless (gst_caps_is_equal (incaps, caps)); + fail_unless (gst_caps_is_equal (outcaps, caps)); + + gst_caps_unref (caps); + + return TRUE; +} + +/* basic in-place, check if the _ip function is called, buffer should be + * writable. we also set a setcaps function and see if it's called. */ +GST_START_TEST (basetransform_chain_ip2) +{ + TestTransData *trans; + GstBuffer *buffer; + GstFlowReturn res; + GstCaps *caps; + + klass_transform_ip = transform_ip_1; + klass_set_caps = set_caps_1; + + trans = gst_test_trans_new (); + + caps = gst_caps_new_simple ("foo/x-bar", NULL); + + /* first try to push a buffer without caps, this should fail */ + buffer = gst_buffer_new_and_alloc (20); + + transform_ip_1_called = FALSE;; + transform_ip_1_writable = FALSE;; + set_caps_1_called = FALSE;; + res = gst_test_trans_push (trans, buffer); + fail_unless (res == GST_FLOW_NOT_NEGOTIATED); + fail_unless (transform_ip_1_called == FALSE); + fail_unless (transform_ip_1_writable == FALSE); + fail_unless (set_caps_1_called == FALSE); + + /* try to push a buffer with caps */ + buffer = gst_buffer_new_and_alloc (20); + gst_buffer_set_caps (buffer, caps); + + transform_ip_1_called = FALSE; + transform_ip_1_writable = FALSE; + set_caps_1_called = FALSE;; + res = gst_test_trans_push (trans, buffer); + fail_unless (res == GST_FLOW_OK); + fail_unless (transform_ip_1_called == TRUE); + fail_unless (transform_ip_1_writable == TRUE); + fail_unless (set_caps_1_called == TRUE); + + buffer = gst_test_trans_pop (trans); + fail_unless (buffer != NULL); + fail_unless (GST_BUFFER_SIZE (buffer) == 20); + fail_unless (GST_BUFFER_CAPS (buffer) == caps); + gst_buffer_unref (buffer); + + buffer = gst_buffer_new_and_alloc (20); + gst_buffer_set_caps (buffer, caps); + /* take additional ref to make it non-writable */ + gst_buffer_ref (buffer); + + fail_unless (GST_MINI_OBJECT_REFCOUNT_VALUE (buffer) == 2); + + transform_ip_1_called = FALSE;; + transform_ip_1_writable = FALSE;; + res = gst_test_trans_push (trans, buffer); + fail_unless (res == GST_FLOW_OK); + fail_unless (transform_ip_1_called == TRUE); + fail_unless (transform_ip_1_writable == TRUE); + /* after push, get rid of the final ref we had */ + gst_buffer_unref (buffer); + + buffer = gst_test_trans_pop (trans); + fail_unless (buffer != NULL); + fail_unless (GST_BUFFER_SIZE (buffer) == 20); + fail_unless (GST_BUFFER_CAPS (buffer) == caps); + + /* output buffer has refcount 1 */ + fail_unless (GST_MINI_OBJECT_REFCOUNT_VALUE (buffer) == 1); + gst_buffer_unref (buffer); + + gst_caps_unref (caps); + + trans->klass->transform_ip = NULL; + gst_test_trans_free (trans); +} + +GST_END_TEST; + +static Suite * +gst_basetransform_suite (void) +{ + Suite *s = suite_create ("GstBaseTransform"); + TCase *tc = tcase_create ("general"); + + suite_add_tcase (s, tc); + tcase_add_test (tc, basetransform_chain_pt1); + tcase_add_test (tc, basetransform_chain_pt2); + tcase_add_test (tc, basetransform_chain_ip1); + tcase_add_test (tc, basetransform_chain_ip2); + + return s; +} + +GST_CHECK_MAIN (gst_basetransform);