#include "test.h" #include #include #include #include static jmp_buf s_testJmp; static const char* s_failMsg; static char* s_logOutput = NULL; void fail(const char* msg) { s_failMsg = msg; longjmp(s_testJmp, 1); } void assert_not_null(void* ptr, const char* msg) { if (ptr == NULL) { fail(msg); } } void assert_str(const char* expected, const char* actual, const char* msg) { if (expected == NULL || actual == NULL || strcmp(expected, actual) != 0) { fail(msg); } } void assert_log(const char* expected, const char* msg) { assert_str(expected, s_logOutput, msg); } void assert_log_file(const char* filepath, const char* msg) { const char* generate = getenv("GENERATE_GOLDEN"); if (generate && strcmp(generate, "1") == 0) { FILE* f = fopen(filepath, "w"); if (!f) { fail("could not open golden file for writing"); return; } fputs(s_logOutput ? s_logOutput : "", f); fclose(f); return; } char* content = read_file_content(filepath); if (!content) { fail("could not open golden file for reading"); return; } assert_str(content, s_logOutput, msg); free(content); } char* read_file_content(const char* filepath) { FILE* f = fopen(filepath, "r"); if (!f) return NULL; fseek(f, 0, SEEK_END); long size = ftell(f); fseek(f, 0, SEEK_SET); char* content = malloc(size + 1); if (!content) { fclose(f); return NULL; } fread(content, 1, size, f); content[size] = '\0'; fclose(f); return content; } void assert_int(int expected, int actual, const char* msg) { if (expected != actual) { char buf[64]; snprintf(buf, sizeof(buf), "%s (expected %d, got %d)", msg, expected, actual); fail(buf); } } void assert_true(bool condition, const char* msg) { if (!condition) { fail(msg); } } void assert_false(bool condition, const char* msg) { if (condition) { fail(msg); } } static void log_append(const char* msg) { size_t oldLen = s_logOutput ? strlen(s_logOutput) : 0; size_t newLen = oldLen + strlen(msg) + 1; char* newOutput = malloc(newLen); if (newOutput) { if (s_logOutput) { strcpy(newOutput, s_logOutput); free(s_logOutput); } else { newOutput[0] = '\0'; } strcat(newOutput, msg); s_logOutput = newOutput; } } static void log_clear() { free(s_logOutput); s_logOutput = NULL; } typedef struct { const char* name; Test func; } TestCase; #include "test_token.c" #include "test_parser.c" #include "test_log.c" static int s_totalTests; static int s_greenTests; static TestCase s_tests[] = { {"tokenstream_open_fail", test_tokenstream_open_fail}, {"tokenstream_simple_keyword", test_tokenstream_simple_keyword}, {"tokenstream_keywords_and_symbols", test_tokenstream_keywords_and_symbols}, {"tokenstream_parentheses_and_brackets", test_tokenstream_parentheses_and_brackets}, {"tokenstream_comma", test_tokenstream_comma}, {"tokenstream_whitespace_ignored", test_tokenstream_whitespace_ignored}, {"tokenstream_void_function_signature", test_tokenstream_void_function_signature}, {"tokenstream_unknown_token", test_tokenstream_unknown_token}, {"tokenstream_info", test_tokenstream_info}, {"parser_module_name", test_parser_module_name}, {"parser_bad_module_name", test_parser_bad_module_name}, {"parser_missing_semicolon_module", test_parser_missing_semicolon_module}, {"parser_missing_semicolon_import", test_parser_missing_semicolon_import}, {"parser_bad_import_name", test_parser_bad_import_name}, {"parser_imports", test_parser_imports}, {"parser_public_imports", test_parser_public_imports}, {"log_error", test_log_error}, {"log_on_line", test_log_on_line}, }; int main(int argc, char** argv) { (void)argc; (void)argv; s_totalTests = sizeof(s_tests) / sizeof(s_tests[0]); s_greenTests = 0; const char* failedTests[s_totalTests + 1]; int failedCount = 0; for (int i = 0; i < s_totalTests; i++) { log_set_output(log_append); printf("%s...", s_tests[i].name); s_failMsg = NULL; if (setjmp(s_testJmp) == 0) { log_clear(); s_tests[i].func(); printf(" [OK]\n"); s_greenTests++; } else { printf(" [FAIL]: %s\n", s_failMsg ? s_failMsg : ""); failedTests[failedCount++] = s_tests[i].name; } } if (failedCount > 0) { printf("\nFailed tests:\n"); for (int i = 0; i < failedCount; i++) { printf(" - %s\n", failedTests[i]); } } printf("\n%d/%d tests passed.\n", s_greenTests, s_totalTests); return failedCount > 0 ? 1 : 0; }