af2f45a3b5a333baa82ae5ee1c8e6976bc3a55ba
[platform/upstream/gstreamer.git] / libs / gst / check / libcheck / check.c
1 /*
2  * Check: a unit test framework for C
3  * Copyright (C) 2001, 2002 Arien Malec
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2.1 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the
17  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
18  * Boston, MA 02110-1301, USA.
19  */
20
21 #include "../lib/libcompat.h"
22
23 #include <string.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <stdarg.h>
27 #include <math.h>
28
29 #include "check.h"
30 #include "check_error.h"
31 #include "check_list.h"
32 #include "check_impl.h"
33 #include "check_msg.h"
34
35 #ifndef DEFAULT_TIMEOUT
36 #define DEFAULT_TIMEOUT 4
37 #endif
38
39 /*
40  * When a process exits either normally, with exit(), or
41  * by an uncaught signal, The lower 0x377 bits are passed
42  * to the parent. Of those, only the lower 8 bits are
43  * returned by the WEXITSTATUS() macro.
44  */
45 #define WEXITSTATUS_MASK 0xFF
46
47 int check_major_version = CHECK_MAJOR_VERSION;
48 int check_minor_version = CHECK_MINOR_VERSION;
49 int check_micro_version = CHECK_MICRO_VERSION;
50
51 static int non_pass (int val);
52 static Fixture *fixture_create (SFun fun, int ischecked);
53 static void tcase_add_fixture (TCase * tc, SFun setup, SFun teardown,
54     int ischecked);
55 static void tr_init (TestResult * tr);
56 static void suite_free (Suite * s);
57 static void tcase_free (TCase * tc);
58
59 Suite *
60 suite_create (const char *name)
61 {
62   Suite *s;
63
64   s = (Suite *) emalloc (sizeof (Suite));       /* freed in suite_free */
65   if (name == NULL)
66     s->name = "";
67   else
68     s->name = name;
69   s->tclst = check_list_create ();
70   return s;
71 }
72
73 int
74 suite_tcase (Suite * s, const char *tcname)
75 {
76   List *l;
77   TCase *tc;
78
79   if (s == NULL)
80     return 0;
81
82   l = s->tclst;
83   for (check_list_front (l); !check_list_at_end (l); check_list_advance (l)) {
84     tc = (TCase *) check_list_val (l);
85     if (strcmp (tcname, tc->name) == 0)
86       return 1;
87   }
88
89   return 0;
90 }
91
92 static void
93 suite_free (Suite * s)
94 {
95   List *l;
96
97   if (s == NULL)
98     return;
99   l = s->tclst;
100   for (check_list_front (l); !check_list_at_end (l); check_list_advance (l)) {
101     tcase_free ((TCase *) check_list_val (l));
102   }
103   check_list_free (s->tclst);
104   free (s);
105 }
106
107 TCase *
108 tcase_create (const char *name)
109 {
110   char *env;
111   double timeout_sec = DEFAULT_TIMEOUT;
112
113   TCase *tc = (TCase *) emalloc (sizeof (TCase));       /*freed in tcase_free */
114
115   if (name == NULL)
116     tc->name = "";
117   else
118     tc->name = name;
119
120   env = getenv ("CK_DEFAULT_TIMEOUT");
121   if (env != NULL) {
122     char *endptr = NULL;
123     double tmp = strtod (env, &endptr);
124
125     if (tmp >= 0 && endptr != env && (*endptr) == '\0') {
126       timeout_sec = tmp;
127     }
128   }
129
130   env = getenv ("CK_TIMEOUT_MULTIPLIER");
131   if (env != NULL) {
132     char *endptr = NULL;
133     double tmp = strtod (env, &endptr);
134
135     if (tmp >= 0 && endptr != env && (*endptr) == '\0') {
136       timeout_sec = timeout_sec * tmp;
137     }
138   }
139
140   tc->timeout.tv_sec = (time_t) floor (timeout_sec);
141   tc->timeout.tv_nsec =
142       (long) ((timeout_sec - floor (timeout_sec)) * (double) NANOS_PER_SECONDS);
143
144   tc->tflst = check_list_create ();
145   tc->unch_sflst = check_list_create ();
146   tc->ch_sflst = check_list_create ();
147   tc->unch_tflst = check_list_create ();
148   tc->ch_tflst = check_list_create ();
149
150   return tc;
151 }
152
153
154 static void
155 tcase_free (TCase * tc)
156 {
157   check_list_apply (tc->tflst, free);
158   check_list_apply (tc->unch_sflst, free);
159   check_list_apply (tc->ch_sflst, free);
160   check_list_apply (tc->unch_tflst, free);
161   check_list_apply (tc->ch_tflst, free);
162   check_list_free (tc->tflst);
163   check_list_free (tc->unch_sflst);
164   check_list_free (tc->ch_sflst);
165   check_list_free (tc->unch_tflst);
166   check_list_free (tc->ch_tflst);
167
168   free (tc);
169 }
170
171 void
172 suite_add_tcase (Suite * s, TCase * tc)
173 {
174   if (s == NULL || tc == NULL)
175     return;
176   check_list_add_end (s->tclst, tc);
177 }
178
179 void
180 _tcase_add_test (TCase * tc, TFun fn, const char *name, int _signal,
181     int allowed_exit_value, int start, int end)
182 {
183   TF *tf;
184
185   if (tc == NULL || fn == NULL || name == NULL)
186     return;
187   tf = (TF *) emalloc (sizeof (TF));    /* freed in tcase_free */
188   tf->fn = fn;
189   tf->loop_start = start;
190   tf->loop_end = end;
191   tf->signal = _signal;         /* 0 means no signal expected */
192   tf->allowed_exit_value = (WEXITSTATUS_MASK & allowed_exit_value);     /* 0 is default successful exit */
193   tf->name = name;
194   check_list_add_end (tc->tflst, tf);
195 }
196
197 static Fixture *
198 fixture_create (SFun fun, int ischecked)
199 {
200   Fixture *f;
201
202   f = (Fixture *) emalloc (sizeof (Fixture));
203   f->fun = fun;
204   f->ischecked = ischecked;
205
206   return f;
207 }
208
209 void
210 tcase_add_unchecked_fixture (TCase * tc, SFun setup, SFun teardown)
211 {
212   tcase_add_fixture (tc, setup, teardown, 0);
213 }
214
215 void
216 tcase_add_checked_fixture (TCase * tc, SFun setup, SFun teardown)
217 {
218   tcase_add_fixture (tc, setup, teardown, 1);
219 }
220
221 static void
222 tcase_add_fixture (TCase * tc, SFun setup, SFun teardown, int ischecked)
223 {
224   if (setup) {
225     if (ischecked)
226       check_list_add_end (tc->ch_sflst, fixture_create (setup, ischecked));
227     else
228       check_list_add_end (tc->unch_sflst, fixture_create (setup, ischecked));
229   }
230
231   /* Add teardowns at front so they are run in reverse order. */
232   if (teardown) {
233     if (ischecked)
234       check_list_add_front (tc->ch_tflst, fixture_create (teardown, ischecked));
235     else
236       check_list_add_front (tc->unch_tflst,
237           fixture_create (teardown, ischecked));
238   }
239 }
240
241 void
242 tcase_set_timeout (TCase * tc, double timeout)
243 {
244 #if defined(HAVE_FORK)
245   if (timeout >= 0) {
246     char *env = getenv ("CK_TIMEOUT_MULTIPLIER");
247
248     if (env != NULL) {
249       char *endptr = NULL;
250       double tmp = strtod (env, &endptr);
251
252       if (tmp >= 0 && endptr != env && (*endptr) == '\0') {
253         timeout = timeout * tmp;
254       }
255     }
256
257     tc->timeout.tv_sec = (time_t) floor (timeout);
258     tc->timeout.tv_nsec =
259         (long) ((timeout - floor (timeout)) * (double) NANOS_PER_SECONDS);
260   }
261 #else
262   (void) tc;
263   (void) timeout;
264   eprintf
265       ("This version does not support timeouts, as fork is not supported",
266       __FILE__, __LINE__);
267 #endif /* HAVE_FORK */
268 }
269
270 void
271 tcase_fn_start (const char *fname CK_ATTRIBUTE_UNUSED, const char *file,
272     int line)
273 {
274   send_ctx_info (CK_CTX_TEST);
275   send_loc_info (file, line);
276 }
277
278 void
279 _mark_point (const char *file, int line)
280 {
281   send_loc_info (file, line);
282 }
283
284 void
285 _ck_assert_failed (const char *file, int line, const char *expr, ...)
286 {
287   const char *msg;
288   va_list ap;
289   char buf[BUFSIZ];
290
291   send_loc_info (file, line);
292
293   va_start (ap, expr);
294   msg = (const char *) va_arg (ap, char *);
295
296   if (msg == NULL)
297     msg = expr;
298   vsnprintf (buf, BUFSIZ, msg, ap);
299   va_end (ap);
300   send_failure_info (buf);
301   if (cur_fork_status () == CK_FORK) {
302 #if defined(HAVE_FORK) && HAVE_FORK==1
303     _exit (1);
304 #endif /* HAVE_FORK */
305   } else {
306     longjmp (error_jmp_buffer, 1);
307   }
308 }
309
310 SRunner *
311 srunner_create (Suite * s)
312 {
313   SRunner *sr = (SRunner *) emalloc (sizeof (SRunner)); /* freed in srunner_free */
314
315   sr->slst = check_list_create ();
316   if (s != NULL)
317     check_list_add_end (sr->slst, s);
318   sr->stats = (TestStats *) emalloc (sizeof (TestStats));       /* freed in srunner_free */
319   sr->stats->n_checked = sr->stats->n_failed = sr->stats->n_errors = 0;
320   sr->resultlst = check_list_create ();
321   sr->log_fname = NULL;
322   sr->xml_fname = NULL;
323   sr->tap_fname = NULL;
324   sr->loglst = NULL;
325
326 #if defined(HAVE_FORK)
327   sr->fstat = CK_FORK_GETENV;
328 #else
329   /*
330    * Overriding the default of running tests in fork mode,
331    * as this system does not have fork()
332    */
333   sr->fstat = CK_NOFORK;
334 #endif /* HAVE_FORK */
335
336   return sr;
337 }
338
339 void
340 srunner_add_suite (SRunner * sr, Suite * s)
341 {
342   if (s == NULL)
343     return;
344
345   check_list_add_end (sr->slst, s);
346 }
347
348 void
349 srunner_free (SRunner * sr)
350 {
351   List *l;
352   TestResult *tr;
353
354   if (sr == NULL)
355     return;
356
357   free (sr->stats);
358   l = sr->slst;
359   for (check_list_front (l); !check_list_at_end (l); check_list_advance (l)) {
360     suite_free ((Suite *) check_list_val (l));
361   }
362   check_list_free (sr->slst);
363
364   l = sr->resultlst;
365   for (check_list_front (l); !check_list_at_end (l); check_list_advance (l)) {
366     tr = (TestResult *) check_list_val (l);
367     tr_free (tr);
368   }
369   check_list_free (sr->resultlst);
370
371   free (sr);
372 }
373
374 int
375 srunner_ntests_failed (SRunner * sr)
376 {
377   return sr->stats->n_failed + sr->stats->n_errors;
378 }
379
380 int
381 srunner_ntests_run (SRunner * sr)
382 {
383   return sr->stats->n_checked;
384 }
385
386 TestResult **
387 srunner_failures (SRunner * sr)
388 {
389   int i = 0;
390   TestResult **trarray;
391   List *rlst;
392
393   trarray =
394       (TestResult **) emalloc (sizeof (trarray[0]) *
395       srunner_ntests_failed (sr));
396
397   rlst = sr->resultlst;
398   for (check_list_front (rlst); !check_list_at_end (rlst);
399       check_list_advance (rlst)) {
400     TestResult *tr = (TestResult *) check_list_val (rlst);
401
402     if (non_pass (tr->rtype))
403       trarray[i++] = tr;
404
405   }
406   return trarray;
407 }
408
409 TestResult **
410 srunner_results (SRunner * sr)
411 {
412   int i = 0;
413   TestResult **trarray;
414   List *rlst;
415
416   trarray =
417       (TestResult **) emalloc (sizeof (trarray[0]) * srunner_ntests_run (sr));
418
419   rlst = sr->resultlst;
420   for (check_list_front (rlst); !check_list_at_end (rlst);
421       check_list_advance (rlst)) {
422     trarray[i++] = (TestResult *) check_list_val (rlst);
423   }
424   return trarray;
425 }
426
427 static int
428 non_pass (int val)
429 {
430   return val != CK_PASS;
431 }
432
433 TestResult *
434 tr_create (void)
435 {
436   TestResult *tr;
437
438   tr = (TestResult *) emalloc (sizeof (TestResult));
439   tr_init (tr);
440   return tr;
441 }
442
443 static void
444 tr_init (TestResult * tr)
445 {
446   tr->ctx = CK_CTX_INVALID;
447   tr->line = -1;
448   tr->rtype = CK_TEST_RESULT_INVALID;
449   tr->msg = NULL;
450   tr->file = NULL;
451   tr->tcname = NULL;
452   tr->tname = NULL;
453   tr->duration = -1;
454 }
455
456 void
457 tr_free (TestResult * tr)
458 {
459   free (tr->file);
460   free (tr->msg);
461   free (tr);
462 }
463
464
465 const char *
466 tr_msg (TestResult * tr)
467 {
468   return tr->msg;
469 }
470
471 int
472 tr_lno (TestResult * tr)
473 {
474   return tr->line;
475 }
476
477 const char *
478 tr_lfile (TestResult * tr)
479 {
480   return tr->file;
481 }
482
483 int
484 tr_rtype (TestResult * tr)
485 {
486   return tr->rtype;
487 }
488
489 enum ck_result_ctx
490 tr_ctx (TestResult * tr)
491 {
492   return tr->ctx;
493 }
494
495 const char *
496 tr_tcname (TestResult * tr)
497 {
498   return tr->tcname;
499 }
500
501 static enum fork_status _fstat = CK_FORK;
502
503 void
504 set_fork_status (enum fork_status fstat)
505 {
506   if (fstat == CK_FORK || fstat == CK_NOFORK || fstat == CK_FORK_GETENV)
507     _fstat = fstat;
508   else
509     eprintf ("Bad status in set_fork_status", __FILE__, __LINE__);
510 }
511
512 enum fork_status
513 cur_fork_status (void)
514 {
515   return _fstat;
516 }
517
518 /**
519  * Not all systems support the same clockid_t's. This call checks
520  * if the CLOCK_MONOTONIC clockid_t is valid. If so, that is returned,
521  * otherwise, CLOCK_REALTIME is returned.
522  *
523  * The clockid_t that was found to work on the first call is
524  * cached for subsequent calls.
525  */
526 clockid_t
527 check_get_clockid ()
528 {
529   static clockid_t clockid = -1;
530
531   if (clockid == -1) {
532 /*
533  * Only check if we have librt available. Otherwise, the clockid
534  * will be ignored anyway, as the clock_gettime() and
535  * timer_create() functions will be re-implemented in libcompat.
536  * Worse, if librt and alarm() are unavailable, this check
537  * will result in an assert(0).
538  */
539 #ifdef HAVE_LIBRT
540     timer_t timerid;
541
542     if (timer_create (CLOCK_MONOTONIC, NULL, &timerid) == 0) {
543       timer_delete (timerid);
544       clockid = CLOCK_MONOTONIC;
545     } else {
546       clockid = CLOCK_REALTIME;
547     }
548 #else
549     clockid = CLOCK_MONOTONIC;
550 #endif
551   }
552
553   return clockid;
554 }