4d4f207589197e6da91f8d2661ee2f77313679ba
[platform/upstream/gstreamer.git] / tests / check / pipelines / parse-launch.c
1 /* GStreamer
2  * Copyright (C) <2005> Thomas Vander Stichele <thomas at apestaart dot org>
3  *
4  * cleanup.c: Unit test for cleanup of pipelines
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 #ifdef HAVE_CONFIG_H
23 #  include "config.h"
24 #endif
25
26 #include <gst/check/gstcheck.h>
27
28 static GstElement *
29 setup_pipeline (const gchar * pipe_descr)
30 {
31   GstElement *pipeline;
32   GError *error = NULL;
33
34   pipeline = gst_parse_launch (pipe_descr, &error);
35   if (error != NULL) {
36     fail_if (error != NULL, "Error parsing pipeline %s: %s", pipe_descr,
37         error->message);
38     g_error_free (error);
39   }
40   fail_unless (pipeline != NULL, "Failed to create pipeline %s", pipe_descr);
41   return pipeline;
42 }
43
44 static void
45 expected_fail_pipe (const gchar * pipe_descr)
46 {
47   GstElement *pipeline;
48   GError *error = NULL;
49
50 #ifndef GST_DISABLE_GST_DEBUG
51   gst_debug_set_default_threshold (GST_LEVEL_NONE);
52 #endif
53
54   pipeline = gst_parse_launch (pipe_descr, &error);
55   fail_unless (pipeline == NULL || error != NULL,
56       "Expected failure pipeline %s: succeeded!", pipe_descr);
57   g_error_free (error);
58
59   /* We get a pipeline back even when parsing has failed, sometimes! */
60   if (pipeline)
61     gst_object_unref (pipeline);
62 }
63
64 static void
65 check_pipeline_runs (GstElement * p)
66 {
67   GstStateChangeReturn ret;
68
69   /* Check that the pipeline changes state to PAUSED and back to NULL */
70   ret = gst_element_set_state (p, GST_STATE_PAUSED);
71   if (ret == GST_STATE_CHANGE_ASYNC)
72     ret = gst_element_get_state (p, NULL, NULL, GST_CLOCK_TIME_NONE);
73   fail_unless (ret != GST_STATE_CHANGE_FAILURE,
74       "Could not set pipeline to paused");
75
76   ret = gst_element_set_state (p, GST_STATE_NULL);
77   if (ret == GST_STATE_CHANGE_ASYNC)
78     ret = gst_element_get_state (p, NULL, NULL, GST_CLOCK_TIME_NONE);
79   fail_unless (ret != GST_STATE_CHANGE_FAILURE,
80       "Could not set pipeline to null");
81 }
82
83 static const gchar *test_lines[] = {
84   "filesrc location=music.mp3 ! identity ! fakesink",
85   "filesrc location=music.ogg ! tee ! identity ! identity ! fakesink",
86   "filesrc location=http://domain.com/music.mp3 ! identity ! fakesink",
87   "filesrc location=movie.avi ! tee name=demuxer ! ( queue ! identity ! fakesink ) ( demuxer. ! queue ! identity ! fakesink )",
88   "fakesrc ! video/x-raw-yuv ! fakesink",
89   "fakesrc !   video/raw,  format=(fourcc)YUY2; video/raw, format=(fourcc)YV12 ! fakesink",
90   "fakesrc ! audio/x-raw-int, width=[16,  32], depth={16, 24, 32}, signed=TRUE ! fakesink",
91   "fakesrc ! identity ! identity ! identity ! fakesink",
92   NULL
93 };
94
95 GST_START_TEST (test_launch_lines)
96 {
97   GstElement *pipeline;
98   const gchar **s;
99
100   for (s = test_lines; *s != NULL; s++) {
101     pipeline = setup_pipeline (*s);
102     gst_object_unref (pipeline);
103   }
104 }
105
106 GST_END_TEST;
107
108 #define PIPELINE1  "fakesrc"
109 #define PIPELINE2  "fakesrc name=donald num-buffers= 27 silent =TruE sizetype = 3 data=   Subbuffer\\ data"
110 #define PIPELINE3  "fakesrc identity fakesink"
111 #define PIPELINE4  "fakesrc num-buffers=4 .src ! identity !.sink identity .src ! .sink fakesink"
112 #define PIPELINE5  "fakesrc num-buffers=4 name=src identity name=id1 identity name = id2 fakesink name =sink src. ! id1. id1.! id2.sink id2.src!sink.sink"
113 #define PIPELINE6  "pipeline.(name=\"john\" fakesrc num-buffers=4 ( bin. ( ! queue ! identity !( queue ! fakesink )) ))"
114 #define PIPELINE7  "fakesrc num-buffers=4 ! tee name=tee .src%d! queue ! fakesink tee.src%d ! queue ! fakesink queue name =\"foo\" ! fakesink tee.src%d ! foo."
115 /* aggregator is borked
116  * #define PIPELINE8  "fakesrc num-buffers=4 ! tee name=tee1 .src0,src1 ! .sink0, sink1 aggregator ! fakesink"
117  * */
118 #define PIPELINE8  "fakesrc num-buffers=4 ! fakesink"
119 #define PIPELINE9  "fakesrc num-buffers=4 ! test. fakesink name=test"
120 #define PIPELINE10 "( fakesrc num-buffers=\"4\" ! ) identity ! fakesink"
121 #define PIPELINE11 "fakesink name = sink identity name=id ( fakesrc num-buffers=\"4\" ! id. ) id. ! sink."
122 #define PIPELINE12 "file:///tmp/test.file ! fakesink"
123 #define PIPELINE13 "fakesrc ! file:///tmp/test.file"
124
125 GST_START_TEST (test_launch_lines2)
126 {
127   GstElement *cur;
128   gint i;
129   gboolean b;
130   gchar *s = NULL;
131
132   /**
133    * checks:
134    * - specifying an element works :)
135    * - if only 1 element is requested, no bin is returned, but the element
136    */
137   cur = setup_pipeline (PIPELINE1);
138   fail_unless (G_OBJECT_TYPE (cur) == g_type_from_name ("GstFakeSrc"),
139       "parse_launch did not produce a fakesrc");
140   gst_object_unref (cur);
141
142   /**
143    * checks:
144    * - properties works
145    * - string, int, boolean and enums can be properly set
146    * - first test of escaping strings
147    */
148   cur = setup_pipeline (PIPELINE2);
149   g_object_get (G_OBJECT (cur), "name", &s, "num-buffers", &i,
150       "silent", &b, NULL);
151   fail_if (s == NULL, "name was NULL");
152   fail_unless (strcmp (s, "donald") == 0, "fakesrc name was not 'donald'");
153   fail_unless (i == 27, "num-buffers was not 27");
154   fail_unless (b == TRUE, "silent was not TRUE");
155   g_free (s);
156
157   g_object_get (G_OBJECT (cur), "sizetype", &i, NULL);
158   fail_unless (i == 3, "sizetype != 3");
159
160   g_object_get (G_OBJECT (cur), "data", &i, NULL);
161   fail_unless (i == 2, "data != 2");
162   gst_object_unref (cur);
163
164   /**
165    * checks:
166    * - specifying multiple elements without links works
167    * - if multiple toplevel elements exist, a pipeline is returned
168    */
169   cur = setup_pipeline (PIPELINE3);
170   fail_unless (GST_BIN_NUMCHILDREN (cur) == 3,
171       "Pipeline does not contain 3 children");
172   gst_object_unref (cur);
173
174   /**
175    * checks:
176    * - test default link "!"
177    * - test if specifying pads on links works
178    */
179   cur = setup_pipeline (PIPELINE4);
180   check_pipeline_runs (cur);
181   gst_object_unref (cur);
182
183   /**
184    * checks:
185    * - test if appending the links works, too
186    * - check if the pipeline constructed works the same as the one before (how?)
187    */
188   cur = setup_pipeline (PIPELINE5);
189   check_pipeline_runs (cur);
190   gst_object_unref (cur);
191
192   /**
193    * checks:
194    * - test various types of bins
195    * - test if linking across bins works
196    * - test if escaping strings works
197    */
198   cur = setup_pipeline (PIPELINE6);
199   fail_unless (GST_IS_PIPELINE (cur), "Parse did not produce a pipeline");
200   g_object_get (G_OBJECT (cur), "name", &s, NULL);
201   fail_if (s == NULL, "name was NULL");
202   fail_unless (strcmp (s, "john") == 0, "Name was not 'john'");
203   g_free (s);
204   check_pipeline_runs (cur);
205   gst_object_unref (cur);
206
207   /**
208    * checks:
209    * - test request pads
210    */
211   cur = setup_pipeline (PIPELINE7);
212   check_pipeline_runs (cur);
213   gst_object_unref (cur);
214
215   /**
216    * checks:
217    * - multiple pads on 1 link
218    */
219   cur = setup_pipeline (PIPELINE8);
220   check_pipeline_runs (cur);
221   gst_object_unref (cur);
222
223   /**
224    * checks:
225    * - failed in grammar.y cvs version 1.17
226    */
227   cur = setup_pipeline (PIPELINE9);
228   check_pipeline_runs (cur);
229   gst_object_unref (cur);
230
231   /**
232    * checks:
233    * - failed in grammar.y cvs version 1.17
234    */
235   cur = setup_pipeline (PIPELINE10);
236   check_pipeline_runs (cur);
237   gst_object_unref (cur);
238
239   /**
240    * checks:
241    * - failed in grammar.y cvs version 1.18
242    */
243   cur = setup_pipeline (PIPELINE11);
244   check_pipeline_runs (cur);
245   gst_object_unref (cur);
246
247   /**
248    * checks:
249    * - URI detection works
250    */
251   cur = setup_pipeline (PIPELINE12);
252   gst_object_unref (cur);
253
254   /** * checks:
255    * - URI sink detection works
256    */
257   cur = setup_pipeline (PIPELINE13);
258   gst_object_unref (cur);
259
260   /* Checks handling of a assignment followed by error inside a bin. 
261    * This should warn, but ignore the error and carry on */
262   cur = setup_pipeline ("( filesrc blocksize=4 location=/dev/null @ )");
263   gst_object_unref (cur);
264 }
265
266 GST_END_TEST;
267
268 static const gchar *expected_failures[] = {
269   /* checks: fails because a=b. is not a valid element reference in parse.l */
270   "fakesrc num-buffers=4 name=\"a=b\"  a=b. ! fakesink",
271   /* checks: Error branch for a non-deserialisable property value */
272   "filesrc blocksize=absdff",
273   /* checks: That requesting an element which doesn't exist doesn't work */
274   "error-does-not-exist-src",
275   /* checks: That broken caps which don't parse can't create a pipeline */
276   "fakesrc ! video/raw,format=(antwerp)monkeys ! fakesink",
277   /* checks: Empty pipeline is invalid */
278   "",
279   /* checks: Link without sink element failes */
280   "fakesrc ! ",
281   /* checks: Link without src element failes */
282   " ! fakesink",
283   /* checks: Source URI for which no element exists is a failure */
284   "borky://fdaffd ! fakesink",
285   /* checks: Sink URI for which no element exists is a failure */
286   "fakesrc ! borky://fdaffd",
287   /* checks: Referencing non-existent source element by name can't link */
288   "fakesrc name=src fakesink name=sink noexiste. ! sink.",
289   /* checks: Referencing non-existent sink element by name can't link */
290   "fakesrc name=src fakesink name=sink src. ! noexiste.",
291   /* checks: Invalid pipeline syntax fails */
292   "fakesrc ! identity ! sgsdfagfd @ gfdgfdsgfsgSF",
293   /* checks: Can't link 2 elements that only have sink pads */
294   "fakesink ! fakesink",
295   /* checks: Attempting to link to a non-existent pad on an element 
296    * created via URI handler should fail */
297   "fakesrc ! .foo file:///dev/null",
298   /* checks multi-chain link without src element fails. */
299   "! identity ! identity ! fakesink",
300   /* END: */
301   NULL
302 };
303
304 GST_START_TEST (expected_to_fail_pipes)
305 {
306   const gchar **s;
307
308   for (s = expected_failures; *s != NULL; s++) {
309     expected_fail_pipe (*s);
310   }
311 }
312
313 GST_END_TEST;
314
315 /* Helper function to test delayed linking support in parse_launch by creating
316  * a test element based on bin, which contains a fakesrc and a sometimes 
317  * pad-template, and trying to link to a fakesink. When the bin transitions
318  * to paused it adds a pad, which should get linked to the fakesink */
319 static void
320 run_delayed_test (const gchar * pipe_str, const gchar * peer,
321     gboolean expect_link)
322 {
323   GstElement *pipe, *src, *sink;
324   GstPad *srcpad, *sinkpad, *peerpad = NULL;
325
326   pipe = setup_pipeline (pipe_str);
327
328   src = gst_bin_get_by_name (GST_BIN (pipe), "src");
329   fail_if (src == NULL, "Test source element was not created");
330
331   sink = gst_bin_get_by_name (GST_BIN (pipe), "sink");
332   fail_if (sink == NULL, "Test sink element was not created");
333
334   /* The src should not yet have a src pad */
335   srcpad = gst_element_get_pad (src, "src");
336   fail_unless (srcpad == NULL, "Source element already has a source pad");
337
338   /* Set the state to PAUSED and wait until the src at least reaches that
339    * state */
340   fail_if (gst_element_set_state (pipe, GST_STATE_PAUSED) ==
341       GST_STATE_CHANGE_FAILURE);
342
343   /* Also set the src state manually to make sure it is changing to that
344    * state */
345   fail_if (gst_element_set_state (src, GST_STATE_PAUSED) ==
346       GST_STATE_CHANGE_FAILURE);
347   fail_if (gst_element_get_state (src, NULL, NULL, GST_CLOCK_TIME_NONE) ==
348       GST_STATE_CHANGE_FAILURE);
349
350   /* Now, the source element should have a src pad, and if "peer" was passed, 
351    * then the src pad should have gotten linked to the 'sink' pad of that 
352    * peer */
353   srcpad = gst_element_get_pad (src, "src");
354   fail_if (srcpad == NULL, "Source element did not create source pad");
355
356   peerpad = gst_pad_get_peer (srcpad);
357
358   if (expect_link == TRUE) {
359     fail_if (peerpad == NULL, "Source element pad did not get linked");
360   } else {
361     fail_if (peerpad != NULL,
362         "Source element pad got linked but should not have");
363   }
364   if (peerpad != NULL)
365     gst_object_unref (peerpad);
366
367   if (peer != NULL) {
368     GstElement *peer_elem = gst_bin_get_by_name (GST_BIN (pipe), peer);
369
370     fail_if (peer_elem == NULL, "Could not retrieve peer %s", peer);
371
372     sinkpad = gst_element_get_pad (peer_elem, "sink");
373     fail_if (sinkpad == NULL, "Peer element did not have a 'sink' pad");
374
375     fail_unless (peerpad == sinkpad,
376         "Source src pad got connected to the wrong peer");
377     gst_object_unref (sinkpad);
378   }
379
380   gst_object_unref (srcpad);
381
382   gst_object_unref (src);
383   gst_object_unref (sink);
384   gst_object_unref (pipe);
385 }
386
387 GST_START_TEST (delayed_link)
388 {
389   /* This tests the delayed linking support in parse_launch by creating
390    * a test element based on bin, which contains a fakesrc and a sometimes 
391    * pad-template, and trying to link to a fakesink. When the bin transitions
392    * to paused it adds a pad, which should get linked to the fakesink */
393   run_delayed_test ("parsetestelement name=src ! fakesink name=sink",
394       "sink", TRUE);
395
396   /* Test, but this time specifying both pad names */
397   run_delayed_test ("parsetestelement name=src .src ! "
398       ".sink fakesink name=sink", "sink", TRUE);
399
400   /* Now try with a caps filter, but not testing that
401    * the peerpad == sinkpad, because the peer will actually
402    * be a capsfilter */
403   run_delayed_test ("parsetestelement name=src ! application/x-test-caps ! "
404       "fakesink name=sink", NULL, TRUE);
405
406   /* Now try with mutually exclusive caps filters that 
407    * will prevent linking, but only once gets around to happening -
408    * ie, the pipeline should create ok but fail to change state */
409   run_delayed_test ("parsetestelement name=src ! application/x-test-caps ! "
410       "identity ! application/x-other-caps ! "
411       "fakesink name=sink", NULL, FALSE);
412 }
413
414 GST_END_TEST;
415
416 #define GST_TYPE_PARSE_TEST_ELEMENT (gst_parse_test_element_get_type())
417
418 typedef struct _GstParseTestElement
419 {
420   GstBin parent;
421
422   GstElement *fakesrc;
423 } GstParseTestElement;
424
425 typedef struct _GstParseTestElementClass
426 {
427   GstBinClass parent;
428 } GstParseTestElementClass;
429
430 static GstStaticPadTemplate test_element_pad_template =
431 GST_STATIC_PAD_TEMPLATE ("src", GST_PAD_SRC,
432     GST_PAD_SOMETIMES, GST_STATIC_CAPS ("application/x-test-caps"));
433
434 GST_BOILERPLATE (GstParseTestElement, gst_parse_test_element, GstBin,
435     GST_TYPE_BIN);
436
437 static GstStateChangeReturn
438 gst_parse_test_element_change_state (GstElement * element,
439     GstStateChange transition);
440
441 static void
442 gst_parse_test_element_base_init (gpointer g_class)
443 {
444   static const GstElementDetails cdfoo_details =
445       GST_ELEMENT_DETAILS ("Test element for parse launch tests",
446       "Source",
447       "Test element for parse launch tests in core",
448       "GStreamer Devel <gstreamer-devel@lists.sf.net>");
449   GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
450
451   gst_element_class_set_details (element_class, &cdfoo_details);
452 }
453
454 static void
455 gst_parse_test_element_class_init (GstParseTestElementClass * klass)
456 {
457   GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
458
459   gst_element_class_add_pad_template (gstelement_class,
460       gst_static_pad_template_get (&test_element_pad_template));
461
462   gstelement_class->change_state = gst_parse_test_element_change_state;
463 }
464
465 static void
466 gst_parse_test_element_init (GstParseTestElement * src,
467     GstParseTestElementClass * klass)
468 {
469   /* Create a fakesrc and add it to ourselves */
470   src->fakesrc = gst_element_factory_make ("fakesrc", NULL);
471   if (src->fakesrc)
472     gst_bin_add (GST_BIN (src), src->fakesrc);
473 }
474
475 static GstStateChangeReturn
476 gst_parse_test_element_change_state (GstElement * element,
477     GstStateChange transition)
478 {
479   GstParseTestElement *src = (GstParseTestElement *) element;
480
481   if (transition == GST_STATE_CHANGE_READY_TO_PAUSED) {
482     /* Add our pad */
483     GstPad *pad;
484     GstPad *ghost;
485
486     if (src->fakesrc == NULL)
487       return GST_STATE_CHANGE_FAILURE;
488
489     pad = gst_element_get_pad (src->fakesrc, "src");
490     if (pad == NULL)
491       return GST_STATE_CHANGE_FAILURE;
492
493     ghost = gst_ghost_pad_new ("src", pad);
494     fail_if (ghost == NULL, "Failed to create ghost pad");
495     gst_element_add_pad (GST_ELEMENT (src), ghost);
496     gst_object_unref (pad);
497   }
498
499   return GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
500 }
501
502 static gboolean
503 gst_register_parse_element (GstPlugin * plugin)
504 {
505   if (!gst_element_register (plugin, "parsetestelement", GST_RANK_NONE,
506           GST_TYPE_PARSE_TEST_ELEMENT))
507     return FALSE;
508   return TRUE;
509 }
510
511 GST_PLUGIN_DEFINE_STATIC (GST_VERSION_MAJOR, GST_VERSION_MINOR,
512     "parsetestelement", "Test element for parse launch",
513     gst_register_parse_element, VERSION, GST_LICENSE, GST_PACKAGE_NAME,
514     GST_PACKAGE_ORIGIN);
515
516 Suite *
517 parse_suite (void)
518 {
519   Suite *s = suite_create ("Parse Launch syntax");
520   TCase *tc_chain = tcase_create ("parselaunch");
521
522   /* time out after 20s, not the default 3 */
523   tcase_set_timeout (tc_chain, 20);
524
525   suite_add_tcase (s, tc_chain);
526   tcase_add_test (tc_chain, test_launch_lines);
527   tcase_add_test (tc_chain, test_launch_lines2);
528   tcase_add_test (tc_chain, expected_to_fail_pipes);
529   tcase_add_test (tc_chain, delayed_link);
530   return s;
531 }
532
533 GST_CHECK_MAIN (parse);