#include "clar_libgit2.h" #include "diff_helpers.h" static git_repository *g_repo = NULL; void test_diff_notify__initialize(void) { } void test_diff_notify__cleanup(void) { cl_git_sandbox_cleanup(); } static int assert_called_notifications( const git_diff *diff_so_far, const git_diff_delta *delta_to_add, const char *matched_pathspec, void *payload) { bool found = false; notify_expected *exp = (notify_expected*)payload; notify_expected *e; GIT_UNUSED(diff_so_far); for (e = exp; e->path != NULL; e++) { if (strcmp(e->path, delta_to_add->new_file.path)) continue; cl_assert_equal_s(e->matched_pathspec, matched_pathspec); found = true; break; } cl_assert(found); return 0; } static void test_notify( char **searched_pathspecs, int pathspecs_count, notify_expected *expected_matched_pathspecs, int expected_diffed_files_count) { git_diff_options opts = GIT_DIFF_OPTIONS_INIT; git_diff *diff = NULL; diff_expects exp; g_repo = cl_git_sandbox_init("status"); opts.flags |= GIT_DIFF_INCLUDE_IGNORED | GIT_DIFF_INCLUDE_UNTRACKED; opts.notify_cb = assert_called_notifications; opts.pathspec.strings = searched_pathspecs; opts.pathspec.count = pathspecs_count; opts.payload = expected_matched_pathspecs; memset(&exp, 0, sizeof(exp)); cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, NULL, &opts)); cl_git_pass(git_diff_foreach(diff, diff_file_cb, NULL, NULL, NULL, &exp)); cl_assert_equal_i(expected_diffed_files_count, exp.files); git_diff_free(diff); } void test_diff_notify__notify_single_pathspec(void) { char *searched_pathspecs[] = { "*_deleted", }; notify_expected expected_matched_pathspecs[] = { { "file_deleted", "*_deleted" }, { "staged_changes_file_deleted", "*_deleted" }, { NULL, NULL } }; test_notify(searched_pathspecs, 1, expected_matched_pathspecs, 2); } void test_diff_notify__notify_multiple_pathspec(void) { char *searched_pathspecs[] = { "staged_changes_cant_find_me", "subdir/modified_cant_find_me", "subdir/*", "staged*" }; notify_expected expected_matched_pathspecs[] = { { "staged_changes_file_deleted", "staged*" }, { "staged_changes_modified_file", "staged*" }, { "staged_delete_modified_file", "staged*" }, { "staged_new_file_deleted_file", "staged*" }, { "staged_new_file_modified_file", "staged*" }, { "subdir/deleted_file", "subdir/*" }, { "subdir/modified_file", "subdir/*" }, { "subdir/new_file", "subdir/*" }, { NULL, NULL } }; test_notify(searched_pathspecs, 4, expected_matched_pathspecs, 8); } void test_diff_notify__notify_catchall_with_empty_pathspecs(void) { char *searched_pathspecs[] = { "", "" }; notify_expected expected_matched_pathspecs[] = { { "file_deleted", NULL }, { "ignored_file", NULL }, { "modified_file", NULL }, { "new_file", NULL }, { "\xe8\xbf\x99", NULL }, { "staged_changes_file_deleted", NULL }, { "staged_changes_modified_file", NULL }, { "staged_delete_modified_file", NULL }, { "staged_new_file_deleted_file", NULL }, { "staged_new_file_modified_file", NULL }, { "subdir/deleted_file", NULL }, { "subdir/modified_file", NULL }, { "subdir/new_file", NULL }, { NULL, NULL } }; test_notify(searched_pathspecs, 1, expected_matched_pathspecs, 13); } void test_diff_notify__notify_catchall(void) { char *searched_pathspecs[] = { "*", }; notify_expected expected_matched_pathspecs[] = { { "file_deleted", "*" }, { "ignored_file", "*" }, { "modified_file", "*" }, { "new_file", "*" }, { "\xe8\xbf\x99", "*" }, { "staged_changes_file_deleted", "*" }, { "staged_changes_modified_file", "*" }, { "staged_delete_modified_file", "*" }, { "staged_new_file_deleted_file", "*" }, { "staged_new_file_modified_file", "*" }, { "subdir/deleted_file", "*" }, { "subdir/modified_file", "*" }, { "subdir/new_file", "*" }, { NULL, NULL } }; test_notify(searched_pathspecs, 1, expected_matched_pathspecs, 13); } static int abort_diff( const git_diff *diff_so_far, const git_diff_delta *delta_to_add, const char *matched_pathspec, void *payload) { GIT_UNUSED(diff_so_far); GIT_UNUSED(delta_to_add); GIT_UNUSED(matched_pathspec); GIT_UNUSED(payload); return -42; } void test_diff_notify__notify_cb_can_abort_diff(void) { git_diff_options opts = GIT_DIFF_OPTIONS_INIT; git_diff *diff = NULL; char *pathspec = NULL; g_repo = cl_git_sandbox_init("status"); opts.flags |= GIT_DIFF_INCLUDE_IGNORED | GIT_DIFF_INCLUDE_UNTRACKED; opts.notify_cb = abort_diff; opts.pathspec.strings = &pathspec; opts.pathspec.count = 1; pathspec = "file_deleted"; cl_git_fail_with( git_diff_index_to_workdir(&diff, g_repo, NULL, &opts), -42); pathspec = "staged_changes_modified_file"; cl_git_fail_with( git_diff_index_to_workdir(&diff, g_repo, NULL, &opts), -42); } static int filter_all( const git_diff *diff_so_far, const git_diff_delta *delta_to_add, const char *matched_pathspec, void *payload) { GIT_UNUSED(diff_so_far); GIT_UNUSED(delta_to_add); GIT_UNUSED(matched_pathspec); GIT_UNUSED(payload); return 42; } void test_diff_notify__notify_cb_can_be_used_as_filtering_function(void) { git_diff_options opts = GIT_DIFF_OPTIONS_INIT; git_diff *diff = NULL; char *pathspec = NULL; diff_expects exp; g_repo = cl_git_sandbox_init("status"); opts.flags |= GIT_DIFF_INCLUDE_IGNORED | GIT_DIFF_INCLUDE_UNTRACKED; opts.notify_cb = filter_all; opts.pathspec.strings = &pathspec; opts.pathspec.count = 1; pathspec = "*_deleted"; memset(&exp, 0, sizeof(exp)); cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, NULL, &opts)); cl_git_pass(git_diff_foreach(diff, diff_file_cb, NULL, NULL, NULL, &exp)); cl_assert_equal_i(0, exp.files); git_diff_free(diff); } static int progress_abort_diff( const git_diff *diff_so_far, const char *old_path, const char *new_path, void *payload) { GIT_UNUSED(diff_so_far); GIT_UNUSED(old_path); GIT_UNUSED(new_path); GIT_UNUSED(payload); return -42; } void test_diff_notify__progress_cb_can_abort_diff(void) { git_diff_options opts = GIT_DIFF_OPTIONS_INIT; git_diff *diff = NULL; g_repo = cl_git_sandbox_init("status"); opts.flags |= GIT_DIFF_INCLUDE_IGNORED | GIT_DIFF_INCLUDE_UNTRACKED; opts.progress_cb = progress_abort_diff; cl_git_fail_with( git_diff_index_to_workdir(&diff, g_repo, NULL, &opts), -42); }