debug: rename debug to debugutils to avoid clash with --disable-debug. Fixes #562168
[platform/upstream/gstreamer.git] / gst / debugutils / tests.c
1 /* GStreamer
2  * Copyright (C) 2004 Benjamin Otte <otte@gnome.org>
3  *
4  * includes code based on glibc 2.2.3's crypt/md5.c,
5  * Copyright (C) 1995, 1996, 1997, 1999, 2000 Free Software Foundation, Inc. 
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 #ifdef HAVE_CONFIG_H
24 #include "config.h"
25 #endif
26
27 #include "tests.h"
28 #include <stdlib.h>
29 #include <string.h>
30
31
32 /*
33  *** LENGTH ***
34  */
35
36 typedef struct
37 {
38   gint64 value;
39 }
40 LengthTest;
41
42 static GParamSpec *
43 length_get_spec (const GstTestInfo * info, gboolean compare_value)
44 {
45   if (compare_value) {
46     return g_param_spec_int64 ("expected-length", "expected length",
47         "expected length of stream", -1, G_MAXINT64, -1,
48         G_PARAM_READWRITE | G_PARAM_CONSTRUCT);
49   } else {
50     return g_param_spec_int64 ("length", "length", "length of stream",
51         -1, G_MAXINT64, -1, G_PARAM_READABLE);
52   }
53 }
54
55 static gpointer
56 length_new (const GstTestInfo * info)
57 {
58   return g_new0 (LengthTest, 1);
59 }
60
61 static void
62 length_add (gpointer test, GstBuffer * buffer)
63 {
64   LengthTest *t = test;
65
66   t->value += GST_BUFFER_SIZE (buffer);
67 }
68
69 static gboolean
70 length_finish (gpointer test, GValue * value)
71 {
72   LengthTest *t = test;
73
74   if (g_value_get_int64 (value) == -1)
75     return TRUE;
76
77   return t->value == g_value_get_int64 (value);
78 }
79
80 static void
81 length_get_value (gpointer test, GValue * value)
82 {
83   LengthTest *t = test;
84
85   g_value_set_int64 (value, t ? t->value : -1);
86 }
87
88 /*
89  *** BUFFER COUNT ***
90  */
91
92 static GParamSpec *
93 buffer_count_get_spec (const GstTestInfo * info, gboolean compare_value)
94 {
95   if (compare_value) {
96     return g_param_spec_int64 ("expected-buffer-count", "expected buffer count",
97         "expected number of buffers in stream",
98         -1, G_MAXINT64, -1, G_PARAM_READWRITE | G_PARAM_CONSTRUCT);
99   } else {
100     return g_param_spec_int64 ("buffer-count", "buffer count",
101         "number of buffers in stream", -1, G_MAXINT64, -1, G_PARAM_READABLE);
102   }
103 }
104
105 static void
106 buffer_count_add (gpointer test, GstBuffer * buffer)
107 {
108   LengthTest *t = test;
109
110   t->value++;
111 }
112
113 /*
114  *** TIMESTAMP / DURATION MATCHING ***
115  */
116
117 typedef struct
118 {
119   guint64 diff;
120   guint count;
121   GstClockTime expected;
122 }
123 TimeDurTest;
124
125 static GParamSpec *
126 timedur_get_spec (const GstTestInfo * info, gboolean compare_value)
127 {
128   if (compare_value) {
129     return g_param_spec_int64 ("allowed-timestamp-deviation",
130         "allowed timestamp deviation",
131         "allowed average difference in usec between timestamp of next buffer "
132         "and expected timestamp from analyzing last buffer",
133         -1, G_MAXINT64, -1, G_PARAM_READWRITE | G_PARAM_CONSTRUCT);
134   } else {
135     return g_param_spec_int64 ("timestamp-deviation",
136         "timestamp deviation",
137         "average difference in usec between timestamp of next buffer "
138         "and expected timestamp from analyzing last buffer",
139         -1, G_MAXINT64, -1, G_PARAM_READABLE);
140   }
141 }
142
143 static gpointer
144 timedur_new (const GstTestInfo * info)
145 {
146   TimeDurTest *ret = g_new0 (TimeDurTest, 1);
147
148   ret->expected = GST_CLOCK_TIME_NONE;
149
150   return ret;
151 }
152
153 static void
154 timedur_add (gpointer test, GstBuffer * buffer)
155 {
156   TimeDurTest *t = test;
157
158   if (GST_BUFFER_TIMESTAMP_IS_VALID (buffer) &&
159       GST_CLOCK_TIME_IS_VALID (t->expected)) {
160     t->diff += labs (GST_BUFFER_TIMESTAMP (buffer) - t->expected);
161     t->count++;
162   }
163   if (GST_BUFFER_TIMESTAMP_IS_VALID (buffer) &&
164       GST_BUFFER_DURATION_IS_VALID (buffer)) {
165     t->expected = GST_BUFFER_TIMESTAMP (buffer) + GST_BUFFER_DURATION (buffer);
166   } else {
167     t->expected = GST_CLOCK_TIME_NONE;
168   }
169 }
170
171 static gboolean
172 timedur_finish (gpointer test, GValue * value)
173 {
174   TimeDurTest *t = test;
175
176   if (g_value_get_int64 (value) == -1)
177     return TRUE;
178
179   return (t->diff / MAX (1, t->count)) <= g_value_get_int64 (value);
180 }
181
182 static void
183 timedur_get_value (gpointer test, GValue * value)
184 {
185   TimeDurTest *t = test;
186
187   g_value_set_int64 (value, t ? (t->diff / MAX (1, t->count)) : -1);
188 }
189
190 /*
191  *** MD5 ***
192  */
193
194 typedef struct
195 {
196   /* md5 information */
197   guint32 A;
198   guint32 B;
199   guint32 C;
200   guint32 D;
201
202   guint32 total[2];
203   guint32 buflen;
204   gchar buffer[128];
205
206   gchar result[33];
207 }
208 MD5Test;
209
210 static void md5_process_block (const void *buffer, size_t len, MD5Test * ctx);
211 static void md5_read_ctx (MD5Test * ctx, gchar * result);
212
213 static GParamSpec *
214 md5_get_spec (const GstTestInfo * info, gboolean compare_value)
215 {
216   if (compare_value) {
217     return g_param_spec_string ("expected-md5", "expected md5",
218         "expected md5 of processing the whole data",
219         "---", G_PARAM_READWRITE | G_PARAM_CONSTRUCT);
220   } else {
221     return g_param_spec_string ("md5", "md5",
222         "md5 of processing the whole data", "---", G_PARAM_READABLE);
223   }
224 }
225
226 /* This array contains the bytes used to pad the buffer to the next
227    64-byte boundary.  (RFC 1321, 3.1: Step 1)  */
228 static const guchar fillbuf[64] = { 0x80, 0 /* , 0, 0, ...  */  };
229
230 /* MD5 functions */
231 /* Initialize structure containing state of computation.
232    (RFC 1321, 3.3: Step 3)  */
233 static gpointer
234 md5_new (const GstTestInfo * info)
235 {
236   MD5Test *ctx = g_new (MD5Test, 1);
237
238   ctx->A = 0x67452301;
239   ctx->B = 0xefcdab89;
240   ctx->C = 0x98badcfe;
241   ctx->D = 0x10325476;
242
243   ctx->total[0] = ctx->total[1] = 0;
244   ctx->buflen = 0;
245
246   memset (ctx->result, 0, 33);
247
248   return ctx;
249 }
250
251 /* Process the remaining bytes in the internal buffer and the usual
252    prolog according to the standard and write the result to RESBUF.
253
254    IMPORTANT: On some systems it is required that RESBUF is correctly
255    aligned for a 32 bits value.  */
256 static gboolean
257 md5_finish (gpointer test, GValue * value)
258 {
259   MD5Test *ctx = test;
260   const gchar *str_val = g_value_get_string (value);
261
262   /* Take yet unprocessed bytes into account.  */
263   guint32 bytes = ctx->buflen;
264   size_t pad;
265
266   /* Now count remaining bytes.  */
267   ctx->total[0] += bytes;
268   if (ctx->total[0] < bytes)
269     ++ctx->total[1];
270
271   pad = bytes >= 56 ? 64 + 56 - bytes : 56 - bytes;
272   memcpy (&ctx->buffer[bytes], fillbuf, pad);
273
274   /* Put the 64-bit file length in *bits* at the end of the buffer.  */
275   *(guint32 *) & ctx->buffer[bytes + pad] = GUINT32_TO_LE (ctx->total[0] << 3);
276   *(guint32 *) & ctx->buffer[bytes + pad + 4] =
277       GUINT32_TO_LE ((ctx->total[1] << 3) | (ctx->total[0] >> 29));
278
279   /* Process last bytes.  */
280   md5_process_block (ctx->buffer, bytes + pad + 8, ctx);
281
282   md5_read_ctx (ctx, ctx->result);
283   if (g_str_equal (str_val, "---"))
284     return TRUE;
285   if (g_str_equal (str_val, ctx->result))
286     return TRUE;
287   return FALSE;
288 }
289
290 /* Put result from CTX in first 16 bytes following RESBUF.  The result
291    must be in little endian byte order.
292
293    IMPORTANT: On some systems it is required that RESBUF is correctly
294    aligned for a 32 bits value.  */
295 static void
296 md5_read_ctx (MD5Test * ctx, gchar * result)
297 {
298   guint32 resbuf[4];
299   guint i;
300
301   resbuf[0] = GUINT32_TO_LE (ctx->A);
302   resbuf[1] = GUINT32_TO_LE (ctx->B);
303   resbuf[2] = GUINT32_TO_LE (ctx->C);
304   resbuf[3] = GUINT32_TO_LE (ctx->D);
305
306   for (i = 0; i < 16; i++)
307     sprintf (result + i * 2, "%02x", ((guchar *) resbuf)[i]);
308 }
309
310 static void
311 md5_add (gpointer test, GstBuffer * gstbuffer)
312 {
313   const void *buffer = GST_BUFFER_DATA (gstbuffer);
314   gsize len = GST_BUFFER_SIZE (gstbuffer);
315   MD5Test *ctx = test;
316
317   /*const void aligned_buffer = buffer; */
318
319   /* When we already have some bits in our internal buffer concatenate
320      both inputs first.  */
321   if (ctx->buflen != 0) {
322     gsize left_over = ctx->buflen;
323     gsize add = 128 - left_over > len ? len : 128 - left_over;
324
325     /* Only put full words in the buffer.  */
326     /* Forcing alignment here appears to be only an optimization.
327      * The glibc source uses __alignof__, which seems to be a
328      * gratuitous usage of a GCC extension, when sizeof() will
329      * work fine.  (And don't question the sanity of using
330      * sizeof(guint32) instead of 4. */
331     /* add -= add % __alignof__ (guint32); */
332     add -= add % sizeof (guint32);
333
334     memcpy (&ctx->buffer[left_over], buffer, add);
335     ctx->buflen += add;
336
337     if (ctx->buflen > 64) {
338       md5_process_block (ctx->buffer, ctx->buflen & ~63, ctx);
339
340       ctx->buflen &= 63;
341       /* The regions in the following copy operation cannot overlap.  */
342       memcpy (ctx->buffer, &ctx->buffer[(left_over + add) & ~63], ctx->buflen);
343     }
344
345     buffer = (const char *) buffer + add;
346     len -= add;
347   }
348
349   /* Process available complete blocks.  */
350   if (len > 64) {
351     md5_process_block (buffer, len & ~63, ctx);
352     buffer = (const char *) buffer + (len & ~63);
353     len &= 63;
354   }
355
356   /* Move remaining bytes in internal buffer.  */
357   if (len > 0) {
358     size_t left_over = ctx->buflen;
359
360     memcpy (&ctx->buffer[left_over], buffer, len);
361     left_over += len;
362     if (left_over >= 64) {
363       md5_process_block (ctx->buffer, 64, ctx);
364       left_over -= 64;
365       memcpy (ctx->buffer, &ctx->buffer[64], left_over);
366     }
367     ctx->buflen = left_over;
368   }
369 }
370
371
372 /* These are the four functions used in the four steps of the MD5 algorithm
373    and defined in the RFC 1321.  The first function is a little bit optimized
374    (as found in Colin Plumbs public domain implementation).  */
375 /* #define FF(b, c, d) ((b & c) | (~b & d)) */
376 #define FF(b, c, d) (d ^ (b & (c ^ d)))
377 #define FG(b, c, d) FF (d, b, c)
378 #define FH(b, c, d) (b ^ c ^ d)
379 #define FI(b, c, d) (c ^ (b | ~d))
380
381 static void
382 md5_process_block (const void *buffer, size_t len, MD5Test * ctx)
383 {
384 /* Process LEN bytes of BUFFER, accumulating context into CTX.
385    It is assumed that LEN % 64 == 0.  */
386   guint32 correct_words[16];
387   const guint32 *words = buffer;
388   size_t nwords = len / sizeof (guint32);
389   const guint32 *endp = words + nwords;
390   guint32 A = ctx->A;
391   guint32 B = ctx->B;
392   guint32 C = ctx->C;
393   guint32 D = ctx->D;
394
395   /* First increment the byte count.  RFC 1321 specifies the possible
396      length of the file up to 2^64 bits.  Here we only compute the
397      number of bytes.  Do a double word increment.  */
398   ctx->total[0] += len;
399   if (ctx->total[0] < len)
400     ++ctx->total[1];
401
402   /* Process all bytes in the buffer with 64 bytes in each round of
403      the loop.  */
404   while (words < endp) {
405     guint32 *cwp = correct_words;
406     guint32 A_save = A;
407     guint32 B_save = B;
408     guint32 C_save = C;
409     guint32 D_save = D;
410
411     /* First round: using the given function, the context and a constant
412        the next context is computed.  Because the algorithms processing
413        unit is a 32-bit word and it is determined to work on words in
414        little endian byte order we perhaps have to change the byte order
415        before the computation.  To reduce the work for the next steps
416        we store the swapped words in the array CORRECT_WORDS.  */
417
418 #define OP(a, b, c, d, s, T)                                            \
419       do                                                                \
420         {                                                               \
421           a += FF (b, c, d) + (*cwp++ = GUINT32_TO_LE (*words)) + T;            \
422           ++words;                                                      \
423           CYCLIC (a, s);                                                \
424           a += b;                                                       \
425         }                                                               \
426       while (0)
427
428     /* It is unfortunate that C does not provide an operator for
429        cyclic rotation.  Hope the C compiler is smart enough.  */
430 #define CYCLIC(w, s) (w = (w << s) | (w >> (32 - s)))
431
432     /* Before we start, one word to the strange constants.
433        They are defined in RFC 1321 as
434
435        T[i] = (int) (4294967296.0 * fabs (sin (i))), i=1..64
436      */
437
438     /* Round 1.  */
439     OP (A, B, C, D, 7, 0xd76aa478);
440     OP (D, A, B, C, 12, 0xe8c7b756);
441     OP (C, D, A, B, 17, 0x242070db);
442     OP (B, C, D, A, 22, 0xc1bdceee);
443     OP (A, B, C, D, 7, 0xf57c0faf);
444     OP (D, A, B, C, 12, 0x4787c62a);
445     OP (C, D, A, B, 17, 0xa8304613);
446     OP (B, C, D, A, 22, 0xfd469501);
447     OP (A, B, C, D, 7, 0x698098d8);
448     OP (D, A, B, C, 12, 0x8b44f7af);
449     OP (C, D, A, B, 17, 0xffff5bb1);
450     OP (B, C, D, A, 22, 0x895cd7be);
451     OP (A, B, C, D, 7, 0x6b901122);
452     OP (D, A, B, C, 12, 0xfd987193);
453     OP (C, D, A, B, 17, 0xa679438e);
454     OP (B, C, D, A, 22, 0x49b40821);
455
456     /* For the second to fourth round we have the possibly swapped words
457        in CORRECT_WORDS.  Redefine the macro to take an additional first
458        argument specifying the function to use.  */
459 #undef OP
460 #define OP(f, a, b, c, d, k, s, T)                                      \
461       do                                                                \
462         {                                                               \
463           a += f (b, c, d) + correct_words[k] + T;                      \
464           CYCLIC (a, s);                                                \
465           a += b;                                                       \
466         }                                                               \
467       while (0)
468
469     /* Round 2.  */
470     OP (FG, A, B, C, D, 1, 5, 0xf61e2562);
471     OP (FG, D, A, B, C, 6, 9, 0xc040b340);
472     OP (FG, C, D, A, B, 11, 14, 0x265e5a51);
473     OP (FG, B, C, D, A, 0, 20, 0xe9b6c7aa);
474     OP (FG, A, B, C, D, 5, 5, 0xd62f105d);
475     OP (FG, D, A, B, C, 10, 9, 0x02441453);
476     OP (FG, C, D, A, B, 15, 14, 0xd8a1e681);
477     OP (FG, B, C, D, A, 4, 20, 0xe7d3fbc8);
478     OP (FG, A, B, C, D, 9, 5, 0x21e1cde6);
479     OP (FG, D, A, B, C, 14, 9, 0xc33707d6);
480     OP (FG, C, D, A, B, 3, 14, 0xf4d50d87);
481     OP (FG, B, C, D, A, 8, 20, 0x455a14ed);
482     OP (FG, A, B, C, D, 13, 5, 0xa9e3e905);
483     OP (FG, D, A, B, C, 2, 9, 0xfcefa3f8);
484     OP (FG, C, D, A, B, 7, 14, 0x676f02d9);
485     OP (FG, B, C, D, A, 12, 20, 0x8d2a4c8a);
486
487     /* Round 3.  */
488     OP (FH, A, B, C, D, 5, 4, 0xfffa3942);
489     OP (FH, D, A, B, C, 8, 11, 0x8771f681);
490     OP (FH, C, D, A, B, 11, 16, 0x6d9d6122);
491     OP (FH, B, C, D, A, 14, 23, 0xfde5380c);
492     OP (FH, A, B, C, D, 1, 4, 0xa4beea44);
493     OP (FH, D, A, B, C, 4, 11, 0x4bdecfa9);
494     OP (FH, C, D, A, B, 7, 16, 0xf6bb4b60);
495     OP (FH, B, C, D, A, 10, 23, 0xbebfbc70);
496     OP (FH, A, B, C, D, 13, 4, 0x289b7ec6);
497     OP (FH, D, A, B, C, 0, 11, 0xeaa127fa);
498     OP (FH, C, D, A, B, 3, 16, 0xd4ef3085);
499     OP (FH, B, C, D, A, 6, 23, 0x04881d05);
500     OP (FH, A, B, C, D, 9, 4, 0xd9d4d039);
501     OP (FH, D, A, B, C, 12, 11, 0xe6db99e5);
502     OP (FH, C, D, A, B, 15, 16, 0x1fa27cf8);
503     OP (FH, B, C, D, A, 2, 23, 0xc4ac5665);
504
505     /* Round 4.  */
506     OP (FI, A, B, C, D, 0, 6, 0xf4292244);
507     OP (FI, D, A, B, C, 7, 10, 0x432aff97);
508     OP (FI, C, D, A, B, 14, 15, 0xab9423a7);
509     OP (FI, B, C, D, A, 5, 21, 0xfc93a039);
510     OP (FI, A, B, C, D, 12, 6, 0x655b59c3);
511     OP (FI, D, A, B, C, 3, 10, 0x8f0ccc92);
512     OP (FI, C, D, A, B, 10, 15, 0xffeff47d);
513     OP (FI, B, C, D, A, 1, 21, 0x85845dd1);
514     OP (FI, A, B, C, D, 8, 6, 0x6fa87e4f);
515     OP (FI, D, A, B, C, 15, 10, 0xfe2ce6e0);
516     OP (FI, C, D, A, B, 6, 15, 0xa3014314);
517     OP (FI, B, C, D, A, 13, 21, 0x4e0811a1);
518     OP (FI, A, B, C, D, 4, 6, 0xf7537e82);
519     OP (FI, D, A, B, C, 11, 10, 0xbd3af235);
520     OP (FI, C, D, A, B, 2, 15, 0x2ad7d2bb);
521     OP (FI, B, C, D, A, 9, 21, 0xeb86d391);
522
523     /* Add the starting values of the context.  */
524     A += A_save;
525     B += B_save;
526     C += C_save;
527     D += D_save;
528   }
529
530   /* Put checksum in context given as argument.  */
531   ctx->A = A;
532   ctx->B = B;
533   ctx->C = C;
534   ctx->D = D;
535 }
536
537 static void
538 md5_get_value (gpointer test, GValue * value)
539 {
540   MD5Test *ctx = test;
541
542   if (!ctx) {
543     g_value_set_string (value, "---");
544   } else if (ctx->result[0] == 0) {
545     gchar *str = g_new (gchar, 33);
546
547     str[32] = 0;
548     md5_read_ctx (ctx, str);
549     g_value_take_string (value, str);
550   } else {
551     g_value_set_string (value, ctx->result);
552   }
553 }
554
555 /*
556  *** TESTINFO ***
557  */
558
559 const GstTestInfo tests[] = {
560   {length_get_spec, length_new, length_add,
561       length_finish, length_get_value, g_free},
562   {buffer_count_get_spec, length_new, buffer_count_add,
563       length_finish, length_get_value, g_free},
564   {timedur_get_spec, timedur_new, timedur_add,
565       timedur_finish, timedur_get_value, g_free},
566   {md5_get_spec, md5_new, md5_add,
567       md5_finish, md5_get_value, g_free}
568 };