3 * unit testing helper lib
5 * Copyright (C) 2009 Edward Hervey <bilboed@bilboed.com>
6 * Copyright (C) 2012 Stefan Sauer <ensonic@users.sf.net>
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Library General Public
10 * License as published by the Free Software Foundation; either
11 * version 2 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Library General Public License for more details.
18 * You should have received a copy of the GNU Library General Public
19 * License along with this library; if not, write to the
20 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21 * Boston, MA 02111-1307, USA.
25 * SECTION:gstcheckconsistencychecker
26 * @short_description: Data flow consistency checker for GStreamer unit tests.
28 * These macros and functions are for internal use of the unit tests found
29 * inside the 'check' directories of various GStreamer packages.
34 #include "gstconsistencychecker.h"
36 struct _GstStreamConsistency
38 /* FIXME: do we want to track some states per pad? */
39 volatile gboolean flushing;
40 volatile gboolean newsegment;
41 volatile gboolean eos;
42 volatile gboolean expect_flush;
47 typedef struct _GstStreamConsistencyProbe
51 } GstStreamConsistencyProbe;
55 source_pad_data_cb (GstPad * pad, GstMiniObject * data,
56 GstStreamConsistency * consist)
58 GST_DEBUG_OBJECT (pad, "%p: %d %d %d %d", consist, consist->flushing,
59 consist->newsegment, consist->eos, consist->expect_flush);
61 if (GST_IS_BUFFER (data)) {
62 GST_DEBUG_OBJECT (pad, "Buffer %" GST_TIME_FORMAT,
63 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (GST_BUFFER (data))));
64 /* If an EOS went through, a buffer would be invalid */
65 fail_if (consist->eos, "Buffer received after EOS");
66 /* Buffers need to be preceded by a newsegment event */
67 fail_unless (consist->newsegment, "Buffer received without newsegment");
68 } else if (GST_IS_EVENT (data)) {
69 GstEvent *event = (GstEvent *) data;
71 GST_DEBUG_OBJECT (pad, "%s", GST_EVENT_TYPE_NAME (event));
72 switch (GST_EVENT_TYPE (event)) {
73 case GST_EVENT_FLUSH_START:
74 /* getting two flush_start in a row seems to be okay
75 fail_if (consist->flushing, "Received another FLUSH_START");
77 consist->flushing = TRUE;
79 case GST_EVENT_FLUSH_STOP:
80 /* Receiving a flush-stop is only valid after receiving a flush-start */
81 fail_unless (consist->flushing,
82 "Received a FLUSH_STOP without a FLUSH_START");
83 fail_if (consist->eos, "Received a FLUSH_STOP after an EOS");
84 consist->flushing = consist->expect_flush = FALSE;
86 case GST_EVENT_NEWSEGMENT:
87 fail_if ((consist->expect_flush && consist->flushing),
88 "Received NEWSEGMENT while in a flushing seek");
89 consist->newsegment = TRUE;
93 /* FIXME : not 100% sure about whether two eos in a row is valid */
94 fail_if (consist->eos, "Received EOS just after another EOS");
96 consist->newsegment = FALSE;
99 GST_DEBUG_OBJECT (pad, "tag %" GST_PTR_FORMAT, event->structure);
102 if (GST_EVENT_IS_SERIALIZED (event) && GST_EVENT_IS_DOWNSTREAM (event)) {
103 fail_if (consist->eos, "Event received after EOS");
104 fail_unless (consist->newsegment, "Event received before newsegment");
106 /* FIXME : Figure out what to do for other events */
115 sink_pad_data_cb (GstPad * pad, GstMiniObject * data,
116 GstStreamConsistency * consist)
118 GST_DEBUG_OBJECT (pad, "%p: %d %d %d %d", consist, consist->flushing,
119 consist->newsegment, consist->eos, consist->expect_flush);
121 if (GST_IS_BUFFER (data)) {
122 GST_DEBUG_OBJECT (pad, "Buffer %" GST_TIME_FORMAT,
123 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (GST_BUFFER (data))));
124 /* If an EOS went through, a buffer would be invalid */
125 fail_if (consist->eos, "Buffer received after EOS");
126 /* Buffers need to be preceded by a newsegment event */
127 fail_unless (consist->newsegment, "Buffer received without newsegment");
128 } else if (GST_IS_EVENT (data)) {
129 GstEvent *event = (GstEvent *) data;
131 GST_DEBUG_OBJECT (pad, "%s", GST_EVENT_TYPE_NAME (event));
132 switch (GST_EVENT_TYPE (event)) {
137 gst_event_parse_seek (event, NULL, NULL, &flags, NULL, NULL, NULL,
139 consist->expect_flush =
140 ((flags & GST_SEEK_FLAG_FLUSH) == GST_SEEK_FLAG_FLUSH);
143 case GST_EVENT_NEWSEGMENT:
144 fail_if ((consist->expect_flush && consist->flushing),
145 "Received NEWSEGMENT while in a flushing seek");
146 consist->newsegment = TRUE;
147 consist->eos = FALSE;
150 /* FIXME : Figure out what to do for other events */
159 add_pad (GstStreamConsistency * consist, GstPad * pad)
161 GstStreamConsistencyProbe *p;
164 p = g_new0 (GstStreamConsistencyProbe, 1);
165 p->pad = g_object_ref (pad);
166 dir = gst_pad_get_direction (pad);
167 if (dir == GST_PAD_SRC) {
169 gst_pad_add_data_probe (pad, (GCallback) source_pad_data_cb, consist);
170 } else if (dir == GST_PAD_SINK) {
172 gst_pad_add_data_probe (pad, (GCallback) sink_pad_data_cb, consist);
174 consist->pads = g_list_prepend (consist->pads, p);
178 * gst_consistency_checker_new:
179 * @pad: The #GstPad on which the dataflow will be checked.
181 * Sets up a data probe on the given pad which will raise assertions if the
182 * data flow is inconsistent.
184 * Returns: A #GstStreamConsistency structure used to track data flow.
188 GstStreamConsistency *
189 gst_consistency_checker_new (GstPad * pad)
191 GstStreamConsistency *consist;
193 g_return_val_if_fail (pad != NULL, NULL);
195 consist = g_new0 (GstStreamConsistency, 1);
197 if (!consist->pads) {
198 consist->parent = GST_OBJECT_PARENT (pad);
200 add_pad (consist, pad);
205 * gst_consistency_checker_add_pad:
206 * @consist: The #GstStreamConsistency handle
207 * @pad: The #GstPad on which the dataflow will be checked.
209 * Sets up a data probe on the given pad which will raise assertions if the
210 * data flow is inconsistent.
212 * Returns: %TRUE if the pad was added
217 gst_consistency_checker_add_pad (GstStreamConsistency * consist, GstPad * pad)
219 g_return_val_if_fail (consist != NULL, FALSE);
220 g_return_val_if_fail (pad != NULL, FALSE);
221 g_return_val_if_fail (GST_OBJECT_PARENT (pad) == consist->parent, FALSE);
223 add_pad (consist, pad);
228 * gst_consistency_checker_reset:
229 * @consist: The #GstStreamConsistency to reset.
231 * Reset the stream checker's internal variables.
237 gst_consistency_checker_reset (GstStreamConsistency * consist)
239 consist->eos = FALSE;
240 consist->flushing = FALSE;
241 consist->newsegment = FALSE;
245 * gst_consistency_checker_free:
246 * @consist: The #GstStreamConsistency to free.
248 * Frees the allocated data and probes associated with @consist.
254 gst_consistency_checker_free (GstStreamConsistency * consist)
257 GstStreamConsistencyProbe *p;
259 /* Remove the data probes */
260 for (node = consist->pads; node; node = g_list_next (node)) {
261 p = (GstStreamConsistencyProbe *) node->data;
262 gst_pad_remove_data_probe (p->pad, p->probeid);
263 g_object_unref (p->pad);
266 g_list_free (consist->pads);