#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; }