check/: I wrote a test!
[platform/upstream/gstreamer.git] / tests / check / gst / gstevents.c
1 /* GStreamer
2  * Copyright (C) 2005 Jan Schmidt <thaytan@mad.scientist.com>
3  *
4  * gstevents.c: Unit test for event handling
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Library General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Library General Public License for more details.
15  *
16  * You should have received a copy of the GNU Library General Public
17  * License along with this library; if not, write to the
18  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19  * Boston, MA 02111-1307, USA.
20  */
21
22
23 #include "../gstcheck.h"
24
25 GST_START_TEST (create_custom_events)
26 {
27   GstEvent *event, *event2;
28   GstStructure *structure;
29
30   /* FLUSH_START */
31   {
32     event = gst_event_new_flush_start ();
33     fail_if (event == NULL);
34     fail_unless (GST_EVENT_TYPE (event) == GST_EVENT_FLUSH_START);
35     fail_unless (GST_EVENT_IS_UPSTREAM (event));
36     fail_unless (GST_EVENT_IS_DOWNSTREAM (event));
37     fail_if (GST_EVENT_IS_SERIALIZED (event));
38     gst_event_unref (event);
39   }
40   /* FLUSH_STOP */
41   {
42     event = gst_event_new_flush_stop ();
43     fail_if (event == NULL);
44     fail_unless (GST_EVENT_TYPE (event) == GST_EVENT_FLUSH_STOP);
45     fail_unless (GST_EVENT_IS_UPSTREAM (event));
46     fail_unless (GST_EVENT_IS_DOWNSTREAM (event));
47     fail_if (GST_EVENT_IS_SERIALIZED (event));
48     gst_event_unref (event);
49   }
50   /* EOS */
51   {
52     event = gst_event_new_eos ();
53     fail_if (event == NULL);
54     fail_unless (GST_EVENT_TYPE (event) == GST_EVENT_EOS);
55     fail_if (GST_EVENT_IS_UPSTREAM (event));
56     fail_unless (GST_EVENT_IS_DOWNSTREAM (event));
57     fail_unless (GST_EVENT_IS_SERIALIZED (event));
58     gst_event_unref (event);
59   }
60   /* NEWSEGMENT */
61   {
62     gdouble rate;
63     GstFormat format;
64     gint64 start, end, base;
65
66     event = gst_event_new_newsegment (0.5, GST_FORMAT_TIME, 1, G_MAXINT64,
67         0xdeadbeef);
68     fail_if (event == NULL);
69     fail_unless (GST_EVENT_TYPE (event) == GST_EVENT_NEWSEGMENT);
70     fail_if (GST_EVENT_IS_UPSTREAM (event));
71     fail_unless (GST_EVENT_IS_DOWNSTREAM (event));
72     fail_unless (GST_EVENT_IS_SERIALIZED (event));
73
74     gst_event_parse_newsegment (event, &rate, &format, &start, &end, &base);
75     fail_unless (rate == 0.5);
76     fail_unless (format == GST_FORMAT_TIME);
77     fail_unless (start == 1);
78     fail_unless (end == G_MAXINT64);
79     fail_unless (base == 0xdeadbeef);
80
81     gst_event_unref (event);
82   }
83   /* TAGS */
84   {
85     GstTagList *taglist = gst_tag_list_new ();
86     GstTagList *tl2 = NULL;
87
88     event = gst_event_new_tag (taglist);
89     fail_if (taglist == NULL);
90     fail_if (event == NULL);
91     fail_unless (GST_EVENT_TYPE (event) == GST_EVENT_TAG);
92     fail_if (GST_EVENT_IS_UPSTREAM (event));
93     fail_unless (GST_EVENT_IS_DOWNSTREAM (event));
94     fail_unless (GST_EVENT_IS_SERIALIZED (event));
95
96     gst_event_parse_tag (event, &tl2);
97     fail_unless (taglist == tl2);
98     gst_event_unref (event);
99   }
100
101   /* FIXME: Add tests for FILLERS and QOS when they are implemented. */
102
103   /* SEEK */
104   {
105     gdouble rate;
106     GstFormat format;
107     GstSeekFlags flags;
108     GstSeekType cur_type, stop_type;
109     gint64 cur, stop;
110
111     event = gst_event_new_seek (0.5, GST_FORMAT_BYTES,
112         GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE,
113         GST_SEEK_TYPE_SET, 1, GST_SEEK_TYPE_NONE, 0xdeadbeef);
114
115     fail_if (event == NULL);
116     fail_unless (GST_EVENT_TYPE (event) == GST_EVENT_SEEK);
117     fail_unless (GST_EVENT_IS_UPSTREAM (event));
118     fail_if (GST_EVENT_IS_DOWNSTREAM (event));
119     fail_if (GST_EVENT_IS_SERIALIZED (event));
120
121     gst_event_parse_seek (event, &rate, &format, &flags, &cur_type, &cur,
122         &stop_type, &stop);
123     fail_unless (rate == 0.5);
124     fail_unless (format == GST_FORMAT_BYTES);
125     fail_unless (flags == (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE));
126     fail_unless (cur_type == GST_SEEK_TYPE_SET);
127     fail_unless (cur == 1);
128     fail_unless (stop_type == GST_SEEK_TYPE_NONE);
129     fail_unless (stop == 0xdeadbeef);
130
131     gst_event_unref (event);
132   }
133
134   /* NAVIGATION */
135   {
136     structure = gst_structure_new ("application/x-gst-navigation", "event",
137         G_TYPE_STRING, "key-press", "key", G_TYPE_STRING, "mon", NULL);
138     fail_if (structure == NULL);
139     event = gst_event_new_navigation (structure);
140     fail_if (event == NULL);
141     fail_unless (GST_EVENT_TYPE (event) == GST_EVENT_NAVIGATION);
142     fail_unless (GST_EVENT_IS_UPSTREAM (event));
143     fail_if (GST_EVENT_IS_DOWNSTREAM (event));
144     fail_if (GST_EVENT_IS_SERIALIZED (event));
145
146     fail_unless (gst_event_get_structure (event) == structure);
147     gst_event_unref (event);
148   }
149
150   /* Custom event types */
151   {
152     structure = gst_structure_empty_new ("application/x-custom");
153     fail_if (structure == NULL);
154     event = gst_event_new_custom (GST_EVENT_CUSTOM_UP, structure);
155     fail_if (event == NULL);
156     fail_unless (GST_EVENT_TYPE (event) == GST_EVENT_CUSTOM_UP);
157     fail_unless (GST_EVENT_IS_UPSTREAM (event));
158     fail_if (GST_EVENT_IS_DOWNSTREAM (event));
159     fail_if (GST_EVENT_IS_SERIALIZED (event));
160     fail_unless (gst_event_get_structure (event) == structure);
161     gst_event_unref (event);
162
163     /* Decided not to test the other custom enum types, as they
164      * only differ by the value of the enum passed to gst_event_new_custom
165      */
166   }
167
168   /* Event copying */
169   {
170     structure = gst_structure_empty_new ("application/x-custom");
171     fail_if (structure == NULL);
172     event = gst_event_new_custom (GST_EVENT_CUSTOM_BOTH, structure);
173
174     fail_if (event == NULL);
175     event2 = gst_event_copy (event);
176     fail_if (event2 == NULL);
177     fail_unless (GST_EVENT_TYPE (event) == GST_EVENT_TYPE (event2));
178
179     /* The structure should have been duplicated */
180     fail_if (gst_event_get_structure (event) ==
181         gst_event_get_structure (event2));
182     gst_event_unref (event);
183     gst_event_unref (event2);
184   }
185 }
186
187 GST_END_TEST GTimeVal sent_event_time;
188 GstEvent *got_event_before_q, *got_event_after_q;
189 GTimeVal got_event_time;
190
191 static gboolean
192 event_probe (GstPad * pad, GstMiniObject ** data, gpointer user_data)
193 {
194   gboolean before_q = (gboolean) user_data;
195
196   fail_unless (GST_IS_EVENT (data));
197
198   if (before_q) {
199     switch (GST_EVENT_TYPE (GST_EVENT (data))) {
200       case GST_EVENT_CUSTOM_UP:
201       case GST_EVENT_CUSTOM_BOTH:
202       case GST_EVENT_CUSTOM_BOTH_OOB:
203         gst_event_ref (data);
204         g_get_current_time (&got_event_time);
205         got_event_before_q = GST_EVENT (data);
206         break;
207       default:
208         break;
209     }
210   } else {
211     switch (GST_EVENT_TYPE (GST_EVENT (data))) {
212       case GST_EVENT_CUSTOM_DS:
213       case GST_EVENT_CUSTOM_DS_OOB:
214       case GST_EVENT_CUSTOM_BOTH:
215       case GST_EVENT_CUSTOM_BOTH_OOB:
216         gst_event_ref (data);
217         g_get_current_time (&got_event_time);
218         got_event_after_q = GST_EVENT (data);
219         break;
220       default:
221         break;
222     }
223   }
224
225   return TRUE;
226 }
227
228 static void test_event
229     (GstEventType type, GstPad * pad, gboolean expect_before_q)
230 {
231   GstEvent *event;
232   gint i;
233
234   got_event_before_q = got_event_after_q = NULL;
235
236   event = gst_event_new_custom (type,
237       gst_structure_empty_new ("application/x-custom"));
238   g_get_current_time (&sent_event_time);
239   got_event_time.tv_sec = 0;
240   got_event_time.tv_usec = 0;
241
242   gst_pad_push_event (pad, event);
243
244   /* Wait up to 5 seconds for the event to appear */
245   if (expect_before_q) {
246     for (i = 0; i < 50; i++) {
247       g_usleep (G_USEC_PER_SEC / 10);
248       if (got_event_before_q != NULL)
249         break;
250     }
251     fail_if (got_event_before_q == NULL);
252     fail_unless (GST_EVENT_TYPE (got_event_before_q) == type);
253   } else {
254     for (i = 0; i < 50; i++) {
255       g_usleep (G_USEC_PER_SEC / 10);
256       if (got_event_after_q != NULL)
257         break;
258     }
259     fail_if (got_event_after_q == NULL);
260     fail_unless (GST_EVENT_TYPE (got_event_after_q) == type);
261   }
262 };
263
264 static gint64
265 timediff (GTimeVal * end, GTimeVal * start)
266 {
267   return (end->tv_sec - start->tv_sec) * G_USEC_PER_SEC +
268       (end->tv_usec - start->tv_usec);
269 }
270
271 GST_START_TEST (send_custom_events)
272 {
273   /* Run some tests on custom events. Checking for serialisation and whatnot.
274    * pipeline is fakesrc ! queue ! fakesink */
275   GstBin *pipeline;
276   GstElement *fakesrc, *fakesink, *queue;
277   GstPad *srcpad, *sinkpad;
278
279   fail_if ((pipeline = (GstBin *) gst_pipeline_new ("testpipe")) == NULL);
280   fail_if ((fakesrc = gst_element_factory_make ("fakesrc", NULL)) == NULL);
281   fail_if ((fakesink = gst_element_factory_make ("fakesink", NULL)) == NULL);
282   fail_if ((queue = gst_element_factory_make ("queue", NULL)) == NULL);
283
284   gst_bin_add_many (pipeline, fakesrc, queue, fakesink, NULL);
285   fail_unless (gst_element_link_many (fakesrc, queue, fakesink, NULL));
286
287   /* Send 25 buffers per sec */
288   g_object_set (G_OBJECT (fakesrc), "silent", TRUE, "datarate", 25,
289       "sizemax", 1, "sizetype", 2, NULL);
290   g_object_set (G_OBJECT (queue), "max-size-buffers", 0, "max-size-time",
291       (guint64) 1.1 * GST_SECOND, "max-size-bytes", 0, NULL);
292   g_object_set (G_OBJECT (fakesink), "silent", TRUE, "sync", TRUE, NULL);
293
294   fail_if ((srcpad = gst_element_get_pad (fakesrc, "src")) == NULL);
295   gst_pad_add_event_probe (srcpad, (GCallback) event_probe,
296       GINT_TO_POINTER (TRUE));
297
298   fail_if ((sinkpad = gst_element_get_pad (fakesink, "sink")) == NULL);
299   gst_pad_add_event_probe (sinkpad, (GCallback) event_probe,
300       GINT_TO_POINTER (FALSE));
301
302   gst_element_set_state (GST_ELEMENT (pipeline), GST_STATE_PLAYING);
303
304   /* Upstream events */
305   test_event (GST_EVENT_CUSTOM_UP, sinkpad, TRUE);
306   fail_unless (timediff (&got_event_time, &sent_event_time) < G_USEC_PER_SEC,
307       "GST_EVENT_CUSTOM_UP took to long to reach source");
308
309   test_event (GST_EVENT_CUSTOM_BOTH, sinkpad, TRUE);
310   fail_unless (timediff (&got_event_time, &sent_event_time) < G_USEC_PER_SEC,
311       "GST_EVENT_CUSTOM_BOTH took to long to reach source");
312
313   test_event (GST_EVENT_CUSTOM_BOTH_OOB, sinkpad, TRUE);
314   fail_unless (timediff (&got_event_time, &sent_event_time) < G_USEC_PER_SEC,
315       "GST_EVENT_CUSTOM_BOTH_OOB took to long to reach source");
316
317   /* Out of band downstream events */
318   test_event (GST_EVENT_CUSTOM_DS_OOB, srcpad, FALSE);
319   fail_unless (timediff (&got_event_time, &sent_event_time) < G_USEC_PER_SEC,
320       "GST_EVENT_CUSTOM_DS_OOB took to long to reach source");
321
322   test_event (GST_EVENT_CUSTOM_BOTH_OOB, srcpad, FALSE);
323   fail_unless (timediff (&got_event_time, &sent_event_time) < G_USEC_PER_SEC,
324       "GST_EVENT_CUSTOM_BOTH_OOB took to long to reach source");
325
326   /* In-band downstream events are expected to take at least 1 second 
327    * to traverse the the queue */
328   test_event (GST_EVENT_CUSTOM_DS, srcpad, FALSE);
329   fail_unless (timediff (&got_event_time, &sent_event_time) >= G_USEC_PER_SEC,
330       "GST_EVENT_CUSTOM_BOTH_OOB arrived at sink too quickly for an in-band event");
331
332   test_event (GST_EVENT_CUSTOM_BOTH, srcpad, FALSE);
333   fail_unless (timediff (&got_event_time, &sent_event_time) >= G_USEC_PER_SEC,
334       "GST_EVENT_CUSTOM_BOTH_OOB arrived at sink too quickly for an in-band event");
335
336   gst_element_set_state (GST_ELEMENT (pipeline), GST_STATE_NULL);
337   gst_bin_watch_for_state_change (GST_BIN (pipeline));
338
339   gst_object_unref (pipeline);
340 }
341
342 GST_END_TEST Suite * gstevents_suite (void)
343 {
344   Suite *s = suite_create ("GstEvent");
345   TCase *tc_chain = tcase_create ("customevents");
346
347   tcase_set_timeout (tc_chain, 20);
348
349   suite_add_tcase (s, tc_chain);
350   tcase_add_test (tc_chain, create_custom_events);
351   tcase_add_test (tc_chain, send_custom_events);
352   return s;
353 }
354
355 int
356 main (int argc, char **argv)
357 {
358   int nf;
359
360   Suite *s = gstevents_suite ();
361   SRunner *sr = srunner_create (s);
362
363   gst_check_init (&argc, &argv);
364
365   srunner_run_all (sr, CK_NORMAL);
366   nf = srunner_ntests_failed (sr);
367   srunner_free (sr);
368
369   return nf;
370 }