gstreamer/tests/check/gst/gstpad.c
Wim Taymans 842afb9732 test: add test to check sticky events order
Sticky events pushed on an unlinked pad should be stored on the pad. When the
pad is then linked and an event is pushed, the event should be merged with the
already existing sticky events and then the sticky events should be pushed in
the order that they were originally pushed.
2012-03-09 11:49:08 +01:00

1520 lines
41 KiB
C

/* GStreamer
* Copyright (C) <2005> Thomas Vander Stichele <thomas at apestaart dot org>
*
* gstpad.c: Unit test for GstPad
*
* 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.
*/
#include <gst/check/gstcheck.h>
GST_START_TEST (test_link)
{
GstPad *src, *sink;
GstPadTemplate *srct;
GstPadLinkReturn ret;
gchar *name;
src = gst_pad_new ("source", GST_PAD_SRC);
fail_if (src == NULL);
ASSERT_OBJECT_REFCOUNT (src, "source pad", 1);
name = gst_pad_get_name (src);
fail_unless (strcmp (name, "source") == 0);
ASSERT_OBJECT_REFCOUNT (src, "source pad", 1);
g_free (name);
sink = gst_pad_new ("sink", GST_PAD_SINK);
fail_if (sink == NULL);
/* linking without templates or caps should work */
ret = gst_pad_link (src, sink);
ASSERT_OBJECT_REFCOUNT (src, "source pad", 1);
ASSERT_OBJECT_REFCOUNT (sink, "sink pad", 1);
fail_unless (ret == GST_PAD_LINK_OK);
ASSERT_CRITICAL (gst_pad_get_pad_template (NULL));
srct = gst_pad_get_pad_template (src);
fail_unless (srct == NULL);
ASSERT_OBJECT_REFCOUNT (src, "source pad", 1);
/* clean up */
ASSERT_OBJECT_REFCOUNT (src, "source pad", 1);
gst_object_unref (src);
gst_object_unref (sink);
}
GST_END_TEST;
/* threaded link/unlink */
/* use globals */
static GstPad *src, *sink;
static void
thread_link_unlink (gpointer data)
{
THREAD_START ();
while (THREAD_TEST_RUNNING ()) {
gst_pad_link (src, sink);
gst_pad_unlink (src, sink);
THREAD_SWITCH ();
}
}
GST_START_TEST (test_link_unlink_threaded)
{
GstCaps *caps;
int i;
src = gst_pad_new ("source", GST_PAD_SRC);
fail_if (src == NULL);
sink = gst_pad_new ("sink", GST_PAD_SINK);
fail_if (sink == NULL);
caps = gst_caps_from_string ("foo/bar");
gst_pad_set_active (src, TRUE);
gst_pad_set_caps (src, caps);
gst_pad_set_active (sink, TRUE);
gst_pad_set_caps (sink, caps);
ASSERT_CAPS_REFCOUNT (caps, "caps", 3);
MAIN_START_THREADS (5, thread_link_unlink, NULL);
for (i = 0; i < 1000; ++i) {
gst_pad_is_linked (src);
gst_pad_is_linked (sink);
THREAD_SWITCH ();
}
MAIN_STOP_THREADS ();
ASSERT_CAPS_REFCOUNT (caps, "caps", 3);
gst_caps_unref (caps);
ASSERT_CAPS_REFCOUNT (caps, "caps", 2);
gst_object_unref (src);
gst_object_unref (sink);
}
GST_END_TEST;
GST_START_TEST (test_refcount)
{
GstPad *src, *sink;
GstCaps *caps;
GstPadLinkReturn plr;
sink = gst_pad_new ("sink", GST_PAD_SINK);
fail_if (sink == NULL);
src = gst_pad_new ("src", GST_PAD_SRC);
fail_if (src == NULL);
caps = gst_caps_from_string ("foo/bar");
/* one for me */
ASSERT_CAPS_REFCOUNT (caps, "caps", 1);
/* can't set caps on flushing sinkpad */
fail_if (gst_pad_set_caps (src, caps) == TRUE);
fail_if (gst_pad_set_caps (sink, caps) == TRUE);
/* one for me and one for each set_caps */
ASSERT_CAPS_REFCOUNT (caps, "caps", 1);
gst_pad_set_active (src, TRUE);
fail_unless (gst_pad_set_caps (src, caps) == TRUE);
ASSERT_CAPS_REFCOUNT (caps, "caps", 2);
gst_pad_set_active (sink, TRUE);
fail_unless (gst_pad_set_caps (sink, caps) == TRUE);
ASSERT_CAPS_REFCOUNT (caps, "caps", 3);
plr = gst_pad_link (src, sink);
fail_unless (GST_PAD_LINK_SUCCESSFUL (plr));
/* src caps added to pending caps on sink */
ASSERT_CAPS_REFCOUNT (caps, "caps", 3);
gst_pad_unlink (src, sink);
ASSERT_CAPS_REFCOUNT (caps, "caps", 3);
/* cleanup */
gst_object_unref (src);
gst_object_unref (sink);
ASSERT_CAPS_REFCOUNT (caps, "caps", 1);
gst_caps_unref (caps);
}
GST_END_TEST;
GST_START_TEST (test_get_allowed_caps)
{
GstPad *src, *sink;
GstCaps *caps, *gotcaps;
GstBuffer *buffer;
GstPadLinkReturn plr;
ASSERT_CRITICAL (gst_pad_get_allowed_caps (NULL));
buffer = gst_buffer_new ();
ASSERT_CRITICAL (gst_pad_get_allowed_caps ((GstPad *) buffer));
gst_buffer_unref (buffer);
src = gst_pad_new ("src", GST_PAD_SRC);
fail_if (src == NULL);
caps = gst_pad_get_allowed_caps (src);
fail_unless (caps == NULL);
caps = gst_caps_from_string ("foo/bar");
sink = gst_pad_new ("sink", GST_PAD_SINK);
gst_pad_set_active (src, TRUE);
/* source pad is active and will accept the caps event */
fail_unless (gst_pad_set_caps (src, caps) == TRUE);
/* sink pad is not active and will refuse the caps event */
fail_if (gst_pad_set_caps (sink, caps) == TRUE);
ASSERT_CAPS_REFCOUNT (caps, "caps", 2);
gst_pad_set_active (sink, TRUE);
/* sink pad is now active and will accept the caps event */
fail_unless (gst_pad_set_caps (sink, caps) == TRUE);
ASSERT_CAPS_REFCOUNT (caps, "caps", 3);
plr = gst_pad_link (src, sink);
fail_unless (GST_PAD_LINK_SUCCESSFUL (plr));
gotcaps = gst_pad_get_allowed_caps (src);
fail_if (gotcaps == NULL);
fail_unless (gst_caps_is_equal (gotcaps, caps));
ASSERT_CAPS_REFCOUNT (gotcaps, "gotcaps", 1);
gst_caps_unref (gotcaps);
gst_pad_unlink (src, sink);
/* cleanup */
ASSERT_CAPS_REFCOUNT (caps, "caps", 3);
ASSERT_OBJECT_REFCOUNT (src, "src", 1);
ASSERT_OBJECT_REFCOUNT (sink, "sink", 1);
gst_object_unref (src);
gst_object_unref (sink);
ASSERT_CAPS_REFCOUNT (caps, "caps", 1);
gst_caps_unref (caps);
}
GST_END_TEST;
static GstCaps *event_caps = NULL;
static gboolean
sticky_event (GstPad * pad, GstObject * parent, GstEvent * event)
{
GstCaps *caps;
fail_unless (GST_EVENT_TYPE (event) == GST_EVENT_CAPS);
/* Ensure we get here just once: */
fail_unless (event_caps == NULL);
/* The event must arrive before any buffer: */
fail_unless_equals_int (g_list_length (buffers), 0);
gst_event_parse_caps (event, &caps);
event_caps = gst_caps_ref (caps);
gst_event_unref (event);
return TRUE;
}
/* Tests whether caps get properly forwarded when pads
are initially unlinked */
GST_START_TEST (test_sticky_caps_unlinked)
{
GstCaps *caps;
GstPadTemplate *src_template, *sink_template;
GstPad *src, *sink;
GstEvent *event;
caps = gst_caps_from_string ("foo/bar, dummy=(int){1, 2}");
src_template = gst_pad_template_new ("src", GST_PAD_SRC,
GST_PAD_ALWAYS, caps);
sink_template = gst_pad_template_new ("sink", GST_PAD_SINK,
GST_PAD_ALWAYS, caps);
gst_caps_unref (caps);
src = gst_pad_new_from_template (src_template, "src");
fail_if (src == NULL);
sink = gst_pad_new_from_template (sink_template, "sink");
fail_if (sink == NULL);
gst_pad_set_event_function (sink, sticky_event);
gst_pad_set_chain_function (sink, gst_check_chain_func);
gst_object_unref (src_template);
gst_object_unref (sink_template);
caps = gst_caps_from_string ("foo/bar, dummy=(int)1");
ASSERT_CAPS_REFCOUNT (caps, "caps", 1);
event = gst_event_new_caps (caps);
gst_pad_set_active (src, TRUE);
fail_unless (gst_pad_push_event (src, event) == TRUE);
fail_unless (event_caps == NULL);
/* Linking and activating will not forward the sticky event yet... */
fail_unless (GST_PAD_LINK_SUCCESSFUL (gst_pad_link (src, sink)));
gst_pad_set_active (sink, TRUE);
fail_unless (event_caps == NULL);
/* ...but the first buffer will: */
fail_unless (gst_pad_push (src, gst_buffer_new ()) == GST_FLOW_OK);
fail_unless (event_caps == caps);
fail_unless_equals_int (g_list_length (buffers), 1);
gst_caps_replace (&caps, NULL);
gst_caps_replace (&event_caps, NULL);
ASSERT_OBJECT_REFCOUNT (src, "src", 1);
ASSERT_OBJECT_REFCOUNT (sink, "sink", 1);
gst_object_unref (src);
gst_object_unref (sink);
}
GST_END_TEST;
/* Same as test_sticky_caps_unlinked except that the source pad
* has a template of ANY and we will attempt to push
* incompatible caps */
GST_START_TEST (test_sticky_caps_unlinked_incompatible)
{
GstCaps *caps, *failcaps;
GstPadTemplate *src_template, *sink_template;
GstPad *src, *sink;
GstEvent *event;
/* Source pad has ANY caps
* Sink pad has foobar caps
* We will push the pony express caps (which should fail)
*/
caps = gst_caps_new_any ();
src_template = gst_pad_template_new ("src", GST_PAD_SRC,
GST_PAD_ALWAYS, caps);
gst_caps_unref (caps);
caps = gst_caps_from_string ("foo/bar, dummy=(int){1, 2}");
sink_template = gst_pad_template_new ("sink", GST_PAD_SINK,
GST_PAD_ALWAYS, caps);
gst_caps_unref (caps);
src = gst_pad_new_from_template (src_template, "src");
fail_if (src == NULL);
sink = gst_pad_new_from_template (sink_template, "sink");
fail_if (sink == NULL);
gst_pad_set_event_function (sink, sticky_event);
gst_pad_set_chain_function (sink, gst_check_chain_func);
gst_object_unref (src_template);
gst_object_unref (sink_template);
failcaps = gst_caps_from_string ("pony/express, failure=(boolean)true");
ASSERT_CAPS_REFCOUNT (failcaps, "caps", 1);
event = gst_event_new_caps (failcaps);
gst_caps_unref (failcaps);
gst_pad_set_active (src, TRUE);
/* The pad isn't linked yet, and anything matches the source pad template
* (which is ANY) */
fail_unless (gst_pad_push_event (src, event) == TRUE);
fail_unless (event_caps == NULL);
/* Linking and activating will not forward the sticky event yet... */
fail_unless (GST_PAD_LINK_SUCCESSFUL (gst_pad_link (src, sink)));
gst_pad_set_active (sink, TRUE);
fail_unless (event_caps == NULL);
/* ...but the first buffer will and should FAIL since the caps
* are not compatible */
fail_unless (gst_pad_push (src,
gst_buffer_new ()) == GST_FLOW_NOT_NEGOTIATED);
/* We shouldn't have received the caps event since it's incompatible */
fail_unless (event_caps == NULL);
/* We shouldn't have received any buffers since caps are incompatible */
fail_unless_equals_int (g_list_length (buffers), 0);
gst_caps_replace (&event_caps, NULL);
ASSERT_OBJECT_REFCOUNT (src, "src", 1);
ASSERT_OBJECT_REFCOUNT (sink, "sink", 1);
gst_object_unref (src);
gst_object_unref (sink);
}
GST_END_TEST;
/* Like test_sticky_caps_unlinked, but link before caps: */
GST_START_TEST (test_sticky_caps_flushing)
{
GstCaps *caps;
GstPadTemplate *src_template, *sink_template;
GstPad *src, *sink;
GstEvent *event;
caps = gst_caps_from_string ("foo/bar, dummy=(int){1, 2}");
src_template = gst_pad_template_new ("src", GST_PAD_SRC,
GST_PAD_ALWAYS, caps);
sink_template = gst_pad_template_new ("sink", GST_PAD_SINK,
GST_PAD_ALWAYS, caps);
gst_caps_unref (caps);
src = gst_pad_new_from_template (src_template, "src");
fail_if (src == NULL);
sink = gst_pad_new_from_template (sink_template, "sink");
fail_if (sink == NULL);
gst_pad_set_event_function (sink, sticky_event);
gst_pad_set_chain_function (sink, gst_check_chain_func);
gst_object_unref (src_template);
gst_object_unref (sink_template);
fail_unless (GST_PAD_LINK_SUCCESSFUL (gst_pad_link (src, sink)));
caps = gst_caps_from_string ("foo/bar, dummy=(int)1");
ASSERT_CAPS_REFCOUNT (caps, "caps", 1);
event = gst_event_new_caps (caps);
gst_pad_set_active (src, TRUE);
/* The caps event gets accepted by the source pad (and stored) */
fail_unless (gst_pad_push_event (src, event) == TRUE);
/* But wasn't forwarded since the sink pad is flushing (not activated) */
fail_unless (event_caps == NULL);
/* Activating will not forward the sticky event yet... */
gst_pad_set_active (sink, TRUE);
fail_unless (event_caps == NULL);
/* ...but the first buffer will: */
fail_unless (gst_pad_push (src, gst_buffer_new ()) == GST_FLOW_OK);
fail_unless (event_caps == caps);
fail_unless_equals_int (g_list_length (buffers), 1);
gst_caps_replace (&caps, NULL);
gst_caps_replace (&event_caps, NULL);
ASSERT_OBJECT_REFCOUNT (src, "src", 1);
ASSERT_OBJECT_REFCOUNT (sink, "sink", 1);
gst_object_unref (src);
gst_object_unref (sink);
}
GST_END_TEST;
static gboolean
name_is_valid (const gchar * name, GstPadPresence presence)
{
GstPadTemplate *new;
GstCaps *any = gst_caps_new_any ();
new = gst_pad_template_new (name, GST_PAD_SRC, presence, any);
gst_caps_unref (any);
if (new) {
gst_object_unref (GST_OBJECT (new));
return TRUE;
}
return FALSE;
}
GST_START_TEST (test_name_is_valid)
{
gboolean result = FALSE;
fail_unless (name_is_valid ("src", GST_PAD_ALWAYS));
ASSERT_WARNING (name_is_valid ("src%", GST_PAD_ALWAYS));
ASSERT_WARNING (result = name_is_valid ("src%d", GST_PAD_ALWAYS));
fail_if (result);
fail_unless (name_is_valid ("src", GST_PAD_REQUEST));
ASSERT_WARNING (name_is_valid ("src%s%s", GST_PAD_REQUEST));
ASSERT_WARNING (name_is_valid ("src%c", GST_PAD_REQUEST));
ASSERT_WARNING (name_is_valid ("src%", GST_PAD_REQUEST));
ASSERT_WARNING (name_is_valid ("src%dsrc", GST_PAD_REQUEST));
fail_unless (name_is_valid ("src", GST_PAD_SOMETIMES));
fail_unless (name_is_valid ("src%c", GST_PAD_SOMETIMES));
}
GST_END_TEST;
static GstPadProbeReturn
_probe_handler (GstPad * pad, GstPadProbeInfo * info, gpointer userdata)
{
gint ret = GPOINTER_TO_INT (userdata);
if (ret == 1)
return GST_PAD_PROBE_OK;
return GST_PAD_PROBE_DROP;
}
GST_START_TEST (test_push_unlinked)
{
GstPad *src;
GstCaps *caps;
GstBuffer *buffer;
gulong id;
src = gst_pad_new ("src", GST_PAD_SRC);
fail_if (src == NULL);
caps = gst_pad_get_allowed_caps (src);
fail_unless (caps == NULL);
caps = gst_caps_from_string ("foo/bar");
/* pushing on an inactive pad will return wrong state */
GST_DEBUG ("push buffer inactive");
buffer = gst_buffer_new ();
gst_buffer_ref (buffer);
fail_unless (gst_pad_push (src, buffer) == GST_FLOW_FLUSHING);
ASSERT_MINI_OBJECT_REFCOUNT (buffer, "buffer", 1);
gst_buffer_unref (buffer);
gst_pad_set_active (src, TRUE);
GST_DEBUG ("push caps event inactive");
gst_pad_set_caps (src, caps);
ASSERT_CAPS_REFCOUNT (caps, "caps", 2);
/* pushing on an unlinked pad will drop the buffer */
GST_DEBUG ("push buffer unlinked");
buffer = gst_buffer_new ();
gst_buffer_ref (buffer);
fail_unless (gst_pad_push (src, buffer) == GST_FLOW_NOT_LINKED);
ASSERT_MINI_OBJECT_REFCOUNT (buffer, "buffer", 1);
gst_buffer_unref (buffer);
/* adding a probe that returns _DROP will drop the buffer without trying
* to chain */
GST_DEBUG ("push buffer drop");
id = gst_pad_add_probe (src, GST_PAD_PROBE_TYPE_BUFFER,
_probe_handler, GINT_TO_POINTER (0), NULL);
buffer = gst_buffer_new ();
gst_buffer_ref (buffer);
fail_unless (gst_pad_push (src, buffer) == GST_FLOW_OK);
ASSERT_MINI_OBJECT_REFCOUNT (buffer, "buffer", 1);
gst_buffer_unref (buffer);
gst_pad_remove_probe (src, id);
/* adding a probe that returns _OK will still chain the buffer,
* and hence drop because pad is unlinked */
GST_DEBUG ("push buffer ok");
id = gst_pad_add_probe (src, GST_PAD_PROBE_TYPE_BUFFER,
_probe_handler, GINT_TO_POINTER (1), NULL);
buffer = gst_buffer_new ();
gst_buffer_ref (buffer);
fail_unless (gst_pad_push (src, buffer) == GST_FLOW_NOT_LINKED);
ASSERT_MINI_OBJECT_REFCOUNT (buffer, "buffer", 1);
gst_buffer_unref (buffer);
gst_pad_remove_probe (src, id);
/* cleanup */
ASSERT_CAPS_REFCOUNT (caps, "caps", 2);
ASSERT_OBJECT_REFCOUNT (src, "src", 1);
gst_object_unref (src);
ASSERT_CAPS_REFCOUNT (caps, "caps", 1);
gst_caps_unref (caps);
}
GST_END_TEST;
GST_START_TEST (test_push_linked)
{
GstPad *src, *sink;
GstPadLinkReturn plr;
GstCaps *caps;
GstBuffer *buffer;
gulong id;
/* setup */
sink = gst_pad_new ("sink", GST_PAD_SINK);
fail_if (sink == NULL);
gst_pad_set_chain_function (sink, gst_check_chain_func);
src = gst_pad_new ("src", GST_PAD_SRC);
fail_if (src == NULL);
caps = gst_caps_from_string ("foo/bar");
/* one for me */
ASSERT_CAPS_REFCOUNT (caps, "caps", 1);
gst_pad_set_active (src, TRUE);
gst_pad_set_caps (src, caps);
gst_pad_set_active (sink, TRUE);
gst_pad_set_caps (sink, caps);
/* one for me and one for each set_caps */
ASSERT_CAPS_REFCOUNT (caps, "caps", 3);
plr = gst_pad_link (src, sink);
fail_unless (GST_PAD_LINK_SUCCESSFUL (plr));
ASSERT_CAPS_REFCOUNT (caps, "caps", 3);
buffer = gst_buffer_new ();
/* test */
/* pushing on a linked pad will drop the ref to the buffer */
gst_buffer_ref (buffer);
fail_unless (gst_pad_push (src, buffer) == GST_FLOW_OK);
ASSERT_MINI_OBJECT_REFCOUNT (buffer, "buffer", 2);
gst_buffer_unref (buffer);
fail_unless_equals_int (g_list_length (buffers), 1);
buffer = GST_BUFFER (buffers->data);
ASSERT_MINI_OBJECT_REFCOUNT (buffer, "buffer", 1);
gst_buffer_unref (buffer);
g_list_free (buffers);
buffers = NULL;
/* adding a probe that returns FALSE will drop the buffer without trying
* to chain */
id = gst_pad_add_probe (src, GST_PAD_PROBE_TYPE_BUFFER,
_probe_handler, GINT_TO_POINTER (0), NULL);
buffer = gst_buffer_new ();
gst_buffer_ref (buffer);
fail_unless (gst_pad_push (src, buffer) == GST_FLOW_OK);
ASSERT_MINI_OBJECT_REFCOUNT (buffer, "buffer", 1);
gst_buffer_unref (buffer);
gst_pad_remove_probe (src, id);
fail_unless_equals_int (g_list_length (buffers), 0);
/* adding a probe that returns TRUE will still chain the buffer */
id = gst_pad_add_probe (src, GST_PAD_PROBE_TYPE_BUFFER,
_probe_handler, GINT_TO_POINTER (1), NULL);
buffer = gst_buffer_new ();
gst_buffer_ref (buffer);
fail_unless (gst_pad_push (src, buffer) == GST_FLOW_OK);
gst_pad_remove_probe (src, id);
ASSERT_MINI_OBJECT_REFCOUNT (buffer, "buffer", 2);
gst_buffer_unref (buffer);
fail_unless_equals_int (g_list_length (buffers), 1);
buffer = GST_BUFFER (buffers->data);
ASSERT_MINI_OBJECT_REFCOUNT (buffer, "buffer", 1);
gst_buffer_unref (buffer);
g_list_free (buffers);
buffers = NULL;
/* teardown */
gst_pad_unlink (src, sink);
ASSERT_CAPS_REFCOUNT (caps, "caps", 2);
gst_object_unref (src);
gst_object_unref (sink);
ASSERT_CAPS_REFCOUNT (caps, "caps", 1);
gst_caps_unref (caps);
}
GST_END_TEST;
GST_START_TEST (test_push_linked_flushing)
{
GstPad *src, *sink;
GstCaps *caps;
GstPadLinkReturn plr;
GstBuffer *buffer;
gulong id;
/* setup */
src = gst_pad_new ("src", GST_PAD_SRC);
fail_if (src == NULL);
sink = gst_pad_new ("sink", GST_PAD_SINK);
fail_if (sink == NULL);
gst_pad_set_chain_function (sink, gst_check_chain_func);
caps = gst_pad_get_allowed_caps (src);
fail_unless (caps == NULL);
caps = gst_pad_get_allowed_caps (sink);
fail_unless (caps == NULL);
caps = gst_caps_from_string ("foo/bar");
/* one for me */
ASSERT_CAPS_REFCOUNT (caps, "caps", 1);
gst_pad_set_active (src, TRUE);
gst_pad_set_caps (src, caps);
/* need to activate to make it accept the caps */
gst_pad_set_active (sink, TRUE);
gst_pad_set_caps (sink, caps);
/* one for me and one for each set_caps */
ASSERT_CAPS_REFCOUNT (caps, "caps", 3);
plr = gst_pad_link (src, sink);
fail_unless (GST_PAD_LINK_SUCCESSFUL (plr));
ASSERT_CAPS_REFCOUNT (caps, "caps", 3);
/* not activating the pads here, which keeps them flushing */
gst_pad_set_active (src, FALSE);
gst_pad_set_active (sink, FALSE);
/* pushing on a flushing pad will drop the buffer */
buffer = gst_buffer_new ();
gst_buffer_ref (buffer);
fail_unless (gst_pad_push (src, buffer) == GST_FLOW_FLUSHING);
ASSERT_MINI_OBJECT_REFCOUNT (buffer, "buffer", 1);
fail_unless_equals_int (g_list_length (buffers), 0);
gst_buffer_unref (buffer);
gst_pad_set_active (src, TRUE);
gst_pad_set_active (sink, FALSE);
/* adding a probe that returns FALSE will drop the buffer without trying
* to chain */
id = gst_pad_add_probe (src, GST_PAD_PROBE_TYPE_BUFFER, _probe_handler,
GINT_TO_POINTER (0), NULL);
buffer = gst_buffer_new ();
gst_buffer_ref (buffer);
fail_unless (gst_pad_push (src, buffer) == GST_FLOW_OK);
ASSERT_MINI_OBJECT_REFCOUNT (buffer, "buffer", 1);
fail_unless_equals_int (g_list_length (buffers), 0);
gst_buffer_unref (buffer);
gst_pad_remove_probe (src, id);
/* adding a probe that returns TRUE will still chain the buffer,
* and hence drop because pad is flushing */
id = gst_pad_add_probe (src, GST_PAD_PROBE_TYPE_BUFFER, _probe_handler,
GINT_TO_POINTER (1), NULL);
buffer = gst_buffer_new ();
gst_buffer_ref (buffer);
fail_unless (gst_pad_push (src, buffer) == GST_FLOW_FLUSHING);
ASSERT_MINI_OBJECT_REFCOUNT (buffer, "buffer", 1);
fail_unless_equals_int (g_list_length (buffers), 0);
gst_buffer_unref (buffer);
gst_pad_remove_probe (src, id);
/* cleanup */
ASSERT_CAPS_REFCOUNT (caps, "caps", 1);
ASSERT_OBJECT_REFCOUNT (src, "src", 1);
gst_pad_link (src, sink);
gst_object_unref (src);
gst_object_unref (sink);
ASSERT_CAPS_REFCOUNT (caps, "caps", 1);
gst_caps_unref (caps);
}
GST_END_TEST;
static GstBuffer *
buffer_from_string (const gchar * str)
{
guint size;
GstBuffer *buf;
size = strlen (str);
buf = gst_buffer_new_and_alloc (size);
gst_buffer_fill (buf, 0, str, size);
return buf;
}
static gboolean
buffer_compare (GstBuffer * buf, const gchar * str, gsize size)
{
gboolean res;
GstMapInfo info;
fail_unless (gst_buffer_map (buf, &info, GST_MAP_READ));
res = memcmp (info.data, str, size) == 0;
GST_DEBUG ("%s <-> %s: %d", (gchar *) info.data, str, res);
gst_buffer_unmap (buf, &info);
return res;
}
GST_START_TEST (test_push_buffer_list_compat)
{
GstPad *src, *sink;
GstPadLinkReturn plr;
GstCaps *caps;
GstBufferList *list;
GstBuffer *buffer;
/* setup */
sink = gst_pad_new ("sink", GST_PAD_SINK);
fail_if (sink == NULL);
gst_pad_set_chain_function (sink, gst_check_chain_func);
/* leave chainlistfunc unset */
src = gst_pad_new ("src", GST_PAD_SRC);
fail_if (src == NULL);
caps = gst_caps_from_string ("foo/bar");
gst_pad_set_active (src, TRUE);
gst_pad_set_caps (src, caps);
gst_pad_set_active (sink, TRUE);
gst_pad_set_caps (sink, caps);
plr = gst_pad_link (src, sink);
fail_unless (GST_PAD_LINK_SUCCESSFUL (plr));
list = gst_buffer_list_new ();
/* test */
/* adding to a buffer list will drop the ref to the buffer */
gst_buffer_list_add (list, buffer_from_string ("ListGroup"));
gst_buffer_list_add (list, buffer_from_string ("AnotherListGroup"));
fail_unless (gst_pad_push_list (src, list) == GST_FLOW_OK);
fail_unless_equals_int (g_list_length (buffers), 2);
buffer = GST_BUFFER (buffers->data);
ASSERT_MINI_OBJECT_REFCOUNT (buffer, "buffer", 1);
fail_unless (buffer_compare (buffer, "ListGroup", 9));
gst_buffer_unref (buffer);
buffers = g_list_delete_link (buffers, buffers);
buffer = GST_BUFFER (buffers->data);
ASSERT_MINI_OBJECT_REFCOUNT (buffer, "buffer", 1);
fail_unless (buffer_compare (buffer, "AnotherListGroup", 16));
gst_buffer_unref (buffer);
buffers = g_list_delete_link (buffers, buffers);
fail_unless (buffers == NULL);
/* teardown */
gst_pad_unlink (src, sink);
gst_object_unref (src);
gst_object_unref (sink);
ASSERT_CAPS_REFCOUNT (caps, "caps", 1);
gst_caps_unref (caps);
}
GST_END_TEST;
GST_START_TEST (test_flowreturn)
{
GstFlowReturn ret;
GQuark quark;
/* test some of the macros */
ret = GST_FLOW_EOS;
fail_if (strcmp (gst_flow_get_name (ret), "eos"));
quark = gst_flow_to_quark (ret);
fail_if (strcmp (g_quark_to_string (quark), "eos"));
/* custom returns */
ret = GST_FLOW_CUSTOM_SUCCESS;
fail_if (strcmp (gst_flow_get_name (ret), "custom-success"));
quark = gst_flow_to_quark (ret);
fail_if (strcmp (g_quark_to_string (quark), "custom-success"));
ret = GST_FLOW_CUSTOM_ERROR;
fail_if (strcmp (gst_flow_get_name (ret), "custom-error"));
quark = gst_flow_to_quark (ret);
fail_if (strcmp (g_quark_to_string (quark), "custom-error"));
/* custom returns clamping */
ret = GST_FLOW_CUSTOM_SUCCESS + 2;
fail_if (strcmp (gst_flow_get_name (ret), "custom-success"));
quark = gst_flow_to_quark (ret);
fail_if (strcmp (g_quark_to_string (quark), "custom-success"));
ret = GST_FLOW_CUSTOM_ERROR - 2;
fail_if (strcmp (gst_flow_get_name (ret), "custom-error"));
quark = gst_flow_to_quark (ret);
fail_if (strcmp (g_quark_to_string (quark), "custom-error"));
/* unknown values */
ret = GST_FLOW_CUSTOM_ERROR + 2;
fail_if (strcmp (gst_flow_get_name (ret), "unknown"));
quark = gst_flow_to_quark (ret);
fail_unless (quark == 0);
}
GST_END_TEST;
GST_START_TEST (test_push_negotiation)
{
GstPad *src, *sink;
GstPadLinkReturn plr;
GstCaps *srccaps =
gst_caps_from_string ("audio/x-raw,width={16,32},depth={16,32}");
GstCaps *sinkcaps =
gst_caps_from_string ("audio/x-raw,width=32,depth={16,32}");
GstPadTemplate *src_template;
GstPadTemplate *sink_template;
GstCaps *caps;
/* setup */
src_template = gst_pad_template_new ("src", GST_PAD_SRC,
GST_PAD_ALWAYS, srccaps);
sink_template = gst_pad_template_new ("sink", GST_PAD_SINK,
GST_PAD_ALWAYS, sinkcaps);
gst_caps_unref (srccaps);
gst_caps_unref (sinkcaps);
sink = gst_pad_new_from_template (sink_template, "sink");
fail_if (sink == NULL);
gst_pad_set_chain_function (sink, gst_check_chain_func);
src = gst_pad_new_from_template (src_template, "src");
fail_if (src == NULL);
plr = gst_pad_link (src, sink);
fail_unless (GST_PAD_LINK_SUCCESSFUL (plr));
/* activate pads */
gst_pad_set_active (src, TRUE);
gst_pad_set_active (sink, TRUE);
caps = gst_caps_from_string ("audio/x-raw,width=16,depth=16");
/* Should fail if src pad caps are incompatible with sink pad caps */
gst_pad_set_caps (src, caps);
fail_unless (gst_pad_set_caps (sink, caps) == FALSE);
/* teardown */
gst_pad_unlink (src, sink);
gst_object_unref (src);
gst_object_unref (sink);
gst_caps_unref (caps);
gst_object_unref (sink_template);
gst_object_unref (src_template);
}
GST_END_TEST;
/* see that an unref also unlinks the pads */
GST_START_TEST (test_src_unref_unlink)
{
GstPad *src, *sink;
GstCaps *caps;
GstPadLinkReturn plr;
sink = gst_pad_new ("sink", GST_PAD_SINK);
fail_if (sink == NULL);
src = gst_pad_new ("src", GST_PAD_SRC);
fail_if (src == NULL);
caps = gst_caps_from_string ("foo/bar");
gst_pad_set_active (src, TRUE);
gst_pad_set_caps (src, caps);
gst_pad_set_active (sink, TRUE);
gst_pad_set_caps (sink, caps);
plr = gst_pad_link (src, sink);
fail_unless (GST_PAD_LINK_SUCCESSFUL (plr));
/* unref the srcpad */
gst_object_unref (src);
/* sink should be unlinked now */
fail_if (gst_pad_is_linked (sink));
/* cleanup */
gst_object_unref (sink);
gst_caps_unref (caps);
}
GST_END_TEST;
/* see that an unref also unlinks the pads */
GST_START_TEST (test_sink_unref_unlink)
{
GstPad *src, *sink;
GstCaps *caps;
GstPadLinkReturn plr;
sink = gst_pad_new ("sink", GST_PAD_SINK);
fail_if (sink == NULL);
src = gst_pad_new ("src", GST_PAD_SRC);
fail_if (src == NULL);
caps = gst_caps_from_string ("foo/bar");
gst_pad_set_active (src, TRUE);
gst_pad_set_caps (src, caps);
gst_pad_set_active (sink, TRUE);
gst_pad_set_caps (sink, caps);
plr = gst_pad_link (src, sink);
fail_unless (GST_PAD_LINK_SUCCESSFUL (plr));
/* unref the sinkpad */
gst_object_unref (sink);
/* src should be unlinked now */
fail_if (gst_pad_is_linked (src));
/* cleanup */
gst_object_unref (src);
gst_caps_unref (caps);
}
GST_END_TEST;
static gulong id;
static GstPadProbeReturn
block_async_cb (GstPad * pad, GstPadProbeInfo * info, gpointer user_data)
{
gboolean *bool_user_data = (gboolean *) user_data;
fail_unless ((info->type & GST_PAD_PROBE_TYPE_BLOCK) != 0);
/* here we should have blocked == 0 unblocked == 0 */
fail_unless (bool_user_data[0] == FALSE);
fail_unless (bool_user_data[1] == FALSE);
bool_user_data[0] = TRUE;
gst_pad_remove_probe (pad, id);
bool_user_data[1] = TRUE;
return GST_PAD_PROBE_OK;
}
GST_START_TEST (test_block_async)
{
GstPad *pad;
/* we set data[0] = TRUE when the pad is blocked, data[1] = TRUE when it's
* unblocked */
gboolean data[2] = { FALSE, FALSE };
pad = gst_pad_new ("src", GST_PAD_SRC);
fail_unless (pad != NULL);
gst_pad_set_active (pad, TRUE);
id = gst_pad_add_probe (pad, GST_PAD_PROBE_TYPE_BLOCK, block_async_cb, &data,
NULL);
fail_unless (data[0] == FALSE);
fail_unless (data[1] == FALSE);
gst_pad_push (pad, gst_buffer_new ());
gst_object_unref (pad);
}
GST_END_TEST;
static GstPadProbeReturn
block_async_cb_return_ok (GstPad * pad, GstPadProbeInfo * info,
gpointer user_data)
{
return GST_PAD_PROBE_OK;
}
static gpointer
push_buffer_async (GstPad * pad)
{
return GINT_TO_POINTER (gst_pad_push (pad, gst_buffer_new ()));
}
static void
test_pad_blocking_with_type (GstPadProbeType type)
{
GstPad *pad;
GThread *thread;
GstFlowReturn ret;
pad = gst_pad_new ("src", GST_PAD_SRC);
fail_unless (pad != NULL);
gst_pad_set_active (pad, TRUE);
id = gst_pad_add_probe (pad, type, block_async_cb_return_ok, NULL, NULL);
thread = g_thread_create ((GThreadFunc) push_buffer_async, pad, TRUE, NULL);
/* wait for the block */
while (!gst_pad_is_blocking (pad)) {
g_usleep (100000);
}
/* stop with flushing */
gst_pad_push_event (pad, gst_event_new_flush_start ());
/* get return value from push */
ret = GPOINTER_TO_INT (g_thread_join (thread));
/* unflush now */
gst_pad_push_event (pad, gst_event_new_flush_stop (FALSE));
/* must be wrong state */
fail_unless (ret == GST_FLOW_FLUSHING);
gst_object_unref (pad);
}
GST_START_TEST (test_pad_blocking_with_probe_type_block)
{
test_pad_blocking_with_type (GST_PAD_PROBE_TYPE_BLOCK);
}
GST_END_TEST;
GST_START_TEST (test_pad_blocking_with_probe_type_blocking)
{
test_pad_blocking_with_type (GST_PAD_PROBE_TYPE_BLOCKING);
}
GST_END_TEST;
static gboolean got_notify;
static void
caps_notify (GstPad * pad, GParamSpec * spec, gpointer data)
{
got_notify = TRUE;
}
static void
test_queue_src_caps_notify (gboolean link_queue)
{
GstElement *queue;
GstPad *src, *sink, *another_pad;
queue = gst_element_factory_make ("queue", NULL);
fail_unless (queue != NULL);
src = gst_element_get_static_pad (queue, "src");
fail_unless (src != NULL);
sink = gst_element_get_static_pad (queue, "sink");
fail_unless (sink != NULL);
if (link_queue) {
another_pad = gst_pad_new ("sink", GST_PAD_SINK);
fail_unless (another_pad != NULL);
gst_pad_set_active (another_pad, TRUE);
gst_pad_link_full (src, another_pad, GST_PAD_LINK_CHECK_NOTHING);
} else {
another_pad = NULL;
}
gst_element_set_state (queue, GST_STATE_PLAYING);
got_notify = FALSE;
g_signal_connect (src, "notify::caps", G_CALLBACK (caps_notify), NULL);
gst_pad_send_event (sink, gst_event_new_caps (gst_caps_from_string ("caps")));
g_usleep (10000);
fail_unless (got_notify == TRUE);
gst_element_set_state (queue, GST_STATE_NULL);
gst_object_unref (src);
gst_object_unref (sink);
gst_object_unref (queue);
if (another_pad) {
gst_object_unref (another_pad);
}
}
GST_START_TEST (test_queue_src_caps_notify_linked)
{
test_queue_src_caps_notify (TRUE);
}
GST_END_TEST
GST_START_TEST (test_queue_src_caps_notify_not_linked)
{
/* This test will fail because queue doesn't set the caps
on src pad unless it is linked */
test_queue_src_caps_notify (FALSE);
}
GST_END_TEST;
#if 0
static void
block_async_second (GstPad * pad, gboolean blocked, gpointer user_data)
{
gst_pad_set_blocked (pad, FALSE, unblock_async_cb, NULL, NULL);
}
static void
block_async_first (GstPad * pad, gboolean blocked, gpointer user_data)
{
static int n_calls = 0;
gboolean *bool_user_data = (gboolean *) user_data;
if (++n_calls > 1)
/* we expect this callback to be called only once */
g_warn_if_reached ();
*bool_user_data = blocked;
/* replace block_async_first with block_async_second so next time the pad is
* blocked the latter should be called */
gst_pad_set_blocked (pad, TRUE, block_async_second, NULL, NULL);
/* unblock temporarily, in the next push block_async_second should be called
*/
gst_pad_push_event (pad, gst_event_new_flush_start ());
}
GST_START_TEST (test_block_async_replace_callback)
{
GstPad *pad;
gboolean blocked;
pad = gst_pad_new ("src", GST_PAD_SRC);
fail_unless (pad != NULL);
gst_pad_set_active (pad, TRUE);
gst_pad_set_blocked (pad, TRUE, block_async_first, &blocked, NULL);
blocked = FALSE;
gst_pad_push (pad, gst_buffer_new ());
fail_unless (blocked == TRUE);
/* block_async_first flushes to unblock */
gst_pad_push_event (pad, gst_event_new_flush_stop ());
/* push again, this time block_async_second should be called */
gst_pad_push (pad, gst_buffer_new ());
fail_unless (blocked == TRUE);
gst_object_unref (pad);
}
GST_END_TEST;
#endif
static void
block_async_full_destroy (gpointer user_data)
{
gint *state = (gint *) user_data;
fail_unless (*state < 2);
GST_DEBUG ("setting state to 2");
*state = 2;
}
static GstPadProbeReturn
block_async_full_cb (GstPad * pad, GstPadProbeInfo * info, gpointer user_data)
{
*(gint *) user_data = (gint) TRUE;
gst_pad_push_event (pad, gst_event_new_flush_start ());
GST_DEBUG ("setting state to 1");
return GST_PAD_PROBE_OK;
}
GST_START_TEST (test_block_async_full_destroy)
{
GstPad *pad;
/* 0 = unblocked, 1 = blocked, 2 = destroyed */
gint state = 0;
gulong id;
pad = gst_pad_new ("src", GST_PAD_SRC);
fail_unless (pad != NULL);
gst_pad_set_active (pad, TRUE);
id = gst_pad_add_probe (pad, GST_PAD_PROBE_TYPE_BLOCK, block_async_full_cb,
&state, block_async_full_destroy);
fail_unless (state == 0);
gst_pad_push (pad, gst_buffer_new ());
/* block_async_full_cb sets state to 1 and then flushes to unblock temporarily
*/
fail_unless (state == 1);
gst_pad_push_event (pad, gst_event_new_flush_stop (TRUE));
/* unblock callback is called */
gst_pad_remove_probe (pad, id);
fail_unless (state == 2);
gst_object_unref (pad);
}
GST_END_TEST;
GST_START_TEST (test_block_async_full_destroy_dispose)
{
GstPad *pad;
/* 0 = unblocked, 1 = blocked, 2 = destroyed */
gint state = 0;
pad = gst_pad_new ("src", GST_PAD_SRC);
fail_unless (pad != NULL);
gst_pad_set_active (pad, TRUE);
(void) gst_pad_add_probe (pad, GST_PAD_PROBE_TYPE_BLOCK, block_async_full_cb,
&state, block_async_full_destroy);
gst_pad_push (pad, gst_buffer_new ());
/* block_async_full_cb sets state to 1 and then flushes to unblock temporarily
*/
fail_unless_equals_int (state, 1);
gst_pad_push_event (pad, gst_event_new_flush_stop (TRUE));
/* gst_BLOCK calls the destroy_notify function if necessary */
gst_object_unref (pad);
fail_unless_equals_int (state, 2);
}
GST_END_TEST;
#if 0
static void
unblock_async_no_flush_cb (GstPad * pad, gboolean blocked, gpointer user_data)
{
gboolean *bool_user_data = (gboolean *) user_data;
/* here we should have blocked == 1 unblocked == 0 */
fail_unless (blocked == FALSE);
fail_unless (bool_user_data[0] == TRUE);
fail_unless (bool_user_data[1] == TRUE);
fail_unless (bool_user_data[2] == FALSE);
bool_user_data[2] = TRUE;
}
#endif
#if 0
static void
unblock_async_not_called (GstPad * pad, gboolean blocked, gpointer user_data)
{
g_warn_if_reached ();
}
#endif
static GstPadProbeReturn
block_async_second_no_flush (GstPad * pad, GstPadProbeInfo * info,
gpointer user_data)
{
gboolean *bool_user_data = (gboolean *) user_data;
GST_DEBUG ("second probe called");
fail_unless (info->type & GST_PAD_PROBE_TYPE_BLOCK);
fail_unless (bool_user_data[0] == TRUE);
fail_unless (bool_user_data[1] == FALSE);
fail_unless (bool_user_data[2] == FALSE);
bool_user_data[1] = TRUE;
GST_DEBUG ("removing second probe with id %lu", id);
gst_pad_remove_probe (pad, id);
return GST_PAD_PROBE_OK;
}
static GstPadProbeReturn
block_async_first_no_flush (GstPad * pad, GstPadProbeInfo * info,
gpointer user_data)
{
static int n_calls = 0;
gboolean *bool_user_data = (gboolean *) user_data;
fail_unless (info->type & GST_PAD_PROBE_TYPE_BLOCK);
GST_DEBUG ("first probe called");
if (++n_calls > 1)
/* we expect this callback to be called only once */
g_warn_if_reached ();
*bool_user_data = TRUE;
fail_unless (bool_user_data[0] == TRUE);
fail_unless (bool_user_data[1] == FALSE);
fail_unless (bool_user_data[2] == FALSE);
GST_DEBUG ("removing first probe with id %lu", id);
gst_pad_remove_probe (pad, id);
GST_DEBUG ("adding second probe");
/* replace block_async_first with block_async_second so next time the pad is
* blocked the latter should be called */
id = gst_pad_add_probe (pad, GST_PAD_PROBE_TYPE_BLOCK,
block_async_second_no_flush, user_data, NULL);
GST_DEBUG ("added probe with id %lu", id);
return GST_PAD_PROBE_OK;
}
GST_START_TEST (test_block_async_replace_callback_no_flush)
{
GstPad *pad;
gboolean bool_user_data[3] = { FALSE, FALSE, FALSE };
pad = gst_pad_new ("src", GST_PAD_SRC);
fail_unless (pad != NULL);
gst_pad_set_active (pad, TRUE);
GST_DEBUG ("adding probe");
id = gst_pad_add_probe (pad, GST_PAD_PROBE_TYPE_BLOCK,
block_async_first_no_flush, bool_user_data, NULL);
GST_DEBUG ("added probe with id %lu", id);
fail_if (id == 0);
GST_DEBUG ("pushing buffer");
gst_pad_push (pad, gst_buffer_new ());
fail_unless (bool_user_data[0] == TRUE);
fail_unless (bool_user_data[1] == TRUE);
fail_unless (bool_user_data[2] == FALSE);
gst_object_unref (pad);
}
GST_END_TEST;
static gint sticky_count;
static gboolean
test_sticky_events_handler (GstPad * pad, GstObject * parent, GstEvent * event)
{
GST_DEBUG_OBJECT (pad, "received event %" GST_PTR_FORMAT, event);
switch (sticky_count) {
case 0:
fail_unless (GST_EVENT_TYPE (event) == GST_EVENT_STREAM_START);
break;
case 1:
{
GstCaps *caps;
GstStructure *s;
fail_unless (GST_EVENT_TYPE (event) == GST_EVENT_CAPS);
gst_event_parse_caps (event, &caps);
fail_unless (gst_caps_get_size (caps) == 1);
s = gst_caps_get_structure (caps, 0);
fail_unless (gst_structure_has_name (s, "foo/baz"));
break;
}
case 2:
fail_unless (GST_EVENT_TYPE (event) == GST_EVENT_SEGMENT);
break;
default:
fail_unless (FALSE);
break;
}
gst_event_unref (event);
sticky_count++;
return TRUE;
}
GST_START_TEST (test_sticky_events)
{
GstPad *srcpad, *sinkpad;
GstCaps *caps;
GstSegment seg;
/* make unlinked srcpad */
srcpad = gst_pad_new ("src", GST_PAD_SRC);
fail_unless (srcpad != NULL);
gst_pad_set_active (srcpad, TRUE);
/* push an event, it should be sticky on the srcpad */
gst_pad_push_event (srcpad, gst_event_new_stream_start ());
/* make a caps event */
caps = gst_caps_new_empty_simple ("foo/bar");
gst_pad_push_event (srcpad, gst_event_new_caps (caps));
gst_caps_unref (caps);
/* make segment event */
gst_segment_init (&seg, GST_FORMAT_TIME);
gst_pad_push_event (srcpad, gst_event_new_segment (&seg));
/* now make a sinkpad */
sinkpad = gst_pad_new ("sink", GST_PAD_SINK);
fail_unless (sinkpad != NULL);
sticky_count = 0;
gst_pad_set_event_function (sinkpad, test_sticky_events_handler);
fail_unless (sticky_count == 0);
gst_pad_set_active (sinkpad, TRUE);
/* link the pads */
gst_pad_link (srcpad, sinkpad);
/* should not trigger events */
fail_unless (sticky_count == 0);
/* caps replaces old caps event at position 2, the pushes all
* pending events */
caps = gst_caps_new_empty_simple ("foo/baz");
gst_pad_push_event (srcpad, gst_event_new_caps (caps));
gst_caps_unref (caps);
/* should have triggered 2 events */
fail_unless (sticky_count == 3);
gst_object_unref (srcpad);
gst_object_unref (sinkpad);
}
GST_END_TEST;
static Suite *
gst_pad_suite (void)
{
Suite *s = suite_create ("GstPad");
TCase *tc_chain = tcase_create ("general");
/* turn off timeout */
tcase_set_timeout (tc_chain, 60);
suite_add_tcase (s, tc_chain);
tcase_add_test (tc_chain, test_link);
tcase_add_test (tc_chain, test_refcount);
tcase_add_test (tc_chain, test_get_allowed_caps);
tcase_add_test (tc_chain, test_sticky_caps_unlinked);
tcase_add_test (tc_chain, test_sticky_caps_unlinked_incompatible);
tcase_add_test (tc_chain, test_sticky_caps_flushing);
tcase_add_test (tc_chain, test_link_unlink_threaded);
tcase_add_test (tc_chain, test_name_is_valid);
tcase_add_test (tc_chain, test_push_unlinked);
tcase_add_test (tc_chain, test_push_linked);
tcase_add_test (tc_chain, test_push_linked_flushing);
tcase_add_test (tc_chain, test_push_buffer_list_compat);
tcase_add_test (tc_chain, test_flowreturn);
tcase_add_test (tc_chain, test_push_negotiation);
tcase_add_test (tc_chain, test_src_unref_unlink);
tcase_add_test (tc_chain, test_sink_unref_unlink);
tcase_add_test (tc_chain, test_block_async);
tcase_add_test (tc_chain, test_pad_blocking_with_probe_type_block);
tcase_add_test (tc_chain, test_pad_blocking_with_probe_type_blocking);
tcase_add_test (tc_chain, test_queue_src_caps_notify_linked);
tcase_add_test (tc_chain, test_queue_src_caps_notify_not_linked);
#if 0
tcase_add_test (tc_chain, test_block_async_replace_callback);
#endif
tcase_add_test (tc_chain, test_block_async_full_destroy);
tcase_add_test (tc_chain, test_block_async_full_destroy_dispose);
tcase_add_test (tc_chain, test_block_async_replace_callback_no_flush);
tcase_add_test (tc_chain, test_sticky_events);
return s;
}
GST_CHECK_MAIN (gst_pad);