| /* GStreamer gst_parse_launch unit tests |
| * Copyright (C) <2005> Thomas Vander Stichele <thomas at apestaart dot org> |
| * Copyright (C) <2008> Tim-Philipp Müller <tim centricular net> |
| * |
| * This library is free software; you can redistribute it and/or |
| * modify it under the terms of the GNU Library General Public |
| * License as published by the Free Software Foundation; either |
| * version 2 of the License, or (at your option) any later version. |
| * |
| * This library is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| * Library General Public License for more details. |
| * |
| * You should have received a copy of the GNU Library General Public |
| * License along with this library; if not, write to the |
| * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, |
| * Boston, MA 02110-1301, USA. |
| */ |
| |
| #ifdef HAVE_CONFIG_H |
| # include "config.h" |
| #endif |
| |
| #ifdef HAVE_VALGRIND_H |
| # include <valgrind/valgrind.h> |
| # include <valgrind/memcheck.h> |
| #endif |
| |
| #include <gst/check/gstcheck.h> |
| |
| #define GST_TYPE_PARSE_TEST_ELEMENT (gst_parse_test_element_get_type()) |
| static GType gst_parse_test_element_get_type (void); |
| |
| static GstElement * |
| setup_pipeline (const gchar * pipe_descr) |
| { |
| GstElement *pipeline; |
| GError *error = NULL; |
| |
| GST_DEBUG ("creating [%s] setup_pipeline", pipe_descr); |
| |
| pipeline = gst_parse_launch (pipe_descr, &error); |
| |
| GST_DEBUG ("created [%s] setup_pipeline", pipe_descr); |
| |
| if (error != NULL) { |
| fail_if (error != NULL, "Error parsing pipeline %s: %s", pipe_descr, |
| error->message); |
| g_error_free (error); |
| } |
| fail_unless (pipeline != NULL, "Failed to create pipeline %s", pipe_descr); |
| /* Newly returned object should be floating reffed */ |
| fail_unless (g_object_is_floating (pipeline)); |
| g_assert_cmpuint (G_OBJECT (pipeline)->ref_count, ==, 1); |
| return pipeline; |
| } |
| |
| static void |
| expected_fail_pipe (const gchar * pipe_descr) |
| { |
| GstElement *pipeline; |
| GError *error = NULL; |
| |
| #ifndef GST_DISABLE_GST_DEBUG |
| gst_debug_set_default_threshold (GST_LEVEL_NONE); |
| #endif |
| |
| pipeline = gst_parse_launch (pipe_descr, &error); |
| fail_unless (pipeline == NULL || error != NULL, |
| "Expected failure pipeline %s: succeeded!", pipe_descr); |
| g_error_free (error); |
| |
| /* We get a pipeline back even when parsing has failed, sometimes! */ |
| if (pipeline) |
| gst_object_unref (pipeline); |
| } |
| |
| static void |
| check_pipeline_runs (GstElement * p) |
| { |
| GstStateChangeReturn ret; |
| |
| /* Check that the pipeline changes state to PAUSED and back to NULL */ |
| ret = gst_element_set_state (p, GST_STATE_PAUSED); |
| if (ret == GST_STATE_CHANGE_ASYNC) |
| ret = gst_element_get_state (p, NULL, NULL, GST_CLOCK_TIME_NONE); |
| fail_unless (ret != GST_STATE_CHANGE_FAILURE, |
| "Could not set pipeline to paused"); |
| |
| ret = gst_element_set_state (p, GST_STATE_NULL); |
| if (ret == GST_STATE_CHANGE_ASYNC) |
| ret = gst_element_get_state (p, NULL, NULL, GST_CLOCK_TIME_NONE); |
| fail_unless (ret != GST_STATE_CHANGE_FAILURE, |
| "Could not set pipeline to null"); |
| } |
| |
| static const gchar *test_lines[] = { |
| "filesrc location=music.mp3 ! identity silent=true ! fakesink silent=true", |
| "filesrc location=music.ogg ! tee ! identity silent=true ! identity silent=true ! fakesink silent=true", |
| "filesrc location=http://domain.com/music.mp3 ! identity silent=true ! fakesink silent=true", |
| "filesrc location=movie.avi ! tee name=demuxer ! ( queue ! identity silent=true ! fakesink silent=true ) ( demuxer. ! queue ! identity silent=true ! fakesink silent=true )", |
| "fakesrc ! video/x-raw ! fakesink silent=true", |
| "fakesrc ! video/raw, format=(string)YUY2; video/raw, format=(string)YV12 ! fakesink silent=true", |
| "fakesrc ! audio/x-raw, width=[16, 32], depth={16, 24, 32}, signed=TRUE ! fakesink silent=true", |
| "fakesrc ! identity silent=true ! identity silent=true ! identity silent=true ! fakesink silent=true", |
| "fakesrc name=100 fakesink name=101 silent=true 100. ! 101.", /* linking with named reference on both sides */ |
| "fakesrc ! 1__dentity ! fakesink silent=true", /* using a freshly registered element type */ |
| "fakesrc ! tee name=t t.src_12 ! queue ! fakesink t.src_3 ! queue ! fakesink", |
| "fakesrc name=foo name=fin fin. ! fakesink", /* testing assignments are executed in correct order (left-to-right) */ |
| "( fakesrc ) ! fakesink", /* ghostPad creation on-the-fly, infix notation link */ |
| "( fakesrc name=dasrc ) dasrc. ! fakesink", /* ghostPad creation on-the-fly, named link */ |
| /* "(name=mabin fakesrc) mabin. ! fakesink", FIXME: linking to named bin does not work yet */ |
| /* "(name=mabin name=yoyo fakesrc) yoyo. ! fakesink", FIXME: linking to named bin does not work yet */ |
| "deepsrc. ! fakesink fakesrc ! ( identity ! ( identity ! ( identity name=deepsrc ) ) )", /* deep name resolution, multilevel ghostpad creation */ |
| NULL |
| }; |
| |
| GST_START_TEST (test_launch_lines) |
| { |
| GstElement *pipeline; |
| const gchar **s; |
| GType type; |
| GstElementFactory *efac; |
| |
| efac = gst_element_factory_find ("identity"); |
| fail_unless (efac != NULL); |
| efac = |
| GST_ELEMENT_FACTORY (gst_plugin_feature_load (GST_PLUGIN_FEATURE (efac))); |
| fail_unless (efac != NULL); |
| type = gst_element_factory_get_element_type (efac); |
| fail_unless (type != 0); |
| g_object_unref (efac); |
| g_object_unref (efac); |
| fail_unless (gst_element_register (NULL, "1__dentity", GST_RANK_NONE, type)); |
| |
| for (s = test_lines; *s != NULL; s++) { |
| pipeline = setup_pipeline (*s); |
| gst_object_unref (pipeline); |
| } |
| } |
| |
| GST_END_TEST; |
| |
| #define PIPELINE1 "fakesrc" |
| #define PIPELINE2 "fakesrc name=donald num-buffers= 27 silent =TruE sizetype = 3 data= Subbuffer\\ data" |
| #define PIPELINE3 "fakesrc identity silent=true fakesink silent=true" |
| #define PIPELINE4 "fakesrc num-buffers=4 .src ! identity silent=true !.sink identity silent=true .src ! .sink fakesink silent=true" |
| #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" |
| #define PIPELINE6 "pipeline.(name=\"john\" fakesrc num-buffers=4 ! ( bin. ( queue ! identity silent=true !( queue ! fakesink silent=true )) ))" |
| #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." |
| /* aggregator is borked |
| * #define PIPELINE8 "fakesrc num-buffers=4 ! tee name=tee1 .src0,src1 ! .sink0, sink1 aggregator ! fakesink silent=true" |
| * */ |
| #define PIPELINE8 "fakesrc num-buffers=4 ! fakesink silent=true" |
| #define PIPELINE9 "fakesrc num-buffers=4 ! test. fakesink silent=true name=test" |
| #define PIPELINE10 "( fakesrc num-buffers=\"4\" ) ! identity silent=true ! fakesink silent=true" |
| #define PIPELINE11 "fakesink silent=true name = sink identity silent=true name=id ( fakesrc num-buffers=\"4\" ! id. ) id. ! sink." |
| #define PIPELINE12 "file:///tmp/test.file ! fakesink silent=true" |
| #define PIPELINE13 "fakesrc ! file:///tmp/test.file" |
| #define PIPELINE14 "capsfilter caps=application/x-rtp,sprop-parameter-sets=(string)\"x\\,x\"" |
| #define PIPELINE15 "capsfilter caps=application/x-rtp,sprop-parameter-sets=(string)\"x\\\"x\\,x\"" |
| |
| GST_START_TEST (test_launch_lines2) |
| { |
| GstElement *cur; |
| gint i; |
| gboolean b; |
| gchar *s = NULL; |
| |
| /** |
| * checks: |
| * - specifying an element works :) |
| * - if only 1 element is requested, no bin is returned, but the element |
| */ |
| cur = setup_pipeline (PIPELINE1); |
| fail_unless (G_OBJECT_TYPE (cur) == g_type_from_name ("GstFakeSrc"), |
| "parse_launch did not produce a fakesrc"); |
| gst_object_unref (cur); |
| |
| /** |
| * checks: |
| * - properties works |
| * - string, int, boolean and enums can be properly set |
| * - first test of escaping strings |
| */ |
| cur = setup_pipeline (PIPELINE2); |
| g_object_get (G_OBJECT (cur), "name", &s, "num-buffers", &i, |
| "silent", &b, NULL); |
| fail_if (s == NULL, "name was NULL"); |
| fail_unless (strcmp (s, "donald") == 0, "fakesrc name was not 'donald'"); |
| fail_unless (i == 27, "num-buffers was not 27"); |
| fail_unless (b == TRUE, "silent was not TRUE"); |
| g_free (s); |
| |
| g_object_get (G_OBJECT (cur), "sizetype", &i, NULL); |
| fail_unless (i == 3, "sizetype != 3"); |
| |
| g_object_get (G_OBJECT (cur), "data", &i, NULL); |
| fail_unless (i == 2, "data != 2"); |
| gst_object_unref (cur); |
| |
| /** |
| * checks: |
| * - specifying multiple elements without links works |
| * - if multiple toplevel elements exist, a pipeline is returned |
| */ |
| cur = setup_pipeline (PIPELINE3); |
| fail_unless (GST_BIN_NUMCHILDREN (cur) == 3, |
| "Pipeline does not contain 3 children"); |
| gst_object_unref (cur); |
| |
| /** |
| * checks: |
| * - test default link "!" |
| * - test if specifying pads on links works |
| */ |
| cur = setup_pipeline (PIPELINE4); |
| check_pipeline_runs (cur); |
| gst_object_unref (cur); |
| |
| /** |
| * checks: |
| * - test if appending the links works, too |
| * - check if the pipeline constructed works the same as the one before (how?) |
| */ |
| cur = setup_pipeline (PIPELINE5); |
| check_pipeline_runs (cur); |
| gst_object_unref (cur); |
| |
| /** |
| * checks: |
| * - test various types of bins |
| * - test if linking across bins works |
| * - test if escaping strings works |
| */ |
| cur = setup_pipeline (PIPELINE6); |
| /* FIXME: valgrind finds element later */ |
| fail_unless (GST_IS_PIPELINE (cur), "Parse did not produce a pipeline"); |
| g_object_get (G_OBJECT (cur), "name", &s, NULL); |
| fail_if (s == NULL, "name was NULL"); |
| fail_unless (strcmp (s, "john") == 0, "Name was not 'john'"); |
| g_free (s); |
| check_pipeline_runs (cur); |
| gst_object_unref (cur); |
| |
| /** |
| * checks: |
| * - test request pads |
| */ |
| cur = setup_pipeline (PIPELINE7); |
| check_pipeline_runs (cur); |
| gst_object_unref (cur); |
| |
| /** |
| * checks: |
| * - multiple pads on 1 link |
| */ |
| cur = setup_pipeline (PIPELINE8); |
| check_pipeline_runs (cur); |
| gst_object_unref (cur); |
| |
| /** |
| * checks: |
| * - failed in grammar.y cvs version 1.17 |
| */ |
| cur = setup_pipeline (PIPELINE9); |
| check_pipeline_runs (cur); |
| gst_object_unref (cur); |
| |
| /** |
| * checks: |
| * - failed in grammar.y cvs version 1.17 |
| */ |
| cur = setup_pipeline (PIPELINE10); |
| check_pipeline_runs (cur); |
| gst_object_unref (cur); |
| |
| /** |
| * checks: |
| * - failed in grammar.y cvs version 1.18 |
| */ |
| cur = setup_pipeline (PIPELINE11); |
| check_pipeline_runs (cur); |
| gst_object_unref (cur); |
| |
| /** |
| * checks: |
| * - URI detection works |
| */ |
| cur = setup_pipeline (PIPELINE12); |
| gst_object_unref (cur); |
| |
| /** * checks: |
| * - URI sink detection works |
| */ |
| cur = setup_pipeline (PIPELINE13); |
| gst_object_unref (cur); |
| |
| /** |
| * Checks if characters inside quotes are not escaped. |
| */ |
| cur = setup_pipeline (PIPELINE14); |
| gst_object_unref (cur); |
| |
| /** |
| * Checks if escaped quotes inside quotes are not treated as end string quotes. |
| * This would make the rest of characters to be escaped incorrectly. |
| */ |
| cur = setup_pipeline (PIPELINE15); |
| gst_object_unref (cur); |
| } |
| |
| GST_END_TEST; |
| |
| static const gchar *expected_failures[] = { |
| /* checks: fails because a=b. is not a valid element reference in parse.l */ |
| "fakesrc num-buffers=4 name=\"a=b\" a=b. ! fakesink silent=true", |
| /* checks: Error branch for a non-deserialisable property value */ |
| "filesrc blocksize=absdff", |
| /* checks: That broken caps which don't parse can't create a pipeline */ |
| "fakesrc ! video/raw,format=(antwerp)monkeys ! fakesink silent=true", |
| /* checks: Empty pipeline is invalid */ |
| "", |
| /* checks: Link without sink element failes */ |
| "fakesrc ! ", |
| /* checks: Link without src element failes */ |
| " ! fakesink silent=true", |
| /* checks: Source URI for which no element exists is a failure */ |
| "borky://fdaffd ! fakesink silent=true", |
| /* checks: Sink URI for which no element exists is a failure */ |
| "fakesrc ! borky://fdaffd", |
| /* checks: Referencing non-existent source element by name can't link */ |
| "fakesrc name=src fakesink silent=true name=sink noexiste. ! sink.", |
| /* checks: Referencing non-existent sink element by name can't link */ |
| "fakesrc name=src fakesink silent=true name=sink src. ! noexiste.", |
| /* checks: Can't link 2 elements that only have sink pads */ |
| "fakesink silent=true ! fakesink silent=true", |
| /* checks multi-chain link without src element fails. */ |
| "! identity silent=true ! identity silent=true ! fakesink silent=true", |
| /* Empty bin not allowed */ |
| "bin.( )", |
| /* bin with non-existent element counts as empty, and not allowed */ |
| "bin.( non_existent_element )", |
| /* bin with an element, assignments and then a syntax error */ |
| "( filesrc blocksize=4 location=/dev/null @ )", |
| /* bin linking with the ! inside the bin and no ! outside */ |
| "( fakesrc num-buffers=\"4\" ! ) identity silent=true ! fakesink silent=true", |
| /* bins with linking without ! */ |
| /* FIXME: one element leaks as reported by valgrind */ |
| "pipeline.(name=\"john\" fakesrc num-buffers=4 ( bin. ( ! queue ! identity silent=true !( queue ! fakesink silent=true )) ))", |
| /* non-existent bin-type containing already created elements */ |
| "coffeebin.( fakesrc ! identity ! fakesink )", |
| /* non-existent bin-type in pipeline */ |
| "fakesrc ! coffeebin.( identity ) ! fakesink", |
| /* unexpected pad references Part I */ |
| "fakesrc ! .ch0 .ch1 fakesink", |
| /* unexpected pad references Part II */ |
| "fakesrc .ch0 .ch1 ! fakesink", |
| /* unexpected pad references Part III */ |
| "(fakesrc .ch1) ! fakesink", |
| /* unexpected full reference, I */ |
| "(fakesrc name=s s.ch1) ! fakesink", |
| /* unexpected full reference, II */ |
| "s.ch1 fakesrc ! fakesink", |
| /* unexpected full reference, III */ |
| "fakesrc ! fakesink s.ch1", |
| /* unlinked src/sink URI */ |
| "http://eff.org fakesrc ! fakesink", |
| /* catch assignments evaluated in wrong order */ |
| "fakesrc name=ss name=st ss. ! fakesink", |
| /* unbalanced brackets */ |
| "(", ")", ") (", |
| /* END: */ |
| NULL |
| }; |
| |
| GST_START_TEST (expected_to_fail_pipes) |
| { |
| const gchar **s; |
| |
| for (s = expected_failures; *s != NULL; s++) { |
| expected_fail_pipe (*s); |
| } |
| } |
| |
| GST_END_TEST; |
| |
| static const gchar *leaking_failures[] = { |
| /* checks: Invalid pipeline syntax fails */ |
| "fakesrc ! identity silent=true ! sgsdfagfd @ gfdgfdsgfsgSF", |
| /* checks: Attempting to link to a non-existent pad on an element |
| * created via URI handler should fail */ |
| "fakesrc ! .foo file:///dev/null", |
| /* checks: That requesting an element which doesn't exist doesn't work */ |
| "error-does-not-exist-src", |
| NULL |
| }; |
| |
| GST_START_TEST (leaking_fail_pipes) |
| { |
| const gchar **s; |
| |
| for (s = leaking_failures; *s != NULL; s++) { |
| /* Uncomment if you want to try fixing the leaks */ |
| #if 0 |
| g_print ("Trying pipe: %s\n", *s); |
| expected_fail_pipe (*s); |
| #endif |
| #ifdef HAVE_VALGRIND_H |
| VALGRIND_DO_LEAK_CHECK; |
| #endif |
| } |
| } |
| |
| GST_END_TEST; |
| |
| /* Helper function to test delayed linking support in parse_launch by creating |
| * a test element based on bin, which contains a fakesrc and a sometimes |
| * pad-template, and trying to link to a fakesink. When the bin transitions |
| * to paused it adds a pad, which should get linked to the fakesink */ |
| static void |
| run_delayed_test (const gchar * pipe_str, const gchar * peer, |
| gboolean expect_link) |
| { |
| GstElement *pipe, *src, *sink; |
| GstPad *srcpad, *sinkpad, *peerpad = NULL; |
| |
| pipe = setup_pipeline (pipe_str); |
| |
| src = gst_bin_get_by_name (GST_BIN (pipe), "src"); |
| fail_if (src == NULL, "Test source element was not created"); |
| |
| sink = gst_bin_get_by_name (GST_BIN (pipe), "sink"); |
| fail_if (sink == NULL, "Test sink element was not created"); |
| |
| /* The src should not yet have a src pad */ |
| srcpad = gst_element_get_static_pad (src, "src"); |
| fail_unless (srcpad == NULL, "Source element already has a source pad"); |
| |
| /* Set the state to PAUSED and wait until the src at least reaches that |
| * state */ |
| fail_if (gst_element_set_state (pipe, GST_STATE_PAUSED) == |
| GST_STATE_CHANGE_FAILURE); |
| |
| fail_if (gst_element_get_state (src, NULL, NULL, GST_CLOCK_TIME_NONE) == |
| GST_STATE_CHANGE_FAILURE); |
| |
| /* Now, the source element should have a src pad, and if "peer" was passed, |
| * then the src pad should have gotten linked to the 'sink' pad of that |
| * peer */ |
| srcpad = gst_element_get_static_pad (src, "src"); |
| fail_if (srcpad == NULL, "Source element did not create source pad"); |
| |
| peerpad = gst_pad_get_peer (srcpad); |
| |
| if (expect_link == TRUE) { |
| fail_if (peerpad == NULL, "Source element pad did not get linked"); |
| } else { |
| fail_if (peerpad != NULL, |
| "Source element pad got linked but should not have"); |
| } |
| if (peerpad != NULL) |
| gst_object_unref (peerpad); |
| |
| if (peer != NULL) { |
| GstElement *peer_elem = gst_bin_get_by_name (GST_BIN (pipe), peer); |
| |
| fail_if (peer_elem == NULL, "Could not retrieve peer %s", peer); |
| |
| sinkpad = gst_element_get_static_pad (peer_elem, "sink"); |
| gst_object_unref (peer_elem); |
| fail_if (sinkpad == NULL, "Peer element did not have a 'sink' pad"); |
| |
| fail_unless (peerpad == sinkpad, |
| "Source src pad got connected to the wrong peer"); |
| gst_object_unref (sinkpad); |
| } |
| |
| gst_object_unref (srcpad); |
| |
| gst_object_unref (src); |
| gst_object_unref (sink); |
| |
| gst_element_set_state (pipe, GST_STATE_NULL); |
| gst_object_unref (pipe); |
| } |
| |
| GST_START_TEST (delayed_link) |
| { |
| fail_unless (gst_element_register (NULL, "parsetestelement", |
| GST_RANK_NONE, GST_TYPE_PARSE_TEST_ELEMENT)); |
| |
| /* This tests the delayed linking support in parse_launch by creating |
| * a test element based on bin, which contains a fakesrc and a sometimes |
| * pad-template, and trying to link to a fakesink. When the bin transitions |
| * to paused it adds a pad, which should get linked to the fakesink */ |
| run_delayed_test |
| ("parsetestelement name=src ! fakesink silent=true name=sink", "sink", |
| TRUE); |
| /* FIXME: valgrind finds one element */ |
| |
| /* Test, but this time specifying both pad names */ |
| run_delayed_test ("parsetestelement name=src .src ! " |
| ".sink fakesink silent=true name=sink", "sink", TRUE); |
| /* FIXME: valgrind finds one element */ |
| |
| /* Now try with a caps filter, but not testing that |
| * the peerpad == sinkpad, because the peer will actually |
| * be a capsfilter */ |
| run_delayed_test ("parsetestelement name=src ! application/x-test-caps ! " |
| "fakesink silent=true name=sink", NULL, TRUE); |
| |
| /* Now try with mutually exclusive caps filters that |
| * will prevent linking, but only once gets around to happening - |
| * ie, the pipeline should create ok but fail to change state */ |
| run_delayed_test ("parsetestelement name=src ! application/x-test-caps ! " |
| "identity silent=true ! application/x-other-caps ! " |
| "fakesink silent=true name=sink silent=true", NULL, FALSE); |
| } |
| |
| GST_END_TEST; |
| |
| typedef struct _GstParseTestElement |
| { |
| GstBin parent; |
| |
| GstElement *fakesrc; |
| } GstParseTestElement; |
| |
| typedef struct _GstParseTestElementClass |
| { |
| GstBinClass parent; |
| } GstParseTestElementClass; |
| |
| static GstStaticPadTemplate test_element_pad_template = |
| GST_STATIC_PAD_TEMPLATE ("src", GST_PAD_SRC, |
| GST_PAD_SOMETIMES, GST_STATIC_CAPS ("application/x-test-caps")); |
| #define gst_parse_test_element_parent_class parent_class |
| G_DEFINE_TYPE (GstParseTestElement, gst_parse_test_element, GST_TYPE_BIN); |
| |
| static GstStateChangeReturn |
| gst_parse_test_element_change_state (GstElement * element, |
| GstStateChange transition); |
| |
| static void |
| gst_parse_test_element_class_init (GstParseTestElementClass * klass) |
| { |
| GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass); |
| |
| gst_element_class_add_static_pad_template (gstelement_class, |
| &test_element_pad_template); |
| |
| gst_element_class_set_metadata (gstelement_class, |
| "Test element for parse launch tests", "Source", |
| "Test element for parse launch tests in core", |
| "GStreamer Devel <gstreamer-devel@lists.sf.net>"); |
| |
| gstelement_class->change_state = gst_parse_test_element_change_state; |
| } |
| |
| static void |
| gst_parse_test_element_init (GstParseTestElement * src) |
| { |
| /* Create a fakesrc and add it to ourselves */ |
| src->fakesrc = gst_element_factory_make ("fakesrc", NULL); |
| if (src->fakesrc) |
| gst_bin_add (GST_BIN (src), src->fakesrc); |
| } |
| |
| static GstStateChangeReturn |
| gst_parse_test_element_change_state (GstElement * element, |
| GstStateChange transition) |
| { |
| GstParseTestElement *src = (GstParseTestElement *) element; |
| |
| if (transition == GST_STATE_CHANGE_READY_TO_PAUSED) { |
| /* Add our pad */ |
| GstPad *pad; |
| GstPad *ghost; |
| |
| if (src->fakesrc == NULL) |
| return GST_STATE_CHANGE_FAILURE; |
| |
| pad = gst_element_get_static_pad (src->fakesrc, "src"); |
| if (pad == NULL) |
| return GST_STATE_CHANGE_FAILURE; |
| |
| ghost = gst_ghost_pad_new ("src", pad); |
| fail_if (ghost == NULL, "Failed to create ghost pad"); |
| /* activate and add */ |
| gst_pad_set_active (ghost, TRUE); |
| gst_element_add_pad (GST_ELEMENT (src), ghost); |
| gst_object_unref (pad); |
| } |
| |
| return GST_ELEMENT_CLASS (parent_class)->change_state (element, transition); |
| } |
| |
| GST_START_TEST (test_missing_elements) |
| { |
| GstParseContext *ctx; |
| GstElement *element; |
| GError *err = NULL; |
| gchar **arr; |
| |
| /* avoid misleading 'no such element' error debug messages when using cvs */ |
| if (!g_getenv ("GST_DEBUG")) |
| gst_debug_set_default_threshold (GST_LEVEL_NONE); |
| |
| /* one missing element */ |
| ctx = gst_parse_context_new (); |
| element = gst_parse_launch_full ("fakesrc ! coffeesink", ctx, |
| GST_PARSE_FLAG_FATAL_ERRORS, &err); |
| fail_unless (err != NULL, "expected error"); |
| fail_unless_equals_int (err->code, GST_PARSE_ERROR_NO_SUCH_ELEMENT); |
| fail_unless (element == NULL, "expected NULL return with FATAL_ERRORS"); |
| arr = gst_parse_context_get_missing_elements (ctx); |
| fail_unless (arr != NULL, "expected missing elements"); |
| fail_unless_equals_string (arr[0], "coffeesink"); |
| fail_unless (arr[1] == NULL); |
| g_strfreev (arr); |
| gst_parse_context_free (ctx); |
| g_error_free (err); |
| err = NULL; |
| |
| /* multiple missing elements */ |
| ctx = gst_parse_context_new (); |
| element = gst_parse_launch_full ("fakesrc ! bogusenc ! identity ! goomux ! " |
| "fakesink", ctx, GST_PARSE_FLAG_FATAL_ERRORS, &err); |
| fail_unless (err != NULL, "expected error"); |
| fail_unless_equals_int (err->code, GST_PARSE_ERROR_NO_SUCH_ELEMENT); |
| fail_unless (element == NULL, "expected NULL return with FATAL_ERRORS"); |
| arr = gst_parse_context_get_missing_elements (ctx); |
| fail_unless (arr != NULL, "expected missing elements"); |
| fail_unless_equals_string (arr[0], "bogusenc"); |
| fail_unless_equals_string (arr[1], "goomux"); |
| fail_unless (arr[2] == NULL); |
| g_strfreev (arr); |
| gst_parse_context_free (ctx); |
| g_error_free (err); |
| err = NULL; |
| |
| /* multiple missing elements, different link pattern */ |
| ctx = gst_parse_context_new (); |
| element = gst_parse_launch_full ("fakesrc ! bogusenc ! mux.sink " |
| "blahsrc ! goomux name=mux ! fakesink fakesrc ! goosink", ctx, |
| GST_PARSE_FLAG_FATAL_ERRORS, &err); |
| fail_unless (err != NULL, "expected error"); |
| fail_unless_equals_int (err->code, GST_PARSE_ERROR_NO_SUCH_ELEMENT); |
| fail_unless (element == NULL, "expected NULL return with FATAL_ERRORS"); |
| arr = gst_parse_context_get_missing_elements (ctx); |
| fail_unless (arr != NULL, "expected missing elements"); |
| fail_unless_equals_string (arr[0], "bogusenc"); |
| fail_unless_equals_string (arr[1], "blahsrc"); |
| fail_unless_equals_string (arr[2], "goomux"); |
| fail_unless_equals_string (arr[3], "goosink"); |
| fail_unless (arr[4] == NULL); |
| g_strfreev (arr); |
| gst_parse_context_free (ctx); |
| g_error_free (err); |
| err = NULL; |
| } |
| |
| GST_END_TEST; |
| |
| GST_START_TEST (test_flags) |
| { |
| GstElement *element; |
| GError *err = NULL; |
| |
| /* avoid misleading 'no such element' error debug messages when using cvs */ |
| if (!g_getenv ("GST_DEBUG")) |
| gst_debug_set_default_threshold (GST_LEVEL_NONE); |
| |
| /* default behaviour is to return any already constructed bins/elements */ |
| element = gst_parse_launch_full ("fakesrc ! coffeesink", NULL, 0, &err); |
| fail_unless (err != NULL, "expected error"); |
| fail_unless_equals_int (err->code, GST_PARSE_ERROR_NO_SUCH_ELEMENT); |
| fail_unless (element != NULL, "expected partial pipeline/element"); |
| g_error_free (err); |
| err = NULL; |
| gst_object_unref (element); |
| |
| /* test GST_PARSE_FLAG_FATAL_ERRORS */ |
| element = gst_parse_launch_full ("fakesrc ! coffeesink", NULL, |
| GST_PARSE_FLAG_FATAL_ERRORS, &err); |
| fail_unless (err != NULL, "expected error"); |
| fail_unless_equals_int (err->code, GST_PARSE_ERROR_NO_SUCH_ELEMENT); |
| fail_unless (element == NULL, "expected NULL return with FATAL_ERRORS"); |
| g_error_free (err); |
| err = NULL; |
| |
| /* test GST_PARSE_FLAG_FATAL_ERRORS without GError */ |
| element = gst_parse_launch_full ("fakesrc ! coffeesink", NULL, |
| GST_PARSE_FLAG_FATAL_ERRORS, NULL); |
| fail_unless (element == NULL, "expected NULL return with FATAL_ERRORS"); |
| } |
| |
| GST_END_TEST; |
| |
| GST_START_TEST (test_parsing) |
| { |
| GstElement *pipeline; |
| |
| /* make sure we don't read beyond the end of the string */ |
| pipeline = gst_parse_launch_full ("filesrc location=x\\", NULL, 0, NULL); |
| gst_object_unref (pipeline); |
| } |
| |
| GST_END_TEST; |
| |
| static Suite * |
| parse_suite (void) |
| { |
| Suite *s = suite_create ("Parse Launch syntax"); |
| TCase *tc_chain = tcase_create ("parselaunch"); |
| |
| /* time out after 20s, not the default 3 */ |
| tcase_set_timeout (tc_chain, 20); |
| |
| suite_add_tcase (s, tc_chain); |
| tcase_add_test (tc_chain, test_launch_lines); |
| tcase_add_test (tc_chain, test_launch_lines2); |
| tcase_add_test (tc_chain, expected_to_fail_pipes); |
| tcase_add_test (tc_chain, leaking_fail_pipes); |
| tcase_add_test (tc_chain, delayed_link); |
| tcase_add_test (tc_chain, test_flags); |
| tcase_add_test (tc_chain, test_missing_elements); |
| tcase_add_test (tc_chain, test_parsing); |
| return s; |
| } |
| |
| GST_CHECK_MAIN (parse); |