From 8d45dc827a898e8319b63ed97d77dbff2697e95c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thorben=20H=C3=B6hne?= Date: Tue, 24 Jun 2025 20:10:25 +0200 Subject: [PATCH] feat: All tests run in a child process now. --- cpp_test.cpp | 8 ++ set.c | 232 +++++++++++++++++++++++++++++++------------------- set.h | 44 +++++++--- set_asserts.h | 2 +- test | Bin 0 -> 25920 bytes testtest.c | 6 +- 6 files changed, 191 insertions(+), 101 deletions(-) create mode 100644 cpp_test.cpp create mode 100755 test diff --git a/cpp_test.cpp b/cpp_test.cpp new file mode 100644 index 0000000..a37207e --- /dev/null +++ b/cpp_test.cpp @@ -0,0 +1,8 @@ +#include "set.h" +#include "set_asserts.h" + +TEST(Basic) { ASSERT_EQ(2, 2); } + +SUIT(Basic) { ADD_TEST(Basic); } + +BUNDLE() { ADD_SUIT(Basic); } diff --git a/set.c b/set.c index 6464991..e6edef1 100644 --- a/set.c +++ b/set.c @@ -3,9 +3,17 @@ #include #include #include +#include +#include +#include +#include + +#include #include "set_asserts.h" +#ifdef COLORIZED + #define ANSI_COLOR_RED "\x1b[31m" #define ANSI_COLOR_GREEN "\x1b[32m" #define ANSI_COLOR_YELLOW "\x1b[33m" @@ -14,113 +22,165 @@ #define ANSI_COLOR_CYAN "\x1b[36m" #define ANSI_COLOR_RESET "\x1b[0m" +#else + +#define ANSI_COLOR_RED +#define ANSI_COLOR_GREEN +#define ANSI_COLOR_YELLOW +#define ANSI_COLOR_BLUE +#define ANSI_COLOR_MAGENTA +#define ANSI_COLOR_CYAN +#define ANSI_COLOR_RESET + +#endif + // clang-format off -#define BANNER \ -"" \ -" _____ _ _ _____ _ _____ _ \n"\ -" / ___| | | | | ___| | | |_ _| | | \n"\ -" \\ `--. _ __ ___ __ _| | | | |__ _ __ ___ _ _ __ _| |__ | | ___ ___| |_ ___ _ __ \n"\ -" `--. | '_ ` _ \\ / _` | | | | __| '_ \\ / _ \\| | | |/ _` | '_ \\ | |/ _ / __| __/ _ | '__|\n"\ -" /\\__/ | | | | | | (_| | | | | |__| | | | (_) | |_| | (_| | | | | | | __\\__ | || __| | \n"\ -" \\____/|_| |_| |_|\\__,_|_|_| \\____|_| |_|\\___/ \\__,_|\\__, |_| |_| \\_/\\___|___/\\__\\___|_| \n"\ -" __/ | \n"\ -" |___/ \n"\ -"" +#define BANNER \ + "" \ + " _____ _ _ _____ _ " \ + "_____ _ \n" \ + " / ___| | | | | ___| | | |_ " \ + "_| | | \n" \ + " \\ `--. _ __ ___ __ _| | | | |__ _ __ ___ _ _ __ _| |__ | " \ + "| ___ ___| |_ ___ _ __ \n" \ + " `--. | '_ ` _ \\ / _` | | | | __| '_ \\ / _ \\| | | |/ _` | '_ \\ " \ + " | |/ _ / __| __/ _ | '__|\n" \ + " /\\__/ | | | | | | (_| | | | | |__| | | | (_) | |_| | (_| | | | | | " \ + "| __\\__ | || __| | \n" \ + " \\____/|_| |_| |_|\\__,_|_|_| \\____|_| |_|\\___/ \\__,_|\\__, |_| " \ + "|_| \\_/\\___|___/\\__\\___|_| \n" \ + " __/ | " \ + " \n" \ + " |___/ " \ + " \n" \ + "" //clang-format on -char* format_string(const char* fmt, ...) +char *format_string(const char *fmt, ...) { - va_list args; - va_start(args, fmt); - size_t size = vsnprintf(NULL, 0, fmt, args); - char* out = (char*)malloc(size + 1); + va_list args; + va_start(args, fmt); + size_t size = vsnprintf(NULL, 0, fmt, args); + char *out = (char *)malloc(size + 1); - if (!out) { - fprintf(stderr, "%s", "Failed to allocate for format string.\n"); - } + if (!out) + { + fprintf(stderr, "%s", "Failed to allocate for format string.\n"); + } - va_end(args); + va_end(args); - va_start(args, fmt); - vsnprintf(out, size + 1, fmt, args); - va_end(args); + va_start(args, fmt); + vsnprintf(out, size + 1, fmt, args); + va_end(args); - return out; + return out; } -static void log_test_start(const char* name) { printf("Running test: %s", name); } - -static void log_test_summary(struct SETest* test) +int create_shared_suit_space(size_t size) { - if (test->passed) { -#ifdef COLORIZED - printf(ANSI_COLOR_GREEN " - passed.\n" ANSI_COLOR_RESET); -#else - printf(" - passed.\n"); -#endif - } else { -#ifdef COLORIZED - printf(ANSI_COLOR_RED " - failed.\n" ANSI_COLOR_RESET " Reason: \n %s\n\n", - test->error_msg); -#else - printf(" - failed.\n Reason: \n %s\n\n", test->error_msg); -#endif - } -} + int suit_space_id = shmget(IPC_PRIVATE, size, IPC_CREAT | 0600); -static void dispatch_tests(struct SETSuit* suit) -{ - printf("\n\n==== Running suit: %s ====\n\n", suit->name); - for (int i = 0; i < suit->len; i++) { - struct SETest* test = suit->tests[i]; - log_test_start(test->name); - test->function(test); - log_test_summary(test); - fflush(stdout); - } + if (suit_space_id == -1) + { + fprintf(stdout, "Couldn't create suite space of size: %lu\n", size); + perror("shmget"); + exit(1); + } + + return suit_space_id; } -static void free_suit(struct SETSuit* suit) +static void log_test_summary(struct SETest *test) { - for (int i = 0; i < suit->len; i++) { - struct SETest* test = suit->tests[i]; - free((void*)test->error_msg); - free((void*)test); - } - - free(suit->tests); - free(suit); + if (test->passed) + { + printf("Test: %s" ANSI_COLOR_GREEN " - passed." ANSI_COLOR_RESET"\n", + test->name); + } + else + { + printf("Test: %s" ANSI_COLOR_RED " - failed.\n" ANSI_COLOR_RESET + " Reason: \n %s\n\n", + test->name, test->error_msg); + } } - -static void dispatch_test_suits(struct SETSuit** suits, int counter) +static void log_abnormal_termination(int status) { - for (int i = 0; i < counter; i++) - { - dispatch_tests(suits[i]); - free_suit(suits[i]); - } + fprintf(stderr, + ANSI_COLOR_RED "A test terminated with signal: %d" ANSI_COLOR_RESET, + WTERMSIG(status)); } -int main(int argc, char** argv) +static void dispatch_single_test(struct SETest *test) { - #ifndef NO_BANNER - - printf("\n\n%s", BANNER); - #endif /* ifndef NO_BANNER */ - - int counter = 0; + pid_t testPID = fork(); - set_bundle_suits(NULL, &counter, true); - - struct SETSuit ** suits = (struct SETSuit**)malloc(counter * sizeof(struct SETSuit*)); - - counter = 0; - - set_bundle_suits(suits, &counter, false); - - dispatch_test_suits(suits, counter); - - free(suits); + if (testPID == 0) + { + test->function(test); + log_test_summary(test); + exit(0); + } +} + +static void dispatch_tests(struct SETSuit *suit) +{ + printf("\n\n==== Running suit: %s (%d) ====\n\n", suit->name, suit->len); + struct SETest *test = suit->tests; + for (int i = 0; i < suit->len; i++) + { + dispatch_single_test(&test[i]); + } + + int status = 0; + // Wait for all tests. + while (wait(&status) > 0) + { + if (WTERMSIG(status) != 0) + log_abnormal_termination(status); + }; + if (shmdt(suit->tests) < 0) + { + fprintf(stderr, "%s\n", "Couldn't detach suit space after dispatch."); + perror("shmat"); + exit(1); + } + if (shmctl(suit->shm_key, IPC_RMID, 0) == -1) + { + fprintf(stderr, "%s\n", "Couldn't remove suit space after dispatch."); + perror("shctl"); + exit(1); + } +} + +static void dispatch_test_suits(struct SETSuit **suits, int counter) +{ + for (int i = 0; i < counter; i++) + { + dispatch_tests(suits[i]); + munmap((void*)suits[i], sizeof(struct SETSuit)); + } +} + +int main(int argc, char **argv) +{ +#ifndef NO_BANNER + + printf("\n\n%s", BANNER); +#endif /* ifndef NO_BANNER */ + + int counter = 0; + + set_bundle_suits(NULL, &counter, true); + + struct SETSuit *suits[counter]; + + counter = 0; + + set_bundle_suits(suits, &counter, false); + + dispatch_test_suits(suits, counter); } diff --git a/set.h b/set.h index b72aa09..fc21800 100644 --- a/set.h +++ b/set.h @@ -1,24 +1,30 @@ #include #include #include +#include +#include #ifndef INCLUDE_SET_H #define INCLUDE_SET_H +#define SET_MAX_ERROR_MSG_SIZE 256 +#define SET_MAX_NAME_SIZE 64 + struct SETest { - char *name; void (*function)(struct SETest *test); + const char *error_msg; + const char *name; bool passed; - char *error_msg; }; struct SETSuit { - char *name; - struct SETest **tests; - bool passed; + const char *name; + struct SETest *tests; int len; + int shm_key; + bool passed; }; char *format_string(const char *fmt, ...); @@ -26,6 +32,8 @@ char *format_string(const char *fmt, ...); // To be implemented by user. void set_bundle_suits(struct SETSuit **suits, int *counter, bool count); +int create_shared_suit_space(size_t size); + #define BUNDLE() \ void set_bundle_suits(struct SETSuit **suits, int *counter, bool count) @@ -36,16 +44,28 @@ void set_bundle_suits(struct SETSuit **suits, int *counter, bool count); } \ (*counter)++; +// We manually allocate suits via mmap be able to mark them DONTFORK. +// Since we don't need the suits in a test fork. #define SUIT(suit_name) \ void suit_name##_suit(struct SETSuit *suit, bool count); \ struct SETSuit *suit_name##_suit_contructor() \ { \ struct SETSuit *suit = \ - (struct SETSuit *)malloc(sizeof(struct SETSuit)); \ - suit->name = #suit_name; \ + mmap(NULL, sizeof(struct SETSuit), PROT_READ | PROT_WRITE, \ + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); \ + madvise(suit, sizeof(struct SETSuit), MADV_DONTFORK); \ + suit->len = 0; \ suit_name##_suit(suit, true); \ - suit->tests = \ - (struct SETest **)malloc(suit->len * sizeof(struct SETest *)); \ + suit->shm_key = \ + create_shared_suit_space(suit->len * sizeof(struct SETest)); \ + suit->name = #suit_name; \ + suit->tests = shmat(suit->shm_key, 0, 0); \ + if (suit->tests == (struct SETest *)-1) \ + { \ + fprintf(stderr, "Couldn't attach suit space.\n"); \ + perror("shmat"); \ + exit(1); \ + } \ suit->len = 0; \ suit_name##_suit(suit, false); \ return suit; \ @@ -55,21 +75,19 @@ void set_bundle_suits(struct SETSuit **suits, int *counter, bool count); #define ADD_TEST(test_name) \ if (!count) \ { \ - suit->tests[suit->len] = test_name##_test_constructor(); \ + test_name##_test_constructor(&suit->tests[suit->len]); \ } \ suit->len++; // TEST MACRO #define TEST(test_name) \ void test_name##_test(struct SETest *test); \ - struct SETest *test_name##_test_constructor() \ + void test_name##_test_constructor(struct SETest *test) \ { \ - struct SETest *test = (struct SETest *)malloc(sizeof(struct SETest)); \ test->name = #test_name; \ test->function = &test_name##_test; \ test->passed = true; \ test->error_msg = NULL; \ - return test; \ } \ void test_name##_test(struct SETest *test) diff --git a/set_asserts.h b/set_asserts.h index 06cd0a3..32d9209 100644 --- a/set_asserts.h +++ b/set_asserts.h @@ -21,7 +21,7 @@ { \ test->passed = false; \ test->error_msg = \ - format_string("Expect %d to be %d\n", act, exp) return; \ + format_string("Expect %d to be %d.\n", act, exp) return; \ } #define ASSERT_EQ_MSG(exp, act, msg) \ diff --git a/test b/test new file mode 100755 index 0000000000000000000000000000000000000000..884353ff9f5e65f4c0a1c00f5b4268eb682e8356 GIT binary patch literal 25920 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 + #include "set_asserts.h" int fac(int n) { - if (n <= 1) + if (n == 1) return 1; return n * fac(n - 1); } +void heavy_load() { sleep(5); } + TEST(Faculty_Basic) { ASSERT_EQ(fac(5), 120);