/* * Clay v0.7.0 * * This is an autogenerated file. Do not modify. * To add new unit tests or suites, regenerate the whole * file with `./clay` */ #define clay_print(...) printf(__VA_ARGS__) #include #include #include #include #include #include /* required for sandboxing */ #include #include #ifdef _WIN32 # include # include # include # include # pragma comment(lib, "shell32") # define _CC __cdecl # define stat(path, st) _stat(path, st) # define mkdir(path, mode) _mkdir(path) # define chdir(path) _chdir(path) # define access(path, mode) _access(path, mode) # define strdup(str) _strdup(str) # ifndef __MINGW32__ # define strncpy(to, from, to_size) strncpy_s(to, to_size, from, _TRUNCATE) # define W_OK 02 # define S_ISDIR(x) ((x & _S_IFDIR) != 0) # endif typedef struct _stat STAT_T; #else # include # define _CC typedef struct stat STAT_T; #endif #include "clay.h" static void fs_rm(const char *_source); static void fs_copy(const char *_source, const char *dest); static const char * fixture_path(const char *base, const char *fixture_name); struct clay_error { const char *test; int test_number; const char *suite; const char *file; int line_number; const char *error_msg; char *description; struct clay_error *next; }; static struct { const char *active_test; const char *active_suite; int suite_errors; int total_errors; int test_count; struct clay_error *errors; struct clay_error *last_error; void (*local_cleanup)(void *); void *local_cleanup_payload; jmp_buf trampoline; int trampoline_enabled; } _clay; struct clay_func { const char *name; void (*ptr)(void); size_t suite_n; }; struct clay_suite { const char *name; struct clay_func initialize; struct clay_func cleanup; const struct clay_func *tests; size_t test_count; }; /* From clay_sandbox.c */ static void clay_unsandbox(void); static int clay_sandbox(void); static void clay_run_test( const struct clay_func *test, const struct clay_func *initialize, const struct clay_func *cleanup) { int error_st = _clay.suite_errors; _clay.trampoline_enabled = 1; if (setjmp(_clay.trampoline) == 0) { if (initialize->ptr != NULL) initialize->ptr(); test->ptr(); } _clay.trampoline_enabled = 0; if (_clay.local_cleanup != NULL) _clay.local_cleanup(_clay.local_cleanup_payload); if (cleanup->ptr != NULL) cleanup->ptr(); _clay.test_count++; /* remove any local-set cleanup methods */ _clay.local_cleanup = NULL; _clay.local_cleanup_payload = NULL; clay_print("%c", (_clay.suite_errors > error_st) ? 'F' : '.'); } static void clay_print_error(int num, const struct clay_error *error) { clay_print(" %d) Failure:\n", num); clay_print("%s::%s (%s) [%s:%d] [-t%d]\n", error->suite, error->test, "no description", error->file, error->line_number, error->test_number); clay_print(" %s\n", error->error_msg); if (error->description != NULL) clay_print(" %s\n", error->description); clay_print("\n"); } static void clay_report_errors(void) { int i = 1; struct clay_error *error, *next; error = _clay.errors; while (error != NULL) { next = error->next; clay_print_error(i++, error); free(error->description); free(error); error = next; } } static void clay_run_suite(const struct clay_suite *suite) { const struct clay_func *test = suite->tests; size_t i; _clay.active_suite = suite->name; _clay.suite_errors = 0; for (i = 0; i < suite->test_count; ++i) { _clay.active_test = test[i].name; clay_run_test(&test[i], &suite->initialize, &suite->cleanup); } } static void clay_run_single(const struct clay_func *test, const struct clay_suite *suite) { _clay.suite_errors = 0; _clay.active_suite = suite->name; _clay.active_test = test->name; clay_run_test(test, &suite->initialize, &suite->cleanup); } static void clay_usage(const char *arg) { printf("Usage: %s [options]\n\n", arg); printf("Options:\n"); printf(" -tXX\t\tRun only the test number XX\n"); printf(" -sXX\t\tRun only the suite number XX\n"); exit(-1); } static void clay_parse_args( int argc, char **argv, const struct clay_func *callbacks, size_t cb_count, const struct clay_suite *suites, size_t suite_count) { int i; for (i = 1; i < argc; ++i) { char *argument = argv[i]; char action; int num; if (argument[0] != '-') clay_usage(argv[0]); action = argument[1]; num = strtol(argument + 2, &argument, 10); if (*argument != '\0' || num < 0) clay_usage(argv[0]); switch (action) { case 't': if ((size_t)num >= cb_count) { fprintf(stderr, "Test number %d does not exist.\n", num); exit(-1); } clay_print("Started (%s::%s)\n", suites[callbacks[num].suite_n].name, callbacks[num].name); clay_run_single(&callbacks[num], &suites[callbacks[num].suite_n]); break; case 's': if ((size_t)num >= suite_count) { fprintf(stderr, "Suite number %d does not exist.\n", num); exit(-1); } clay_print("Started (%s::*)\n", suites[num].name); clay_run_suite(&suites[num]); break; default: clay_usage(argv[0]); } } } static int clay_test( int argc, char **argv, const char *suites_str, const struct clay_func *callbacks, size_t cb_count, const struct clay_suite *suites, size_t suite_count) { clay_print("Loaded %d suites: %s\n", (int)suite_count, suites_str); if (clay_sandbox() < 0) { fprintf(stderr, "Failed to sandbox the test runner.\n" "Testing will proceed without sandboxing.\n"); } if (argc > 1) { clay_parse_args(argc, argv, callbacks, cb_count, suites, suite_count); } else { size_t i; clay_print("Started\n"); for (i = 0; i < suite_count; ++i) { const struct clay_suite *s = &suites[i]; clay_run_suite(s); } } clay_print("\n\n"); clay_report_errors(); clay_unsandbox(); return _clay.total_errors; } void clay__assert( int condition, const char *file, int line, const char *error_msg, const char *description, int should_abort) { struct clay_error *error; if (condition) return; error = calloc(1, sizeof(struct clay_error)); if (_clay.errors == NULL) _clay.errors = error; if (_clay.last_error != NULL) _clay.last_error->next = error; _clay.last_error = error; error->test = _clay.active_test; error->test_number = _clay.test_count; error->suite = _clay.active_suite; error->file = file; error->line_number = line; error->error_msg = error_msg; if (description != NULL) error->description = strdup(description); _clay.suite_errors++; _clay.total_errors++; if (should_abort) { if (!_clay.trampoline_enabled) { fprintf(stderr, "Fatal error: a cleanup method raised an exception."); exit(-1); } longjmp(_clay.trampoline, -1); } } void cl_set_cleanup(void (*cleanup)(void *), void *opaque) { _clay.local_cleanup = cleanup; _clay.local_cleanup_payload = opaque; } static char _clay_path[4096]; static int is_valid_tmp_path(const char *path) { STAT_T st; if (stat(path, &st) != 0) return 0; if (!S_ISDIR(st.st_mode)) return 0; return (access(path, W_OK) == 0); } static int find_tmp_path(char *buffer, size_t length) { static const size_t var_count = 4; static const char *env_vars[] = { "TMPDIR", "TMP", "TEMP", "USERPROFILE" }; #ifdef _WIN32 if (GetTempPath((DWORD)length, buffer)) return 0; #else size_t i; for (i = 0; i < var_count; ++i) { const char *env = getenv(env_vars[i]); if (!env) continue; if (is_valid_tmp_path(env)) { strncpy(buffer, env, length); return 0; } } /* If the environment doesn't say anything, try to use /tmp */ if (is_valid_tmp_path("/tmp")) { strncpy(buffer, "/tmp", length); return 0; } #endif /* This system doesn't like us, try to use the current directory */ if (is_valid_tmp_path(".")) { strncpy(buffer, ".", length); return 0; } return -1; } static void clay_unsandbox(void) { if (_clay_path[0] == '\0') return; #ifdef _WIN32 chdir(".."); #endif fs_rm(_clay_path); } static int build_sandbox_path(void) { const char path_tail[] = "clay_tmp_XXXXXX"; size_t len; if (find_tmp_path(_clay_path, sizeof(_clay_path)) < 0) return -1; len = strlen(_clay_path); #ifdef _WIN32 { /* normalize path to POSIX forward slashes */ size_t i; for (i = 0; i < len; ++i) { if (_clay_path[i] == '\\') _clay_path[i] = '/'; } } #endif if (_clay_path[len - 1] != '/') { _clay_path[len++] = '/'; } strncpy(_clay_path + len, path_tail, sizeof(_clay_path) - len); #ifdef _MSC_VER if (_mktemp_s(_clay_path, sizeof(_clay_path)) != 0) return -1; #else if (mktemp(_clay_path) == NULL) return -1; #endif return 0; } static int clay_sandbox(void) { if (_clay_path[0] == '\0' && build_sandbox_path() < 0) return -1; if (mkdir(_clay_path, 0700) != 0) return -1; if (chdir(_clay_path) != 0) return -1; return 0; } static const char * fixture_path(const char *base, const char *fixture_name) { static char _path[4096]; size_t root_len; root_len = strlen(base); strncpy(_path, base, sizeof(_path)); if (_path[root_len - 1] != '/') _path[root_len++] = '/'; if (fixture_name[0] == '/') fixture_name++; strncpy(_path + root_len, fixture_name, sizeof(_path) - root_len); return _path; } #ifdef CLAY_FIXTURE_PATH const char *cl_fixture(const char *fixture_name) { return fixture_path(CLAY_FIXTURE_PATH, fixture_name); } void cl_fixture_sandbox(const char *fixture_name) { fs_copy(cl_fixture(fixture_name), _clay_path); } void cl_fixture_cleanup(const char *fixture_name) { fs_rm(fixture_path(_clay_path, fixture_name)); } #endif #ifdef _WIN32 #define FOF_FLAGS (FOF_SILENT | FOF_NOCONFIRMATION | FOF_NOERRORUI | FOF_NOCONFIRMMKDIR) static char * fileops_path(const char *_path) { char *path = NULL; size_t length, i; if (_path == NULL) return NULL; length = strlen(_path); path = malloc(length + 2); if (path == NULL) return NULL; memcpy(path, _path, length); path[length] = 0; path[length + 1] = 0; for (i = 0; i < length; ++i) { if (path[i] == '/') path[i] = '\\'; } return path; } static void fileops(int mode, const char *_source, const char *_dest) { SHFILEOPSTRUCT fops; char *source = fileops_path(_source); char *dest = fileops_path(_dest); ZeroMemory(&fops, sizeof(SHFILEOPSTRUCT)); fops.wFunc = mode; fops.pFrom = source; fops.pTo = dest; fops.fFlags = FOF_FLAGS; cl_assert_( SHFileOperation(&fops) == 0, "Windows SHFileOperation failed" ); free(source); free(dest); } static void fs_rm(const char *_source) { fileops(FO_DELETE, _source, NULL); } static void fs_copy(const char *_source, const char *_dest) { fileops(FO_COPY, _source, _dest); } void cl_fs_cleanup(void) { fs_rm(fixture_path(_clay_path, "*")); } #else static int shell_out(char * const argv[]) { int status; pid_t pid; pid = fork(); if (pid < 0) { fprintf(stderr, "System error: `fork()` call failed.\n"); exit(-1); } if (pid == 0) { execv(argv[0], argv); } waitpid(pid, &status, 0); return WEXITSTATUS(status); } static void fs_copy(const char *_source, const char *dest) { char *argv[5]; char *source; size_t source_len; source = strdup(_source); source_len = strlen(source); if (source[source_len - 1] == '/') source[source_len - 1] = 0; argv[0] = "/bin/cp"; argv[1] = "-R"; argv[2] = source; argv[3] = (char *)dest; argv[4] = NULL; cl_must_pass_( shell_out(argv), "Failed to copy test fixtures to sandbox" ); free(source); } static void fs_rm(const char *source) { char *argv[4]; argv[0] = "/bin/rm"; argv[1] = "-Rf"; argv[2] = (char *)source; argv[3] = NULL; cl_must_pass_( shell_out(argv), "Failed to cleanup the sandbox" ); } void cl_fs_cleanup(void) { clay_unsandbox(); clay_sandbox(); } #endif extern void test_core_dirent__dont_traverse_dot(void); extern void test_core_dirent__traverse_subfolder(void); extern void test_core_dirent__traverse_slash_terminated_folder(void); extern void test_core_dirent__dont_traverse_empty_folders(void); extern void test_core_dirent__traverse_weird_filenames(void); extern void test_core_filebuf__0(void); extern void test_core_filebuf__1(void); extern void test_core_filebuf__2(void); extern void test_core_path__0(void); extern void test_core_path__1(void); extern void test_core_path__2(void); extern void test_core_path__5(void); extern void test_core_path__6(void); extern void test_core_rmdir__initialize(void); extern void test_core_rmdir__delete_recursive(void); extern void test_core_rmdir__fail_to_delete_non_empty_dir(void); extern void test_core_string__0(void); extern void test_core_string__1(void); extern void test_core_vector__0(void); extern void test_core_vector__1(void); extern void test_core_vector__2(void); extern void test_network_remotes__initialize(void); extern void test_network_remotes__cleanup(void); extern void test_network_remotes__parsing(void); extern void test_network_remotes__refspec_parsing(void); extern void test_network_remotes__fnmatch(void); extern void test_network_remotes__transform(void); extern void test_status_single__hash_single_file(void); extern void test_status_worktree__initialize(void); extern void test_status_worktree__cleanup(void); extern void test_status_worktree__whole_repository(void); extern void test_status_worktree__empty_repository(void); static const struct clay_func _all_callbacks[] = { {"dont_traverse_dot", &test_core_dirent__dont_traverse_dot, 0}, {"traverse_subfolder", &test_core_dirent__traverse_subfolder, 0}, {"traverse_slash_terminated_folder", &test_core_dirent__traverse_slash_terminated_folder, 0}, {"dont_traverse_empty_folders", &test_core_dirent__dont_traverse_empty_folders, 0}, {"traverse_weird_filenames", &test_core_dirent__traverse_weird_filenames, 0}, {"0", &test_core_filebuf__0, 1}, {"1", &test_core_filebuf__1, 1}, {"2", &test_core_filebuf__2, 1}, {"0", &test_core_path__0, 2}, {"1", &test_core_path__1, 2}, {"2", &test_core_path__2, 2}, {"5", &test_core_path__5, 2}, {"6", &test_core_path__6, 2}, {"delete_recursive", &test_core_rmdir__delete_recursive, 3}, {"fail_to_delete_non_empty_dir", &test_core_rmdir__fail_to_delete_non_empty_dir, 3}, {"0", &test_core_string__0, 4}, {"1", &test_core_string__1, 4}, {"0", &test_core_vector__0, 5}, {"1", &test_core_vector__1, 5}, {"2", &test_core_vector__2, 5}, {"parsing", &test_network_remotes__parsing, 6}, {"refspec_parsing", &test_network_remotes__refspec_parsing, 6}, {"fnmatch", &test_network_remotes__fnmatch, 6}, {"transform", &test_network_remotes__transform, 6}, {"hash_single_file", &test_status_single__hash_single_file, 7}, {"whole_repository", &test_status_worktree__whole_repository, 8}, {"empty_repository", &test_status_worktree__empty_repository, 8} }; static const struct clay_suite _all_suites[] = { { "core::dirent", {NULL, NULL, 0}, {NULL, NULL, 0}, &_all_callbacks[0], 5 }, { "core::filebuf", {NULL, NULL, 0}, {NULL, NULL, 0}, &_all_callbacks[5], 3 }, { "core::path", {NULL, NULL, 0}, {NULL, NULL, 0}, &_all_callbacks[8], 5 }, { "core::rmdir", {"initialize", &test_core_rmdir__initialize, 3}, {NULL, NULL, 0}, &_all_callbacks[13], 2 }, { "core::string", {NULL, NULL, 0}, {NULL, NULL, 0}, &_all_callbacks[15], 2 }, { "core::vector", {NULL, NULL, 0}, {NULL, NULL, 0}, &_all_callbacks[17], 3 }, { "network::remotes", {"initialize", &test_network_remotes__initialize, 6}, {"cleanup", &test_network_remotes__cleanup, 6}, &_all_callbacks[20], 4 }, { "status::single", {NULL, NULL, 0}, {NULL, NULL, 0}, &_all_callbacks[24], 1 }, { "status::worktree", {"initialize", &test_status_worktree__initialize, 8}, {"cleanup", &test_status_worktree__cleanup, 8}, &_all_callbacks[25], 2 } }; static const char _suites_str[] = "core::dirent, core::filebuf, core::path, core::rmdir, core::string, core::vector, network::remotes, status::single, status::worktree"; int _CC main(int argc, char *argv[]) { return clay_test( argc, argv, _suites_str, _all_callbacks, 27, _all_suites, 9 ); }