• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* GStreamer gst_parse_launch unit tests
2  * Copyright (C) <2005> Thomas Vander Stichele <thomas at apestaart dot org>
3  * Copyright (C) <2008> Tim-Philipp Müller <tim centricular net>
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Library General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Library General Public License for more details.
14  *
15  * You should have received a copy of the GNU Library General Public
16  * License along with this library; if not, write to the
17  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
18  * Boston, MA 02110-1301, USA.
19  */
20 
21 #ifdef HAVE_CONFIG_H
22 #  include "config.h"
23 #endif
24 
25 #include <gst/check/gstcheck.h>
26 
27 #define GST_TYPE_PARSE_TEST_ELEMENT (gst_parse_test_element_get_type())
28 static GType gst_parse_test_element_get_type (void);
29 
30 static GstElement *
setup_pipeline(const gchar * pipe_descr)31 setup_pipeline (const gchar * pipe_descr)
32 {
33   GstElement *pipeline;
34   GError *error = NULL;
35 
36   GST_DEBUG ("creating [%s] setup_pipeline", pipe_descr);
37 
38   pipeline = gst_parse_launch (pipe_descr, &error);
39 
40   GST_DEBUG ("created [%s] setup_pipeline", pipe_descr);
41 
42   if (error != NULL) {
43     fail_if (error != NULL, "Error parsing pipeline %s: %s", pipe_descr,
44         error->message);
45     g_error_free (error);
46   }
47   fail_unless (pipeline != NULL, "Failed to create pipeline %s", pipe_descr);
48   /* Newly returned object should be floating reffed */
49   fail_unless (g_object_is_floating (pipeline));
50   g_assert_cmpuint (G_OBJECT (pipeline)->ref_count, ==, 1);
51   return pipeline;
52 }
53 
54 static void
expected_fail_pipe(const gchar * pipe_descr)55 expected_fail_pipe (const gchar * pipe_descr)
56 {
57   GstElement *pipeline;
58   GError *error = NULL;
59 
60 #ifndef GST_DISABLE_GST_DEBUG
61   gst_debug_set_default_threshold (GST_LEVEL_NONE);
62 #endif
63 
64   pipeline = gst_parse_launch (pipe_descr, &error);
65   fail_unless (pipeline == NULL || error != NULL,
66       "Expected failure pipeline %s: succeeded!", pipe_descr);
67   g_error_free (error);
68 
69   /* We get a pipeline back even when parsing has failed, sometimes! */
70   if (pipeline)
71     gst_object_unref (pipeline);
72 }
73 
74 static void
check_pipeline_runs(GstElement * p)75 check_pipeline_runs (GstElement * p)
76 {
77   GstStateChangeReturn ret;
78 
79   /* Check that the pipeline changes state to PAUSED and back to NULL */
80   ret = gst_element_set_state (p, GST_STATE_PAUSED);
81   if (ret == GST_STATE_CHANGE_ASYNC)
82     ret = gst_element_get_state (p, NULL, NULL, GST_CLOCK_TIME_NONE);
83   fail_unless (ret != GST_STATE_CHANGE_FAILURE,
84       "Could not set pipeline to paused");
85 
86   ret = gst_element_set_state (p, GST_STATE_NULL);
87   if (ret == GST_STATE_CHANGE_ASYNC)
88     ret = gst_element_get_state (p, NULL, NULL, GST_CLOCK_TIME_NONE);
89   fail_unless (ret != GST_STATE_CHANGE_FAILURE,
90       "Could not set pipeline to null");
91 }
92 
93 static const gchar *test_lines[] = {
94   "filesrc location=music.mp3 ! identity silent=true ! fakesink silent=true",
95   "filesrc location=music.ogg ! tee ! identity silent=true ! identity silent=true ! fakesink silent=true",
96   "filesrc location=http://domain.com/music.mp3 ! identity silent=true ! fakesink silent=true",
97   "filesrc location=movie.avi ! tee name=demuxer ! ( queue ! identity silent=true ! fakesink silent=true ) ( demuxer. ! queue ! identity silent=true ! fakesink silent=true )",
98   "fakesrc ! video/x-raw ! fakesink silent=true",
99   "fakesrc !   video/raw,  format=(string)YUY2; video/raw, format=(string)YV12 ! fakesink silent=true",
100   "fakesrc ! audio/x-raw, width=[16,  32], depth={16, 24, 32}, signed=TRUE ! fakesink silent=true",
101   "fakesrc ! identity silent=true ! identity silent=true ! identity silent=true ! fakesink silent=true",
102   "fakesrc name=100 fakesink name=101 silent=true 100. ! 101.", /* linking with named reference on both sides */
103   "fakesrc ! 1__dentity ! fakesink silent=true",        /* using a freshly registered element type */
104   "fakesrc ! tee name=t  t.src_12 ! queue ! fakesink  t.src_3 ! queue ! fakesink",
105   "fakesrc name=foo name=fin  fin. ! fakesink", /* testing assignments are executed in correct order (left-to-right) */
106   "( fakesrc ) ! fakesink",     /* ghostPad creation on-the-fly, infix notation link */
107   "( fakesrc name=dasrc ) dasrc. ! fakesink",   /* ghostPad creation on-the-fly, named link */
108 /*  "(name=mabin fakesrc) mabin. ! fakesink", FIXME: linking to named bin does not work yet */
109 /*  "(name=mabin name=yoyo fakesrc) yoyo. ! fakesink", FIXME: linking to named bin does not work yet  */
110   "deepsrc. ! fakesink fakesrc  ! ( identity ! ( identity ! (  identity name=deepsrc ) ) )",    /* deep name resolution, multilevel ghostpad creation */
111   "fakesrc : fakesink",         /* linking all matching pads */
112   "fakesrc : video/x-all : fakesink",   /* linking all matching pads with filter */
113   "fakesrc ! video/x-all : fakesink",   /* linking all matching pads with filter */
114   "fakesrc : video/x-all ! fakesink",   /* linking all matching pads with filter */
115   NULL
116 };
117 
GST_START_TEST(test_launch_lines)118 GST_START_TEST (test_launch_lines)
119 {
120   GstElement *pipeline;
121   const gchar **s;
122   GType type;
123   GstElementFactory *efac;
124 
125   efac = gst_element_factory_find ("identity");
126   fail_unless (efac != NULL);
127   efac =
128       GST_ELEMENT_FACTORY (gst_plugin_feature_load (GST_PLUGIN_FEATURE (efac)));
129   fail_unless (efac != NULL);
130   type = gst_element_factory_get_element_type (efac);
131   fail_unless (type != 0);
132   gst_object_unref (efac);
133   gst_object_unref (efac);
134   fail_unless (gst_element_register (NULL, "1__dentity", GST_RANK_NONE, type));
135 
136   for (s = test_lines; *s != NULL; s++) {
137     pipeline = setup_pipeline (*s);
138     gst_object_unref (pipeline);
139   }
140 }
141 
142 GST_END_TEST;
143 
144 #define PIPELINE1  "fakesrc"
145 #define PIPELINE2  "fakesrc name=donald num-buffers= 27 silent =TruE sizetype = 3 data=   Subbuffer\\ data"
146 #define PIPELINE3  "fakesrc identity silent=true fakesink silent=true"
147 #define PIPELINE4  "fakesrc num-buffers=4 .src ! identity silent=true !.sink identity silent=true .src ! .sink fakesink silent=true"
148 #define PIPELINE5  "fakesrc num-buffers=4 name=src identity silent=true name=id1 identity silent=true name = id2 fakesink silent=true name =sink src. ! id1. id1.! id2.sink id2.src!sink.sink"
149 #define PIPELINE6  "pipeline.(name=\"john\" fakesrc num-buffers=4 ! ( bin. (  queue ! identity silent=true !( queue ! fakesink silent=true )) ))"
150 #define PIPELINE7  "fakesrc num-buffers=4 ! tee name=tee .src_%u ! queue ! fakesink silent=true tee.src_%u ! queue ! fakesink silent=true queue name =\"foo\" ! fakesink silent=true tee.src_%u ! foo."
151 /* aggregator is borked
152  * #define PIPELINE8  "fakesrc num-buffers=4 ! tee name=tee1 .src0,src1 ! .sink0, sink1 aggregator ! fakesink silent=true"
153  * */
154 #define PIPELINE8  "fakesrc num-buffers=4 ! fakesink silent=true"
155 #define PIPELINE9  "fakesrc num-buffers=4 ! test. fakesink silent=true name=test"
156 #define PIPELINE10 "( fakesrc num-buffers=\"4\"  ) ! identity silent=true ! fakesink silent=true"
157 #define PIPELINE11 "fakesink silent=true name = sink identity silent=true name=id ( fakesrc num-buffers=\"4\" ! id. ) id. ! sink."
158 #define PIPELINE12 "file:///tmp/test.file ! fakesink silent=true"
159 #define PIPELINE13 "fakesrc ! file:///tmp/test.file"
160 #define PIPELINE14 "capsfilter caps=application/x-rtp,sprop-parameter-sets=(string)\"x\\,x\""
161 #define PIPELINE15 "capsfilter caps=application/x-rtp,sprop-parameter-sets=(string)\"x\\\"x\\,x\""
162 
GST_START_TEST(test_launch_lines2)163 GST_START_TEST (test_launch_lines2)
164 {
165   GstElement *cur;
166   gint i;
167   gboolean b;
168   gchar *s = NULL;
169 
170   /**
171    * checks:
172    * - specifying an element works :)
173    * - if only 1 element is requested, no bin is returned, but the element
174    */
175   cur = setup_pipeline (PIPELINE1);
176   fail_unless (G_OBJECT_TYPE (cur) == g_type_from_name ("GstFakeSrc"),
177       "parse_launch did not produce a fakesrc");
178   gst_object_unref (cur);
179 
180   /**
181    * checks:
182    * - properties works
183    * - string, int, boolean and enums can be properly set
184    * - first test of escaping strings
185    */
186   cur = setup_pipeline (PIPELINE2);
187   g_object_get (G_OBJECT (cur), "name", &s, "num-buffers", &i,
188       "silent", &b, NULL);
189   fail_if (s == NULL, "name was NULL");
190   fail_unless (strcmp (s, "donald") == 0, "fakesrc name was not 'donald'");
191   fail_unless (i == 27, "num-buffers was not 27");
192   fail_unless (b == TRUE, "silent was not TRUE");
193   g_free (s);
194 
195   g_object_get (G_OBJECT (cur), "sizetype", &i, NULL);
196   fail_unless (i == 3, "sizetype != 3");
197 
198   g_object_get (G_OBJECT (cur), "data", &i, NULL);
199   fail_unless (i == 2, "data != 2");
200   gst_object_unref (cur);
201 
202   /**
203    * checks:
204    * - specifying multiple elements without links works
205    * - if multiple toplevel elements exist, a pipeline is returned
206    */
207   cur = setup_pipeline (PIPELINE3);
208   fail_unless (GST_BIN_NUMCHILDREN (cur) == 3,
209       "Pipeline does not contain 3 children");
210   gst_object_unref (cur);
211 
212   /**
213    * checks:
214    * - test default link "!"
215    * - test if specifying pads on links works
216    */
217   cur = setup_pipeline (PIPELINE4);
218   check_pipeline_runs (cur);
219   gst_object_unref (cur);
220 
221   /**
222    * checks:
223    * - test if appending the links works, too
224    * - check if the pipeline constructed works the same as the one before (how?)
225    */
226   cur = setup_pipeline (PIPELINE5);
227   check_pipeline_runs (cur);
228   gst_object_unref (cur);
229 
230   /**
231    * checks:
232    * - test various types of bins
233    * - test if linking across bins works
234    * - test if escaping strings works
235    */
236   cur = setup_pipeline (PIPELINE6);
237   /* FIXME: valgrind finds element later */
238   fail_unless (GST_IS_PIPELINE (cur), "Parse did not produce a pipeline");
239   g_object_get (G_OBJECT (cur), "name", &s, NULL);
240   fail_if (s == NULL, "name was NULL");
241   fail_unless (strcmp (s, "john") == 0, "Name was not 'john'");
242   g_free (s);
243   check_pipeline_runs (cur);
244   gst_object_unref (cur);
245 
246   /**
247    * checks:
248    * - test request pads
249    */
250   cur = setup_pipeline (PIPELINE7);
251   check_pipeline_runs (cur);
252   gst_object_unref (cur);
253 
254   /**
255    * checks:
256    * - multiple pads on 1 link
257    */
258   cur = setup_pipeline (PIPELINE8);
259   check_pipeline_runs (cur);
260   gst_object_unref (cur);
261 
262   /**
263    * checks:
264    * - failed in grammar.y cvs version 1.17
265    */
266   cur = setup_pipeline (PIPELINE9);
267   check_pipeline_runs (cur);
268   gst_object_unref (cur);
269 
270   /**
271    * checks:
272    * - failed in grammar.y cvs version 1.17
273    */
274   cur = setup_pipeline (PIPELINE10);
275   check_pipeline_runs (cur);
276   gst_object_unref (cur);
277 
278   /**
279    * checks:
280    * - failed in grammar.y cvs version 1.18
281    */
282   cur = setup_pipeline (PIPELINE11);
283   check_pipeline_runs (cur);
284   gst_object_unref (cur);
285 
286   /**
287    * checks:
288    * - URI detection works
289    */
290   cur = setup_pipeline (PIPELINE12);
291   gst_object_unref (cur);
292 
293   /** * checks:
294    * - URI sink detection works
295    */
296   cur = setup_pipeline (PIPELINE13);
297   gst_object_unref (cur);
298 
299   /**
300    * Checks if characters inside quotes are not escaped.
301   */
302   cur = setup_pipeline (PIPELINE14);
303   gst_object_unref (cur);
304 
305   /**
306    * Checks if escaped quotes inside quotes are not treated as end string quotes.
307    * This would make the rest of characters to be escaped incorrectly.
308    */
309   cur = setup_pipeline (PIPELINE15);
310   gst_object_unref (cur);
311 }
312 
313 GST_END_TEST;
314 
315 static const gchar *expected_failures[] = {
316   /* checks: fails because a=b. is not a valid element reference in parse.l */
317   "fakesrc num-buffers=4 name=\"a=b\"  a=b. ! fakesink silent=true",
318   /* checks: Error branch for a non-deserialisable property value */
319   "filesrc blocksize=absdff",
320   /* checks: That broken caps which don't parse can't create a pipeline */
321   "fakesrc ! video/raw,format=(antwerp)monkeys ! fakesink silent=true",
322   /* checks: Empty pipeline is invalid */
323   "",
324   /* checks: Link without sink element fails */
325   "fakesrc ! ",
326   /* checks: Link without src element fails */
327   " ! fakesink silent=true",
328   /* checks: Source URI for which no element exists is a failure */
329   "borky://fdaffd ! fakesink silent=true",
330   /* checks: Sink URI for which no element exists is a failure */
331   "fakesrc ! borky://fdaffd",
332   /* checks: Referencing non-existent source element by name can't link */
333   "fakesrc name=src fakesink silent=true name=sink noexiste. ! sink.",
334   /* checks: Referencing non-existent sink element by name can't link */
335   "fakesrc name=src fakesink silent=true name=sink src. ! noexiste.",
336   /* checks: Can't link 2 elements that only have sink pads */
337   "fakesink silent=true ! fakesink silent=true",
338   /* checks multi-chain link without src element fails. */
339   "! identity silent=true ! identity silent=true ! fakesink silent=true",
340   /* Empty bin not allowed */
341   "bin.( )",
342   /* bin with non-existent element counts as empty, and not allowed */
343   "bin.( non_existent_element )",
344   /* bin with an element, assignments and then a syntax error */
345   "( filesrc blocksize=4 location=/dev/null @ )",
346   /* bin linking with the ! inside the bin and no ! outside */
347   "( fakesrc num-buffers=\"4\" ! ) identity silent=true ! fakesink silent=true",
348   /* bins with linking without ! */
349   /* FIXME: one element leaks as reported by valgrind */
350   "pipeline.(name=\"john\" fakesrc num-buffers=4 ( bin. ( ! queue ! identity silent=true !( queue ! fakesink silent=true )) ))",
351   /* non-existent bin-type containing already created elements */
352   "coffeebin.( fakesrc ! identity ! fakesink )",
353   /* non-existent bin-type in pipeline */
354   "fakesrc ! coffeebin.( identity ) ! fakesink",
355   /* unexpected pad references Part I */
356   "fakesrc ! .ch0 .ch1 fakesink",
357   /* unexpected pad references Part II */
358   "fakesrc .ch0 .ch1 !  fakesink",
359   /* unexpected pad references Part III */
360   "(fakesrc .ch1) !  fakesink",
361   /* unexpected full reference, I */
362   "(fakesrc name=s  s.ch1) !  fakesink",
363   /* unexpected full reference, II */
364   "s.ch1 fakesrc ! fakesink",
365   /* unexpected full reference, III */
366   "fakesrc ! fakesink s.ch1",
367   /* unlinked src/sink URI */
368   "http://eff.org fakesrc ! fakesink",
369   /* catch assignments evaluated in wrong order */
370   "fakesrc name=ss name=st  ss. ! fakesink",
371   /* unbalanced brackets */
372   "(", ")", ")  (",
373   /* END: */
374   NULL
375 };
376 
GST_START_TEST(expected_to_fail_pipes)377 GST_START_TEST (expected_to_fail_pipes)
378 {
379   const gchar **s;
380 
381   for (s = expected_failures; *s != NULL; s++) {
382     expected_fail_pipe (*s);
383   }
384 }
385 
386 GST_END_TEST;
387 
388 static const gchar *leaking_failures[] = {
389   /* checks: Invalid pipeline syntax fails */
390   "fakesrc ! identity silent=true ! sgsdfagfd @ gfdgfdsgfsgSF",
391   /* checks: Attempting to link to a non-existent pad on an element
392    * created via URI handler should fail */
393   "fakesrc ! .foo file:///dev/null",
394   /* checks: That requesting an element which doesn't exist doesn't work */
395   "error-does-not-exist-src",
396   NULL
397 };
398 
399 /* These don't seem to leak any longer? */
GST_START_TEST(leaking_fail_pipes)400 GST_START_TEST (leaking_fail_pipes)
401 {
402   const gchar **s;
403 
404   for (s = leaking_failures; *s != NULL; s++) {
405     GST_INFO ("Trying pipe: %s", *s);
406     expected_fail_pipe (*s);
407   }
408 }
409 
410 GST_END_TEST;
411 
412 /* Helper function to test delayed linking support in parse_launch by creating
413  * a test element based on bin, which contains a fakesrc and a sometimes
414  * pad-template, and trying to link to a fakesink. When the bin transitions
415  * to paused it adds a pad, which should get linked to the fakesink */
416 static void
run_delayed_test(const gchar * pipe_str,const gchar * peer,gboolean expect_link)417 run_delayed_test (const gchar * pipe_str, const gchar * peer,
418     gboolean expect_link)
419 {
420   GstElement *pipe, *src, *sink;
421   GstPad *srcpad, *sinkpad, *peerpad = NULL;
422   GstStateChangeReturn ret;
423 
424   pipe = setup_pipeline (pipe_str);
425 
426   src = gst_bin_get_by_name (GST_BIN (pipe), "src");
427   fail_if (src == NULL, "Test source element was not created");
428 
429   sink = gst_bin_get_by_name (GST_BIN (pipe), "sink");
430   fail_if (sink == NULL, "Test sink element was not created");
431 
432   /* The src should not yet have a src pad */
433   srcpad = gst_element_get_static_pad (src, "src");
434   fail_unless (srcpad == NULL, "Source element already has a source pad");
435 
436   /* Set the state to PAUSED and wait until the src at least reaches that
437    * state */
438   ret = gst_element_set_state (pipe, GST_STATE_PAUSED);
439 
440   if (expect_link) {
441     fail_if (ret == GST_STATE_CHANGE_FAILURE);
442   } else {
443     fail_unless (ret == GST_STATE_CHANGE_FAILURE
444         || ret == GST_STATE_CHANGE_ASYNC);
445   }
446 
447   ret = gst_element_get_state (pipe, NULL, NULL, GST_CLOCK_TIME_NONE);
448 
449   if (expect_link) {
450     fail_if (ret == GST_STATE_CHANGE_FAILURE);
451   } else {
452     fail_unless (ret == GST_STATE_CHANGE_FAILURE);
453   }
454 
455   /* Now, the source element should have a src pad, and if "peer" was passed,
456    * then the src pad should have gotten linked to the 'sink' pad of that
457    * peer */
458   srcpad = gst_element_get_static_pad (src, "src");
459   fail_if (srcpad == NULL, "Source element did not create source pad");
460 
461   peerpad = gst_pad_get_peer (srcpad);
462 
463   if (expect_link == TRUE) {
464     fail_if (peerpad == NULL, "Source element pad did not get linked");
465   } else {
466     fail_if (peerpad != NULL,
467         "Source element pad got linked but should not have");
468   }
469   if (peerpad != NULL)
470     gst_object_unref (peerpad);
471 
472   if (peer != NULL) {
473     GstElement *peer_elem = gst_bin_get_by_name (GST_BIN (pipe), peer);
474 
475     fail_if (peer_elem == NULL, "Could not retrieve peer %s", peer);
476 
477     sinkpad = gst_element_get_static_pad (peer_elem, "sink");
478     gst_object_unref (peer_elem);
479     fail_if (sinkpad == NULL, "Peer element did not have a 'sink' pad");
480 
481     fail_unless (peerpad == sinkpad,
482         "Source src pad got connected to the wrong peer");
483     gst_object_unref (sinkpad);
484   }
485 
486   gst_object_unref (srcpad);
487 
488   gst_object_unref (src);
489   gst_object_unref (sink);
490 
491   gst_element_set_state (pipe, GST_STATE_NULL);
492   gst_object_unref (pipe);
493 }
494 
GST_START_TEST(delayed_link)495 GST_START_TEST (delayed_link)
496 {
497   fail_unless (gst_element_register (NULL, "parsetestelement",
498           GST_RANK_NONE, GST_TYPE_PARSE_TEST_ELEMENT));
499 
500   /* This tests the delayed linking support in parse_launch by creating
501    * a test element based on bin, which contains a fakesrc and a sometimes
502    * pad-template, and trying to link to a fakesink. When the bin transitions
503    * to paused it adds a pad, which should get linked to the fakesink */
504   run_delayed_test
505       ("parsetestelement name=src ! fakesink silent=true name=sink", "sink",
506       TRUE);
507   /* FIXME: valgrind finds one element */
508 
509   /* Test, but this time specifying both pad names */
510   run_delayed_test ("parsetestelement name=src .src ! "
511       ".sink fakesink silent=true name=sink", "sink", TRUE);
512   /* FIXME: valgrind finds one element */
513 
514   /* Now try with a caps filter, but not testing that
515    * the peerpad == sinkpad, because the peer will actually
516    * be a capsfilter */
517   run_delayed_test ("parsetestelement name=src ! application/x-test-caps ! "
518       "fakesink silent=true name=sink", NULL, TRUE);
519 
520   /* Now try with mutually exclusive caps filters that
521    * will prevent linking, but only once gets around to happening -
522    * ie, the pipeline should create ok but fail to change state */
523   run_delayed_test ("parsetestelement name=src ! application/x-test-caps ! "
524       "identity silent=true ! application/x-other-caps ! "
525       "fakesink silent=true name=sink silent=true", NULL, FALSE);
526 }
527 
528 GST_END_TEST;
529 
530 typedef struct _GstParseTestElement
531 {
532   GstBin parent;
533 
534   GstElement *fakesrc;
535 } GstParseTestElement;
536 
537 typedef struct _GstParseTestElementClass
538 {
539   GstBinClass parent;
540 } GstParseTestElementClass;
541 
542 static GstStaticPadTemplate test_element_pad_template =
543 GST_STATIC_PAD_TEMPLATE ("src", GST_PAD_SRC,
544     GST_PAD_SOMETIMES, GST_STATIC_CAPS ("application/x-test-caps"));
545 #define gst_parse_test_element_parent_class parent_class
546 G_DEFINE_TYPE (GstParseTestElement, gst_parse_test_element, GST_TYPE_BIN);
547 
548 static GstStateChangeReturn
549 gst_parse_test_element_change_state (GstElement * element,
550     GstStateChange transition);
551 
552 static void
gst_parse_test_element_class_init(GstParseTestElementClass * klass)553 gst_parse_test_element_class_init (GstParseTestElementClass * klass)
554 {
555   GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
556 
557   gst_element_class_add_static_pad_template (gstelement_class,
558       &test_element_pad_template);
559 
560   gst_element_class_set_metadata (gstelement_class,
561       "Test element for parse launch tests", "Source",
562       "Test element for parse launch tests in core",
563       "GStreamer Devel <gstreamer-devel@lists.sf.net>");
564 
565   gstelement_class->change_state = gst_parse_test_element_change_state;
566 }
567 
568 static void
gst_parse_test_element_init(GstParseTestElement * src)569 gst_parse_test_element_init (GstParseTestElement * src)
570 {
571   /* Create a fakesrc and add it to ourselves */
572   src->fakesrc = gst_element_factory_make ("fakesrc", NULL);
573   if (src->fakesrc)
574     gst_bin_add (GST_BIN (src), src->fakesrc);
575 }
576 
577 static GstStateChangeReturn
gst_parse_test_element_change_state(GstElement * element,GstStateChange transition)578 gst_parse_test_element_change_state (GstElement * element,
579     GstStateChange transition)
580 {
581   GstParseTestElement *src = (GstParseTestElement *) element;
582 
583   if (transition == GST_STATE_CHANGE_READY_TO_PAUSED) {
584     /* Add our pad */
585     GstPad *pad;
586     GstPad *ghost;
587 
588     if (src->fakesrc == NULL)
589       return GST_STATE_CHANGE_FAILURE;
590 
591     pad = gst_element_get_static_pad (src->fakesrc, "src");
592     if (pad == NULL)
593       return GST_STATE_CHANGE_FAILURE;
594 
595     ghost = gst_ghost_pad_new ("src", pad);
596     fail_if (ghost == NULL, "Failed to create ghost pad");
597     /* activate and add */
598     gst_pad_set_active (ghost, TRUE);
599     gst_element_add_pad (GST_ELEMENT (src), ghost);
600     gst_object_unref (pad);
601   }
602 
603   return GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
604 }
605 
GST_START_TEST(test_missing_elements)606 GST_START_TEST (test_missing_elements)
607 {
608   GstParseContext *ctx;
609   GstElement *element;
610   GError *err = NULL;
611   gchar **arr;
612 
613   /* avoid misleading 'no such element' error debug messages when using cvs */
614   if (!g_getenv ("GST_DEBUG"))
615     gst_debug_set_default_threshold (GST_LEVEL_NONE);
616 
617   /* one missing element */
618   ctx = gst_parse_context_new ();
619   element = gst_parse_launch_full ("fakesrc ! coffeesink", ctx,
620       GST_PARSE_FLAG_FATAL_ERRORS, &err);
621   fail_unless (err != NULL, "expected error");
622   fail_unless_equals_int (err->code, GST_PARSE_ERROR_NO_SUCH_ELEMENT);
623   fail_unless (element == NULL, "expected NULL return with FATAL_ERRORS");
624   arr = gst_parse_context_get_missing_elements (ctx);
625   fail_unless (arr != NULL, "expected missing elements");
626   fail_unless_equals_string (arr[0], "coffeesink");
627   fail_unless (arr[1] == NULL);
628   g_strfreev (arr);
629   gst_parse_context_free (ctx);
630   g_error_free (err);
631   err = NULL;
632 
633   /* multiple missing elements */
634   ctx = gst_parse_context_new ();
635   element = gst_parse_launch_full ("fakesrc ! bogusenc ! identity ! goomux ! "
636       "fakesink", ctx, GST_PARSE_FLAG_FATAL_ERRORS, &err);
637   fail_unless (err != NULL, "expected error");
638   fail_unless_equals_int (err->code, GST_PARSE_ERROR_NO_SUCH_ELEMENT);
639   fail_unless (element == NULL, "expected NULL return with FATAL_ERRORS");
640   arr = gst_parse_context_get_missing_elements (ctx);
641   fail_unless (arr != NULL, "expected missing elements");
642   fail_unless_equals_string (arr[0], "bogusenc");
643   fail_unless_equals_string (arr[1], "goomux");
644   fail_unless (arr[2] == NULL);
645   g_strfreev (arr);
646   gst_parse_context_free (ctx);
647   g_error_free (err);
648   err = NULL;
649 
650   /* multiple missing elements, different link pattern */
651   ctx = gst_parse_context_new ();
652   element = gst_parse_launch_full ("fakesrc ! bogusenc ! mux.sink "
653       "blahsrc ! goomux name=mux ! fakesink   fakesrc ! goosink", ctx,
654       GST_PARSE_FLAG_FATAL_ERRORS, &err);
655   fail_unless (err != NULL, "expected error");
656   fail_unless_equals_int (err->code, GST_PARSE_ERROR_NO_SUCH_ELEMENT);
657   fail_unless (element == NULL, "expected NULL return with FATAL_ERRORS");
658   arr = gst_parse_context_get_missing_elements (ctx);
659   fail_unless (arr != NULL, "expected missing elements");
660   fail_unless_equals_string (arr[0], "bogusenc");
661   fail_unless_equals_string (arr[1], "blahsrc");
662   fail_unless_equals_string (arr[2], "goomux");
663   fail_unless_equals_string (arr[3], "goosink");
664   fail_unless (arr[4] == NULL);
665   g_strfreev (arr);
666   gst_parse_context_free (ctx);
667   g_error_free (err);
668   err = NULL;
669 }
670 
671 GST_END_TEST;
672 
GST_START_TEST(test_preset)673 GST_START_TEST (test_preset)
674 {
675   GstElement *element;
676   GError *err = NULL;
677 
678   /* missing preset */
679   element =
680       gst_parse_launch
681       ("fakesrc ! identity @preset=\"Wrong preset\" ! fakesink", &err);
682   fail_unless (err != NULL, "expected error");
683   fail_unless_equals_int (err->code, GST_PARSE_ERROR_COULD_NOT_SET_PROPERTY);
684   fail_unless (element != NULL, "Doesn't NULL return without FATAL_ERRORS");
685   gst_clear_object (&element);
686   g_clear_error (&err);
687 }
688 
689 GST_END_TEST;
690 
GST_START_TEST(test_flags)691 GST_START_TEST (test_flags)
692 {
693   GstElement *element;
694   GError *err = NULL;
695 
696   /* avoid misleading 'no such element' error debug messages when using cvs */
697   if (!g_getenv ("GST_DEBUG"))
698     gst_debug_set_default_threshold (GST_LEVEL_NONE);
699 
700   /* default behaviour is to return any already constructed bins/elements */
701   element = gst_parse_launch_full ("fakesrc ! coffeesink", NULL, 0, &err);
702   fail_unless (err != NULL, "expected error");
703   fail_unless_equals_int (err->code, GST_PARSE_ERROR_NO_SUCH_ELEMENT);
704   fail_unless (element != NULL, "expected partial pipeline/element");
705   g_error_free (err);
706   err = NULL;
707   gst_object_unref (element);
708 
709   /* test GST_PARSE_FLAG_FATAL_ERRORS */
710   element = gst_parse_launch_full ("fakesrc ! coffeesink", NULL,
711       GST_PARSE_FLAG_FATAL_ERRORS, &err);
712   fail_unless (err != NULL, "expected error");
713   fail_unless_equals_int (err->code, GST_PARSE_ERROR_NO_SUCH_ELEMENT);
714   fail_unless (element == NULL, "expected NULL return with FATAL_ERRORS");
715   g_error_free (err);
716   err = NULL;
717 
718   /* test GST_PARSE_FLAG_FATAL_ERRORS without GError */
719   element = gst_parse_launch_full ("fakesrc ! coffeesink", NULL,
720       GST_PARSE_FLAG_FATAL_ERRORS, NULL);
721   fail_unless (element == NULL, "expected NULL return with FATAL_ERRORS");
722 }
723 
724 GST_END_TEST;
725 
GST_START_TEST(test_parsing)726 GST_START_TEST (test_parsing)
727 {
728   GstElement *pipeline;
729 
730   /* make sure we don't read beyond the end of the string */
731   pipeline = gst_parse_launch_full ("filesrc location=x\\", NULL, 0, NULL);
732   gst_object_unref (pipeline);
733 }
734 
735 GST_END_TEST;
736 
737 static Suite *
parse_suite(void)738 parse_suite (void)
739 {
740   Suite *s = suite_create ("Parse Launch syntax");
741   TCase *tc_chain = tcase_create ("parselaunch");
742 
743   /* time out after 20s, not the default 3 */
744   tcase_set_timeout (tc_chain, 20);
745 
746   suite_add_tcase (s, tc_chain);
747   tcase_add_test (tc_chain, test_launch_lines);
748   tcase_add_test (tc_chain, test_launch_lines2);
749   tcase_add_test (tc_chain, expected_to_fail_pipes);
750   tcase_add_test (tc_chain, leaking_fail_pipes);
751   tcase_add_test (tc_chain, delayed_link);
752   tcase_add_test (tc_chain, test_flags);
753   tcase_add_test (tc_chain, test_missing_elements);
754   tcase_add_test (tc_chain, test_parsing);
755   tcase_add_test (tc_chain, test_preset);
756   return s;
757 }
758 
759 GST_CHECK_MAIN (parse);
760