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 segment;
41 volatile gboolean eos;
42 volatile gboolean expect_flush;
47 typedef struct _GstStreamConsistencyProbe
51 } GstStreamConsistencyProbe;
54 source_pad_data_cb (GstPad * pad, GstPadProbeInfo * info,
55 GstStreamConsistency * consist)
57 GstMiniObject *data = GST_PAD_PROBE_INFO_DATA (info);
59 GST_DEBUG_OBJECT (pad, "%p: %d %d %d %d", consist, consist->flushing,
60 consist->segment, consist->eos, consist->expect_flush);
62 if (GST_IS_BUFFER (data)) {
63 GST_DEBUG_OBJECT (pad,
64 "Buffer pts %" GST_TIME_FORMAT ", dts %" GST_TIME_FORMAT,
65 GST_TIME_ARGS (GST_BUFFER_PTS (GST_BUFFER_CAST (data))),
66 GST_TIME_ARGS (GST_BUFFER_DTS (GST_BUFFER_CAST (data))));
67 /* If an EOS went through, a buffer would be invalid */
68 fail_if (consist->eos, "Buffer received after EOS");
69 /* Buffers need to be preceded by a segment event */
70 fail_unless (consist->segment, "Buffer received without segment");
71 } else if (GST_IS_EVENT (data)) {
72 GstEvent *event = (GstEvent *) data;
74 GST_DEBUG_OBJECT (pad, "%s", GST_EVENT_TYPE_NAME (event));
75 switch (GST_EVENT_TYPE (event)) {
76 case GST_EVENT_FLUSH_START:
77 /* getting two flush_start in a row seems to be okay
78 fail_if (consist->flushing, "Received another FLUSH_START");
80 consist->flushing = TRUE;
82 case GST_EVENT_FLUSH_STOP:
83 /* Receiving a flush-stop is only valid after receiving a flush-start */
84 fail_unless (consist->flushing,
85 "Received a FLUSH_STOP without a FLUSH_START");
86 fail_if (consist->eos, "Received a FLUSH_STOP after an EOS");
87 consist->flushing = consist->expect_flush = FALSE;
89 case GST_EVENT_STREAM_START:
90 case GST_EVENT_STREAM_CONFIG:
92 /* ok to have these before segment event */
93 /* FIXME check order more precisely, if so spec'ed somehow ? */
95 case GST_EVENT_SEGMENT:
96 fail_if ((consist->expect_flush && consist->flushing),
97 "Received SEGMENT while in a flushing seek");
98 consist->segment = TRUE;
102 /* FIXME : not 100% sure about whether two eos in a row is valid */
103 fail_if (consist->eos, "Received EOS just after another EOS");
105 consist->segment = FALSE;
108 GST_DEBUG_OBJECT (pad, "tag %" GST_PTR_FORMAT,
109 gst_event_get_structure (event));
112 if (GST_EVENT_IS_SERIALIZED (event) && GST_EVENT_IS_DOWNSTREAM (event)) {
113 fail_if (consist->eos, "Event received after EOS");
114 fail_unless (consist->segment, "Event received before segment");
116 /* FIXME : Figure out what to do for other events */
125 sink_pad_data_cb (GstPad * pad, GstPadProbeInfo * info,
126 GstStreamConsistency * consist)
128 GstMiniObject *data = GST_PAD_PROBE_INFO_DATA (info);
130 GST_DEBUG_OBJECT (pad, "%p: %d %d %d %d", consist, consist->flushing,
131 consist->segment, consist->eos, consist->expect_flush);
133 if (GST_IS_BUFFER (data)) {
134 GST_DEBUG_OBJECT (pad, "Buffer %" GST_TIME_FORMAT,
135 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (GST_BUFFER (data))));
136 /* If an EOS went through, a buffer would be invalid */
137 fail_if (consist->eos, "Buffer received after EOS");
138 /* Buffers need to be preceded by a segment event */
139 fail_unless (consist->segment, "Buffer received without segment");
140 } else if (GST_IS_EVENT (data)) {
141 GstEvent *event = (GstEvent *) data;
143 GST_DEBUG_OBJECT (pad, "%s", GST_EVENT_TYPE_NAME (event));
144 switch (GST_EVENT_TYPE (event)) {
149 gst_event_parse_seek (event, NULL, NULL, &flags, NULL, NULL, NULL,
151 consist->expect_flush =
152 ((flags & GST_SEEK_FLAG_FLUSH) == GST_SEEK_FLAG_FLUSH);
155 case GST_EVENT_SEGMENT:
156 fail_if ((consist->expect_flush && consist->flushing),
157 "Received SEGMENT while in a flushing seek");
158 consist->segment = TRUE;
159 consist->eos = FALSE;
162 /* FIXME : Figure out what to do for other events */
171 add_pad (GstStreamConsistency * consist, GstPad * pad)
173 GstStreamConsistencyProbe *p;
176 p = g_new0 (GstStreamConsistencyProbe, 1);
177 p->pad = g_object_ref (pad);
178 dir = gst_pad_get_direction (pad);
179 if (dir == GST_PAD_SRC) {
182 gst_pad_add_probe (pad, GST_PAD_PROBE_TYPE_DATA_DOWNSTREAM,
183 (GstPadProbeCallback) source_pad_data_cb, consist, NULL);
185 } else if (dir == GST_PAD_SINK) {
187 gst_pad_add_probe (pad, GST_PAD_PROBE_TYPE_DATA_DOWNSTREAM,
188 (GstPadProbeCallback) sink_pad_data_cb, consist, NULL);
190 consist->pads = g_list_prepend (consist->pads, p);
194 * gst_consistency_checker_new:
195 * @pad: The #GstPad on which the dataflow will be checked.
197 * Sets up a data probe on the given pad which will raise assertions if the
198 * data flow is inconsistent.
200 * Returns: A #GstStreamConsistency structure used to track data flow.
204 GstStreamConsistency *
205 gst_consistency_checker_new (GstPad * pad)
207 GstStreamConsistency *consist;
209 g_return_val_if_fail (pad != NULL, NULL);
211 consist = g_new0 (GstStreamConsistency, 1);
213 if (!consist->pads) {
214 consist->parent = GST_OBJECT_PARENT (pad);
216 add_pad (consist, pad);
221 * gst_consistency_checker_add_pad:
222 * @consist: The #GstStreamConsistency handle
223 * @pad: The #GstPad on which the dataflow will be checked.
225 * Sets up a data probe on the given pad which will raise assertions if the
226 * data flow is inconsistent.
228 * Returns: %TRUE if the pad was added
233 gst_consistency_checker_add_pad (GstStreamConsistency * consist, GstPad * pad)
235 g_return_val_if_fail (consist != NULL, FALSE);
236 g_return_val_if_fail (pad != NULL, FALSE);
237 g_return_val_if_fail (GST_OBJECT_PARENT (pad) == consist->parent, FALSE);
239 add_pad (consist, pad);
244 * gst_consistency_checker_reset:
245 * @consist: The #GstStreamConsistency to reset.
247 * Reset the stream checker's internal variables.
253 gst_consistency_checker_reset (GstStreamConsistency * consist)
255 consist->eos = FALSE;
256 consist->flushing = FALSE;
257 consist->segment = FALSE;
261 * gst_consistency_checker_free:
262 * @consist: The #GstStreamConsistency to free.
264 * Frees the allocated data and probes associated with @consist.
270 gst_consistency_checker_free (GstStreamConsistency * consist)
273 GstStreamConsistencyProbe *p;
275 /* Remove the data probes */
276 for (node = consist->pads; node; node = g_list_next (node)) {
277 p = (GstStreamConsistencyProbe *) node->data;
278 gst_pad_remove_probe (p->pad, p->probeid);
279 g_object_unref (p->pad);
282 g_list_free (consist->pads);