1 #include "clar_libgit2.h"
2 #include "diff_helpers.h"
3 #include "git2/sys/diff.h"
5 git_tree
*resolve_commit_oid_to_tree(
7 const char *partial_oid
)
9 size_t len
= strlen(partial_oid
);
11 git_object
*obj
= NULL
;
12 git_tree
*tree
= NULL
;
14 if (git_oid_fromstrn(&oid
, partial_oid
, len
) == 0)
15 cl_git_pass(git_object_lookup_prefix(&obj
, repo
, &oid
, len
, GIT_OBJECT_ANY
));
17 cl_git_pass(git_object_peel((git_object
**) &tree
, obj
, GIT_OBJECT_TREE
));
22 static char diff_pick_suffix(int mode
)
26 else if (GIT_PERMS_IS_EXEC(mode
))
32 static void fprintf_delta(FILE *fp
, const git_diff_delta
*delta
, float progress
)
34 char code
= git_diff_status_char(delta
->status
);
35 char old_suffix
= diff_pick_suffix(delta
->old_file
.mode
);
36 char new_suffix
= diff_pick_suffix(delta
->new_file
.mode
);
38 fprintf(fp
, "%c\t%s", code
, delta
->old_file
.path
);
40 if ((delta
->old_file
.path
!= delta
->new_file
.path
&&
41 strcmp(delta
->old_file
.path
, delta
->new_file
.path
) != 0) ||
42 (delta
->old_file
.mode
!= delta
->new_file
.mode
&&
43 delta
->old_file
.mode
!= 0 && delta
->new_file
.mode
!= 0))
44 fprintf(fp
, "%c %s%c", old_suffix
, delta
->new_file
.path
, new_suffix
);
45 else if (old_suffix
!= ' ')
46 fprintf(fp
, "%c", old_suffix
);
48 fprintf(fp
, "\t[%.2f]\n", progress
);
52 const git_diff_delta
*delta
,
56 diff_expects
*e
= payload
;
59 fprintf_delta(stderr
, delta
, progress
);
62 cl_assert_equal_s(e
->names
[e
->files
], delta
->old_file
.path
);
64 cl_assert_equal_i(e
->statuses
[e
->files
], (int)delta
->status
);
68 if ((delta
->flags
& GIT_DIFF_FLAG_BINARY
) != 0)
71 cl_assert(delta
->status
<= GIT_DELTA_CONFLICTED
);
73 e
->file_status
[delta
->status
] += 1;
78 int diff_print_file_cb(
79 const git_diff_delta
*delta
,
84 fprintf_delta(stderr
, delta
, progress
);
88 if (!((diff_expects
*)payload
)->debug
)
89 fprintf_delta(stderr
, delta
, progress
);
91 return diff_file_cb(delta
, progress
, payload
);
95 const git_diff_delta
*delta
,
96 const git_diff_binary
*binary
,
107 const git_diff_delta
*delta
,
108 const git_diff_hunk
*hunk
,
111 diff_expects
*e
= payload
;
112 const char *scan
= hunk
->header
, *scan_end
= scan
+ hunk
->header_len
;
116 /* confirm no NUL bytes in header text */
117 while (scan
< scan_end
)
118 cl_assert('\0' != *scan
++);
121 e
->hunk_old_lines
+= hunk
->old_lines
;
122 e
->hunk_new_lines
+= hunk
->new_lines
;
127 const git_diff_delta
*delta
,
128 const git_diff_hunk
*hunk
,
129 const git_diff_line
*line
,
132 diff_expects
*e
= payload
;
138 switch (line
->origin
) {
139 case GIT_DIFF_LINE_CONTEXT
:
140 case GIT_DIFF_LINE_CONTEXT_EOFNL
: /* techically not a line */
143 case GIT_DIFF_LINE_ADDITION
:
144 case GIT_DIFF_LINE_ADD_EOFNL
: /* technically not a line add */
147 case GIT_DIFF_LINE_DELETION
:
148 case GIT_DIFF_LINE_DEL_EOFNL
: /* technically not a line delete */
157 int diff_foreach_via_iterator(
159 git_diff_file_cb file_cb
,
160 git_diff_binary_cb binary_cb
,
161 git_diff_hunk_cb hunk_cb
,
162 git_diff_line_cb line_cb
,
165 size_t d
, num_d
= git_diff_num_deltas(diff
);
167 GIT_UNUSED(binary_cb
);
169 for (d
= 0; d
< num_d
; ++d
) {
171 const git_diff_delta
*delta
;
174 cl_git_pass(git_patch_from_diff(&patch
, diff
, d
));
175 cl_assert((delta
= git_patch_get_delta(patch
)) != NULL
);
177 /* call file_cb for this file */
178 if (file_cb
!= NULL
&& file_cb(delta
, (float)d
/ num_d
, data
) != 0) {
179 git_patch_free(patch
);
183 /* if there are no changes, then the patch will be NULL */
185 cl_assert(delta
->status
== GIT_DELTA_UNMODIFIED
||
186 (delta
->flags
& GIT_DIFF_FLAG_BINARY
) != 0);
190 if (!hunk_cb
&& !line_cb
) {
191 git_patch_free(patch
);
195 num_h
= git_patch_num_hunks(patch
);
197 for (h
= 0; h
< num_h
; h
++) {
198 const git_diff_hunk
*hunk
;
201 cl_git_pass(git_patch_get_hunk(&hunk
, &num_l
, patch
, h
));
203 if (hunk_cb
&& hunk_cb(delta
, hunk
, data
) != 0) {
204 git_patch_free(patch
);
208 for (l
= 0; l
< num_l
; ++l
) {
209 const git_diff_line
*line
;
211 cl_git_pass(git_patch_get_line_in_hunk(&line
, patch
, h
, l
));
214 line_cb(delta
, hunk
, line
, data
) != 0) {
215 git_patch_free(patch
);
221 git_patch_free(patch
);
231 void diff_print(FILE *fp
, git_diff
*diff
)
234 git_diff_print(diff
, GIT_DIFF_FORMAT_PATCH
,
235 git_diff_print_callback__to_file_handle
, fp
? fp
: stderr
));
238 void diff_print_raw(FILE *fp
, git_diff
*diff
)
241 git_diff_print(diff
, GIT_DIFF_FORMAT_RAW
,
242 git_diff_print_callback__to_file_handle
, fp
? fp
: stderr
));
245 static size_t num_modified_deltas(git_diff
*diff
)
247 const git_diff_delta
*delta
;
250 for (i
= 0; i
< git_diff_num_deltas(diff
); i
++) {
251 delta
= git_diff_get_delta(diff
, i
);
253 if (delta
->status
!= GIT_DELTA_UNMODIFIED
)
260 void diff_assert_equal(git_diff
*a
, git_diff
*b
)
262 const git_diff_delta
*ad
, *bd
;
267 cl_assert_equal_i(num_modified_deltas(a
), num_modified_deltas(b
));
270 i
< git_diff_num_deltas(a
) && j
< git_diff_num_deltas(b
); ) {
272 ad
= git_diff_get_delta(a
, i
);
273 bd
= git_diff_get_delta(b
, j
);
275 if (ad
->status
== GIT_DELTA_UNMODIFIED
) {
279 if (bd
->status
== GIT_DELTA_UNMODIFIED
) {
284 cl_assert_equal_i(ad
->status
, bd
->status
);
285 cl_assert_equal_i(ad
->flags
, bd
->flags
);
286 cl_assert_equal_i(ad
->similarity
, bd
->similarity
);
287 cl_assert_equal_i(ad
->nfiles
, bd
->nfiles
);
289 /* Don't examine the size or the flags of the deltas;
290 * computed deltas have sizes (parsed deltas do not) and
291 * computed deltas will have flags of `VALID_ID` and
292 * `EXISTS` (parsed deltas will not query the ODB.)
295 /* an empty id indicates that it wasn't presented, because
296 * the diff was identical. (eg, pure rename, mode change only, etc)
298 if (ad
->old_file
.id_abbrev
&& bd
->old_file
.id_abbrev
) {
299 cl_assert_equal_i(ad
->old_file
.id_abbrev
, bd
->old_file
.id_abbrev
);
300 cl_assert_equal_oid(&ad
->old_file
.id
, &bd
->old_file
.id
);
301 cl_assert_equal_i(ad
->old_file
.mode
, bd
->old_file
.mode
);
303 cl_assert_equal_s(ad
->old_file
.path
, bd
->old_file
.path
);
305 if (ad
->new_file
.id_abbrev
&& bd
->new_file
.id_abbrev
) {
306 cl_assert_equal_oid(&ad
->new_file
.id
, &bd
->new_file
.id
);
307 cl_assert_equal_i(ad
->new_file
.id_abbrev
, bd
->new_file
.id_abbrev
);
308 cl_assert_equal_i(ad
->new_file
.mode
, bd
->new_file
.mode
);
310 cl_assert_equal_s(ad
->new_file
.path
, bd
->new_file
.path
);