1 #include "clar_libgit2.h"
2 #include "diff_helpers.h"
3 #include "repository.h"
4 #include "git2/sys/diff.h"
5 #include "../checkout/checkout_helpers.h"
7 static git_repository
*g_repo
= NULL
;
9 void test_diff_workdir__cleanup(void)
11 cl_git_sandbox_cleanup();
14 void test_diff_workdir__to_index(void)
16 git_diff_options opts
= GIT_DIFF_OPTIONS_INIT
;
17 git_diff
*diff
= NULL
;
21 g_repo
= cl_git_sandbox_init("status");
23 opts
.context_lines
= 3;
24 opts
.interhunk_lines
= 1;
25 opts
.flags
|= GIT_DIFF_INCLUDE_IGNORED
| GIT_DIFF_INCLUDE_UNTRACKED
;
27 cl_git_pass(git_diff_index_to_workdir(&diff
, g_repo
, NULL
, &opts
));
29 for (use_iterator
= 0; use_iterator
<= 1; use_iterator
++) {
30 memset(&exp
, 0, sizeof(exp
));
33 cl_git_pass(diff_foreach_via_iterator(
34 diff
, diff_file_cb
, diff_binary_cb
, diff_hunk_cb
, diff_line_cb
, &exp
));
36 cl_git_pass(git_diff_foreach(
37 diff
, diff_file_cb
, diff_binary_cb
, diff_hunk_cb
, diff_line_cb
, &exp
));
39 /* to generate these values:
40 * - cd to tests/resources/status,
42 * - git diff --name-status
46 cl_assert_equal_i(13, exp
.files
);
47 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_ADDED
]);
48 cl_assert_equal_i(4, exp
.file_status
[GIT_DELTA_DELETED
]);
49 cl_assert_equal_i(4, exp
.file_status
[GIT_DELTA_MODIFIED
]);
50 cl_assert_equal_i(1, exp
.file_status
[GIT_DELTA_IGNORED
]);
51 cl_assert_equal_i(4, exp
.file_status
[GIT_DELTA_UNTRACKED
]);
53 cl_assert_equal_i(8, exp
.hunks
);
55 cl_assert_equal_i(14, exp
.lines
);
56 cl_assert_equal_i(5, exp
.line_ctxt
);
57 cl_assert_equal_i(4, exp
.line_adds
);
58 cl_assert_equal_i(5, exp
.line_dels
);
62 git_diff_perfdata perf
= GIT_DIFF_PERFDATA_INIT
;
63 cl_git_pass(git_diff_get_perfdata(&perf
, diff
));
65 13 /* in root */ + 3 /* in subdir */, perf
.stat_calls
);
66 cl_assert_equal_sz(5, perf
.oid_calculations
);
72 void test_diff_workdir__to_index_with_conflicts(void)
74 git_diff_options opts
= GIT_DIFF_OPTIONS_INIT
;
75 git_diff
*diff
= NULL
;
77 git_index_entry our_entry
= {{0}}, their_entry
= {{0}};
78 diff_expects exp
= {0};
80 g_repo
= cl_git_sandbox_init("status");
82 opts
.context_lines
= 3;
83 opts
.interhunk_lines
= 1;
85 /* Adding an entry that represents a rename gets two files in conflict */
86 our_entry
.path
= "subdir/modified_file";
87 our_entry
.mode
= 0100644;
88 git_oid_fromstr(&our_entry
.id
, "ee3fa1b8c00aff7fe02065fdb50864bb0d932ccf");
90 their_entry
.path
= "subdir/rename_conflict";
91 their_entry
.mode
= 0100644;
92 git_oid_fromstr(&their_entry
.id
, "2bd0a343aeef7a2cf0d158478966a6e587ff3863");
94 cl_git_pass(git_repository_index(&index
, g_repo
));
95 cl_git_pass(git_index_conflict_add(index
, NULL
, &our_entry
, &their_entry
));
97 cl_git_pass(git_diff_index_to_workdir(&diff
, g_repo
, index
, &opts
));
99 cl_git_pass(diff_foreach_via_iterator(
100 diff
, diff_file_cb
, diff_binary_cb
, diff_hunk_cb
, diff_line_cb
, &exp
));
102 cl_assert_equal_i(9, exp
.files
);
103 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_ADDED
]);
104 cl_assert_equal_i(4, exp
.file_status
[GIT_DELTA_DELETED
]);
105 cl_assert_equal_i(3, exp
.file_status
[GIT_DELTA_MODIFIED
]);
106 cl_assert_equal_i(2, exp
.file_status
[GIT_DELTA_CONFLICTED
]);
108 cl_assert_equal_i(7, exp
.hunks
);
110 cl_assert_equal_i(12, exp
.lines
);
111 cl_assert_equal_i(4, exp
.line_ctxt
);
112 cl_assert_equal_i(3, exp
.line_adds
);
113 cl_assert_equal_i(5, exp
.line_dels
);
116 git_index_free(index
);
119 void test_diff_workdir__to_index_with_assume_unchanged(void)
121 git_diff_options opts
= GIT_DIFF_OPTIONS_INIT
;
122 git_diff
*diff
= NULL
;
123 git_index
*idx
= NULL
;
125 const git_index_entry
*iep
;
128 g_repo
= cl_git_sandbox_init("status");
130 /* do initial diff */
132 cl_git_pass(git_diff_index_to_workdir(&diff
, g_repo
, NULL
, &opts
));
133 memset(&exp
, 0, sizeof(exp
));
134 cl_git_pass(git_diff_foreach(
135 diff
, diff_file_cb
, diff_binary_cb
, diff_hunk_cb
, diff_line_cb
, &exp
));
136 cl_assert_equal_i(8, exp
.files
);
137 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_ADDED
]);
138 cl_assert_equal_i(4, exp
.file_status
[GIT_DELTA_DELETED
]);
139 cl_assert_equal_i(4, exp
.file_status
[GIT_DELTA_MODIFIED
]);
142 /* mark a couple of entries with ASSUME_UNCHANGED */
144 cl_git_pass(git_repository_index(&idx
, g_repo
));
146 cl_assert((iep
= git_index_get_bypath(idx
, "modified_file", 0)) != NULL
);
147 memcpy(&ie
, iep
, sizeof(ie
));
148 ie
.flags
|= GIT_INDEX_ENTRY_VALID
;
149 cl_git_pass(git_index_add(idx
, &ie
));
151 cl_assert((iep
= git_index_get_bypath(idx
, "file_deleted", 0)) != NULL
);
152 memcpy(&ie
, iep
, sizeof(ie
));
153 ie
.flags
|= GIT_INDEX_ENTRY_VALID
;
154 cl_git_pass(git_index_add(idx
, &ie
));
156 cl_git_pass(git_index_write(idx
));
159 /* redo diff and see that entries are skipped */
161 cl_git_pass(git_diff_index_to_workdir(&diff
, g_repo
, NULL
, &opts
));
162 memset(&exp
, 0, sizeof(exp
));
163 cl_git_pass(git_diff_foreach(
164 diff
, diff_file_cb
, diff_binary_cb
, diff_hunk_cb
, diff_line_cb
, &exp
));
165 cl_assert_equal_i(6, exp
.files
);
166 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_ADDED
]);
167 cl_assert_equal_i(3, exp
.file_status
[GIT_DELTA_DELETED
]);
168 cl_assert_equal_i(3, exp
.file_status
[GIT_DELTA_MODIFIED
]);
173 void test_diff_workdir__to_tree(void)
175 /* grabbed a couple of commit oids from the history of the attr repo */
176 const char *a_commit
= "26a125ee1bf"; /* the current HEAD */
177 const char *b_commit
= "0017bd4ab1ec3"; /* the start */
179 git_diff_options opts
= GIT_DIFF_OPTIONS_INIT
;
180 git_diff
*diff
= NULL
;
181 git_diff
*diff2
= NULL
;
185 g_repo
= cl_git_sandbox_init("status");
187 a
= resolve_commit_oid_to_tree(g_repo
, a_commit
);
188 b
= resolve_commit_oid_to_tree(g_repo
, b_commit
);
190 opts
.context_lines
= 3;
191 opts
.interhunk_lines
= 1;
192 opts
.flags
|= GIT_DIFF_INCLUDE_IGNORED
| GIT_DIFF_INCLUDE_UNTRACKED
;
194 /* You can't really generate the equivalent of git_diff_tree_to_workdir()
195 * using C git. It really wants to interpose the index into the diff.
197 * To validate the following results with command line git, I ran the
199 * - git ls-tree 26a125
200 * - find . ! -path ./.git/\* -a -type f | git hash-object --stdin-paths
201 * The results are documented at the bottom of this file in the
202 * long comment entitled "PREPARATION OF TEST DATA".
204 cl_git_pass(git_diff_tree_to_workdir(&diff
, g_repo
, a
, &opts
));
206 for (use_iterator
= 0; use_iterator
<= 1; use_iterator
++) {
207 memset(&exp
, 0, sizeof(exp
));
210 cl_git_pass(diff_foreach_via_iterator(
211 diff
, diff_file_cb
, diff_binary_cb
, diff_hunk_cb
, diff_line_cb
, &exp
));
213 cl_git_pass(git_diff_foreach(
214 diff
, diff_file_cb
, diff_binary_cb
, diff_hunk_cb
, diff_line_cb
, &exp
));
216 cl_assert_equal_i(14, exp
.files
);
217 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_ADDED
]);
218 cl_assert_equal_i(4, exp
.file_status
[GIT_DELTA_DELETED
]);
219 cl_assert_equal_i(4, exp
.file_status
[GIT_DELTA_MODIFIED
]);
220 cl_assert_equal_i(1, exp
.file_status
[GIT_DELTA_IGNORED
]);
221 cl_assert_equal_i(5, exp
.file_status
[GIT_DELTA_UNTRACKED
]);
224 /* Since there is no git diff equivalent, let's just assume that the
225 * text diffs produced by git_diff_foreach are accurate here. We will
226 * do more apples-to-apples test comparison below.
231 memset(&exp
, 0, sizeof(exp
));
233 /* This is a compatible emulation of "git diff <sha>" which looks like
234 * a workdir to tree diff (even though it is not really). This is what
235 * you would get from "git diff --name-status 26a125ee1bf"
237 cl_git_pass(git_diff_tree_to_index(&diff
, g_repo
, a
, NULL
, &opts
));
238 cl_git_pass(git_diff_index_to_workdir(&diff2
, g_repo
, NULL
, &opts
));
239 cl_git_pass(git_diff_merge(diff
, diff2
));
240 git_diff_free(diff2
);
242 for (use_iterator
= 0; use_iterator
<= 1; use_iterator
++) {
243 memset(&exp
, 0, sizeof(exp
));
246 cl_git_pass(diff_foreach_via_iterator(
247 diff
, diff_file_cb
, diff_binary_cb
, diff_hunk_cb
, diff_line_cb
, &exp
));
249 cl_git_pass(git_diff_foreach(
250 diff
, diff_file_cb
, diff_binary_cb
, diff_hunk_cb
, diff_line_cb
, &exp
));
252 cl_assert_equal_i(15, exp
.files
);
253 cl_assert_equal_i(2, exp
.file_status
[GIT_DELTA_ADDED
]);
254 cl_assert_equal_i(5, exp
.file_status
[GIT_DELTA_DELETED
]);
255 cl_assert_equal_i(4, exp
.file_status
[GIT_DELTA_MODIFIED
]);
256 cl_assert_equal_i(1, exp
.file_status
[GIT_DELTA_IGNORED
]);
257 cl_assert_equal_i(3, exp
.file_status
[GIT_DELTA_UNTRACKED
]);
259 cl_assert_equal_i(11, exp
.hunks
);
261 cl_assert_equal_i(17, exp
.lines
);
262 cl_assert_equal_i(4, exp
.line_ctxt
);
263 cl_assert_equal_i(8, exp
.line_adds
);
264 cl_assert_equal_i(5, exp
.line_dels
);
269 memset(&exp
, 0, sizeof(exp
));
271 /* Again, emulating "git diff <sha>" for testing purposes using
272 * "git diff --name-status 0017bd4ab1ec3" instead.
274 cl_git_pass(git_diff_tree_to_index(&diff
, g_repo
, b
, NULL
, &opts
));
275 cl_git_pass(git_diff_index_to_workdir(&diff2
, g_repo
, NULL
, &opts
));
276 cl_git_pass(git_diff_merge(diff
, diff2
));
277 git_diff_free(diff2
);
279 for (use_iterator
= 0; use_iterator
<= 1; use_iterator
++) {
280 memset(&exp
, 0, sizeof(exp
));
283 cl_git_pass(diff_foreach_via_iterator(
284 diff
, diff_file_cb
, diff_binary_cb
, diff_hunk_cb
, diff_line_cb
, &exp
));
286 cl_git_pass(git_diff_foreach(
287 diff
, diff_file_cb
, diff_binary_cb
, diff_hunk_cb
, diff_line_cb
, &exp
));
289 cl_assert_equal_i(16, exp
.files
);
290 cl_assert_equal_i(5, exp
.file_status
[GIT_DELTA_ADDED
]);
291 cl_assert_equal_i(4, exp
.file_status
[GIT_DELTA_DELETED
]);
292 cl_assert_equal_i(3, exp
.file_status
[GIT_DELTA_MODIFIED
]);
293 cl_assert_equal_i(1, exp
.file_status
[GIT_DELTA_IGNORED
]);
294 cl_assert_equal_i(3, exp
.file_status
[GIT_DELTA_UNTRACKED
]);
296 cl_assert_equal_i(12, exp
.hunks
);
298 cl_assert_equal_i(19, exp
.lines
);
299 cl_assert_equal_i(3, exp
.line_ctxt
);
300 cl_assert_equal_i(12, exp
.line_adds
);
301 cl_assert_equal_i(4, exp
.line_dels
);
306 /* Let's try that once more with a reversed diff */
308 opts
.flags
|= GIT_DIFF_REVERSE
;
310 cl_git_pass(git_diff_tree_to_index(&diff
, g_repo
, b
, NULL
, &opts
));
311 cl_git_pass(git_diff_index_to_workdir(&diff2
, g_repo
, NULL
, &opts
));
312 cl_git_pass(git_diff_merge(diff
, diff2
));
313 git_diff_free(diff2
);
315 memset(&exp
, 0, sizeof(exp
));
317 cl_git_pass(git_diff_foreach(
318 diff
, diff_file_cb
, diff_binary_cb
, diff_hunk_cb
, diff_line_cb
, &exp
));
320 cl_assert_equal_i(16, exp
.files
);
321 cl_assert_equal_i(5, exp
.file_status
[GIT_DELTA_DELETED
]);
322 cl_assert_equal_i(4, exp
.file_status
[GIT_DELTA_ADDED
]);
323 cl_assert_equal_i(3, exp
.file_status
[GIT_DELTA_MODIFIED
]);
324 cl_assert_equal_i(1, exp
.file_status
[GIT_DELTA_IGNORED
]);
325 cl_assert_equal_i(3, exp
.file_status
[GIT_DELTA_UNTRACKED
]);
327 cl_assert_equal_i(12, exp
.hunks
);
329 cl_assert_equal_i(19, exp
.lines
);
330 cl_assert_equal_i(3, exp
.line_ctxt
);
331 cl_assert_equal_i(12, exp
.line_dels
);
332 cl_assert_equal_i(4, exp
.line_adds
);
342 void test_diff_workdir__to_index_with_pathspec(void)
344 git_diff_options opts
= GIT_DIFF_OPTIONS_INIT
;
345 git_diff
*diff
= NULL
;
347 char *pathspec
= NULL
;
350 g_repo
= cl_git_sandbox_init("status");
352 opts
.context_lines
= 3;
353 opts
.interhunk_lines
= 1;
354 opts
.flags
|= GIT_DIFF_INCLUDE_IGNORED
| GIT_DIFF_INCLUDE_UNTRACKED
;
355 opts
.pathspec
.strings
= &pathspec
;
356 opts
.pathspec
.count
= 1;
358 cl_git_pass(git_diff_index_to_workdir(&diff
, g_repo
, NULL
, &opts
));
360 for (use_iterator
= 0; use_iterator
<= 1; use_iterator
++) {
361 memset(&exp
, 0, sizeof(exp
));
364 cl_git_pass(diff_foreach_via_iterator(
365 diff
, diff_file_cb
, NULL
, NULL
, NULL
, &exp
));
367 cl_git_pass(git_diff_foreach(diff
, diff_file_cb
, NULL
, NULL
, NULL
, &exp
));
369 cl_assert_equal_i(13, exp
.files
);
370 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_ADDED
]);
371 cl_assert_equal_i(4, exp
.file_status
[GIT_DELTA_DELETED
]);
372 cl_assert_equal_i(4, exp
.file_status
[GIT_DELTA_MODIFIED
]);
373 cl_assert_equal_i(1, exp
.file_status
[GIT_DELTA_IGNORED
]);
374 cl_assert_equal_i(4, exp
.file_status
[GIT_DELTA_UNTRACKED
]);
379 pathspec
= "modified_file";
381 cl_git_pass(git_diff_index_to_workdir(&diff
, g_repo
, NULL
, &opts
));
383 for (use_iterator
= 0; use_iterator
<= 1; use_iterator
++) {
384 memset(&exp
, 0, sizeof(exp
));
387 cl_git_pass(diff_foreach_via_iterator(
388 diff
, diff_file_cb
, NULL
, NULL
, NULL
, &exp
));
390 cl_git_pass(git_diff_foreach(diff
, diff_file_cb
, NULL
, NULL
, NULL
, &exp
));
392 cl_assert_equal_i(1, exp
.files
);
393 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_ADDED
]);
394 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_DELETED
]);
395 cl_assert_equal_i(1, exp
.file_status
[GIT_DELTA_MODIFIED
]);
396 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_IGNORED
]);
397 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_UNTRACKED
]);
404 cl_git_pass(git_diff_index_to_workdir(&diff
, g_repo
, NULL
, &opts
));
406 for (use_iterator
= 0; use_iterator
<= 1; use_iterator
++) {
407 memset(&exp
, 0, sizeof(exp
));
410 cl_git_pass(diff_foreach_via_iterator(
411 diff
, diff_file_cb
, NULL
, NULL
, NULL
, &exp
));
413 cl_git_pass(git_diff_foreach(diff
, diff_file_cb
, NULL
, NULL
, NULL
, &exp
));
415 cl_assert_equal_i(3, exp
.files
);
416 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_ADDED
]);
417 cl_assert_equal_i(1, exp
.file_status
[GIT_DELTA_DELETED
]);
418 cl_assert_equal_i(1, exp
.file_status
[GIT_DELTA_MODIFIED
]);
419 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_IGNORED
]);
420 cl_assert_equal_i(1, exp
.file_status
[GIT_DELTA_UNTRACKED
]);
425 pathspec
= "*_deleted";
427 cl_git_pass(git_diff_index_to_workdir(&diff
, g_repo
, NULL
, &opts
));
429 for (use_iterator
= 0; use_iterator
<= 1; use_iterator
++) {
430 memset(&exp
, 0, sizeof(exp
));
433 cl_git_pass(diff_foreach_via_iterator(
434 diff
, diff_file_cb
, NULL
, NULL
, NULL
, &exp
));
436 cl_git_pass(git_diff_foreach(diff
, diff_file_cb
, NULL
, NULL
, NULL
, &exp
));
438 cl_assert_equal_i(2, exp
.files
);
439 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_ADDED
]);
440 cl_assert_equal_i(2, exp
.file_status
[GIT_DELTA_DELETED
]);
441 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_MODIFIED
]);
442 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_IGNORED
]);
443 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_UNTRACKED
]);
449 void test_diff_workdir__to_index_with_pathlist_disabling_fnmatch(void)
451 git_diff_options opts
= GIT_DIFF_OPTIONS_INIT
;
452 git_diff
*diff
= NULL
;
454 char *pathspec
= NULL
;
457 g_repo
= cl_git_sandbox_init("status");
459 opts
.context_lines
= 3;
460 opts
.interhunk_lines
= 1;
461 opts
.flags
|= GIT_DIFF_INCLUDE_IGNORED
| GIT_DIFF_INCLUDE_UNTRACKED
|
462 GIT_DIFF_DISABLE_PATHSPEC_MATCH
;
463 opts
.pathspec
.strings
= &pathspec
;
464 opts
.pathspec
.count
= 0;
466 /* ensure that an empty pathspec list is ignored */
467 cl_git_pass(git_diff_index_to_workdir(&diff
, g_repo
, NULL
, &opts
));
469 for (use_iterator
= 0; use_iterator
<= 1; use_iterator
++) {
470 memset(&exp
, 0, sizeof(exp
));
473 cl_git_pass(diff_foreach_via_iterator(
474 diff
, diff_file_cb
, NULL
, NULL
, NULL
, &exp
));
476 cl_git_pass(git_diff_foreach(diff
, diff_file_cb
, NULL
, NULL
, NULL
, &exp
));
478 cl_assert_equal_i(13, exp
.files
);
479 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_ADDED
]);
480 cl_assert_equal_i(4, exp
.file_status
[GIT_DELTA_DELETED
]);
481 cl_assert_equal_i(4, exp
.file_status
[GIT_DELTA_MODIFIED
]);
482 cl_assert_equal_i(1, exp
.file_status
[GIT_DELTA_IGNORED
]);
483 cl_assert_equal_i(4, exp
.file_status
[GIT_DELTA_UNTRACKED
]);
488 /* ensure that a single NULL pathspec is filtered out (like when using
492 opts
.pathspec
.count
= 1;
494 cl_git_pass(git_diff_index_to_workdir(&diff
, g_repo
, NULL
, &opts
));
496 for (use_iterator
= 0; use_iterator
<= 1; use_iterator
++) {
497 memset(&exp
, 0, sizeof(exp
));
500 cl_git_pass(diff_foreach_via_iterator(
501 diff
, diff_file_cb
, NULL
, NULL
, NULL
, &exp
));
503 cl_git_pass(git_diff_foreach(diff
, diff_file_cb
, NULL
, NULL
, NULL
, &exp
));
505 cl_assert_equal_i(13, exp
.files
);
506 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_ADDED
]);
507 cl_assert_equal_i(4, exp
.file_status
[GIT_DELTA_DELETED
]);
508 cl_assert_equal_i(4, exp
.file_status
[GIT_DELTA_MODIFIED
]);
509 cl_assert_equal_i(1, exp
.file_status
[GIT_DELTA_IGNORED
]);
510 cl_assert_equal_i(4, exp
.file_status
[GIT_DELTA_UNTRACKED
]);
515 pathspec
= "modified_file";
517 cl_git_pass(git_diff_index_to_workdir(&diff
, g_repo
, NULL
, &opts
));
519 for (use_iterator
= 0; use_iterator
<= 1; use_iterator
++) {
520 memset(&exp
, 0, sizeof(exp
));
523 cl_git_pass(diff_foreach_via_iterator(
524 diff
, diff_file_cb
, NULL
, NULL
, NULL
, &exp
));
526 cl_git_pass(git_diff_foreach(diff
, diff_file_cb
, NULL
, NULL
, NULL
, &exp
));
528 cl_assert_equal_i(1, exp
.files
);
529 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_ADDED
]);
530 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_DELETED
]);
531 cl_assert_equal_i(1, exp
.file_status
[GIT_DELTA_MODIFIED
]);
532 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_IGNORED
]);
533 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_UNTRACKED
]);
538 /* ensure that subdirs can be specified */
541 cl_git_pass(git_diff_index_to_workdir(&diff
, g_repo
, NULL
, &opts
));
543 for (use_iterator
= 0; use_iterator
<= 1; use_iterator
++) {
544 memset(&exp
, 0, sizeof(exp
));
547 cl_git_pass(diff_foreach_via_iterator(
548 diff
, diff_file_cb
, NULL
, NULL
, NULL
, &exp
));
550 cl_git_pass(git_diff_foreach(diff
, diff_file_cb
, NULL
, NULL
, NULL
, &exp
));
552 cl_assert_equal_i(3, exp
.files
);
553 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_ADDED
]);
554 cl_assert_equal_i(1, exp
.file_status
[GIT_DELTA_DELETED
]);
555 cl_assert_equal_i(1, exp
.file_status
[GIT_DELTA_MODIFIED
]);
556 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_IGNORED
]);
557 cl_assert_equal_i(1, exp
.file_status
[GIT_DELTA_UNTRACKED
]);
562 /* ensure that subdirs can be specified with a trailing slash */
563 pathspec
= "subdir/";
565 cl_git_pass(git_diff_index_to_workdir(&diff
, g_repo
, NULL
, &opts
));
567 for (use_iterator
= 0; use_iterator
<= 1; use_iterator
++) {
568 memset(&exp
, 0, sizeof(exp
));
571 cl_git_pass(diff_foreach_via_iterator(
572 diff
, diff_file_cb
, NULL
, NULL
, NULL
, &exp
));
574 cl_git_pass(git_diff_foreach(diff
, diff_file_cb
, NULL
, NULL
, NULL
, &exp
));
576 cl_assert_equal_i(3, exp
.files
);
577 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_ADDED
]);
578 cl_assert_equal_i(1, exp
.file_status
[GIT_DELTA_DELETED
]);
579 cl_assert_equal_i(1, exp
.file_status
[GIT_DELTA_MODIFIED
]);
580 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_IGNORED
]);
581 cl_assert_equal_i(1, exp
.file_status
[GIT_DELTA_UNTRACKED
]);
586 /* ensure that fnmatching is completely disabled */
587 pathspec
= "subdir/*";
589 cl_git_pass(git_diff_index_to_workdir(&diff
, g_repo
, NULL
, &opts
));
591 for (use_iterator
= 0; use_iterator
<= 1; use_iterator
++) {
592 memset(&exp
, 0, sizeof(exp
));
595 cl_git_pass(diff_foreach_via_iterator(
596 diff
, diff_file_cb
, NULL
, NULL
, NULL
, &exp
));
598 cl_git_pass(git_diff_foreach(diff
, diff_file_cb
, NULL
, NULL
, NULL
, &exp
));
600 cl_assert_equal_i(0, exp
.files
);
601 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_ADDED
]);
602 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_DELETED
]);
603 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_MODIFIED
]);
604 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_IGNORED
]);
605 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_UNTRACKED
]);
610 /* ensure that the prefix matching isn't completely braindead */
613 cl_git_pass(git_diff_index_to_workdir(&diff
, g_repo
, NULL
, &opts
));
615 for (use_iterator
= 0; use_iterator
<= 1; use_iterator
++) {
616 memset(&exp
, 0, sizeof(exp
));
619 cl_git_pass(diff_foreach_via_iterator(
620 diff
, diff_file_cb
, NULL
, NULL
, NULL
, &exp
));
622 cl_git_pass(git_diff_foreach(diff
, diff_file_cb
, NULL
, NULL
, NULL
, &exp
));
624 cl_assert_equal_i(0, exp
.files
);
625 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_ADDED
]);
626 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_DELETED
]);
627 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_MODIFIED
]);
628 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_IGNORED
]);
629 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_UNTRACKED
]);
634 /* ensure that fnmatching isn't working at all */
635 pathspec
= "*_deleted";
637 cl_git_pass(git_diff_index_to_workdir(&diff
, g_repo
, NULL
, &opts
));
639 for (use_iterator
= 0; use_iterator
<= 1; use_iterator
++) {
640 memset(&exp
, 0, sizeof(exp
));
643 cl_git_pass(diff_foreach_via_iterator(
644 diff
, diff_file_cb
, NULL
, NULL
, NULL
, &exp
));
646 cl_git_pass(git_diff_foreach(diff
, diff_file_cb
, NULL
, NULL
, NULL
, &exp
));
648 cl_assert_equal_i(0, exp
.files
);
649 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_ADDED
]);
650 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_DELETED
]);
651 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_MODIFIED
]);
652 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_IGNORED
]);
653 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_UNTRACKED
]);
659 void test_diff_workdir__filemode_changes(void)
661 git_diff
*diff
= NULL
;
665 if (!cl_is_chmod_supported())
668 g_repo
= cl_git_sandbox_init("issue_592");
670 cl_repo_set_bool(g_repo
, "core.filemode", true);
672 /* test once with no mods */
674 cl_git_pass(git_diff_index_to_workdir(&diff
, g_repo
, NULL
, NULL
));
676 for (use_iterator
= 0; use_iterator
<= 1; use_iterator
++) {
677 memset(&exp
, 0, sizeof(exp
));
680 cl_git_pass(diff_foreach_via_iterator(
681 diff
, diff_file_cb
, diff_binary_cb
, diff_hunk_cb
, diff_line_cb
, &exp
));
683 cl_git_pass(git_diff_foreach(
684 diff
, diff_file_cb
, diff_binary_cb
, diff_hunk_cb
, diff_line_cb
, &exp
));
686 cl_assert_equal_i(0, exp
.files
);
687 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_MODIFIED
]);
688 cl_assert_equal_i(0, exp
.hunks
);
693 /* chmod file and test again */
695 cl_assert(cl_toggle_filemode("issue_592/a.txt"));
697 cl_git_pass(git_diff_index_to_workdir(&diff
, g_repo
, NULL
, NULL
));
699 for (use_iterator
= 0; use_iterator
<= 1; use_iterator
++) {
700 memset(&exp
, 0, sizeof(exp
));
703 cl_git_pass(diff_foreach_via_iterator(
704 diff
, diff_file_cb
, diff_binary_cb
, diff_hunk_cb
, diff_line_cb
, &exp
));
706 cl_git_pass(git_diff_foreach(
707 diff
, diff_file_cb
, diff_binary_cb
, diff_hunk_cb
, diff_line_cb
, &exp
));
709 cl_assert_equal_i(1, exp
.files
);
710 cl_assert_equal_i(1, exp
.file_status
[GIT_DELTA_MODIFIED
]);
711 cl_assert_equal_i(0, exp
.hunks
);
716 cl_assert(cl_toggle_filemode("issue_592/a.txt"));
719 void test_diff_workdir__filemode_changes_with_filemode_false(void)
721 git_diff
*diff
= NULL
;
724 if (!cl_is_chmod_supported())
727 g_repo
= cl_git_sandbox_init("issue_592");
729 cl_repo_set_bool(g_repo
, "core.filemode", false);
731 /* test once with no mods */
733 cl_git_pass(git_diff_index_to_workdir(&diff
, g_repo
, NULL
, NULL
));
735 memset(&exp
, 0, sizeof(exp
));
736 cl_git_pass(git_diff_foreach(
737 diff
, diff_file_cb
, diff_binary_cb
, diff_hunk_cb
, diff_line_cb
, &exp
));
739 cl_assert_equal_i(0, exp
.files
);
740 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_MODIFIED
]);
741 cl_assert_equal_i(0, exp
.hunks
);
745 /* chmod file and test again */
747 cl_assert(cl_toggle_filemode("issue_592/a.txt"));
749 cl_git_pass(git_diff_index_to_workdir(&diff
, g_repo
, NULL
, NULL
));
751 memset(&exp
, 0, sizeof(exp
));
752 cl_git_pass(git_diff_foreach(diff
,
753 diff_file_cb
, diff_binary_cb
, diff_hunk_cb
, diff_line_cb
, &exp
));
755 cl_assert_equal_i(0, exp
.files
);
756 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_MODIFIED
]);
757 cl_assert_equal_i(0, exp
.hunks
);
761 cl_assert(cl_toggle_filemode("issue_592/a.txt"));
764 void test_diff_workdir__head_index_and_workdir_all_differ(void)
766 git_diff_options opts
= GIT_DIFF_OPTIONS_INIT
;
767 git_diff
*diff_i2t
= NULL
, *diff_w2i
= NULL
;
769 char *pathspec
= "staged_changes_modified_file";
774 * - head->index diff has 1 line of context, 1 line of diff
775 * - index->workdir diff has 2 lines of context, 1 line of diff
777 * - head->workdir diff has 1 line of context, 2 lines of diff
778 * Let's make sure the right one is returned from each fn.
781 g_repo
= cl_git_sandbox_init("status");
783 tree
= resolve_commit_oid_to_tree(g_repo
, "26a125ee1bfc5df1e1b2e9441bbe63c8a7ae989f");
785 opts
.pathspec
.strings
= &pathspec
;
786 opts
.pathspec
.count
= 1;
788 cl_git_pass(git_diff_tree_to_index(&diff_i2t
, g_repo
, tree
, NULL
, &opts
));
789 cl_git_pass(git_diff_index_to_workdir(&diff_w2i
, g_repo
, NULL
, &opts
));
791 for (use_iterator
= 0; use_iterator
<= 1; use_iterator
++) {
792 memset(&exp
, 0, sizeof(exp
));
795 cl_git_pass(diff_foreach_via_iterator(
796 diff_i2t
, diff_file_cb
, diff_binary_cb
, diff_hunk_cb
, diff_line_cb
, &exp
));
798 cl_git_pass(git_diff_foreach(
799 diff_i2t
, diff_file_cb
, diff_binary_cb
, diff_hunk_cb
, diff_line_cb
, &exp
));
801 cl_assert_equal_i(1, exp
.files
);
802 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_ADDED
]);
803 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_DELETED
]);
804 cl_assert_equal_i(1, exp
.file_status
[GIT_DELTA_MODIFIED
]);
805 cl_assert_equal_i(1, exp
.hunks
);
806 cl_assert_equal_i(2, exp
.lines
);
807 cl_assert_equal_i(1, exp
.line_ctxt
);
808 cl_assert_equal_i(1, exp
.line_adds
);
809 cl_assert_equal_i(0, exp
.line_dels
);
812 for (use_iterator
= 0; use_iterator
<= 1; use_iterator
++) {
813 memset(&exp
, 0, sizeof(exp
));
816 cl_git_pass(diff_foreach_via_iterator(
817 diff_w2i
, diff_file_cb
, diff_binary_cb
, diff_hunk_cb
, diff_line_cb
, &exp
));
819 cl_git_pass(git_diff_foreach(
820 diff_w2i
, diff_file_cb
, diff_binary_cb
, diff_hunk_cb
, diff_line_cb
, &exp
));
822 cl_assert_equal_i(1, exp
.files
);
823 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_ADDED
]);
824 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_DELETED
]);
825 cl_assert_equal_i(1, exp
.file_status
[GIT_DELTA_MODIFIED
]);
826 cl_assert_equal_i(1, exp
.hunks
);
827 cl_assert_equal_i(3, exp
.lines
);
828 cl_assert_equal_i(2, exp
.line_ctxt
);
829 cl_assert_equal_i(1, exp
.line_adds
);
830 cl_assert_equal_i(0, exp
.line_dels
);
833 cl_git_pass(git_diff_merge(diff_i2t
, diff_w2i
));
835 for (use_iterator
= 0; use_iterator
<= 1; use_iterator
++) {
836 memset(&exp
, 0, sizeof(exp
));
839 cl_git_pass(diff_foreach_via_iterator(
840 diff_i2t
, diff_file_cb
, diff_binary_cb
, diff_hunk_cb
, diff_line_cb
, &exp
));
842 cl_git_pass(git_diff_foreach(
843 diff_i2t
, diff_file_cb
, diff_binary_cb
, diff_hunk_cb
, diff_line_cb
, &exp
));
845 cl_assert_equal_i(1, exp
.files
);
846 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_ADDED
]);
847 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_DELETED
]);
848 cl_assert_equal_i(1, exp
.file_status
[GIT_DELTA_MODIFIED
]);
849 cl_assert_equal_i(1, exp
.hunks
);
850 cl_assert_equal_i(3, exp
.lines
);
851 cl_assert_equal_i(1, exp
.line_ctxt
);
852 cl_assert_equal_i(2, exp
.line_adds
);
853 cl_assert_equal_i(0, exp
.line_dels
);
856 git_diff_free(diff_i2t
);
857 git_diff_free(diff_w2i
);
862 void test_diff_workdir__eof_newline_changes(void)
864 git_diff_options opts
= GIT_DIFF_OPTIONS_INIT
;
865 git_diff
*diff
= NULL
;
867 char *pathspec
= "current_file";
870 g_repo
= cl_git_sandbox_init("status");
872 opts
.pathspec
.strings
= &pathspec
;
873 opts
.pathspec
.count
= 1;
875 cl_git_pass(git_diff_index_to_workdir(&diff
, g_repo
, NULL
, &opts
));
877 for (use_iterator
= 0; use_iterator
<= 1; use_iterator
++) {
878 memset(&exp
, 0, sizeof(exp
));
881 cl_git_pass(diff_foreach_via_iterator(
882 diff
, diff_file_cb
, diff_binary_cb
, diff_hunk_cb
, diff_line_cb
, &exp
));
884 cl_git_pass(git_diff_foreach(
885 diff
, diff_file_cb
, diff_binary_cb
, diff_hunk_cb
, diff_line_cb
, &exp
));
887 cl_assert_equal_i(0, exp
.files
);
888 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_ADDED
]);
889 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_DELETED
]);
890 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_MODIFIED
]);
891 cl_assert_equal_i(0, exp
.hunks
);
892 cl_assert_equal_i(0, exp
.lines
);
893 cl_assert_equal_i(0, exp
.line_ctxt
);
894 cl_assert_equal_i(0, exp
.line_adds
);
895 cl_assert_equal_i(0, exp
.line_dels
);
900 cl_git_append2file("status/current_file", "\n");
902 cl_git_pass(git_diff_index_to_workdir(&diff
, g_repo
, NULL
, &opts
));
904 for (use_iterator
= 0; use_iterator
<= 1; use_iterator
++) {
905 memset(&exp
, 0, sizeof(exp
));
908 cl_git_pass(diff_foreach_via_iterator(
909 diff
, diff_file_cb
, diff_binary_cb
, diff_hunk_cb
, diff_line_cb
, &exp
));
911 cl_git_pass(git_diff_foreach(
912 diff
, diff_file_cb
, diff_binary_cb
, diff_hunk_cb
, diff_line_cb
, &exp
));
914 cl_assert_equal_i(1, exp
.files
);
915 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_ADDED
]);
916 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_DELETED
]);
917 cl_assert_equal_i(1, exp
.file_status
[GIT_DELTA_MODIFIED
]);
918 cl_assert_equal_i(1, exp
.hunks
);
919 cl_assert_equal_i(2, exp
.lines
);
920 cl_assert_equal_i(1, exp
.line_ctxt
);
921 cl_assert_equal_i(1, exp
.line_adds
);
922 cl_assert_equal_i(0, exp
.line_dels
);
927 cl_git_rewritefile("status/current_file", "current_file");
929 cl_git_pass(git_diff_index_to_workdir(&diff
, g_repo
, NULL
, &opts
));
931 for (use_iterator
= 0; use_iterator
<= 1; use_iterator
++) {
932 memset(&exp
, 0, sizeof(exp
));
935 cl_git_pass(diff_foreach_via_iterator(
936 diff
, diff_file_cb
, diff_binary_cb
, diff_hunk_cb
, diff_line_cb
, &exp
));
938 cl_git_pass(git_diff_foreach(
939 diff
, diff_file_cb
, diff_binary_cb
, diff_hunk_cb
, diff_line_cb
, &exp
));
941 cl_assert_equal_i(1, exp
.files
);
942 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_ADDED
]);
943 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_DELETED
]);
944 cl_assert_equal_i(1, exp
.file_status
[GIT_DELTA_MODIFIED
]);
945 cl_assert_equal_i(1, exp
.hunks
);
946 cl_assert_equal_i(3, exp
.lines
);
947 cl_assert_equal_i(0, exp
.line_ctxt
);
948 cl_assert_equal_i(1, exp
.line_adds
);
949 cl_assert_equal_i(2, exp
.line_dels
);
955 /* PREPARATION OF TEST DATA
957 * Since there is no command line equivalent of git_diff_tree_to_workdir,
958 * it was a bit of a pain to confirm that I was getting the expected
959 * results in the first part of this tests. Here is what I ended up
960 * doing to set my expectation for the file counts and results:
962 * Running "git ls-tree 26a125" and "git ls-tree aa27a6" shows:
964 * A a0de7e0ac200c489c41c59dfa910154a70264e6e current_file
965 * B 5452d32f1dd538eb0405e8a83cc185f79e25e80f file_deleted
966 * C 452e4244b5d083ddf0460acf1ecc74db9dcfa11a modified_file
967 * D 32504b727382542f9f089e24fddac5e78533e96c staged_changes
968 * E 061d42a44cacde5726057b67558821d95db96f19 staged_changes_file_deleted
969 * F 70bd9443ada07063e7fbf0b3ff5c13f7494d89c2 staged_changes_modified_file
970 * G e9b9107f290627c04d097733a10055af941f6bca staged_delete_file_deleted
971 * H dabc8af9bd6e9f5bbe96a176f1a24baf3d1f8916 staged_delete_modified_file
972 * I 53ace0d1cc1145a5f4fe4f78a186a60263190733 subdir/current_file
973 * J 1888c805345ba265b0ee9449b8877b6064592058 subdir/deleted_file
974 * K a6191982709b746d5650e93c2acf34ef74e11504 subdir/modified_file
975 * L e8ee89e15bbe9b20137715232387b3de5b28972e subdir.txt
979 * find . ! -path ./.git/\* -a -type f | git hash-object --stdin-paths
981 * A a0de7e0ac200c489c41c59dfa910154a70264e6e current_file
982 * M 6a79f808a9c6bc9531ac726c184bbcd9351ccf11 ignored_file
983 * C 0a539630525aca2e7bc84975958f92f10a64c9b6 modified_file
984 * N d4fa8600b4f37d7516bef4816ae2c64dbf029e3a new_file
985 * D 55d316c9ba708999f1918e9677d01dfcae69c6b9 staged_changes
986 * F 011c3440d5c596e21d836aa6d7b10eb581f68c49 staged_changes_modified_file
987 * H dabc8af9bd6e9f5bbe96a176f1a24baf3d1f8916 staged_delete_modified_file
988 * O 529a16e8e762d4acb7b9636ff540a00831f9155a staged_new_file
989 * P 8b090c06d14ffa09c4e880088ebad33893f921d1 staged_new_file_modified_file
990 * I 53ace0d1cc1145a5f4fe4f78a186a60263190733 subdir/current_file
991 * K 57274b75eeb5f36fd55527806d567b2240a20c57 subdir/modified_file
992 * Q 80a86a6931b91bc01c2dbf5ca55bdd24ad1ef466 subdir/new_file
993 * L e8ee89e15bbe9b20137715232387b3de5b28972e subdir.txt
997 * A - current_file (UNMODIFIED) -> not in results
999 * M I ignored_file (IGNORED)
1001 * N U new_file (UNTRACKED)
1002 * D M staged_changes
1003 * E D staged_changes_file_deleted
1004 * F M staged_changes_modified_file
1005 * G D staged_delete_file_deleted
1006 * H - staged_delete_modified_file (UNMODIFIED) -> not in results
1007 * O U staged_new_file
1008 * P U staged_new_file_modified_file
1009 * I - subdir/current_file (UNMODIFIED) -> not in results
1010 * J D subdir/deleted_file
1011 * K M subdir/modified_file
1012 * Q U subdir/new_file
1013 * L - subdir.txt (UNMODIFIED) -> not in results
1015 * Expect 13 files, 0 ADD, 4 DEL, 4 MOD, 1 IGN, 4 UNTR
1019 void test_diff_workdir__larger_hunks(void)
1021 const char *a_commit
= "d70d245ed97ed2aa596dd1af6536e4bfdb047b69";
1022 const char *b_commit
= "7a9e0b02e63179929fed24f0a3e0f19168114d10";
1024 git_diff_options opts
= GIT_DIFF_OPTIONS_INIT
;
1025 size_t i
, d
, num_d
, h
, num_h
, l
, num_l
;
1027 g_repo
= cl_git_sandbox_init("diff");
1029 cl_assert((a
= resolve_commit_oid_to_tree(g_repo
, a_commit
)) != NULL
);
1030 cl_assert((b
= resolve_commit_oid_to_tree(g_repo
, b_commit
)) != NULL
);
1032 opts
.context_lines
= 1;
1033 opts
.interhunk_lines
= 0;
1035 for (i
= 0; i
<= 2; ++i
) {
1036 git_diff
*diff
= NULL
;
1038 const git_diff_hunk
*hunk
;
1039 const git_diff_line
*line
;
1041 /* okay, this is a bit silly, but oh well */
1044 cl_git_pass(git_diff_index_to_workdir(&diff
, g_repo
, NULL
, &opts
));
1047 cl_git_pass(git_diff_tree_to_workdir(&diff
, g_repo
, a
, &opts
));
1050 cl_git_pass(git_diff_tree_to_workdir(&diff
, g_repo
, b
, &opts
));
1054 num_d
= git_diff_num_deltas(diff
);
1055 cl_assert_equal_i(2, (int)num_d
);
1057 for (d
= 0; d
< num_d
; ++d
) {
1058 cl_git_pass(git_patch_from_diff(&patch
, diff
, d
));
1061 num_h
= git_patch_num_hunks(patch
);
1062 for (h
= 0; h
< num_h
; h
++) {
1063 cl_git_pass(git_patch_get_hunk(&hunk
, &num_l
, patch
, h
));
1065 for (l
= 0; l
< num_l
; ++l
) {
1067 git_patch_get_line_in_hunk(&line
, patch
, h
, l
));
1071 /* confirm fail after the last item */
1073 git_patch_get_line_in_hunk(&line
, patch
, h
, num_l
));
1076 /* confirm fail after the last item */
1077 cl_git_fail(git_patch_get_hunk(&hunk
, &num_l
, patch
, num_h
));
1079 git_patch_free(patch
);
1082 git_diff_free(diff
);
1089 /* Set up a test that exercises this code. The easiest test using existing
1090 * test data is probably to create a sandbox of submod2 and then run a
1091 * git_diff_tree_to_workdir against tree
1092 * 873585b94bdeabccea991ea5e3ec1a277895b698. As for what you should actually
1093 * test, you can start by just checking that the number of lines of diff
1094 * content matches the actual output of git diff. That will at least
1095 * demonstrate that the submodule content is being used to generate somewhat
1096 * comparable outputs. It is a test that would fail without this code and
1097 * will succeed with it.
1100 #include "../submodule/submodule_helpers.h"
1102 void test_diff_workdir__submodules(void)
1104 const char *a_commit
= "873585b94bdeabccea991ea5e3ec1a277895b698";
1106 git_diff_options opts
= GIT_DIFF_OPTIONS_INIT
;
1107 git_diff
*diff
= NULL
;
1110 g_repo
= setup_fixture_submod2();
1112 a
= resolve_commit_oid_to_tree(g_repo
, a_commit
);
1115 GIT_DIFF_INCLUDE_UNTRACKED
|
1116 GIT_DIFF_INCLUDE_IGNORED
|
1117 GIT_DIFF_RECURSE_UNTRACKED_DIRS
|
1118 GIT_DIFF_SHOW_UNTRACKED_CONTENT
;
1120 cl_git_pass(git_diff_tree_to_workdir(&diff
, g_repo
, a
, &opts
));
1122 /* diff_print(stderr, diff); */
1124 /* essentially doing: git diff 873585b94bdeabccea991ea5e3ec1a277895b698 */
1126 memset(&exp
, 0, sizeof(exp
));
1128 cl_git_pass(git_diff_foreach(
1129 diff
, diff_file_cb
, diff_binary_cb
, diff_hunk_cb
, diff_line_cb
, &exp
));
1131 /* so "git diff 873585" returns:
1133 * A just_a_dir/contents
1135 * A sm_added_and_uncommited
1138 * A sm_changed_index
1139 * A sm_changed_untracked_file
1140 * M sm_missing_commits
1142 * which is a little deceptive because of the difference between the
1143 * "git diff <treeish>" results from "git_diff_tree_to_workdir". The
1144 * only significant difference is that those Added items will show up
1145 * as Untracked items in the pure libgit2 diff.
1147 * Then add in the two extra untracked items "not" and "not-submodule"
1148 * to get the 12 files reported here.
1151 cl_assert_equal_i(12, exp
.files
);
1153 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_ADDED
]);
1154 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_DELETED
]);
1155 cl_assert_equal_i(2, exp
.file_status
[GIT_DELTA_MODIFIED
]);
1156 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_IGNORED
]);
1157 cl_assert_equal_i(10, exp
.file_status
[GIT_DELTA_UNTRACKED
]);
1159 /* the following numbers match "git diff 873585" exactly */
1161 cl_assert_equal_i(9, exp
.hunks
);
1163 cl_assert_equal_i(33, exp
.lines
);
1164 cl_assert_equal_i(2, exp
.line_ctxt
);
1165 cl_assert_equal_i(30, exp
.line_adds
);
1166 cl_assert_equal_i(1, exp
.line_dels
);
1168 git_diff_free(diff
);
1172 void test_diff_workdir__cannot_diff_against_a_bare_repository(void)
1174 git_diff_options opts
= GIT_DIFF_OPTIONS_INIT
;
1175 git_diff
*diff
= NULL
;
1178 g_repo
= cl_git_sandbox_init("testrepo.git");
1181 GIT_EBAREREPO
, git_diff_index_to_workdir(&diff
, g_repo
, NULL
, &opts
));
1183 cl_git_pass(git_repository_head_tree(&tree
, g_repo
));
1186 GIT_EBAREREPO
, git_diff_tree_to_workdir(&diff
, g_repo
, tree
, &opts
));
1188 git_tree_free(tree
);
1191 void test_diff_workdir__to_null_tree(void)
1195 git_diff_options opts
= GIT_DIFF_OPTIONS_INIT
;
1197 opts
.flags
= GIT_DIFF_INCLUDE_UNTRACKED
|
1198 GIT_DIFF_RECURSE_UNTRACKED_DIRS
;
1200 g_repo
= cl_git_sandbox_init("status");
1202 cl_git_pass(git_diff_tree_to_workdir(&diff
, g_repo
, NULL
, &opts
));
1204 memset(&exp
, 0, sizeof(exp
));
1206 cl_git_pass(git_diff_foreach(
1207 diff
, diff_file_cb
, diff_binary_cb
, diff_hunk_cb
, diff_line_cb
, &exp
));
1209 cl_assert_equal_i(exp
.files
, exp
.file_status
[GIT_DELTA_UNTRACKED
]);
1211 git_diff_free(diff
);
1214 void test_diff_workdir__checks_options_version(void)
1217 git_diff_options opts
= GIT_DIFF_OPTIONS_INIT
;
1218 const git_error
*err
;
1220 g_repo
= cl_git_sandbox_init("status");
1223 cl_git_fail(git_diff_tree_to_workdir(&diff
, g_repo
, NULL
, &opts
));
1224 err
= git_error_last();
1225 cl_assert_equal_i(GIT_ERROR_INVALID
, err
->klass
);
1228 opts
.version
= 1024;
1229 cl_git_fail(git_diff_tree_to_workdir(&diff
, g_repo
, NULL
, &opts
));
1230 err
= git_error_last();
1231 cl_assert_equal_i(GIT_ERROR_INVALID
, err
->klass
);
1234 void test_diff_workdir__can_diff_empty_file(void)
1238 git_diff_options opts
= GIT_DIFF_OPTIONS_INIT
;
1242 g_repo
= cl_git_sandbox_init("attr_index");
1244 tree
= resolve_commit_oid_to_tree(g_repo
, "3812cfef3661"); /* HEAD */
1246 /* baseline - make sure there are no outstanding diffs */
1248 cl_git_pass(git_diff_tree_to_workdir(&diff
, g_repo
, tree
, &opts
));
1249 cl_assert_equal_i(2, (int)git_diff_num_deltas(diff
));
1250 git_diff_free(diff
);
1252 /* empty contents of file */
1254 cl_git_rewritefile("attr_index/README.txt", "");
1255 cl_git_pass(git_path_lstat("attr_index/README.txt", &st
));
1256 cl_assert_equal_i(0, (int)st
.st_size
);
1258 cl_git_pass(git_diff_tree_to_workdir(&diff
, g_repo
, tree
, &opts
));
1259 cl_assert_equal_i(3, (int)git_diff_num_deltas(diff
));
1260 /* diffs are: .gitattributes, README.txt, sub/sub/.gitattributes */
1261 cl_git_pass(git_patch_from_diff(&patch
, diff
, 1));
1262 git_patch_free(patch
);
1263 git_diff_free(diff
);
1265 /* remove a file altogether */
1267 cl_git_pass(p_unlink("attr_index/README.txt"));
1268 cl_assert(!git_path_exists("attr_index/README.txt"));
1270 cl_git_pass(git_diff_tree_to_workdir(&diff
, g_repo
, tree
, &opts
));
1271 cl_assert_equal_i(3, (int)git_diff_num_deltas(diff
));
1272 cl_git_pass(git_patch_from_diff(&patch
, diff
, 1));
1273 git_patch_free(patch
);
1274 git_diff_free(diff
);
1276 git_tree_free(tree
);
1279 void test_diff_workdir__to_index_issue_1397(void)
1281 git_diff_options opts
= GIT_DIFF_OPTIONS_INIT
;
1282 git_diff
*diff
= NULL
;
1285 g_repo
= cl_git_sandbox_init("issue_1397");
1287 cl_repo_set_bool(g_repo
, "core.autocrlf", true);
1289 opts
.context_lines
= 3;
1290 opts
.interhunk_lines
= 1;
1292 cl_git_pass(git_diff_index_to_workdir(&diff
, g_repo
, NULL
, &opts
));
1294 memset(&exp
, 0, sizeof(exp
));
1295 cl_git_pass(git_diff_foreach(
1296 diff
, diff_file_cb
, diff_binary_cb
, diff_hunk_cb
, diff_line_cb
, &exp
));
1298 cl_assert_equal_i(0, exp
.files
);
1299 cl_assert_equal_i(0, exp
.hunks
);
1300 cl_assert_equal_i(0, exp
.lines
);
1302 git_diff_free(diff
);
1305 cl_git_rewritefile("issue_1397/crlf_file.txt",
1306 "first line\r\nsecond line modified\r\nboth with crlf");
1308 cl_git_pass(git_diff_index_to_workdir(&diff
, g_repo
, NULL
, &opts
));
1310 memset(&exp
, 0, sizeof(exp
));
1311 cl_git_pass(git_diff_foreach(
1312 diff
, diff_file_cb
, diff_binary_cb
, diff_hunk_cb
, diff_line_cb
, &exp
));
1314 cl_assert_equal_i(1, exp
.files
);
1315 cl_assert_equal_i(1, exp
.file_status
[GIT_DELTA_MODIFIED
]);
1317 cl_assert_equal_i(1, exp
.hunks
);
1319 cl_assert_equal_i(5, exp
.lines
);
1320 cl_assert_equal_i(3, exp
.line_ctxt
);
1321 cl_assert_equal_i(1, exp
.line_adds
);
1322 cl_assert_equal_i(1, exp
.line_dels
);
1324 git_diff_free(diff
);
1327 void test_diff_workdir__to_tree_issue_1397(void)
1329 const char *a_commit
= "7f483a738"; /* the current HEAD */
1331 git_diff_options opts
= GIT_DIFF_OPTIONS_INIT
;
1332 git_diff
*diff
= NULL
;
1333 git_diff
*diff2
= NULL
;
1336 g_repo
= cl_git_sandbox_init("issue_1397");
1338 cl_repo_set_bool(g_repo
, "core.autocrlf", true);
1340 a
= resolve_commit_oid_to_tree(g_repo
, a_commit
);
1342 opts
.context_lines
= 3;
1343 opts
.interhunk_lines
= 1;
1345 cl_git_pass(git_diff_tree_to_workdir(&diff
, g_repo
, a
, &opts
));
1347 memset(&exp
, 0, sizeof(exp
));
1348 cl_git_pass(git_diff_foreach(
1349 diff
, diff_file_cb
, diff_binary_cb
, diff_hunk_cb
, diff_line_cb
, &exp
));
1351 cl_assert_equal_i(0, exp
.files
);
1352 cl_assert_equal_i(0, exp
.hunks
);
1353 cl_assert_equal_i(0, exp
.lines
);
1355 git_diff_free(diff
);
1358 cl_git_pass(git_diff_tree_to_index(&diff
, g_repo
, a
, NULL
, &opts
));
1359 cl_git_pass(git_diff_index_to_workdir(&diff2
, g_repo
, NULL
, &opts
));
1360 cl_git_pass(git_diff_merge(diff
, diff2
));
1361 git_diff_free(diff2
);
1363 memset(&exp
, 0, sizeof(exp
));
1364 cl_git_pass(git_diff_foreach(
1365 diff
, diff_file_cb
, diff_binary_cb
, diff_hunk_cb
, diff_line_cb
, &exp
));
1367 cl_assert_equal_i(0, exp
.files
);
1368 cl_assert_equal_i(0, exp
.hunks
);
1369 cl_assert_equal_i(0, exp
.lines
);
1371 git_diff_free(diff
);
1375 void test_diff_workdir__untracked_directory_scenarios(void)
1377 git_diff_options opts
= GIT_DIFF_OPTIONS_INIT
;
1378 git_diff
*diff
= NULL
;
1380 char *pathspec
= NULL
;
1381 static const char *files0
[] = {
1382 "subdir/deleted_file",
1383 "subdir/modified_file",
1387 static const char *files1
[] = {
1388 "subdir/deleted_file",
1389 "subdir/directory/",
1390 "subdir/modified_file",
1394 static const char *files2
[] = {
1395 "subdir/deleted_file",
1396 "subdir/directory/more/notignored",
1397 "subdir/modified_file",
1402 g_repo
= cl_git_sandbox_init("status");
1403 cl_git_mkfile("status/.gitignore", "ignored\n");
1405 opts
.context_lines
= 3;
1406 opts
.interhunk_lines
= 1;
1407 opts
.flags
|= GIT_DIFF_INCLUDE_IGNORED
| GIT_DIFF_INCLUDE_UNTRACKED
;
1408 opts
.pathspec
.strings
= &pathspec
;
1409 opts
.pathspec
.count
= 1;
1410 pathspec
= "subdir";
1412 /* baseline for "subdir" pathspec */
1414 memset(&exp
, 0, sizeof(exp
));
1417 cl_git_pass(git_diff_index_to_workdir(&diff
, g_repo
, NULL
, &opts
));
1419 cl_git_pass(git_diff_foreach(diff
, diff_file_cb
, NULL
, NULL
, NULL
, &exp
));
1421 cl_assert_equal_i(3, exp
.files
);
1422 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_ADDED
]);
1423 cl_assert_equal_i(1, exp
.file_status
[GIT_DELTA_DELETED
]);
1424 cl_assert_equal_i(1, exp
.file_status
[GIT_DELTA_MODIFIED
]);
1425 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_IGNORED
]);
1426 cl_assert_equal_i(1, exp
.file_status
[GIT_DELTA_UNTRACKED
]);
1428 git_diff_free(diff
);
1430 /* empty directory */
1432 cl_git_pass(p_mkdir("status/subdir/directory", 0777));
1434 memset(&exp
, 0, sizeof(exp
));
1437 cl_git_pass(git_diff_index_to_workdir(&diff
, g_repo
, NULL
, &opts
));
1439 cl_git_pass(git_diff_foreach(diff
, diff_file_cb
, NULL
, NULL
, NULL
, &exp
));
1441 cl_assert_equal_i(4, exp
.files
);
1442 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_ADDED
]);
1443 cl_assert_equal_i(1, exp
.file_status
[GIT_DELTA_DELETED
]);
1444 cl_assert_equal_i(1, exp
.file_status
[GIT_DELTA_MODIFIED
]);
1445 cl_assert_equal_i(1, exp
.file_status
[GIT_DELTA_IGNORED
]);
1446 cl_assert_equal_i(1, exp
.file_status
[GIT_DELTA_UNTRACKED
]);
1448 git_diff_free(diff
);
1450 /* empty directory in empty directory */
1452 cl_git_pass(p_mkdir("status/subdir/directory/empty", 0777));
1454 memset(&exp
, 0, sizeof(exp
));
1457 cl_git_pass(git_diff_index_to_workdir(&diff
, g_repo
, NULL
, &opts
));
1459 cl_git_pass(git_diff_foreach(diff
, diff_file_cb
, NULL
, NULL
, NULL
, &exp
));
1461 cl_assert_equal_i(4, exp
.files
);
1462 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_ADDED
]);
1463 cl_assert_equal_i(1, exp
.file_status
[GIT_DELTA_DELETED
]);
1464 cl_assert_equal_i(1, exp
.file_status
[GIT_DELTA_MODIFIED
]);
1465 cl_assert_equal_i(1, exp
.file_status
[GIT_DELTA_IGNORED
]);
1466 cl_assert_equal_i(1, exp
.file_status
[GIT_DELTA_UNTRACKED
]);
1468 git_diff_free(diff
);
1470 /* directory with only ignored files */
1472 cl_git_pass(p_mkdir("status/subdir/directory/deeper", 0777));
1473 cl_git_mkfile("status/subdir/directory/deeper/ignored", "ignore me\n");
1475 cl_git_pass(p_mkdir("status/subdir/directory/another", 0777));
1476 cl_git_mkfile("status/subdir/directory/another/ignored", "ignore me\n");
1478 memset(&exp
, 0, sizeof(exp
));
1481 cl_git_pass(git_diff_index_to_workdir(&diff
, g_repo
, NULL
, &opts
));
1483 cl_git_pass(git_diff_foreach(diff
, diff_file_cb
, NULL
, NULL
, NULL
, &exp
));
1485 cl_assert_equal_i(4, exp
.files
);
1486 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_ADDED
]);
1487 cl_assert_equal_i(1, exp
.file_status
[GIT_DELTA_DELETED
]);
1488 cl_assert_equal_i(1, exp
.file_status
[GIT_DELTA_MODIFIED
]);
1489 cl_assert_equal_i(1, exp
.file_status
[GIT_DELTA_IGNORED
]);
1490 cl_assert_equal_i(1, exp
.file_status
[GIT_DELTA_UNTRACKED
]);
1492 git_diff_free(diff
);
1494 /* directory with ignored directory (contents irrelevant) */
1496 cl_git_pass(p_mkdir("status/subdir/directory/more", 0777));
1497 cl_git_pass(p_mkdir("status/subdir/directory/more/ignored", 0777));
1498 cl_git_mkfile("status/subdir/directory/more/ignored/notignored",
1499 "inside ignored dir\n");
1501 memset(&exp
, 0, sizeof(exp
));
1504 cl_git_pass(git_diff_index_to_workdir(&diff
, g_repo
, NULL
, &opts
));
1506 cl_git_pass(git_diff_foreach(diff
, diff_file_cb
, NULL
, NULL
, NULL
, &exp
));
1508 cl_assert_equal_i(4, exp
.files
);
1509 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_ADDED
]);
1510 cl_assert_equal_i(1, exp
.file_status
[GIT_DELTA_DELETED
]);
1511 cl_assert_equal_i(1, exp
.file_status
[GIT_DELTA_MODIFIED
]);
1512 cl_assert_equal_i(1, exp
.file_status
[GIT_DELTA_IGNORED
]);
1513 cl_assert_equal_i(1, exp
.file_status
[GIT_DELTA_UNTRACKED
]);
1515 git_diff_free(diff
);
1517 /* quick version avoids directory scan */
1519 opts
.flags
= opts
.flags
| GIT_DIFF_ENABLE_FAST_UNTRACKED_DIRS
;
1521 memset(&exp
, 0, sizeof(exp
));
1524 cl_git_pass(git_diff_index_to_workdir(&diff
, g_repo
, NULL
, &opts
));
1526 cl_git_pass(git_diff_foreach(diff
, diff_file_cb
, NULL
, NULL
, NULL
, &exp
));
1528 cl_assert_equal_i(4, exp
.files
);
1529 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_ADDED
]);
1530 cl_assert_equal_i(1, exp
.file_status
[GIT_DELTA_DELETED
]);
1531 cl_assert_equal_i(1, exp
.file_status
[GIT_DELTA_MODIFIED
]);
1532 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_IGNORED
]);
1533 cl_assert_equal_i(2, exp
.file_status
[GIT_DELTA_UNTRACKED
]);
1535 git_diff_free(diff
);
1537 /* directory with nested non-ignored content */
1539 opts
.flags
= opts
.flags
& ~GIT_DIFF_ENABLE_FAST_UNTRACKED_DIRS
;
1541 cl_git_mkfile("status/subdir/directory/more/notignored",
1542 "not ignored deep under untracked\n");
1544 memset(&exp
, 0, sizeof(exp
));
1547 cl_git_pass(git_diff_index_to_workdir(&diff
, g_repo
, NULL
, &opts
));
1549 cl_git_pass(git_diff_foreach(diff
, diff_file_cb
, NULL
, NULL
, NULL
, &exp
));
1551 cl_assert_equal_i(4, exp
.files
);
1552 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_ADDED
]);
1553 cl_assert_equal_i(1, exp
.file_status
[GIT_DELTA_DELETED
]);
1554 cl_assert_equal_i(1, exp
.file_status
[GIT_DELTA_MODIFIED
]);
1555 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_IGNORED
]);
1556 cl_assert_equal_i(2, exp
.file_status
[GIT_DELTA_UNTRACKED
]);
1558 git_diff_free(diff
);
1560 /* use RECURSE_UNTRACKED_DIRS to get actual untracked files (no ignores) */
1562 opts
.flags
= opts
.flags
& ~GIT_DIFF_INCLUDE_IGNORED
;
1563 opts
.flags
= opts
.flags
| GIT_DIFF_RECURSE_UNTRACKED_DIRS
;
1565 memset(&exp
, 0, sizeof(exp
));
1568 cl_git_pass(git_diff_index_to_workdir(&diff
, g_repo
, NULL
, &opts
));
1570 cl_git_pass(git_diff_foreach(diff
, diff_file_cb
, NULL
, NULL
, NULL
, &exp
));
1572 cl_assert_equal_i(4, exp
.files
);
1573 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_ADDED
]);
1574 cl_assert_equal_i(1, exp
.file_status
[GIT_DELTA_DELETED
]);
1575 cl_assert_equal_i(1, exp
.file_status
[GIT_DELTA_MODIFIED
]);
1576 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_IGNORED
]);
1577 cl_assert_equal_i(2, exp
.file_status
[GIT_DELTA_UNTRACKED
]);
1579 git_diff_free(diff
);
1583 void test_diff_workdir__untracked_directory_comes_last(void)
1585 git_diff_options opts
= GIT_DIFF_OPTIONS_INIT
;
1586 git_diff
*diff
= NULL
;
1588 g_repo
= cl_git_sandbox_init("renames");
1590 cl_git_mkfile("renames/.gitignore", "*.ign\n");
1591 cl_git_pass(p_mkdir("renames/zzz_untracked", 0777));
1592 cl_git_mkfile("renames/zzz_untracked/an.ign", "ignore me please");
1593 cl_git_mkfile("renames/zzz_untracked/skip.ign", "ignore me really");
1594 cl_git_mkfile("renames/zzz_untracked/test.ign", "ignore me now");
1596 opts
.context_lines
= 3;
1597 opts
.interhunk_lines
= 1;
1598 opts
.flags
|= GIT_DIFF_INCLUDE_IGNORED
| GIT_DIFF_INCLUDE_UNTRACKED
;
1600 cl_git_pass(git_diff_index_to_workdir(&diff
, g_repo
, NULL
, &opts
));
1602 cl_assert(diff
!= NULL
);
1604 git_diff_free(diff
);
1607 void test_diff_workdir__untracked_with_bom(void)
1609 git_diff_options opts
= GIT_DIFF_OPTIONS_INIT
;
1610 git_diff
*diff
= NULL
;
1611 const git_diff_delta
*delta
;
1613 g_repo
= cl_git_sandbox_init("empty_standard_repo");
1614 cl_repo_set_bool(g_repo
, "core.autocrlf", true);
1616 cl_git_write2file("empty_standard_repo/bom.txt",
1617 "\xFF\xFE\x31\x00\x32\x00\x33\x00\x34\x00", 10, O_WRONLY
|O_CREAT
, 0664);
1620 GIT_DIFF_INCLUDE_UNTRACKED
| GIT_DIFF_SHOW_UNTRACKED_CONTENT
;
1622 cl_git_pass(git_diff_index_to_workdir(&diff
, g_repo
, NULL
, &opts
));
1624 cl_assert_equal_i(1, git_diff_num_deltas(diff
));
1625 cl_assert((delta
= git_diff_get_delta(diff
, 0)) != NULL
);
1626 cl_assert_equal_i(GIT_DELTA_UNTRACKED
, delta
->status
);
1628 /* not known at this point
1629 * cl_assert((delta->flags & GIT_DIFF_FLAG_BINARY) != 0);
1632 git_diff_free(diff
);
1635 void test_diff_workdir__patience_diff(void)
1638 git_diff_options opts
= GIT_DIFF_OPTIONS_INIT
;
1639 git_diff
*diff
= NULL
;
1640 git_patch
*patch
= NULL
;
1641 git_buf buf
= GIT_BUF_INIT
;
1642 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";
1643 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";
1645 g_repo
= cl_git_sandbox_init("empty_standard_repo");
1646 cl_repo_set_bool(g_repo
, "core.autocrlf", true);
1647 cl_git_pass(git_repository_index(&index
, g_repo
));
1650 "empty_standard_repo/test.txt",
1651 "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");
1652 cl_git_pass(git_index_add_bypath(index
, "test.txt"));
1653 cl_repo_commit_from_index(NULL
, g_repo
, NULL
, 1372350000, "Base");
1654 git_index_free(index
);
1657 "empty_standard_repo/test.txt",
1658 "When I wrote this\nI did not know\nI did not know\nhow to create\na patience diff\nanother problem\na minimal diff\n");
1660 cl_git_pass(git_diff_index_to_workdir(&diff
, g_repo
, NULL
, &opts
));
1661 cl_assert_equal_i(1, git_diff_num_deltas(diff
));
1662 cl_git_pass(git_patch_from_diff(&patch
, diff
, 0));
1663 cl_git_pass(git_patch_to_buf(&buf
, patch
));
1665 cl_assert_equal_s(expected_normal
, buf
.ptr
);
1666 git_buf_clear(&buf
);
1667 git_patch_free(patch
);
1668 git_diff_free(diff
);
1670 opts
.flags
|= GIT_DIFF_PATIENCE
;
1672 cl_git_pass(git_diff_index_to_workdir(&diff
, g_repo
, NULL
, &opts
));
1673 cl_assert_equal_i(1, git_diff_num_deltas(diff
));
1674 cl_git_pass(git_patch_from_diff(&patch
, diff
, 0));
1675 cl_git_pass(git_patch_to_buf(&buf
, patch
));
1677 cl_assert_equal_s(expected_patience
, buf
.ptr
);
1678 git_buf_clear(&buf
);
1680 git_buf_dispose(&buf
);
1681 git_patch_free(patch
);
1682 git_diff_free(diff
);
1685 void test_diff_workdir__with_stale_index(void)
1687 git_diff_options opts
= GIT_DIFF_OPTIONS_INIT
;
1688 git_diff
*diff
= NULL
;
1689 git_index
*idx
= NULL
;
1692 g_repo
= cl_git_sandbox_init("status");
1693 cl_git_pass(git_repository_index(&idx
, g_repo
));
1695 /* make the in-memory index invalid */
1699 cl_git_pass(git_repository_open(&r2
, "status"));
1700 cl_git_pass(git_repository_index(&idx2
, r2
));
1701 cl_git_pass(git_index_add_bypath(idx2
, "new_file"));
1702 cl_git_pass(git_index_add_bypath(idx2
, "subdir/new_file"));
1703 cl_git_pass(git_index_remove_bypath(idx2
, "staged_new_file"));
1704 cl_git_pass(git_index_remove_bypath(idx2
, "staged_changes_file_deleted"));
1705 cl_git_pass(git_index_write(idx2
));
1706 git_index_free(idx2
);
1707 git_repository_free(r2
);
1710 opts
.context_lines
= 3;
1711 opts
.interhunk_lines
= 1;
1712 opts
.flags
|= GIT_DIFF_INCLUDE_UNTRACKED
| GIT_DIFF_INCLUDE_UNMODIFIED
;
1714 /* first try with index pointer which should prevent reload */
1716 cl_git_pass(git_diff_index_to_workdir(&diff
, g_repo
, idx
, &opts
));
1718 memset(&exp
, 0, sizeof(exp
));
1720 cl_git_pass(git_diff_foreach(
1721 diff
, diff_file_cb
, diff_binary_cb
, diff_hunk_cb
, diff_line_cb
, &exp
));
1723 cl_assert_equal_i(17, exp
.files
);
1724 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_ADDED
]);
1725 cl_assert_equal_i(4, exp
.file_status
[GIT_DELTA_DELETED
]);
1726 cl_assert_equal_i(4, exp
.file_status
[GIT_DELTA_MODIFIED
]);
1727 cl_assert_equal_i(4, exp
.file_status
[GIT_DELTA_UNTRACKED
]);
1728 cl_assert_equal_i(5, exp
.file_status
[GIT_DELTA_UNMODIFIED
]);
1730 git_diff_free(diff
);
1732 /* now let's try without the index pointer which should trigger reload */
1734 /* two files that were UNTRACKED should have become UNMODIFIED */
1735 /* one file that was UNMODIFIED should now have become UNTRACKED */
1736 /* one file that was DELETED should now be gone completely */
1738 cl_git_pass(git_diff_index_to_workdir(&diff
, g_repo
, NULL
, &opts
));
1740 memset(&exp
, 0, sizeof(exp
));
1742 cl_git_pass(git_diff_foreach(
1743 diff
, diff_file_cb
, diff_binary_cb
, diff_hunk_cb
, diff_line_cb
, &exp
));
1745 git_diff_free(diff
);
1747 cl_assert_equal_i(16, exp
.files
);
1748 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_ADDED
]);
1749 cl_assert_equal_i(3, exp
.file_status
[GIT_DELTA_DELETED
]);
1750 cl_assert_equal_i(4, exp
.file_status
[GIT_DELTA_MODIFIED
]);
1751 cl_assert_equal_i(3, exp
.file_status
[GIT_DELTA_UNTRACKED
]);
1752 cl_assert_equal_i(6, exp
.file_status
[GIT_DELTA_UNMODIFIED
]);
1754 git_index_free(idx
);
1757 static int touch_file(void *payload
, git_buf
*path
)
1760 struct p_timeval times
[2];
1762 GIT_UNUSED(payload
);
1763 if (git_path_isdir(path
->ptr
))
1766 cl_must_pass(p_stat(path
->ptr
, &st
));
1768 times
[0].tv_sec
= st
.st_mtime
+ 3;
1769 times
[0].tv_usec
= 0;
1770 times
[1].tv_sec
= st
.st_mtime
+ 3;
1771 times
[1].tv_usec
= 0;
1773 cl_must_pass(p_utimes(path
->ptr
, times
));
1777 static void basic_diff_status(git_diff
**out
, const git_diff_options
*opts
)
1781 cl_git_pass(git_diff_index_to_workdir(out
, g_repo
, NULL
, opts
));
1783 memset(&exp
, 0, sizeof(exp
));
1785 cl_git_pass(git_diff_foreach(
1786 *out
, diff_file_cb
, diff_binary_cb
, diff_hunk_cb
, diff_line_cb
, &exp
));
1788 cl_assert_equal_i(13, exp
.files
);
1789 cl_assert_equal_i(0, exp
.file_status
[GIT_DELTA_ADDED
]);
1790 cl_assert_equal_i(4, exp
.file_status
[GIT_DELTA_DELETED
]);
1791 cl_assert_equal_i(4, exp
.file_status
[GIT_DELTA_MODIFIED
]);
1792 cl_assert_equal_i(1, exp
.file_status
[GIT_DELTA_IGNORED
]);
1793 cl_assert_equal_i(4, exp
.file_status
[GIT_DELTA_UNTRACKED
]);
1796 void test_diff_workdir__can_update_index(void)
1798 git_diff_options opts
= GIT_DIFF_OPTIONS_INIT
;
1799 git_diff
*diff
= NULL
;
1800 git_diff_perfdata perf
= GIT_DIFF_PERFDATA_INIT
;
1803 g_repo
= cl_git_sandbox_init("status");
1805 /* touch all the files so stat times are different */
1807 git_buf path
= GIT_BUF_INIT
;
1808 cl_git_pass(git_buf_sets(&path
, "status"));
1809 cl_git_pass(git_path_direach(&path
, 0, touch_file
, NULL
));
1810 git_buf_dispose(&path
);
1813 opts
.flags
|= GIT_DIFF_INCLUDE_IGNORED
| GIT_DIFF_INCLUDE_UNTRACKED
;
1815 basic_diff_status(&diff
, &opts
);
1817 cl_git_pass(git_diff_get_perfdata(&perf
, diff
));
1818 cl_assert_equal_sz(13 + 3, perf
.stat_calls
);
1819 cl_assert_equal_sz(5, perf
.oid_calculations
);
1821 git_diff_free(diff
);
1823 /* now allow diff to update stat cache */
1824 opts
.flags
|= GIT_DIFF_UPDATE_INDEX
;
1826 /* advance a tick for the index so we don't re-calculate racily-clean entries */
1827 cl_git_pass(git_repository_index__weakptr(&index
, g_repo
));
1830 basic_diff_status(&diff
, &opts
);
1832 cl_git_pass(git_diff_get_perfdata(&perf
, diff
));
1833 cl_assert_equal_sz(13 + 3, perf
.stat_calls
);
1834 cl_assert_equal_sz(5, perf
.oid_calculations
);
1836 git_diff_free(diff
);
1838 /* now if we do it again, we should see fewer OID calculations */
1840 /* tick again as the index updating from the previous diff might have reset the timestamp */
1842 basic_diff_status(&diff
, &opts
);
1844 cl_git_pass(git_diff_get_perfdata(&perf
, diff
));
1845 cl_assert_equal_sz(13 + 3, perf
.stat_calls
);
1846 cl_assert_equal_sz(0, perf
.oid_calculations
);
1848 git_diff_free(diff
);
1851 #define STR7 "0123456"
1852 #define STR8 "01234567"
1853 #define STR40 STR8 STR8 STR8 STR8 STR8
1854 #define STR200 STR40 STR40 STR40 STR40 STR40
1855 #define STR999Z STR200 STR200 STR200 STR200 STR40 STR40 STR40 STR40 \
1856 STR8 STR8 STR8 STR8 STR7 "\0"
1857 #define STR1000 STR200 STR200 STR200 STR200 STR200
1858 #define STR3999Z STR1000 STR1000 STR1000 STR999Z
1859 #define STR4000 STR1000 STR1000 STR1000 STR1000
1861 static void assert_delta_binary(git_diff
*diff
, size_t idx
, int is_binary
)
1864 const git_diff_delta
*delta
;
1866 cl_git_pass(git_patch_from_diff(&patch
, diff
, idx
));
1867 delta
= git_patch_get_delta(patch
);
1868 cl_assert_equal_b((delta
->flags
& GIT_DIFF_FLAG_BINARY
), is_binary
);
1869 git_patch_free(patch
);
1872 void test_diff_workdir__binary_detection(void)
1875 git_diff
*diff
= NULL
;
1876 git_buf b
= GIT_BUF_INIT
;
1878 git_buf data
[10] = {
1879 { "1234567890", 0, 0 }, /* 0 - all ascii text control */
1880 { "\xC3\x85\xC3\xBC\xE2\x80\xA0\x48\xC3\xB8\xCF\x80\xCE\xA9", 0, 0 }, /* 1 - UTF-8 multibyte text */
1881 { "\xEF\xBB\xBF\xC3\x9C\xE2\xA4\x92\xC6\x92\x38\xC2\xA3\xE2\x82\xAC", 0, 0 }, /* 2 - UTF-8 with BOM */
1882 { STR999Z
, 0, 1000 }, /* 3 - ASCII with NUL at 1000 */
1883 { STR3999Z
, 0, 4000 }, /* 4 - ASCII with NUL at 4000 */
1884 { STR4000 STR3999Z
"x", 0, 8001 }, /* 5 - ASCII with NUL at 8000 */
1885 { STR4000 STR4000
"\0", 0, 8001 }, /* 6 - ASCII with NUL at 8001 */
1886 { "\x00\xDC\x00\x6E\x21\x39\xFE\x0E\x00\x63\x00\xF8"
1887 "\x00\x64\x00\x65\x20\x48", 0, 18 }, /* 7 - UTF-16 text */
1888 { "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d"
1889 "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d",
1890 0, 26 }, /* 8 - All non-printable characters (no NUL) */
1891 { "Hello \x01\x02\x03\x04\x05\x06 World!\x01\x02\x03\x04"
1892 "\x05\x06\x07", 0, 26 }, /* 9 - 50-50 non-printable (no NUL) */
1895 g_repo
= cl_git_sandbox_init("empty_standard_repo");
1896 cl_git_pass(git_repository_index(&idx
, g_repo
));
1898 /* We start with ASCII in index and test data in workdir,
1899 * then we will try with test data in index and ASCII in workdir.
1902 cl_git_pass(git_buf_sets(&b
, "empty_standard_repo/0"));
1903 for (i
= 0; i
< 10; ++i
) {
1904 b
.ptr
[b
.size
- 1] = '0' + i
;
1905 cl_git_mkfile(b
.ptr
, "baseline");
1906 cl_git_pass(git_index_add_bypath(idx
, &b
.ptr
[b
.size
- 1]));
1908 if (data
[i
].size
== 0)
1909 data
[i
].size
= strlen(data
[i
].ptr
);
1911 b
.ptr
, data
[i
].ptr
, data
[i
].size
, O_WRONLY
|O_TRUNC
, 0664);
1913 cl_git_pass(git_index_write(idx
));
1915 cl_git_pass(git_diff_index_to_workdir(&diff
, g_repo
, NULL
, NULL
));
1917 cl_assert_equal_i(10, git_diff_num_deltas(diff
));
1919 /* using diff binary detection (i.e. looking for NUL byte) */
1920 assert_delta_binary(diff
, 0, false);
1921 assert_delta_binary(diff
, 1, false);
1922 assert_delta_binary(diff
, 2, false);
1923 assert_delta_binary(diff
, 3, true);
1924 assert_delta_binary(diff
, 4, true);
1925 assert_delta_binary(diff
, 5, true);
1926 assert_delta_binary(diff
, 6, false);
1927 assert_delta_binary(diff
, 7, true);
1928 assert_delta_binary(diff
, 8, false);
1929 assert_delta_binary(diff
, 9, false);
1930 /* The above have been checked to match command-line Git */
1932 git_diff_free(diff
);
1934 cl_git_pass(git_buf_sets(&b
, "empty_standard_repo/0"));
1935 for (i
= 0; i
< 10; ++i
) {
1936 b
.ptr
[b
.size
- 1] = '0' + i
;
1937 cl_git_pass(git_index_add_bypath(idx
, &b
.ptr
[b
.size
- 1]));
1939 cl_git_write2file(b
.ptr
, "baseline\n", 9, O_WRONLY
|O_TRUNC
, 0664);
1941 cl_git_pass(git_index_write(idx
));
1943 cl_git_pass(git_diff_index_to_workdir(&diff
, g_repo
, NULL
, NULL
));
1945 cl_assert_equal_i(10, git_diff_num_deltas(diff
));
1947 /* using diff binary detection (i.e. looking for NUL byte) */
1948 assert_delta_binary(diff
, 0, false);
1949 assert_delta_binary(diff
, 1, false);
1950 assert_delta_binary(diff
, 2, false);
1951 assert_delta_binary(diff
, 3, true);
1952 assert_delta_binary(diff
, 4, true);
1953 assert_delta_binary(diff
, 5, true);
1954 assert_delta_binary(diff
, 6, false);
1955 assert_delta_binary(diff
, 7, true);
1956 assert_delta_binary(diff
, 8, false);
1957 assert_delta_binary(diff
, 9, false);
1959 git_diff_free(diff
);
1961 git_index_free(idx
);
1962 git_buf_dispose(&b
);
1965 void test_diff_workdir__to_index_conflicted(void) {
1966 const char *a_commit
= "26a125ee1bf"; /* the current HEAD */
1967 git_index_entry ancestor
= {{0}}, ours
= {{0}}, theirs
= {{0}};
1970 git_diff
*diff1
, *diff2
;
1971 const git_diff_delta
*delta
;
1973 g_repo
= cl_git_sandbox_init("status");
1974 a
= resolve_commit_oid_to_tree(g_repo
, a_commit
);
1976 cl_git_pass(git_repository_index(&index
, g_repo
));
1978 ancestor
.path
= ours
.path
= theirs
.path
= "_file";
1979 ancestor
.mode
= ours
.mode
= theirs
.mode
= 0100644;
1980 git_oid_fromstr(&ancestor
.id
, "d427e0b2e138501a3d15cc376077a3631e15bd46");
1981 git_oid_fromstr(&ours
.id
, "ee3fa1b8c00aff7fe02065fdb50864bb0d932ccf");
1982 git_oid_fromstr(&theirs
.id
, "2bd0a343aeef7a2cf0d158478966a6e587ff3863");
1983 cl_git_pass(git_index_conflict_add(index
, &ancestor
, &ours
, &theirs
));
1985 cl_git_pass(git_diff_tree_to_index(&diff1
, g_repo
, a
, index
, NULL
));
1986 cl_git_pass(git_diff_index_to_workdir(&diff2
, g_repo
, index
, NULL
));
1987 cl_git_pass(git_diff_merge(diff1
, diff2
));
1989 cl_assert_equal_i(git_diff_num_deltas(diff1
), 12);
1990 delta
= git_diff_get_delta(diff1
, 0);
1991 cl_assert_equal_s(delta
->old_file
.path
, "_file");
1992 cl_assert_equal_i(delta
->nfiles
, 1);
1993 cl_assert_equal_i(delta
->status
, GIT_DELTA_CONFLICTED
);
1995 git_diff_free(diff2
);
1996 git_diff_free(diff1
);
1997 git_index_free(index
);
2001 void test_diff_workdir__only_writes_index_when_necessary(void)
2004 git_diff_options opts
= GIT_DIFF_OPTIONS_INIT
;
2005 git_diff
*diff
= NULL
;
2006 git_reference
*head
;
2007 git_object
*head_object
;
2008 git_oid initial
, first
, second
;
2009 git_buf path
= GIT_BUF_INIT
;
2011 struct p_timeval times
[2];
2013 opts
.flags
|= GIT_DIFF_INCLUDE_UNTRACKED
| GIT_DIFF_UPDATE_INDEX
;
2015 g_repo
= cl_git_sandbox_init("status");
2017 cl_git_pass(git_repository_index(&index
, g_repo
));
2018 cl_git_pass(git_repository_head(&head
, g_repo
));
2019 cl_git_pass(git_reference_peel(&head_object
, head
, GIT_OBJECT_COMMIT
));
2021 cl_git_pass(git_reset(g_repo
, head_object
, GIT_RESET_HARD
, NULL
));
2023 git_oid_cpy(&initial
, git_index_checksum(index
));
2025 /* update the index timestamp to avoid raciness */
2026 cl_must_pass(p_stat("status/.git/index", &st
));
2028 times
[0].tv_sec
= st
.st_mtime
+ 5;
2029 times
[0].tv_usec
= 0;
2030 times
[1].tv_sec
= st
.st_mtime
+ 5;
2031 times
[1].tv_usec
= 0;
2033 cl_must_pass(p_utimes("status/.git/index", times
));
2035 /* ensure diff doesn't touch the index */
2036 cl_git_pass(git_diff_index_to_workdir(&diff
, g_repo
, NULL
, &opts
));
2037 git_diff_free(diff
);
2039 git_oid_cpy(&first
, git_index_checksum(index
));
2040 cl_assert(!git_oid_equal(&initial
, &first
));
2042 /* touch all the files so stat times are different */
2043 cl_git_pass(git_buf_sets(&path
, "status"));
2044 cl_git_pass(git_path_direach(&path
, 0, touch_file
, NULL
));
2046 cl_git_pass(git_diff_index_to_workdir(&diff
, g_repo
, NULL
, &opts
));
2047 git_diff_free(diff
);
2049 /* ensure the second diff did update the index */
2050 git_oid_cpy(&second
, git_index_checksum(index
));
2051 cl_assert(!git_oid_equal(&first
, &second
));
2053 git_buf_dispose(&path
);
2054 git_object_free(head_object
);
2055 git_reference_free(head
);
2056 git_index_free(index
);
2059 void test_diff_workdir__to_index_pathlist(void)
2063 git_diff_options opts
= GIT_DIFF_OPTIONS_INIT
;
2064 git_vector pathlist
= GIT_VECTOR_INIT
;
2066 git_vector_insert(&pathlist
, "foobar/asdf");
2067 git_vector_insert(&pathlist
, "subdir/asdf");
2068 git_vector_insert(&pathlist
, "ignored/asdf");
2070 g_repo
= cl_git_sandbox_init("status");
2072 cl_git_mkfile("status/.gitignore", ".gitignore\n" "ignored/\n");
2074 cl_must_pass(p_mkdir("status/foobar", 0777));
2075 cl_git_mkfile("status/foobar/one", "one\n");
2077 cl_must_pass(p_mkdir("status/ignored", 0777));
2078 cl_git_mkfile("status/ignored/one", "one\n");
2079 cl_git_mkfile("status/ignored/two", "two\n");
2080 cl_git_mkfile("status/ignored/three", "three\n");
2082 cl_git_pass(git_repository_index(&index
, g_repo
));
2084 opts
.flags
= GIT_DIFF_INCLUDE_IGNORED
;
2085 opts
.pathspec
.strings
= (char **)pathlist
.contents
;
2086 opts
.pathspec
.count
= pathlist
.length
;
2088 cl_git_pass(git_diff_index_to_workdir(&diff
, g_repo
, index
, &opts
));
2089 cl_assert_equal_i(0, git_diff_num_deltas(diff
));
2090 git_diff_free(diff
);
2092 opts
.flags
|= GIT_DIFF_DISABLE_PATHSPEC_MATCH
;
2094 cl_git_pass(git_diff_index_to_workdir(&diff
, g_repo
, index
, &opts
));
2095 cl_assert_equal_i(0, git_diff_num_deltas(diff
));
2096 git_diff_free(diff
);
2098 git_index_free(index
);
2099 git_vector_free(&pathlist
);
2102 void test_diff_workdir__symlink_changed_on_non_symlink_platform(void)
2106 diff_expects exp
= {0};
2107 const git_diff_delta
*delta
;
2108 const char *commit
= "7fccd7";
2109 git_diff_options opts
= GIT_DIFF_OPTIONS_INIT
;
2110 git_vector pathlist
= GIT_VECTOR_INIT
;
2113 g_repo
= cl_git_sandbox_init("unsymlinked.git");
2115 cl_git_pass(git_repository__configmap_lookup(&symlinks
, g_repo
, GIT_CONFIGMAP_SYMLINKS
));
2120 cl_git_pass(git_vector_insert(&pathlist
, "include/Nu/Nu.h"));
2122 opts
.pathspec
.strings
= (char **)pathlist
.contents
;
2123 opts
.pathspec
.count
= pathlist
.length
;
2125 cl_must_pass(p_mkdir("symlink", 0777));
2126 cl_git_pass(git_repository_set_workdir(g_repo
, "symlink", false));
2128 cl_assert((tree
= resolve_commit_oid_to_tree(g_repo
, commit
)) != NULL
);
2130 /* first, do the diff with the original contents */
2132 cl_git_pass(git_futils_mkpath2file("symlink/include/Nu/Nu.h", 0755));
2133 cl_git_mkfile("symlink/include/Nu/Nu.h", "../../objc/Nu.h");
2135 cl_git_pass(git_diff_tree_to_workdir(&diff
, g_repo
, tree
, &opts
));
2136 cl_assert_equal_i(0, git_diff_num_deltas(diff
));
2137 git_diff_free(diff
);
2139 /* now update the contents and expect a difference, but that the file
2140 * mode has persisted as a symbolic link.
2143 cl_git_rewritefile("symlink/include/Nu/Nu.h", "awesome content\n");
2145 cl_git_pass(git_diff_tree_to_workdir(&diff
, g_repo
, tree
, &opts
));
2147 cl_git_pass(git_diff_foreach(
2148 diff
, diff_file_cb
, diff_binary_cb
, diff_hunk_cb
, diff_line_cb
, &exp
));
2149 cl_assert_equal_i(1, exp
.files
);
2151 cl_assert_equal_i(1, git_diff_num_deltas(diff
));
2152 delta
= git_diff_get_delta(diff
, 0);
2153 cl_assert_equal_i(GIT_FILEMODE_LINK
, delta
->old_file
.mode
);
2154 cl_assert_equal_i(GIT_FILEMODE_LINK
, delta
->new_file
.mode
);
2156 git_diff_free(diff
);
2158 cl_git_pass(git_futils_rmdir_r("symlink", NULL
, GIT_RMDIR_REMOVE_FILES
));
2160 git_tree_free(tree
);
2161 git_vector_free(&pathlist
);