summaryrefslogtreecommitdiff
path: root/tests-clar/diff/diff_helpers.c
blob: 59e01802c1f8656a9fe5e75b85e4f179f958a4ac (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
#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;
}

int diff_file_fn(
	void *cb_data,
	git_diff_delta *delta,
	float progress)
{
	diff_expects *e = cb_data;

	GIT_UNUSED(progress);

	if (delta->binary)
		e->at_least_one_of_them_is_binary = true;

	e->files++;
	switch (delta->status) {
	case GIT_DELTA_ADDED: e->file_adds++; break;
	case GIT_DELTA_DELETED: e->file_dels++; break;
	case GIT_DELTA_MODIFIED: e->file_mods++; break;
	case GIT_DELTA_IGNORED: e->file_ignored++; break;
	case GIT_DELTA_UNTRACKED: e->file_untracked++; break;
	case GIT_DELTA_UNMODIFIED: e->file_unmodified++; break;
	default: break;
	}
	return 0;
}

int diff_hunk_fn(
	void *cb_data,
	git_diff_delta *delta,
	git_diff_range *range,
	const char *header,
	size_t header_len)
{
	diff_expects *e = cb_data;

	GIT_UNUSED(delta);
	GIT_UNUSED(header);
	GIT_UNUSED(header_len);

	e->hunks++;
	e->hunk_old_lines += range->old_lines;
	e->hunk_new_lines += range->new_lines;
	return 0;
}

int diff_line_fn(
	void *cb_data,
	git_diff_delta *delta,
	git_diff_range *range,
	char line_origin,
	const char *content,
	size_t content_len)
{
	diff_expects *e = cb_data;

	GIT_UNUSED(delta);
	GIT_UNUSED(range);
	GIT_UNUSED(content);
	GIT_UNUSED(content_len);

	e->lines++;
	switch (line_origin) {
	case GIT_DIFF_LINE_CONTEXT:
		e->line_ctxt++;
		break;
	case GIT_DIFF_LINE_ADDITION:
		e->line_adds++;
		break;
	case GIT_DIFF_LINE_ADD_EOFNL:
		assert(0);
		break;
	case GIT_DIFF_LINE_DELETION:
		e->line_dels++;
		break;
	case GIT_DIFF_LINE_DEL_EOFNL:
		/* technically not a line delete, but we'll count it as such */
		e->line_dels++;
		break;
	default:
		break;
	}
	return 0;
}

int diff_foreach_via_iterator(
	git_diff_list *diff,
	void *data,
	git_diff_file_fn file_cb,
	git_diff_hunk_fn hunk_cb,
	git_diff_data_fn line_cb)
{
	int error, curr, total;
	git_diff_iterator *iter;
	git_diff_delta *delta;

	if ((error = git_diff_iterator_new(&iter, diff)) < 0)
		return error;

	curr  = 0;
	total = git_diff_iterator_num_files(iter);

	while (!(error = git_diff_iterator_next_file(&delta, iter))) {
		git_diff_range *range;
		const char *hdr;
		size_t hdr_len;

		/* call file_cb for this file */
		if (file_cb != NULL && file_cb(data, delta, (float)curr / total) != 0)
			goto abort;

		if (!hunk_cb && !line_cb)
			continue;

		while (!(error = git_diff_iterator_next_hunk(
				&range, &hdr, &hdr_len, iter))) {
			char origin;
			const char *line;
			size_t line_len;

			if (hunk_cb && hunk_cb(data, delta, range, hdr, hdr_len) != 0)
				goto abort;

			if (!line_cb)
				continue;

			while (!(error = git_diff_iterator_next_line(
				&origin, &line, &line_len, iter))) {

				if (line_cb(data, delta, range, origin, line, line_len) != 0)
					goto abort;
			}

			if (error && error != GIT_ITEROVER)
				goto done;
		}

		if (error && error != GIT_ITEROVER)
			goto done;
	}

done:
	git_diff_iterator_free(iter);

	if (error == GIT_ITEROVER)
		error = 0;

	return error;

abort:
	git_diff_iterator_free(iter);
	giterr_clear();

	return GIT_EUSER;
}