bunkum

an old and silly c99 web server with some fun features
Log | Files | Refs | README

test.c (3644B)


      1 #include <stdio.h>
      2 #include <stddef.h>
      3 #include <dlfcn.h>
      4 #include <string.h>
      5 #include <stdlib.h>
      6 #include <sys/types.h>
      7 #include <unistd.h>
      8 #include <sys/wait.h>
      9 #include <elf.h>
     10 #include <stdbool.h>
     11 
     12 #define MAX_SYMBOL_LEN 32
     13 #define MAX_NUM_SYMBOLS 128
     14 char symbols[MAX_NUM_SYMBOLS*MAX_SYMBOL_LEN] = {0};
     15 char* symbols_off = (char*)&symbols;
     16 
     17 #define MAX_SYMTABS 16
     18 char symtabs[sizeof(Elf64_Shdr)*2*MAX_SYMTABS] = {0};
     19 char* symtabs_off = (char*)&symtabs;
     20 
     21 void get_symbols(char* path) {
     22     FILE* fptr = fopen(path, "r");
     23     Elf64_Ehdr header = {0};
     24     fread(&header, sizeof(Elf64_Ehdr), 1, fptr);
     25     if (strncmp((char*)&header, ELFMAG, 3) != 0) {
     26         printf("Attempted read of invalid ELF file.");
     27     }
     28     fseek(fptr, header.e_shoff, SEEK_SET);
     29     Elf64_Shdr syment[2] = {0};
     30     for (int i = 0; i < header.e_shnum-1; i++) {
     31         fread(&syment, sizeof(Elf64_Shdr), 2, fptr); // NOTE: questionable
     32         if (syment[0].sh_type == SHT_SYMTAB && syment[1].sh_type == SHT_STRTAB) {
     33             memcpy(symtabs_off, &syment[0], sizeof(Elf64_Shdr));
     34             memcpy(symtabs_off+sizeof(Elf64_Shdr), &syment[1], sizeof(Elf64_Shdr));
     35             symtabs_off = symtabs_off+(sizeof(Elf64_Shdr)*2);
     36         }
     37         fseek(fptr, -sizeof(Elf64_Shdr), SEEK_CUR); // HACK
     38     }
     39     for (int i = 0; i < (symtabs_off-symtabs)/(sizeof(Elf64_Shdr)*2); i++) {
     40         Elf64_Shdr symtab0 = ((Elf64_Shdr*)symtabs)[i*2];
     41         Elf64_Shdr symtab1 = ((Elf64_Shdr*)symtabs)[i*2+1];
     42 
     43         fseek(fptr, symtab1.sh_offset, SEEK_SET);
     44         char* strtbl = malloc(symtab1.sh_size);
     45         fread(strtbl, symtab1.sh_size, 1, fptr);
     46         fseek(fptr, symtab0.sh_offset, SEEK_SET);
     47         Elf64_Sym symbol = {0};
     48         for (size_t i = 0; i < symtab0.sh_size; i+=sizeof(Elf64_Sym)) {
     49             fread(&symbol, sizeof(Elf64_Sym), 1, fptr);
     50             if (symbol.st_name != 0) {
     51                 char* mangled = (char*)(&strtbl[symbol.st_name]);
     52                 if (strncmp(mangled, "test_", 5) == 0) {
     53                     strcpy(symbols_off, mangled);
     54                     symbols_off += MAX_SYMBOL_LEN;
     55                 }
     56             }
     57         }
     58     }
     59     fclose(fptr);
     60 }
     61 
     62 int run_test_safe(bool(*testf)(void)) {
     63     pid_t pid = fork();
     64     if (pid == 0) {
     65         testf();
     66         exit(0);
     67     } else {
     68         int status;
     69         waitpid(pid, &status, 0);
     70         return status;
     71     }
     72 }
     73 
     74 #define ANSI_RED "\x1b[31m"
     75 #define ANSI_GREEN "\x1b[32m"
     76 #define ANSI_BOLD "\x1b[1m"
     77 #define ANSI_RESET "\x1b[0m"
     78 
     79 int main(int argc, char** argv) {
     80     bool imode = false;
     81     if (argc > 2 && strcmp(argv[2], "-i") == 0) imode = true;
     82     get_symbols(argv[1]);
     83     char path[64] = {0};
     84     sprintf(path, "./%s", argv[1]);
     85     void* lib = dlopen(path, RTLD_LAZY);
     86     printf(ANSI_BOLD "Running tests...\n" ANSI_RESET);
     87     size_t passed = 0;
     88     size_t total = (symbols_off-symbols)/MAX_SYMBOL_LEN;
     89     for (char* sym = symbols; sym < symbols_off; sym+=MAX_SYMBOL_LEN) {
     90         printf("  %s ", sym+5);
     91         fflush(STDIN_FILENO);
     92         bool(*testf)(void) = dlsym(lib, sym);
     93         int status = run_test_safe(testf);
     94 
     95         if (status == 0) {
     96             passed += 1;
     97             puts(" " ANSI_GREEN "[GOOD]" ANSI_RESET);
     98         } else {
     99             printf(" " ANSI_RED "[BAD]" ANSI_RESET);
    100             if (status != 1) printf(ANSI_RED " (%d)" ANSI_RESET, status);
    101             printf("\n");
    102         }
    103         if (status != 0 && status != 1 && imode) testf();
    104     }
    105     printf("\n" ANSI_GREEN "%ld tests" ANSI_RESET " passed, "
    106            ANSI_RED "%ld tests" ANSI_RESET " failed.\n" ANSI_RESET,
    107            passed, total-passed);
    108     dlclose(lib);
    109 }