check/gst/gstbin.c: Added test to check state change order in bins (can still be...
[platform/upstream/gstreamer.git] / tests / check / gst / gstbin.c
1 /* GStreamer
2  * Copyright (C) 2005 Wim Taymans <wim@fluendo.com>
3  * Copyright (C) 2005 Thomas Vander Stichele <thomas at apestaart dot org>
4  *
5  * gstbin.c: Unit test for GstBin
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Library General Public
9  * License as published by the Free Software Foundation; either
10  * version 2 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Library General Public License for more details.
16  *
17  * You should have received a copy of the GNU Library General Public
18  * License along with this library; if not, write to the
19  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20  * Boston, MA 02111-1307, USA.
21  */
22
23 #include <gst/check/gstcheck.h>
24
25 static void
26 pop_messages (GstBus * bus, int count)
27 {
28   GstMessage *message;
29
30   int i;
31
32   GST_DEBUG ("popping %d messages", count);
33   for (i = 0; i < count; ++i) {
34     message = gst_bus_poll (bus, GST_MESSAGE_STATE_CHANGED, -1);
35
36     fail_unless (message && GST_MESSAGE_TYPE (message)
37         == GST_MESSAGE_STATE_CHANGED, "did not get GST_MESSAGE_STATE_CHANGED");
38
39     gst_message_unref (message);
40   }
41   GST_DEBUG ("popped %d messages", count);
42 }
43
44 GST_START_TEST (test_interface)
45 {
46   GstBin *bin, *bin2;
47   GstElement *filesrc;
48   GstIterator *it;
49   gpointer item;
50
51   bin = GST_BIN (gst_bin_new (NULL));
52   fail_unless (bin != NULL, "Could not create bin");
53
54   filesrc = gst_element_factory_make ("filesrc", NULL);
55   fail_unless (filesrc != NULL, "Could not create filesrc");
56   fail_unless (GST_IS_URI_HANDLER (filesrc), "Filesrc not a URI handler");
57   gst_bin_add (bin, filesrc);
58
59   fail_unless (gst_bin_get_by_interface (bin, GST_TYPE_URI_HANDLER) == filesrc);
60   it = gst_bin_iterate_all_by_interface (bin, GST_TYPE_URI_HANDLER);
61   fail_unless (it != NULL);
62   fail_unless (gst_iterator_next (it, &item) == GST_ITERATOR_OK);
63   fail_unless (item == (gpointer) filesrc);
64   fail_unless (gst_iterator_next (it, &item) == GST_ITERATOR_DONE);
65   gst_iterator_free (it);
66
67   gst_bin_add_many (bin,
68       gst_element_factory_make ("identity", NULL),
69       gst_element_factory_make ("identity", NULL),
70       gst_element_factory_make ("identity", NULL), NULL);
71   fail_unless (gst_bin_get_by_interface (bin, GST_TYPE_URI_HANDLER) == filesrc);
72   it = gst_bin_iterate_all_by_interface (bin, GST_TYPE_URI_HANDLER);
73   fail_unless (it != NULL);
74   fail_unless (gst_iterator_next (it, &item) == GST_ITERATOR_OK);
75   fail_unless (item == (gpointer) filesrc);
76   fail_unless (gst_iterator_next (it, &item) == GST_ITERATOR_DONE);
77   gst_iterator_free (it);
78
79   bin2 = bin;
80   bin = GST_BIN (gst_bin_new (NULL));
81   fail_unless (bin != NULL);
82   gst_bin_add_many (bin,
83       gst_element_factory_make ("identity", NULL),
84       gst_element_factory_make ("identity", NULL),
85       GST_ELEMENT (bin2), gst_element_factory_make ("identity", NULL), NULL);
86   fail_unless (gst_bin_get_by_interface (bin, GST_TYPE_URI_HANDLER) == filesrc);
87   it = gst_bin_iterate_all_by_interface (bin, GST_TYPE_URI_HANDLER);
88   fail_unless (gst_iterator_next (it, &item) == GST_ITERATOR_OK);
89   fail_unless (item == (gpointer) filesrc);
90   fail_unless (gst_iterator_next (it, &item) == GST_ITERATOR_DONE);
91   gst_iterator_free (it);
92
93   gst_bin_add (bin, gst_element_factory_make ("filesrc", NULL));
94   gst_bin_add (bin2, gst_element_factory_make ("filesrc", NULL));
95   it = gst_bin_iterate_all_by_interface (bin, GST_TYPE_URI_HANDLER);
96   fail_unless (gst_iterator_next (it, &item) == GST_ITERATOR_OK);
97   fail_unless (gst_iterator_next (it, &item) == GST_ITERATOR_OK);
98   fail_unless (gst_iterator_next (it, &item) == GST_ITERATOR_OK);
99   fail_unless (gst_iterator_next (it, &item) == GST_ITERATOR_DONE);
100   gst_iterator_free (it);
101
102   gst_object_unref (bin);
103 }
104
105 GST_END_TEST;
106
107 GST_START_TEST (test_message_state_changed)
108 {
109   GstBin *bin;
110   GstBus *bus;
111   GstMessage *message;
112
113   bin = GST_BIN (gst_bin_new (NULL));
114   fail_unless (bin != NULL, "Could not create bin");
115   ASSERT_OBJECT_REFCOUNT (bin, "bin", 1);
116
117   bus = GST_ELEMENT_BUS (bin);
118
119   /* change state, spawning a message, causing an incref on the bin */
120   gst_element_set_state (GST_ELEMENT (bin), GST_STATE_READY);
121
122   ASSERT_OBJECT_REFCOUNT (bin, "bin", 2);
123
124   /* get and unref the message, causing a decref on the bin */
125   message = gst_bus_poll (bus, GST_MESSAGE_STATE_CHANGED, -1);
126
127   fail_unless (message && GST_MESSAGE_TYPE (message)
128       == GST_MESSAGE_STATE_CHANGED, "did not get GST_MESSAGE_STATE_CHANGED");
129
130   gst_message_unref (message);
131
132   ASSERT_OBJECT_REFCOUNT (bin, "bin", 1);
133
134   /* clean up */
135   gst_object_unref (bin);
136 }
137
138 GST_END_TEST;
139
140 GST_START_TEST (test_message_state_changed_child)
141 {
142   GstBin *bin;
143   GstElement *src;
144   GstBus *bus;
145   GstMessage *message;
146
147   bin = GST_BIN (gst_bin_new (NULL));
148   fail_unless (bin != NULL, "Could not create bin");
149   ASSERT_OBJECT_REFCOUNT (bin, "bin", 1);
150
151   src = gst_element_factory_make ("fakesrc", NULL);
152   fail_if (src == NULL, "Could not create fakesrc");
153   gst_bin_add (bin, src);
154   ASSERT_OBJECT_REFCOUNT (bin, "bin", 1);
155   ASSERT_OBJECT_REFCOUNT (src, "src", 1);
156
157   bus = GST_ELEMENT_BUS (bin);
158
159   /* change state, spawning two messages:
160    * - first for fakesrc, forwarded to bin's bus, causing incref on fakesrc
161    * - second for bin, causing an incref on the bin */
162   GST_DEBUG ("setting bin to READY");
163   fail_unless (gst_element_set_state (GST_ELEMENT (bin), GST_STATE_READY)
164       == GST_STATE_CHANGE_SUCCESS);
165
166   ASSERT_OBJECT_REFCOUNT (src, "src", 2);
167   ASSERT_OBJECT_REFCOUNT (bin, "bin", 2);
168
169   /* get and unref the message, causing a decref on the src */
170   message = gst_bus_poll (bus, GST_MESSAGE_STATE_CHANGED, -1);
171   fail_unless (message && GST_MESSAGE_TYPE (message)
172       == GST_MESSAGE_STATE_CHANGED, "did not get GST_MESSAGE_STATE_CHANGED");
173
174   fail_unless (message->src == GST_OBJECT (src));
175   gst_message_unref (message);
176
177   ASSERT_OBJECT_REFCOUNT (src, "src", 1);
178   ASSERT_OBJECT_REFCOUNT (bin, "bin", 2);
179
180   /* get and unref message 2, causing a decref on the bin */
181   message = gst_bus_poll (bus, GST_MESSAGE_STATE_CHANGED, -1);
182   fail_unless (message && GST_MESSAGE_TYPE (message)
183       == GST_MESSAGE_STATE_CHANGED, "did not get GST_MESSAGE_STATE_CHANGED");
184
185   fail_unless (message->src == GST_OBJECT (bin));
186   gst_message_unref (message);
187
188   ASSERT_OBJECT_REFCOUNT (src, "src", 1);
189   ASSERT_OBJECT_REFCOUNT (bin, "bin", 1);
190
191   /* clean up */
192   gst_object_unref (bin);
193 }
194
195 GST_END_TEST;
196
197 GST_START_TEST (test_message_state_changed_children)
198 {
199   GstPipeline *pipeline;
200   GstElement *src, *sink;
201   GstBus *bus;
202
203   pipeline = GST_PIPELINE (gst_pipeline_new (NULL));
204   fail_unless (pipeline != NULL, "Could not create pipeline");
205   ASSERT_OBJECT_REFCOUNT (pipeline, "pipeline", 1);
206
207   src = gst_element_factory_make ("fakesrc", NULL);
208   fail_if (src == NULL, "Could not create fakesrc");
209   /* need to silence the element as the deep_notify refcounts the
210    * parents while running */
211   g_object_set (G_OBJECT (src), "silent", TRUE, NULL);
212   gst_bin_add (GST_BIN (pipeline), src);
213
214   sink = gst_element_factory_make ("fakesink", NULL);
215   /* need to silence the element as the deep_notify refcounts the
216    * parents while running */
217   g_object_set (G_OBJECT (sink), "silent", TRUE, NULL);
218   fail_if (sink == NULL, "Could not create fakesink");
219   gst_bin_add (GST_BIN (pipeline), sink);
220
221   fail_unless (gst_element_link (src, sink), "could not link src and sink");
222
223   ASSERT_OBJECT_REFCOUNT (pipeline, "pipeline", 1);
224   ASSERT_OBJECT_REFCOUNT (src, "src", 1);
225   ASSERT_OBJECT_REFCOUNT (sink, "sink", 1);
226
227   bus = GST_ELEMENT_BUS (pipeline);
228
229   /* change state to READY, spawning three messages */
230   GST_DEBUG ("setting pipeline to READY");
231   fail_unless (gst_element_set_state (GST_ELEMENT (pipeline), GST_STATE_READY)
232       == GST_STATE_CHANGE_SUCCESS);
233
234   /* each object is referenced by a message */
235   ASSERT_OBJECT_REFCOUNT (bus, "bus", 1);
236   ASSERT_OBJECT_REFCOUNT (src, "src", 2);
237   ASSERT_OBJECT_REFCOUNT (sink, "sink", 2);
238   ASSERT_OBJECT_REFCOUNT (pipeline, "pipeline", 2);
239
240   pop_messages (bus, 3);
241   fail_if ((gst_bus_pop (bus)) != NULL);
242
243   ASSERT_OBJECT_REFCOUNT (bus, "bus", 1);
244   ASSERT_OBJECT_REFCOUNT (src, "src", 1);
245   ASSERT_OBJECT_REFCOUNT (sink, "sink", 1);
246   ASSERT_OBJECT_REFCOUNT (pipeline, "pipeline", 1);
247
248   /* change state to PAUSED, spawning three messages */
249   GST_DEBUG ("setting pipeline to PAUSED");
250   fail_unless (gst_element_set_state (GST_ELEMENT (pipeline), GST_STATE_PAUSED)
251       == GST_STATE_CHANGE_SUCCESS);
252
253   /* each object is referenced by a message;
254    * base_sink_chain has taken a refcount on the sink, and is blocked on
255    * preroll */
256   ASSERT_OBJECT_REFCOUNT (src, "src", 2);
257   ASSERT_OBJECT_REFCOUNT (sink, "sink", 3);
258   ASSERT_OBJECT_REFCOUNT (pipeline, "pipeline", 2);
259
260   pop_messages (bus, 3);
261   fail_if ((gst_bus_pop (bus)) != NULL);
262
263   ASSERT_OBJECT_REFCOUNT (bus, "bus", 1);
264   ASSERT_OBJECT_REFCOUNT (src, "src", 1);
265   ASSERT_OBJECT_REFCOUNT (sink, "sink", 2);
266   ASSERT_OBJECT_REFCOUNT (pipeline, "pipeline", 1);
267
268   /* change state to PLAYING, spawning three messages */
269   GST_DEBUG ("setting pipeline to PLAYING");
270   fail_unless (gst_element_set_state (GST_ELEMENT (pipeline), GST_STATE_PLAYING)
271       == GST_STATE_CHANGE_SUCCESS);
272
273   /* each object is referenced by one message
274    * sink might have an extra reference if it's still blocked on preroll */
275   ASSERT_OBJECT_REFCOUNT (src, "src", 2);
276   ASSERT_OBJECT_REFCOUNT_BETWEEN (sink, "sink", 2, 3);
277   ASSERT_OBJECT_REFCOUNT (pipeline, "pipeline", 2);
278
279   pop_messages (bus, 3);
280   fail_if ((gst_bus_pop (bus)) != NULL);
281
282   ASSERT_OBJECT_REFCOUNT (bus, "bus", 1);
283   ASSERT_OBJECT_REFCOUNT (src, "src", 1);
284   /* sink might have an extra reference if it's still blocked on preroll */
285   ASSERT_OBJECT_REFCOUNT_BETWEEN (sink, "sink", 1, 2);
286   ASSERT_OBJECT_REFCOUNT (pipeline, "pipeline", 1);
287
288   /* go back to READY, spawning six messages */
289   GST_DEBUG ("setting pipeline to READY");
290   fail_unless (gst_element_set_state (GST_ELEMENT (pipeline), GST_STATE_READY)
291       == GST_STATE_CHANGE_SUCCESS);
292
293   /* each object is referenced by two messages */
294   ASSERT_OBJECT_REFCOUNT (src, "src", 3);
295   ASSERT_OBJECT_REFCOUNT (sink, "sink", 3);
296   ASSERT_OBJECT_REFCOUNT (pipeline, "pipeline", 3);
297
298   pop_messages (bus, 6);
299   fail_if ((gst_bus_pop (bus)) != NULL);
300
301   ASSERT_OBJECT_REFCOUNT (src, "src", 1);
302   ASSERT_OBJECT_REFCOUNT (sink, "sink", 1);
303   ASSERT_OBJECT_REFCOUNT (pipeline, "pipeline", 1);
304
305   /* setting pipeline to NULL flushes the bus automatically */
306   fail_unless (gst_element_set_state (GST_ELEMENT (pipeline), GST_STATE_NULL)
307       == GST_STATE_CHANGE_SUCCESS);
308
309   ASSERT_OBJECT_REFCOUNT (src, "src", 1);
310   ASSERT_OBJECT_REFCOUNT (sink, "sink", 1);
311   ASSERT_OBJECT_REFCOUNT (pipeline, "pipeline", 1);
312
313   /* clean up */
314   gst_object_unref (pipeline);
315 }
316
317 GST_END_TEST;
318
319 GST_START_TEST (test_watch_for_state_change)
320 {
321   GstElement *src, *sink, *bin;
322   GstBus *bus;
323
324   bin = gst_element_factory_make ("bin", NULL);
325   fail_unless (bin != NULL, "Could not create bin");
326
327   src = gst_element_factory_make ("fakesrc", NULL);
328   fail_if (src == NULL, "Could not create fakesrc");
329   sink = gst_element_factory_make ("fakesink", NULL);
330   fail_if (sink == NULL, "Could not create fakesink");
331
332   gst_bin_add (GST_BIN (bin), sink);
333   gst_bin_add (GST_BIN (bin), src);
334
335   fail_unless (gst_element_link (src, sink), "could not link src and sink");
336
337   bus = GST_ELEMENT_BUS (bin);
338
339   /* change state, spawning two times three messages, minus one async */
340   fail_unless (gst_element_set_state (GST_ELEMENT (bin), GST_STATE_PAUSED)
341       == GST_STATE_CHANGE_ASYNC);
342
343   pop_messages (bus, 5);
344
345   fail_unless (gst_bus_have_pending (bus, GST_MESSAGE_ANY) == FALSE,
346       "Unexpected messages on bus");
347
348   gst_bin_watch_for_state_change (GST_BIN (bin));
349
350   /* should get the bin's state change message now */
351   pop_messages (bus, 1);
352
353   fail_unless (gst_bus_have_pending (bus, GST_MESSAGE_ANY) == FALSE,
354       "Unexpected messages on bus");
355
356   fail_unless (gst_element_set_state (GST_ELEMENT (bin), GST_STATE_PLAYING)
357       == GST_STATE_CHANGE_SUCCESS);
358
359   pop_messages (bus, 3);
360
361   /* this one might return either SUCCESS or ASYNC, likely SUCCESS */
362   gst_element_set_state (GST_ELEMENT (bin), GST_STATE_PAUSED);
363
364   gst_bin_watch_for_state_change (GST_BIN (bin));
365
366   pop_messages (bus, 3);
367
368   fail_unless (gst_bus_have_pending (bus, GST_MESSAGE_ANY) == FALSE,
369       "Unexpected messages on bus");
370
371   /* setting bin to NULL flushes the bus automatically */
372   fail_unless (gst_element_set_state (GST_ELEMENT (bin), GST_STATE_NULL)
373       == GST_STATE_CHANGE_SUCCESS);
374
375   /* clean up */
376   gst_object_unref (bin);
377 }
378
379 GST_END_TEST;
380
381 /* adding an element with linked pads to a bin unlinks the
382  * pads */
383 GST_START_TEST (test_add_linked)
384 {
385   GstElement *src, *sink;
386   GstPad *srcpad, *sinkpad;
387   GstElement *pipeline;
388
389   pipeline = gst_pipeline_new (NULL);
390   fail_unless (pipeline != NULL, "Could not create pipeline");
391
392   src = gst_element_factory_make ("fakesrc", NULL);
393   fail_if (src == NULL, "Could not create fakesrc");
394   sink = gst_element_factory_make ("fakesink", NULL);
395   fail_if (sink == NULL, "Could not create fakesink");
396
397   srcpad = gst_element_get_pad (src, "src");
398   fail_unless (srcpad != NULL);
399   sinkpad = gst_element_get_pad (sink, "sink");
400   fail_unless (sinkpad != NULL);
401
402   fail_unless (gst_pad_link (srcpad, sinkpad) == GST_PAD_LINK_OK);
403
404   /* pads are linked now */
405   fail_unless (gst_pad_is_linked (srcpad));
406   fail_unless (gst_pad_is_linked (sinkpad));
407
408   /* adding element to bin voids hierarchy so pads are unlinked */
409   gst_bin_add (GST_BIN (pipeline), src);
410
411   /* check if pads really are unlinked */
412   fail_unless (!gst_pad_is_linked (srcpad));
413   fail_unless (!gst_pad_is_linked (sinkpad));
414
415   /* cannot link pads in wrong hierarchy */
416   fail_unless (gst_pad_link (srcpad, sinkpad) == GST_PAD_LINK_WRONG_HIERARCHY);
417
418   /* adding other element to bin as well */
419   gst_bin_add (GST_BIN (pipeline), sink);
420
421   /* now we can link again */
422   fail_unless (gst_pad_link (srcpad, sinkpad) == GST_PAD_LINK_OK);
423
424   /* check if pads really are linked */
425   fail_unless (gst_pad_is_linked (srcpad));
426   fail_unless (gst_pad_is_linked (sinkpad));
427
428   gst_object_unref (srcpad);
429   gst_object_unref (sinkpad);
430   gst_object_unref (pipeline);
431 }
432
433 GST_END_TEST;
434
435 /* g_print ("%10s: %4d => %4d\n", GST_OBJECT_NAME (msg->src), old, new); */
436
437 #define ASSERT_STATE_CHANGE_MSG(bus,element,old_state,new_state,num)          \
438   {                                                                           \
439     GstMessage *msg;                                                          \
440     GstState old = 0, new = 0;                                                \
441     msg = gst_bus_poll (bus, GST_MESSAGE_STATE_CHANGED, GST_SECOND);          \
442     fail_if (msg == NULL, "No state change message within 1 second (#"        \
443         G_STRINGIFY (num) ")");                                               \
444     gst_message_parse_state_changed (msg, &old, &new);                        \
445     fail_if (msg->src != GST_OBJECT (element), G_STRINGIFY(element)           \
446         " should have changed state next (#" G_STRINGIFY (num) ")");          \
447     fail_if (old != old_state || new != new_state, "state change is not "     \
448         G_STRINGIFY (old_state) " => " G_STRINGIFY (new_state));              \
449     gst_message_unref (msg);                                                  \
450   }
451
452 GST_START_TEST (test_children_state_change_order_flagged_sink)
453 {
454   GstElement *src, *identity, *sink, *pipeline;
455   GstStateChangeReturn ret;
456   GstBus *bus;
457
458   pipeline = gst_pipeline_new (NULL);
459   fail_unless (pipeline != NULL, "Could not create pipeline");
460
461   bus = GST_ELEMENT_BUS (pipeline);
462   fail_unless (bus != NULL, "Pipeline has no bus?!");
463
464   src = gst_element_factory_make ("fakesrc", NULL);
465   fail_if (src == NULL, "Could not create fakesrc");
466
467   identity = gst_element_factory_make ("identity", NULL);
468   fail_if (identity == NULL, "Could not create identity");
469
470   sink = gst_element_factory_make ("fakesink", NULL);
471   fail_if (sink == NULL, "Could not create fakesink");
472
473   gst_bin_add_many (GST_BIN (pipeline), src, identity, sink, NULL);
474
475   fail_unless (gst_element_link (src, identity) == TRUE);
476   fail_unless (gst_element_link (identity, sink) == TRUE);
477
478   /* (1) Test state change with fakesink being a regular sink */
479   ret = gst_element_set_state (pipeline, GST_STATE_PLAYING);
480   fail_if (ret != GST_STATE_CHANGE_SUCCESS, "State change to PLAYING failed");
481
482   /* NULL => READY */
483   ASSERT_STATE_CHANGE_MSG (bus, sink, GST_STATE_NULL, GST_STATE_READY, 101);
484   ASSERT_STATE_CHANGE_MSG (bus, identity, GST_STATE_NULL, GST_STATE_READY, 102);
485   ASSERT_STATE_CHANGE_MSG (bus, src, GST_STATE_NULL, GST_STATE_READY, 103);
486   ASSERT_STATE_CHANGE_MSG (bus, pipeline, GST_STATE_NULL, GST_STATE_READY, 104);
487
488   /* READY => PAUSED */
489   /* because of pre-rolling, sink will return ASYNC on state 
490    * change and change state later when it has a buffer */
491   ASSERT_STATE_CHANGE_MSG (bus, identity, GST_STATE_READY, GST_STATE_PAUSED,
492       105);
493   ASSERT_STATE_CHANGE_MSG (bus, src, GST_STATE_READY, GST_STATE_PAUSED, 106);
494   ASSERT_STATE_CHANGE_MSG (bus, sink, GST_STATE_READY, GST_STATE_PAUSED, 107);
495   ASSERT_STATE_CHANGE_MSG (bus, pipeline, GST_STATE_READY, GST_STATE_PAUSED,
496       108);
497
498   /* PAUSED => PLAYING */
499   ASSERT_STATE_CHANGE_MSG (bus, sink, GST_STATE_PAUSED, GST_STATE_PLAYING, 109);
500   ASSERT_STATE_CHANGE_MSG (bus, identity, GST_STATE_PAUSED, GST_STATE_PLAYING,
501       110);
502   ASSERT_STATE_CHANGE_MSG (bus, src, GST_STATE_PAUSED, GST_STATE_PLAYING, 111);
503   ASSERT_STATE_CHANGE_MSG (bus, pipeline, GST_STATE_PAUSED, GST_STATE_PLAYING,
504       112);
505
506   /* don't set to NULL that will set the bus flushing and kill our messages */
507   ret = gst_element_set_state (pipeline, GST_STATE_READY);
508   fail_if (ret != GST_STATE_CHANGE_SUCCESS, "State change to READY failed");
509
510   /* TODO: do we need to check downwards state change order as well? */
511   pop_messages (bus, 4);        /* pop playing => paused messages off the bus */
512   pop_messages (bus, 4);        /* pop paused => ready messages off the bus */
513
514   ASSERT_OBJECT_REFCOUNT (src, "src", 1);
515   ASSERT_OBJECT_REFCOUNT (sink, "sink", 1);
516   ASSERT_OBJECT_REFCOUNT (pipeline, "pipeline", 1);
517
518   ret = gst_element_set_state (pipeline, GST_STATE_NULL);
519   fail_if (ret != GST_STATE_CHANGE_SUCCESS, "State change to NULL failed");
520
521   ASSERT_OBJECT_REFCOUNT (src, "src", 1);
522   ASSERT_OBJECT_REFCOUNT (sink, "sink", 1);
523   ASSERT_OBJECT_REFCOUNT (pipeline, "pipeline", 1);
524
525   gst_object_unref (pipeline);
526 }
527
528 GST_END_TEST;
529
530
531 GST_START_TEST (test_children_state_change_order_semi_sink)
532 {
533   GstElement *src, *identity, *sink, *pipeline;
534   GstStateChangeReturn ret;
535   GstBus *bus;
536
537   /* (2) Now again, but check other code path where we don't have
538    *     a proper sink correctly flagged as such, but a 'semi-sink' */
539   pipeline = gst_pipeline_new (NULL);
540   fail_unless (pipeline != NULL, "Could not create pipeline");
541
542   bus = GST_ELEMENT_BUS (pipeline);
543   fail_unless (bus != NULL, "Pipeline has no bus?!");
544
545   src = gst_element_factory_make ("fakesrc", NULL);
546   fail_if (src == NULL, "Could not create fakesrc");
547
548   identity = gst_element_factory_make ("identity", NULL);
549   fail_if (identity == NULL, "Could not create identity");
550
551   sink = gst_element_factory_make ("fakesink", NULL);
552   fail_if (sink == NULL, "Could not create fakesink");
553
554   gst_bin_add_many (GST_BIN (pipeline), src, identity, sink, NULL);
555
556   fail_unless (gst_element_link (src, identity) == TRUE);
557   fail_unless (gst_element_link (identity, sink) == TRUE);
558
559   GST_FLAG_UNSET (sink, GST_ELEMENT_IS_SINK);   /* <======== */
560
561   ret = gst_element_set_state (pipeline, GST_STATE_PLAYING);
562   fail_if (ret != GST_STATE_CHANGE_SUCCESS, "State change to PLAYING failed");
563
564   /* NULL => READY */
565   ASSERT_STATE_CHANGE_MSG (bus, sink, GST_STATE_NULL, GST_STATE_READY, 201);
566   ASSERT_STATE_CHANGE_MSG (bus, identity, GST_STATE_NULL, GST_STATE_READY, 202);
567   ASSERT_STATE_CHANGE_MSG (bus, src, GST_STATE_NULL, GST_STATE_READY, 203);
568   ASSERT_STATE_CHANGE_MSG (bus, pipeline, GST_STATE_NULL, GST_STATE_READY, 204);
569
570   /* READY => PAUSED */
571   /* because of pre-rolling, sink will return ASYNC on state 
572    * change and change state later when it has a buffer */
573   ASSERT_STATE_CHANGE_MSG (bus, identity, GST_STATE_READY, GST_STATE_PAUSED,
574       205);
575   ASSERT_STATE_CHANGE_MSG (bus, src, GST_STATE_READY, GST_STATE_PAUSED, 206);
576   ASSERT_STATE_CHANGE_MSG (bus, sink, GST_STATE_READY, GST_STATE_PAUSED, 207);
577   ASSERT_STATE_CHANGE_MSG (bus, pipeline, GST_STATE_READY, GST_STATE_PAUSED,
578       208);
579
580   /* PAUSED => PLAYING */
581   ASSERT_STATE_CHANGE_MSG (bus, sink, GST_STATE_PAUSED, GST_STATE_PLAYING, 209);
582   ASSERT_STATE_CHANGE_MSG (bus, identity, GST_STATE_PAUSED, GST_STATE_PLAYING,
583       210);
584   ASSERT_STATE_CHANGE_MSG (bus, src, GST_STATE_PAUSED, GST_STATE_PLAYING, 211);
585   ASSERT_STATE_CHANGE_MSG (bus, pipeline, GST_STATE_PAUSED, GST_STATE_PLAYING,
586       212);
587
588   /* don't set to NULL that will set the bus flushing and kill our messages */
589   ret = gst_element_set_state (pipeline, GST_STATE_READY);
590   fail_if (ret != GST_STATE_CHANGE_SUCCESS, "State change to READY failed");
591
592   /* TODO: do we need to check downwards state change order as well? */
593   pop_messages (bus, 4);        /* pop playing => paused messages off the bus */
594   pop_messages (bus, 4);        /* pop paused => ready messages off the bus */
595
596   ASSERT_OBJECT_REFCOUNT (src, "src", 1);
597   ASSERT_OBJECT_REFCOUNT (sink, "sink", 1);
598   ASSERT_OBJECT_REFCOUNT (pipeline, "pipeline", 1);
599
600   ret = gst_element_set_state (pipeline, GST_STATE_NULL);
601   fail_if (ret != GST_STATE_CHANGE_SUCCESS, "State change to NULL failed");
602
603   ASSERT_OBJECT_REFCOUNT (src, "src", 1);
604   ASSERT_OBJECT_REFCOUNT (sink, "sink", 1);
605   ASSERT_OBJECT_REFCOUNT (pipeline, "pipeline", 1);
606
607   gst_object_unref (pipeline);
608 }
609
610 GST_END_TEST;
611
612 Suite *
613 gst_bin_suite (void)
614 {
615   Suite *s = suite_create ("GstBin");
616   TCase *tc_chain = tcase_create ("bin tests");
617
618   suite_add_tcase (s, tc_chain);
619   tcase_add_test (tc_chain, test_interface);
620   tcase_add_test (tc_chain, test_children_state_change_order_flagged_sink);
621   tcase_add_test (tc_chain, test_children_state_change_order_semi_sink);
622   tcase_add_test (tc_chain, test_message_state_changed);
623   tcase_add_test (tc_chain, test_message_state_changed_child);
624   tcase_add_test (tc_chain, test_message_state_changed_children);
625   tcase_add_test (tc_chain, test_watch_for_state_change);
626   tcase_add_test (tc_chain, test_add_linked);
627
628   return s;
629 }
630
631 int
632 main (int argc, char **argv)
633 {
634   int nf;
635
636   Suite *s = gst_bin_suite ();
637   SRunner *sr = srunner_create (s);
638
639   gst_check_init (&argc, &argv);
640
641   srunner_run_all (sr, CK_NORMAL);
642   nf = srunner_ntests_failed (sr);
643   srunner_free (sr);
644
645   return nf;
646 }