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 g_object_unref (efac);
133 g_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 failes */
325 "fakesrc ! ",
326 /* checks: Link without src element failes */
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
423 pipe = setup_pipeline (pipe_str);
424
425 src = gst_bin_get_by_name (GST_BIN (pipe), "src");
426 fail_if (src == NULL, "Test source element was not created");
427
428 sink = gst_bin_get_by_name (GST_BIN (pipe), "sink");
429 fail_if (sink == NULL, "Test sink element was not created");
430
431 /* The src should not yet have a src pad */
432 srcpad = gst_element_get_static_pad (src, "src");
433 fail_unless (srcpad == NULL, "Source element already has a source pad");
434
435 /* Set the state to PAUSED and wait until the src at least reaches that
436 * state */
437 fail_if (gst_element_set_state (pipe, GST_STATE_PAUSED) ==
438 GST_STATE_CHANGE_FAILURE);
439
440 fail_if (gst_element_get_state (src, NULL, NULL, GST_CLOCK_TIME_NONE) ==
441 GST_STATE_CHANGE_FAILURE);
442
443 /* Now, the source element should have a src pad, and if "peer" was passed,
444 * then the src pad should have gotten linked to the 'sink' pad of that
445 * peer */
446 srcpad = gst_element_get_static_pad (src, "src");
447 fail_if (srcpad == NULL, "Source element did not create source pad");
448
449 peerpad = gst_pad_get_peer (srcpad);
450
451 if (expect_link == TRUE) {
452 fail_if (peerpad == NULL, "Source element pad did not get linked");
453 } else {
454 fail_if (peerpad != NULL,
455 "Source element pad got linked but should not have");
456 }
457 if (peerpad != NULL)
458 gst_object_unref (peerpad);
459
460 if (peer != NULL) {
461 GstElement *peer_elem = gst_bin_get_by_name (GST_BIN (pipe), peer);
462
463 fail_if (peer_elem == NULL, "Could not retrieve peer %s", peer);
464
465 sinkpad = gst_element_get_static_pad (peer_elem, "sink");
466 gst_object_unref (peer_elem);
467 fail_if (sinkpad == NULL, "Peer element did not have a 'sink' pad");
468
469 fail_unless (peerpad == sinkpad,
470 "Source src pad got connected to the wrong peer");
471 gst_object_unref (sinkpad);
472 }
473
474 gst_object_unref (srcpad);
475
476 gst_object_unref (src);
477 gst_object_unref (sink);
478
479 gst_element_set_state (pipe, GST_STATE_NULL);
480 gst_object_unref (pipe);
481 }
482
GST_START_TEST(delayed_link)483 GST_START_TEST (delayed_link)
484 {
485 fail_unless (gst_element_register (NULL, "parsetestelement",
486 GST_RANK_NONE, GST_TYPE_PARSE_TEST_ELEMENT));
487
488 /* This tests the delayed linking support in parse_launch by creating
489 * a test element based on bin, which contains a fakesrc and a sometimes
490 * pad-template, and trying to link to a fakesink. When the bin transitions
491 * to paused it adds a pad, which should get linked to the fakesink */
492 run_delayed_test
493 ("parsetestelement name=src ! fakesink silent=true name=sink", "sink",
494 TRUE);
495 /* FIXME: valgrind finds one element */
496
497 /* Test, but this time specifying both pad names */
498 run_delayed_test ("parsetestelement name=src .src ! "
499 ".sink fakesink silent=true name=sink", "sink", TRUE);
500 /* FIXME: valgrind finds one element */
501
502 /* Now try with a caps filter, but not testing that
503 * the peerpad == sinkpad, because the peer will actually
504 * be a capsfilter */
505 run_delayed_test ("parsetestelement name=src ! application/x-test-caps ! "
506 "fakesink silent=true name=sink", NULL, TRUE);
507
508 /* Now try with mutually exclusive caps filters that
509 * will prevent linking, but only once gets around to happening -
510 * ie, the pipeline should create ok but fail to change state */
511 run_delayed_test ("parsetestelement name=src ! application/x-test-caps ! "
512 "identity silent=true ! application/x-other-caps ! "
513 "fakesink silent=true name=sink silent=true", NULL, FALSE);
514 }
515
516 GST_END_TEST;
517
518 typedef struct _GstParseTestElement
519 {
520 GstBin parent;
521
522 GstElement *fakesrc;
523 } GstParseTestElement;
524
525 typedef struct _GstParseTestElementClass
526 {
527 GstBinClass parent;
528 } GstParseTestElementClass;
529
530 static GstStaticPadTemplate test_element_pad_template =
531 GST_STATIC_PAD_TEMPLATE ("src", GST_PAD_SRC,
532 GST_PAD_SOMETIMES, GST_STATIC_CAPS ("application/x-test-caps"));
533 #define gst_parse_test_element_parent_class parent_class
534 G_DEFINE_TYPE (GstParseTestElement, gst_parse_test_element, GST_TYPE_BIN);
535
536 static GstStateChangeReturn
537 gst_parse_test_element_change_state (GstElement * element,
538 GstStateChange transition);
539
540 static void
gst_parse_test_element_class_init(GstParseTestElementClass * klass)541 gst_parse_test_element_class_init (GstParseTestElementClass * klass)
542 {
543 GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
544
545 gst_element_class_add_static_pad_template (gstelement_class,
546 &test_element_pad_template);
547
548 gst_element_class_set_metadata (gstelement_class,
549 "Test element for parse launch tests", "Source",
550 "Test element for parse launch tests in core",
551 "GStreamer Devel <gstreamer-devel@lists.sf.net>");
552
553 gstelement_class->change_state = gst_parse_test_element_change_state;
554 }
555
556 static void
gst_parse_test_element_init(GstParseTestElement * src)557 gst_parse_test_element_init (GstParseTestElement * src)
558 {
559 /* Create a fakesrc and add it to ourselves */
560 src->fakesrc = gst_element_factory_make ("fakesrc", NULL);
561 if (src->fakesrc)
562 gst_bin_add (GST_BIN (src), src->fakesrc);
563 }
564
565 static GstStateChangeReturn
gst_parse_test_element_change_state(GstElement * element,GstStateChange transition)566 gst_parse_test_element_change_state (GstElement * element,
567 GstStateChange transition)
568 {
569 GstParseTestElement *src = (GstParseTestElement *) element;
570
571 if (transition == GST_STATE_CHANGE_READY_TO_PAUSED) {
572 /* Add our pad */
573 GstPad *pad;
574 GstPad *ghost;
575
576 if (src->fakesrc == NULL)
577 return GST_STATE_CHANGE_FAILURE;
578
579 pad = gst_element_get_static_pad (src->fakesrc, "src");
580 if (pad == NULL)
581 return GST_STATE_CHANGE_FAILURE;
582
583 ghost = gst_ghost_pad_new ("src", pad);
584 fail_if (ghost == NULL, "Failed to create ghost pad");
585 /* activate and add */
586 gst_pad_set_active (ghost, TRUE);
587 gst_element_add_pad (GST_ELEMENT (src), ghost);
588 gst_object_unref (pad);
589 }
590
591 return GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
592 }
593
GST_START_TEST(test_missing_elements)594 GST_START_TEST (test_missing_elements)
595 {
596 GstParseContext *ctx;
597 GstElement *element;
598 GError *err = NULL;
599 gchar **arr;
600
601 /* avoid misleading 'no such element' error debug messages when using cvs */
602 if (!g_getenv ("GST_DEBUG"))
603 gst_debug_set_default_threshold (GST_LEVEL_NONE);
604
605 /* one missing element */
606 ctx = gst_parse_context_new ();
607 element = gst_parse_launch_full ("fakesrc ! coffeesink", ctx,
608 GST_PARSE_FLAG_FATAL_ERRORS, &err);
609 fail_unless (err != NULL, "expected error");
610 fail_unless_equals_int (err->code, GST_PARSE_ERROR_NO_SUCH_ELEMENT);
611 fail_unless (element == NULL, "expected NULL return with FATAL_ERRORS");
612 arr = gst_parse_context_get_missing_elements (ctx);
613 fail_unless (arr != NULL, "expected missing elements");
614 fail_unless_equals_string (arr[0], "coffeesink");
615 fail_unless (arr[1] == NULL);
616 g_strfreev (arr);
617 gst_parse_context_free (ctx);
618 g_error_free (err);
619 err = NULL;
620
621 /* multiple missing elements */
622 ctx = gst_parse_context_new ();
623 element = gst_parse_launch_full ("fakesrc ! bogusenc ! identity ! goomux ! "
624 "fakesink", ctx, GST_PARSE_FLAG_FATAL_ERRORS, &err);
625 fail_unless (err != NULL, "expected error");
626 fail_unless_equals_int (err->code, GST_PARSE_ERROR_NO_SUCH_ELEMENT);
627 fail_unless (element == NULL, "expected NULL return with FATAL_ERRORS");
628 arr = gst_parse_context_get_missing_elements (ctx);
629 fail_unless (arr != NULL, "expected missing elements");
630 fail_unless_equals_string (arr[0], "bogusenc");
631 fail_unless_equals_string (arr[1], "goomux");
632 fail_unless (arr[2] == NULL);
633 g_strfreev (arr);
634 gst_parse_context_free (ctx);
635 g_error_free (err);
636 err = NULL;
637
638 /* multiple missing elements, different link pattern */
639 ctx = gst_parse_context_new ();
640 element = gst_parse_launch_full ("fakesrc ! bogusenc ! mux.sink "
641 "blahsrc ! goomux name=mux ! fakesink fakesrc ! goosink", ctx,
642 GST_PARSE_FLAG_FATAL_ERRORS, &err);
643 fail_unless (err != NULL, "expected error");
644 fail_unless_equals_int (err->code, GST_PARSE_ERROR_NO_SUCH_ELEMENT);
645 fail_unless (element == NULL, "expected NULL return with FATAL_ERRORS");
646 arr = gst_parse_context_get_missing_elements (ctx);
647 fail_unless (arr != NULL, "expected missing elements");
648 fail_unless_equals_string (arr[0], "bogusenc");
649 fail_unless_equals_string (arr[1], "blahsrc");
650 fail_unless_equals_string (arr[2], "goomux");
651 fail_unless_equals_string (arr[3], "goosink");
652 fail_unless (arr[4] == NULL);
653 g_strfreev (arr);
654 gst_parse_context_free (ctx);
655 g_error_free (err);
656 err = NULL;
657 }
658
659 GST_END_TEST;
660
GST_START_TEST(test_flags)661 GST_START_TEST (test_flags)
662 {
663 GstElement *element;
664 GError *err = NULL;
665
666 /* avoid misleading 'no such element' error debug messages when using cvs */
667 if (!g_getenv ("GST_DEBUG"))
668 gst_debug_set_default_threshold (GST_LEVEL_NONE);
669
670 /* default behaviour is to return any already constructed bins/elements */
671 element = gst_parse_launch_full ("fakesrc ! coffeesink", NULL, 0, &err);
672 fail_unless (err != NULL, "expected error");
673 fail_unless_equals_int (err->code, GST_PARSE_ERROR_NO_SUCH_ELEMENT);
674 fail_unless (element != NULL, "expected partial pipeline/element");
675 g_error_free (err);
676 err = NULL;
677 gst_object_unref (element);
678
679 /* test GST_PARSE_FLAG_FATAL_ERRORS */
680 element = gst_parse_launch_full ("fakesrc ! coffeesink", NULL,
681 GST_PARSE_FLAG_FATAL_ERRORS, &err);
682 fail_unless (err != NULL, "expected error");
683 fail_unless_equals_int (err->code, GST_PARSE_ERROR_NO_SUCH_ELEMENT);
684 fail_unless (element == NULL, "expected NULL return with FATAL_ERRORS");
685 g_error_free (err);
686 err = NULL;
687
688 /* test GST_PARSE_FLAG_FATAL_ERRORS without GError */
689 element = gst_parse_launch_full ("fakesrc ! coffeesink", NULL,
690 GST_PARSE_FLAG_FATAL_ERRORS, NULL);
691 fail_unless (element == NULL, "expected NULL return with FATAL_ERRORS");
692 }
693
694 GST_END_TEST;
695
GST_START_TEST(test_parsing)696 GST_START_TEST (test_parsing)
697 {
698 GstElement *pipeline;
699
700 /* make sure we don't read beyond the end of the string */
701 pipeline = gst_parse_launch_full ("filesrc location=x\\", NULL, 0, NULL);
702 gst_object_unref (pipeline);
703 }
704
705 GST_END_TEST;
706
707 static Suite *
parse_suite(void)708 parse_suite (void)
709 {
710 Suite *s = suite_create ("Parse Launch syntax");
711 TCase *tc_chain = tcase_create ("parselaunch");
712
713 /* time out after 20s, not the default 3 */
714 tcase_set_timeout (tc_chain, 20);
715
716 suite_add_tcase (s, tc_chain);
717 tcase_add_test (tc_chain, test_launch_lines);
718 tcase_add_test (tc_chain, test_launch_lines2);
719 tcase_add_test (tc_chain, expected_to_fail_pipes);
720 tcase_add_test (tc_chain, leaking_fail_pipes);
721 tcase_add_test (tc_chain, delayed_link);
722 tcase_add_test (tc_chain, test_flags);
723 tcase_add_test (tc_chain, test_missing_elements);
724 tcase_add_test (tc_chain, test_parsing);
725 return s;
726 }
727
728 GST_CHECK_MAIN (parse);
729