summaryrefslogtreecommitdiff
path: root/tests/diff/diff_helpers.c
diff options
context:
space:
mode:
Diffstat (limited to 'tests/diff/diff_helpers.c')
-rw-r--r--tests/diff/diff_helpers.c246
1 files changed, 246 insertions, 0 deletions
diff --git a/tests/diff/diff_helpers.c b/tests/diff/diff_helpers.c
new file mode 100644
index 000000000..33bb561f6
--- /dev/null
+++ b/tests/diff/diff_helpers.c
@@ -0,0 +1,246 @@
+#include "clar_libgit2.h"
+#include "diff_helpers.h"
+
+git_tree *resolve_commit_oid_to_tree(
+ git_repository *repo,
+ const char *partial_oid)
+{
+ size_t len = strlen(partial_oid);
+ git_oid oid;
+ git_object *obj = NULL;
+ git_tree *tree = NULL;
+
+ if (git_oid_fromstrn(&oid, partial_oid, len) == 0)
+ git_object_lookup_prefix(&obj, repo, &oid, len, GIT_OBJ_ANY);
+ cl_assert(obj);
+ if (git_object_type(obj) == GIT_OBJ_TREE)
+ return (git_tree *)obj;
+ cl_assert(git_object_type(obj) == GIT_OBJ_COMMIT);
+ cl_git_pass(git_commit_tree(&tree, (git_commit *)obj));
+ git_object_free(obj);
+ return tree;
+}
+
+static char diff_pick_suffix(int mode)
+{
+ if (S_ISDIR(mode))
+ return '/';
+ else if (GIT_PERMS_IS_EXEC(mode))
+ return '*';
+ else
+ return ' ';
+}
+
+static void fprintf_delta(FILE *fp, const git_diff_delta *delta, float progress)
+{
+ char code = git_diff_status_char(delta->status);
+ char old_suffix = diff_pick_suffix(delta->old_file.mode);
+ char new_suffix = diff_pick_suffix(delta->new_file.mode);
+
+ fprintf(fp, "%c\t%s", code, delta->old_file.path);
+
+ if ((delta->old_file.path != delta->new_file.path &&
+ strcmp(delta->old_file.path, delta->new_file.path) != 0) ||
+ (delta->old_file.mode != delta->new_file.mode &&
+ delta->old_file.mode != 0 && delta->new_file.mode != 0))
+ fprintf(fp, "%c %s%c", old_suffix, delta->new_file.path, new_suffix);
+ else if (old_suffix != ' ')
+ fprintf(fp, "%c", old_suffix);
+
+ fprintf(fp, "\t[%.2f]\n", progress);
+}
+
+int diff_file_cb(
+ const git_diff_delta *delta,
+ float progress,
+ void *payload)
+{
+ diff_expects *e = payload;
+
+ if (e->debug)
+ fprintf_delta(stderr, delta, progress);
+
+ if (e->names)
+ cl_assert_equal_s(e->names[e->files], delta->old_file.path);
+ if (e->statuses)
+ cl_assert_equal_i(e->statuses[e->files], (int)delta->status);
+
+ e->files++;
+
+ if ((delta->flags & GIT_DIFF_FLAG_BINARY) != 0)
+ e->files_binary++;
+
+ cl_assert(delta->status <= GIT_DELTA_TYPECHANGE);
+
+ e->file_status[delta->status] += 1;
+
+ return 0;
+}
+
+int diff_print_file_cb(
+ const git_diff_delta *delta,
+ float progress,
+ void *payload)
+{
+ if (!payload) {
+ fprintf_delta(stderr, delta, progress);
+ return 0;
+ }
+
+ if (!((diff_expects *)payload)->debug)
+ fprintf_delta(stderr, delta, progress);
+
+ return diff_file_cb(delta, progress, payload);
+}
+
+int diff_hunk_cb(
+ const git_diff_delta *delta,
+ const git_diff_hunk *hunk,
+ void *payload)
+{
+ diff_expects *e = payload;
+ const char *scan = hunk->header, *scan_end = scan + hunk->header_len;
+
+ GIT_UNUSED(delta);
+
+ /* confirm no NUL bytes in header text */
+ while (scan < scan_end)
+ cl_assert('\0' != *scan++);
+
+ e->hunks++;
+ e->hunk_old_lines += hunk->old_lines;
+ e->hunk_new_lines += hunk->new_lines;
+ return 0;
+}
+
+int diff_line_cb(
+ const git_diff_delta *delta,
+ const git_diff_hunk *hunk,
+ const git_diff_line *line,
+ void *payload)
+{
+ diff_expects *e = payload;
+
+ GIT_UNUSED(delta);
+ GIT_UNUSED(hunk);
+
+ e->lines++;
+ switch (line->origin) {
+ case GIT_DIFF_LINE_CONTEXT:
+ case GIT_DIFF_LINE_CONTEXT_EOFNL: /* techically not a line */
+ e->line_ctxt++;
+ break;
+ case GIT_DIFF_LINE_ADDITION:
+ case GIT_DIFF_LINE_ADD_EOFNL: /* technically not a line add */
+ e->line_adds++;
+ break;
+ case GIT_DIFF_LINE_DELETION:
+ case GIT_DIFF_LINE_DEL_EOFNL: /* technically not a line delete */
+ e->line_dels++;
+ break;
+ default:
+ break;
+ }
+ return 0;
+}
+
+int diff_foreach_via_iterator(
+ git_diff *diff,
+ git_diff_file_cb file_cb,
+ git_diff_hunk_cb hunk_cb,
+ git_diff_line_cb line_cb,
+ void *data)
+{
+ size_t d, num_d = git_diff_num_deltas(diff);
+
+ for (d = 0; d < num_d; ++d) {
+ git_patch *patch;
+ const git_diff_delta *delta;
+ size_t h, num_h;
+
+ cl_git_pass(git_patch_from_diff(&patch, diff, d));
+ cl_assert((delta = git_patch_get_delta(patch)) != NULL);
+
+ /* call file_cb for this file */
+ if (file_cb != NULL && file_cb(delta, (float)d / num_d, data) != 0) {
+ git_patch_free(patch);
+ goto abort;
+ }
+
+ /* if there are no changes, then the patch will be NULL */
+ if (!patch) {
+ cl_assert(delta->status == GIT_DELTA_UNMODIFIED ||
+ (delta->flags & GIT_DIFF_FLAG_BINARY) != 0);
+ continue;
+ }
+
+ if (!hunk_cb && !line_cb) {
+ git_patch_free(patch);
+ continue;
+ }
+
+ num_h = git_patch_num_hunks(patch);
+
+ for (h = 0; h < num_h; h++) {
+ const git_diff_hunk *hunk;
+ size_t l, num_l;
+
+ cl_git_pass(git_patch_get_hunk(&hunk, &num_l, patch, h));
+
+ if (hunk_cb && hunk_cb(delta, hunk, data) != 0) {
+ git_patch_free(patch);
+ goto abort;
+ }
+
+ for (l = 0; l < num_l; ++l) {
+ const git_diff_line *line;
+
+ cl_git_pass(git_patch_get_line_in_hunk(&line, patch, h, l));
+
+ if (line_cb &&
+ line_cb(delta, hunk, line, data) != 0) {
+ git_patch_free(patch);
+ goto abort;
+ }
+ }
+ }
+
+ git_patch_free(patch);
+ }
+
+ return 0;
+
+abort:
+ giterr_clear();
+ return GIT_EUSER;
+}
+
+static int diff_print_cb(
+ const git_diff_delta *delta,
+ const git_diff_hunk *hunk,
+ const git_diff_line *line,
+ void *payload)
+{
+ FILE *fp = payload;
+
+ GIT_UNUSED(delta); GIT_UNUSED(hunk);
+
+ if (line->origin == GIT_DIFF_LINE_CONTEXT ||
+ line->origin == GIT_DIFF_LINE_ADDITION ||
+ line->origin == GIT_DIFF_LINE_DELETION)
+ fputc(line->origin, fp);
+ fwrite(line->content, 1, line->content_len, fp);
+ return 0;
+}
+
+void diff_print(FILE *fp, git_diff *diff)
+{
+ cl_git_pass(git_diff_print(
+ diff, GIT_DIFF_FORMAT_PATCH, diff_print_cb, fp ? fp : stderr));
+}
+
+void diff_print_raw(FILE *fp, git_diff *diff)
+{
+ cl_git_pass(git_diff_print(
+ diff, GIT_DIFF_FORMAT_RAW, diff_print_cb, fp ? fp : stderr));
+}