#include #include #include #include #undef ft_assert //--- // Test framework //--- void ft_test_init(ft_test *test) { test->passed = 0; test->skipped = 0; test->failed = 0; test->log = NULL; test->log_size = 0; } void ft_test_run(ft_test *test) { if(test->log) free(test->log); ft_test_init(test); test->run = true; if(!test->function) return; test->function(test); } int ft_assert(ft_test *test, int expression, char const *file, int line, char const *str) { if(expression) { test->passed++; } else { test->failed++; ft_log(test, "%s:%d: assertion failed:\n %s\n", file, line, str); } return expression; } void ft_skip(ft_test *test, int count) { test->skipped += count; } int ft_log(ft_test *test, char const *format, ...) { va_list args1, args2; va_start(args1, format); va_copy(args2, args1); int size = vsnprintf(NULL, 0, format, args1); if(test->log_size + size > 0xffff) return 0; char *newlog = realloc(test->log, test->log_size + size + 1); if(!newlog) return 0; vsnprintf(newlog + test->log_size, size + 1, format, args2); test->log = newlog; test->log_size += size; return size; } void ft_log_raw(ft_test *test, char const *str, size_t size) { if(test->log_size + size > 0xffff) return; char *newlog = realloc(test->log, test->log_size + size + 1); if(!newlog) return; memcpy(newlog + test->log_size, str, size); test->log = newlog; test->log_size += size; test->log[test->log_size] = 0; } //--- // Test lists (to organize by header) //--- void ft_list_init(ft_list *list) { list->passed = 0; list->skipped = 0; list->failed = 0; if(!list->children) return; for(int i = 0; list->children[i]; i++) { ft_test_init(list->children[i]); } } void ft_list_run(ft_list *list) { ft_list_init(list); if(!list->children) return; for(int i = 0; list->children[i]; i++) { ft_test_run(list->children[i]); } ft_list_aggregate(list); } void ft_list_aggregate(ft_list *l) { l->passed = 0; l->skipped = 0; l->failed = 0; if(!l->children) return; for(int i = 0; l->children[i]; i++) { ft_test const *t = l->children[i]; l->passed += t->passed; l->skipped += t->skipped; l->failed += t->failed; } } //--- // Utilities //--- int ft_test_color(ft_test const *t) { if(t->failed > 0) return FT_TEST_FAILED; if(t->skipped > 0) return FT_TEST_SKIPPED; if(t->passed > 0) return FT_TEST_PASSED; return (t->function && !t->run) ? FT_TEST_PENDING : FT_TEST_EMPTY; } int ft_list_color(ft_list const *l) { if(l->failed > 0) return FT_TEST_FAILED; if(l->skipped > 0) return FT_TEST_SKIPPED; if(l->children) { for(int i = 0; l->children[i]; i++) { if(l->children[i]->function && l->children[i]->run == 0) return FT_TEST_PENDING; } } if(l->passed > 0) return FT_TEST_PASSED; return FT_TEST_EMPTY; }