Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add signal and exit code support #9

Merged
merged 1 commit into from
Feb 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions src/assertions.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include "config.h"
#include "evaluators.h"
#include "formatters.h"
#include "fork.h"

#ifndef CAUGHT_ASSERTIONS
#define CAUGHT_ASSERTIONS
Expand Down Expand Up @@ -72,4 +73,18 @@ bool caught_internal_handle_assertion_result(caught_internal_assertion_result as
#define EXPECT_STR_PTR(lhs, op, rhs) \
CAUGHT_INTERNAL_EXPECT_HANDLE(STR_PTR, char **, lhs, op, rhs, caught_internal_evaluator_str_ptr, caught_internal_formatter_str_ptr)

#define CAUGHT_INTERNAL_EXPECT_TERMINATE_HANDLE(func_name, expected_status, execute_block) \
do \
{ \
CAUGHT_INTERNAL_FORK(execute_block) \
CAUGHT_INTERNAL_EXPECT_HANDLE(func_name, caught_internal_process_status, caught_internal_fork_child_status, ==, expected_status, \
caught_internal_evaluator_exit_status, caught_internal_formatter_exit_status); \
} while (0)

#define EXPECT_EXIT(expected_status, execute_block) \
CAUGHT_INTERNAL_EXPECT_TERMINATE_HANDLE(EXIT, create_caught_internal_process_status(0, expected_status), execute_block)

#define EXPECT_SIGNAL(expected_status, execute_block) \
CAUGHT_INTERNAL_EXPECT_TERMINATE_HANDLE(EXIT, create_caught_internal_process_status(1, expected_status), execute_block)

#endif
11 changes: 11 additions & 0 deletions src/evaluators.c
Original file line number Diff line number Diff line change
Expand Up @@ -94,3 +94,14 @@ bool caught_internal_evaluator_str_ptr(char **lhs, enum caught_operator operator
CAUGHT_GENERATE_GENERIC_EVALUATOR_NULL_GUARD(lhs, operator, rhs);
return caught_internal_evaluator_str(*lhs, operator, * rhs);
}

bool caught_internal_evaluator_exit_status(caught_internal_process_status lhs, enum caught_operator operator, caught_internal_process_status rhs)
{
if (operator!= CAUGHT_OP_EQUAL)
{
fprintf(stderr, "Cannot compare exit statuses with %s, only == is supported!", caught_operator_to_str(operator));
exit(1);
}

return lhs.type == rhs.type && lhs.status == rhs.status;
}
3 changes: 3 additions & 0 deletions src/evaluators.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#include <stdbool.h>
#include <string.h>
#include "fork.h"

#ifndef CAUGHT_EVALUATORS
#define CAUGHT_EVALUATORS
Expand Down Expand Up @@ -52,6 +53,8 @@ bool caught_internal_evaluator_char_ptr(char *lhs, enum caught_operator operator
bool caught_internal_evaluator_str(char *lhs, enum caught_operator operator, char * rhs);
bool caught_internal_evaluator_str_ptr(char **lhs, enum caught_operator operator, char ** rhs);

bool caught_internal_evaluator_exit_status(caught_internal_process_status lhs, enum caught_operator operator, caught_internal_process_status rhs);

// Uses default operators (==, <=, >=, ...) to compare lhs to rhs
#define CAUGHT_GENERATE_GENERIC_EVALUATOR(lhs, operator, rhs) \
switch (operator) \
Expand Down
19 changes: 19 additions & 0 deletions src/fork.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
#include "fork.h"

caught_internal_process_status create_caught_internal_process_status(int type, int status)
{
caught_internal_process_status new = {
.type = type,
.status = status,
.status_str = NULL,
};
if (type == 1 && status >= 1 && status <= 31)
{
new.status_str = signal_names[status - 1];
}
else if (type == 0 && status >= 0 && status <= 1)
{
new.status_str = exit_status_names[status];
}
return new;
}
59 changes: 59 additions & 0 deletions src/fork.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
#ifndef CAUGHT_FORK
#define CAUGHT_FORK

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>

typedef struct caught_internal_process_status
{
int type; // 0 for exit status, 1 for signal status
int status; // The exit status or signal, depending on above
const char *status_str; // The string signal, if there is one
} caught_internal_process_status;

static const char *exit_status_names[] = {"EXIT_SUCCESS", "EXIT_FAILURE"};

static const char *signal_names[] = {
"SIGHUP", "SIGINT", "SIGQUIT", "SIGILL", "SIGTRAP", "SIGABRT", "SIGBUS",
"SIGFPE", "SIGKILL", "SIGUSR1", "SIGSEGV", "SIGUSR2", "SIGPIPE", "SIGALRM",
"SIGTERM", "SIGSTKFLT", "SIGCHLD", "SIGCONT", "SIGSTOP", "SIGTSTP", "SIGTTIN",
"SIGTTOU", "SIGURG", "SIGXCPU", "SIGXFSZ", "SIGVTALRM", "SIGPROF", "SIGWINCH",
"SIGIO", "SIGPWR", "SIGSYS"};

caught_internal_process_status create_caught_internal_process_status(int type, int status);

#define CAUGHT_INTERNAL_FORK(child_execute_block) \
caught_internal_process_status caught_internal_fork_child_status = {}; \
pid_t caught_internal_pid = fork(); \
if (caught_internal_pid == -1) \
{ \
perror("Caught: failed to fork\n"); \
exit(EXIT_FAILURE); \
} \
if (caught_internal_pid == 0) \
{ \
child_execute_block \
\
perror("Caught: fork segment must call exit to prevent fork bombs\n"); \
exit(EXIT_FAILURE); \
} \
else \
{ \
int caught_internal_status = 0; \
waitpid(caught_internal_pid, &caught_internal_status, 0); \
if (WIFEXITED(caught_internal_status)) \
{ \
caught_internal_fork_child_status = \
create_caught_internal_process_status(0, WEXITSTATUS(caught_internal_status)); \
} \
else if (WIFSIGNALED(caught_internal_status)) \
{ \
caught_internal_fork_child_status = \
create_caught_internal_process_status(1, WTERMSIG(caught_internal_status)); \
} \
}

#endif
10 changes: 10 additions & 0 deletions src/formatters.c
Original file line number Diff line number Diff line change
Expand Up @@ -53,3 +53,13 @@ char *caught_internal_formatter_str_ptr(char **value)
CAUGHT_INTERNAL_FORMATTER_NULL_GUARD(value)
return caught_internal_formatter_str(*value);
}

char *caught_internal_formatter_exit_status(caught_internal_process_status value)
{
const char *type = value.type ? "Signal" : "Exit code";
if (value.status_str)
{
CAUGHT_INTERNAL_FORMATTER_FORMAT("%s (%i)", value.status_str, value.status)
}
CAUGHT_INTERNAL_FORMATTER_FORMAT("%s %i", type, value.status)
}
9 changes: 6 additions & 3 deletions src/formatters.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#define _GNU_SOURCE
#include <string.h>
#include <stdbool.h>
#include "fork.h"

#ifndef CAUGHT_FORMATTERS
#define CAUGHT_FORMATTERS
Expand All @@ -23,9 +24,11 @@ char *caught_internal_formatter_char_ptr(char *value);
char *caught_internal_formatter_str(char *value);
char *caught_internal_formatter_str_ptr(char **value);

#define CAUGHT_INTERNAL_FORMATTER_FORMAT(fstr, value) \
char *result; \
asprintf(&result, fstr, value); \
char *caught_internal_formatter_exit_status(caught_internal_process_status value);

#define CAUGHT_INTERNAL_FORMATTER_FORMAT(fstr, ...) \
char *result; \
asprintf(&result, fstr, __VA_ARGS__); \
return result;
#define CAUGHT_INTERNAL_FORMATTER_NULL_GUARD(value) \
if (value == NULL) \
Expand Down
21 changes: 21 additions & 0 deletions tests/exit.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// NOTE: The location of this include might differ in your code depending on location
// For example, it could be: #include "caught.h"
#include "../src/caught.h"

TEST("exit - success")
{
EXPECT_EXIT(EXIT_SUCCESS, {
exit(EXIT_SUCCESS);
});

EXPECT_INT(1 + 1, ==, 2); // This still runs
}

TEST("exit - failure")
{
EXPECT_EXIT(EXIT_FAILURE, {
exit(EXIT_FAILURE);
});

EXPECT_INT(1 + 1, ==, 2); // This still runs
}
22 changes: 22 additions & 0 deletions tests/signal.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// NOTE: The location of this include might differ in your code depending on location
// For example, it could be: #include "caught.h"
#include "../src/caught.h"

TEST("signal - SIGABRT")
{
EXPECT_SIGNAL(SIGABRT, {
raise(SIGABRT);
});

EXPECT_INT(1 + 1, ==, 2); // This still runs
}

TEST("signal - SIGSEGV")
{
EXPECT_SIGNAL(SIGSEGV, {
int *ptr = NULL;
ptr[1] = 123; // BAD!
});

EXPECT_INT(1 + 1, ==, 2); // This still runs
}