#include #include #include #include #include #define MAX_NUMBER_OF_TESTS_PER_FILE 100 #define MAX_LENGTH_OF_TEST_NAME 100 typedef enum { path_type_unknown, path_type_directory, path_type_file } path_type; int check_path_type(const char* path) { struct stat path_stat; if (stat(path, &path_stat) != 0) return path_type_unknown; if (S_ISDIR(path_stat.st_mode)) return path_type_directory; return path_type_file; } void handle_input_file( const char* input_path, int path_strip_index, void (*handle)(const char*, int, FILE*) ) { FILE* input_fd = fopen(input_path, "rb"); handle(input_path, path_strip_index, input_fd); fclose(input_fd); } void push(char* directories, int cursor, const char* to_add) { int i = 0; for (; to_add[i] != 0; i++) { directories[cursor * PATH_MAX + i] = to_add[i]; } while (i < PATH_MAX) directories[cursor * PATH_MAX + i++] = 0; } void handle_input_directory( const char* input_path, void (*handle)(const char*, int, FILE*) ) { int cursor = 0; char* directories = malloc(PATH_MAX * PATH_MAX * sizeof(*directories)); push(directories, cursor, input_path); int input_shift = strlen(input_path) + 1; while (cursor != -1) { char* path = &directories[(cursor--) * PATH_MAX]; DIR* dir_ptr = opendir(path); if (dir_ptr == NULL) { fprintf(stderr, "Couldn't open the directory: %s\n", path); continue; } struct dirent* entry_ptr; char full_path[PATH_MAX]; int i = 0; for (; path[i] != 0; i++) { full_path[i] = path[i]; } full_path[i++] = '/'; while ((entry_ptr = readdir(dir_ptr)) != NULL) { if ( strcmp(entry_ptr->d_name, ".") == 0 || strcmp(entry_ptr->d_name, "..") == 0 ) continue; int j = 0; for (; entry_ptr->d_name[j] != 0; j++) { full_path[i + j] = entry_ptr->d_name[j]; } full_path[i + j] = 0; if (entry_ptr->d_type == DT_REG) { handle_input_file(full_path, input_shift, handle); continue; } push(directories, ++cursor, full_path); } closedir(dir_ptr); } free(directories); } void handle_input( const char* input_path, int input_type, void (*handle)(const char*, int, FILE*) ) { if (input_type == path_type_file) { handle_input_file(input_path, 0, handle); } else { handle_input_directory(input_path, handle); return; } } struct file_tests { char path[PATH_MAX]; int test_count; char test_names[MAX_NUMBER_OF_TESTS_PER_FILE][MAX_LENGTH_OF_TEST_NAME]; }; struct tests { int count; int capacity; struct file_tests* items; }; struct tests tests; int max(int a, int b) { if (a > b) return a; return b; } void append_tests(struct file_tests file_tests) { if (tests.count + 1 > tests.capacity) { tests.capacity = max(32, tests.count) + tests.count; tests.items = realloc(tests.items, tests.capacity * sizeof(*tests.items)); } tests.items[tests.count++] = file_tests; } void handle_fn(const char* input_path, int path_strip_index, FILE* file) { if (input_path[strlen(input_path) - 1] != 'c') return; char ch; char match[] = "\nbool test_"; int match_len = strlen(match); int i = 0; char output[MAX_NUMBER_OF_TESTS_PER_FILE][MAX_LENGTH_OF_TEST_NAME]; int k = 0; int kk = 0; enum { search_mode, read_test_name }; int mode = search_mode; while ((ch = fgetc(file)) != EOF) { if (mode == search_mode) { if (match[i] == ch) i++; else i = match[0] == ch; if (i == match_len) { mode = read_test_name; kk = 0; } } else if (mode == read_test_name) { if (ch == '(') { mode = search_mode; k++; continue; } output[k][kk++] = ch; output[k][kk] = 0; } } struct file_tests tests = { .test_count = k }; memcpy(tests.path, input_path, strlen(input_path) + 1); memcpy(tests.test_names, output, sizeof(output)); append_tests(tests); } int main() { tests.items = malloc(sizeof(*tests.items) * 100); tests.capacity = 100; tests.count = 0; handle_input("src", path_type_directory, handle_fn); FILE* f = fopen("generated/tests.c", "w"); int total_test_count = 0; for (int i = 0; i < tests.count; i++) { struct file_tests item = tests.items[i]; if (item.test_count == 0) continue; total_test_count += item.test_count; fprintf(f, "#include \"../%s\"\n", item.path); } fprintf( f, "\nint total_test_count = %d;\nbool (*tests[%d])(void) = {\n", total_test_count, total_test_count ); int max_test_name_size = 0; for (int i = 0; i < tests.count; i++) { struct file_tests item = tests.items[i]; printf("%s\n", item.path); if (item.test_count == 0) continue; for (int j = 0; j < item.test_count; j++) { printf("\t%s\n", item.test_names[j]); fprintf(f, " test_%s,\n", item.test_names[j]); int test_name_size = strlen(item.test_names[j]); if (max_test_name_size < test_name_size) { max_test_name_size = test_name_size; } } } fprintf(f, "};\n"); fprintf(f, "\nint max_test_name_size = %d;", max_test_name_size); fprintf(f, "\nchar test_names[%d][100] = {\n", total_test_count); for (int i = 0; i < tests.count; i++) { struct file_tests item = tests.items[i]; if (item.test_count == 0) continue; for (int j = 0; j < item.test_count; j++) { fprintf(f, " \"%s\",\n", item.test_names[j]); } } fprintf(f, "};\n"); fclose(f); }