1 #include "clar_libgit2.h"
2 #include "diff_helpers.h"
3 #include "repository.h"
5 #include "git2/sys/diff.h"
6 #include "../checkout/checkout_helpers.h"
8 static git_repository
*g_repo
= NULL
;
10 void test_diff_workdir__cleanup(void)
12 cl_git_sandbox_cleanup();
15 void test_diff_workdir__to_index(void)
17 git_diff_options opts
= GIT_DIFF_OPTIONS_INIT
;
18 git_diff
*diff
= NULL
;
22 g_repo
= cl_git_sandbox_init("status");
24 opts
.context_lines
= 3;
25 opts
.interhunk_lines
= 1;
26 opts
.flags
|= GIT_DIFF_INCLUDE_IGNORED
| GIT_DIFF_INCLUDE_UNTRACKED
;
28 cl_git_pass(git_diff_index_to_workdir(&diff
, g_repo
, NULL
, &opts
));
30 for (use_iterator
= 0; use_iterator
<= 1; use_iterator
++) {
31 memset(&exp
, 0, sizeof(exp
));
34 cl_git_pass(diff_foreach_via_iterator(
35 diff
, diff_file_cb
, diff_binary_cb
, diff_hunk_cb
, diff_line_cb
, &exp
));
37 cl_git_pass(git_diff_foreach(
38 diff
, diff_file_cb
, diff_binary_cb
, diff_hunk_cb
, diff_line_cb
, &exp
));
40 /* to generate these values:
41 * - cd to tests/resources/status,
43 * - git diff --name-status
47 cl_assert_equal_i(13, exp
.files
);
48 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_ADDED
]);
49 cl_assert_equal_i(4, exp
.file_status
[GIT_DELTA_DELETED
]);
50 cl_assert_equal_i(4, exp
.file_status
[GIT_DELTA_MODIFIED
]);
51 cl_assert_equal_i(1, exp
.file_status
[GIT_DELTA_IGNORED
]);
52 cl_assert_equal_i(4, exp
.file_status
[GIT_DELTA_UNTRACKED
]);
54 cl_assert_equal_i(8, exp
.hunks
);
56 cl_assert_equal_i(14, exp
.lines
);
57 cl_assert_equal_i(5, exp
.line_ctxt
);
58 cl_assert_equal_i(4, exp
.line_adds
);
59 cl_assert_equal_i(5, exp
.line_dels
);
63 git_diff_perfdata perf
= GIT_DIFF_PERFDATA_INIT
;
64 cl_git_pass(git_diff_get_perfdata(&perf
, diff
));
66 13 /* in root */ + 3 /* in subdir */, perf
.stat_calls
);
67 cl_assert_equal_sz(5, perf
.oid_calculations
);
73 void test_diff_workdir__to_index_with_conflicts(void)
75 git_diff_options opts
= GIT_DIFF_OPTIONS_INIT
;
76 git_diff
*diff
= NULL
;
78 git_index_entry our_entry
= {{0}}, their_entry
= {{0}};
79 diff_expects exp
= {0};
81 g_repo
= cl_git_sandbox_init("status");
83 opts
.context_lines
= 3;
84 opts
.interhunk_lines
= 1;
86 /* Adding an entry that represents a rename gets two files in conflict */
87 our_entry
.path
= "subdir/modified_file";
88 our_entry
.mode
= 0100644;
89 git_oid_fromstr(&our_entry
.id
, "ee3fa1b8c00aff7fe02065fdb50864bb0d932ccf");
91 their_entry
.path
= "subdir/rename_conflict";
92 their_entry
.mode
= 0100644;
93 git_oid_fromstr(&their_entry
.id
, "2bd0a343aeef7a2cf0d158478966a6e587ff3863");
95 cl_git_pass(git_repository_index(&index
, g_repo
));
96 cl_git_pass(git_index_conflict_add(index
, NULL
, &our_entry
, &their_entry
));
98 cl_git_pass(git_diff_index_to_workdir(&diff
, g_repo
, index
, &opts
));
100 cl_git_pass(diff_foreach_via_iterator(
101 diff
, diff_file_cb
, diff_binary_cb
, diff_hunk_cb
, diff_line_cb
, &exp
));
103 cl_assert_equal_i(9, exp
.files
);
104 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_ADDED
]);
105 cl_assert_equal_i(4, exp
.file_status
[GIT_DELTA_DELETED
]);
106 cl_assert_equal_i(3, exp
.file_status
[GIT_DELTA_MODIFIED
]);
107 cl_assert_equal_i(2, exp
.file_status
[GIT_DELTA_CONFLICTED
]);
109 cl_assert_equal_i(7, exp
.hunks
);
111 cl_assert_equal_i(12, exp
.lines
);
112 cl_assert_equal_i(4, exp
.line_ctxt
);
113 cl_assert_equal_i(3, exp
.line_adds
);
114 cl_assert_equal_i(5, exp
.line_dels
);
117 git_index_free(index
);
120 void test_diff_workdir__to_index_with_assume_unchanged(void)
122 git_diff_options opts
= GIT_DIFF_OPTIONS_INIT
;
123 git_diff
*diff
= NULL
;
124 git_index
*idx
= NULL
;
126 const git_index_entry
*iep
;
129 g_repo
= cl_git_sandbox_init("status");
131 /* do initial diff */
133 cl_git_pass(git_diff_index_to_workdir(&diff
, g_repo
, NULL
, &opts
));
134 memset(&exp
, 0, sizeof(exp
));
135 cl_git_pass(git_diff_foreach(
136 diff
, diff_file_cb
, diff_binary_cb
, diff_hunk_cb
, diff_line_cb
, &exp
));
137 cl_assert_equal_i(8, exp
.files
);
138 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_ADDED
]);
139 cl_assert_equal_i(4, exp
.file_status
[GIT_DELTA_DELETED
]);
140 cl_assert_equal_i(4, exp
.file_status
[GIT_DELTA_MODIFIED
]);
143 /* mark a couple of entries with ASSUME_UNCHANGED */
145 cl_git_pass(git_repository_index(&idx
, g_repo
));
147 cl_assert((iep
= git_index_get_bypath(idx
, "modified_file", 0)) != NULL
);
148 memcpy(&ie
, iep
, sizeof(ie
));
149 ie
.flags
|= GIT_INDEX_ENTRY_VALID
;
150 cl_git_pass(git_index_add(idx
, &ie
));
152 cl_assert((iep
= git_index_get_bypath(idx
, "file_deleted", 0)) != NULL
);
153 memcpy(&ie
, iep
, sizeof(ie
));
154 ie
.flags
|= GIT_INDEX_ENTRY_VALID
;
155 cl_git_pass(git_index_add(idx
, &ie
));
157 cl_git_pass(git_index_write(idx
));
160 /* redo diff and see that entries are skipped */
162 cl_git_pass(git_diff_index_to_workdir(&diff
, g_repo
, NULL
, &opts
));
163 memset(&exp
, 0, sizeof(exp
));
164 cl_git_pass(git_diff_foreach(
165 diff
, diff_file_cb
, diff_binary_cb
, diff_hunk_cb
, diff_line_cb
, &exp
));
166 cl_assert_equal_i(6, exp
.files
);
167 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_ADDED
]);
168 cl_assert_equal_i(3, exp
.file_status
[GIT_DELTA_DELETED
]);
169 cl_assert_equal_i(3, exp
.file_status
[GIT_DELTA_MODIFIED
]);
174 void test_diff_workdir__to_tree(void)
176 /* grabbed a couple of commit oids from the history of the attr repo */
177 const char *a_commit
= "26a125ee1bf"; /* the current HEAD */
178 const char *b_commit
= "0017bd4ab1ec3"; /* the start */
180 git_diff_options opts
= GIT_DIFF_OPTIONS_INIT
;
181 git_diff
*diff
= NULL
;
182 git_diff
*diff2
= NULL
;
186 g_repo
= cl_git_sandbox_init("status");
188 a
= resolve_commit_oid_to_tree(g_repo
, a_commit
);
189 b
= resolve_commit_oid_to_tree(g_repo
, b_commit
);
191 opts
.context_lines
= 3;
192 opts
.interhunk_lines
= 1;
193 opts
.flags
|= GIT_DIFF_INCLUDE_IGNORED
| GIT_DIFF_INCLUDE_UNTRACKED
;
195 /* You can't really generate the equivalent of git_diff_tree_to_workdir()
196 * using C git. It really wants to interpose the index into the diff.
198 * To validate the following results with command line git, I ran the
200 * - git ls-tree 26a125
201 * - find . ! -path ./.git/\* -a -type f | git hash-object --stdin-paths
202 * The results are documented at the bottom of this file in the
203 * long comment entitled "PREPARATION OF TEST DATA".
205 cl_git_pass(git_diff_tree_to_workdir(&diff
, g_repo
, a
, &opts
));
207 for (use_iterator
= 0; use_iterator
<= 1; use_iterator
++) {
208 memset(&exp
, 0, sizeof(exp
));
211 cl_git_pass(diff_foreach_via_iterator(
212 diff
, diff_file_cb
, diff_binary_cb
, diff_hunk_cb
, diff_line_cb
, &exp
));
214 cl_git_pass(git_diff_foreach(
215 diff
, diff_file_cb
, diff_binary_cb
, diff_hunk_cb
, diff_line_cb
, &exp
));
217 cl_assert_equal_i(14, exp
.files
);
218 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_ADDED
]);
219 cl_assert_equal_i(4, exp
.file_status
[GIT_DELTA_DELETED
]);
220 cl_assert_equal_i(4, exp
.file_status
[GIT_DELTA_MODIFIED
]);
221 cl_assert_equal_i(1, exp
.file_status
[GIT_DELTA_IGNORED
]);
222 cl_assert_equal_i(5, exp
.file_status
[GIT_DELTA_UNTRACKED
]);
225 /* Since there is no git diff equivalent, let's just assume that the
226 * text diffs produced by git_diff_foreach are accurate here. We will
227 * do more apples-to-apples test comparison below.
232 memset(&exp
, 0, sizeof(exp
));
234 /* This is a compatible emulation of "git diff <sha>" which looks like
235 * a workdir to tree diff (even though it is not really). This is what
236 * you would get from "git diff --name-status 26a125ee1bf"
238 cl_git_pass(git_diff_tree_to_index(&diff
, g_repo
, a
, NULL
, &opts
));
239 cl_git_pass(git_diff_index_to_workdir(&diff2
, g_repo
, NULL
, &opts
));
240 cl_git_pass(git_diff_merge(diff
, diff2
));
241 git_diff_free(diff2
);
243 for (use_iterator
= 0; use_iterator
<= 1; use_iterator
++) {
244 memset(&exp
, 0, sizeof(exp
));
247 cl_git_pass(diff_foreach_via_iterator(
248 diff
, diff_file_cb
, diff_binary_cb
, diff_hunk_cb
, diff_line_cb
, &exp
));
250 cl_git_pass(git_diff_foreach(
251 diff
, diff_file_cb
, diff_binary_cb
, diff_hunk_cb
, diff_line_cb
, &exp
));
253 cl_assert_equal_i(15, exp
.files
);
254 cl_assert_equal_i(2, exp
.file_status
[GIT_DELTA_ADDED
]);
255 cl_assert_equal_i(5, exp
.file_status
[GIT_DELTA_DELETED
]);
256 cl_assert_equal_i(4, exp
.file_status
[GIT_DELTA_MODIFIED
]);
257 cl_assert_equal_i(1, exp
.file_status
[GIT_DELTA_IGNORED
]);
258 cl_assert_equal_i(3, exp
.file_status
[GIT_DELTA_UNTRACKED
]);
260 cl_assert_equal_i(11, exp
.hunks
);
262 cl_assert_equal_i(17, exp
.lines
);
263 cl_assert_equal_i(4, exp
.line_ctxt
);
264 cl_assert_equal_i(8, exp
.line_adds
);
265 cl_assert_equal_i(5, exp
.line_dels
);
270 memset(&exp
, 0, sizeof(exp
));
272 /* Again, emulating "git diff <sha>" for testing purposes using
273 * "git diff --name-status 0017bd4ab1ec3" instead.
275 cl_git_pass(git_diff_tree_to_index(&diff
, g_repo
, b
, NULL
, &opts
));
276 cl_git_pass(git_diff_index_to_workdir(&diff2
, g_repo
, NULL
, &opts
));
277 cl_git_pass(git_diff_merge(diff
, diff2
));
278 git_diff_free(diff2
);
280 for (use_iterator
= 0; use_iterator
<= 1; use_iterator
++) {
281 memset(&exp
, 0, sizeof(exp
));
284 cl_git_pass(diff_foreach_via_iterator(
285 diff
, diff_file_cb
, diff_binary_cb
, diff_hunk_cb
, diff_line_cb
, &exp
));
287 cl_git_pass(git_diff_foreach(
288 diff
, diff_file_cb
, diff_binary_cb
, diff_hunk_cb
, diff_line_cb
, &exp
));
290 cl_assert_equal_i(16, exp
.files
);
291 cl_assert_equal_i(5, exp
.file_status
[GIT_DELTA_ADDED
]);
292 cl_assert_equal_i(4, exp
.file_status
[GIT_DELTA_DELETED
]);
293 cl_assert_equal_i(3, exp
.file_status
[GIT_DELTA_MODIFIED
]);
294 cl_assert_equal_i(1, exp
.file_status
[GIT_DELTA_IGNORED
]);
295 cl_assert_equal_i(3, exp
.file_status
[GIT_DELTA_UNTRACKED
]);
297 cl_assert_equal_i(12, exp
.hunks
);
299 cl_assert_equal_i(19, exp
.lines
);
300 cl_assert_equal_i(3, exp
.line_ctxt
);
301 cl_assert_equal_i(12, exp
.line_adds
);
302 cl_assert_equal_i(4, exp
.line_dels
);
307 /* Let's try that once more with a reversed diff */
309 opts
.flags
|= GIT_DIFF_REVERSE
;
311 cl_git_pass(git_diff_tree_to_index(&diff
, g_repo
, b
, NULL
, &opts
));
312 cl_git_pass(git_diff_index_to_workdir(&diff2
, g_repo
, NULL
, &opts
));
313 cl_git_pass(git_diff_merge(diff
, diff2
));
314 git_diff_free(diff2
);
316 memset(&exp
, 0, sizeof(exp
));
318 cl_git_pass(git_diff_foreach(
319 diff
, diff_file_cb
, diff_binary_cb
, diff_hunk_cb
, diff_line_cb
, &exp
));
321 cl_assert_equal_i(16, exp
.files
);
322 cl_assert_equal_i(5, exp
.file_status
[GIT_DELTA_DELETED
]);
323 cl_assert_equal_i(4, exp
.file_status
[GIT_DELTA_ADDED
]);
324 cl_assert_equal_i(3, exp
.file_status
[GIT_DELTA_MODIFIED
]);
325 cl_assert_equal_i(1, exp
.file_status
[GIT_DELTA_IGNORED
]);
326 cl_assert_equal_i(3, exp
.file_status
[GIT_DELTA_UNTRACKED
]);
328 cl_assert_equal_i(12, exp
.hunks
);
330 cl_assert_equal_i(19, exp
.lines
);
331 cl_assert_equal_i(3, exp
.line_ctxt
);
332 cl_assert_equal_i(12, exp
.line_dels
);
333 cl_assert_equal_i(4, exp
.line_adds
);
343 void test_diff_workdir__to_index_with_pathspec(void)
345 git_diff_options opts
= GIT_DIFF_OPTIONS_INIT
;
346 git_diff
*diff
= NULL
;
348 char *pathspec
= NULL
;
351 g_repo
= cl_git_sandbox_init("status");
353 opts
.context_lines
= 3;
354 opts
.interhunk_lines
= 1;
355 opts
.flags
|= GIT_DIFF_INCLUDE_IGNORED
| GIT_DIFF_INCLUDE_UNTRACKED
;
356 opts
.pathspec
.strings
= &pathspec
;
357 opts
.pathspec
.count
= 1;
359 cl_git_pass(git_diff_index_to_workdir(&diff
, g_repo
, NULL
, &opts
));
361 for (use_iterator
= 0; use_iterator
<= 1; use_iterator
++) {
362 memset(&exp
, 0, sizeof(exp
));
365 cl_git_pass(diff_foreach_via_iterator(
366 diff
, diff_file_cb
, NULL
, NULL
, NULL
, &exp
));
368 cl_git_pass(git_diff_foreach(diff
, diff_file_cb
, NULL
, NULL
, NULL
, &exp
));
370 cl_assert_equal_i(13, exp
.files
);
371 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_ADDED
]);
372 cl_assert_equal_i(4, exp
.file_status
[GIT_DELTA_DELETED
]);
373 cl_assert_equal_i(4, exp
.file_status
[GIT_DELTA_MODIFIED
]);
374 cl_assert_equal_i(1, exp
.file_status
[GIT_DELTA_IGNORED
]);
375 cl_assert_equal_i(4, exp
.file_status
[GIT_DELTA_UNTRACKED
]);
380 pathspec
= "modified_file";
382 cl_git_pass(git_diff_index_to_workdir(&diff
, g_repo
, NULL
, &opts
));
384 for (use_iterator
= 0; use_iterator
<= 1; use_iterator
++) {
385 memset(&exp
, 0, sizeof(exp
));
388 cl_git_pass(diff_foreach_via_iterator(
389 diff
, diff_file_cb
, NULL
, NULL
, NULL
, &exp
));
391 cl_git_pass(git_diff_foreach(diff
, diff_file_cb
, NULL
, NULL
, NULL
, &exp
));
393 cl_assert_equal_i(1, exp
.files
);
394 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_ADDED
]);
395 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_DELETED
]);
396 cl_assert_equal_i(1, exp
.file_status
[GIT_DELTA_MODIFIED
]);
397 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_IGNORED
]);
398 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_UNTRACKED
]);
405 cl_git_pass(git_diff_index_to_workdir(&diff
, g_repo
, NULL
, &opts
));
407 for (use_iterator
= 0; use_iterator
<= 1; use_iterator
++) {
408 memset(&exp
, 0, sizeof(exp
));
411 cl_git_pass(diff_foreach_via_iterator(
412 diff
, diff_file_cb
, NULL
, NULL
, NULL
, &exp
));
414 cl_git_pass(git_diff_foreach(diff
, diff_file_cb
, NULL
, NULL
, NULL
, &exp
));
416 cl_assert_equal_i(3, exp
.files
);
417 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_ADDED
]);
418 cl_assert_equal_i(1, exp
.file_status
[GIT_DELTA_DELETED
]);
419 cl_assert_equal_i(1, exp
.file_status
[GIT_DELTA_MODIFIED
]);
420 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_IGNORED
]);
421 cl_assert_equal_i(1, exp
.file_status
[GIT_DELTA_UNTRACKED
]);
426 pathspec
= "*_deleted";
428 cl_git_pass(git_diff_index_to_workdir(&diff
, g_repo
, NULL
, &opts
));
430 for (use_iterator
= 0; use_iterator
<= 1; use_iterator
++) {
431 memset(&exp
, 0, sizeof(exp
));
434 cl_git_pass(diff_foreach_via_iterator(
435 diff
, diff_file_cb
, NULL
, NULL
, NULL
, &exp
));
437 cl_git_pass(git_diff_foreach(diff
, diff_file_cb
, NULL
, NULL
, NULL
, &exp
));
439 cl_assert_equal_i(2, exp
.files
);
440 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_ADDED
]);
441 cl_assert_equal_i(2, exp
.file_status
[GIT_DELTA_DELETED
]);
442 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_MODIFIED
]);
443 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_IGNORED
]);
444 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_UNTRACKED
]);
450 void test_diff_workdir__to_index_with_pathlist_disabling_fnmatch(void)
452 git_diff_options opts
= GIT_DIFF_OPTIONS_INIT
;
453 git_diff
*diff
= NULL
;
455 char *pathspec
= NULL
;
458 g_repo
= cl_git_sandbox_init("status");
460 opts
.context_lines
= 3;
461 opts
.interhunk_lines
= 1;
462 opts
.flags
|= GIT_DIFF_INCLUDE_IGNORED
| GIT_DIFF_INCLUDE_UNTRACKED
|
463 GIT_DIFF_DISABLE_PATHSPEC_MATCH
;
464 opts
.pathspec
.strings
= &pathspec
;
465 opts
.pathspec
.count
= 0;
467 /* ensure that an empty pathspec list is ignored */
468 cl_git_pass(git_diff_index_to_workdir(&diff
, g_repo
, NULL
, &opts
));
470 for (use_iterator
= 0; use_iterator
<= 1; use_iterator
++) {
471 memset(&exp
, 0, sizeof(exp
));
474 cl_git_pass(diff_foreach_via_iterator(
475 diff
, diff_file_cb
, NULL
, NULL
, NULL
, &exp
));
477 cl_git_pass(git_diff_foreach(diff
, diff_file_cb
, NULL
, NULL
, NULL
, &exp
));
479 cl_assert_equal_i(13, exp
.files
);
480 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_ADDED
]);
481 cl_assert_equal_i(4, exp
.file_status
[GIT_DELTA_DELETED
]);
482 cl_assert_equal_i(4, exp
.file_status
[GIT_DELTA_MODIFIED
]);
483 cl_assert_equal_i(1, exp
.file_status
[GIT_DELTA_IGNORED
]);
484 cl_assert_equal_i(4, exp
.file_status
[GIT_DELTA_UNTRACKED
]);
489 /* ensure that a single NULL pathspec is filtered out (like when using
493 opts
.pathspec
.count
= 1;
495 cl_git_pass(git_diff_index_to_workdir(&diff
, g_repo
, NULL
, &opts
));
497 for (use_iterator
= 0; use_iterator
<= 1; use_iterator
++) {
498 memset(&exp
, 0, sizeof(exp
));
501 cl_git_pass(diff_foreach_via_iterator(
502 diff
, diff_file_cb
, NULL
, NULL
, NULL
, &exp
));
504 cl_git_pass(git_diff_foreach(diff
, diff_file_cb
, NULL
, NULL
, NULL
, &exp
));
506 cl_assert_equal_i(13, exp
.files
);
507 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_ADDED
]);
508 cl_assert_equal_i(4, exp
.file_status
[GIT_DELTA_DELETED
]);
509 cl_assert_equal_i(4, exp
.file_status
[GIT_DELTA_MODIFIED
]);
510 cl_assert_equal_i(1, exp
.file_status
[GIT_DELTA_IGNORED
]);
511 cl_assert_equal_i(4, exp
.file_status
[GIT_DELTA_UNTRACKED
]);
516 pathspec
= "modified_file";
518 cl_git_pass(git_diff_index_to_workdir(&diff
, g_repo
, NULL
, &opts
));
520 for (use_iterator
= 0; use_iterator
<= 1; use_iterator
++) {
521 memset(&exp
, 0, sizeof(exp
));
524 cl_git_pass(diff_foreach_via_iterator(
525 diff
, diff_file_cb
, NULL
, NULL
, NULL
, &exp
));
527 cl_git_pass(git_diff_foreach(diff
, diff_file_cb
, NULL
, NULL
, NULL
, &exp
));
529 cl_assert_equal_i(1, exp
.files
);
530 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_ADDED
]);
531 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_DELETED
]);
532 cl_assert_equal_i(1, exp
.file_status
[GIT_DELTA_MODIFIED
]);
533 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_IGNORED
]);
534 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_UNTRACKED
]);
539 /* ensure that subdirs can be specified */
542 cl_git_pass(git_diff_index_to_workdir(&diff
, g_repo
, NULL
, &opts
));
544 for (use_iterator
= 0; use_iterator
<= 1; use_iterator
++) {
545 memset(&exp
, 0, sizeof(exp
));
548 cl_git_pass(diff_foreach_via_iterator(
549 diff
, diff_file_cb
, NULL
, NULL
, NULL
, &exp
));
551 cl_git_pass(git_diff_foreach(diff
, diff_file_cb
, NULL
, NULL
, NULL
, &exp
));
553 cl_assert_equal_i(3, exp
.files
);
554 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_ADDED
]);
555 cl_assert_equal_i(1, exp
.file_status
[GIT_DELTA_DELETED
]);
556 cl_assert_equal_i(1, exp
.file_status
[GIT_DELTA_MODIFIED
]);
557 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_IGNORED
]);
558 cl_assert_equal_i(1, exp
.file_status
[GIT_DELTA_UNTRACKED
]);
563 /* ensure that subdirs can be specified with a trailing slash */
564 pathspec
= "subdir/";
566 cl_git_pass(git_diff_index_to_workdir(&diff
, g_repo
, NULL
, &opts
));
568 for (use_iterator
= 0; use_iterator
<= 1; use_iterator
++) {
569 memset(&exp
, 0, sizeof(exp
));
572 cl_git_pass(diff_foreach_via_iterator(
573 diff
, diff_file_cb
, NULL
, NULL
, NULL
, &exp
));
575 cl_git_pass(git_diff_foreach(diff
, diff_file_cb
, NULL
, NULL
, NULL
, &exp
));
577 cl_assert_equal_i(3, exp
.files
);
578 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_ADDED
]);
579 cl_assert_equal_i(1, exp
.file_status
[GIT_DELTA_DELETED
]);
580 cl_assert_equal_i(1, exp
.file_status
[GIT_DELTA_MODIFIED
]);
581 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_IGNORED
]);
582 cl_assert_equal_i(1, exp
.file_status
[GIT_DELTA_UNTRACKED
]);
587 /* ensure that fnmatching is completely disabled */
588 pathspec
= "subdir/*";
590 cl_git_pass(git_diff_index_to_workdir(&diff
, g_repo
, NULL
, &opts
));
592 for (use_iterator
= 0; use_iterator
<= 1; use_iterator
++) {
593 memset(&exp
, 0, sizeof(exp
));
596 cl_git_pass(diff_foreach_via_iterator(
597 diff
, diff_file_cb
, NULL
, NULL
, NULL
, &exp
));
599 cl_git_pass(git_diff_foreach(diff
, diff_file_cb
, NULL
, NULL
, NULL
, &exp
));
601 cl_assert_equal_i(0, exp
.files
);
602 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_ADDED
]);
603 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_DELETED
]);
604 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_MODIFIED
]);
605 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_IGNORED
]);
606 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_UNTRACKED
]);
611 /* ensure that the prefix matching isn't completely braindead */
614 cl_git_pass(git_diff_index_to_workdir(&diff
, g_repo
, NULL
, &opts
));
616 for (use_iterator
= 0; use_iterator
<= 1; use_iterator
++) {
617 memset(&exp
, 0, sizeof(exp
));
620 cl_git_pass(diff_foreach_via_iterator(
621 diff
, diff_file_cb
, NULL
, NULL
, NULL
, &exp
));
623 cl_git_pass(git_diff_foreach(diff
, diff_file_cb
, NULL
, NULL
, NULL
, &exp
));
625 cl_assert_equal_i(0, exp
.files
);
626 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_ADDED
]);
627 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_DELETED
]);
628 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_MODIFIED
]);
629 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_IGNORED
]);
630 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_UNTRACKED
]);
635 /* ensure that fnmatching isn't working at all */
636 pathspec
= "*_deleted";
638 cl_git_pass(git_diff_index_to_workdir(&diff
, g_repo
, NULL
, &opts
));
640 for (use_iterator
= 0; use_iterator
<= 1; use_iterator
++) {
641 memset(&exp
, 0, sizeof(exp
));
644 cl_git_pass(diff_foreach_via_iterator(
645 diff
, diff_file_cb
, NULL
, NULL
, NULL
, &exp
));
647 cl_git_pass(git_diff_foreach(diff
, diff_file_cb
, NULL
, NULL
, NULL
, &exp
));
649 cl_assert_equal_i(0, exp
.files
);
650 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_ADDED
]);
651 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_DELETED
]);
652 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_MODIFIED
]);
653 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_IGNORED
]);
654 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_UNTRACKED
]);
660 void test_diff_workdir__filemode_changes(void)
662 git_diff
*diff
= NULL
;
666 if (!cl_is_chmod_supported())
669 g_repo
= cl_git_sandbox_init("issue_592");
671 cl_repo_set_bool(g_repo
, "core.filemode", true);
673 /* test once with no mods */
675 cl_git_pass(git_diff_index_to_workdir(&diff
, g_repo
, NULL
, NULL
));
677 for (use_iterator
= 0; use_iterator
<= 1; use_iterator
++) {
678 memset(&exp
, 0, sizeof(exp
));
681 cl_git_pass(diff_foreach_via_iterator(
682 diff
, diff_file_cb
, diff_binary_cb
, diff_hunk_cb
, diff_line_cb
, &exp
));
684 cl_git_pass(git_diff_foreach(
685 diff
, diff_file_cb
, diff_binary_cb
, diff_hunk_cb
, diff_line_cb
, &exp
));
687 cl_assert_equal_i(0, exp
.files
);
688 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_MODIFIED
]);
689 cl_assert_equal_i(0, exp
.hunks
);
694 /* chmod file and test again */
696 cl_assert(cl_toggle_filemode("issue_592/a.txt"));
698 cl_git_pass(git_diff_index_to_workdir(&diff
, g_repo
, NULL
, NULL
));
700 for (use_iterator
= 0; use_iterator
<= 1; use_iterator
++) {
701 memset(&exp
, 0, sizeof(exp
));
704 cl_git_pass(diff_foreach_via_iterator(
705 diff
, diff_file_cb
, diff_binary_cb
, diff_hunk_cb
, diff_line_cb
, &exp
));
707 cl_git_pass(git_diff_foreach(
708 diff
, diff_file_cb
, diff_binary_cb
, diff_hunk_cb
, diff_line_cb
, &exp
));
710 cl_assert_equal_i(1, exp
.files
);
711 cl_assert_equal_i(1, exp
.file_status
[GIT_DELTA_MODIFIED
]);
712 cl_assert_equal_i(0, exp
.hunks
);
717 cl_assert(cl_toggle_filemode("issue_592/a.txt"));
720 void test_diff_workdir__filemode_changes_with_filemode_false(void)
722 git_diff
*diff
= NULL
;
725 if (!cl_is_chmod_supported())
728 g_repo
= cl_git_sandbox_init("issue_592");
730 cl_repo_set_bool(g_repo
, "core.filemode", false);
732 /* test once with no mods */
734 cl_git_pass(git_diff_index_to_workdir(&diff
, g_repo
, NULL
, NULL
));
736 memset(&exp
, 0, sizeof(exp
));
737 cl_git_pass(git_diff_foreach(
738 diff
, diff_file_cb
, diff_binary_cb
, diff_hunk_cb
, diff_line_cb
, &exp
));
740 cl_assert_equal_i(0, exp
.files
);
741 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_MODIFIED
]);
742 cl_assert_equal_i(0, exp
.hunks
);
746 /* chmod file and test again */
748 cl_assert(cl_toggle_filemode("issue_592/a.txt"));
750 cl_git_pass(git_diff_index_to_workdir(&diff
, g_repo
, NULL
, NULL
));
752 memset(&exp
, 0, sizeof(exp
));
753 cl_git_pass(git_diff_foreach(diff
,
754 diff_file_cb
, diff_binary_cb
, diff_hunk_cb
, diff_line_cb
, &exp
));
756 cl_assert_equal_i(0, exp
.files
);
757 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_MODIFIED
]);
758 cl_assert_equal_i(0, exp
.hunks
);
762 cl_assert(cl_toggle_filemode("issue_592/a.txt"));
765 void test_diff_workdir__head_index_and_workdir_all_differ(void)
767 git_diff_options opts
= GIT_DIFF_OPTIONS_INIT
;
768 git_diff
*diff_i2t
= NULL
, *diff_w2i
= NULL
;
770 char *pathspec
= "staged_changes_modified_file";
775 * - head->index diff has 1 line of context, 1 line of diff
776 * - index->workdir diff has 2 lines of context, 1 line of diff
778 * - head->workdir diff has 1 line of context, 2 lines of diff
779 * Let's make sure the right one is returned from each fn.
782 g_repo
= cl_git_sandbox_init("status");
784 tree
= resolve_commit_oid_to_tree(g_repo
, "26a125ee1bfc5df1e1b2e9441bbe63c8a7ae989f");
786 opts
.pathspec
.strings
= &pathspec
;
787 opts
.pathspec
.count
= 1;
789 cl_git_pass(git_diff_tree_to_index(&diff_i2t
, g_repo
, tree
, NULL
, &opts
));
790 cl_git_pass(git_diff_index_to_workdir(&diff_w2i
, g_repo
, NULL
, &opts
));
792 for (use_iterator
= 0; use_iterator
<= 1; use_iterator
++) {
793 memset(&exp
, 0, sizeof(exp
));
796 cl_git_pass(diff_foreach_via_iterator(
797 diff_i2t
, diff_file_cb
, diff_binary_cb
, diff_hunk_cb
, diff_line_cb
, &exp
));
799 cl_git_pass(git_diff_foreach(
800 diff_i2t
, diff_file_cb
, diff_binary_cb
, diff_hunk_cb
, diff_line_cb
, &exp
));
802 cl_assert_equal_i(1, exp
.files
);
803 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_ADDED
]);
804 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_DELETED
]);
805 cl_assert_equal_i(1, exp
.file_status
[GIT_DELTA_MODIFIED
]);
806 cl_assert_equal_i(1, exp
.hunks
);
807 cl_assert_equal_i(2, exp
.lines
);
808 cl_assert_equal_i(1, exp
.line_ctxt
);
809 cl_assert_equal_i(1, exp
.line_adds
);
810 cl_assert_equal_i(0, exp
.line_dels
);
813 for (use_iterator
= 0; use_iterator
<= 1; use_iterator
++) {
814 memset(&exp
, 0, sizeof(exp
));
817 cl_git_pass(diff_foreach_via_iterator(
818 diff_w2i
, diff_file_cb
, diff_binary_cb
, diff_hunk_cb
, diff_line_cb
, &exp
));
820 cl_git_pass(git_diff_foreach(
821 diff_w2i
, diff_file_cb
, diff_binary_cb
, diff_hunk_cb
, diff_line_cb
, &exp
));
823 cl_assert_equal_i(1, exp
.files
);
824 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_ADDED
]);
825 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_DELETED
]);
826 cl_assert_equal_i(1, exp
.file_status
[GIT_DELTA_MODIFIED
]);
827 cl_assert_equal_i(1, exp
.hunks
);
828 cl_assert_equal_i(3, exp
.lines
);
829 cl_assert_equal_i(2, exp
.line_ctxt
);
830 cl_assert_equal_i(1, exp
.line_adds
);
831 cl_assert_equal_i(0, exp
.line_dels
);
834 cl_git_pass(git_diff_merge(diff_i2t
, diff_w2i
));
836 for (use_iterator
= 0; use_iterator
<= 1; use_iterator
++) {
837 memset(&exp
, 0, sizeof(exp
));
840 cl_git_pass(diff_foreach_via_iterator(
841 diff_i2t
, diff_file_cb
, diff_binary_cb
, diff_hunk_cb
, diff_line_cb
, &exp
));
843 cl_git_pass(git_diff_foreach(
844 diff_i2t
, diff_file_cb
, diff_binary_cb
, diff_hunk_cb
, diff_line_cb
, &exp
));
846 cl_assert_equal_i(1, exp
.files
);
847 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_ADDED
]);
848 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_DELETED
]);
849 cl_assert_equal_i(1, exp
.file_status
[GIT_DELTA_MODIFIED
]);
850 cl_assert_equal_i(1, exp
.hunks
);
851 cl_assert_equal_i(3, exp
.lines
);
852 cl_assert_equal_i(1, exp
.line_ctxt
);
853 cl_assert_equal_i(2, exp
.line_adds
);
854 cl_assert_equal_i(0, exp
.line_dels
);
857 git_diff_free(diff_i2t
);
858 git_diff_free(diff_w2i
);
863 void test_diff_workdir__eof_newline_changes(void)
865 git_diff_options opts
= GIT_DIFF_OPTIONS_INIT
;
866 git_diff
*diff
= NULL
;
868 char *pathspec
= "current_file";
871 g_repo
= cl_git_sandbox_init("status");
873 opts
.pathspec
.strings
= &pathspec
;
874 opts
.pathspec
.count
= 1;
876 cl_git_pass(git_diff_index_to_workdir(&diff
, g_repo
, NULL
, &opts
));
878 for (use_iterator
= 0; use_iterator
<= 1; use_iterator
++) {
879 memset(&exp
, 0, sizeof(exp
));
882 cl_git_pass(diff_foreach_via_iterator(
883 diff
, diff_file_cb
, diff_binary_cb
, diff_hunk_cb
, diff_line_cb
, &exp
));
885 cl_git_pass(git_diff_foreach(
886 diff
, diff_file_cb
, diff_binary_cb
, diff_hunk_cb
, diff_line_cb
, &exp
));
888 cl_assert_equal_i(0, exp
.files
);
889 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_ADDED
]);
890 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_DELETED
]);
891 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_MODIFIED
]);
892 cl_assert_equal_i(0, exp
.hunks
);
893 cl_assert_equal_i(0, exp
.lines
);
894 cl_assert_equal_i(0, exp
.line_ctxt
);
895 cl_assert_equal_i(0, exp
.line_adds
);
896 cl_assert_equal_i(0, exp
.line_dels
);
901 cl_git_append2file("status/current_file", "\n");
903 cl_git_pass(git_diff_index_to_workdir(&diff
, g_repo
, NULL
, &opts
));
905 for (use_iterator
= 0; use_iterator
<= 1; use_iterator
++) {
906 memset(&exp
, 0, sizeof(exp
));
909 cl_git_pass(diff_foreach_via_iterator(
910 diff
, diff_file_cb
, diff_binary_cb
, diff_hunk_cb
, diff_line_cb
, &exp
));
912 cl_git_pass(git_diff_foreach(
913 diff
, diff_file_cb
, diff_binary_cb
, diff_hunk_cb
, diff_line_cb
, &exp
));
915 cl_assert_equal_i(1, exp
.files
);
916 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_ADDED
]);
917 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_DELETED
]);
918 cl_assert_equal_i(1, exp
.file_status
[GIT_DELTA_MODIFIED
]);
919 cl_assert_equal_i(1, exp
.hunks
);
920 cl_assert_equal_i(2, exp
.lines
);
921 cl_assert_equal_i(1, exp
.line_ctxt
);
922 cl_assert_equal_i(1, exp
.line_adds
);
923 cl_assert_equal_i(0, exp
.line_dels
);
928 cl_git_rewritefile("status/current_file", "current_file");
930 cl_git_pass(git_diff_index_to_workdir(&diff
, g_repo
, NULL
, &opts
));
932 for (use_iterator
= 0; use_iterator
<= 1; use_iterator
++) {
933 memset(&exp
, 0, sizeof(exp
));
936 cl_git_pass(diff_foreach_via_iterator(
937 diff
, diff_file_cb
, diff_binary_cb
, diff_hunk_cb
, diff_line_cb
, &exp
));
939 cl_git_pass(git_diff_foreach(
940 diff
, diff_file_cb
, diff_binary_cb
, diff_hunk_cb
, diff_line_cb
, &exp
));
942 cl_assert_equal_i(1, exp
.files
);
943 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_ADDED
]);
944 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_DELETED
]);
945 cl_assert_equal_i(1, exp
.file_status
[GIT_DELTA_MODIFIED
]);
946 cl_assert_equal_i(1, exp
.hunks
);
947 cl_assert_equal_i(3, exp
.lines
);
948 cl_assert_equal_i(0, exp
.line_ctxt
);
949 cl_assert_equal_i(1, exp
.line_adds
);
950 cl_assert_equal_i(2, exp
.line_dels
);
956 /* PREPARATION OF TEST DATA
958 * Since there is no command line equivalent of git_diff_tree_to_workdir,
959 * it was a bit of a pain to confirm that I was getting the expected
960 * results in the first part of this tests. Here is what I ended up
961 * doing to set my expectation for the file counts and results:
963 * Running "git ls-tree 26a125" and "git ls-tree aa27a6" shows:
965 * A a0de7e0ac200c489c41c59dfa910154a70264e6e current_file
966 * B 5452d32f1dd538eb0405e8a83cc185f79e25e80f file_deleted
967 * C 452e4244b5d083ddf0460acf1ecc74db9dcfa11a modified_file
968 * D 32504b727382542f9f089e24fddac5e78533e96c staged_changes
969 * E 061d42a44cacde5726057b67558821d95db96f19 staged_changes_file_deleted
970 * F 70bd9443ada07063e7fbf0b3ff5c13f7494d89c2 staged_changes_modified_file
971 * G e9b9107f290627c04d097733a10055af941f6bca staged_delete_file_deleted
972 * H dabc8af9bd6e9f5bbe96a176f1a24baf3d1f8916 staged_delete_modified_file
973 * I 53ace0d1cc1145a5f4fe4f78a186a60263190733 subdir/current_file
974 * J 1888c805345ba265b0ee9449b8877b6064592058 subdir/deleted_file
975 * K a6191982709b746d5650e93c2acf34ef74e11504 subdir/modified_file
976 * L e8ee89e15bbe9b20137715232387b3de5b28972e subdir.txt
980 * find . ! -path ./.git/\* -a -type f | git hash-object --stdin-paths
982 * A a0de7e0ac200c489c41c59dfa910154a70264e6e current_file
983 * M 6a79f808a9c6bc9531ac726c184bbcd9351ccf11 ignored_file
984 * C 0a539630525aca2e7bc84975958f92f10a64c9b6 modified_file
985 * N d4fa8600b4f37d7516bef4816ae2c64dbf029e3a new_file
986 * D 55d316c9ba708999f1918e9677d01dfcae69c6b9 staged_changes
987 * F 011c3440d5c596e21d836aa6d7b10eb581f68c49 staged_changes_modified_file
988 * H dabc8af9bd6e9f5bbe96a176f1a24baf3d1f8916 staged_delete_modified_file
989 * O 529a16e8e762d4acb7b9636ff540a00831f9155a staged_new_file
990 * P 8b090c06d14ffa09c4e880088ebad33893f921d1 staged_new_file_modified_file
991 * I 53ace0d1cc1145a5f4fe4f78a186a60263190733 subdir/current_file
992 * K 57274b75eeb5f36fd55527806d567b2240a20c57 subdir/modified_file
993 * Q 80a86a6931b91bc01c2dbf5ca55bdd24ad1ef466 subdir/new_file
994 * L e8ee89e15bbe9b20137715232387b3de5b28972e subdir.txt
998 * A - current_file (UNMODIFIED) -> not in results
1000 * M I ignored_file (IGNORED)
1002 * N U new_file (UNTRACKED)
1003 * D M staged_changes
1004 * E D staged_changes_file_deleted
1005 * F M staged_changes_modified_file
1006 * G D staged_delete_file_deleted
1007 * H - staged_delete_modified_file (UNMODIFIED) -> not in results
1008 * O U staged_new_file
1009 * P U staged_new_file_modified_file
1010 * I - subdir/current_file (UNMODIFIED) -> not in results
1011 * J D subdir/deleted_file
1012 * K M subdir/modified_file
1013 * Q U subdir/new_file
1014 * L - subdir.txt (UNMODIFIED) -> not in results
1016 * Expect 13 files, 0 ADD, 4 DEL, 4 MOD, 1 IGN, 4 UNTR
1020 void test_diff_workdir__larger_hunks(void)
1022 const char *a_commit
= "d70d245ed97ed2aa596dd1af6536e4bfdb047b69";
1023 const char *b_commit
= "7a9e0b02e63179929fed24f0a3e0f19168114d10";
1025 git_diff_options opts
= GIT_DIFF_OPTIONS_INIT
;
1026 size_t i
, d
, num_d
, h
, num_h
, l
, num_l
;
1028 g_repo
= cl_git_sandbox_init("diff");
1030 cl_assert((a
= resolve_commit_oid_to_tree(g_repo
, a_commit
)) != NULL
);
1031 cl_assert((b
= resolve_commit_oid_to_tree(g_repo
, b_commit
)) != NULL
);
1033 opts
.context_lines
= 1;
1034 opts
.interhunk_lines
= 0;
1036 for (i
= 0; i
<= 2; ++i
) {
1037 git_diff
*diff
= NULL
;
1039 const git_diff_hunk
*hunk
;
1040 const git_diff_line
*line
;
1042 /* okay, this is a bit silly, but oh well */
1045 cl_git_pass(git_diff_index_to_workdir(&diff
, g_repo
, NULL
, &opts
));
1048 cl_git_pass(git_diff_tree_to_workdir(&diff
, g_repo
, a
, &opts
));
1051 cl_git_pass(git_diff_tree_to_workdir(&diff
, g_repo
, b
, &opts
));
1055 num_d
= git_diff_num_deltas(diff
);
1056 cl_assert_equal_i(2, (int)num_d
);
1058 for (d
= 0; d
< num_d
; ++d
) {
1059 cl_git_pass(git_patch_from_diff(&patch
, diff
, d
));
1062 num_h
= git_patch_num_hunks(patch
);
1063 for (h
= 0; h
< num_h
; h
++) {
1064 cl_git_pass(git_patch_get_hunk(&hunk
, &num_l
, patch
, h
));
1066 for (l
= 0; l
< num_l
; ++l
) {
1068 git_patch_get_line_in_hunk(&line
, patch
, h
, l
));
1072 /* confirm fail after the last item */
1074 git_patch_get_line_in_hunk(&line
, patch
, h
, num_l
));
1077 /* confirm fail after the last item */
1078 cl_git_fail(git_patch_get_hunk(&hunk
, &num_l
, patch
, num_h
));
1080 git_patch_free(patch
);
1083 git_diff_free(diff
);
1090 /* Set up a test that exercises this code. The easiest test using existing
1091 * test data is probably to create a sandbox of submod2 and then run a
1092 * git_diff_tree_to_workdir against tree
1093 * 873585b94bdeabccea991ea5e3ec1a277895b698. As for what you should actually
1094 * test, you can start by just checking that the number of lines of diff
1095 * content matches the actual output of git diff. That will at least
1096 * demonstrate that the submodule content is being used to generate somewhat
1097 * comparable outputs. It is a test that would fail without this code and
1098 * will succeed with it.
1101 #include "../submodule/submodule_helpers.h"
1103 void test_diff_workdir__submodules(void)
1105 const char *a_commit
= "873585b94bdeabccea991ea5e3ec1a277895b698";
1107 git_diff_options opts
= GIT_DIFF_OPTIONS_INIT
;
1108 git_diff
*diff
= NULL
;
1111 g_repo
= setup_fixture_submod2();
1113 a
= resolve_commit_oid_to_tree(g_repo
, a_commit
);
1116 GIT_DIFF_INCLUDE_UNTRACKED
|
1117 GIT_DIFF_INCLUDE_IGNORED
|
1118 GIT_DIFF_RECURSE_UNTRACKED_DIRS
|
1119 GIT_DIFF_SHOW_UNTRACKED_CONTENT
;
1121 cl_git_pass(git_diff_tree_to_workdir(&diff
, g_repo
, a
, &opts
));
1123 /* diff_print(stderr, diff); */
1125 /* essentially doing: git diff 873585b94bdeabccea991ea5e3ec1a277895b698 */
1127 memset(&exp
, 0, sizeof(exp
));
1129 cl_git_pass(git_diff_foreach(
1130 diff
, diff_file_cb
, diff_binary_cb
, diff_hunk_cb
, diff_line_cb
, &exp
));
1132 /* so "git diff 873585" returns:
1134 * A just_a_dir/contents
1136 * A sm_added_and_uncommited
1139 * A sm_changed_index
1140 * A sm_changed_untracked_file
1141 * M sm_missing_commits
1143 * which is a little deceptive because of the difference between the
1144 * "git diff <treeish>" results from "git_diff_tree_to_workdir". The
1145 * only significant difference is that those Added items will show up
1146 * as Untracked items in the pure libgit2 diff.
1148 * Then add in the two extra untracked items "not" and "not-submodule"
1149 * to get the 12 files reported here.
1152 cl_assert_equal_i(12, exp
.files
);
1154 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_ADDED
]);
1155 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_DELETED
]);
1156 cl_assert_equal_i(2, exp
.file_status
[GIT_DELTA_MODIFIED
]);
1157 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_IGNORED
]);
1158 cl_assert_equal_i(10, exp
.file_status
[GIT_DELTA_UNTRACKED
]);
1160 /* the following numbers match "git diff 873585" exactly */
1162 cl_assert_equal_i(9, exp
.hunks
);
1164 cl_assert_equal_i(33, exp
.lines
);
1165 cl_assert_equal_i(2, exp
.line_ctxt
);
1166 cl_assert_equal_i(30, exp
.line_adds
);
1167 cl_assert_equal_i(1, exp
.line_dels
);
1169 git_diff_free(diff
);
1173 void test_diff_workdir__cannot_diff_against_a_bare_repository(void)
1175 git_diff_options opts
= GIT_DIFF_OPTIONS_INIT
;
1176 git_diff
*diff
= NULL
;
1179 g_repo
= cl_git_sandbox_init("testrepo.git");
1182 GIT_EBAREREPO
, git_diff_index_to_workdir(&diff
, g_repo
, NULL
, &opts
));
1184 cl_git_pass(git_repository_head_tree(&tree
, g_repo
));
1187 GIT_EBAREREPO
, git_diff_tree_to_workdir(&diff
, g_repo
, tree
, &opts
));
1189 git_tree_free(tree
);
1192 void test_diff_workdir__to_null_tree(void)
1196 git_diff_options opts
= GIT_DIFF_OPTIONS_INIT
;
1198 opts
.flags
= GIT_DIFF_INCLUDE_UNTRACKED
|
1199 GIT_DIFF_RECURSE_UNTRACKED_DIRS
;
1201 g_repo
= cl_git_sandbox_init("status");
1203 cl_git_pass(git_diff_tree_to_workdir(&diff
, g_repo
, NULL
, &opts
));
1205 memset(&exp
, 0, sizeof(exp
));
1207 cl_git_pass(git_diff_foreach(
1208 diff
, diff_file_cb
, diff_binary_cb
, diff_hunk_cb
, diff_line_cb
, &exp
));
1210 cl_assert_equal_i(exp
.files
, exp
.file_status
[GIT_DELTA_UNTRACKED
]);
1212 git_diff_free(diff
);
1215 void test_diff_workdir__checks_options_version(void)
1218 git_diff_options opts
= GIT_DIFF_OPTIONS_INIT
;
1219 const git_error
*err
;
1221 g_repo
= cl_git_sandbox_init("status");
1224 cl_git_fail(git_diff_tree_to_workdir(&diff
, g_repo
, NULL
, &opts
));
1225 err
= git_error_last();
1226 cl_assert_equal_i(GIT_ERROR_INVALID
, err
->klass
);
1229 opts
.version
= 1024;
1230 cl_git_fail(git_diff_tree_to_workdir(&diff
, g_repo
, NULL
, &opts
));
1231 err
= git_error_last();
1232 cl_assert_equal_i(GIT_ERROR_INVALID
, err
->klass
);
1235 void test_diff_workdir__can_diff_empty_file(void)
1239 git_diff_options opts
= GIT_DIFF_OPTIONS_INIT
;
1243 g_repo
= cl_git_sandbox_init("attr_index");
1245 tree
= resolve_commit_oid_to_tree(g_repo
, "3812cfef3661"); /* HEAD */
1247 /* baseline - make sure there are no outstanding diffs */
1249 cl_git_pass(git_diff_tree_to_workdir(&diff
, g_repo
, tree
, &opts
));
1250 cl_assert_equal_i(2, (int)git_diff_num_deltas(diff
));
1251 git_diff_free(diff
);
1253 /* empty contents of file */
1255 cl_git_rewritefile("attr_index/README.txt", "");
1256 cl_git_pass(git_fs_path_lstat("attr_index/README.txt", &st
));
1257 cl_assert_equal_i(0, (int)st
.st_size
);
1259 cl_git_pass(git_diff_tree_to_workdir(&diff
, g_repo
, tree
, &opts
));
1260 cl_assert_equal_i(3, (int)git_diff_num_deltas(diff
));
1261 /* diffs are: .gitattributes, README.txt, sub/sub/.gitattributes */
1262 cl_git_pass(git_patch_from_diff(&patch
, diff
, 1));
1263 git_patch_free(patch
);
1264 git_diff_free(diff
);
1266 /* remove a file altogether */
1268 cl_git_pass(p_unlink("attr_index/README.txt"));
1269 cl_assert(!git_fs_path_exists("attr_index/README.txt"));
1271 cl_git_pass(git_diff_tree_to_workdir(&diff
, g_repo
, tree
, &opts
));
1272 cl_assert_equal_i(3, (int)git_diff_num_deltas(diff
));
1273 cl_git_pass(git_patch_from_diff(&patch
, diff
, 1));
1274 git_patch_free(patch
);
1275 git_diff_free(diff
);
1277 git_tree_free(tree
);
1280 void test_diff_workdir__to_index_issue_1397(void)
1282 git_diff_options opts
= GIT_DIFF_OPTIONS_INIT
;
1283 git_diff
*diff
= NULL
;
1286 g_repo
= cl_git_sandbox_init("issue_1397");
1288 cl_repo_set_bool(g_repo
, "core.autocrlf", true);
1290 opts
.context_lines
= 3;
1291 opts
.interhunk_lines
= 1;
1293 cl_git_pass(git_diff_index_to_workdir(&diff
, g_repo
, NULL
, &opts
));
1295 memset(&exp
, 0, sizeof(exp
));
1296 cl_git_pass(git_diff_foreach(
1297 diff
, diff_file_cb
, diff_binary_cb
, diff_hunk_cb
, diff_line_cb
, &exp
));
1299 cl_assert_equal_i(0, exp
.files
);
1300 cl_assert_equal_i(0, exp
.hunks
);
1301 cl_assert_equal_i(0, exp
.lines
);
1303 git_diff_free(diff
);
1306 cl_git_rewritefile("issue_1397/crlf_file.txt",
1307 "first line\r\nsecond line modified\r\nboth with crlf");
1309 cl_git_pass(git_diff_index_to_workdir(&diff
, g_repo
, NULL
, &opts
));
1311 memset(&exp
, 0, sizeof(exp
));
1312 cl_git_pass(git_diff_foreach(
1313 diff
, diff_file_cb
, diff_binary_cb
, diff_hunk_cb
, diff_line_cb
, &exp
));
1315 cl_assert_equal_i(1, exp
.files
);
1316 cl_assert_equal_i(1, exp
.file_status
[GIT_DELTA_MODIFIED
]);
1318 cl_assert_equal_i(1, exp
.hunks
);
1320 cl_assert_equal_i(5, exp
.lines
);
1321 cl_assert_equal_i(3, exp
.line_ctxt
);
1322 cl_assert_equal_i(1, exp
.line_adds
);
1323 cl_assert_equal_i(1, exp
.line_dels
);
1325 git_diff_free(diff
);
1328 void test_diff_workdir__to_tree_issue_1397(void)
1330 const char *a_commit
= "7f483a738"; /* the current HEAD */
1332 git_diff_options opts
= GIT_DIFF_OPTIONS_INIT
;
1333 git_diff
*diff
= NULL
;
1334 git_diff
*diff2
= NULL
;
1337 g_repo
= cl_git_sandbox_init("issue_1397");
1339 cl_repo_set_bool(g_repo
, "core.autocrlf", true);
1341 a
= resolve_commit_oid_to_tree(g_repo
, a_commit
);
1343 opts
.context_lines
= 3;
1344 opts
.interhunk_lines
= 1;
1346 cl_git_pass(git_diff_tree_to_workdir(&diff
, g_repo
, a
, &opts
));
1348 memset(&exp
, 0, sizeof(exp
));
1349 cl_git_pass(git_diff_foreach(
1350 diff
, diff_file_cb
, diff_binary_cb
, diff_hunk_cb
, diff_line_cb
, &exp
));
1352 cl_assert_equal_i(0, exp
.files
);
1353 cl_assert_equal_i(0, exp
.hunks
);
1354 cl_assert_equal_i(0, exp
.lines
);
1356 git_diff_free(diff
);
1359 cl_git_pass(git_diff_tree_to_index(&diff
, g_repo
, a
, NULL
, &opts
));
1360 cl_git_pass(git_diff_index_to_workdir(&diff2
, g_repo
, NULL
, &opts
));
1361 cl_git_pass(git_diff_merge(diff
, diff2
));
1362 git_diff_free(diff2
);
1364 memset(&exp
, 0, sizeof(exp
));
1365 cl_git_pass(git_diff_foreach(
1366 diff
, diff_file_cb
, diff_binary_cb
, diff_hunk_cb
, diff_line_cb
, &exp
));
1368 cl_assert_equal_i(0, exp
.files
);
1369 cl_assert_equal_i(0, exp
.hunks
);
1370 cl_assert_equal_i(0, exp
.lines
);
1372 git_diff_free(diff
);
1376 void test_diff_workdir__untracked_directory_scenarios(void)
1378 git_diff_options opts
= GIT_DIFF_OPTIONS_INIT
;
1379 git_diff
*diff
= NULL
;
1381 char *pathspec
= NULL
;
1382 static const char *files0
[] = {
1383 "subdir/deleted_file",
1384 "subdir/modified_file",
1388 static const char *files1
[] = {
1389 "subdir/deleted_file",
1390 "subdir/directory/",
1391 "subdir/modified_file",
1395 static const char *files2
[] = {
1396 "subdir/deleted_file",
1397 "subdir/directory/more/notignored",
1398 "subdir/modified_file",
1403 g_repo
= cl_git_sandbox_init("status");
1404 cl_git_mkfile("status/.gitignore", "ignored\n");
1406 opts
.context_lines
= 3;
1407 opts
.interhunk_lines
= 1;
1408 opts
.flags
|= GIT_DIFF_INCLUDE_IGNORED
| GIT_DIFF_INCLUDE_UNTRACKED
;
1409 opts
.pathspec
.strings
= &pathspec
;
1410 opts
.pathspec
.count
= 1;
1411 pathspec
= "subdir";
1413 /* baseline for "subdir" pathspec */
1415 memset(&exp
, 0, sizeof(exp
));
1418 cl_git_pass(git_diff_index_to_workdir(&diff
, g_repo
, NULL
, &opts
));
1420 cl_git_pass(git_diff_foreach(diff
, diff_file_cb
, NULL
, NULL
, NULL
, &exp
));
1422 cl_assert_equal_i(3, exp
.files
);
1423 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_ADDED
]);
1424 cl_assert_equal_i(1, exp
.file_status
[GIT_DELTA_DELETED
]);
1425 cl_assert_equal_i(1, exp
.file_status
[GIT_DELTA_MODIFIED
]);
1426 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_IGNORED
]);
1427 cl_assert_equal_i(1, exp
.file_status
[GIT_DELTA_UNTRACKED
]);
1429 git_diff_free(diff
);
1431 /* empty directory */
1433 cl_git_pass(p_mkdir("status/subdir/directory", 0777));
1435 memset(&exp
, 0, sizeof(exp
));
1438 cl_git_pass(git_diff_index_to_workdir(&diff
, g_repo
, NULL
, &opts
));
1440 cl_git_pass(git_diff_foreach(diff
, diff_file_cb
, NULL
, NULL
, NULL
, &exp
));
1442 cl_assert_equal_i(4, exp
.files
);
1443 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_ADDED
]);
1444 cl_assert_equal_i(1, exp
.file_status
[GIT_DELTA_DELETED
]);
1445 cl_assert_equal_i(1, exp
.file_status
[GIT_DELTA_MODIFIED
]);
1446 cl_assert_equal_i(1, exp
.file_status
[GIT_DELTA_IGNORED
]);
1447 cl_assert_equal_i(1, exp
.file_status
[GIT_DELTA_UNTRACKED
]);
1449 git_diff_free(diff
);
1451 /* empty directory in empty directory */
1453 cl_git_pass(p_mkdir("status/subdir/directory/empty", 0777));
1455 memset(&exp
, 0, sizeof(exp
));
1458 cl_git_pass(git_diff_index_to_workdir(&diff
, g_repo
, NULL
, &opts
));
1460 cl_git_pass(git_diff_foreach(diff
, diff_file_cb
, NULL
, NULL
, NULL
, &exp
));
1462 cl_assert_equal_i(4, exp
.files
);
1463 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_ADDED
]);
1464 cl_assert_equal_i(1, exp
.file_status
[GIT_DELTA_DELETED
]);
1465 cl_assert_equal_i(1, exp
.file_status
[GIT_DELTA_MODIFIED
]);
1466 cl_assert_equal_i(1, exp
.file_status
[GIT_DELTA_IGNORED
]);
1467 cl_assert_equal_i(1, exp
.file_status
[GIT_DELTA_UNTRACKED
]);
1469 git_diff_free(diff
);
1471 /* directory with only ignored files */
1473 cl_git_pass(p_mkdir("status/subdir/directory/deeper", 0777));
1474 cl_git_mkfile("status/subdir/directory/deeper/ignored", "ignore me\n");
1476 cl_git_pass(p_mkdir("status/subdir/directory/another", 0777));
1477 cl_git_mkfile("status/subdir/directory/another/ignored", "ignore me\n");
1479 memset(&exp
, 0, sizeof(exp
));
1482 cl_git_pass(git_diff_index_to_workdir(&diff
, g_repo
, NULL
, &opts
));
1484 cl_git_pass(git_diff_foreach(diff
, diff_file_cb
, NULL
, NULL
, NULL
, &exp
));
1486 cl_assert_equal_i(4, exp
.files
);
1487 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_ADDED
]);
1488 cl_assert_equal_i(1, exp
.file_status
[GIT_DELTA_DELETED
]);
1489 cl_assert_equal_i(1, exp
.file_status
[GIT_DELTA_MODIFIED
]);
1490 cl_assert_equal_i(1, exp
.file_status
[GIT_DELTA_IGNORED
]);
1491 cl_assert_equal_i(1, exp
.file_status
[GIT_DELTA_UNTRACKED
]);
1493 git_diff_free(diff
);
1495 /* directory with ignored directory (contents irrelevant) */
1497 cl_git_pass(p_mkdir("status/subdir/directory/more", 0777));
1498 cl_git_pass(p_mkdir("status/subdir/directory/more/ignored", 0777));
1499 cl_git_mkfile("status/subdir/directory/more/ignored/notignored",
1500 "inside ignored dir\n");
1502 memset(&exp
, 0, sizeof(exp
));
1505 cl_git_pass(git_diff_index_to_workdir(&diff
, g_repo
, NULL
, &opts
));
1507 cl_git_pass(git_diff_foreach(diff
, diff_file_cb
, NULL
, NULL
, NULL
, &exp
));
1509 cl_assert_equal_i(4, exp
.files
);
1510 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_ADDED
]);
1511 cl_assert_equal_i(1, exp
.file_status
[GIT_DELTA_DELETED
]);
1512 cl_assert_equal_i(1, exp
.file_status
[GIT_DELTA_MODIFIED
]);
1513 cl_assert_equal_i(1, exp
.file_status
[GIT_DELTA_IGNORED
]);
1514 cl_assert_equal_i(1, exp
.file_status
[GIT_DELTA_UNTRACKED
]);
1516 git_diff_free(diff
);
1518 /* quick version avoids directory scan */
1520 opts
.flags
= opts
.flags
| GIT_DIFF_ENABLE_FAST_UNTRACKED_DIRS
;
1522 memset(&exp
, 0, sizeof(exp
));
1525 cl_git_pass(git_diff_index_to_workdir(&diff
, g_repo
, NULL
, &opts
));
1527 cl_git_pass(git_diff_foreach(diff
, diff_file_cb
, NULL
, NULL
, NULL
, &exp
));
1529 cl_assert_equal_i(4, exp
.files
);
1530 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_ADDED
]);
1531 cl_assert_equal_i(1, exp
.file_status
[GIT_DELTA_DELETED
]);
1532 cl_assert_equal_i(1, exp
.file_status
[GIT_DELTA_MODIFIED
]);
1533 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_IGNORED
]);
1534 cl_assert_equal_i(2, exp
.file_status
[GIT_DELTA_UNTRACKED
]);
1536 git_diff_free(diff
);
1538 /* directory with nested non-ignored content */
1540 opts
.flags
= opts
.flags
& ~GIT_DIFF_ENABLE_FAST_UNTRACKED_DIRS
;
1542 cl_git_mkfile("status/subdir/directory/more/notignored",
1543 "not ignored deep under untracked\n");
1545 memset(&exp
, 0, sizeof(exp
));
1548 cl_git_pass(git_diff_index_to_workdir(&diff
, g_repo
, NULL
, &opts
));
1550 cl_git_pass(git_diff_foreach(diff
, diff_file_cb
, NULL
, NULL
, NULL
, &exp
));
1552 cl_assert_equal_i(4, exp
.files
);
1553 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_ADDED
]);
1554 cl_assert_equal_i(1, exp
.file_status
[GIT_DELTA_DELETED
]);
1555 cl_assert_equal_i(1, exp
.file_status
[GIT_DELTA_MODIFIED
]);
1556 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_IGNORED
]);
1557 cl_assert_equal_i(2, exp
.file_status
[GIT_DELTA_UNTRACKED
]);
1559 git_diff_free(diff
);
1561 /* use RECURSE_UNTRACKED_DIRS to get actual untracked files (no ignores) */
1563 opts
.flags
= opts
.flags
& ~GIT_DIFF_INCLUDE_IGNORED
;
1564 opts
.flags
= opts
.flags
| GIT_DIFF_RECURSE_UNTRACKED_DIRS
;
1566 memset(&exp
, 0, sizeof(exp
));
1569 cl_git_pass(git_diff_index_to_workdir(&diff
, g_repo
, NULL
, &opts
));
1571 cl_git_pass(git_diff_foreach(diff
, diff_file_cb
, NULL
, NULL
, NULL
, &exp
));
1573 cl_assert_equal_i(4, exp
.files
);
1574 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_ADDED
]);
1575 cl_assert_equal_i(1, exp
.file_status
[GIT_DELTA_DELETED
]);
1576 cl_assert_equal_i(1, exp
.file_status
[GIT_DELTA_MODIFIED
]);
1577 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_IGNORED
]);
1578 cl_assert_equal_i(2, exp
.file_status
[GIT_DELTA_UNTRACKED
]);
1580 git_diff_free(diff
);
1584 void test_diff_workdir__untracked_directory_comes_last(void)
1586 git_diff_options opts
= GIT_DIFF_OPTIONS_INIT
;
1587 git_diff
*diff
= NULL
;
1589 g_repo
= cl_git_sandbox_init("renames");
1591 cl_git_mkfile("renames/.gitignore", "*.ign\n");
1592 cl_git_pass(p_mkdir("renames/zzz_untracked", 0777));
1593 cl_git_mkfile("renames/zzz_untracked/an.ign", "ignore me please");
1594 cl_git_mkfile("renames/zzz_untracked/skip.ign", "ignore me really");
1595 cl_git_mkfile("renames/zzz_untracked/test.ign", "ignore me now");
1597 opts
.context_lines
= 3;
1598 opts
.interhunk_lines
= 1;
1599 opts
.flags
|= GIT_DIFF_INCLUDE_IGNORED
| GIT_DIFF_INCLUDE_UNTRACKED
;
1601 cl_git_pass(git_diff_index_to_workdir(&diff
, g_repo
, NULL
, &opts
));
1603 cl_assert(diff
!= NULL
);
1605 git_diff_free(diff
);
1608 void test_diff_workdir__untracked_with_bom(void)
1610 git_diff_options opts
= GIT_DIFF_OPTIONS_INIT
;
1611 git_diff
*diff
= NULL
;
1612 const git_diff_delta
*delta
;
1614 g_repo
= cl_git_sandbox_init("empty_standard_repo");
1615 cl_repo_set_bool(g_repo
, "core.autocrlf", true);
1617 cl_git_write2file("empty_standard_repo/bom.txt",
1618 "\xFF\xFE\x31\x00\x32\x00\x33\x00\x34\x00", 10, O_WRONLY
|O_CREAT
, 0664);
1621 GIT_DIFF_INCLUDE_UNTRACKED
| GIT_DIFF_SHOW_UNTRACKED_CONTENT
;
1623 cl_git_pass(git_diff_index_to_workdir(&diff
, g_repo
, NULL
, &opts
));
1625 cl_assert_equal_i(1, git_diff_num_deltas(diff
));
1626 cl_assert((delta
= git_diff_get_delta(diff
, 0)) != NULL
);
1627 cl_assert_equal_i(GIT_DELTA_UNTRACKED
, delta
->status
);
1629 /* not known at this point
1630 * cl_assert((delta->flags & GIT_DIFF_FLAG_BINARY) != 0);
1633 git_diff_free(diff
);
1636 void test_diff_workdir__patience_diff(void)
1639 git_diff_options opts
= GIT_DIFF_OPTIONS_INIT
;
1640 git_diff
*diff
= NULL
;
1641 git_patch
*patch
= NULL
;
1642 git_buf buf
= GIT_BUF_INIT
;
1643 const char *expected_normal
= "diff --git a/test.txt b/test.txt\nindex 34a5acc..d52725f 100644\n--- a/test.txt\n+++ b/test.txt\n@@ -1,10 +1,7 @@\n When I wrote this\n I did not know\n-how to create\n-a patience diff\n I did not know\n how to create\n+a patience diff\n another problem\n-I did not know\n-how to create\n a minimal diff\n";
1644 const char *expected_patience
= "diff --git a/test.txt b/test.txt\nindex 34a5acc..d52725f 100644\n--- a/test.txt\n+++ b/test.txt\n@@ -1,10 +1,7 @@\n When I wrote this\n I did not know\n+I did not know\n how to create\n a patience diff\n-I did not know\n-how to create\n another problem\n-I did not know\n-how to create\n a minimal diff\n";
1646 g_repo
= cl_git_sandbox_init("empty_standard_repo");
1647 cl_repo_set_bool(g_repo
, "core.autocrlf", true);
1648 cl_git_pass(git_repository_index(&index
, g_repo
));
1651 "empty_standard_repo/test.txt",
1652 "When I wrote this\nI did not know\nhow to create\na patience diff\nI did not know\nhow to create\nanother problem\nI did not know\nhow to create\na minimal diff\n");
1653 cl_git_pass(git_index_add_bypath(index
, "test.txt"));
1654 cl_repo_commit_from_index(NULL
, g_repo
, NULL
, 1372350000, "Base");
1655 git_index_free(index
);
1658 "empty_standard_repo/test.txt",
1659 "When I wrote this\nI did not know\nI did not know\nhow to create\na patience diff\nanother problem\na minimal diff\n");
1661 cl_git_pass(git_diff_index_to_workdir(&diff
, g_repo
, NULL
, &opts
));
1662 cl_assert_equal_i(1, git_diff_num_deltas(diff
));
1663 cl_git_pass(git_patch_from_diff(&patch
, diff
, 0));
1664 cl_git_pass(git_patch_to_buf(&buf
, patch
));
1666 cl_assert_equal_s(expected_normal
, buf
.ptr
);
1667 git_buf_dispose(&buf
);
1668 git_patch_free(patch
);
1669 git_diff_free(diff
);
1671 opts
.flags
|= GIT_DIFF_PATIENCE
;
1673 cl_git_pass(git_diff_index_to_workdir(&diff
, g_repo
, NULL
, &opts
));
1674 cl_assert_equal_i(1, git_diff_num_deltas(diff
));
1675 cl_git_pass(git_patch_from_diff(&patch
, diff
, 0));
1676 cl_git_pass(git_patch_to_buf(&buf
, patch
));
1678 cl_assert_equal_s(expected_patience
, buf
.ptr
);
1679 git_buf_dispose(&buf
);
1681 git_patch_free(patch
);
1682 git_diff_free(diff
);
1685 void test_diff_workdir__with_stale_index(void)
1687 git_diff_options opts
= GIT_DIFF_OPTIONS_INIT
;
1688 git_diff
*diff
= NULL
;
1689 git_index
*idx
= NULL
;
1692 g_repo
= cl_git_sandbox_init("status");
1693 cl_git_pass(git_repository_index(&idx
, g_repo
));
1695 /* make the in-memory index invalid */
1699 cl_git_pass(git_repository_open(&r2
, "status"));
1700 cl_git_pass(git_repository_index(&idx2
, r2
));
1701 cl_git_pass(git_index_add_bypath(idx2
, "new_file"));
1702 cl_git_pass(git_index_add_bypath(idx2
, "subdir/new_file"));
1703 cl_git_pass(git_index_remove_bypath(idx2
, "staged_new_file"));
1704 cl_git_pass(git_index_remove_bypath(idx2
, "staged_changes_file_deleted"));
1705 cl_git_pass(git_index_write(idx2
));
1706 git_index_free(idx2
);
1707 git_repository_free(r2
);
1710 opts
.context_lines
= 3;
1711 opts
.interhunk_lines
= 1;
1712 opts
.flags
|= GIT_DIFF_INCLUDE_UNTRACKED
| GIT_DIFF_INCLUDE_UNMODIFIED
;
1714 /* first try with index pointer which should prevent reload */
1716 cl_git_pass(git_diff_index_to_workdir(&diff
, g_repo
, idx
, &opts
));
1718 memset(&exp
, 0, sizeof(exp
));
1720 cl_git_pass(git_diff_foreach(
1721 diff
, diff_file_cb
, diff_binary_cb
, diff_hunk_cb
, diff_line_cb
, &exp
));
1723 cl_assert_equal_i(17, exp
.files
);
1724 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_ADDED
]);
1725 cl_assert_equal_i(4, exp
.file_status
[GIT_DELTA_DELETED
]);
1726 cl_assert_equal_i(4, exp
.file_status
[GIT_DELTA_MODIFIED
]);
1727 cl_assert_equal_i(4, exp
.file_status
[GIT_DELTA_UNTRACKED
]);
1728 cl_assert_equal_i(5, exp
.file_status
[GIT_DELTA_UNMODIFIED
]);
1730 git_diff_free(diff
);
1732 /* now let's try without the index pointer which should trigger reload */
1734 /* two files that were UNTRACKED should have become UNMODIFIED */
1735 /* one file that was UNMODIFIED should now have become UNTRACKED */
1736 /* one file that was DELETED should now be gone completely */
1738 cl_git_pass(git_diff_index_to_workdir(&diff
, g_repo
, NULL
, &opts
));
1740 memset(&exp
, 0, sizeof(exp
));
1742 cl_git_pass(git_diff_foreach(
1743 diff
, diff_file_cb
, diff_binary_cb
, diff_hunk_cb
, diff_line_cb
, &exp
));
1745 git_diff_free(diff
);
1747 cl_assert_equal_i(16, exp
.files
);
1748 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_ADDED
]);
1749 cl_assert_equal_i(3, exp
.file_status
[GIT_DELTA_DELETED
]);
1750 cl_assert_equal_i(4, exp
.file_status
[GIT_DELTA_MODIFIED
]);
1751 cl_assert_equal_i(3, exp
.file_status
[GIT_DELTA_UNTRACKED
]);
1752 cl_assert_equal_i(6, exp
.file_status
[GIT_DELTA_UNMODIFIED
]);
1754 git_index_free(idx
);
1757 static int touch_file(void *payload
, git_str
*path
)
1760 struct p_timeval times
[2];
1762 GIT_UNUSED(payload
);
1763 if (git_fs_path_isdir(path
->ptr
))
1766 cl_must_pass(p_stat(path
->ptr
, &st
));
1768 times
[0].tv_sec
= st
.st_mtime
+ 3;
1769 times
[0].tv_usec
= 0;
1770 times
[1].tv_sec
= st
.st_mtime
+ 3;
1771 times
[1].tv_usec
= 0;
1773 cl_must_pass(p_utimes(path
->ptr
, times
));
1777 static void basic_diff_status(git_diff
**out
, const git_diff_options
*opts
)
1781 cl_git_pass(git_diff_index_to_workdir(out
, g_repo
, NULL
, opts
));
1783 memset(&exp
, 0, sizeof(exp
));
1785 cl_git_pass(git_diff_foreach(
1786 *out
, diff_file_cb
, diff_binary_cb
, diff_hunk_cb
, diff_line_cb
, &exp
));
1788 cl_assert_equal_i(13, exp
.files
);
1789 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_ADDED
]);
1790 cl_assert_equal_i(4, exp
.file_status
[GIT_DELTA_DELETED
]);
1791 cl_assert_equal_i(4, exp
.file_status
[GIT_DELTA_MODIFIED
]);
1792 cl_assert_equal_i(1, exp
.file_status
[GIT_DELTA_IGNORED
]);
1793 cl_assert_equal_i(4, exp
.file_status
[GIT_DELTA_UNTRACKED
]);
1796 void test_diff_workdir__can_update_index(void)
1798 git_diff_options opts
= GIT_DIFF_OPTIONS_INIT
;
1799 git_diff
*diff
= NULL
;
1800 git_diff_perfdata perf
= GIT_DIFF_PERFDATA_INIT
;
1803 g_repo
= cl_git_sandbox_init("status");
1805 /* touch all the files so stat times are different */
1807 git_str path
= GIT_STR_INIT
;
1808 cl_git_pass(git_str_sets(&path
, "status"));
1809 cl_git_pass(git_fs_path_direach(&path
, 0, touch_file
, NULL
));
1810 git_str_dispose(&path
);
1813 opts
.flags
|= GIT_DIFF_INCLUDE_IGNORED
| GIT_DIFF_INCLUDE_UNTRACKED
;
1815 basic_diff_status(&diff
, &opts
);
1817 cl_git_pass(git_diff_get_perfdata(&perf
, diff
));
1818 cl_assert_equal_sz(13 + 3, perf
.stat_calls
);
1819 cl_assert_equal_sz(5, perf
.oid_calculations
);
1821 git_diff_free(diff
);
1823 /* now allow diff to update stat cache */
1824 opts
.flags
|= GIT_DIFF_UPDATE_INDEX
;
1826 /* advance a tick for the index so we don't re-calculate racily-clean entries */
1827 cl_git_pass(git_repository_index__weakptr(&index
, g_repo
));
1830 basic_diff_status(&diff
, &opts
);
1832 cl_git_pass(git_diff_get_perfdata(&perf
, diff
));
1833 cl_assert_equal_sz(13 + 3, perf
.stat_calls
);
1834 cl_assert_equal_sz(5, perf
.oid_calculations
);
1836 git_diff_free(diff
);
1838 /* now if we do it again, we should see fewer OID calculations */
1840 /* tick again as the index updating from the previous diff might have reset the timestamp */
1842 basic_diff_status(&diff
, &opts
);
1844 cl_git_pass(git_diff_get_perfdata(&perf
, diff
));
1845 cl_assert_equal_sz(13 + 3, perf
.stat_calls
);
1846 cl_assert_equal_sz(0, perf
.oid_calculations
);
1848 git_diff_free(diff
);
1851 #define STR7 "0123456"
1852 #define STR8 "01234567"
1853 #define STR40 STR8 STR8 STR8 STR8 STR8
1854 #define STR200 STR40 STR40 STR40 STR40 STR40
1855 #define STR999Z STR200 STR200 STR200 STR200 STR40 STR40 STR40 STR40 \
1856 STR8 STR8 STR8 STR8 STR7 "\0"
1857 #define STR1000 STR200 STR200 STR200 STR200 STR200
1858 #define STR3999Z STR1000 STR1000 STR1000 STR999Z
1859 #define STR4000 STR1000 STR1000 STR1000 STR1000
1861 static void assert_delta_binary(git_diff
*diff
, size_t idx
, int is_binary
)
1864 const git_diff_delta
*delta
;
1866 cl_git_pass(git_patch_from_diff(&patch
, diff
, idx
));
1867 delta
= git_patch_get_delta(patch
);
1868 cl_assert_equal_b((delta
->flags
& GIT_DIFF_FLAG_BINARY
), is_binary
);
1869 git_patch_free(patch
);
1872 void test_diff_workdir__binary_detection(void)
1875 git_diff
*diff
= NULL
;
1876 git_str b
= GIT_STR_INIT
;
1878 git_str data
[10] = {
1879 { "1234567890", 0, 10 }, /* 0 - all ascii text control */
1880 { "\xC3\x85\xC3\xBC\xE2\x80\xA0\x48\xC3\xB8\xCF\x80\xCE\xA9", 0, 14 }, /* 1 - UTF-8 multibyte text */
1881 { "\xEF\xBB\xBF\xC3\x9C\xE2\xA4\x92\xC6\x92\x38\xC2\xA3\xE2\x82\xAC", 0, 16 }, /* 2 - UTF-8 with BOM */
1882 { STR999Z
, 0, 1000 }, /* 3 - ASCII with NUL at 1000 */
1883 { STR3999Z
, 0, 4000 }, /* 4 - ASCII with NUL at 4000 */
1884 { STR4000 STR3999Z
"x", 0, 8001 }, /* 5 - ASCII with NUL at 8000 */
1885 { STR4000 STR4000
"\0", 0, 8001 }, /* 6 - ASCII with NUL at 8001 */
1886 { "\x00\xDC\x00\x6E\x21\x39\xFE\x0E\x00\x63\x00\xF8"
1887 "\x00\x64\x00\x65\x20\x48", 0, 18 }, /* 7 - UTF-16 text */
1888 { "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d"
1889 "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d",
1890 0, 26 }, /* 8 - All non-printable characters (no NUL) */
1891 { "Hello \x01\x02\x03\x04\x05\x06 World!\x01\x02\x03\x04"
1892 "\x05\x06\x07", 0, 26 }, /* 9 - 50-50 non-printable (no NUL) */
1895 g_repo
= cl_git_sandbox_init("empty_standard_repo");
1896 cl_git_pass(git_repository_index(&idx
, g_repo
));
1898 /* We start with ASCII in index and test data in workdir,
1899 * then we will try with test data in index and ASCII in workdir.
1902 cl_git_pass(git_str_sets(&b
, "empty_standard_repo/0"));
1903 for (i
= 0; i
< 10; ++i
) {
1904 b
.ptr
[b
.size
- 1] = '0' + i
;
1905 cl_git_mkfile(b
.ptr
, "baseline");
1906 cl_git_pass(git_index_add_bypath(idx
, &b
.ptr
[b
.size
- 1]));
1908 if (data
[i
].size
== 0)
1909 data
[i
].size
= strlen(data
[i
].ptr
);
1911 b
.ptr
, data
[i
].ptr
, data
[i
].size
, O_WRONLY
|O_TRUNC
, 0664);
1913 cl_git_pass(git_index_write(idx
));
1915 cl_git_pass(git_diff_index_to_workdir(&diff
, g_repo
, NULL
, NULL
));
1917 cl_assert_equal_i(10, git_diff_num_deltas(diff
));
1919 /* using diff binary detection (i.e. looking for NUL byte) */
1920 assert_delta_binary(diff
, 0, false);
1921 assert_delta_binary(diff
, 1, false);
1922 assert_delta_binary(diff
, 2, false);
1923 assert_delta_binary(diff
, 3, true);
1924 assert_delta_binary(diff
, 4, true);
1925 assert_delta_binary(diff
, 5, true);
1926 assert_delta_binary(diff
, 6, false);
1927 assert_delta_binary(diff
, 7, true);
1928 assert_delta_binary(diff
, 8, false);
1929 assert_delta_binary(diff
, 9, false);
1930 /* The above have been checked to match command-line Git */
1932 git_diff_free(diff
);
1934 cl_git_pass(git_str_sets(&b
, "empty_standard_repo/0"));
1935 for (i
= 0; i
< 10; ++i
) {
1936 b
.ptr
[b
.size
- 1] = '0' + i
;
1937 cl_git_pass(git_index_add_bypath(idx
, &b
.ptr
[b
.size
- 1]));
1939 cl_git_write2file(b
.ptr
, "baseline\n", 9, O_WRONLY
|O_TRUNC
, 0664);
1941 cl_git_pass(git_index_write(idx
));
1943 cl_git_pass(git_diff_index_to_workdir(&diff
, g_repo
, NULL
, NULL
));
1945 cl_assert_equal_i(10, git_diff_num_deltas(diff
));
1947 /* using diff binary detection (i.e. looking for NUL byte) */
1948 assert_delta_binary(diff
, 0, false);
1949 assert_delta_binary(diff
, 1, false);
1950 assert_delta_binary(diff
, 2, false);
1951 assert_delta_binary(diff
, 3, true);
1952 assert_delta_binary(diff
, 4, true);
1953 assert_delta_binary(diff
, 5, true);
1954 assert_delta_binary(diff
, 6, false);
1955 assert_delta_binary(diff
, 7, true);
1956 assert_delta_binary(diff
, 8, false);
1957 assert_delta_binary(diff
, 9, false);
1959 git_diff_free(diff
);
1961 git_index_free(idx
);
1962 git_str_dispose(&b
);
1965 void test_diff_workdir__to_index_conflicted(void) {
1966 const char *a_commit
= "26a125ee1bf"; /* the current HEAD */
1967 git_index_entry ancestor
= {{0}}, ours
= {{0}}, theirs
= {{0}};
1970 git_diff
*diff1
, *diff2
;
1971 const git_diff_delta
*delta
;
1973 g_repo
= cl_git_sandbox_init("status");
1974 a
= resolve_commit_oid_to_tree(g_repo
, a_commit
);
1976 cl_git_pass(git_repository_index(&index
, g_repo
));
1978 ancestor
.path
= ours
.path
= theirs
.path
= "_file";
1979 ancestor
.mode
= ours
.mode
= theirs
.mode
= 0100644;
1980 git_oid_fromstr(&ancestor
.id
, "d427e0b2e138501a3d15cc376077a3631e15bd46");
1981 git_oid_fromstr(&ours
.id
, "ee3fa1b8c00aff7fe02065fdb50864bb0d932ccf");
1982 git_oid_fromstr(&theirs
.id
, "2bd0a343aeef7a2cf0d158478966a6e587ff3863");
1983 cl_git_pass(git_index_conflict_add(index
, &ancestor
, &ours
, &theirs
));
1985 cl_git_pass(git_diff_tree_to_index(&diff1
, g_repo
, a
, index
, NULL
));
1986 cl_git_pass(git_diff_index_to_workdir(&diff2
, g_repo
, index
, NULL
));
1987 cl_git_pass(git_diff_merge(diff1
, diff2
));
1989 cl_assert_equal_i(git_diff_num_deltas(diff1
), 12);
1990 delta
= git_diff_get_delta(diff1
, 0);
1991 cl_assert_equal_s(delta
->old_file
.path
, "_file");
1992 cl_assert_equal_i(delta
->nfiles
, 1);
1993 cl_assert_equal_i(delta
->status
, GIT_DELTA_CONFLICTED
);
1995 git_diff_free(diff2
);
1996 git_diff_free(diff1
);
1997 git_index_free(index
);
2001 void test_diff_workdir__only_writes_index_when_necessary(void)
2004 git_diff_options opts
= GIT_DIFF_OPTIONS_INIT
;
2005 git_diff
*diff
= NULL
;
2006 git_reference
*head
;
2007 git_object
*head_object
;
2008 unsigned char initial
[GIT_HASH_SHA1_SIZE
],
2009 first
[GIT_HASH_SHA1_SIZE
],
2010 second
[GIT_HASH_SHA1_SIZE
];
2011 git_str path
= GIT_STR_INIT
;
2013 struct p_timeval times
[2];
2015 opts
.flags
|= GIT_DIFF_INCLUDE_UNTRACKED
| GIT_DIFF_UPDATE_INDEX
;
2017 g_repo
= cl_git_sandbox_init("status");
2019 cl_git_pass(git_repository_index(&index
, g_repo
));
2020 cl_git_pass(git_repository_head(&head
, g_repo
));
2021 cl_git_pass(git_reference_peel(&head_object
, head
, GIT_OBJECT_COMMIT
));
2023 cl_git_pass(git_reset(g_repo
, head_object
, GIT_RESET_HARD
, NULL
));
2025 memcpy(initial
, git_index__checksum(index
), GIT_HASH_SHA1_SIZE
);
2027 /* update the index timestamp to avoid raciness */
2028 cl_must_pass(p_stat("status/.git/index", &st
));
2030 times
[0].tv_sec
= st
.st_mtime
+ 5;
2031 times
[0].tv_usec
= 0;
2032 times
[1].tv_sec
= st
.st_mtime
+ 5;
2033 times
[1].tv_usec
= 0;
2035 cl_must_pass(p_utimes("status/.git/index", times
));
2037 /* ensure diff doesn't touch the index */
2038 cl_git_pass(git_diff_index_to_workdir(&diff
, g_repo
, NULL
, &opts
));
2039 git_diff_free(diff
);
2041 memcpy(first
, git_index__checksum(index
), GIT_HASH_SHA1_SIZE
);
2042 cl_assert(memcmp(initial
, first
, GIT_HASH_SHA1_SIZE
) != 0);
2044 /* touch all the files so stat times are different */
2045 cl_git_pass(git_str_sets(&path
, "status"));
2046 cl_git_pass(git_fs_path_direach(&path
, 0, touch_file
, NULL
));
2048 cl_git_pass(git_diff_index_to_workdir(&diff
, g_repo
, NULL
, &opts
));
2049 git_diff_free(diff
);
2051 /* ensure the second diff did update the index */
2052 memcpy(second
, git_index__checksum(index
), GIT_HASH_SHA1_SIZE
);
2053 cl_assert(memcmp(first
, second
, GIT_HASH_SHA1_SIZE
) != 0);
2055 git_str_dispose(&path
);
2056 git_object_free(head_object
);
2057 git_reference_free(head
);
2058 git_index_free(index
);
2061 void test_diff_workdir__to_index_pathlist(void)
2065 git_diff_options opts
= GIT_DIFF_OPTIONS_INIT
;
2066 git_vector pathlist
= GIT_VECTOR_INIT
;
2068 git_vector_insert(&pathlist
, "foobar/asdf");
2069 git_vector_insert(&pathlist
, "subdir/asdf");
2070 git_vector_insert(&pathlist
, "ignored/asdf");
2072 g_repo
= cl_git_sandbox_init("status");
2074 cl_git_mkfile("status/.gitignore", ".gitignore\n" "ignored/\n");
2076 cl_must_pass(p_mkdir("status/foobar", 0777));
2077 cl_git_mkfile("status/foobar/one", "one\n");
2079 cl_must_pass(p_mkdir("status/ignored", 0777));
2080 cl_git_mkfile("status/ignored/one", "one\n");
2081 cl_git_mkfile("status/ignored/two", "two\n");
2082 cl_git_mkfile("status/ignored/three", "three\n");
2084 cl_git_pass(git_repository_index(&index
, g_repo
));
2086 opts
.flags
= GIT_DIFF_INCLUDE_IGNORED
;
2087 opts
.pathspec
.strings
= (char **)pathlist
.contents
;
2088 opts
.pathspec
.count
= pathlist
.length
;
2090 cl_git_pass(git_diff_index_to_workdir(&diff
, g_repo
, index
, &opts
));
2091 cl_assert_equal_i(0, git_diff_num_deltas(diff
));
2092 git_diff_free(diff
);
2094 opts
.flags
|= GIT_DIFF_DISABLE_PATHSPEC_MATCH
;
2096 cl_git_pass(git_diff_index_to_workdir(&diff
, g_repo
, index
, &opts
));
2097 cl_assert_equal_i(0, git_diff_num_deltas(diff
));
2098 git_diff_free(diff
);
2100 git_index_free(index
);
2101 git_vector_free(&pathlist
);
2104 void test_diff_workdir__symlink_changed_on_non_symlink_platform(void)
2108 diff_expects exp
= {0};
2109 const git_diff_delta
*delta
;
2110 const char *commit
= "7fccd7";
2111 git_diff_options opts
= GIT_DIFF_OPTIONS_INIT
;
2112 git_vector pathlist
= GIT_VECTOR_INIT
;
2115 g_repo
= cl_git_sandbox_init("unsymlinked.git");
2117 cl_git_pass(git_repository__configmap_lookup(&symlinks
, g_repo
, GIT_CONFIGMAP_SYMLINKS
));
2122 cl_git_pass(git_vector_insert(&pathlist
, "include/Nu/Nu.h"));
2124 opts
.pathspec
.strings
= (char **)pathlist
.contents
;
2125 opts
.pathspec
.count
= pathlist
.length
;
2127 cl_must_pass(p_mkdir("symlink", 0777));
2128 cl_git_pass(git_repository_set_workdir(g_repo
, "symlink", false));
2130 cl_assert((tree
= resolve_commit_oid_to_tree(g_repo
, commit
)) != NULL
);
2132 /* first, do the diff with the original contents */
2134 cl_git_pass(git_futils_mkpath2file("symlink/include/Nu/Nu.h", 0755));
2135 cl_git_mkfile("symlink/include/Nu/Nu.h", "../../objc/Nu.h");
2137 cl_git_pass(git_diff_tree_to_workdir(&diff
, g_repo
, tree
, &opts
));
2138 cl_assert_equal_i(0, git_diff_num_deltas(diff
));
2139 git_diff_free(diff
);
2141 /* now update the contents and expect a difference, but that the file
2142 * mode has persisted as a symbolic link.
2145 cl_git_rewritefile("symlink/include/Nu/Nu.h", "awesome content\n");
2147 cl_git_pass(git_diff_tree_to_workdir(&diff
, g_repo
, tree
, &opts
));
2149 cl_git_pass(git_diff_foreach(
2150 diff
, diff_file_cb
, diff_binary_cb
, diff_hunk_cb
, diff_line_cb
, &exp
));
2151 cl_assert_equal_i(1, exp
.files
);
2153 cl_assert_equal_i(1, git_diff_num_deltas(diff
));
2154 delta
= git_diff_get_delta(diff
, 0);
2155 cl_assert_equal_i(GIT_FILEMODE_LINK
, delta
->old_file
.mode
);
2156 cl_assert_equal_i(GIT_FILEMODE_LINK
, delta
->new_file
.mode
);
2158 git_diff_free(diff
);
2160 cl_git_pass(git_futils_rmdir_r("symlink", NULL
, GIT_RMDIR_REMOVE_FILES
));
2162 git_tree_free(tree
);
2163 git_vector_free(&pathlist
);
2166 void test_diff_workdir__order(void)
2168 git_diff_options opts
= GIT_DIFF_OPTIONS_INIT
;
2169 git_buf patch
= GIT_BUF_INIT
;
2170 git_oid tree_oid
, blob_oid
;
2171 git_treebuilder
*builder
;
2175 g_repo
= cl_git_sandbox_init("empty_standard_repo");
2177 /* Build tree with a single file "abc.txt" */
2178 cl_git_pass(git_blob_create_from_buffer(&blob_oid
, g_repo
, "foo\n", 4));
2179 cl_git_pass(git_treebuilder_new(&builder
, g_repo
, NULL
));
2180 cl_git_pass(git_treebuilder_insert(NULL
, builder
, "abc.txt", &blob_oid
, GIT_FILEMODE_BLOB
));
2181 cl_git_pass(git_treebuilder_write(&tree_oid
, builder
));
2182 cl_git_pass(git_tree_lookup(&tree
, g_repo
, &tree_oid
));
2184 /* Create a directory that sorts before and one that sorts after "abc.txt" */
2185 cl_git_mkfile("empty_standard_repo/abc.txt", "bar\n");
2186 cl_must_pass(p_mkdir("empty_standard_repo/abb", 0777));
2187 cl_must_pass(p_mkdir("empty_standard_repo/abd", 0777));
2189 opts
.flags
= GIT_DIFF_INCLUDE_UNTRACKED
;
2190 cl_git_pass(git_diff_tree_to_workdir(&diff
, g_repo
, tree
, &opts
));
2192 cl_assert_equal_i(1, git_diff_num_deltas(diff
));
2193 cl_git_pass(git_diff_to_buf(&patch
, diff
, GIT_DIFF_FORMAT_PATCH
));
2194 cl_assert_equal_s(patch
.ptr
,
2195 "diff --git a/abc.txt b/abc.txt\n"
2196 "index 257cc56..5716ca5 100644\n"
2203 git_treebuilder_free(builder
);
2204 git_buf_dispose(&patch
);
2205 git_diff_free(diff
);
2206 git_tree_free(tree
);
2209 void test_diff_workdir__ignore_blank_lines(void)
2211 git_diff_options opts
= GIT_DIFF_OPTIONS_INIT
;
2214 git_buf buf
= GIT_BUF_INIT
;
2216 g_repo
= cl_git_sandbox_init("rebase");
2217 cl_git_rewritefile("rebase/gravy.txt", "GRAVY SOUP.\n\n\nGet eight pounds of coarse lean beef--wash it clean and lay it in your\n\npot, put in the same ingredients as for the shin soup, with the same\nquantity of water, and follow the process directed for that. Strain the\nsoup through a sieve, and serve it up clear, with nothing more than\ntoasted bread in it; two table-spoonsful of mushroom catsup will add a\nfine flavour to the soup!\n");
2219 /* Perform the diff normally */
2220 cl_git_pass(git_diff_index_to_workdir(&diff
, g_repo
, NULL
, &opts
));
2221 cl_git_pass(git_patch_from_diff(&patch
, diff
, 0));
2222 cl_git_pass(git_patch_to_buf(&buf
, patch
));
2224 cl_assert_equal_s("diff --git a/gravy.txt b/gravy.txt\nindex c4e6cca..3c617e6 100644\n--- a/gravy.txt\n+++ b/gravy.txt\n@@ -1,8 +1,10 @@\n GRAVY SOUP.\n \n+\n Get eight pounds of coarse lean beef--wash it clean and lay it in your\n+\n pot, put in the same ingredients as for the shin soup, with the same\n quantity of water, and follow the process directed for that. Strain the\n soup through a sieve, and serve it up clear, with nothing more than\n toasted bread in it; two table-spoonsful of mushroom catsup will add a\n-fine flavour to the soup.\n+fine flavour to the soup!\n", buf
.ptr
);
2226 git_buf_dispose(&buf
);
2227 git_patch_free(patch
);
2228 git_diff_free(diff
);
2230 /* Perform the diff ignoring blank lines */
2231 opts
.flags
|= GIT_DIFF_IGNORE_BLANK_LINES
;
2233 cl_git_pass(git_diff_index_to_workdir(&diff
, g_repo
, NULL
, &opts
));
2234 cl_git_pass(git_patch_from_diff(&patch
, diff
, 0));
2235 cl_git_pass(git_patch_to_buf(&buf
, patch
));
2237 cl_assert_equal_s("diff --git a/gravy.txt b/gravy.txt\nindex c4e6cca..3c617e6 100644\n--- a/gravy.txt\n+++ b/gravy.txt\n@@ -5,4 +7,4 @@ pot, put in the same ingredients as for the shin soup, with the same\n quantity of water, and follow the process directed for that. Strain the\n soup through a sieve, and serve it up clear, with nothing more than\n toasted bread in it; two table-spoonsful of mushroom catsup will add a\n-fine flavour to the soup.\n+fine flavour to the soup!\n", buf
.ptr
);
2239 git_buf_dispose(&buf
);
2240 git_patch_free(patch
);
2241 git_diff_free(diff
);