Initialize Tizen 2.3
[framework/multimedia/gstreamer0.10.git] / mobile / 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., 59 Temple Place - Suite 330,
18  * Boston, MA 02111-1307, USA.
19  */
20
21 #include "config.h"
22
23 #include <sys/types.h>
24 #ifdef HAVE_SYS_WAIT_H
25 #include <sys/wait.h>
26 #endif
27 #ifdef HAVE_UNISTD_H
28 #include <unistd.h>
29 #endif
30 #include <stdlib.h>
31 #include <stdio.h>
32 #include <string.h>
33 #include <stdarg.h>
34 #include <signal.h>
35
36 #include "check.h"
37 #include "check_error.h"
38 #include "check_list.h"
39 #include "check_impl.h"
40 #include "check_msg.h"
41 #include "check_log.h"
42
43 enum rinfo
44 {
45   CK_R_SIG,
46   CK_R_PASS,
47   CK_R_EXIT,
48   CK_R_FAIL_TEST,
49   CK_R_FAIL_FIXTURE
50 };
51
52 enum tf_type
53 {
54   CK_FORK_TEST,
55   CK_NOFORK_TEST,
56   CK_NOFORK_FIXTURE
57 };
58
59 /* all functions are defined in the same order they are declared.
60    functions that depend on forking are gathered all together.
61    non-static functions are at the end of the file. */
62 static void srunner_run_init (SRunner * sr, enum print_output print_mode);
63 static void srunner_run_end (SRunner * sr, enum print_output print_mode);
64 static void srunner_iterate_suites (SRunner * sr, enum print_output print_mode);
65 static void srunner_iterate_tcase_tfuns (SRunner * sr, TCase * tc);
66 static void srunner_add_failure (SRunner * sr, TestResult * tf);
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 * l);
70 static void srunner_run_unchecked_teardown (TCase * tc);
71 static void tcase_run_checked_teardown (TCase * tc);
72 static void srunner_run_tcase (SRunner * sr, TCase * tc);
73 static TestResult *tcase_run_tfun_nofork (SRunner * sr, TCase * tc, TF * tf,
74     int i);
75 static TestResult *receive_result_info_nofork (const char *tcname,
76     const char *tname, int iter);
77 static void set_nofork_info (TestResult * tr);
78 static char *pass_msg (void);
79
80 #ifdef _POSIX_VERSION
81 static TestResult *tcase_run_tfun_fork (SRunner * sr, TCase * tc, TF * tf,
82     int i);
83 static TestResult *receive_result_info_fork (const char *tcname,
84     const char *tname, int iter, int status, int expected_signal,
85     unsigned char allowed_exit_value);
86 static void set_fork_info (TestResult * tr, int status, int expected_signal,
87     unsigned char allowed_exit_value);
88 static char *signal_msg (int sig);
89 static char *signal_error_msg (int signal_received, int signal_expected);
90 static char *exit_msg (int exitstatus);
91 static int waserror (int status, int expected_signal);
92
93 static int alarm_received;
94 static pid_t group_pid;
95
96 static void CK_ATTRIBUTE_UNUSED
97 sig_handler (int sig_nr)
98 {
99   switch (sig_nr) {
100     case SIGALRM:
101       alarm_received = 1;
102       killpg (group_pid, SIGKILL);
103       break;
104     default:
105       eprintf ("Unhandled signal: %d", __FILE__, __LINE__, sig_nr);
106       break;
107   }
108 }
109 #endif /* _POSIX_VERSION */
110
111 #define MSG_LEN 100
112
113 static void
114 srunner_run_init (SRunner * sr, enum print_output print_mode)
115 {
116   set_fork_status (srunner_fork_status (sr));
117   setup_messaging ();
118   srunner_init_logging (sr, print_mode);
119   log_srunner_start (sr);
120 }
121
122 static void
123 srunner_run_end (SRunner * sr, enum print_output CK_ATTRIBUTE_UNUSED print_mode)
124 {
125   log_srunner_end (sr);
126   srunner_end_logging (sr);
127   teardown_messaging ();
128   set_fork_status (CK_FORK);
129 }
130
131 static void
132 srunner_iterate_suites (SRunner * sr,
133     enum print_output CK_ATTRIBUTE_UNUSED print_mode)
134 {
135   List *slst;
136   List *tcl;
137   TCase *tc;
138
139   slst = sr->slst;
140
141   for (list_front (slst); !list_at_end (slst); list_advance (slst)) {
142     Suite *s = list_val (slst);
143
144     log_suite_start (sr, s);
145
146     tcl = s->tclst;
147
148     for (list_front (tcl); !list_at_end (tcl); list_advance (tcl)) {
149       tc = list_val (tcl);
150       srunner_run_tcase (sr, tc);
151     }
152
153     log_suite_end (sr, s);
154   }
155 }
156
157 static void
158 srunner_iterate_tcase_tfuns (SRunner * sr, TCase * tc)
159 {
160   List *tfl;
161   TF *tfun;
162   TestResult *tr = NULL;
163
164   tfl = tc->tflst;
165
166   for (list_front (tfl); !list_at_end (tfl); list_advance (tfl)) {
167     int i;
168     tfun = list_val (tfl);
169
170     for (i = tfun->loop_start; i < tfun->loop_end; i++) {
171       log_test_start (sr, tc, tfun);
172       switch (srunner_fork_status (sr)) {
173         case CK_FORK:
174 #ifdef _POSIX_VERSION
175           tr = tcase_run_tfun_fork (sr, tc, tfun, i);
176 #else /* _POSIX_VERSION */
177           eprintf ("This version does not support fork", __FILE__, __LINE__);
178 #endif /* _POSIX_VERSION */
179           break;
180         case CK_NOFORK:
181           tr = tcase_run_tfun_nofork (sr, tc, tfun, i);
182           break;
183         default:
184           eprintf ("Bad fork status in SRunner", __FILE__, __LINE__);
185       }
186       srunner_add_failure (sr, tr);
187       log_test_end (sr, tr);
188     }
189   }
190 }
191
192 static void
193 srunner_add_failure (SRunner * sr, TestResult * tr)
194 {
195   list_add_end (sr->resultlst, tr);
196   sr->stats->n_checked++;       /* count checks during setup, test, and teardown */
197   if (tr->rtype == CK_FAILURE)
198     sr->stats->n_failed++;
199   else if (tr->rtype == CK_ERROR)
200     sr->stats->n_errors++;
201
202 }
203
204 static int
205 srunner_run_unchecked_setup (SRunner * sr, TCase * tc)
206 {
207   TestResult *tr;
208   List *l;
209   Fixture *f;
210   int rval = 1;
211
212   set_fork_status (CK_NOFORK);
213
214   l = tc->unch_sflst;
215
216   for (list_front (l); !list_at_end (l); list_advance (l)) {
217     send_ctx_info (CK_CTX_SETUP);
218     f = list_val (l);
219     f->fun ();
220
221     tr = receive_result_info_nofork (tc->name, "unchecked_setup", 0);
222
223     if (tr->rtype != CK_PASS) {
224       srunner_add_failure (sr, tr);
225       rval = 0;
226       break;
227     }
228     free (tr->file);
229     free (tr->msg);
230     free (tr);
231   }
232
233   set_fork_status (srunner_fork_status (sr));
234   return rval;
235 }
236
237 static TestResult *
238 tcase_run_checked_setup (SRunner * sr, TCase * tc)
239 {
240   TestResult *tr = NULL;
241   List *l;
242   Fixture *f;
243   enum fork_status fstat = srunner_fork_status (sr);
244
245   l = tc->ch_sflst;
246   if (fstat == CK_FORK) {
247     send_ctx_info (CK_CTX_SETUP);
248   }
249
250   for (list_front (l); !list_at_end (l); list_advance (l)) {
251     if (fstat == CK_NOFORK) {
252       send_ctx_info (CK_CTX_SETUP);
253     }
254     f = list_val (l);
255     f->fun ();
256
257     /* Stop the setup and return the failure if nofork mode. */
258     if (fstat == CK_NOFORK) {
259       tr = receive_result_info_nofork (tc->name, "checked_setup", 0);
260       if (tr->rtype != CK_PASS) {
261         break;
262       }
263
264       free (tr->file);
265       free (tr->msg);
266       free (tr);
267       tr = NULL;
268     }
269   }
270
271   return tr;
272 }
273
274 static void
275 srunner_run_teardown (List * l)
276 {
277   Fixture *f;
278
279   for (list_front (l); !list_at_end (l); list_advance (l)) {
280     f = list_val (l);
281     send_ctx_info (CK_CTX_TEARDOWN);
282     f->fun ();
283   }
284 }
285
286 static void
287 srunner_run_unchecked_teardown (TCase * tc)
288 {
289   srunner_run_teardown (tc->unch_tflst);
290 }
291
292 static void
293 tcase_run_checked_teardown (TCase * tc)
294 {
295   srunner_run_teardown (tc->ch_tflst);
296 }
297
298 static void
299 srunner_run_tcase (SRunner * sr, TCase * tc)
300 {
301   if (srunner_run_unchecked_setup (sr, tc)) {
302     srunner_iterate_tcase_tfuns (sr, tc);
303     srunner_run_unchecked_teardown (tc);
304   }
305 }
306
307 static TestResult *
308 tcase_run_tfun_nofork (SRunner * sr, TCase * tc, TF * tfun, int i)
309 {
310   TestResult *tr;
311
312   tr = tcase_run_checked_setup (sr, tc);
313   if (tr == NULL) {
314     tfun->fn (i);
315     tcase_run_checked_teardown (tc);
316     return receive_result_info_nofork (tc->name, tfun->name, i);
317   }
318
319   return tr;
320 }
321
322 static TestResult *
323 receive_result_info_nofork (const char *tcname, const char *tname, int iter)
324 {
325   TestResult *tr;
326
327   tr = receive_test_result (0);
328   if (tr == NULL)
329     eprintf ("Failed to receive test result", __FILE__, __LINE__);
330   tr->tcname = tcname;
331   tr->tname = tname;
332   tr->iter = iter;
333   set_nofork_info (tr);
334
335   return tr;
336 }
337
338 static void
339 set_nofork_info (TestResult * tr)
340 {
341   if (tr->msg == NULL) {
342     tr->rtype = CK_PASS;
343     tr->msg = pass_msg ();
344   } else {
345     tr->rtype = CK_FAILURE;
346   }
347 }
348
349 static char *
350 pass_msg (void)
351 {
352   char *msg = emalloc (sizeof ("Passed"));
353   strcpy (msg, "Passed");
354   return msg;
355 }
356
357 #ifdef _POSIX_VERSION
358 static TestResult *
359 tcase_run_tfun_fork (SRunner * sr, TCase * tc, TF * tfun, int i)
360 {
361   pid_t pid_w;
362   pid_t pid;
363   int status = 0;
364
365   pid = fork ();
366   if (pid == -1)
367     eprintf ("Error in call to fork:", __FILE__, __LINE__ - 2);
368   if (pid == 0) {
369     setpgid (0, 0);
370     group_pid = getpgrp ();
371     tcase_run_checked_setup (sr, tc);
372     tfun->fn (i);
373     tcase_run_checked_teardown (tc);
374     exit (EXIT_SUCCESS);
375   } else {
376     group_pid = pid;
377   }
378
379   alarm_received = 0;
380   alarm (tc->timeout);
381   do {
382     pid_w = waitpid (pid, &status, 0);
383   } while (pid_w == -1);
384
385   killpg (pid, SIGKILL);        /* Kill remaining processes. */
386
387   return receive_result_info_fork (tc->name, tfun->name, i, status,
388       tfun->signal, tfun->allowed_exit_value);
389 }
390
391 static TestResult *
392 receive_result_info_fork (const char *tcname,
393     const char *tname,
394     int iter, int status, int expected_signal, unsigned char allowed_exit_value)
395 {
396   TestResult *tr;
397
398   tr = receive_test_result (waserror (status, expected_signal));
399   if (tr == NULL)
400     eprintf ("Failed to receive test result", __FILE__, __LINE__);
401   tr->tcname = tcname;
402   tr->tname = tname;
403   tr->iter = iter;
404   set_fork_info (tr, status, expected_signal, allowed_exit_value);
405
406   return tr;
407 }
408
409 static void
410 set_fork_info (TestResult * tr, int status, int signal_expected,
411     unsigned char allowed_exit_value)
412 {
413   int was_sig = WIFSIGNALED (status);
414   int was_exit = WIFEXITED (status);
415   int exit_status = WEXITSTATUS (status);
416   int signal_received = WTERMSIG (status);
417
418   if (was_sig) {
419     if (signal_expected == signal_received) {
420       if (alarm_received) {
421         /* Got alarm instead of signal */
422         tr->rtype = CK_ERROR;
423         tr->msg = signal_error_msg (signal_received, signal_expected);
424       } else {
425         tr->rtype = CK_PASS;
426         tr->msg = pass_msg ();
427       }
428     } else if (signal_expected != 0) {
429       /* signal received, but not the expected one */
430       tr->rtype = CK_ERROR;
431       tr->msg = signal_error_msg (signal_received, signal_expected);
432     } else {
433       /* signal received and none expected */
434       tr->rtype = CK_ERROR;
435       tr->msg = signal_msg (signal_received);
436     }
437   } else if (signal_expected == 0) {
438     if (was_exit && exit_status == allowed_exit_value) {
439       tr->rtype = CK_PASS;
440       tr->msg = pass_msg ();
441     } else if (was_exit && exit_status != allowed_exit_value) {
442       if (tr->msg == NULL) {    /* early exit */
443         tr->rtype = CK_ERROR;
444         tr->msg = exit_msg (exit_status);
445       } else {
446         tr->rtype = CK_FAILURE;
447       }
448     }
449   } else {                      /* a signal was expected and none raised */
450     if (was_exit) {
451       tr->msg = exit_msg (exit_status);
452       if (exit_status == allowed_exit_value)
453         tr->rtype = CK_FAILURE; /* normal exit status */
454       else
455         tr->rtype = CK_FAILURE; /* early exit */
456     }
457   }
458 }
459
460 static char *
461 signal_msg (int signal)
462 {
463   char *msg = emalloc (MSG_LEN);        /* free'd by caller */
464   if (alarm_received) {
465     snprintf (msg, MSG_LEN, "Test timeout expired");
466   } else {
467     snprintf (msg, MSG_LEN, "Received signal %d (%s)",
468         signal, strsignal (signal));
469   }
470   return msg;
471 }
472
473 static char *
474 signal_error_msg (int signal_received, int signal_expected)
475 {
476   char *sig_r_str;
477   char *sig_e_str;
478   char *msg = emalloc (MSG_LEN);        /* free'd by caller */
479   sig_r_str = strdup (strsignal (signal_received));
480   sig_e_str = strdup (strsignal (signal_expected));
481   if (alarm_received) {
482     snprintf (msg, MSG_LEN, "Test timeout expired, expected signal %d (%s)",
483         signal_expected, sig_e_str);
484   } else {
485     snprintf (msg, MSG_LEN, "Received signal %d (%s), expected %d (%s)",
486         signal_received, sig_r_str, signal_expected, sig_e_str);
487   }
488   free (sig_r_str);
489   free (sig_e_str);
490   return msg;
491 }
492
493 static char *
494 exit_msg (int exitval)
495 {
496   char *msg = emalloc (MSG_LEN);        /* free'd by caller */
497   snprintf (msg, MSG_LEN, "Early exit with return value %d", exitval);
498   return msg;
499 }
500
501 static int
502 waserror (int status, int signal_expected)
503 {
504   int was_sig = WIFSIGNALED (status);
505   int was_exit = WIFEXITED (status);
506   int exit_status = WEXITSTATUS (status);
507   int signal_received = WTERMSIG (status);
508
509   return ((was_sig && (signal_received != signal_expected)) ||
510       (was_exit && exit_status != 0));
511 }
512 #endif /* _POSIX_VERSION */
513
514 enum fork_status
515 srunner_fork_status (SRunner * sr)
516 {
517   if (sr->fstat == CK_FORK_GETENV) {
518     char *env = getenv ("CK_FORK");
519     if (env == NULL)
520       return CK_FORK;
521     if (strcmp (env, "no") == 0)
522       return CK_NOFORK;
523     else {
524 #ifdef _POSIX_VERSION
525       return CK_FORK;
526 #else /* _POSIX_VERSION */
527       eprintf ("This version does not support fork", __FILE__, __LINE__);
528       return CK_NOFORK;
529 #endif /* _POSIX_VERSION */
530     }
531   } else
532     return sr->fstat;
533 }
534
535 void
536 srunner_set_fork_status (SRunner * sr, enum fork_status fstat)
537 {
538   sr->fstat = fstat;
539 }
540
541 void
542 srunner_run_all (SRunner * sr, enum print_output print_mode)
543 {
544 #ifdef _POSIX_VERSION
545   struct sigaction old_action;
546   struct sigaction new_action;
547 #endif /* _POSIX_VERSION */
548
549   if (sr == NULL)
550     return;
551   if (print_mode >= CK_LAST) {
552     eprintf ("Bad print_mode argument to srunner_run_all: %d",
553         __FILE__, __LINE__, print_mode);
554   }
555 #ifdef _POSIX_VERSION
556   memset (&new_action, 0, sizeof new_action);
557   new_action.sa_handler = sig_handler;
558   sigaction (SIGALRM, &new_action, &old_action);
559 #endif /* _POSIX_VERSION */
560   srunner_run_init (sr, print_mode);
561   srunner_iterate_suites (sr, print_mode);
562   srunner_run_end (sr, print_mode);
563 #ifdef _POSIX_VERSION
564   sigaction (SIGALRM, &old_action, NULL);
565 #endif /* _POSIX_VERSION */
566 }
567
568 pid_t
569 check_fork (void)
570 {
571 #ifdef _POSIX_VERSION
572   pid_t pid = fork ();
573   /* Set the process to a process group to be able to kill it easily. */
574   setpgid (pid, group_pid);
575   return pid;
576 #else /* _POSIX_VERSION */
577   eprintf ("This version does not support fork", __FILE__, __LINE__);
578   return 0;
579 #endif /* _POSIX_VERSION */
580 }
581
582 void
583 check_waitpid_and_exit (pid_t pid CK_ATTRIBUTE_UNUSED)
584 {
585 #ifdef _POSIX_VERSION
586   pid_t pid_w;
587   int status;
588
589   if (pid > 0) {
590     do {
591       pid_w = waitpid (pid, &status, 0);
592     } while (pid_w == -1);
593     if (waserror (status, 0)) {
594       exit (EXIT_FAILURE);
595     }
596   }
597   exit (EXIT_SUCCESS);
598 #else /* _POSIX_VERSION */
599   eprintf ("This version does not support fork", __FILE__, __LINE__);
600 #endif /* _POSIX_VERSION */
601 }