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_conflicts(void)
73 git_diff_options opts
= GIT_DIFF_OPTIONS_INIT
;
74 git_diff
*diff
= NULL
;
76 git_index_entry our_entry
= {{0}}, their_entry
= {{0}};
77 diff_expects exp
= {0};
79 g_repo
= cl_git_sandbox_init("status");
81 opts
.context_lines
= 3;
82 opts
.interhunk_lines
= 1;
84 /* Adding an entry that represents a rename gets two files in conflict */
85 our_entry
.path
= "subdir/modified_file";
86 our_entry
.mode
= 0100644;
88 their_entry
.path
= "subdir/rename_conflict";
89 their_entry
.mode
= 0100644;
91 cl_git_pass(git_repository_index(&index
, g_repo
));
92 cl_git_pass(git_index_conflict_add(index
, NULL
, &our_entry
, &their_entry
));
94 cl_git_pass(git_diff_index_to_workdir(&diff
, g_repo
, index
, &opts
));
96 cl_git_pass(diff_foreach_via_iterator(
97 diff
, diff_file_cb
, diff_hunk_cb
, diff_line_cb
, &exp
));
99 cl_assert_equal_i(9, exp
.files
);
100 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_ADDED
]);
101 cl_assert_equal_i(4, exp
.file_status
[GIT_DELTA_DELETED
]);
102 cl_assert_equal_i(3, exp
.file_status
[GIT_DELTA_MODIFIED
]);
103 cl_assert_equal_i(2, exp
.file_status
[GIT_DELTA_CONFLICTED
]);
105 cl_assert_equal_i(7, exp
.hunks
);
107 cl_assert_equal_i(12, exp
.lines
);
108 cl_assert_equal_i(4, exp
.line_ctxt
);
109 cl_assert_equal_i(3, exp
.line_adds
);
110 cl_assert_equal_i(5, exp
.line_dels
);
113 git_index_free(index
);
116 void test_diff_workdir__to_index_with_assume_unchanged(void)
118 git_diff_options opts
= GIT_DIFF_OPTIONS_INIT
;
119 git_diff
*diff
= NULL
;
120 git_index
*idx
= NULL
;
122 const git_index_entry
*iep
;
125 g_repo
= cl_git_sandbox_init("status");
127 /* do initial diff */
129 cl_git_pass(git_diff_index_to_workdir(&diff
, g_repo
, NULL
, &opts
));
130 memset(&exp
, 0, sizeof(exp
));
131 cl_git_pass(git_diff_foreach(
132 diff
, diff_file_cb
, diff_hunk_cb
, diff_line_cb
, &exp
));
133 cl_assert_equal_i(8, exp
.files
);
134 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_ADDED
]);
135 cl_assert_equal_i(4, exp
.file_status
[GIT_DELTA_DELETED
]);
136 cl_assert_equal_i(4, exp
.file_status
[GIT_DELTA_MODIFIED
]);
139 /* mark a couple of entries with ASSUME_UNCHANGED */
141 cl_git_pass(git_repository_index(&idx
, g_repo
));
143 cl_assert((iep
= git_index_get_bypath(idx
, "modified_file", 0)) != NULL
);
144 memcpy(&ie
, iep
, sizeof(ie
));
145 ie
.flags
|= GIT_IDXENTRY_VALID
;
146 cl_git_pass(git_index_add(idx
, &ie
));
148 cl_assert((iep
= git_index_get_bypath(idx
, "file_deleted", 0)) != NULL
);
149 memcpy(&ie
, iep
, sizeof(ie
));
150 ie
.flags
|= GIT_IDXENTRY_VALID
;
151 cl_git_pass(git_index_add(idx
, &ie
));
153 cl_git_pass(git_index_write(idx
));
156 /* redo diff and see that entries are skipped */
158 cl_git_pass(git_diff_index_to_workdir(&diff
, g_repo
, NULL
, &opts
));
159 memset(&exp
, 0, sizeof(exp
));
160 cl_git_pass(git_diff_foreach(
161 diff
, diff_file_cb
, diff_hunk_cb
, diff_line_cb
, &exp
));
162 cl_assert_equal_i(6, exp
.files
);
163 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_ADDED
]);
164 cl_assert_equal_i(3, exp
.file_status
[GIT_DELTA_DELETED
]);
165 cl_assert_equal_i(3, exp
.file_status
[GIT_DELTA_MODIFIED
]);
170 void test_diff_workdir__to_tree(void)
172 /* grabbed a couple of commit oids from the history of the attr repo */
173 const char *a_commit
= "26a125ee1bf"; /* the current HEAD */
174 const char *b_commit
= "0017bd4ab1ec3"; /* the start */
176 git_diff_options opts
= GIT_DIFF_OPTIONS_INIT
;
177 git_diff
*diff
= NULL
;
178 git_diff
*diff2
= NULL
;
182 g_repo
= cl_git_sandbox_init("status");
184 a
= resolve_commit_oid_to_tree(g_repo
, a_commit
);
185 b
= resolve_commit_oid_to_tree(g_repo
, b_commit
);
187 opts
.context_lines
= 3;
188 opts
.interhunk_lines
= 1;
189 opts
.flags
|= GIT_DIFF_INCLUDE_IGNORED
| GIT_DIFF_INCLUDE_UNTRACKED
;
191 /* You can't really generate the equivalent of git_diff_tree_to_workdir()
192 * using C git. It really wants to interpose the index into the diff.
194 * To validate the following results with command line git, I ran the
196 * - git ls-tree 26a125
197 * - find . ! -path ./.git/\* -a -type f | git hash-object --stdin-paths
198 * The results are documented at the bottom of this file in the
199 * long comment entitled "PREPARATION OF TEST DATA".
201 cl_git_pass(git_diff_tree_to_workdir(&diff
, g_repo
, a
, &opts
));
203 for (use_iterator
= 0; use_iterator
<= 1; use_iterator
++) {
204 memset(&exp
, 0, sizeof(exp
));
207 cl_git_pass(diff_foreach_via_iterator(
208 diff
, diff_file_cb
, diff_hunk_cb
, diff_line_cb
, &exp
));
210 cl_git_pass(git_diff_foreach(
211 diff
, diff_file_cb
, diff_hunk_cb
, diff_line_cb
, &exp
));
213 cl_assert_equal_i(14, exp
.files
);
214 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_ADDED
]);
215 cl_assert_equal_i(4, exp
.file_status
[GIT_DELTA_DELETED
]);
216 cl_assert_equal_i(4, exp
.file_status
[GIT_DELTA_MODIFIED
]);
217 cl_assert_equal_i(1, exp
.file_status
[GIT_DELTA_IGNORED
]);
218 cl_assert_equal_i(5, exp
.file_status
[GIT_DELTA_UNTRACKED
]);
221 /* Since there is no git diff equivalent, let's just assume that the
222 * text diffs produced by git_diff_foreach are accurate here. We will
223 * do more apples-to-apples test comparison below.
228 memset(&exp
, 0, sizeof(exp
));
230 /* This is a compatible emulation of "git diff <sha>" which looks like
231 * a workdir to tree diff (even though it is not really). This is what
232 * you would get from "git diff --name-status 26a125ee1bf"
234 cl_git_pass(git_diff_tree_to_index(&diff
, g_repo
, a
, NULL
, &opts
));
235 cl_git_pass(git_diff_index_to_workdir(&diff2
, g_repo
, NULL
, &opts
));
236 cl_git_pass(git_diff_merge(diff
, diff2
));
237 git_diff_free(diff2
);
239 for (use_iterator
= 0; use_iterator
<= 1; use_iterator
++) {
240 memset(&exp
, 0, sizeof(exp
));
243 cl_git_pass(diff_foreach_via_iterator(
244 diff
, diff_file_cb
, diff_hunk_cb
, diff_line_cb
, &exp
));
246 cl_git_pass(git_diff_foreach(
247 diff
, diff_file_cb
, diff_hunk_cb
, diff_line_cb
, &exp
));
249 cl_assert_equal_i(15, exp
.files
);
250 cl_assert_equal_i(2, exp
.file_status
[GIT_DELTA_ADDED
]);
251 cl_assert_equal_i(5, exp
.file_status
[GIT_DELTA_DELETED
]);
252 cl_assert_equal_i(4, exp
.file_status
[GIT_DELTA_MODIFIED
]);
253 cl_assert_equal_i(1, exp
.file_status
[GIT_DELTA_IGNORED
]);
254 cl_assert_equal_i(3, exp
.file_status
[GIT_DELTA_UNTRACKED
]);
256 cl_assert_equal_i(11, exp
.hunks
);
258 cl_assert_equal_i(17, exp
.lines
);
259 cl_assert_equal_i(4, exp
.line_ctxt
);
260 cl_assert_equal_i(8, exp
.line_adds
);
261 cl_assert_equal_i(5, exp
.line_dels
);
266 memset(&exp
, 0, sizeof(exp
));
268 /* Again, emulating "git diff <sha>" for testing purposes using
269 * "git diff --name-status 0017bd4ab1ec3" instead.
271 cl_git_pass(git_diff_tree_to_index(&diff
, g_repo
, b
, NULL
, &opts
));
272 cl_git_pass(git_diff_index_to_workdir(&diff2
, g_repo
, NULL
, &opts
));
273 cl_git_pass(git_diff_merge(diff
, diff2
));
274 git_diff_free(diff2
);
276 for (use_iterator
= 0; use_iterator
<= 1; use_iterator
++) {
277 memset(&exp
, 0, sizeof(exp
));
280 cl_git_pass(diff_foreach_via_iterator(
281 diff
, diff_file_cb
, diff_hunk_cb
, diff_line_cb
, &exp
));
283 cl_git_pass(git_diff_foreach(
284 diff
, diff_file_cb
, diff_hunk_cb
, diff_line_cb
, &exp
));
286 cl_assert_equal_i(16, exp
.files
);
287 cl_assert_equal_i(5, exp
.file_status
[GIT_DELTA_ADDED
]);
288 cl_assert_equal_i(4, exp
.file_status
[GIT_DELTA_DELETED
]);
289 cl_assert_equal_i(3, exp
.file_status
[GIT_DELTA_MODIFIED
]);
290 cl_assert_equal_i(1, exp
.file_status
[GIT_DELTA_IGNORED
]);
291 cl_assert_equal_i(3, exp
.file_status
[GIT_DELTA_UNTRACKED
]);
293 cl_assert_equal_i(12, exp
.hunks
);
295 cl_assert_equal_i(19, exp
.lines
);
296 cl_assert_equal_i(3, exp
.line_ctxt
);
297 cl_assert_equal_i(12, exp
.line_adds
);
298 cl_assert_equal_i(4, exp
.line_dels
);
303 /* Let's try that once more with a reversed diff */
305 opts
.flags
|= GIT_DIFF_REVERSE
;
307 cl_git_pass(git_diff_tree_to_index(&diff
, g_repo
, b
, NULL
, &opts
));
308 cl_git_pass(git_diff_index_to_workdir(&diff2
, g_repo
, NULL
, &opts
));
309 cl_git_pass(git_diff_merge(diff
, diff2
));
310 git_diff_free(diff2
);
312 memset(&exp
, 0, sizeof(exp
));
314 cl_git_pass(git_diff_foreach(
315 diff
, diff_file_cb
, diff_hunk_cb
, diff_line_cb
, &exp
));
317 cl_assert_equal_i(16, exp
.files
);
318 cl_assert_equal_i(5, exp
.file_status
[GIT_DELTA_DELETED
]);
319 cl_assert_equal_i(4, exp
.file_status
[GIT_DELTA_ADDED
]);
320 cl_assert_equal_i(3, exp
.file_status
[GIT_DELTA_MODIFIED
]);
321 cl_assert_equal_i(1, exp
.file_status
[GIT_DELTA_IGNORED
]);
322 cl_assert_equal_i(3, exp
.file_status
[GIT_DELTA_UNTRACKED
]);
324 cl_assert_equal_i(12, exp
.hunks
);
326 cl_assert_equal_i(19, exp
.lines
);
327 cl_assert_equal_i(3, exp
.line_ctxt
);
328 cl_assert_equal_i(12, exp
.line_dels
);
329 cl_assert_equal_i(4, exp
.line_adds
);
339 void test_diff_workdir__to_index_with_pathspec(void)
341 git_diff_options opts
= GIT_DIFF_OPTIONS_INIT
;
342 git_diff
*diff
= NULL
;
344 char *pathspec
= NULL
;
347 g_repo
= cl_git_sandbox_init("status");
349 opts
.context_lines
= 3;
350 opts
.interhunk_lines
= 1;
351 opts
.flags
|= GIT_DIFF_INCLUDE_IGNORED
| GIT_DIFF_INCLUDE_UNTRACKED
;
352 opts
.pathspec
.strings
= &pathspec
;
353 opts
.pathspec
.count
= 1;
355 cl_git_pass(git_diff_index_to_workdir(&diff
, g_repo
, NULL
, &opts
));
357 for (use_iterator
= 0; use_iterator
<= 1; use_iterator
++) {
358 memset(&exp
, 0, sizeof(exp
));
361 cl_git_pass(diff_foreach_via_iterator(
362 diff
, diff_file_cb
, NULL
, NULL
, &exp
));
364 cl_git_pass(git_diff_foreach(diff
, diff_file_cb
, NULL
, NULL
, &exp
));
366 cl_assert_equal_i(13, exp
.files
);
367 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_ADDED
]);
368 cl_assert_equal_i(4, exp
.file_status
[GIT_DELTA_DELETED
]);
369 cl_assert_equal_i(4, exp
.file_status
[GIT_DELTA_MODIFIED
]);
370 cl_assert_equal_i(1, exp
.file_status
[GIT_DELTA_IGNORED
]);
371 cl_assert_equal_i(4, exp
.file_status
[GIT_DELTA_UNTRACKED
]);
376 pathspec
= "modified_file";
378 cl_git_pass(git_diff_index_to_workdir(&diff
, g_repo
, NULL
, &opts
));
380 for (use_iterator
= 0; use_iterator
<= 1; use_iterator
++) {
381 memset(&exp
, 0, sizeof(exp
));
384 cl_git_pass(diff_foreach_via_iterator(
385 diff
, diff_file_cb
, NULL
, NULL
, &exp
));
387 cl_git_pass(git_diff_foreach(diff
, diff_file_cb
, NULL
, NULL
, &exp
));
389 cl_assert_equal_i(1, exp
.files
);
390 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_ADDED
]);
391 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_DELETED
]);
392 cl_assert_equal_i(1, exp
.file_status
[GIT_DELTA_MODIFIED
]);
393 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_IGNORED
]);
394 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_UNTRACKED
]);
401 cl_git_pass(git_diff_index_to_workdir(&diff
, g_repo
, NULL
, &opts
));
403 for (use_iterator
= 0; use_iterator
<= 1; use_iterator
++) {
404 memset(&exp
, 0, sizeof(exp
));
407 cl_git_pass(diff_foreach_via_iterator(
408 diff
, diff_file_cb
, NULL
, NULL
, &exp
));
410 cl_git_pass(git_diff_foreach(diff
, diff_file_cb
, NULL
, NULL
, &exp
));
412 cl_assert_equal_i(3, exp
.files
);
413 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_ADDED
]);
414 cl_assert_equal_i(1, exp
.file_status
[GIT_DELTA_DELETED
]);
415 cl_assert_equal_i(1, exp
.file_status
[GIT_DELTA_MODIFIED
]);
416 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_IGNORED
]);
417 cl_assert_equal_i(1, exp
.file_status
[GIT_DELTA_UNTRACKED
]);
422 pathspec
= "*_deleted";
424 cl_git_pass(git_diff_index_to_workdir(&diff
, g_repo
, NULL
, &opts
));
426 for (use_iterator
= 0; use_iterator
<= 1; use_iterator
++) {
427 memset(&exp
, 0, sizeof(exp
));
430 cl_git_pass(diff_foreach_via_iterator(
431 diff
, diff_file_cb
, NULL
, NULL
, &exp
));
433 cl_git_pass(git_diff_foreach(diff
, diff_file_cb
, NULL
, NULL
, &exp
));
435 cl_assert_equal_i(2, exp
.files
);
436 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_ADDED
]);
437 cl_assert_equal_i(2, exp
.file_status
[GIT_DELTA_DELETED
]);
438 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_MODIFIED
]);
439 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_IGNORED
]);
440 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_UNTRACKED
]);
446 void test_diff_workdir__filemode_changes(void)
448 git_diff
*diff
= NULL
;
452 if (!cl_is_chmod_supported())
455 g_repo
= cl_git_sandbox_init("issue_592");
457 cl_repo_set_bool(g_repo
, "core.filemode", true);
459 /* test once with no mods */
461 cl_git_pass(git_diff_index_to_workdir(&diff
, g_repo
, NULL
, NULL
));
463 for (use_iterator
= 0; use_iterator
<= 1; use_iterator
++) {
464 memset(&exp
, 0, sizeof(exp
));
467 cl_git_pass(diff_foreach_via_iterator(
468 diff
, diff_file_cb
, diff_hunk_cb
, diff_line_cb
, &exp
));
470 cl_git_pass(git_diff_foreach(
471 diff
, diff_file_cb
, diff_hunk_cb
, diff_line_cb
, &exp
));
473 cl_assert_equal_i(0, exp
.files
);
474 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_MODIFIED
]);
475 cl_assert_equal_i(0, exp
.hunks
);
480 /* chmod file and test again */
482 cl_assert(cl_toggle_filemode("issue_592/a.txt"));
484 cl_git_pass(git_diff_index_to_workdir(&diff
, g_repo
, NULL
, NULL
));
486 for (use_iterator
= 0; use_iterator
<= 1; use_iterator
++) {
487 memset(&exp
, 0, sizeof(exp
));
490 cl_git_pass(diff_foreach_via_iterator(
491 diff
, diff_file_cb
, diff_hunk_cb
, diff_line_cb
, &exp
));
493 cl_git_pass(git_diff_foreach(
494 diff
, diff_file_cb
, diff_hunk_cb
, diff_line_cb
, &exp
));
496 cl_assert_equal_i(1, exp
.files
);
497 cl_assert_equal_i(1, exp
.file_status
[GIT_DELTA_MODIFIED
]);
498 cl_assert_equal_i(0, exp
.hunks
);
503 cl_assert(cl_toggle_filemode("issue_592/a.txt"));
506 void test_diff_workdir__filemode_changes_with_filemode_false(void)
508 git_diff
*diff
= NULL
;
511 if (!cl_is_chmod_supported())
514 g_repo
= cl_git_sandbox_init("issue_592");
516 cl_repo_set_bool(g_repo
, "core.filemode", false);
518 /* test once with no mods */
520 cl_git_pass(git_diff_index_to_workdir(&diff
, g_repo
, NULL
, NULL
));
522 memset(&exp
, 0, sizeof(exp
));
523 cl_git_pass(git_diff_foreach(
524 diff
, diff_file_cb
, diff_hunk_cb
, diff_line_cb
, &exp
));
526 cl_assert_equal_i(0, exp
.files
);
527 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_MODIFIED
]);
528 cl_assert_equal_i(0, exp
.hunks
);
532 /* chmod file and test again */
534 cl_assert(cl_toggle_filemode("issue_592/a.txt"));
536 cl_git_pass(git_diff_index_to_workdir(&diff
, g_repo
, NULL
, NULL
));
538 memset(&exp
, 0, sizeof(exp
));
539 cl_git_pass(git_diff_foreach(
540 diff
, diff_file_cb
, diff_hunk_cb
, diff_line_cb
, &exp
));
542 cl_assert_equal_i(0, exp
.files
);
543 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_MODIFIED
]);
544 cl_assert_equal_i(0, exp
.hunks
);
548 cl_assert(cl_toggle_filemode("issue_592/a.txt"));
551 void test_diff_workdir__head_index_and_workdir_all_differ(void)
553 git_diff_options opts
= GIT_DIFF_OPTIONS_INIT
;
554 git_diff
*diff_i2t
= NULL
, *diff_w2i
= NULL
;
556 char *pathspec
= "staged_changes_modified_file";
561 * - head->index diff has 1 line of context, 1 line of diff
562 * - index->workdir diff has 2 lines of context, 1 line of diff
564 * - head->workdir diff has 1 line of context, 2 lines of diff
565 * Let's make sure the right one is returned from each fn.
568 g_repo
= cl_git_sandbox_init("status");
570 tree
= resolve_commit_oid_to_tree(g_repo
, "26a125ee1bfc5df1e1b2e9441bbe63c8a7ae989f");
572 opts
.pathspec
.strings
= &pathspec
;
573 opts
.pathspec
.count
= 1;
575 cl_git_pass(git_diff_tree_to_index(&diff_i2t
, g_repo
, tree
, NULL
, &opts
));
576 cl_git_pass(git_diff_index_to_workdir(&diff_w2i
, g_repo
, NULL
, &opts
));
578 for (use_iterator
= 0; use_iterator
<= 1; use_iterator
++) {
579 memset(&exp
, 0, sizeof(exp
));
582 cl_git_pass(diff_foreach_via_iterator(
583 diff_i2t
, diff_file_cb
, diff_hunk_cb
, diff_line_cb
, &exp
));
585 cl_git_pass(git_diff_foreach(
586 diff_i2t
, diff_file_cb
, diff_hunk_cb
, diff_line_cb
, &exp
));
588 cl_assert_equal_i(1, exp
.files
);
589 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_ADDED
]);
590 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_DELETED
]);
591 cl_assert_equal_i(1, exp
.file_status
[GIT_DELTA_MODIFIED
]);
592 cl_assert_equal_i(1, exp
.hunks
);
593 cl_assert_equal_i(2, exp
.lines
);
594 cl_assert_equal_i(1, exp
.line_ctxt
);
595 cl_assert_equal_i(1, exp
.line_adds
);
596 cl_assert_equal_i(0, exp
.line_dels
);
599 for (use_iterator
= 0; use_iterator
<= 1; use_iterator
++) {
600 memset(&exp
, 0, sizeof(exp
));
603 cl_git_pass(diff_foreach_via_iterator(
604 diff_w2i
, diff_file_cb
, diff_hunk_cb
, diff_line_cb
, &exp
));
606 cl_git_pass(git_diff_foreach(
607 diff_w2i
, diff_file_cb
, diff_hunk_cb
, diff_line_cb
, &exp
));
609 cl_assert_equal_i(1, exp
.files
);
610 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_ADDED
]);
611 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_DELETED
]);
612 cl_assert_equal_i(1, exp
.file_status
[GIT_DELTA_MODIFIED
]);
613 cl_assert_equal_i(1, exp
.hunks
);
614 cl_assert_equal_i(3, exp
.lines
);
615 cl_assert_equal_i(2, exp
.line_ctxt
);
616 cl_assert_equal_i(1, exp
.line_adds
);
617 cl_assert_equal_i(0, exp
.line_dels
);
620 cl_git_pass(git_diff_merge(diff_i2t
, diff_w2i
));
622 for (use_iterator
= 0; use_iterator
<= 1; use_iterator
++) {
623 memset(&exp
, 0, sizeof(exp
));
626 cl_git_pass(diff_foreach_via_iterator(
627 diff_i2t
, diff_file_cb
, diff_hunk_cb
, diff_line_cb
, &exp
));
629 cl_git_pass(git_diff_foreach(
630 diff_i2t
, diff_file_cb
, diff_hunk_cb
, diff_line_cb
, &exp
));
632 cl_assert_equal_i(1, exp
.files
);
633 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_ADDED
]);
634 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_DELETED
]);
635 cl_assert_equal_i(1, exp
.file_status
[GIT_DELTA_MODIFIED
]);
636 cl_assert_equal_i(1, exp
.hunks
);
637 cl_assert_equal_i(3, exp
.lines
);
638 cl_assert_equal_i(1, exp
.line_ctxt
);
639 cl_assert_equal_i(2, exp
.line_adds
);
640 cl_assert_equal_i(0, exp
.line_dels
);
643 git_diff_free(diff_i2t
);
644 git_diff_free(diff_w2i
);
649 void test_diff_workdir__eof_newline_changes(void)
651 git_diff_options opts
= GIT_DIFF_OPTIONS_INIT
;
652 git_diff
*diff
= NULL
;
654 char *pathspec
= "current_file";
657 g_repo
= cl_git_sandbox_init("status");
659 opts
.pathspec
.strings
= &pathspec
;
660 opts
.pathspec
.count
= 1;
662 cl_git_pass(git_diff_index_to_workdir(&diff
, g_repo
, NULL
, &opts
));
664 for (use_iterator
= 0; use_iterator
<= 1; use_iterator
++) {
665 memset(&exp
, 0, sizeof(exp
));
668 cl_git_pass(diff_foreach_via_iterator(
669 diff
, diff_file_cb
, diff_hunk_cb
, diff_line_cb
, &exp
));
671 cl_git_pass(git_diff_foreach(
672 diff
, diff_file_cb
, diff_hunk_cb
, diff_line_cb
, &exp
));
674 cl_assert_equal_i(0, exp
.files
);
675 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_ADDED
]);
676 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_DELETED
]);
677 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_MODIFIED
]);
678 cl_assert_equal_i(0, exp
.hunks
);
679 cl_assert_equal_i(0, exp
.lines
);
680 cl_assert_equal_i(0, exp
.line_ctxt
);
681 cl_assert_equal_i(0, exp
.line_adds
);
682 cl_assert_equal_i(0, exp
.line_dels
);
687 cl_git_append2file("status/current_file", "\n");
689 cl_git_pass(git_diff_index_to_workdir(&diff
, g_repo
, NULL
, &opts
));
691 for (use_iterator
= 0; use_iterator
<= 1; use_iterator
++) {
692 memset(&exp
, 0, sizeof(exp
));
695 cl_git_pass(diff_foreach_via_iterator(
696 diff
, diff_file_cb
, diff_hunk_cb
, diff_line_cb
, &exp
));
698 cl_git_pass(git_diff_foreach(
699 diff
, diff_file_cb
, diff_hunk_cb
, diff_line_cb
, &exp
));
701 cl_assert_equal_i(1, exp
.files
);
702 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_ADDED
]);
703 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_DELETED
]);
704 cl_assert_equal_i(1, exp
.file_status
[GIT_DELTA_MODIFIED
]);
705 cl_assert_equal_i(1, exp
.hunks
);
706 cl_assert_equal_i(2, exp
.lines
);
707 cl_assert_equal_i(1, exp
.line_ctxt
);
708 cl_assert_equal_i(1, exp
.line_adds
);
709 cl_assert_equal_i(0, exp
.line_dels
);
714 cl_git_rewritefile("status/current_file", "current_file");
716 cl_git_pass(git_diff_index_to_workdir(&diff
, g_repo
, NULL
, &opts
));
718 for (use_iterator
= 0; use_iterator
<= 1; use_iterator
++) {
719 memset(&exp
, 0, sizeof(exp
));
722 cl_git_pass(diff_foreach_via_iterator(
723 diff
, diff_file_cb
, diff_hunk_cb
, diff_line_cb
, &exp
));
725 cl_git_pass(git_diff_foreach(
726 diff
, diff_file_cb
, diff_hunk_cb
, diff_line_cb
, &exp
));
728 cl_assert_equal_i(1, exp
.files
);
729 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_ADDED
]);
730 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_DELETED
]);
731 cl_assert_equal_i(1, exp
.file_status
[GIT_DELTA_MODIFIED
]);
732 cl_assert_equal_i(1, exp
.hunks
);
733 cl_assert_equal_i(3, exp
.lines
);
734 cl_assert_equal_i(0, exp
.line_ctxt
);
735 cl_assert_equal_i(1, exp
.line_adds
);
736 cl_assert_equal_i(2, exp
.line_dels
);
742 /* PREPARATION OF TEST DATA
744 * Since there is no command line equivalent of git_diff_tree_to_workdir,
745 * it was a bit of a pain to confirm that I was getting the expected
746 * results in the first part of this tests. Here is what I ended up
747 * doing to set my expectation for the file counts and results:
749 * Running "git ls-tree 26a125" and "git ls-tree aa27a6" shows:
751 * A a0de7e0ac200c489c41c59dfa910154a70264e6e current_file
752 * B 5452d32f1dd538eb0405e8a83cc185f79e25e80f file_deleted
753 * C 452e4244b5d083ddf0460acf1ecc74db9dcfa11a modified_file
754 * D 32504b727382542f9f089e24fddac5e78533e96c staged_changes
755 * E 061d42a44cacde5726057b67558821d95db96f19 staged_changes_file_deleted
756 * F 70bd9443ada07063e7fbf0b3ff5c13f7494d89c2 staged_changes_modified_file
757 * G e9b9107f290627c04d097733a10055af941f6bca staged_delete_file_deleted
758 * H dabc8af9bd6e9f5bbe96a176f1a24baf3d1f8916 staged_delete_modified_file
759 * I 53ace0d1cc1145a5f4fe4f78a186a60263190733 subdir/current_file
760 * J 1888c805345ba265b0ee9449b8877b6064592058 subdir/deleted_file
761 * K a6191982709b746d5650e93c2acf34ef74e11504 subdir/modified_file
762 * L e8ee89e15bbe9b20137715232387b3de5b28972e subdir.txt
766 * find . ! -path ./.git/\* -a -type f | git hash-object --stdin-paths
768 * A a0de7e0ac200c489c41c59dfa910154a70264e6e current_file
769 * M 6a79f808a9c6bc9531ac726c184bbcd9351ccf11 ignored_file
770 * C 0a539630525aca2e7bc84975958f92f10a64c9b6 modified_file
771 * N d4fa8600b4f37d7516bef4816ae2c64dbf029e3a new_file
772 * D 55d316c9ba708999f1918e9677d01dfcae69c6b9 staged_changes
773 * F 011c3440d5c596e21d836aa6d7b10eb581f68c49 staged_changes_modified_file
774 * H dabc8af9bd6e9f5bbe96a176f1a24baf3d1f8916 staged_delete_modified_file
775 * O 529a16e8e762d4acb7b9636ff540a00831f9155a staged_new_file
776 * P 8b090c06d14ffa09c4e880088ebad33893f921d1 staged_new_file_modified_file
777 * I 53ace0d1cc1145a5f4fe4f78a186a60263190733 subdir/current_file
778 * K 57274b75eeb5f36fd55527806d567b2240a20c57 subdir/modified_file
779 * Q 80a86a6931b91bc01c2dbf5ca55bdd24ad1ef466 subdir/new_file
780 * L e8ee89e15bbe9b20137715232387b3de5b28972e subdir.txt
784 * A - current_file (UNMODIFIED) -> not in results
786 * M I ignored_file (IGNORED)
788 * N U new_file (UNTRACKED)
790 * E D staged_changes_file_deleted
791 * F M staged_changes_modified_file
792 * G D staged_delete_file_deleted
793 * H - staged_delete_modified_file (UNMODIFIED) -> not in results
794 * O U staged_new_file
795 * P U staged_new_file_modified_file
796 * I - subdir/current_file (UNMODIFIED) -> not in results
797 * J D subdir/deleted_file
798 * K M subdir/modified_file
799 * Q U subdir/new_file
800 * L - subdir.txt (UNMODIFIED) -> not in results
802 * Expect 13 files, 0 ADD, 4 DEL, 4 MOD, 1 IGN, 4 UNTR
806 void test_diff_workdir__larger_hunks(void)
808 const char *a_commit
= "d70d245ed97ed2aa596dd1af6536e4bfdb047b69";
809 const char *b_commit
= "7a9e0b02e63179929fed24f0a3e0f19168114d10";
811 git_diff_options opts
= GIT_DIFF_OPTIONS_INIT
;
812 size_t i
, d
, num_d
, h
, num_h
, l
, num_l
;
814 g_repo
= cl_git_sandbox_init("diff");
816 cl_assert((a
= resolve_commit_oid_to_tree(g_repo
, a_commit
)) != NULL
);
817 cl_assert((b
= resolve_commit_oid_to_tree(g_repo
, b_commit
)) != NULL
);
819 opts
.context_lines
= 1;
820 opts
.interhunk_lines
= 0;
822 for (i
= 0; i
<= 2; ++i
) {
823 git_diff
*diff
= NULL
;
825 const git_diff_hunk
*hunk
;
826 const git_diff_line
*line
;
828 /* okay, this is a bit silly, but oh well */
831 cl_git_pass(git_diff_index_to_workdir(&diff
, g_repo
, NULL
, &opts
));
834 cl_git_pass(git_diff_tree_to_workdir(&diff
, g_repo
, a
, &opts
));
837 cl_git_pass(git_diff_tree_to_workdir(&diff
, g_repo
, b
, &opts
));
841 num_d
= git_diff_num_deltas(diff
);
842 cl_assert_equal_i(2, (int)num_d
);
844 for (d
= 0; d
< num_d
; ++d
) {
845 cl_git_pass(git_patch_from_diff(&patch
, diff
, d
));
848 num_h
= git_patch_num_hunks(patch
);
849 for (h
= 0; h
< num_h
; h
++) {
850 cl_git_pass(git_patch_get_hunk(&hunk
, &num_l
, patch
, h
));
852 for (l
= 0; l
< num_l
; ++l
) {
854 git_patch_get_line_in_hunk(&line
, patch
, h
, l
));
858 /* confirm fail after the last item */
860 git_patch_get_line_in_hunk(&line
, patch
, h
, num_l
));
863 /* confirm fail after the last item */
864 cl_git_fail(git_patch_get_hunk(&hunk
, &num_l
, patch
, num_h
));
866 git_patch_free(patch
);
876 /* Set up a test that exercises this code. The easiest test using existing
877 * test data is probably to create a sandbox of submod2 and then run a
878 * git_diff_tree_to_workdir against tree
879 * 873585b94bdeabccea991ea5e3ec1a277895b698. As for what you should actually
880 * test, you can start by just checking that the number of lines of diff
881 * content matches the actual output of git diff. That will at least
882 * demonstrate that the submodule content is being used to generate somewhat
883 * comparable outputs. It is a test that would fail without this code and
884 * will succeed with it.
887 #include "../submodule/submodule_helpers.h"
889 void test_diff_workdir__submodules(void)
891 const char *a_commit
= "873585b94bdeabccea991ea5e3ec1a277895b698";
893 git_diff_options opts
= GIT_DIFF_OPTIONS_INIT
;
894 git_diff
*diff
= NULL
;
897 g_repo
= setup_fixture_submod2();
899 a
= resolve_commit_oid_to_tree(g_repo
, a_commit
);
902 GIT_DIFF_INCLUDE_UNTRACKED
|
903 GIT_DIFF_INCLUDE_IGNORED
|
904 GIT_DIFF_RECURSE_UNTRACKED_DIRS
|
905 GIT_DIFF_SHOW_UNTRACKED_CONTENT
;
907 cl_git_pass(git_diff_tree_to_workdir(&diff
, g_repo
, a
, &opts
));
909 /* diff_print(stderr, diff); */
911 /* essentially doing: git diff 873585b94bdeabccea991ea5e3ec1a277895b698 */
913 memset(&exp
, 0, sizeof(exp
));
915 cl_git_pass(git_diff_foreach(
916 diff
, diff_file_cb
, diff_hunk_cb
, diff_line_cb
, &exp
));
918 /* so "git diff 873585" returns:
920 * A just_a_dir/contents
922 * A sm_added_and_uncommited
926 * A sm_changed_untracked_file
927 * M sm_missing_commits
929 * which is a little deceptive because of the difference between the
930 * "git diff <treeish>" results from "git_diff_tree_to_workdir". The
931 * only significant difference is that those Added items will show up
932 * as Untracked items in the pure libgit2 diff.
934 * Then add in the two extra untracked items "not" and "not-submodule"
935 * to get the 12 files reported here.
938 cl_assert_equal_i(12, exp
.files
);
940 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_ADDED
]);
941 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_DELETED
]);
942 cl_assert_equal_i(2, exp
.file_status
[GIT_DELTA_MODIFIED
]);
943 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_IGNORED
]);
944 cl_assert_equal_i(10, exp
.file_status
[GIT_DELTA_UNTRACKED
]);
946 /* the following numbers match "git diff 873585" exactly */
948 cl_assert_equal_i(9, exp
.hunks
);
950 cl_assert_equal_i(33, exp
.lines
);
951 cl_assert_equal_i(2, exp
.line_ctxt
);
952 cl_assert_equal_i(30, exp
.line_adds
);
953 cl_assert_equal_i(1, exp
.line_dels
);
959 void test_diff_workdir__cannot_diff_against_a_bare_repository(void)
961 git_diff_options opts
= GIT_DIFF_OPTIONS_INIT
;
962 git_diff
*diff
= NULL
;
965 g_repo
= cl_git_sandbox_init("testrepo.git");
968 GIT_EBAREREPO
, git_diff_index_to_workdir(&diff
, g_repo
, NULL
, &opts
));
970 cl_git_pass(git_repository_head_tree(&tree
, g_repo
));
973 GIT_EBAREREPO
, git_diff_tree_to_workdir(&diff
, g_repo
, tree
, &opts
));
978 void test_diff_workdir__to_null_tree(void)
982 git_diff_options opts
= GIT_DIFF_OPTIONS_INIT
;
984 opts
.flags
= GIT_DIFF_INCLUDE_UNTRACKED
|
985 GIT_DIFF_RECURSE_UNTRACKED_DIRS
;
987 g_repo
= cl_git_sandbox_init("status");
989 cl_git_pass(git_diff_tree_to_workdir(&diff
, g_repo
, NULL
, &opts
));
991 memset(&exp
, 0, sizeof(exp
));
993 cl_git_pass(git_diff_foreach(
994 diff
, diff_file_cb
, diff_hunk_cb
, diff_line_cb
, &exp
));
996 cl_assert_equal_i(exp
.files
, exp
.file_status
[GIT_DELTA_UNTRACKED
]);
1001 void test_diff_workdir__checks_options_version(void)
1004 git_diff_options opts
= GIT_DIFF_OPTIONS_INIT
;
1005 const git_error
*err
;
1007 g_repo
= cl_git_sandbox_init("status");
1010 cl_git_fail(git_diff_tree_to_workdir(&diff
, g_repo
, NULL
, &opts
));
1011 err
= giterr_last();
1012 cl_assert_equal_i(GITERR_INVALID
, err
->klass
);
1015 opts
.version
= 1024;
1016 cl_git_fail(git_diff_tree_to_workdir(&diff
, g_repo
, NULL
, &opts
));
1017 err
= giterr_last();
1018 cl_assert_equal_i(GITERR_INVALID
, err
->klass
);
1021 void test_diff_workdir__can_diff_empty_file(void)
1025 git_diff_options opts
= GIT_DIFF_OPTIONS_INIT
;
1029 g_repo
= cl_git_sandbox_init("attr_index");
1031 tree
= resolve_commit_oid_to_tree(g_repo
, "3812cfef3661"); /* HEAD */
1033 /* baseline - make sure there are no outstanding diffs */
1035 cl_git_pass(git_diff_tree_to_workdir(&diff
, g_repo
, tree
, &opts
));
1036 cl_assert_equal_i(2, (int)git_diff_num_deltas(diff
));
1037 git_diff_free(diff
);
1039 /* empty contents of file */
1041 cl_git_rewritefile("attr_index/README.txt", "");
1042 cl_git_pass(git_path_lstat("attr_index/README.txt", &st
));
1043 cl_assert_equal_i(0, (int)st
.st_size
);
1045 cl_git_pass(git_diff_tree_to_workdir(&diff
, g_repo
, tree
, &opts
));
1046 cl_assert_equal_i(3, (int)git_diff_num_deltas(diff
));
1047 /* diffs are: .gitattributes, README.txt, sub/sub/.gitattributes */
1048 cl_git_pass(git_patch_from_diff(&patch
, diff
, 1));
1049 git_patch_free(patch
);
1050 git_diff_free(diff
);
1052 /* remove a file altogether */
1054 cl_git_pass(p_unlink("attr_index/README.txt"));
1055 cl_assert(!git_path_exists("attr_index/README.txt"));
1057 cl_git_pass(git_diff_tree_to_workdir(&diff
, g_repo
, tree
, &opts
));
1058 cl_assert_equal_i(3, (int)git_diff_num_deltas(diff
));
1059 cl_git_pass(git_patch_from_diff(&patch
, diff
, 1));
1060 git_patch_free(patch
);
1061 git_diff_free(diff
);
1063 git_tree_free(tree
);
1066 void test_diff_workdir__to_index_issue_1397(void)
1068 git_diff_options opts
= GIT_DIFF_OPTIONS_INIT
;
1069 git_diff
*diff
= NULL
;
1072 g_repo
= cl_git_sandbox_init("issue_1397");
1074 cl_repo_set_bool(g_repo
, "core.autocrlf", true);
1076 opts
.context_lines
= 3;
1077 opts
.interhunk_lines
= 1;
1079 cl_git_pass(git_diff_index_to_workdir(&diff
, g_repo
, NULL
, &opts
));
1081 memset(&exp
, 0, sizeof(exp
));
1082 cl_git_pass(git_diff_foreach(
1083 diff
, diff_file_cb
, diff_hunk_cb
, diff_line_cb
, &exp
));
1085 cl_assert_equal_i(0, exp
.files
);
1086 cl_assert_equal_i(0, exp
.hunks
);
1087 cl_assert_equal_i(0, exp
.lines
);
1089 git_diff_free(diff
);
1092 cl_git_rewritefile("issue_1397/crlf_file.txt",
1093 "first line\r\nsecond line modified\r\nboth with crlf");
1095 cl_git_pass(git_diff_index_to_workdir(&diff
, g_repo
, NULL
, &opts
));
1097 memset(&exp
, 0, sizeof(exp
));
1098 cl_git_pass(git_diff_foreach(
1099 diff
, diff_file_cb
, diff_hunk_cb
, diff_line_cb
, &exp
));
1101 cl_assert_equal_i(1, exp
.files
);
1102 cl_assert_equal_i(1, exp
.file_status
[GIT_DELTA_MODIFIED
]);
1104 cl_assert_equal_i(1, exp
.hunks
);
1106 cl_assert_equal_i(5, exp
.lines
);
1107 cl_assert_equal_i(3, exp
.line_ctxt
);
1108 cl_assert_equal_i(1, exp
.line_adds
);
1109 cl_assert_equal_i(1, exp
.line_dels
);
1111 git_diff_free(diff
);
1114 void test_diff_workdir__to_tree_issue_1397(void)
1116 const char *a_commit
= "7f483a738"; /* the current HEAD */
1118 git_diff_options opts
= GIT_DIFF_OPTIONS_INIT
;
1119 git_diff
*diff
= NULL
;
1120 git_diff
*diff2
= NULL
;
1123 g_repo
= cl_git_sandbox_init("issue_1397");
1125 cl_repo_set_bool(g_repo
, "core.autocrlf", true);
1127 a
= resolve_commit_oid_to_tree(g_repo
, a_commit
);
1129 opts
.context_lines
= 3;
1130 opts
.interhunk_lines
= 1;
1132 cl_git_pass(git_diff_tree_to_workdir(&diff
, g_repo
, a
, &opts
));
1134 memset(&exp
, 0, sizeof(exp
));
1135 cl_git_pass(git_diff_foreach(
1136 diff
, diff_file_cb
, diff_hunk_cb
, diff_line_cb
, &exp
));
1138 cl_assert_equal_i(0, exp
.files
);
1139 cl_assert_equal_i(0, exp
.hunks
);
1140 cl_assert_equal_i(0, exp
.lines
);
1142 git_diff_free(diff
);
1145 cl_git_pass(git_diff_tree_to_index(&diff
, g_repo
, a
, NULL
, &opts
));
1146 cl_git_pass(git_diff_index_to_workdir(&diff2
, g_repo
, NULL
, &opts
));
1147 cl_git_pass(git_diff_merge(diff
, diff2
));
1148 git_diff_free(diff2
);
1150 memset(&exp
, 0, sizeof(exp
));
1151 cl_git_pass(git_diff_foreach(
1152 diff
, diff_file_cb
, diff_hunk_cb
, diff_line_cb
, &exp
));
1154 cl_assert_equal_i(0, exp
.files
);
1155 cl_assert_equal_i(0, exp
.hunks
);
1156 cl_assert_equal_i(0, exp
.lines
);
1158 git_diff_free(diff
);
1162 void test_diff_workdir__untracked_directory_scenarios(void)
1164 git_diff_options opts
= GIT_DIFF_OPTIONS_INIT
;
1165 git_diff
*diff
= NULL
;
1167 char *pathspec
= NULL
;
1168 static const char *files0
[] = {
1169 "subdir/deleted_file",
1170 "subdir/modified_file",
1174 static const char *files1
[] = {
1175 "subdir/deleted_file",
1176 "subdir/directory/",
1177 "subdir/modified_file",
1181 static const char *files2
[] = {
1182 "subdir/deleted_file",
1183 "subdir/directory/more/notignored",
1184 "subdir/modified_file",
1189 g_repo
= cl_git_sandbox_init("status");
1190 cl_git_mkfile("status/.gitignore", "ignored\n");
1192 opts
.context_lines
= 3;
1193 opts
.interhunk_lines
= 1;
1194 opts
.flags
|= GIT_DIFF_INCLUDE_IGNORED
| GIT_DIFF_INCLUDE_UNTRACKED
;
1195 opts
.pathspec
.strings
= &pathspec
;
1196 opts
.pathspec
.count
= 1;
1197 pathspec
= "subdir";
1199 /* baseline for "subdir" pathspec */
1201 memset(&exp
, 0, sizeof(exp
));
1204 cl_git_pass(git_diff_index_to_workdir(&diff
, g_repo
, NULL
, &opts
));
1206 cl_git_pass(git_diff_foreach(diff
, diff_file_cb
, NULL
, NULL
, &exp
));
1208 cl_assert_equal_i(3, exp
.files
);
1209 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_ADDED
]);
1210 cl_assert_equal_i(1, exp
.file_status
[GIT_DELTA_DELETED
]);
1211 cl_assert_equal_i(1, exp
.file_status
[GIT_DELTA_MODIFIED
]);
1212 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_IGNORED
]);
1213 cl_assert_equal_i(1, exp
.file_status
[GIT_DELTA_UNTRACKED
]);
1215 git_diff_free(diff
);
1217 /* empty directory */
1219 cl_git_pass(p_mkdir("status/subdir/directory", 0777));
1221 memset(&exp
, 0, sizeof(exp
));
1224 cl_git_pass(git_diff_index_to_workdir(&diff
, g_repo
, NULL
, &opts
));
1226 cl_git_pass(git_diff_foreach(diff
, diff_file_cb
, NULL
, NULL
, &exp
));
1228 cl_assert_equal_i(4, exp
.files
);
1229 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_ADDED
]);
1230 cl_assert_equal_i(1, exp
.file_status
[GIT_DELTA_DELETED
]);
1231 cl_assert_equal_i(1, exp
.file_status
[GIT_DELTA_MODIFIED
]);
1232 cl_assert_equal_i(1, exp
.file_status
[GIT_DELTA_IGNORED
]);
1233 cl_assert_equal_i(1, exp
.file_status
[GIT_DELTA_UNTRACKED
]);
1235 git_diff_free(diff
);
1237 /* empty directory in empty directory */
1239 cl_git_pass(p_mkdir("status/subdir/directory/empty", 0777));
1241 memset(&exp
, 0, sizeof(exp
));
1244 cl_git_pass(git_diff_index_to_workdir(&diff
, g_repo
, NULL
, &opts
));
1246 cl_git_pass(git_diff_foreach(diff
, diff_file_cb
, NULL
, NULL
, &exp
));
1248 cl_assert_equal_i(4, exp
.files
);
1249 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_ADDED
]);
1250 cl_assert_equal_i(1, exp
.file_status
[GIT_DELTA_DELETED
]);
1251 cl_assert_equal_i(1, exp
.file_status
[GIT_DELTA_MODIFIED
]);
1252 cl_assert_equal_i(1, exp
.file_status
[GIT_DELTA_IGNORED
]);
1253 cl_assert_equal_i(1, exp
.file_status
[GIT_DELTA_UNTRACKED
]);
1255 git_diff_free(diff
);
1257 /* directory with only ignored files */
1259 cl_git_pass(p_mkdir("status/subdir/directory/deeper", 0777));
1260 cl_git_mkfile("status/subdir/directory/deeper/ignored", "ignore me\n");
1262 cl_git_pass(p_mkdir("status/subdir/directory/another", 0777));
1263 cl_git_mkfile("status/subdir/directory/another/ignored", "ignore me\n");
1265 memset(&exp
, 0, sizeof(exp
));
1268 cl_git_pass(git_diff_index_to_workdir(&diff
, g_repo
, NULL
, &opts
));
1270 cl_git_pass(git_diff_foreach(diff
, diff_file_cb
, NULL
, NULL
, &exp
));
1272 cl_assert_equal_i(4, exp
.files
);
1273 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_ADDED
]);
1274 cl_assert_equal_i(1, exp
.file_status
[GIT_DELTA_DELETED
]);
1275 cl_assert_equal_i(1, exp
.file_status
[GIT_DELTA_MODIFIED
]);
1276 cl_assert_equal_i(1, exp
.file_status
[GIT_DELTA_IGNORED
]);
1277 cl_assert_equal_i(1, exp
.file_status
[GIT_DELTA_UNTRACKED
]);
1279 git_diff_free(diff
);
1281 /* directory with ignored directory (contents irrelevant) */
1283 cl_git_pass(p_mkdir("status/subdir/directory/more", 0777));
1284 cl_git_pass(p_mkdir("status/subdir/directory/more/ignored", 0777));
1285 cl_git_mkfile("status/subdir/directory/more/ignored/notignored",
1286 "inside ignored dir\n");
1288 memset(&exp
, 0, sizeof(exp
));
1291 cl_git_pass(git_diff_index_to_workdir(&diff
, g_repo
, NULL
, &opts
));
1293 cl_git_pass(git_diff_foreach(diff
, diff_file_cb
, NULL
, NULL
, &exp
));
1295 cl_assert_equal_i(4, exp
.files
);
1296 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_ADDED
]);
1297 cl_assert_equal_i(1, exp
.file_status
[GIT_DELTA_DELETED
]);
1298 cl_assert_equal_i(1, exp
.file_status
[GIT_DELTA_MODIFIED
]);
1299 cl_assert_equal_i(1, exp
.file_status
[GIT_DELTA_IGNORED
]);
1300 cl_assert_equal_i(1, exp
.file_status
[GIT_DELTA_UNTRACKED
]);
1302 git_diff_free(diff
);
1304 /* quick version avoids directory scan */
1306 opts
.flags
= opts
.flags
| GIT_DIFF_ENABLE_FAST_UNTRACKED_DIRS
;
1308 memset(&exp
, 0, sizeof(exp
));
1311 cl_git_pass(git_diff_index_to_workdir(&diff
, g_repo
, NULL
, &opts
));
1313 cl_git_pass(git_diff_foreach(diff
, diff_file_cb
, NULL
, NULL
, &exp
));
1315 cl_assert_equal_i(4, exp
.files
);
1316 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_ADDED
]);
1317 cl_assert_equal_i(1, exp
.file_status
[GIT_DELTA_DELETED
]);
1318 cl_assert_equal_i(1, exp
.file_status
[GIT_DELTA_MODIFIED
]);
1319 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_IGNORED
]);
1320 cl_assert_equal_i(2, exp
.file_status
[GIT_DELTA_UNTRACKED
]);
1322 git_diff_free(diff
);
1324 /* directory with nested non-ignored content */
1326 opts
.flags
= opts
.flags
& ~GIT_DIFF_ENABLE_FAST_UNTRACKED_DIRS
;
1328 cl_git_mkfile("status/subdir/directory/more/notignored",
1329 "not ignored deep under untracked\n");
1331 memset(&exp
, 0, sizeof(exp
));
1334 cl_git_pass(git_diff_index_to_workdir(&diff
, g_repo
, NULL
, &opts
));
1336 cl_git_pass(git_diff_foreach(diff
, diff_file_cb
, NULL
, NULL
, &exp
));
1338 cl_assert_equal_i(4, exp
.files
);
1339 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_ADDED
]);
1340 cl_assert_equal_i(1, exp
.file_status
[GIT_DELTA_DELETED
]);
1341 cl_assert_equal_i(1, exp
.file_status
[GIT_DELTA_MODIFIED
]);
1342 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_IGNORED
]);
1343 cl_assert_equal_i(2, exp
.file_status
[GIT_DELTA_UNTRACKED
]);
1345 git_diff_free(diff
);
1347 /* use RECURSE_UNTRACKED_DIRS to get actual untracked files (no ignores) */
1349 opts
.flags
= opts
.flags
& ~GIT_DIFF_INCLUDE_IGNORED
;
1350 opts
.flags
= opts
.flags
| GIT_DIFF_RECURSE_UNTRACKED_DIRS
;
1352 memset(&exp
, 0, sizeof(exp
));
1355 cl_git_pass(git_diff_index_to_workdir(&diff
, g_repo
, NULL
, &opts
));
1357 cl_git_pass(git_diff_foreach(diff
, diff_file_cb
, NULL
, NULL
, &exp
));
1359 cl_assert_equal_i(4, exp
.files
);
1360 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_ADDED
]);
1361 cl_assert_equal_i(1, exp
.file_status
[GIT_DELTA_DELETED
]);
1362 cl_assert_equal_i(1, exp
.file_status
[GIT_DELTA_MODIFIED
]);
1363 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_IGNORED
]);
1364 cl_assert_equal_i(2, exp
.file_status
[GIT_DELTA_UNTRACKED
]);
1366 git_diff_free(diff
);
1370 void test_diff_workdir__untracked_directory_comes_last(void)
1372 git_diff_options opts
= GIT_DIFF_OPTIONS_INIT
;
1373 git_diff
*diff
= NULL
;
1375 g_repo
= cl_git_sandbox_init("renames");
1377 cl_git_mkfile("renames/.gitignore", "*.ign\n");
1378 cl_git_pass(p_mkdir("renames/zzz_untracked", 0777));
1379 cl_git_mkfile("renames/zzz_untracked/an.ign", "ignore me please");
1380 cl_git_mkfile("renames/zzz_untracked/skip.ign", "ignore me really");
1381 cl_git_mkfile("renames/zzz_untracked/test.ign", "ignore me now");
1383 opts
.context_lines
= 3;
1384 opts
.interhunk_lines
= 1;
1385 opts
.flags
|= GIT_DIFF_INCLUDE_IGNORED
| GIT_DIFF_INCLUDE_UNTRACKED
;
1387 cl_git_pass(git_diff_index_to_workdir(&diff
, g_repo
, NULL
, &opts
));
1389 cl_assert(diff
!= NULL
);
1391 git_diff_free(diff
);
1394 void test_diff_workdir__untracked_with_bom(void)
1396 git_diff_options opts
= GIT_DIFF_OPTIONS_INIT
;
1397 git_diff
*diff
= NULL
;
1398 const git_diff_delta
*delta
;
1400 g_repo
= cl_git_sandbox_init("empty_standard_repo");
1401 cl_repo_set_bool(g_repo
, "core.autocrlf", true);
1403 cl_git_write2file("empty_standard_repo/bom.txt",
1404 "\xFF\xFE\x31\x00\x32\x00\x33\x00\x34\x00", 10, O_WRONLY
|O_CREAT
, 0664);
1407 GIT_DIFF_INCLUDE_UNTRACKED
| GIT_DIFF_SHOW_UNTRACKED_CONTENT
;
1409 cl_git_pass(git_diff_index_to_workdir(&diff
, g_repo
, NULL
, &opts
));
1411 cl_assert_equal_i(1, git_diff_num_deltas(diff
));
1412 cl_assert((delta
= git_diff_get_delta(diff
, 0)) != NULL
);
1413 cl_assert_equal_i(GIT_DELTA_UNTRACKED
, delta
->status
);
1415 /* not known at this point
1416 * cl_assert((delta->flags & GIT_DIFF_FLAG_BINARY) != 0);
1419 git_diff_free(diff
);
1422 void test_diff_workdir__patience_diff(void)
1425 git_diff_options opts
= GIT_DIFF_OPTIONS_INIT
;
1426 git_diff
*diff
= NULL
;
1427 git_patch
*patch
= NULL
;
1428 git_buf buf
= GIT_BUF_INIT
;
1429 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";
1430 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";
1432 g_repo
= cl_git_sandbox_init("empty_standard_repo");
1433 cl_repo_set_bool(g_repo
, "core.autocrlf", true);
1434 cl_git_pass(git_repository_index(&index
, g_repo
));
1437 "empty_standard_repo/test.txt",
1438 "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");
1439 cl_git_pass(git_index_add_bypath(index
, "test.txt"));
1440 cl_repo_commit_from_index(NULL
, g_repo
, NULL
, 1372350000, "Base");
1441 git_index_free(index
);
1444 "empty_standard_repo/test.txt",
1445 "When I wrote this\nI did not know\nI did not know\nhow to create\na patience diff\nanother problem\na minimal diff\n");
1447 cl_git_pass(git_diff_index_to_workdir(&diff
, g_repo
, NULL
, &opts
));
1448 cl_assert_equal_i(1, git_diff_num_deltas(diff
));
1449 cl_git_pass(git_patch_from_diff(&patch
, diff
, 0));
1450 cl_git_pass(git_patch_to_buf(&buf
, patch
));
1452 cl_assert_equal_s(expected_normal
, buf
.ptr
);
1453 git_buf_clear(&buf
);
1454 git_patch_free(patch
);
1455 git_diff_free(diff
);
1457 opts
.flags
|= GIT_DIFF_PATIENCE
;
1459 cl_git_pass(git_diff_index_to_workdir(&diff
, g_repo
, NULL
, &opts
));
1460 cl_assert_equal_i(1, git_diff_num_deltas(diff
));
1461 cl_git_pass(git_patch_from_diff(&patch
, diff
, 0));
1462 cl_git_pass(git_patch_to_buf(&buf
, patch
));
1464 cl_assert_equal_s(expected_patience
, buf
.ptr
);
1465 git_buf_clear(&buf
);
1468 git_patch_free(patch
);
1469 git_diff_free(diff
);
1472 void test_diff_workdir__with_stale_index(void)
1474 git_diff_options opts
= GIT_DIFF_OPTIONS_INIT
;
1475 git_diff
*diff
= NULL
;
1476 git_index
*idx
= NULL
;
1479 g_repo
= cl_git_sandbox_init("status");
1480 cl_git_pass(git_repository_index(&idx
, g_repo
));
1482 /* make the in-memory index invalid */
1486 cl_git_pass(git_repository_open(&r2
, "status"));
1487 cl_git_pass(git_repository_index(&idx2
, r2
));
1488 cl_git_pass(git_index_add_bypath(idx2
, "new_file"));
1489 cl_git_pass(git_index_add_bypath(idx2
, "subdir/new_file"));
1490 cl_git_pass(git_index_remove_bypath(idx2
, "staged_new_file"));
1491 cl_git_pass(git_index_remove_bypath(idx2
, "staged_changes_file_deleted"));
1492 cl_git_pass(git_index_write(idx2
));
1493 git_index_free(idx2
);
1494 git_repository_free(r2
);
1497 opts
.context_lines
= 3;
1498 opts
.interhunk_lines
= 1;
1499 opts
.flags
|= GIT_DIFF_INCLUDE_UNTRACKED
| GIT_DIFF_INCLUDE_UNMODIFIED
;
1501 /* first try with index pointer which should prevent reload */
1503 cl_git_pass(git_diff_index_to_workdir(&diff
, g_repo
, idx
, &opts
));
1505 memset(&exp
, 0, sizeof(exp
));
1507 cl_git_pass(git_diff_foreach(
1508 diff
, diff_file_cb
, diff_hunk_cb
, diff_line_cb
, &exp
));
1510 cl_assert_equal_i(17, exp
.files
);
1511 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_ADDED
]);
1512 cl_assert_equal_i(4, exp
.file_status
[GIT_DELTA_DELETED
]);
1513 cl_assert_equal_i(4, exp
.file_status
[GIT_DELTA_MODIFIED
]);
1514 cl_assert_equal_i(4, exp
.file_status
[GIT_DELTA_UNTRACKED
]);
1515 cl_assert_equal_i(5, exp
.file_status
[GIT_DELTA_UNMODIFIED
]);
1517 git_diff_free(diff
);
1519 /* now let's try without the index pointer which should trigger reload */
1521 /* two files that were UNTRACKED should have become UNMODIFIED */
1522 /* one file that was UNMODIFIED should now have become UNTRACKED */
1523 /* one file that was DELETED should now be gone completely */
1525 cl_git_pass(git_diff_index_to_workdir(&diff
, g_repo
, NULL
, &opts
));
1527 memset(&exp
, 0, sizeof(exp
));
1529 cl_git_pass(git_diff_foreach(
1530 diff
, diff_file_cb
, diff_hunk_cb
, diff_line_cb
, &exp
));
1532 git_diff_free(diff
);
1534 cl_assert_equal_i(16, exp
.files
);
1535 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_ADDED
]);
1536 cl_assert_equal_i(3, exp
.file_status
[GIT_DELTA_DELETED
]);
1537 cl_assert_equal_i(4, exp
.file_status
[GIT_DELTA_MODIFIED
]);
1538 cl_assert_equal_i(3, exp
.file_status
[GIT_DELTA_UNTRACKED
]);
1539 cl_assert_equal_i(6, exp
.file_status
[GIT_DELTA_UNMODIFIED
]);
1541 git_index_free(idx
);
1544 static int touch_file(void *payload
, git_buf
*path
)
1549 GIT_UNUSED(payload
);
1550 if (git_path_isdir(path
->ptr
))
1553 cl_assert((fd
= p_open(path
->ptr
, O_RDWR
)) >= 0);
1554 cl_assert_equal_i(1, p_read(fd
, &b
, 1));
1555 cl_must_pass(p_lseek(fd
, 0, SEEK_SET
));
1556 cl_must_pass(p_write(fd
, &b
, 1));
1557 cl_must_pass(p_close(fd
));
1562 static void basic_diff_status(git_diff
**out
, const git_diff_options
*opts
)
1566 cl_git_pass(git_diff_index_to_workdir(out
, g_repo
, NULL
, opts
));
1568 memset(&exp
, 0, sizeof(exp
));
1570 cl_git_pass(git_diff_foreach(
1571 *out
, diff_file_cb
, diff_hunk_cb
, diff_line_cb
, &exp
));
1573 cl_assert_equal_i(13, exp
.files
);
1574 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_ADDED
]);
1575 cl_assert_equal_i(4, exp
.file_status
[GIT_DELTA_DELETED
]);
1576 cl_assert_equal_i(4, exp
.file_status
[GIT_DELTA_MODIFIED
]);
1577 cl_assert_equal_i(1, exp
.file_status
[GIT_DELTA_IGNORED
]);
1578 cl_assert_equal_i(4, exp
.file_status
[GIT_DELTA_UNTRACKED
]);
1581 void test_diff_workdir__can_update_index(void)
1583 git_diff_options opts
= GIT_DIFF_OPTIONS_INIT
;
1584 git_diff
*diff
= NULL
;
1585 git_diff_perfdata perf
= GIT_DIFF_PERFDATA_INIT
;
1587 g_repo
= cl_git_sandbox_init("status");
1589 /* touch all the files so stat times are different */
1591 git_buf path
= GIT_BUF_INIT
;
1592 cl_git_pass(git_buf_sets(&path
, "status"));
1593 cl_git_pass(git_path_direach(&path
, 0, touch_file
, NULL
));
1594 git_buf_free(&path
);
1597 opts
.flags
|= GIT_DIFF_INCLUDE_IGNORED
| GIT_DIFF_INCLUDE_UNTRACKED
;
1599 basic_diff_status(&diff
, &opts
);
1601 cl_git_pass(git_diff_get_perfdata(&perf
, diff
));
1602 cl_assert_equal_sz(13 + 3, perf
.stat_calls
);
1603 cl_assert_equal_sz(5, perf
.oid_calculations
);
1605 git_diff_free(diff
);
1607 /* now allow diff to update stat cache */
1608 opts
.flags
|= GIT_DIFF_UPDATE_INDEX
;
1610 basic_diff_status(&diff
, &opts
);
1612 cl_git_pass(git_diff_get_perfdata(&perf
, diff
));
1613 cl_assert_equal_sz(13 + 3, perf
.stat_calls
);
1614 cl_assert_equal_sz(5, perf
.oid_calculations
);
1616 git_diff_free(diff
);
1618 /* now if we do it again, we should see fewer OID calculations */
1620 basic_diff_status(&diff
, &opts
);
1622 cl_git_pass(git_diff_get_perfdata(&perf
, diff
));
1623 cl_assert_equal_sz(13 + 3, perf
.stat_calls
);
1624 cl_assert_equal_sz(0, perf
.oid_calculations
);
1626 git_diff_free(diff
);
1629 #define STR7 "0123456"
1630 #define STR8 "01234567"
1631 #define STR40 STR8 STR8 STR8 STR8 STR8
1632 #define STR200 STR40 STR40 STR40 STR40 STR40
1633 #define STR999Z STR200 STR200 STR200 STR200 STR40 STR40 STR40 STR40 \
1634 STR8 STR8 STR8 STR8 STR7 "\0"
1635 #define STR1000 STR200 STR200 STR200 STR200 STR200
1636 #define STR3999Z STR1000 STR1000 STR1000 STR999Z
1637 #define STR4000 STR1000 STR1000 STR1000 STR1000
1639 static void assert_delta_binary(git_diff
*diff
, size_t idx
, int is_binary
)
1642 const git_diff_delta
*delta
;
1644 cl_git_pass(git_patch_from_diff(&patch
, diff
, idx
));
1645 delta
= git_patch_get_delta(patch
);
1646 cl_assert_equal_b((delta
->flags
& GIT_DIFF_FLAG_BINARY
), is_binary
);
1647 git_patch_free(patch
);
1650 void test_diff_workdir__binary_detection(void)
1653 git_diff
*diff
= NULL
;
1654 git_buf b
= GIT_BUF_INIT
;
1656 git_buf data
[10] = {
1657 { "1234567890", 0, 0 }, /* 0 - all ascii text control */
1658 { "\xC3\x85\xC3\xBC\xE2\x80\xA0\x48\xC3\xB8\xCF\x80\xCE\xA9", 0, 0 }, /* 1 - UTF-8 multibyte text */
1659 { "\xEF\xBB\xBF\xC3\x9C\xE2\xA4\x92\xC6\x92\x38\xC2\xA3\xE2\x82\xAC", 0, 0 }, /* 2 - UTF-8 with BOM */
1660 { STR999Z
, 0, 1000 }, /* 3 - ASCII with NUL at 1000 */
1661 { STR3999Z
, 0, 4000 }, /* 4 - ASCII with NUL at 4000 */
1662 { STR4000 STR3999Z
"x", 0, 8001 }, /* 5 - ASCII with NUL at 8000 */
1663 { STR4000 STR4000
"\0", 0, 8001 }, /* 6 - ASCII with NUL at 8001 */
1664 { "\x00\xDC\x00\x6E\x21\x39\xFE\x0E\x00\x63\x00\xF8"
1665 "\x00\x64\x00\x65\x20\x48", 0, 18 }, /* 7 - UTF-16 text */
1666 { "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d"
1667 "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d",
1668 0, 26 }, /* 8 - All non-printable characters (no NUL) */
1669 { "Hello \x01\x02\x03\x04\x05\x06 World!\x01\x02\x03\x04"
1670 "\x05\x06\x07", 0, 26 }, /* 9 - 50-50 non-printable (no NUL) */
1673 g_repo
= cl_git_sandbox_init("empty_standard_repo");
1674 cl_git_pass(git_repository_index(&idx
, g_repo
));
1676 /* We start with ASCII in index and test data in workdir,
1677 * then we will try with test data in index and ASCII in workdir.
1680 cl_git_pass(git_buf_sets(&b
, "empty_standard_repo/0"));
1681 for (i
= 0; i
< 10; ++i
) {
1682 b
.ptr
[b
.size
- 1] = '0' + i
;
1683 cl_git_mkfile(b
.ptr
, "baseline");
1684 cl_git_pass(git_index_add_bypath(idx
, &b
.ptr
[b
.size
- 1]));
1686 if (data
[i
].size
== 0)
1687 data
[i
].size
= strlen(data
[i
].ptr
);
1689 b
.ptr
, data
[i
].ptr
, data
[i
].size
, O_WRONLY
|O_TRUNC
, 0664);
1691 git_index_write(idx
);
1693 cl_git_pass(git_diff_index_to_workdir(&diff
, g_repo
, NULL
, NULL
));
1695 cl_assert_equal_i(10, git_diff_num_deltas(diff
));
1697 /* using diff binary detection (i.e. looking for NUL byte) */
1698 assert_delta_binary(diff
, 0, false);
1699 assert_delta_binary(diff
, 1, false);
1700 assert_delta_binary(diff
, 2, false);
1701 assert_delta_binary(diff
, 3, true);
1702 assert_delta_binary(diff
, 4, true);
1703 assert_delta_binary(diff
, 5, true);
1704 assert_delta_binary(diff
, 6, false);
1705 assert_delta_binary(diff
, 7, true);
1706 assert_delta_binary(diff
, 8, false);
1707 assert_delta_binary(diff
, 9, false);
1708 /* The above have been checked to match command-line Git */
1710 git_diff_free(diff
);
1712 cl_git_pass(git_buf_sets(&b
, "empty_standard_repo/0"));
1713 for (i
= 0; i
< 10; ++i
) {
1714 b
.ptr
[b
.size
- 1] = '0' + i
;
1715 cl_git_pass(git_index_add_bypath(idx
, &b
.ptr
[b
.size
- 1]));
1717 cl_git_write2file(b
.ptr
, "baseline\n", 9, O_WRONLY
|O_TRUNC
, 0664);
1719 git_index_write(idx
);
1721 cl_git_pass(git_diff_index_to_workdir(&diff
, g_repo
, NULL
, NULL
));
1723 cl_assert_equal_i(10, git_diff_num_deltas(diff
));
1725 /* using diff binary detection (i.e. looking for NUL byte) */
1726 assert_delta_binary(diff
, 0, false);
1727 assert_delta_binary(diff
, 1, false);
1728 assert_delta_binary(diff
, 2, false);
1729 assert_delta_binary(diff
, 3, true);
1730 assert_delta_binary(diff
, 4, true);
1731 assert_delta_binary(diff
, 5, true);
1732 assert_delta_binary(diff
, 6, false);
1733 assert_delta_binary(diff
, 7, true);
1734 assert_delta_binary(diff
, 8, false);
1735 assert_delta_binary(diff
, 9, false);
1737 git_diff_free(diff
);
1739 git_index_free(idx
);