From 5905cb67b06d27443344ddd752a23eaf38584cbf Mon Sep 17 00:00:00 2001 From: xavi Date: Tue, 23 Dec 2025 21:34:56 -0800 Subject: [PATCH] Added the test framework to the tests directory Separated the test framework into the header. Test definitions should be placed in the test.c. --- c_projects/x_tfw4c/tests/include/test.h | 162 ++++++++++++++++++++++++ c_projects/x_tfw4c/tests/test.c | 29 +++++ 2 files changed, 191 insertions(+) create mode 100644 c_projects/x_tfw4c/tests/include/test.h create mode 100644 c_projects/x_tfw4c/tests/test.c diff --git a/c_projects/x_tfw4c/tests/include/test.h b/c_projects/x_tfw4c/tests/include/test.h new file mode 100644 index 0000000..45e4fe5 --- /dev/null +++ b/c_projects/x_tfw4c/tests/include/test.h @@ -0,0 +1,162 @@ +#include +#include +#include +#include +#include + +// printf Formating +#define X_RED "\x1B[31m" +#define X_GREEN "\x1B[32m" +#define X_YELLOW "\x1B[33m" +#define X_RST "\x1B[0m" + + +// TEST FRAMEWORK STRUCT +typedef struct testnode{ + char* name; + int (*op)(void); + struct testnode* next; +}testnode; + +// LL nodes +static testnode* head = NULL; +static testnode* tail = NULL; +static testnode* ptr = NULL; + +// TEST FRAMEWORK MACRO +// create a new node and pass in the name of the test. Then make a new function +// that adds the test to the LL. __attribute__((constructor)) has the function +// run before main +#define TEST(UNIT)\ + static int UNIT(void);\ + static testnode UNIT##node = {#UNIT, UNIT, NULL};\ + __attribute__((constructor)) \ + static void add##UNIT(void){ \ + if (head == NULL){\ + head = &UNIT##node;\ + tail = head;\ + return; \ + }\ + ptr = tail;\ + tail = &UNIT##node;\ + ptr->next = tail;\ + }\ + static int UNIT(void) + +// TEST HELPER FUNCTIONS and STRUCTS +typedef enum {START, END} header_opt; +static void ptest_headers(header_opt option){ + switch (option){ + case START: + printf("\n-------------------\n"); + printf(" Starting Tests\n"); + printf("-------------------\n"); + break; + case END: + printf("-------------------\n"); + printf(" ENDING TESTS\n"); + printf("-------------------\n\n"); + break; + default: + printf("error: Wrong option in ptest_headers()\n"); + exit(-1); + } +} + +typedef enum {PASS, FAIL}rc_opt; +static void ppass_fail(rc_opt rc){ + switch (rc){ + case PASS: + printf("%s[PASS]%s ", X_GREEN, X_RST); + printf("%s", ptr->name); + break; + case FAIL: + printf("%s[FAIL]%s ", X_RED, X_RST); + printf("%s ", ptr->name); + break; + default: + printf("error: Unknown return code"); + exit(-1); + } + +} + +static int presult(int status){ + if (WIFEXITED(status)){ + int rc = WEXITSTATUS(status); + if (rc == 0) { + ppass_fail(PASS); + return 0; + } + else{ + ppass_fail(FAIL); + printf("- Exit Code %s(%d)%s", + X_YELLOW, rc, X_RST); + return 1; + } + } + else if (WIFSIGNALED(status)){ + ppass_fail(FAIL); + printf("- Termination Signal %s(%d)%s", + X_YELLOW, WTERMSIG(status), X_RST); + return 1; + } + else{ + printf("%s[FAIL]%s ", X_RED, X_RST); + printf("%s ", ptr->name); + printf("- Unknown Error "); + return 1; + } +} + +static int run_child(){ + int status; + pid_t cpid = fork(); + if (cpid < 0){ + perror("fork"); + exit(EXIT_FAILURE); + } + + if (cpid == 0){ + int rc = ptr->op(); + _exit(rc); + }else{ + if (waitpid(cpid, &status, 0) < 0){ + perror("waitpid"); + exit(EXIT_FAILURE); + } + } + + return status; +} + +static int run_tests(){ + int total_tests = 0; + int errors = 0; + + ptest_headers(START); + + ptr = head; + while (ptr != NULL){ + total_tests++; + + + if(presult(run_child())){ + errors++; + } + + printf("\n"); + ptr = ptr->next; + } + + + printf("\nTests completed with %s%d PASS%s", X_GREEN, total_tests - errors, X_RST); + printf(" and %s%d FAIL%s\n", X_RED, errors, X_RST); + + ptest_headers(END); + + if (errors > 0){ + return 1; + } + return 0; +} diff --git a/c_projects/x_tfw4c/tests/test.c b/c_projects/x_tfw4c/tests/test.c new file mode 100644 index 0000000..9ebbfc8 --- /dev/null +++ b/c_projects/x_tfw4c/tests/test.c @@ -0,0 +1,29 @@ +#include "test.h" + +// INCLUDE PROJECT HEADERS +#include "hello_world.h" + + +// DEFINE TESTS +TEST(success){ + return 0; +} + +TEST(fail){ + int i = 1; + assert(i == 0); + printf("after assert\n"); + return i; +} + +TEST(segfault){ + int* x = NULL; + int y = *x; + return y; +} + +// END OF TEST DEFINITIONS + +int main(void){ + return run_tests(); +}