check: Import version 0.9.14
[platform/upstream/gstreamer.git] / libs / gst / check / libcheck / check_run.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 <sys/types.h>
24 #include <time.h>
25 #include <stdlib.h>
26 #include <stdio.h>
27 #include <string.h>
28 #include <stdarg.h>
29 #include <signal.h>
30 #include <setjmp.h>
31
32 #include "check.h"
33 #include "check_error.h"
34 #include "check_list.h"
35 #include "check_impl.h"
36 #include "check_msg.h"
37 #include "check_log.h"
38
39 enum rinfo
40 {
41   CK_R_SIG,
42   CK_R_PASS,
43   CK_R_EXIT,
44   CK_R_FAIL_TEST,
45   CK_R_FAIL_FIXTURE
46 };
47
48 enum tf_type
49 {
50   CK_FORK_TEST,
51   CK_NOFORK_TEST,
52   CK_NOFORK_FIXTURE
53 };
54
55
56 /* all functions are defined in the same order they are declared.
57    functions that depend on forking are gathered all together.
58    non-static functions are at the end of the file. */
59 static void srunner_run_init (SRunner * sr, enum print_output print_mode);
60 static void srunner_run_end (SRunner * sr, enum print_output print_mode);
61 static void srunner_iterate_suites (SRunner * sr,
62     const char *sname, const char *tcname, enum print_output print_mode);
63 static void srunner_iterate_tcase_tfuns (SRunner * sr, TCase * tc);
64 static void srunner_add_failure (SRunner * sr, TestResult * tf);
65 static TestResult *srunner_run_setup (List * func_list,
66     enum fork_status fork_usage, const char *test_name, const char *setup_name);
67 static int srunner_run_unchecked_setup (SRunner * sr, TCase * tc);
68 static TestResult *tcase_run_checked_setup (SRunner * sr, TCase * tc);
69 static void srunner_run_teardown (List * fixture_list,
70     enum fork_status fork_usage);
71 static void srunner_run_unchecked_teardown (SRunner * sr, TCase * tc);
72 static void tcase_run_checked_teardown (TCase * tc);
73 static void srunner_run_tcase (SRunner * sr, TCase * tc);
74 static TestResult *tcase_run_tfun_nofork (SRunner * sr, TCase * tc, TF * tf,
75     int i);
76 static TestResult *receive_result_info_nofork (const char *tcname,
77     const char *tname, int iter, int duration);
78 static void set_nofork_info (TestResult * tr);
79 static char *pass_msg (void);
80
81 #if defined(HAVE_FORK) && HAVE_FORK==1
82 static TestResult *tcase_run_tfun_fork (SRunner * sr, TCase * tc, TF * tf,
83     int i);
84 static TestResult *receive_result_info_fork (const char *tcname,
85     const char *tname, int iter,
86     int status, int expected_signal, signed char allowed_exit_value);
87 static void set_fork_info (TestResult * tr, int status, int expected_signal,
88     signed char allowed_exit_value);
89 static char *signal_msg (int sig);
90 static char *signal_error_msg (int signal_received, int signal_expected);
91 static char *exit_msg (int exitstatus);
92 static int waserror (int status, int expected_signal);
93
94 static int alarm_received;
95 static pid_t group_pid;
96
97 static void CK_ATTRIBUTE_UNUSED
98 sig_handler (int sig_nr)
99 {
100   switch (sig_nr) {
101     case SIGALRM:
102       alarm_received = 1;
103       killpg (group_pid, SIGKILL);
104       break;
105     default:
106       eprintf ("Unhandled signal: %d", __FILE__, __LINE__, sig_nr);
107       break;
108   }
109 }
110 #endif /* HAVE_FORK */
111
112 #define MSG_LEN 100
113
114 static void
115 srunner_run_init (SRunner * sr, enum print_output print_mode)
116 {
117   set_fork_status (srunner_fork_status (sr));
118   setup_messaging ();
119   srunner_init_logging (sr, print_mode);
120   log_srunner_start (sr);
121 }
122
123 static void
124 srunner_run_end (SRunner * sr, enum print_output CK_ATTRIBUTE_UNUSED print_mode)
125 {
126   log_srunner_end (sr);
127   srunner_end_logging (sr);
128   teardown_messaging ();
129   set_fork_status (CK_FORK);
130 }
131
132 static void
133 srunner_iterate_suites (SRunner * sr,
134     const char *sname, const char *tcname,
135     enum print_output CK_ATTRIBUTE_UNUSED print_mode)
136 {
137   List *slst;
138   List *tcl;
139   TCase *tc;
140
141   slst = sr->slst;
142
143   for (check_list_front (slst); !check_list_at_end (slst);
144       check_list_advance (slst)) {
145     Suite *s = (Suite *) check_list_val (slst);
146
147     if (((sname != NULL) && (strcmp (sname, s->name) != 0))
148         || ((tcname != NULL) && (!suite_tcase (s, tcname))))
149       continue;
150
151     log_suite_start (sr, s);
152
153     tcl = s->tclst;
154
155     for (check_list_front (tcl); !check_list_at_end (tcl);
156         check_list_advance (tcl)) {
157       tc = (TCase *) check_list_val (tcl);
158
159       if ((tcname != NULL) && (strcmp (tcname, tc->name) != 0)) {
160         continue;
161       }
162
163       srunner_run_tcase (sr, tc);
164     }
165
166     log_suite_end (sr, s);
167   }
168 }
169
170 static void
171 srunner_iterate_tcase_tfuns (SRunner * sr, TCase * tc)
172 {
173   List *tfl;
174   TF *tfun;
175   TestResult *tr = NULL;
176
177   tfl = tc->tflst;
178
179   for (check_list_front (tfl); !check_list_at_end (tfl);
180       check_list_advance (tfl)) {
181     int i;
182
183     tfun = (TF *) check_list_val (tfl);
184
185     for (i = tfun->loop_start; i < tfun->loop_end; i++) {
186       log_test_start (sr, tc, tfun);
187       switch (srunner_fork_status (sr)) {
188         case CK_FORK:
189 #if defined(HAVE_FORK) && HAVE_FORK==1
190           tr = tcase_run_tfun_fork (sr, tc, tfun, i);
191 #else /* HAVE_FORK */
192           eprintf ("This version does not support fork", __FILE__, __LINE__);
193 #endif /* HAVE_FORK */
194           break;
195         case CK_NOFORK:
196           tr = tcase_run_tfun_nofork (sr, tc, tfun, i);
197           break;
198         case CK_FORK_GETENV:
199         default:
200           eprintf ("Bad fork status in SRunner", __FILE__, __LINE__);
201       }
202
203       if (NULL != tr) {
204         srunner_add_failure (sr, tr);
205         log_test_end (sr, tr);
206       }
207     }
208   }
209 }
210
211 static void
212 srunner_add_failure (SRunner * sr, TestResult * tr)
213 {
214   check_list_add_end (sr->resultlst, tr);
215   sr->stats->n_checked++;       /* count checks during setup, test, and teardown */
216   if (tr->rtype == CK_FAILURE)
217     sr->stats->n_failed++;
218   else if (tr->rtype == CK_ERROR)
219     sr->stats->n_errors++;
220
221 }
222
223 static TestResult *
224 srunner_run_setup (List * fixture_list, enum fork_status fork_usage,
225     const char *test_name, const char *setup_name)
226 {
227   TestResult *tr = NULL;
228   Fixture *setup_fixture;
229
230   if (fork_usage == CK_FORK) {
231     send_ctx_info (CK_CTX_SETUP);
232   }
233
234   for (check_list_front (fixture_list); !check_list_at_end (fixture_list);
235       check_list_advance (fixture_list)) {
236     setup_fixture = (Fixture *) check_list_val (fixture_list);
237
238     if (fork_usage == CK_NOFORK) {
239       send_ctx_info (CK_CTX_SETUP);
240
241       if (0 == setjmp (error_jmp_buffer)) {
242         setup_fixture->fun ();
243       }
244
245       /* Stop the setup and return the failure in nofork mode. */
246       tr = receive_result_info_nofork (test_name, setup_name, 0, -1);
247       if (tr->rtype != CK_PASS) {
248         break;
249       }
250
251       free (tr->file);
252       free (tr->msg);
253       free (tr);
254       tr = NULL;
255     } else {
256       setup_fixture->fun ();
257     }
258   }
259
260   return tr;
261 }
262
263 static int
264 srunner_run_unchecked_setup (SRunner * sr, TCase * tc)
265 {
266   TestResult *tr = NULL;
267   int rval = 1;
268
269   set_fork_status (CK_NOFORK);
270   tr = srunner_run_setup (tc->unch_sflst, CK_NOFORK, tc->name,
271       "unchecked_setup");
272   set_fork_status (srunner_fork_status (sr));
273
274   if (tr != NULL && tr->rtype != CK_PASS) {
275     srunner_add_failure (sr, tr);
276     rval = 0;
277   }
278
279   return rval;
280 }
281
282 static TestResult *
283 tcase_run_checked_setup (SRunner * sr, TCase * tc)
284 {
285   TestResult *tr = srunner_run_setup (tc->ch_sflst, srunner_fork_status (sr),
286       tc->name, "checked_setup");
287
288   return tr;
289 }
290
291 static void
292 srunner_run_teardown (List * fixture_list, enum fork_status fork_usage)
293 {
294   Fixture *fixture;
295
296   for (check_list_front (fixture_list); !check_list_at_end (fixture_list);
297       check_list_advance (fixture_list)) {
298     fixture = (Fixture *) check_list_val (fixture_list);
299     send_ctx_info (CK_CTX_TEARDOWN);
300
301     if (fork_usage == CK_NOFORK) {
302       if (0 == setjmp (error_jmp_buffer)) {
303         fixture->fun ();
304       } else {
305         /* Abort the remaining teardowns */
306         break;
307       }
308     } else {
309       fixture->fun ();
310     }
311   }
312 }
313
314 static void
315 srunner_run_unchecked_teardown (SRunner * sr, TCase * tc)
316 {
317   srunner_run_teardown (tc->unch_tflst, srunner_fork_status (sr));
318 }
319
320 static void
321 tcase_run_checked_teardown (TCase * tc)
322 {
323   srunner_run_teardown (tc->ch_tflst, CK_NOFORK);
324 }
325
326 static void
327 srunner_run_tcase (SRunner * sr, TCase * tc)
328 {
329   if (srunner_run_unchecked_setup (sr, tc)) {
330     srunner_iterate_tcase_tfuns (sr, tc);
331     srunner_run_unchecked_teardown (sr, tc);
332   }
333 }
334
335 static TestResult *
336 tcase_run_tfun_nofork (SRunner * sr, TCase * tc, TF * tfun, int i)
337 {
338   TestResult *tr;
339   struct timespec ts_start = { 0, 0 }, ts_end = {
340   0, 0};
341
342   tr = tcase_run_checked_setup (sr, tc);
343   if (tr == NULL) {
344     clock_gettime (check_get_clockid (), &ts_start);
345     if (0 == setjmp (error_jmp_buffer)) {
346       tfun->fn (i);
347     }
348     clock_gettime (check_get_clockid (), &ts_end);
349     tcase_run_checked_teardown (tc);
350     return receive_result_info_nofork (tc->name, tfun->name, i,
351         DIFF_IN_USEC (ts_start, ts_end));
352   }
353
354   return tr;
355 }
356
357 static TestResult *
358 receive_result_info_nofork (const char *tcname,
359     const char *tname, int iter, int duration)
360 {
361   TestResult *tr;
362
363   tr = receive_test_result (0);
364   if (tr == NULL) {
365     eprintf ("Failed to receive test result", __FILE__, __LINE__);
366   } else {
367     tr->tcname = tcname;
368     tr->tname = tname;
369     tr->iter = iter;
370     tr->duration = duration;
371     set_nofork_info (tr);
372   }
373
374   return tr;
375 }
376
377 static void
378 set_nofork_info (TestResult * tr)
379 {
380   if (tr->msg == NULL) {
381     tr->rtype = CK_PASS;
382     tr->msg = pass_msg ();
383   } else {
384     tr->rtype = CK_FAILURE;
385   }
386 }
387
388 static char *
389 pass_msg (void)
390 {
391   return strdup ("Passed");
392 }
393
394 #if defined(HAVE_FORK) && HAVE_FORK==1
395 static TestResult *
396 tcase_run_tfun_fork (SRunner * sr, TCase * tc, TF * tfun, int i)
397 {
398   pid_t pid_w;
399   pid_t pid;
400   int status = 0;
401   struct timespec ts_start = { 0, 0 }, ts_end = {
402   0, 0};
403
404   timer_t timerid;
405   struct itimerspec timer_spec;
406   TestResult *tr;
407
408
409   pid = fork ();
410   if (pid == -1)
411     eprintf ("Error in call to fork:", __FILE__, __LINE__ - 2);
412   if (pid == 0) {
413     setpgid (0, 0);
414     group_pid = getpgrp ();
415     tr = tcase_run_checked_setup (sr, tc);
416     free (tr);
417     clock_gettime (check_get_clockid (), &ts_start);
418     tfun->fn (i);
419     clock_gettime (check_get_clockid (), &ts_end);
420     tcase_run_checked_teardown (tc);
421     send_duration_info (DIFF_IN_USEC (ts_start, ts_end));
422     exit (EXIT_SUCCESS);
423   } else {
424     group_pid = pid;
425   }
426
427   alarm_received = 0;
428
429   if (timer_create (check_get_clockid (),
430           NULL /* fire SIGALRM if timer expires */ ,
431           &timerid) == 0) {
432     /* Set the timer to fire once */
433     timer_spec.it_value = tc->timeout;
434     timer_spec.it_interval.tv_sec = 0;
435     timer_spec.it_interval.tv_nsec = 0;
436     if (timer_settime (timerid, 0, &timer_spec, NULL) == 0) {
437       do {
438         pid_w = waitpid (pid, &status, 0);
439       }
440       while (pid_w == -1);
441     } else {
442       eprintf ("Error in call to timer_settime:", __FILE__, __LINE__);
443     }
444
445     /* If the timer has not fired, disable it */
446     timer_delete (timerid);
447   } else {
448     eprintf ("Error in call to timer_create:", __FILE__, __LINE__);
449   }
450
451   killpg (pid, SIGKILL);        /* Kill remaining processes. */
452
453   return receive_result_info_fork (tc->name, tfun->name, i, status,
454       tfun->signal, tfun->allowed_exit_value);
455 }
456
457 static TestResult *
458 receive_result_info_fork (const char *tcname,
459     const char *tname,
460     int iter, int status, int expected_signal, signed char allowed_exit_value)
461 {
462   TestResult *tr;
463
464   tr = receive_test_result (waserror (status, expected_signal));
465   if (tr == NULL) {
466     eprintf ("Failed to receive test result", __FILE__, __LINE__);
467   } else {
468     tr->tcname = tcname;
469     tr->tname = tname;
470     tr->iter = iter;
471     set_fork_info (tr, status, expected_signal, allowed_exit_value);
472   }
473
474   return tr;
475 }
476
477 static void
478 set_fork_info (TestResult * tr, int status, int signal_expected,
479     signed char allowed_exit_value)
480 {
481   int was_sig = WIFSIGNALED (status);
482   int was_exit = WIFEXITED (status);
483   signed char exit_status = WEXITSTATUS (status);
484   int signal_received = WTERMSIG (status);
485
486   if (was_sig) {
487     if (signal_expected == signal_received) {
488       if (alarm_received) {
489         /* Got alarm instead of signal */
490         tr->rtype = CK_ERROR;
491         if (tr->msg != NULL) {
492           free (tr->msg);
493         }
494         tr->msg = signal_error_msg (signal_received, signal_expected);
495       } else {
496         tr->rtype = CK_PASS;
497         if (tr->msg != NULL) {
498           free (tr->msg);
499         }
500         tr->msg = pass_msg ();
501       }
502     } else if (signal_expected != 0) {
503       /* signal received, but not the expected one */
504       tr->rtype = CK_ERROR;
505       if (tr->msg != NULL) {
506         free (tr->msg);
507       }
508       tr->msg = signal_error_msg (signal_received, signal_expected);
509     } else {
510       /* signal received and none expected */
511       tr->rtype = CK_ERROR;
512       if (tr->msg != NULL) {
513         free (tr->msg);
514       }
515       tr->msg = signal_msg (signal_received);
516     }
517   } else if (signal_expected == 0) {
518     if (was_exit && exit_status == allowed_exit_value) {
519       tr->rtype = CK_PASS;
520       if (tr->msg != NULL) {
521         free (tr->msg);
522       }
523       tr->msg = pass_msg ();
524     } else if (was_exit && exit_status != allowed_exit_value) {
525       if (tr->msg == NULL) {    /* early exit */
526         tr->rtype = CK_ERROR;
527         tr->msg = exit_msg (exit_status);
528       } else {
529         tr->rtype = CK_FAILURE;
530       }
531     }
532   } else {                      /* a signal was expected and none raised */
533     if (was_exit) {
534       if (tr->msg != NULL) {
535         free (tr->msg);
536       }
537       tr->msg = exit_msg (exit_status);
538       if (exit_status == allowed_exit_value) {
539         tr->rtype = CK_FAILURE; /* normal exit status */
540       } else {
541         tr->rtype = CK_FAILURE; /* early exit */
542       }
543     }
544   }
545 }
546
547 static char *
548 signal_msg (int signal)
549 {
550   char *msg = (char *) emalloc (MSG_LEN);       /* free'd by caller */
551
552   if (alarm_received) {
553     snprintf (msg, MSG_LEN, "Test timeout expired");
554   } else {
555     snprintf (msg, MSG_LEN, "Received signal %d (%s)",
556         signal, strsignal (signal));
557   }
558   return msg;
559 }
560
561 static char *
562 signal_error_msg (int signal_received, int signal_expected)
563 {
564   char *sig_r_str;
565   char *sig_e_str;
566   char *msg = (char *) emalloc (MSG_LEN);       /* free'd by caller */
567
568   sig_r_str = strdup (strsignal (signal_received));
569   sig_e_str = strdup (strsignal (signal_expected));
570   if (alarm_received) {
571     snprintf (msg, MSG_LEN,
572         "Test timeout expired, expected signal %d (%s)",
573         signal_expected, sig_e_str);
574   } else {
575     snprintf (msg, MSG_LEN, "Received signal %d (%s), expected %d (%s)",
576         signal_received, sig_r_str, signal_expected, sig_e_str);
577   }
578   free (sig_r_str);
579   free (sig_e_str);
580   return msg;
581 }
582
583 static char *
584 exit_msg (int exitval)
585 {
586   char *msg = (char *) emalloc (MSG_LEN);       /* free'd by caller */
587
588   snprintf (msg, MSG_LEN, "Early exit with return value %d", exitval);
589   return msg;
590 }
591
592 static int
593 waserror (int status, int signal_expected)
594 {
595   int was_sig = WIFSIGNALED (status);
596   int was_exit = WIFEXITED (status);
597   int exit_status = WEXITSTATUS (status);
598   int signal_received = WTERMSIG (status);
599
600   return ((was_sig && (signal_received != signal_expected)) ||
601       (was_exit && exit_status != 0));
602 }
603 #endif /* HAVE_FORK */
604
605 enum fork_status
606 srunner_fork_status (SRunner * sr)
607 {
608   if (sr->fstat == CK_FORK_GETENV) {
609     char *env = getenv ("CK_FORK");
610
611     if (env == NULL)
612 #if defined(HAVE_FORK) && HAVE_FORK==1
613       return CK_FORK;
614 #else
615       return CK_NOFORK;
616 #endif
617     if (strcmp (env, "no") == 0)
618       return CK_NOFORK;
619     else {
620 #if defined(HAVE_FORK) && HAVE_FORK==1
621       return CK_FORK;
622 #else /* HAVE_FORK */
623       eprintf ("This version does not support fork", __FILE__, __LINE__);
624       return CK_NOFORK;
625 #endif /* HAVE_FORK */
626     }
627   } else
628     return sr->fstat;
629 }
630
631 void
632 srunner_set_fork_status (SRunner * sr, enum fork_status fstat)
633 {
634 #if !defined(HAVE_FORK) || HAVE_FORK==0
635   /* If fork() is unavailable, do not allow a fork mode to be set */
636   if (fstat != CK_NOFORK) {
637     eprintf ("This version does not support fork", __FILE__, __LINE__);
638   }
639 #endif /* ! HAVE_FORK */
640   sr->fstat = fstat;
641 }
642
643 void
644 srunner_run_all (SRunner * sr, enum print_output print_mode)
645 {
646   srunner_run (sr, NULL,        /* All test suites.  */
647       NULL,                     /* All test cases.   */
648       print_mode);
649 }
650
651 void
652 srunner_run (SRunner * sr, const char *sname, const char *tcname,
653     enum print_output print_mode)
654 {
655 #if defined(HAVE_SIGACTION) && defined(HAVE_FORK)
656   struct sigaction old_action;
657   struct sigaction new_action;
658 #endif /* HAVE_SIGACTION && HAVE_FORK */
659
660   /*  Get the selected test suite and test case from the
661      environment.  */
662   if (!tcname)
663     tcname = getenv ("CK_RUN_CASE");
664   if (!sname)
665     sname = getenv ("CK_RUN_SUITE");
666
667   if (sr == NULL)
668     return;
669   if (print_mode >= CK_LAST) {
670     eprintf ("Bad print_mode argument to srunner_run_all: %d",
671         __FILE__, __LINE__, print_mode);
672   }
673 #if defined(HAVE_SIGACTION) && defined(HAVE_FORK)
674   memset (&new_action, 0, sizeof new_action);
675   new_action.sa_handler = sig_handler;
676   sigaction (SIGALRM, &new_action, &old_action);
677 #endif /* HAVE_SIGACTION && HAVE_FORK */
678   srunner_run_init (sr, print_mode);
679   srunner_iterate_suites (sr, sname, tcname, print_mode);
680   srunner_run_end (sr, print_mode);
681 #if defined(HAVE_SIGACTION) && defined(HAVE_FORK)
682   sigaction (SIGALRM, &old_action, NULL);
683 #endif /* HAVE_SIGACTION && HAVE_FORK */
684 }
685
686 pid_t
687 check_fork (void)
688 {
689 #if defined(HAVE_FORK) && HAVE_FORK==1
690   pid_t pid = fork ();
691
692   /* Set the process to a process group to be able to kill it easily. */
693   if (pid >= 0) {
694     setpgid (pid, group_pid);
695   }
696   return pid;
697 #else /* HAVE_FORK */
698   eprintf ("This version does not support fork", __FILE__, __LINE__);
699   return 0;
700 #endif /* HAVE_FORK */
701 }
702
703 void
704 check_waitpid_and_exit (pid_t pid CK_ATTRIBUTE_UNUSED)
705 {
706 #if defined(HAVE_FORK) && HAVE_FORK==1
707   pid_t pid_w;
708   int status;
709
710   if (pid > 0) {
711     do {
712       pid_w = waitpid (pid, &status, 0);
713     }
714     while (pid_w == -1);
715     if (waserror (status, 0)) {
716       exit (EXIT_FAILURE);
717     }
718   }
719   exit (EXIT_SUCCESS);
720 #else /* HAVE_FORK */
721   eprintf ("This version does not support fork", __FILE__, __LINE__);
722 #endif /* HAVE_FORK */
723 }