2 * Check: a unit test framework for C
3 * Copyright (C) 2001, 2002 Arien Malec
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.
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.
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.
21 #include "../lib/libcompat.h"
23 #include <sys/types.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"
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,
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);
81 #if defined(HAVE_FORK) && HAVE_FORK==1
82 static TestResult *tcase_run_tfun_fork (SRunner * sr, TCase * tc, TF * tf,
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);
94 static int alarm_received;
95 static pid_t group_pid;
97 static void CK_ATTRIBUTE_UNUSED
98 sig_handler (int sig_nr)
103 killpg (group_pid, SIGKILL);
106 eprintf ("Unhandled signal: %d", __FILE__, __LINE__, sig_nr);
110 #endif /* HAVE_FORK */
115 srunner_run_init (SRunner * sr, enum print_output print_mode)
117 set_fork_status (srunner_fork_status (sr));
119 srunner_init_logging (sr, print_mode);
120 log_srunner_start (sr);
124 srunner_run_end (SRunner * sr, enum print_output CK_ATTRIBUTE_UNUSED print_mode)
126 log_srunner_end (sr);
127 srunner_end_logging (sr);
128 teardown_messaging ();
129 set_fork_status (CK_FORK);
133 srunner_iterate_suites (SRunner * sr,
134 const char *sname, const char *tcname,
135 enum print_output CK_ATTRIBUTE_UNUSED print_mode)
143 for (check_list_front (slst); !check_list_at_end (slst);
144 check_list_advance (slst)) {
145 Suite *s = (Suite *) check_list_val (slst);
147 if (((sname != NULL) && (strcmp (sname, s->name) != 0))
148 || ((tcname != NULL) && (!suite_tcase (s, tcname))))
151 log_suite_start (sr, s);
155 for (check_list_front (tcl); !check_list_at_end (tcl);
156 check_list_advance (tcl)) {
157 tc = (TCase *) check_list_val (tcl);
159 if ((tcname != NULL) && (strcmp (tcname, tc->name) != 0)) {
163 srunner_run_tcase (sr, tc);
166 log_suite_end (sr, s);
171 srunner_iterate_tcase_tfuns (SRunner * sr, TCase * tc)
175 TestResult *tr = NULL;
179 for (check_list_front (tfl); !check_list_at_end (tfl);
180 check_list_advance (tfl)) {
183 tfun = (TF *) check_list_val (tfl);
185 for (i = tfun->loop_start; i < tfun->loop_end; i++) {
186 log_test_start (sr, tc, tfun);
187 switch (srunner_fork_status (sr)) {
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 */
196 tr = tcase_run_tfun_nofork (sr, tc, tfun, i);
200 eprintf ("Bad fork status in SRunner", __FILE__, __LINE__);
204 srunner_add_failure (sr, tr);
205 log_test_end (sr, tr);
212 srunner_add_failure (SRunner * sr, TestResult * tr)
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++;
224 srunner_run_setup (List * fixture_list, enum fork_status fork_usage,
225 const char *test_name, const char *setup_name)
227 TestResult *tr = NULL;
228 Fixture *setup_fixture;
230 if (fork_usage == CK_FORK) {
231 send_ctx_info (CK_CTX_SETUP);
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);
238 if (fork_usage == CK_NOFORK) {
239 send_ctx_info (CK_CTX_SETUP);
241 if (0 == setjmp (error_jmp_buffer)) {
242 setup_fixture->fun ();
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) {
256 setup_fixture->fun ();
264 srunner_run_unchecked_setup (SRunner * sr, TCase * tc)
266 TestResult *tr = NULL;
269 set_fork_status (CK_NOFORK);
270 tr = srunner_run_setup (tc->unch_sflst, CK_NOFORK, tc->name,
272 set_fork_status (srunner_fork_status (sr));
274 if (tr != NULL && tr->rtype != CK_PASS) {
275 srunner_add_failure (sr, tr);
283 tcase_run_checked_setup (SRunner * sr, TCase * tc)
285 TestResult *tr = srunner_run_setup (tc->ch_sflst, srunner_fork_status (sr),
286 tc->name, "checked_setup");
292 srunner_run_teardown (List * fixture_list, enum fork_status fork_usage)
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);
301 if (fork_usage == CK_NOFORK) {
302 if (0 == setjmp (error_jmp_buffer)) {
305 /* Abort the remaining teardowns */
315 srunner_run_unchecked_teardown (SRunner * sr, TCase * tc)
317 srunner_run_teardown (tc->unch_tflst, srunner_fork_status (sr));
321 tcase_run_checked_teardown (TCase * tc)
323 srunner_run_teardown (tc->ch_tflst, CK_NOFORK);
327 srunner_run_tcase (SRunner * sr, TCase * tc)
329 if (srunner_run_unchecked_setup (sr, tc)) {
330 srunner_iterate_tcase_tfuns (sr, tc);
331 srunner_run_unchecked_teardown (sr, tc);
336 tcase_run_tfun_nofork (SRunner * sr, TCase * tc, TF * tfun, int i)
339 struct timespec ts_start = { 0, 0 }, ts_end = {
342 tr = tcase_run_checked_setup (sr, tc);
344 clock_gettime (check_get_clockid (), &ts_start);
345 if (0 == setjmp (error_jmp_buffer)) {
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));
358 receive_result_info_nofork (const char *tcname,
359 const char *tname, int iter, int duration)
363 tr = receive_test_result (0);
365 eprintf ("Failed to receive test result", __FILE__, __LINE__);
370 tr->duration = duration;
371 set_nofork_info (tr);
378 set_nofork_info (TestResult * tr)
380 if (tr->msg == NULL) {
382 tr->msg = pass_msg ();
384 tr->rtype = CK_FAILURE;
391 return strdup ("Passed");
394 #if defined(HAVE_FORK) && HAVE_FORK==1
396 tcase_run_tfun_fork (SRunner * sr, TCase * tc, TF * tfun, int i)
401 struct timespec ts_start = { 0, 0 }, ts_end = {
405 struct itimerspec timer_spec;
411 eprintf ("Error in call to fork:", __FILE__, __LINE__ - 2);
414 group_pid = getpgrp ();
415 tr = tcase_run_checked_setup (sr, tc);
417 clock_gettime (check_get_clockid (), &ts_start);
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));
429 if (timer_create (check_get_clockid (),
430 NULL /* fire SIGALRM if timer expires */ ,
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) {
438 pid_w = waitpid (pid, &status, 0);
442 eprintf ("Error in call to timer_settime:", __FILE__, __LINE__);
445 /* If the timer has not fired, disable it */
446 timer_delete (timerid);
448 eprintf ("Error in call to timer_create:", __FILE__, __LINE__);
451 killpg (pid, SIGKILL); /* Kill remaining processes. */
453 return receive_result_info_fork (tc->name, tfun->name, i, status,
454 tfun->signal, tfun->allowed_exit_value);
458 receive_result_info_fork (const char *tcname,
460 int iter, int status, int expected_signal, signed char allowed_exit_value)
464 tr = receive_test_result (waserror (status, expected_signal));
466 eprintf ("Failed to receive test result", __FILE__, __LINE__);
471 set_fork_info (tr, status, expected_signal, allowed_exit_value);
478 set_fork_info (TestResult * tr, int status, int signal_expected,
479 signed char allowed_exit_value)
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);
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) {
494 tr->msg = signal_error_msg (signal_received, signal_expected);
497 if (tr->msg != NULL) {
500 tr->msg = pass_msg ();
502 } else if (signal_expected != 0) {
503 /* signal received, but not the expected one */
504 tr->rtype = CK_ERROR;
505 if (tr->msg != NULL) {
508 tr->msg = signal_error_msg (signal_received, signal_expected);
510 /* signal received and none expected */
511 tr->rtype = CK_ERROR;
512 if (tr->msg != NULL) {
515 tr->msg = signal_msg (signal_received);
517 } else if (signal_expected == 0) {
518 if (was_exit && exit_status == allowed_exit_value) {
520 if (tr->msg != NULL) {
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);
529 tr->rtype = CK_FAILURE;
532 } else { /* a signal was expected and none raised */
534 if (tr->msg != NULL) {
537 tr->msg = exit_msg (exit_status);
538 if (exit_status == allowed_exit_value) {
539 tr->rtype = CK_FAILURE; /* normal exit status */
541 tr->rtype = CK_FAILURE; /* early exit */
548 signal_msg (int signal)
550 char *msg = (char *) emalloc (MSG_LEN); /* free'd by caller */
552 if (alarm_received) {
553 snprintf (msg, MSG_LEN, "Test timeout expired");
555 snprintf (msg, MSG_LEN, "Received signal %d (%s)",
556 signal, strsignal (signal));
562 signal_error_msg (int signal_received, int signal_expected)
566 char *msg = (char *) emalloc (MSG_LEN); /* free'd by caller */
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);
575 snprintf (msg, MSG_LEN, "Received signal %d (%s), expected %d (%s)",
576 signal_received, sig_r_str, signal_expected, sig_e_str);
584 exit_msg (int exitval)
586 char *msg = (char *) emalloc (MSG_LEN); /* free'd by caller */
588 snprintf (msg, MSG_LEN, "Early exit with return value %d", exitval);
593 waserror (int status, int signal_expected)
595 int was_sig = WIFSIGNALED (status);
596 int was_exit = WIFEXITED (status);
597 int exit_status = WEXITSTATUS (status);
598 int signal_received = WTERMSIG (status);
600 return ((was_sig && (signal_received != signal_expected)) ||
601 (was_exit && exit_status != 0));
603 #endif /* HAVE_FORK */
606 srunner_fork_status (SRunner * sr)
608 if (sr->fstat == CK_FORK_GETENV) {
609 char *env = getenv ("CK_FORK");
612 #if defined(HAVE_FORK) && HAVE_FORK==1
617 if (strcmp (env, "no") == 0)
620 #if defined(HAVE_FORK) && HAVE_FORK==1
622 #else /* HAVE_FORK */
623 eprintf ("This version does not support fork", __FILE__, __LINE__);
625 #endif /* HAVE_FORK */
632 srunner_set_fork_status (SRunner * sr, enum fork_status fstat)
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__);
639 #endif /* ! HAVE_FORK */
644 srunner_run_all (SRunner * sr, enum print_output print_mode)
646 srunner_run (sr, NULL, /* All test suites. */
647 NULL, /* All test cases. */
652 srunner_run (SRunner * sr, const char *sname, const char *tcname,
653 enum print_output print_mode)
655 #if defined(HAVE_SIGACTION) && defined(HAVE_FORK)
656 struct sigaction old_action;
657 struct sigaction new_action;
658 #endif /* HAVE_SIGACTION && HAVE_FORK */
660 /* Get the selected test suite and test case from the
663 tcname = getenv ("CK_RUN_CASE");
665 sname = getenv ("CK_RUN_SUITE");
669 if (print_mode >= CK_LAST) {
670 eprintf ("Bad print_mode argument to srunner_run_all: %d",
671 __FILE__, __LINE__, print_mode);
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 */
689 #if defined(HAVE_FORK) && HAVE_FORK==1
692 /* Set the process to a process group to be able to kill it easily. */
694 setpgid (pid, group_pid);
697 #else /* HAVE_FORK */
698 eprintf ("This version does not support fork", __FILE__, __LINE__);
700 #endif /* HAVE_FORK */
704 check_waitpid_and_exit (pid_t pid CK_ATTRIBUTE_UNUSED)
706 #if defined(HAVE_FORK) && HAVE_FORK==1
712 pid_w = waitpid (pid, &status, 0);
715 if (waserror (status, 0)) {
720 #else /* HAVE_FORK */
721 eprintf ("This version does not support fork", __FILE__, __LINE__);
722 #endif /* HAVE_FORK */