1 #include "clar_libgit2.h"
2 #include "diff_helpers.h"
3 #include "repository.h"
4 #include "git2/sys/diff.h"
6 static git_repository
*g_repo
= NULL
;
8 void test_diff_workdir__cleanup(void)
10 cl_git_sandbox_cleanup();
13 void test_diff_workdir__to_index(void)
15 git_diff_options opts
= GIT_DIFF_OPTIONS_INIT
;
16 git_diff
*diff
= NULL
;
20 g_repo
= cl_git_sandbox_init("status");
22 opts
.context_lines
= 3;
23 opts
.interhunk_lines
= 1;
24 opts
.flags
|= GIT_DIFF_INCLUDE_IGNORED
| GIT_DIFF_INCLUDE_UNTRACKED
;
26 cl_git_pass(git_diff_index_to_workdir(&diff
, g_repo
, NULL
, &opts
));
28 for (use_iterator
= 0; use_iterator
<= 1; use_iterator
++) {
29 memset(&exp
, 0, sizeof(exp
));
32 cl_git_pass(diff_foreach_via_iterator(
33 diff
, diff_file_cb
, diff_hunk_cb
, diff_line_cb
, &exp
));
35 cl_git_pass(git_diff_foreach(
36 diff
, diff_file_cb
, diff_hunk_cb
, diff_line_cb
, &exp
));
38 /* to generate these values:
39 * - cd to tests/resources/status,
41 * - git diff --name-status
45 cl_assert_equal_i(13, exp
.files
);
46 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_ADDED
]);
47 cl_assert_equal_i(4, exp
.file_status
[GIT_DELTA_DELETED
]);
48 cl_assert_equal_i(4, exp
.file_status
[GIT_DELTA_MODIFIED
]);
49 cl_assert_equal_i(1, exp
.file_status
[GIT_DELTA_IGNORED
]);
50 cl_assert_equal_i(4, exp
.file_status
[GIT_DELTA_UNTRACKED
]);
52 cl_assert_equal_i(8, exp
.hunks
);
54 cl_assert_equal_i(14, exp
.lines
);
55 cl_assert_equal_i(5, exp
.line_ctxt
);
56 cl_assert_equal_i(4, exp
.line_adds
);
57 cl_assert_equal_i(5, exp
.line_dels
);
61 git_diff_perfdata perf
= GIT_DIFF_PERFDATA_INIT
;
62 cl_git_pass(git_diff_get_perfdata(&perf
, diff
));
64 13 /* in root */ + 3 /* in subdir */, perf
.stat_calls
);
65 cl_assert_equal_sz(5, perf
.oid_calculations
);
71 void test_diff_workdir__to_index_with_assume_unchanged(void)
73 git_diff_options opts
= GIT_DIFF_OPTIONS_INIT
;
74 git_diff
*diff
= NULL
;
75 git_index
*idx
= NULL
;
77 const git_index_entry
*iep
;
80 g_repo
= cl_git_sandbox_init("status");
84 cl_git_pass(git_diff_index_to_workdir(&diff
, g_repo
, NULL
, &opts
));
85 memset(&exp
, 0, sizeof(exp
));
86 cl_git_pass(git_diff_foreach(
87 diff
, diff_file_cb
, diff_hunk_cb
, diff_line_cb
, &exp
));
88 cl_assert_equal_i(8, exp
.files
);
89 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_ADDED
]);
90 cl_assert_equal_i(4, exp
.file_status
[GIT_DELTA_DELETED
]);
91 cl_assert_equal_i(4, exp
.file_status
[GIT_DELTA_MODIFIED
]);
94 /* mark a couple of entries with ASSUME_UNCHANGED */
96 cl_git_pass(git_repository_index(&idx
, g_repo
));
98 cl_assert((iep
= git_index_get_bypath(idx
, "modified_file", 0)) != NULL
);
99 memcpy(&ie
, iep
, sizeof(ie
));
100 ie
.flags
|= GIT_IDXENTRY_VALID
;
101 cl_git_pass(git_index_add(idx
, &ie
));
103 cl_assert((iep
= git_index_get_bypath(idx
, "file_deleted", 0)) != NULL
);
104 memcpy(&ie
, iep
, sizeof(ie
));
105 ie
.flags
|= GIT_IDXENTRY_VALID
;
106 cl_git_pass(git_index_add(idx
, &ie
));
108 cl_git_pass(git_index_write(idx
));
111 /* redo diff and see that entries are skipped */
113 cl_git_pass(git_diff_index_to_workdir(&diff
, g_repo
, NULL
, &opts
));
114 memset(&exp
, 0, sizeof(exp
));
115 cl_git_pass(git_diff_foreach(
116 diff
, diff_file_cb
, diff_hunk_cb
, diff_line_cb
, &exp
));
117 cl_assert_equal_i(6, exp
.files
);
118 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_ADDED
]);
119 cl_assert_equal_i(3, exp
.file_status
[GIT_DELTA_DELETED
]);
120 cl_assert_equal_i(3, exp
.file_status
[GIT_DELTA_MODIFIED
]);
125 void test_diff_workdir__to_tree(void)
127 /* grabbed a couple of commit oids from the history of the attr repo */
128 const char *a_commit
= "26a125ee1bf"; /* the current HEAD */
129 const char *b_commit
= "0017bd4ab1ec3"; /* the start */
131 git_diff_options opts
= GIT_DIFF_OPTIONS_INIT
;
132 git_diff
*diff
= NULL
;
133 git_diff
*diff2
= NULL
;
137 g_repo
= cl_git_sandbox_init("status");
139 a
= resolve_commit_oid_to_tree(g_repo
, a_commit
);
140 b
= resolve_commit_oid_to_tree(g_repo
, b_commit
);
142 opts
.context_lines
= 3;
143 opts
.interhunk_lines
= 1;
144 opts
.flags
|= GIT_DIFF_INCLUDE_IGNORED
| GIT_DIFF_INCLUDE_UNTRACKED
;
146 /* You can't really generate the equivalent of git_diff_tree_to_workdir()
147 * using C git. It really wants to interpose the index into the diff.
149 * To validate the following results with command line git, I ran the
151 * - git ls-tree 26a125
152 * - find . ! -path ./.git/\* -a -type f | git hash-object --stdin-paths
153 * The results are documented at the bottom of this file in the
154 * long comment entitled "PREPARATION OF TEST DATA".
156 cl_git_pass(git_diff_tree_to_workdir(&diff
, g_repo
, a
, &opts
));
158 for (use_iterator
= 0; use_iterator
<= 1; use_iterator
++) {
159 memset(&exp
, 0, sizeof(exp
));
162 cl_git_pass(diff_foreach_via_iterator(
163 diff
, diff_file_cb
, diff_hunk_cb
, diff_line_cb
, &exp
));
165 cl_git_pass(git_diff_foreach(
166 diff
, diff_file_cb
, diff_hunk_cb
, diff_line_cb
, &exp
));
168 cl_assert_equal_i(14, exp
.files
);
169 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_ADDED
]);
170 cl_assert_equal_i(4, exp
.file_status
[GIT_DELTA_DELETED
]);
171 cl_assert_equal_i(4, exp
.file_status
[GIT_DELTA_MODIFIED
]);
172 cl_assert_equal_i(1, exp
.file_status
[GIT_DELTA_IGNORED
]);
173 cl_assert_equal_i(5, exp
.file_status
[GIT_DELTA_UNTRACKED
]);
176 /* Since there is no git diff equivalent, let's just assume that the
177 * text diffs produced by git_diff_foreach are accurate here. We will
178 * do more apples-to-apples test comparison below.
183 memset(&exp
, 0, sizeof(exp
));
185 /* This is a compatible emulation of "git diff <sha>" which looks like
186 * a workdir to tree diff (even though it is not really). This is what
187 * you would get from "git diff --name-status 26a125ee1bf"
189 cl_git_pass(git_diff_tree_to_index(&diff
, g_repo
, a
, NULL
, &opts
));
190 cl_git_pass(git_diff_index_to_workdir(&diff2
, g_repo
, NULL
, &opts
));
191 cl_git_pass(git_diff_merge(diff
, diff2
));
192 git_diff_free(diff2
);
194 for (use_iterator
= 0; use_iterator
<= 1; use_iterator
++) {
195 memset(&exp
, 0, sizeof(exp
));
198 cl_git_pass(diff_foreach_via_iterator(
199 diff
, diff_file_cb
, diff_hunk_cb
, diff_line_cb
, &exp
));
201 cl_git_pass(git_diff_foreach(
202 diff
, diff_file_cb
, diff_hunk_cb
, diff_line_cb
, &exp
));
204 cl_assert_equal_i(15, exp
.files
);
205 cl_assert_equal_i(2, exp
.file_status
[GIT_DELTA_ADDED
]);
206 cl_assert_equal_i(5, exp
.file_status
[GIT_DELTA_DELETED
]);
207 cl_assert_equal_i(4, exp
.file_status
[GIT_DELTA_MODIFIED
]);
208 cl_assert_equal_i(1, exp
.file_status
[GIT_DELTA_IGNORED
]);
209 cl_assert_equal_i(3, exp
.file_status
[GIT_DELTA_UNTRACKED
]);
211 cl_assert_equal_i(11, exp
.hunks
);
213 cl_assert_equal_i(17, exp
.lines
);
214 cl_assert_equal_i(4, exp
.line_ctxt
);
215 cl_assert_equal_i(8, exp
.line_adds
);
216 cl_assert_equal_i(5, exp
.line_dels
);
221 memset(&exp
, 0, sizeof(exp
));
223 /* Again, emulating "git diff <sha>" for testing purposes using
224 * "git diff --name-status 0017bd4ab1ec3" instead.
226 cl_git_pass(git_diff_tree_to_index(&diff
, g_repo
, b
, NULL
, &opts
));
227 cl_git_pass(git_diff_index_to_workdir(&diff2
, g_repo
, NULL
, &opts
));
228 cl_git_pass(git_diff_merge(diff
, diff2
));
229 git_diff_free(diff2
);
231 for (use_iterator
= 0; use_iterator
<= 1; use_iterator
++) {
232 memset(&exp
, 0, sizeof(exp
));
235 cl_git_pass(diff_foreach_via_iterator(
236 diff
, diff_file_cb
, diff_hunk_cb
, diff_line_cb
, &exp
));
238 cl_git_pass(git_diff_foreach(
239 diff
, diff_file_cb
, diff_hunk_cb
, diff_line_cb
, &exp
));
241 cl_assert_equal_i(16, exp
.files
);
242 cl_assert_equal_i(5, exp
.file_status
[GIT_DELTA_ADDED
]);
243 cl_assert_equal_i(4, exp
.file_status
[GIT_DELTA_DELETED
]);
244 cl_assert_equal_i(3, exp
.file_status
[GIT_DELTA_MODIFIED
]);
245 cl_assert_equal_i(1, exp
.file_status
[GIT_DELTA_IGNORED
]);
246 cl_assert_equal_i(3, exp
.file_status
[GIT_DELTA_UNTRACKED
]);
248 cl_assert_equal_i(12, exp
.hunks
);
250 cl_assert_equal_i(19, exp
.lines
);
251 cl_assert_equal_i(3, exp
.line_ctxt
);
252 cl_assert_equal_i(12, exp
.line_adds
);
253 cl_assert_equal_i(4, exp
.line_dels
);
258 /* Let's try that once more with a reversed diff */
260 opts
.flags
|= GIT_DIFF_REVERSE
;
262 cl_git_pass(git_diff_tree_to_index(&diff
, g_repo
, b
, NULL
, &opts
));
263 cl_git_pass(git_diff_index_to_workdir(&diff2
, g_repo
, NULL
, &opts
));
264 cl_git_pass(git_diff_merge(diff
, diff2
));
265 git_diff_free(diff2
);
267 memset(&exp
, 0, sizeof(exp
));
269 cl_git_pass(git_diff_foreach(
270 diff
, diff_file_cb
, diff_hunk_cb
, diff_line_cb
, &exp
));
272 cl_assert_equal_i(16, exp
.files
);
273 cl_assert_equal_i(5, exp
.file_status
[GIT_DELTA_DELETED
]);
274 cl_assert_equal_i(4, exp
.file_status
[GIT_DELTA_ADDED
]);
275 cl_assert_equal_i(3, exp
.file_status
[GIT_DELTA_MODIFIED
]);
276 cl_assert_equal_i(1, exp
.file_status
[GIT_DELTA_IGNORED
]);
277 cl_assert_equal_i(3, exp
.file_status
[GIT_DELTA_UNTRACKED
]);
279 cl_assert_equal_i(12, exp
.hunks
);
281 cl_assert_equal_i(19, exp
.lines
);
282 cl_assert_equal_i(3, exp
.line_ctxt
);
283 cl_assert_equal_i(12, exp
.line_dels
);
284 cl_assert_equal_i(4, exp
.line_adds
);
294 void test_diff_workdir__to_index_with_pathspec(void)
296 git_diff_options opts
= GIT_DIFF_OPTIONS_INIT
;
297 git_diff
*diff
= NULL
;
299 char *pathspec
= NULL
;
302 g_repo
= cl_git_sandbox_init("status");
304 opts
.context_lines
= 3;
305 opts
.interhunk_lines
= 1;
306 opts
.flags
|= GIT_DIFF_INCLUDE_IGNORED
| GIT_DIFF_INCLUDE_UNTRACKED
;
307 opts
.pathspec
.strings
= &pathspec
;
308 opts
.pathspec
.count
= 1;
310 cl_git_pass(git_diff_index_to_workdir(&diff
, g_repo
, NULL
, &opts
));
312 for (use_iterator
= 0; use_iterator
<= 1; use_iterator
++) {
313 memset(&exp
, 0, sizeof(exp
));
316 cl_git_pass(diff_foreach_via_iterator(
317 diff
, diff_file_cb
, NULL
, NULL
, &exp
));
319 cl_git_pass(git_diff_foreach(diff
, diff_file_cb
, NULL
, NULL
, &exp
));
321 cl_assert_equal_i(13, exp
.files
);
322 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_ADDED
]);
323 cl_assert_equal_i(4, exp
.file_status
[GIT_DELTA_DELETED
]);
324 cl_assert_equal_i(4, exp
.file_status
[GIT_DELTA_MODIFIED
]);
325 cl_assert_equal_i(1, exp
.file_status
[GIT_DELTA_IGNORED
]);
326 cl_assert_equal_i(4, exp
.file_status
[GIT_DELTA_UNTRACKED
]);
331 pathspec
= "modified_file";
333 cl_git_pass(git_diff_index_to_workdir(&diff
, g_repo
, NULL
, &opts
));
335 for (use_iterator
= 0; use_iterator
<= 1; use_iterator
++) {
336 memset(&exp
, 0, sizeof(exp
));
339 cl_git_pass(diff_foreach_via_iterator(
340 diff
, diff_file_cb
, NULL
, NULL
, &exp
));
342 cl_git_pass(git_diff_foreach(diff
, diff_file_cb
, NULL
, NULL
, &exp
));
344 cl_assert_equal_i(1, exp
.files
);
345 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_ADDED
]);
346 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_DELETED
]);
347 cl_assert_equal_i(1, exp
.file_status
[GIT_DELTA_MODIFIED
]);
348 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_IGNORED
]);
349 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_UNTRACKED
]);
356 cl_git_pass(git_diff_index_to_workdir(&diff
, g_repo
, NULL
, &opts
));
358 for (use_iterator
= 0; use_iterator
<= 1; use_iterator
++) {
359 memset(&exp
, 0, sizeof(exp
));
362 cl_git_pass(diff_foreach_via_iterator(
363 diff
, diff_file_cb
, NULL
, NULL
, &exp
));
365 cl_git_pass(git_diff_foreach(diff
, diff_file_cb
, NULL
, NULL
, &exp
));
367 cl_assert_equal_i(3, exp
.files
);
368 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_ADDED
]);
369 cl_assert_equal_i(1, exp
.file_status
[GIT_DELTA_DELETED
]);
370 cl_assert_equal_i(1, exp
.file_status
[GIT_DELTA_MODIFIED
]);
371 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_IGNORED
]);
372 cl_assert_equal_i(1, exp
.file_status
[GIT_DELTA_UNTRACKED
]);
377 pathspec
= "*_deleted";
379 cl_git_pass(git_diff_index_to_workdir(&diff
, g_repo
, NULL
, &opts
));
381 for (use_iterator
= 0; use_iterator
<= 1; use_iterator
++) {
382 memset(&exp
, 0, sizeof(exp
));
385 cl_git_pass(diff_foreach_via_iterator(
386 diff
, diff_file_cb
, NULL
, NULL
, &exp
));
388 cl_git_pass(git_diff_foreach(diff
, diff_file_cb
, NULL
, NULL
, &exp
));
390 cl_assert_equal_i(2, exp
.files
);
391 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_ADDED
]);
392 cl_assert_equal_i(2, exp
.file_status
[GIT_DELTA_DELETED
]);
393 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_MODIFIED
]);
394 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_IGNORED
]);
395 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_UNTRACKED
]);
401 void test_diff_workdir__filemode_changes(void)
403 git_diff
*diff
= NULL
;
407 if (!cl_is_chmod_supported())
410 g_repo
= cl_git_sandbox_init("issue_592");
412 cl_repo_set_bool(g_repo
, "core.filemode", true);
414 /* test once with no mods */
416 cl_git_pass(git_diff_index_to_workdir(&diff
, g_repo
, NULL
, NULL
));
418 for (use_iterator
= 0; use_iterator
<= 1; use_iterator
++) {
419 memset(&exp
, 0, sizeof(exp
));
422 cl_git_pass(diff_foreach_via_iterator(
423 diff
, diff_file_cb
, diff_hunk_cb
, diff_line_cb
, &exp
));
425 cl_git_pass(git_diff_foreach(
426 diff
, diff_file_cb
, diff_hunk_cb
, diff_line_cb
, &exp
));
428 cl_assert_equal_i(0, exp
.files
);
429 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_MODIFIED
]);
430 cl_assert_equal_i(0, exp
.hunks
);
435 /* chmod file and test again */
437 cl_assert(cl_toggle_filemode("issue_592/a.txt"));
439 cl_git_pass(git_diff_index_to_workdir(&diff
, g_repo
, NULL
, NULL
));
441 for (use_iterator
= 0; use_iterator
<= 1; use_iterator
++) {
442 memset(&exp
, 0, sizeof(exp
));
445 cl_git_pass(diff_foreach_via_iterator(
446 diff
, diff_file_cb
, diff_hunk_cb
, diff_line_cb
, &exp
));
448 cl_git_pass(git_diff_foreach(
449 diff
, diff_file_cb
, diff_hunk_cb
, diff_line_cb
, &exp
));
451 cl_assert_equal_i(1, exp
.files
);
452 cl_assert_equal_i(1, exp
.file_status
[GIT_DELTA_MODIFIED
]);
453 cl_assert_equal_i(0, exp
.hunks
);
458 cl_assert(cl_toggle_filemode("issue_592/a.txt"));
461 void test_diff_workdir__filemode_changes_with_filemode_false(void)
463 git_diff
*diff
= NULL
;
466 if (!cl_is_chmod_supported())
469 g_repo
= cl_git_sandbox_init("issue_592");
471 cl_repo_set_bool(g_repo
, "core.filemode", false);
473 /* test once with no mods */
475 cl_git_pass(git_diff_index_to_workdir(&diff
, g_repo
, NULL
, NULL
));
477 memset(&exp
, 0, sizeof(exp
));
478 cl_git_pass(git_diff_foreach(
479 diff
, diff_file_cb
, diff_hunk_cb
, diff_line_cb
, &exp
));
481 cl_assert_equal_i(0, exp
.files
);
482 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_MODIFIED
]);
483 cl_assert_equal_i(0, exp
.hunks
);
487 /* chmod file and test again */
489 cl_assert(cl_toggle_filemode("issue_592/a.txt"));
491 cl_git_pass(git_diff_index_to_workdir(&diff
, g_repo
, NULL
, NULL
));
493 memset(&exp
, 0, sizeof(exp
));
494 cl_git_pass(git_diff_foreach(
495 diff
, diff_file_cb
, diff_hunk_cb
, diff_line_cb
, &exp
));
497 cl_assert_equal_i(0, exp
.files
);
498 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_MODIFIED
]);
499 cl_assert_equal_i(0, exp
.hunks
);
503 cl_assert(cl_toggle_filemode("issue_592/a.txt"));
506 void test_diff_workdir__head_index_and_workdir_all_differ(void)
508 git_diff_options opts
= GIT_DIFF_OPTIONS_INIT
;
509 git_diff
*diff_i2t
= NULL
, *diff_w2i
= NULL
;
511 char *pathspec
= "staged_changes_modified_file";
516 * - head->index diff has 1 line of context, 1 line of diff
517 * - index->workdir diff has 2 lines of context, 1 line of diff
519 * - head->workdir diff has 1 line of context, 2 lines of diff
520 * Let's make sure the right one is returned from each fn.
523 g_repo
= cl_git_sandbox_init("status");
525 tree
= resolve_commit_oid_to_tree(g_repo
, "26a125ee1bfc5df1e1b2e9441bbe63c8a7ae989f");
527 opts
.pathspec
.strings
= &pathspec
;
528 opts
.pathspec
.count
= 1;
530 cl_git_pass(git_diff_tree_to_index(&diff_i2t
, g_repo
, tree
, NULL
, &opts
));
531 cl_git_pass(git_diff_index_to_workdir(&diff_w2i
, g_repo
, NULL
, &opts
));
533 for (use_iterator
= 0; use_iterator
<= 1; use_iterator
++) {
534 memset(&exp
, 0, sizeof(exp
));
537 cl_git_pass(diff_foreach_via_iterator(
538 diff_i2t
, diff_file_cb
, diff_hunk_cb
, diff_line_cb
, &exp
));
540 cl_git_pass(git_diff_foreach(
541 diff_i2t
, diff_file_cb
, diff_hunk_cb
, diff_line_cb
, &exp
));
543 cl_assert_equal_i(1, exp
.files
);
544 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_ADDED
]);
545 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_DELETED
]);
546 cl_assert_equal_i(1, exp
.file_status
[GIT_DELTA_MODIFIED
]);
547 cl_assert_equal_i(1, exp
.hunks
);
548 cl_assert_equal_i(2, exp
.lines
);
549 cl_assert_equal_i(1, exp
.line_ctxt
);
550 cl_assert_equal_i(1, exp
.line_adds
);
551 cl_assert_equal_i(0, exp
.line_dels
);
554 for (use_iterator
= 0; use_iterator
<= 1; use_iterator
++) {
555 memset(&exp
, 0, sizeof(exp
));
558 cl_git_pass(diff_foreach_via_iterator(
559 diff_w2i
, diff_file_cb
, diff_hunk_cb
, diff_line_cb
, &exp
));
561 cl_git_pass(git_diff_foreach(
562 diff_w2i
, diff_file_cb
, diff_hunk_cb
, diff_line_cb
, &exp
));
564 cl_assert_equal_i(1, exp
.files
);
565 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_ADDED
]);
566 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_DELETED
]);
567 cl_assert_equal_i(1, exp
.file_status
[GIT_DELTA_MODIFIED
]);
568 cl_assert_equal_i(1, exp
.hunks
);
569 cl_assert_equal_i(3, exp
.lines
);
570 cl_assert_equal_i(2, exp
.line_ctxt
);
571 cl_assert_equal_i(1, exp
.line_adds
);
572 cl_assert_equal_i(0, exp
.line_dels
);
575 cl_git_pass(git_diff_merge(diff_i2t
, diff_w2i
));
577 for (use_iterator
= 0; use_iterator
<= 1; use_iterator
++) {
578 memset(&exp
, 0, sizeof(exp
));
581 cl_git_pass(diff_foreach_via_iterator(
582 diff_i2t
, diff_file_cb
, diff_hunk_cb
, diff_line_cb
, &exp
));
584 cl_git_pass(git_diff_foreach(
585 diff_i2t
, diff_file_cb
, diff_hunk_cb
, diff_line_cb
, &exp
));
587 cl_assert_equal_i(1, exp
.files
);
588 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_ADDED
]);
589 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_DELETED
]);
590 cl_assert_equal_i(1, exp
.file_status
[GIT_DELTA_MODIFIED
]);
591 cl_assert_equal_i(1, exp
.hunks
);
592 cl_assert_equal_i(3, exp
.lines
);
593 cl_assert_equal_i(1, exp
.line_ctxt
);
594 cl_assert_equal_i(2, exp
.line_adds
);
595 cl_assert_equal_i(0, exp
.line_dels
);
598 git_diff_free(diff_i2t
);
599 git_diff_free(diff_w2i
);
604 void test_diff_workdir__eof_newline_changes(void)
606 git_diff_options opts
= GIT_DIFF_OPTIONS_INIT
;
607 git_diff
*diff
= NULL
;
609 char *pathspec
= "current_file";
612 g_repo
= cl_git_sandbox_init("status");
614 opts
.pathspec
.strings
= &pathspec
;
615 opts
.pathspec
.count
= 1;
617 cl_git_pass(git_diff_index_to_workdir(&diff
, g_repo
, NULL
, &opts
));
619 for (use_iterator
= 0; use_iterator
<= 1; use_iterator
++) {
620 memset(&exp
, 0, sizeof(exp
));
623 cl_git_pass(diff_foreach_via_iterator(
624 diff
, diff_file_cb
, diff_hunk_cb
, diff_line_cb
, &exp
));
626 cl_git_pass(git_diff_foreach(
627 diff
, diff_file_cb
, diff_hunk_cb
, diff_line_cb
, &exp
));
629 cl_assert_equal_i(0, exp
.files
);
630 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_ADDED
]);
631 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_DELETED
]);
632 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_MODIFIED
]);
633 cl_assert_equal_i(0, exp
.hunks
);
634 cl_assert_equal_i(0, exp
.lines
);
635 cl_assert_equal_i(0, exp
.line_ctxt
);
636 cl_assert_equal_i(0, exp
.line_adds
);
637 cl_assert_equal_i(0, exp
.line_dels
);
642 cl_git_append2file("status/current_file", "\n");
644 cl_git_pass(git_diff_index_to_workdir(&diff
, g_repo
, NULL
, &opts
));
646 for (use_iterator
= 0; use_iterator
<= 1; use_iterator
++) {
647 memset(&exp
, 0, sizeof(exp
));
650 cl_git_pass(diff_foreach_via_iterator(
651 diff
, diff_file_cb
, diff_hunk_cb
, diff_line_cb
, &exp
));
653 cl_git_pass(git_diff_foreach(
654 diff
, diff_file_cb
, diff_hunk_cb
, diff_line_cb
, &exp
));
656 cl_assert_equal_i(1, exp
.files
);
657 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_ADDED
]);
658 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_DELETED
]);
659 cl_assert_equal_i(1, exp
.file_status
[GIT_DELTA_MODIFIED
]);
660 cl_assert_equal_i(1, exp
.hunks
);
661 cl_assert_equal_i(2, exp
.lines
);
662 cl_assert_equal_i(1, exp
.line_ctxt
);
663 cl_assert_equal_i(1, exp
.line_adds
);
664 cl_assert_equal_i(0, exp
.line_dels
);
669 cl_git_rewritefile("status/current_file", "current_file");
671 cl_git_pass(git_diff_index_to_workdir(&diff
, g_repo
, NULL
, &opts
));
673 for (use_iterator
= 0; use_iterator
<= 1; use_iterator
++) {
674 memset(&exp
, 0, sizeof(exp
));
677 cl_git_pass(diff_foreach_via_iterator(
678 diff
, diff_file_cb
, diff_hunk_cb
, diff_line_cb
, &exp
));
680 cl_git_pass(git_diff_foreach(
681 diff
, diff_file_cb
, diff_hunk_cb
, diff_line_cb
, &exp
));
683 cl_assert_equal_i(1, exp
.files
);
684 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_ADDED
]);
685 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_DELETED
]);
686 cl_assert_equal_i(1, exp
.file_status
[GIT_DELTA_MODIFIED
]);
687 cl_assert_equal_i(1, exp
.hunks
);
688 cl_assert_equal_i(3, exp
.lines
);
689 cl_assert_equal_i(0, exp
.line_ctxt
);
690 cl_assert_equal_i(1, exp
.line_adds
);
691 cl_assert_equal_i(2, exp
.line_dels
);
697 /* PREPARATION OF TEST DATA
699 * Since there is no command line equivalent of git_diff_tree_to_workdir,
700 * it was a bit of a pain to confirm that I was getting the expected
701 * results in the first part of this tests. Here is what I ended up
702 * doing to set my expectation for the file counts and results:
704 * Running "git ls-tree 26a125" and "git ls-tree aa27a6" shows:
706 * A a0de7e0ac200c489c41c59dfa910154a70264e6e current_file
707 * B 5452d32f1dd538eb0405e8a83cc185f79e25e80f file_deleted
708 * C 452e4244b5d083ddf0460acf1ecc74db9dcfa11a modified_file
709 * D 32504b727382542f9f089e24fddac5e78533e96c staged_changes
710 * E 061d42a44cacde5726057b67558821d95db96f19 staged_changes_file_deleted
711 * F 70bd9443ada07063e7fbf0b3ff5c13f7494d89c2 staged_changes_modified_file
712 * G e9b9107f290627c04d097733a10055af941f6bca staged_delete_file_deleted
713 * H dabc8af9bd6e9f5bbe96a176f1a24baf3d1f8916 staged_delete_modified_file
714 * I 53ace0d1cc1145a5f4fe4f78a186a60263190733 subdir/current_file
715 * J 1888c805345ba265b0ee9449b8877b6064592058 subdir/deleted_file
716 * K a6191982709b746d5650e93c2acf34ef74e11504 subdir/modified_file
717 * L e8ee89e15bbe9b20137715232387b3de5b28972e subdir.txt
721 * find . ! -path ./.git/\* -a -type f | git hash-object --stdin-paths
723 * A a0de7e0ac200c489c41c59dfa910154a70264e6e current_file
724 * M 6a79f808a9c6bc9531ac726c184bbcd9351ccf11 ignored_file
725 * C 0a539630525aca2e7bc84975958f92f10a64c9b6 modified_file
726 * N d4fa8600b4f37d7516bef4816ae2c64dbf029e3a new_file
727 * D 55d316c9ba708999f1918e9677d01dfcae69c6b9 staged_changes
728 * F 011c3440d5c596e21d836aa6d7b10eb581f68c49 staged_changes_modified_file
729 * H dabc8af9bd6e9f5bbe96a176f1a24baf3d1f8916 staged_delete_modified_file
730 * O 529a16e8e762d4acb7b9636ff540a00831f9155a staged_new_file
731 * P 8b090c06d14ffa09c4e880088ebad33893f921d1 staged_new_file_modified_file
732 * I 53ace0d1cc1145a5f4fe4f78a186a60263190733 subdir/current_file
733 * K 57274b75eeb5f36fd55527806d567b2240a20c57 subdir/modified_file
734 * Q 80a86a6931b91bc01c2dbf5ca55bdd24ad1ef466 subdir/new_file
735 * L e8ee89e15bbe9b20137715232387b3de5b28972e subdir.txt
739 * A - current_file (UNMODIFIED) -> not in results
741 * M I ignored_file (IGNORED)
743 * N U new_file (UNTRACKED)
745 * E D staged_changes_file_deleted
746 * F M staged_changes_modified_file
747 * G D staged_delete_file_deleted
748 * H - staged_delete_modified_file (UNMODIFIED) -> not in results
749 * O U staged_new_file
750 * P U staged_new_file_modified_file
751 * I - subdir/current_file (UNMODIFIED) -> not in results
752 * J D subdir/deleted_file
753 * K M subdir/modified_file
754 * Q U subdir/new_file
755 * L - subdir.txt (UNMODIFIED) -> not in results
757 * Expect 13 files, 0 ADD, 4 DEL, 4 MOD, 1 IGN, 4 UNTR
761 void test_diff_workdir__larger_hunks(void)
763 const char *a_commit
= "d70d245ed97ed2aa596dd1af6536e4bfdb047b69";
764 const char *b_commit
= "7a9e0b02e63179929fed24f0a3e0f19168114d10";
766 git_diff_options opts
= GIT_DIFF_OPTIONS_INIT
;
767 size_t i
, d
, num_d
, h
, num_h
, l
, num_l
;
769 g_repo
= cl_git_sandbox_init("diff");
771 cl_assert((a
= resolve_commit_oid_to_tree(g_repo
, a_commit
)) != NULL
);
772 cl_assert((b
= resolve_commit_oid_to_tree(g_repo
, b_commit
)) != NULL
);
774 opts
.context_lines
= 1;
775 opts
.interhunk_lines
= 0;
777 for (i
= 0; i
<= 2; ++i
) {
778 git_diff
*diff
= NULL
;
780 const git_diff_hunk
*hunk
;
781 const git_diff_line
*line
;
783 /* okay, this is a bit silly, but oh well */
786 cl_git_pass(git_diff_index_to_workdir(&diff
, g_repo
, NULL
, &opts
));
789 cl_git_pass(git_diff_tree_to_workdir(&diff
, g_repo
, a
, &opts
));
792 cl_git_pass(git_diff_tree_to_workdir(&diff
, g_repo
, b
, &opts
));
796 num_d
= git_diff_num_deltas(diff
);
797 cl_assert_equal_i(2, (int)num_d
);
799 for (d
= 0; d
< num_d
; ++d
) {
800 cl_git_pass(git_patch_from_diff(&patch
, diff
, d
));
803 num_h
= git_patch_num_hunks(patch
);
804 for (h
= 0; h
< num_h
; h
++) {
805 cl_git_pass(git_patch_get_hunk(&hunk
, &num_l
, patch
, h
));
807 for (l
= 0; l
< num_l
; ++l
) {
809 git_patch_get_line_in_hunk(&line
, patch
, h
, l
));
813 /* confirm fail after the last item */
815 git_patch_get_line_in_hunk(&line
, patch
, h
, num_l
));
818 /* confirm fail after the last item */
819 cl_git_fail(git_patch_get_hunk(&hunk
, &num_l
, patch
, num_h
));
821 git_patch_free(patch
);
831 /* Set up a test that exercises this code. The easiest test using existing
832 * test data is probably to create a sandbox of submod2 and then run a
833 * git_diff_tree_to_workdir against tree
834 * 873585b94bdeabccea991ea5e3ec1a277895b698. As for what you should actually
835 * test, you can start by just checking that the number of lines of diff
836 * content matches the actual output of git diff. That will at least
837 * demonstrate that the submodule content is being used to generate somewhat
838 * comparable outputs. It is a test that would fail without this code and
839 * will succeed with it.
842 #include "../submodule/submodule_helpers.h"
844 void test_diff_workdir__submodules(void)
846 const char *a_commit
= "873585b94bdeabccea991ea5e3ec1a277895b698";
848 git_diff_options opts
= GIT_DIFF_OPTIONS_INIT
;
849 git_diff
*diff
= NULL
;
852 g_repo
= setup_fixture_submod2();
854 a
= resolve_commit_oid_to_tree(g_repo
, a_commit
);
857 GIT_DIFF_INCLUDE_UNTRACKED
|
858 GIT_DIFF_INCLUDE_IGNORED
|
859 GIT_DIFF_RECURSE_UNTRACKED_DIRS
|
860 GIT_DIFF_SHOW_UNTRACKED_CONTENT
;
862 cl_git_pass(git_diff_tree_to_workdir(&diff
, g_repo
, a
, &opts
));
864 /* diff_print(stderr, diff); */
866 /* essentially doing: git diff 873585b94bdeabccea991ea5e3ec1a277895b698 */
868 memset(&exp
, 0, sizeof(exp
));
870 cl_git_pass(git_diff_foreach(
871 diff
, diff_file_cb
, diff_hunk_cb
, diff_line_cb
, &exp
));
873 /* so "git diff 873585" returns:
875 * A just_a_dir/contents
877 * A sm_added_and_uncommited
881 * A sm_changed_untracked_file
882 * M sm_missing_commits
884 * which is a little deceptive because of the difference between the
885 * "git diff <treeish>" results from "git_diff_tree_to_workdir". The
886 * only significant difference is that those Added items will show up
887 * as Untracked items in the pure libgit2 diff.
889 * Then add in the two extra untracked items "not" and "not-submodule"
890 * to get the 12 files reported here.
893 cl_assert_equal_i(12, exp
.files
);
895 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_ADDED
]);
896 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_DELETED
]);
897 cl_assert_equal_i(2, exp
.file_status
[GIT_DELTA_MODIFIED
]);
898 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_IGNORED
]);
899 cl_assert_equal_i(10, exp
.file_status
[GIT_DELTA_UNTRACKED
]);
901 /* the following numbers match "git diff 873585" exactly */
903 cl_assert_equal_i(9, exp
.hunks
);
905 cl_assert_equal_i(33, exp
.lines
);
906 cl_assert_equal_i(2, exp
.line_ctxt
);
907 cl_assert_equal_i(30, exp
.line_adds
);
908 cl_assert_equal_i(1, exp
.line_dels
);
914 void test_diff_workdir__cannot_diff_against_a_bare_repository(void)
916 git_diff_options opts
= GIT_DIFF_OPTIONS_INIT
;
917 git_diff
*diff
= NULL
;
920 g_repo
= cl_git_sandbox_init("testrepo.git");
923 GIT_EBAREREPO
, git_diff_index_to_workdir(&diff
, g_repo
, NULL
, &opts
));
925 cl_git_pass(git_repository_head_tree(&tree
, g_repo
));
928 GIT_EBAREREPO
, git_diff_tree_to_workdir(&diff
, g_repo
, tree
, &opts
));
933 void test_diff_workdir__to_null_tree(void)
937 git_diff_options opts
= GIT_DIFF_OPTIONS_INIT
;
939 opts
.flags
= GIT_DIFF_INCLUDE_UNTRACKED
|
940 GIT_DIFF_RECURSE_UNTRACKED_DIRS
;
942 g_repo
= cl_git_sandbox_init("status");
944 cl_git_pass(git_diff_tree_to_workdir(&diff
, g_repo
, NULL
, &opts
));
946 memset(&exp
, 0, sizeof(exp
));
948 cl_git_pass(git_diff_foreach(
949 diff
, diff_file_cb
, diff_hunk_cb
, diff_line_cb
, &exp
));
951 cl_assert_equal_i(exp
.files
, exp
.file_status
[GIT_DELTA_UNTRACKED
]);
956 void test_diff_workdir__checks_options_version(void)
959 git_diff_options opts
= GIT_DIFF_OPTIONS_INIT
;
960 const git_error
*err
;
962 g_repo
= cl_git_sandbox_init("status");
965 cl_git_fail(git_diff_tree_to_workdir(&diff
, g_repo
, NULL
, &opts
));
967 cl_assert_equal_i(GITERR_INVALID
, err
->klass
);
971 cl_git_fail(git_diff_tree_to_workdir(&diff
, g_repo
, NULL
, &opts
));
973 cl_assert_equal_i(GITERR_INVALID
, err
->klass
);
976 void test_diff_workdir__can_diff_empty_file(void)
980 git_diff_options opts
= GIT_DIFF_OPTIONS_INIT
;
984 g_repo
= cl_git_sandbox_init("attr_index");
986 tree
= resolve_commit_oid_to_tree(g_repo
, "3812cfef3661"); /* HEAD */
988 /* baseline - make sure there are no outstanding diffs */
990 cl_git_pass(git_diff_tree_to_workdir(&diff
, g_repo
, tree
, &opts
));
991 cl_assert_equal_i(2, (int)git_diff_num_deltas(diff
));
994 /* empty contents of file */
996 cl_git_rewritefile("attr_index/README.txt", "");
997 cl_git_pass(git_path_lstat("attr_index/README.txt", &st
));
998 cl_assert_equal_i(0, (int)st
.st_size
);
1000 cl_git_pass(git_diff_tree_to_workdir(&diff
, g_repo
, tree
, &opts
));
1001 cl_assert_equal_i(3, (int)git_diff_num_deltas(diff
));
1002 /* diffs are: .gitattributes, README.txt, sub/sub/.gitattributes */
1003 cl_git_pass(git_patch_from_diff(&patch
, diff
, 1));
1004 git_patch_free(patch
);
1005 git_diff_free(diff
);
1007 /* remove a file altogether */
1009 cl_git_pass(p_unlink("attr_index/README.txt"));
1010 cl_assert(!git_path_exists("attr_index/README.txt"));
1012 cl_git_pass(git_diff_tree_to_workdir(&diff
, g_repo
, tree
, &opts
));
1013 cl_assert_equal_i(3, (int)git_diff_num_deltas(diff
));
1014 cl_git_pass(git_patch_from_diff(&patch
, diff
, 1));
1015 git_patch_free(patch
);
1016 git_diff_free(diff
);
1018 git_tree_free(tree
);
1021 void test_diff_workdir__to_index_issue_1397(void)
1023 git_diff_options opts
= GIT_DIFF_OPTIONS_INIT
;
1024 git_diff
*diff
= NULL
;
1027 g_repo
= cl_git_sandbox_init("issue_1397");
1029 cl_repo_set_bool(g_repo
, "core.autocrlf", true);
1031 opts
.context_lines
= 3;
1032 opts
.interhunk_lines
= 1;
1034 cl_git_pass(git_diff_index_to_workdir(&diff
, g_repo
, NULL
, &opts
));
1036 memset(&exp
, 0, sizeof(exp
));
1037 cl_git_pass(git_diff_foreach(
1038 diff
, diff_file_cb
, diff_hunk_cb
, diff_line_cb
, &exp
));
1040 cl_assert_equal_i(0, exp
.files
);
1041 cl_assert_equal_i(0, exp
.hunks
);
1042 cl_assert_equal_i(0, exp
.lines
);
1044 git_diff_free(diff
);
1047 cl_git_rewritefile("issue_1397/crlf_file.txt",
1048 "first line\r\nsecond line modified\r\nboth with crlf");
1050 cl_git_pass(git_diff_index_to_workdir(&diff
, g_repo
, NULL
, &opts
));
1052 memset(&exp
, 0, sizeof(exp
));
1053 cl_git_pass(git_diff_foreach(
1054 diff
, diff_file_cb
, diff_hunk_cb
, diff_line_cb
, &exp
));
1056 cl_assert_equal_i(1, exp
.files
);
1057 cl_assert_equal_i(1, exp
.file_status
[GIT_DELTA_MODIFIED
]);
1059 cl_assert_equal_i(1, exp
.hunks
);
1061 cl_assert_equal_i(5, exp
.lines
);
1062 cl_assert_equal_i(3, exp
.line_ctxt
);
1063 cl_assert_equal_i(1, exp
.line_adds
);
1064 cl_assert_equal_i(1, exp
.line_dels
);
1066 git_diff_free(diff
);
1069 void test_diff_workdir__to_tree_issue_1397(void)
1071 const char *a_commit
= "7f483a738"; /* the current HEAD */
1073 git_diff_options opts
= GIT_DIFF_OPTIONS_INIT
;
1074 git_diff
*diff
= NULL
;
1075 git_diff
*diff2
= NULL
;
1078 g_repo
= cl_git_sandbox_init("issue_1397");
1080 cl_repo_set_bool(g_repo
, "core.autocrlf", true);
1082 a
= resolve_commit_oid_to_tree(g_repo
, a_commit
);
1084 opts
.context_lines
= 3;
1085 opts
.interhunk_lines
= 1;
1087 cl_git_pass(git_diff_tree_to_workdir(&diff
, g_repo
, a
, &opts
));
1089 memset(&exp
, 0, sizeof(exp
));
1090 cl_git_pass(git_diff_foreach(
1091 diff
, diff_file_cb
, diff_hunk_cb
, diff_line_cb
, &exp
));
1093 cl_assert_equal_i(0, exp
.files
);
1094 cl_assert_equal_i(0, exp
.hunks
);
1095 cl_assert_equal_i(0, exp
.lines
);
1097 git_diff_free(diff
);
1100 cl_git_pass(git_diff_tree_to_index(&diff
, g_repo
, a
, NULL
, &opts
));
1101 cl_git_pass(git_diff_index_to_workdir(&diff2
, g_repo
, NULL
, &opts
));
1102 cl_git_pass(git_diff_merge(diff
, diff2
));
1103 git_diff_free(diff2
);
1105 memset(&exp
, 0, sizeof(exp
));
1106 cl_git_pass(git_diff_foreach(
1107 diff
, diff_file_cb
, diff_hunk_cb
, diff_line_cb
, &exp
));
1109 cl_assert_equal_i(0, exp
.files
);
1110 cl_assert_equal_i(0, exp
.hunks
);
1111 cl_assert_equal_i(0, exp
.lines
);
1113 git_diff_free(diff
);
1117 void test_diff_workdir__untracked_directory_scenarios(void)
1119 git_diff_options opts
= GIT_DIFF_OPTIONS_INIT
;
1120 git_diff
*diff
= NULL
;
1122 char *pathspec
= NULL
;
1123 static const char *files0
[] = {
1124 "subdir/deleted_file",
1125 "subdir/modified_file",
1129 static const char *files1
[] = {
1130 "subdir/deleted_file",
1131 "subdir/directory/",
1132 "subdir/modified_file",
1136 static const char *files2
[] = {
1137 "subdir/deleted_file",
1138 "subdir/directory/more/notignored",
1139 "subdir/modified_file",
1144 g_repo
= cl_git_sandbox_init("status");
1145 cl_git_mkfile("status/.gitignore", "ignored\n");
1147 opts
.context_lines
= 3;
1148 opts
.interhunk_lines
= 1;
1149 opts
.flags
|= GIT_DIFF_INCLUDE_IGNORED
| GIT_DIFF_INCLUDE_UNTRACKED
;
1150 opts
.pathspec
.strings
= &pathspec
;
1151 opts
.pathspec
.count
= 1;
1152 pathspec
= "subdir";
1154 /* baseline for "subdir" pathspec */
1156 memset(&exp
, 0, sizeof(exp
));
1159 cl_git_pass(git_diff_index_to_workdir(&diff
, g_repo
, NULL
, &opts
));
1161 cl_git_pass(git_diff_foreach(diff
, diff_file_cb
, NULL
, NULL
, &exp
));
1163 cl_assert_equal_i(3, exp
.files
);
1164 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_ADDED
]);
1165 cl_assert_equal_i(1, exp
.file_status
[GIT_DELTA_DELETED
]);
1166 cl_assert_equal_i(1, exp
.file_status
[GIT_DELTA_MODIFIED
]);
1167 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_IGNORED
]);
1168 cl_assert_equal_i(1, exp
.file_status
[GIT_DELTA_UNTRACKED
]);
1170 git_diff_free(diff
);
1172 /* empty directory */
1174 cl_git_pass(p_mkdir("status/subdir/directory", 0777));
1176 memset(&exp
, 0, sizeof(exp
));
1179 cl_git_pass(git_diff_index_to_workdir(&diff
, g_repo
, NULL
, &opts
));
1181 cl_git_pass(git_diff_foreach(diff
, diff_file_cb
, NULL
, NULL
, &exp
));
1183 cl_assert_equal_i(4, exp
.files
);
1184 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_ADDED
]);
1185 cl_assert_equal_i(1, exp
.file_status
[GIT_DELTA_DELETED
]);
1186 cl_assert_equal_i(1, exp
.file_status
[GIT_DELTA_MODIFIED
]);
1187 cl_assert_equal_i(1, exp
.file_status
[GIT_DELTA_IGNORED
]);
1188 cl_assert_equal_i(1, exp
.file_status
[GIT_DELTA_UNTRACKED
]);
1190 git_diff_free(diff
);
1192 /* empty directory in empty directory */
1194 cl_git_pass(p_mkdir("status/subdir/directory/empty", 0777));
1196 memset(&exp
, 0, sizeof(exp
));
1199 cl_git_pass(git_diff_index_to_workdir(&diff
, g_repo
, NULL
, &opts
));
1201 cl_git_pass(git_diff_foreach(diff
, diff_file_cb
, NULL
, NULL
, &exp
));
1203 cl_assert_equal_i(4, exp
.files
);
1204 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_ADDED
]);
1205 cl_assert_equal_i(1, exp
.file_status
[GIT_DELTA_DELETED
]);
1206 cl_assert_equal_i(1, exp
.file_status
[GIT_DELTA_MODIFIED
]);
1207 cl_assert_equal_i(1, exp
.file_status
[GIT_DELTA_IGNORED
]);
1208 cl_assert_equal_i(1, exp
.file_status
[GIT_DELTA_UNTRACKED
]);
1210 git_diff_free(diff
);
1212 /* directory with only ignored files */
1214 cl_git_pass(p_mkdir("status/subdir/directory/deeper", 0777));
1215 cl_git_mkfile("status/subdir/directory/deeper/ignored", "ignore me\n");
1217 cl_git_pass(p_mkdir("status/subdir/directory/another", 0777));
1218 cl_git_mkfile("status/subdir/directory/another/ignored", "ignore me\n");
1220 memset(&exp
, 0, sizeof(exp
));
1223 cl_git_pass(git_diff_index_to_workdir(&diff
, g_repo
, NULL
, &opts
));
1225 cl_git_pass(git_diff_foreach(diff
, diff_file_cb
, NULL
, NULL
, &exp
));
1227 cl_assert_equal_i(4, exp
.files
);
1228 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_ADDED
]);
1229 cl_assert_equal_i(1, exp
.file_status
[GIT_DELTA_DELETED
]);
1230 cl_assert_equal_i(1, exp
.file_status
[GIT_DELTA_MODIFIED
]);
1231 cl_assert_equal_i(1, exp
.file_status
[GIT_DELTA_IGNORED
]);
1232 cl_assert_equal_i(1, exp
.file_status
[GIT_DELTA_UNTRACKED
]);
1234 git_diff_free(diff
);
1236 /* directory with ignored directory (contents irrelevant) */
1238 cl_git_pass(p_mkdir("status/subdir/directory/more", 0777));
1239 cl_git_pass(p_mkdir("status/subdir/directory/more/ignored", 0777));
1240 cl_git_mkfile("status/subdir/directory/more/ignored/notignored",
1241 "inside ignored dir\n");
1243 memset(&exp
, 0, sizeof(exp
));
1246 cl_git_pass(git_diff_index_to_workdir(&diff
, g_repo
, NULL
, &opts
));
1248 cl_git_pass(git_diff_foreach(diff
, diff_file_cb
, NULL
, NULL
, &exp
));
1250 cl_assert_equal_i(4, exp
.files
);
1251 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_ADDED
]);
1252 cl_assert_equal_i(1, exp
.file_status
[GIT_DELTA_DELETED
]);
1253 cl_assert_equal_i(1, exp
.file_status
[GIT_DELTA_MODIFIED
]);
1254 cl_assert_equal_i(1, exp
.file_status
[GIT_DELTA_IGNORED
]);
1255 cl_assert_equal_i(1, exp
.file_status
[GIT_DELTA_UNTRACKED
]);
1257 git_diff_free(diff
);
1259 /* quick version avoids directory scan */
1261 opts
.flags
= opts
.flags
| GIT_DIFF_ENABLE_FAST_UNTRACKED_DIRS
;
1263 memset(&exp
, 0, sizeof(exp
));
1266 cl_git_pass(git_diff_index_to_workdir(&diff
, g_repo
, NULL
, &opts
));
1268 cl_git_pass(git_diff_foreach(diff
, diff_file_cb
, NULL
, NULL
, &exp
));
1270 cl_assert_equal_i(4, exp
.files
);
1271 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_ADDED
]);
1272 cl_assert_equal_i(1, exp
.file_status
[GIT_DELTA_DELETED
]);
1273 cl_assert_equal_i(1, exp
.file_status
[GIT_DELTA_MODIFIED
]);
1274 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_IGNORED
]);
1275 cl_assert_equal_i(2, exp
.file_status
[GIT_DELTA_UNTRACKED
]);
1277 git_diff_free(diff
);
1279 /* directory with nested non-ignored content */
1281 opts
.flags
= opts
.flags
& ~GIT_DIFF_ENABLE_FAST_UNTRACKED_DIRS
;
1283 cl_git_mkfile("status/subdir/directory/more/notignored",
1284 "not ignored deep under untracked\n");
1286 memset(&exp
, 0, sizeof(exp
));
1289 cl_git_pass(git_diff_index_to_workdir(&diff
, g_repo
, NULL
, &opts
));
1291 cl_git_pass(git_diff_foreach(diff
, diff_file_cb
, NULL
, NULL
, &exp
));
1293 cl_assert_equal_i(4, exp
.files
);
1294 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_ADDED
]);
1295 cl_assert_equal_i(1, exp
.file_status
[GIT_DELTA_DELETED
]);
1296 cl_assert_equal_i(1, exp
.file_status
[GIT_DELTA_MODIFIED
]);
1297 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_IGNORED
]);
1298 cl_assert_equal_i(2, exp
.file_status
[GIT_DELTA_UNTRACKED
]);
1300 git_diff_free(diff
);
1302 /* use RECURSE_UNTRACKED_DIRS to get actual untracked files (no ignores) */
1304 opts
.flags
= opts
.flags
& ~GIT_DIFF_INCLUDE_IGNORED
;
1305 opts
.flags
= opts
.flags
| GIT_DIFF_RECURSE_UNTRACKED_DIRS
;
1307 memset(&exp
, 0, sizeof(exp
));
1310 cl_git_pass(git_diff_index_to_workdir(&diff
, g_repo
, NULL
, &opts
));
1312 cl_git_pass(git_diff_foreach(diff
, diff_file_cb
, NULL
, NULL
, &exp
));
1314 cl_assert_equal_i(4, exp
.files
);
1315 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_ADDED
]);
1316 cl_assert_equal_i(1, exp
.file_status
[GIT_DELTA_DELETED
]);
1317 cl_assert_equal_i(1, exp
.file_status
[GIT_DELTA_MODIFIED
]);
1318 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_IGNORED
]);
1319 cl_assert_equal_i(2, exp
.file_status
[GIT_DELTA_UNTRACKED
]);
1321 git_diff_free(diff
);
1325 void test_diff_workdir__untracked_directory_comes_last(void)
1327 git_diff_options opts
= GIT_DIFF_OPTIONS_INIT
;
1328 git_diff
*diff
= NULL
;
1330 g_repo
= cl_git_sandbox_init("renames");
1332 cl_git_mkfile("renames/.gitignore", "*.ign\n");
1333 cl_git_pass(p_mkdir("renames/zzz_untracked", 0777));
1334 cl_git_mkfile("renames/zzz_untracked/an.ign", "ignore me please");
1335 cl_git_mkfile("renames/zzz_untracked/skip.ign", "ignore me really");
1336 cl_git_mkfile("renames/zzz_untracked/test.ign", "ignore me now");
1338 opts
.context_lines
= 3;
1339 opts
.interhunk_lines
= 1;
1340 opts
.flags
|= GIT_DIFF_INCLUDE_IGNORED
| GIT_DIFF_INCLUDE_UNTRACKED
;
1342 cl_git_pass(git_diff_index_to_workdir(&diff
, g_repo
, NULL
, &opts
));
1344 cl_assert(diff
!= NULL
);
1346 git_diff_free(diff
);
1349 void test_diff_workdir__untracked_with_bom(void)
1351 git_diff_options opts
= GIT_DIFF_OPTIONS_INIT
;
1352 git_diff
*diff
= NULL
;
1353 const git_diff_delta
*delta
;
1355 g_repo
= cl_git_sandbox_init("empty_standard_repo");
1356 cl_repo_set_bool(g_repo
, "core.autocrlf", true);
1358 cl_git_write2file("empty_standard_repo/bom.txt",
1359 "\xFF\xFE\x31\x00\x32\x00\x33\x00\x34\x00", 10, O_WRONLY
|O_CREAT
, 0664);
1362 GIT_DIFF_INCLUDE_UNTRACKED
| GIT_DIFF_SHOW_UNTRACKED_CONTENT
;
1364 cl_git_pass(git_diff_index_to_workdir(&diff
, g_repo
, NULL
, &opts
));
1366 cl_assert_equal_i(1, git_diff_num_deltas(diff
));
1367 cl_assert((delta
= git_diff_get_delta(diff
, 0)) != NULL
);
1368 cl_assert_equal_i(GIT_DELTA_UNTRACKED
, delta
->status
);
1370 /* not known at this point
1371 * cl_assert((delta->flags & GIT_DIFF_FLAG_BINARY) != 0);
1374 git_diff_free(diff
);
1377 void test_diff_workdir__patience_diff(void)
1380 git_diff_options opts
= GIT_DIFF_OPTIONS_INIT
;
1381 git_diff
*diff
= NULL
;
1382 git_patch
*patch
= NULL
;
1383 git_buf buf
= GIT_BUF_INIT
;
1384 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";
1385 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";
1387 g_repo
= cl_git_sandbox_init("empty_standard_repo");
1388 cl_repo_set_bool(g_repo
, "core.autocrlf", true);
1389 cl_git_pass(git_repository_index(&index
, g_repo
));
1392 "empty_standard_repo/test.txt",
1393 "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");
1394 cl_git_pass(git_index_add_bypath(index
, "test.txt"));
1395 cl_repo_commit_from_index(NULL
, g_repo
, NULL
, 1372350000, "Base");
1396 git_index_free(index
);
1399 "empty_standard_repo/test.txt",
1400 "When I wrote this\nI did not know\nI did not know\nhow to create\na patience diff\nanother problem\na minimal diff\n");
1402 cl_git_pass(git_diff_index_to_workdir(&diff
, g_repo
, NULL
, &opts
));
1403 cl_assert_equal_i(1, git_diff_num_deltas(diff
));
1404 cl_git_pass(git_patch_from_diff(&patch
, diff
, 0));
1405 cl_git_pass(git_patch_to_buf(&buf
, patch
));
1407 cl_assert_equal_s(expected_normal
, buf
.ptr
);
1408 git_buf_clear(&buf
);
1409 git_patch_free(patch
);
1410 git_diff_free(diff
);
1412 opts
.flags
|= GIT_DIFF_PATIENCE
;
1414 cl_git_pass(git_diff_index_to_workdir(&diff
, g_repo
, NULL
, &opts
));
1415 cl_assert_equal_i(1, git_diff_num_deltas(diff
));
1416 cl_git_pass(git_patch_from_diff(&patch
, diff
, 0));
1417 cl_git_pass(git_patch_to_buf(&buf
, patch
));
1419 cl_assert_equal_s(expected_patience
, buf
.ptr
);
1420 git_buf_clear(&buf
);
1423 git_patch_free(patch
);
1424 git_diff_free(diff
);
1427 void test_diff_workdir__with_stale_index(void)
1429 git_diff_options opts
= GIT_DIFF_OPTIONS_INIT
;
1430 git_diff
*diff
= NULL
;
1431 git_index
*idx
= NULL
;
1434 g_repo
= cl_git_sandbox_init("status");
1435 cl_git_pass(git_repository_index(&idx
, g_repo
));
1437 /* make the in-memory index invalid */
1441 cl_git_pass(git_repository_open(&r2
, "status"));
1442 cl_git_pass(git_repository_index(&idx2
, r2
));
1443 cl_git_pass(git_index_add_bypath(idx2
, "new_file"));
1444 cl_git_pass(git_index_add_bypath(idx2
, "subdir/new_file"));
1445 cl_git_pass(git_index_remove_bypath(idx2
, "staged_new_file"));
1446 cl_git_pass(git_index_remove_bypath(idx2
, "staged_changes_file_deleted"));
1447 cl_git_pass(git_index_write(idx2
));
1448 git_index_free(idx2
);
1449 git_repository_free(r2
);
1452 opts
.context_lines
= 3;
1453 opts
.interhunk_lines
= 1;
1454 opts
.flags
|= GIT_DIFF_INCLUDE_UNTRACKED
| GIT_DIFF_INCLUDE_UNMODIFIED
;
1456 /* first try with index pointer which should prevent reload */
1458 cl_git_pass(git_diff_index_to_workdir(&diff
, g_repo
, idx
, &opts
));
1460 memset(&exp
, 0, sizeof(exp
));
1462 cl_git_pass(git_diff_foreach(
1463 diff
, diff_file_cb
, diff_hunk_cb
, diff_line_cb
, &exp
));
1465 cl_assert_equal_i(17, exp
.files
);
1466 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_ADDED
]);
1467 cl_assert_equal_i(4, exp
.file_status
[GIT_DELTA_DELETED
]);
1468 cl_assert_equal_i(4, exp
.file_status
[GIT_DELTA_MODIFIED
]);
1469 cl_assert_equal_i(4, exp
.file_status
[GIT_DELTA_UNTRACKED
]);
1470 cl_assert_equal_i(5, exp
.file_status
[GIT_DELTA_UNMODIFIED
]);
1472 git_diff_free(diff
);
1474 /* now let's try without the index pointer which should trigger reload */
1476 /* two files that were UNTRACKED should have become UNMODIFIED */
1477 /* one file that was UNMODIFIED should now have become UNTRACKED */
1478 /* one file that was DELETED should now be gone completely */
1480 cl_git_pass(git_diff_index_to_workdir(&diff
, g_repo
, NULL
, &opts
));
1482 memset(&exp
, 0, sizeof(exp
));
1484 cl_git_pass(git_diff_foreach(
1485 diff
, diff_file_cb
, diff_hunk_cb
, diff_line_cb
, &exp
));
1487 git_diff_free(diff
);
1489 cl_assert_equal_i(16, exp
.files
);
1490 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_ADDED
]);
1491 cl_assert_equal_i(3, exp
.file_status
[GIT_DELTA_DELETED
]);
1492 cl_assert_equal_i(4, exp
.file_status
[GIT_DELTA_MODIFIED
]);
1493 cl_assert_equal_i(3, exp
.file_status
[GIT_DELTA_UNTRACKED
]);
1494 cl_assert_equal_i(6, exp
.file_status
[GIT_DELTA_UNMODIFIED
]);
1496 git_index_free(idx
);
1499 static int touch_file(void *payload
, git_buf
*path
)
1504 GIT_UNUSED(payload
);
1505 if (git_path_isdir(path
->ptr
))
1508 cl_assert((fd
= p_open(path
->ptr
, O_RDWR
)) >= 0);
1509 cl_assert_equal_i(1, p_read(fd
, &b
, 1));
1510 cl_must_pass(p_lseek(fd
, 0, SEEK_SET
));
1511 cl_must_pass(p_write(fd
, &b
, 1));
1512 cl_must_pass(p_close(fd
));
1517 static void basic_diff_status(git_diff
**out
, const git_diff_options
*opts
)
1521 cl_git_pass(git_diff_index_to_workdir(out
, g_repo
, NULL
, opts
));
1523 memset(&exp
, 0, sizeof(exp
));
1525 cl_git_pass(git_diff_foreach(
1526 *out
, diff_file_cb
, diff_hunk_cb
, diff_line_cb
, &exp
));
1528 cl_assert_equal_i(13, exp
.files
);
1529 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_ADDED
]);
1530 cl_assert_equal_i(4, exp
.file_status
[GIT_DELTA_DELETED
]);
1531 cl_assert_equal_i(4, exp
.file_status
[GIT_DELTA_MODIFIED
]);
1532 cl_assert_equal_i(1, exp
.file_status
[GIT_DELTA_IGNORED
]);
1533 cl_assert_equal_i(4, exp
.file_status
[GIT_DELTA_UNTRACKED
]);
1536 void test_diff_workdir__can_update_index(void)
1538 git_diff_options opts
= GIT_DIFF_OPTIONS_INIT
;
1539 git_diff
*diff
= NULL
;
1540 git_diff_perfdata perf
= GIT_DIFF_PERFDATA_INIT
;
1542 g_repo
= cl_git_sandbox_init("status");
1544 /* touch all the files so stat times are different */
1546 git_buf path
= GIT_BUF_INIT
;
1547 cl_git_pass(git_buf_sets(&path
, "status"));
1548 cl_git_pass(git_path_direach(&path
, 0, touch_file
, NULL
));
1549 git_buf_free(&path
);
1552 opts
.flags
|= GIT_DIFF_INCLUDE_IGNORED
| GIT_DIFF_INCLUDE_UNTRACKED
;
1554 basic_diff_status(&diff
, &opts
);
1556 cl_git_pass(git_diff_get_perfdata(&perf
, diff
));
1557 cl_assert_equal_sz(13 + 3, perf
.stat_calls
);
1558 cl_assert_equal_sz(5, perf
.oid_calculations
);
1560 git_diff_free(diff
);
1562 /* now allow diff to update stat cache */
1563 opts
.flags
|= GIT_DIFF_UPDATE_INDEX
;
1565 basic_diff_status(&diff
, &opts
);
1567 cl_git_pass(git_diff_get_perfdata(&perf
, diff
));
1568 cl_assert_equal_sz(13 + 3, perf
.stat_calls
);
1569 cl_assert_equal_sz(5, perf
.oid_calculations
);
1571 git_diff_free(diff
);
1573 /* now if we do it again, we should see fewer OID calculations */
1575 basic_diff_status(&diff
, &opts
);
1577 cl_git_pass(git_diff_get_perfdata(&perf
, diff
));
1578 cl_assert_equal_sz(13 + 3, perf
.stat_calls
);
1579 cl_assert_equal_sz(0, perf
.oid_calculations
);
1581 git_diff_free(diff
);
1584 #define STR7 "0123456"
1585 #define STR8 "01234567"
1586 #define STR40 STR8 STR8 STR8 STR8 STR8
1587 #define STR200 STR40 STR40 STR40 STR40 STR40
1588 #define STR999Z STR200 STR200 STR200 STR200 STR40 STR40 STR40 STR40 \
1589 STR8 STR8 STR8 STR8 STR7 "\0"
1590 #define STR1000 STR200 STR200 STR200 STR200 STR200
1591 #define STR3999Z STR1000 STR1000 STR1000 STR999Z
1592 #define STR4000 STR1000 STR1000 STR1000 STR1000
1594 static void assert_delta_binary(git_diff
*diff
, size_t idx
, int is_binary
)
1597 const git_diff_delta
*delta
;
1599 cl_git_pass(git_patch_from_diff(&patch
, diff
, idx
));
1600 delta
= git_patch_get_delta(patch
);
1601 cl_assert_equal_b((delta
->flags
& GIT_DIFF_FLAG_BINARY
), is_binary
);
1602 git_patch_free(patch
);
1605 void test_diff_workdir__binary_detection(void)
1608 git_diff
*diff
= NULL
;
1609 git_buf b
= GIT_BUF_INIT
;
1611 git_buf data
[10] = {
1612 { "1234567890", 0, 0 }, /* 0 - all ascii text control */
1613 { "\xC3\x85\xC3\xBC\xE2\x80\xA0\x48\xC3\xB8\xCF\x80\xCE\xA9", 0, 0 }, /* 1 - UTF-8 multibyte text */
1614 { "\xEF\xBB\xBF\xC3\x9C\xE2\xA4\x92\xC6\x92\x38\xC2\xA3\xE2\x82\xAC", 0, 0 }, /* 2 - UTF-8 with BOM */
1615 { STR999Z
, 0, 1000 }, /* 3 - ASCII with NUL at 1000 */
1616 { STR3999Z
, 0, 4000 }, /* 4 - ASCII with NUL at 4000 */
1617 { STR4000 STR3999Z
"x", 0, 8001 }, /* 5 - ASCII with NUL at 8000 */
1618 { STR4000 STR4000
"\0", 0, 8001 }, /* 6 - ASCII with NUL at 8001 */
1619 { "\x00\xDC\x00\x6E\x21\x39\xFE\x0E\x00\x63\x00\xF8"
1620 "\x00\x64\x00\x65\x20\x48", 0, 18 }, /* 7 - UTF-16 text */
1621 { "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d"
1622 "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d",
1623 0, 26 }, /* 8 - All non-printable characters (no NUL) */
1624 { "Hello \x01\x02\x03\x04\x05\x06 World!\x01\x02\x03\x04"
1625 "\x05\x06\x07", 0, 26 }, /* 9 - 50-50 non-printable (no NUL) */
1628 g_repo
= cl_git_sandbox_init("empty_standard_repo");
1629 cl_git_pass(git_repository_index(&idx
, g_repo
));
1631 /* We start with ASCII in index and test data in workdir,
1632 * then we will try with test data in index and ASCII in workdir.
1635 cl_git_pass(git_buf_sets(&b
, "empty_standard_repo/0"));
1636 for (i
= 0; i
< 10; ++i
) {
1637 b
.ptr
[b
.size
- 1] = '0' + i
;
1638 cl_git_mkfile(b
.ptr
, "baseline");
1639 cl_git_pass(git_index_add_bypath(idx
, &b
.ptr
[b
.size
- 1]));
1641 if (data
[i
].size
== 0)
1642 data
[i
].size
= strlen(data
[i
].ptr
);
1644 b
.ptr
, data
[i
].ptr
, data
[i
].size
, O_WRONLY
|O_TRUNC
, 0664);
1646 git_index_write(idx
);
1648 cl_git_pass(git_diff_index_to_workdir(&diff
, g_repo
, NULL
, NULL
));
1650 cl_assert_equal_i(10, git_diff_num_deltas(diff
));
1652 /* using diff binary detection (i.e. looking for NUL byte) */
1653 assert_delta_binary(diff
, 0, false);
1654 assert_delta_binary(diff
, 1, false);
1655 assert_delta_binary(diff
, 2, false);
1656 assert_delta_binary(diff
, 3, true);
1657 assert_delta_binary(diff
, 4, true);
1658 assert_delta_binary(diff
, 5, true);
1659 assert_delta_binary(diff
, 6, false);
1660 assert_delta_binary(diff
, 7, true);
1661 assert_delta_binary(diff
, 8, false);
1662 assert_delta_binary(diff
, 9, false);
1663 /* The above have been checked to match command-line Git */
1665 git_diff_free(diff
);
1667 cl_git_pass(git_buf_sets(&b
, "empty_standard_repo/0"));
1668 for (i
= 0; i
< 10; ++i
) {
1669 b
.ptr
[b
.size
- 1] = '0' + i
;
1670 cl_git_pass(git_index_add_bypath(idx
, &b
.ptr
[b
.size
- 1]));
1672 cl_git_write2file(b
.ptr
, "baseline\n", 9, O_WRONLY
|O_TRUNC
, 0664);
1674 git_index_write(idx
);
1676 cl_git_pass(git_diff_index_to_workdir(&diff
, g_repo
, NULL
, NULL
));
1678 cl_assert_equal_i(10, git_diff_num_deltas(diff
));
1680 /* using diff binary detection (i.e. looking for NUL byte) */
1681 assert_delta_binary(diff
, 0, false);
1682 assert_delta_binary(diff
, 1, false);
1683 assert_delta_binary(diff
, 2, false);
1684 assert_delta_binary(diff
, 3, true);
1685 assert_delta_binary(diff
, 4, true);
1686 assert_delta_binary(diff
, 5, true);
1687 assert_delta_binary(diff
, 6, false);
1688 assert_delta_binary(diff
, 7, true);
1689 assert_delta_binary(diff
, 8, false);
1690 assert_delta_binary(diff
, 9, false);
1692 git_diff_free(diff
);
1694 git_index_free(idx
);