docs/design/part-qos.txt: Fix typo.
[platform/upstream/gstreamer.git] / tests / check / gst / gstpad.c
1 /* GStreamer
2  * Copyright (C) <2005> Thomas Vander Stichele <thomas at apestaart dot org>
3  *
4  * gstpad.c: Unit test for GstPad
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Library General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Library General Public License for more details.
15  *
16  * You should have received a copy of the GNU Library General Public
17  * License along with this library; if not, write to the
18  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19  * Boston, MA 02111-1307, USA.
20  */
21
22 #include <gst/check/gstcheck.h>
23
24 GST_START_TEST (test_link)
25 {
26   GstPad *src, *sink;
27   GstPadTemplate *srct;
28
29   GstPadLinkReturn ret;
30   gchar *name;
31
32   src = gst_pad_new ("source", GST_PAD_SRC);
33   fail_if (src == NULL);
34   ASSERT_OBJECT_REFCOUNT (src, "source pad", 1);
35
36   name = gst_pad_get_name (src);
37   fail_unless (strcmp (name, "source") == 0);
38   ASSERT_OBJECT_REFCOUNT (src, "source pad", 1);
39   g_free (name);
40
41   sink = gst_pad_new ("sink", GST_PAD_SINK);
42   fail_if (sink == NULL);
43
44   /* linking without templates or caps should fail */
45   ret = gst_pad_link (src, sink);
46   ASSERT_OBJECT_REFCOUNT (src, "source pad", 1);
47   ASSERT_OBJECT_REFCOUNT (sink, "sink pad", 1);
48   fail_unless (ret == GST_PAD_LINK_NOFORMAT);
49
50   ASSERT_CRITICAL (gst_pad_get_pad_template (NULL));
51
52   srct = gst_pad_get_pad_template (src);
53   fail_unless (srct == NULL);
54   ASSERT_OBJECT_REFCOUNT (src, "source pad", 1);
55
56   /* clean up */
57   ASSERT_OBJECT_REFCOUNT (src, "source pad", 1);
58   gst_object_unref (src);
59   gst_object_unref (sink);
60 }
61
62 GST_END_TEST;
63
64 /* threaded link/unlink */
65 /* use globals */
66 GstPad *src, *sink;
67
68 void
69 thread_link_unlink (gpointer data)
70 {
71   THREAD_START ();
72
73   while (THREAD_TEST_RUNNING ()) {
74     gst_pad_link (src, sink);
75     gst_pad_unlink (src, sink);
76     THREAD_SWITCH ();
77   }
78 }
79
80 GST_START_TEST (test_link_unlink_threaded)
81 {
82   GstCaps *caps;
83   int i;
84
85   src = gst_pad_new ("source", GST_PAD_SRC);
86   fail_if (src == NULL);
87   sink = gst_pad_new ("sink", GST_PAD_SINK);
88   fail_if (sink == NULL);
89
90   caps = gst_caps_from_string ("foo/bar");
91   gst_pad_set_caps (src, caps);
92   gst_pad_set_caps (sink, caps);
93   ASSERT_CAPS_REFCOUNT (caps, "caps", 3);
94
95   MAIN_START_THREADS (5, thread_link_unlink, NULL);
96   for (i = 0; i < 1000; ++i) {
97     gst_pad_is_linked (src);
98     gst_pad_is_linked (sink);
99     THREAD_SWITCH ();
100   }
101   MAIN_STOP_THREADS ();
102
103   ASSERT_CAPS_REFCOUNT (caps, "caps", 3);
104   gst_caps_unref (caps);
105
106   ASSERT_CAPS_REFCOUNT (caps, "caps", 2);
107   gst_object_unref (src);
108   gst_object_unref (sink);
109 }
110
111 GST_END_TEST;
112
113 GST_START_TEST (test_refcount)
114 {
115   GstPad *src, *sink;
116   GstCaps *caps;
117   GstPadLinkReturn plr;
118
119   sink = gst_pad_new ("sink", GST_PAD_SINK);
120   fail_if (sink == NULL);
121
122   src = gst_pad_new ("src", GST_PAD_SRC);
123   fail_if (src == NULL);
124
125   caps = gst_caps_from_string ("foo/bar");
126   /* one for me */
127   ASSERT_CAPS_REFCOUNT (caps, "caps", 1);
128
129   gst_pad_set_caps (src, caps);
130   gst_pad_set_caps (sink, caps);
131   /* one for me and one for each set_caps */
132   ASSERT_CAPS_REFCOUNT (caps, "caps", 3);
133
134   plr = gst_pad_link (src, sink);
135   fail_unless (GST_PAD_LINK_SUCCESSFUL (plr));
136   ASSERT_CAPS_REFCOUNT (caps, "caps", 3);
137
138   gst_pad_unlink (src, sink);
139   ASSERT_CAPS_REFCOUNT (caps, "caps", 3);
140
141   /* cleanup */
142   gst_object_unref (src);
143   gst_object_unref (sink);
144   ASSERT_CAPS_REFCOUNT (caps, "caps", 1);
145
146   gst_caps_unref (caps);
147 }
148
149 GST_END_TEST;
150
151 GST_START_TEST (test_get_allowed_caps)
152 {
153   GstPad *src, *sink;
154   GstCaps *caps, *gotcaps;
155   GstBuffer *buffer;
156   GstPadLinkReturn plr;
157
158   ASSERT_CRITICAL (gst_pad_get_allowed_caps (NULL));
159
160   buffer = gst_buffer_new ();
161   ASSERT_CRITICAL (gst_pad_get_allowed_caps ((GstPad *) buffer));
162   gst_buffer_unref (buffer);
163
164   sink = gst_pad_new ("sink", GST_PAD_SINK);
165   ASSERT_CRITICAL (gst_pad_get_allowed_caps (sink));
166
167   src = gst_pad_new ("src", GST_PAD_SRC);
168   fail_if (src == NULL);
169   caps = gst_pad_get_allowed_caps (src);
170   fail_unless (caps == NULL);
171
172   caps = gst_caps_from_string ("foo/bar");
173
174   gst_pad_set_caps (src, caps);
175   gst_pad_set_caps (sink, caps);
176   ASSERT_CAPS_REFCOUNT (caps, "caps", 3);
177
178   plr = gst_pad_link (src, sink);
179   fail_unless (GST_PAD_LINK_SUCCESSFUL (plr));
180
181   gotcaps = gst_pad_get_allowed_caps (src);
182   fail_if (gotcaps == NULL);
183   fail_unless (gst_caps_is_equal (gotcaps, caps));
184
185   ASSERT_CAPS_REFCOUNT (gotcaps, "gotcaps", 1);
186   gst_caps_unref (gotcaps);
187
188   gst_pad_unlink (src, sink);
189
190   /* cleanup */
191   ASSERT_CAPS_REFCOUNT (caps, "caps", 3);
192   ASSERT_OBJECT_REFCOUNT (src, "src", 1);
193   ASSERT_OBJECT_REFCOUNT (sink, "sink", 1);
194
195   gst_object_unref (src);
196   gst_object_unref (sink);
197
198   ASSERT_CAPS_REFCOUNT (caps, "caps", 1);
199   gst_caps_unref (caps);
200 }
201
202 GST_END_TEST;
203
204 static gboolean
205 name_is_valid (const gchar * name, GstPadPresence presence)
206 {
207   GstPadTemplate *new;
208
209   new = gst_pad_template_new (name, GST_PAD_SRC, presence, GST_CAPS_ANY);
210   if (new) {
211     gst_object_unref (GST_OBJECT (new));
212     return TRUE;
213   }
214   return FALSE;
215 }
216
217 GST_START_TEST (test_name_is_valid)
218 {
219   gboolean result = FALSE;
220
221   fail_unless (name_is_valid ("src", GST_PAD_ALWAYS));
222   ASSERT_WARNING (name_is_valid ("src%", GST_PAD_ALWAYS));
223   ASSERT_WARNING (result = name_is_valid ("src%d", GST_PAD_ALWAYS));
224   fail_if (result);
225
226   fail_unless (name_is_valid ("src", GST_PAD_REQUEST));
227   ASSERT_WARNING (name_is_valid ("src%s%s", GST_PAD_REQUEST));
228   ASSERT_WARNING (name_is_valid ("src%c", GST_PAD_REQUEST));
229   ASSERT_WARNING (name_is_valid ("src%", GST_PAD_REQUEST));
230   ASSERT_WARNING (name_is_valid ("src%dsrc", GST_PAD_REQUEST));
231
232   fail_unless (name_is_valid ("src", GST_PAD_SOMETIMES));
233   fail_unless (name_is_valid ("src%c", GST_PAD_SOMETIMES));
234 }
235
236 GST_END_TEST;
237
238 static gboolean
239 _probe_handler (GstPad * pad, GstBuffer * buffer, gpointer userdata)
240 {
241   gint ret = GPOINTER_TO_INT (userdata);
242
243   if (ret == 1)
244     return TRUE;
245   return FALSE;
246 }
247
248 GST_START_TEST (test_push_unlinked)
249 {
250   GstPad *src;
251   GstCaps *caps;
252   GstBuffer *buffer;
253   gulong id;
254
255   src = gst_pad_new ("src", GST_PAD_SRC);
256   fail_if (src == NULL);
257   caps = gst_pad_get_allowed_caps (src);
258   fail_unless (caps == NULL);
259
260   caps = gst_caps_from_string ("foo/bar");
261
262   gst_pad_set_caps (src, caps);
263   ASSERT_CAPS_REFCOUNT (caps, "caps", 2);
264
265   /* pushing on an unlinked pad will drop the buffer */
266   buffer = gst_buffer_new ();
267   gst_buffer_ref (buffer);
268   fail_unless (gst_pad_push (src, buffer) == GST_FLOW_NOT_LINKED);
269   ASSERT_MINI_OBJECT_REFCOUNT (buffer, "buffer", 1);
270   gst_buffer_unref (buffer);
271
272   /* adding a probe that returns FALSE will drop the buffer without trying
273    * to chain */
274   id = gst_pad_add_buffer_probe (src, (GCallback) _probe_handler,
275       GINT_TO_POINTER (0));
276   buffer = gst_buffer_new ();
277   gst_buffer_ref (buffer);
278   fail_unless (gst_pad_push (src, buffer) == GST_FLOW_OK);
279   ASSERT_MINI_OBJECT_REFCOUNT (buffer, "buffer", 1);
280   gst_buffer_unref (buffer);
281   gst_pad_remove_buffer_probe (src, id);
282
283   /* adding a probe that returns TRUE will still chain the buffer,
284    * and hence drop because pad is unlinked */
285   id = gst_pad_add_buffer_probe (src, (GCallback) _probe_handler,
286       GINT_TO_POINTER (1));
287   buffer = gst_buffer_new ();
288   gst_buffer_ref (buffer);
289   fail_unless (gst_pad_push (src, buffer) == GST_FLOW_NOT_LINKED);
290   ASSERT_MINI_OBJECT_REFCOUNT (buffer, "buffer", 1);
291   gst_buffer_unref (buffer);
292   gst_pad_remove_buffer_probe (src, id);
293
294
295   /* cleanup */
296   ASSERT_CAPS_REFCOUNT (caps, "caps", 2);
297   ASSERT_OBJECT_REFCOUNT (src, "src", 1);
298
299   gst_object_unref (src);
300
301   ASSERT_CAPS_REFCOUNT (caps, "caps", 1);
302   gst_caps_unref (caps);
303 }
304
305 GST_END_TEST;
306
307 GST_START_TEST (test_push_linked)
308 {
309   GstPad *src, *sink;
310   GstPadLinkReturn plr;
311   GstCaps *caps;
312   GstBuffer *buffer;
313   ulong id;
314
315   /* setup */
316   sink = gst_pad_new ("sink", GST_PAD_SINK);
317   fail_if (sink == NULL);
318   gst_pad_set_chain_function (sink, gst_check_chain_func);
319
320   src = gst_pad_new ("src", GST_PAD_SRC);
321   fail_if (src == NULL);
322
323   caps = gst_caps_from_string ("foo/bar");
324   /* one for me */
325   ASSERT_CAPS_REFCOUNT (caps, "caps", 1);
326
327   gst_pad_set_caps (src, caps);
328   gst_pad_set_caps (sink, caps);
329   /* one for me and one for each set_caps */
330   ASSERT_CAPS_REFCOUNT (caps, "caps", 3);
331
332   plr = gst_pad_link (src, sink);
333   fail_unless (GST_PAD_LINK_SUCCESSFUL (plr));
334   ASSERT_CAPS_REFCOUNT (caps, "caps", 3);
335
336   buffer = gst_buffer_new ();
337 #if 0
338   /* FIXME, new pad should be flushing */
339   gst_buffer_ref (buffer);
340   fail_unless (gst_pad_push (src, buffer) == GST_FLOW_WRONG_STATE);
341   gst_buffer_ref (buffer);
342   fail_unless (gst_pad_chain (sink, buffer) == GST_FLOW_WRONG_STATE);
343 #endif
344
345   /* activate pads */
346   gst_pad_set_active (src, TRUE);
347   gst_pad_set_active (sink, TRUE);
348
349   /* test */
350   /* pushing on a linked pad will drop the ref to the buffer */
351   gst_buffer_ref (buffer);
352   fail_unless (gst_pad_push (src, buffer) == GST_FLOW_OK);
353   ASSERT_MINI_OBJECT_REFCOUNT (buffer, "buffer", 2);
354   gst_buffer_unref (buffer);
355   fail_unless_equals_int (g_list_length (buffers), 1);
356   buffer = GST_BUFFER (buffers->data);
357   ASSERT_MINI_OBJECT_REFCOUNT (buffer, "buffer", 1);
358   gst_buffer_unref (buffer);
359   g_list_free (buffers);
360   buffers = NULL;
361
362   /* adding a probe that returns FALSE will drop the buffer without trying
363    * to chain */
364   id = gst_pad_add_buffer_probe (src, (GCallback) _probe_handler,
365       GINT_TO_POINTER (0));
366   buffer = gst_buffer_new ();
367   gst_buffer_ref (buffer);
368   fail_unless (gst_pad_push (src, buffer) == GST_FLOW_OK);
369   ASSERT_MINI_OBJECT_REFCOUNT (buffer, "buffer", 1);
370   gst_buffer_unref (buffer);
371   gst_pad_remove_buffer_probe (src, id);
372   fail_unless_equals_int (g_list_length (buffers), 0);
373
374   /* adding a probe that returns TRUE will still chain the buffer */
375   id = gst_pad_add_buffer_probe (src, (GCallback) _probe_handler,
376       GINT_TO_POINTER (1));
377   buffer = gst_buffer_new ();
378   gst_buffer_ref (buffer);
379   fail_unless (gst_pad_push (src, buffer) == GST_FLOW_OK);
380   gst_pad_remove_buffer_probe (src, id);
381
382   ASSERT_MINI_OBJECT_REFCOUNT (buffer, "buffer", 2);
383   gst_buffer_unref (buffer);
384   fail_unless_equals_int (g_list_length (buffers), 1);
385   buffer = GST_BUFFER (buffers->data);
386   ASSERT_MINI_OBJECT_REFCOUNT (buffer, "buffer", 1);
387   gst_buffer_unref (buffer);
388   g_list_free (buffers);
389   buffers = NULL;
390
391   /* teardown */
392   gst_pad_unlink (src, sink);
393   ASSERT_CAPS_REFCOUNT (caps, "caps", 3);
394   gst_object_unref (src);
395   gst_object_unref (sink);
396   ASSERT_CAPS_REFCOUNT (caps, "caps", 1);
397
398   gst_caps_unref (caps);
399 }
400
401 GST_END_TEST;
402
403 GST_START_TEST (test_flowreturn)
404 {
405   GstFlowReturn ret;
406   GQuark quark;
407
408   /* test some of the macros */
409   ret = GST_FLOW_UNEXPECTED;
410   fail_unless (GST_FLOW_IS_FATAL (ret));
411   fail_if (GST_FLOW_IS_SUCCESS (ret));
412   fail_if (strcmp (gst_flow_get_name (ret), "unexpected"));
413   quark = gst_flow_to_quark (ret);
414   fail_if (strcmp (g_quark_to_string (quark), "unexpected"));
415
416   ret = GST_FLOW_RESEND;
417   fail_if (GST_FLOW_IS_FATAL (ret));
418   fail_unless (GST_FLOW_IS_SUCCESS (ret));
419   fail_if (strcmp (gst_flow_get_name (ret), "resend"));
420   quark = gst_flow_to_quark (ret);
421   fail_if (strcmp (g_quark_to_string (quark), "resend"));
422
423   /* custom returns */
424   ret = GST_FLOW_CUSTOM_SUCCESS;
425   fail_if (GST_FLOW_IS_FATAL (ret));
426   fail_unless (GST_FLOW_IS_SUCCESS (ret));
427   fail_if (strcmp (gst_flow_get_name (ret), "custom-success"));
428   quark = gst_flow_to_quark (ret);
429   fail_if (strcmp (g_quark_to_string (quark), "custom-success"));
430
431   ret = GST_FLOW_CUSTOM_ERROR;
432   fail_unless (GST_FLOW_IS_FATAL (ret));
433   fail_if (GST_FLOW_IS_SUCCESS (ret));
434   fail_if (strcmp (gst_flow_get_name (ret), "custom-error"));
435   quark = gst_flow_to_quark (ret);
436   fail_if (strcmp (g_quark_to_string (quark), "custom-error"));
437
438   /* custom returns clamping */
439   ret = GST_FLOW_CUSTOM_SUCCESS + 2;
440   fail_if (GST_FLOW_IS_FATAL (ret));
441   fail_unless (GST_FLOW_IS_SUCCESS (ret));
442   fail_if (strcmp (gst_flow_get_name (ret), "custom-success"));
443   quark = gst_flow_to_quark (ret);
444   fail_if (strcmp (g_quark_to_string (quark), "custom-success"));
445
446   ret = GST_FLOW_CUSTOM_ERROR - 2;
447   fail_unless (GST_FLOW_IS_FATAL (ret));
448   fail_if (GST_FLOW_IS_SUCCESS (ret));
449   fail_if (strcmp (gst_flow_get_name (ret), "custom-error"));
450   quark = gst_flow_to_quark (ret);
451   fail_if (strcmp (g_quark_to_string (quark), "custom-error"));
452
453   /* unknown values */
454   ret = GST_FLOW_CUSTOM_ERROR + 2;
455   fail_unless (GST_FLOW_IS_FATAL (ret));
456   fail_if (GST_FLOW_IS_SUCCESS (ret));
457   fail_if (strcmp (gst_flow_get_name (ret), "unknown"));
458   quark = gst_flow_to_quark (ret);
459   fail_unless (quark == 0);
460 }
461
462 GST_END_TEST;
463
464 Suite *
465 gst_pad_suite (void)
466 {
467   Suite *s = suite_create ("GstPad");
468   TCase *tc_chain = tcase_create ("general");
469
470   /* turn off timeout */
471   tcase_set_timeout (tc_chain, 60);
472
473   suite_add_tcase (s, tc_chain);
474   tcase_add_test (tc_chain, test_link);
475   tcase_add_test (tc_chain, test_refcount);
476   tcase_add_test (tc_chain, test_get_allowed_caps);
477   tcase_add_test (tc_chain, test_link_unlink_threaded);
478   tcase_add_test (tc_chain, test_name_is_valid);
479   tcase_add_test (tc_chain, test_push_unlinked);
480   tcase_add_test (tc_chain, test_push_linked);
481   tcase_add_test (tc_chain, test_flowreturn);
482
483   return s;
484 }
485
486 GST_CHECK_MAIN (gst_pad);