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., 59 Temple Place - Suite 330,
18 * Boston, MA 02111-1307, USA.
23 #include <sys/types.h>
24 #ifdef HAVE_SYS_WAIT_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"
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,
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);
81 static TestResult *tcase_run_tfun_fork (SRunner * sr, TCase * tc, TF * tf,
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);
93 static int alarm_received;
94 static pid_t group_pid;
96 static void CK_ATTRIBUTE_UNUSED
97 sig_handler (int sig_nr)
102 killpg (group_pid, SIGKILL);
105 eprintf ("Unhandled signal: %d", __FILE__, __LINE__, sig_nr);
109 #endif /* _POSIX_VERSION */
114 srunner_run_init (SRunner * sr, enum print_output print_mode)
116 set_fork_status (srunner_fork_status (sr));
118 srunner_init_logging (sr, print_mode);
119 log_srunner_start (sr);
123 srunner_run_end (SRunner * sr, enum print_output CK_ATTRIBUTE_UNUSED print_mode)
125 log_srunner_end (sr);
126 srunner_end_logging (sr);
127 teardown_messaging ();
128 set_fork_status (CK_FORK);
132 srunner_iterate_suites (SRunner * sr,
133 enum print_output CK_ATTRIBUTE_UNUSED print_mode)
141 for (list_front (slst); !list_at_end (slst); list_advance (slst)) {
142 Suite *s = list_val (slst);
144 log_suite_start (sr, s);
148 for (list_front (tcl); !list_at_end (tcl); list_advance (tcl)) {
150 srunner_run_tcase (sr, tc);
153 log_suite_end (sr, s);
158 srunner_iterate_tcase_tfuns (SRunner * sr, TCase * tc)
162 TestResult *tr = NULL;
166 for (list_front (tfl); !list_at_end (tfl); list_advance (tfl)) {
168 tfun = list_val (tfl);
170 for (i = tfun->loop_start; i < tfun->loop_end; i++) {
171 log_test_start (sr, tc, tfun);
172 switch (srunner_fork_status (sr)) {
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 */
181 tr = tcase_run_tfun_nofork (sr, tc, tfun, i);
184 eprintf ("Bad fork status in SRunner", __FILE__, __LINE__);
186 srunner_add_failure (sr, tr);
187 log_test_end (sr, tr);
193 srunner_add_failure (SRunner * sr, TestResult * tr)
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++;
205 srunner_run_unchecked_setup (SRunner * sr, TCase * tc)
212 set_fork_status (CK_NOFORK);
216 for (list_front (l); !list_at_end (l); list_advance (l)) {
217 send_ctx_info (CK_CTX_SETUP);
221 tr = receive_result_info_nofork (tc->name, "unchecked_setup", 0);
223 if (tr->rtype != CK_PASS) {
224 srunner_add_failure (sr, tr);
233 set_fork_status (srunner_fork_status (sr));
238 tcase_run_checked_setup (SRunner * sr, TCase * tc)
240 TestResult *tr = NULL;
243 enum fork_status fstat = srunner_fork_status (sr);
246 if (fstat == CK_FORK) {
247 send_ctx_info (CK_CTX_SETUP);
250 for (list_front (l); !list_at_end (l); list_advance (l)) {
251 if (fstat == CK_NOFORK) {
252 send_ctx_info (CK_CTX_SETUP);
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) {
275 srunner_run_teardown (List * l)
279 for (list_front (l); !list_at_end (l); list_advance (l)) {
281 send_ctx_info (CK_CTX_TEARDOWN);
287 srunner_run_unchecked_teardown (TCase * tc)
289 srunner_run_teardown (tc->unch_tflst);
293 tcase_run_checked_teardown (TCase * tc)
295 srunner_run_teardown (tc->ch_tflst);
299 srunner_run_tcase (SRunner * sr, TCase * tc)
301 if (srunner_run_unchecked_setup (sr, tc)) {
302 srunner_iterate_tcase_tfuns (sr, tc);
303 srunner_run_unchecked_teardown (tc);
308 tcase_run_tfun_nofork (SRunner * sr, TCase * tc, TF * tfun, int i)
312 tr = tcase_run_checked_setup (sr, tc);
315 tcase_run_checked_teardown (tc);
316 return receive_result_info_nofork (tc->name, tfun->name, i);
323 receive_result_info_nofork (const char *tcname, const char *tname, int iter)
327 tr = receive_test_result (0);
329 eprintf ("Failed to receive test result", __FILE__, __LINE__);
333 set_nofork_info (tr);
339 set_nofork_info (TestResult * tr)
341 if (tr->msg == NULL) {
343 tr->msg = pass_msg ();
345 tr->rtype = CK_FAILURE;
352 char *msg = emalloc (sizeof ("Passed"));
353 strcpy (msg, "Passed");
357 #ifdef _POSIX_VERSION
359 tcase_run_tfun_fork (SRunner * sr, TCase * tc, TF * tfun, int i)
367 eprintf ("Error in call to fork:", __FILE__, __LINE__ - 2);
370 group_pid = getpgrp ();
371 tcase_run_checked_setup (sr, tc);
373 tcase_run_checked_teardown (tc);
382 pid_w = waitpid (pid, &status, 0);
383 } while (pid_w == -1);
385 killpg (pid, SIGKILL); /* Kill remaining processes. */
387 return receive_result_info_fork (tc->name, tfun->name, i, status,
388 tfun->signal, tfun->allowed_exit_value);
392 receive_result_info_fork (const char *tcname,
394 int iter, int status, int expected_signal, unsigned char allowed_exit_value)
398 tr = receive_test_result (waserror (status, expected_signal));
400 eprintf ("Failed to receive test result", __FILE__, __LINE__);
404 set_fork_info (tr, status, expected_signal, allowed_exit_value);
410 set_fork_info (TestResult * tr, int status, int signal_expected,
411 unsigned char allowed_exit_value)
413 int was_sig = WIFSIGNALED (status);
414 int was_exit = WIFEXITED (status);
415 int exit_status = WEXITSTATUS (status);
416 int signal_received = WTERMSIG (status);
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);
426 tr->msg = pass_msg ();
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);
433 /* signal received and none expected */
434 tr->rtype = CK_ERROR;
435 tr->msg = signal_msg (signal_received);
437 } else if (signal_expected == 0) {
438 if (was_exit && exit_status == allowed_exit_value) {
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);
446 tr->rtype = CK_FAILURE;
449 } else { /* a signal was expected and none raised */
451 tr->msg = exit_msg (exit_status);
452 if (exit_status == allowed_exit_value)
453 tr->rtype = CK_FAILURE; /* normal exit status */
455 tr->rtype = CK_FAILURE; /* early exit */
461 signal_msg (int signal)
463 char *msg = emalloc (MSG_LEN); /* free'd by caller */
464 if (alarm_received) {
465 snprintf (msg, MSG_LEN, "Test timeout expired");
467 snprintf (msg, MSG_LEN, "Received signal %d (%s)",
468 signal, strsignal (signal));
474 signal_error_msg (int signal_received, int signal_expected)
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);
485 snprintf (msg, MSG_LEN, "Received signal %d (%s), expected %d (%s)",
486 signal_received, sig_r_str, signal_expected, sig_e_str);
494 exit_msg (int exitval)
496 char *msg = emalloc (MSG_LEN); /* free'd by caller */
497 snprintf (msg, MSG_LEN, "Early exit with return value %d", exitval);
502 waserror (int status, int signal_expected)
504 int was_sig = WIFSIGNALED (status);
505 int was_exit = WIFEXITED (status);
506 int exit_status = WEXITSTATUS (status);
507 int signal_received = WTERMSIG (status);
509 return ((was_sig && (signal_received != signal_expected)) ||
510 (was_exit && exit_status != 0));
512 #endif /* _POSIX_VERSION */
515 srunner_fork_status (SRunner * sr)
517 if (sr->fstat == CK_FORK_GETENV) {
518 char *env = getenv ("CK_FORK");
521 if (strcmp (env, "no") == 0)
524 #ifdef _POSIX_VERSION
526 #else /* _POSIX_VERSION */
527 eprintf ("This version does not support fork", __FILE__, __LINE__);
529 #endif /* _POSIX_VERSION */
536 srunner_set_fork_status (SRunner * sr, enum fork_status fstat)
542 srunner_run_all (SRunner * sr, enum print_output print_mode)
544 #ifdef _POSIX_VERSION
545 struct sigaction old_action;
546 struct sigaction new_action;
547 #endif /* _POSIX_VERSION */
551 if (print_mode >= CK_LAST) {
552 eprintf ("Bad print_mode argument to srunner_run_all: %d",
553 __FILE__, __LINE__, print_mode);
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 */
571 #ifdef _POSIX_VERSION
573 /* Set the process to a process group to be able to kill it easily. */
574 setpgid (pid, group_pid);
576 #else /* _POSIX_VERSION */
577 eprintf ("This version does not support fork", __FILE__, __LINE__);
579 #endif /* _POSIX_VERSION */
583 check_waitpid_and_exit (pid_t pid CK_ATTRIBUTE_UNUSED)
585 #ifdef _POSIX_VERSION
591 pid_w = waitpid (pid, &status, 0);
592 } while (pid_w == -1);
593 if (waserror (status, 0)) {
598 #else /* _POSIX_VERSION */
599 eprintf ("This version does not support fork", __FILE__, __LINE__);
600 #endif /* _POSIX_VERSION */