1 #include "clar_libgit2.h"
4 #include "status_data.h"
8 #include "../diff/diff_helpers.h"
9 #include "../checkout/checkout_helpers.h"
10 #include "git2/sys/diff.h"
15 * This will be called once after each test finishes, even
18 void test_status_worktree__cleanup(void)
20 cl_git_sandbox_cleanup();
24 * Tests - Status determination on a working tree
26 /* this test is equivalent to t18-status.c:statuscb0 */
27 void test_status_worktree__whole_repository(void)
29 status_entry_counts counts
;
30 git_repository
*repo
= cl_git_sandbox_init("status");
32 memset(&counts
, 0x0, sizeof(status_entry_counts
));
33 counts
.expected_entry_count
= entry_count0
;
34 counts
.expected_paths
= entry_paths0
;
35 counts
.expected_statuses
= entry_statuses0
;
38 git_status_foreach(repo
, cb_status__normal
, &counts
)
41 cl_assert_equal_i(counts
.expected_entry_count
, counts
.entry_count
);
42 cl_assert_equal_i(0, counts
.wrong_status_flags_count
);
43 cl_assert_equal_i(0, counts
.wrong_sorted_path
);
46 static void assert_show(
47 const int entry_counts
,
48 const char *entry_paths
[],
49 const unsigned int entry_statuses
[],
51 git_status_show_t show
,
52 unsigned int extra_flags
)
54 status_entry_counts counts
;
55 git_status_options opts
= GIT_STATUS_OPTIONS_INIT
;
57 memset(&counts
, 0x0, sizeof(status_entry_counts
));
58 counts
.expected_entry_count
= entry_counts
;
59 counts
.expected_paths
= entry_paths
;
60 counts
.expected_statuses
= entry_statuses
;
62 opts
.flags
= GIT_STATUS_OPT_DEFAULTS
| extra_flags
;
66 git_status_foreach_ext(repo
, &opts
, cb_status__normal
, &counts
)
69 cl_assert_equal_i(counts
.expected_entry_count
, counts
.entry_count
);
70 cl_assert_equal_i(0, counts
.wrong_status_flags_count
);
71 cl_assert_equal_i(0, counts
.wrong_sorted_path
);
74 void test_status_worktree__show_index_and_workdir(void)
76 assert_show(entry_count0
, entry_paths0
, entry_statuses0
,
77 cl_git_sandbox_init("status"), GIT_STATUS_SHOW_INDEX_AND_WORKDIR
, 0);
80 void test_status_worktree__show_index_only(void)
82 assert_show(entry_count5
, entry_paths5
, entry_statuses5
,
83 cl_git_sandbox_init("status"), GIT_STATUS_SHOW_INDEX_ONLY
, 0);
86 void test_status_worktree__show_workdir_only(void)
88 assert_show(entry_count6
, entry_paths6
, entry_statuses6
,
89 cl_git_sandbox_init("status"), GIT_STATUS_SHOW_WORKDIR_ONLY
, 0);
92 /* this test is equivalent to t18-status.c:statuscb1 */
93 void test_status_worktree__empty_repository(void)
96 git_repository
*repo
= cl_git_sandbox_init("empty_standard_repo");
98 cl_git_pass(git_status_foreach(repo
, cb_status__count
, &count
));
100 cl_assert_equal_i(0, count
);
103 static int remove_file_cb(void *data
, git_str
*file
)
105 const char *filename
= git_str_cstr(file
);
109 if (git__suffixcmp(filename
, ".git") == 0)
112 if (git_fs_path_isdir(filename
))
113 cl_git_pass(git_futils_rmdir_r(filename
, NULL
, GIT_RMDIR_REMOVE_FILES
));
115 cl_git_pass(p_unlink(git_str_cstr(file
)));
120 /* this test is equivalent to t18-status.c:statuscb2 */
121 void test_status_worktree__purged_worktree(void)
123 status_entry_counts counts
;
124 git_repository
*repo
= cl_git_sandbox_init("status");
125 git_str workdir
= GIT_STR_INIT
;
127 /* first purge the contents of the worktree */
128 cl_git_pass(git_str_sets(&workdir
, git_repository_workdir(repo
)));
129 cl_git_pass(git_fs_path_direach(&workdir
, 0, remove_file_cb
, NULL
));
130 git_str_dispose(&workdir
);
133 memset(&counts
, 0x0, sizeof(status_entry_counts
));
134 counts
.expected_entry_count
= entry_count2
;
135 counts
.expected_paths
= entry_paths2
;
136 counts
.expected_statuses
= entry_statuses2
;
139 git_status_foreach(repo
, cb_status__normal
, &counts
)
142 cl_assert_equal_i(counts
.expected_entry_count
, counts
.entry_count
);
143 cl_assert_equal_i(0, counts
.wrong_status_flags_count
);
144 cl_assert_equal_i(0, counts
.wrong_sorted_path
);
147 /* this test is similar to t18-status.c:statuscb3 */
148 void test_status_worktree__swap_subdir_and_file(void)
150 status_entry_counts counts
;
151 git_repository
*repo
= cl_git_sandbox_init("status");
153 git_status_options opts
= GIT_STATUS_OPTIONS_INIT
;
156 cl_git_pass(git_repository_index(&index
, repo
));
157 ignore_case
= (git_index_caps(index
) & GIT_INDEX_CAPABILITY_IGNORE_CASE
) != 0;
158 git_index_free(index
);
160 /* first alter the contents of the worktree */
161 cl_git_pass(p_rename("status/current_file", "status/swap"));
162 cl_git_pass(p_rename("status/subdir", "status/current_file"));
163 cl_git_pass(p_rename("status/swap", "status/subdir"));
165 cl_git_mkfile("status/.HEADER", "dummy");
166 cl_git_mkfile("status/42-is-not-prime.sigh", "dummy");
167 cl_git_mkfile("status/README.md", "dummy");
170 memset(&counts
, 0x0, sizeof(status_entry_counts
));
171 counts
.expected_entry_count
= entry_count3
;
172 counts
.expected_paths
= ignore_case
? entry_paths3_icase
: entry_paths3
;
173 counts
.expected_statuses
= ignore_case
? entry_statuses3_icase
: entry_statuses3
;
175 opts
.flags
= GIT_STATUS_OPT_INCLUDE_UNTRACKED
|
176 GIT_STATUS_OPT_INCLUDE_IGNORED
;
179 git_status_foreach_ext(repo
, &opts
, cb_status__normal
, &counts
)
182 cl_assert_equal_i(counts
.expected_entry_count
, counts
.entry_count
);
183 cl_assert_equal_i(0, counts
.wrong_status_flags_count
);
184 cl_assert_equal_i(0, counts
.wrong_sorted_path
);
187 void test_status_worktree__swap_subdir_with_recurse_and_pathspec(void)
189 status_entry_counts counts
;
190 git_repository
*repo
= cl_git_sandbox_init("status");
191 git_status_options opts
= GIT_STATUS_OPTIONS_INIT
;
193 /* first alter the contents of the worktree */
194 cl_git_pass(p_rename("status/current_file", "status/swap"));
195 cl_git_pass(p_rename("status/subdir", "status/current_file"));
196 cl_git_pass(p_rename("status/swap", "status/subdir"));
197 cl_git_mkfile("status/.new_file", "dummy");
198 cl_git_pass(git_futils_mkdir_r("status/zzz_new_dir", 0777));
199 cl_git_mkfile("status/zzz_new_dir/new_file", "dummy");
200 cl_git_mkfile("status/zzz_new_file", "dummy");
203 memset(&counts
, 0x0, sizeof(status_entry_counts
));
204 counts
.expected_entry_count
= entry_count4
;
205 counts
.expected_paths
= entry_paths4
;
206 counts
.expected_statuses
= entry_statuses4
;
208 opts
.flags
= GIT_STATUS_OPT_INCLUDE_UNTRACKED
|
209 GIT_STATUS_OPT_RECURSE_UNTRACKED_DIRS
;
210 /* TODO: set pathspec to "current_file" eventually */
213 git_status_foreach_ext(repo
, &opts
, cb_status__normal
, &counts
)
216 cl_assert_equal_i(counts
.expected_entry_count
, counts
.entry_count
);
217 cl_assert_equal_i(0, counts
.wrong_status_flags_count
);
218 cl_assert_equal_i(0, counts
.wrong_sorted_path
);
221 static void stage_and_commit(git_repository
*repo
, const char *path
)
225 cl_git_pass(git_repository_index(&index
, repo
));
226 cl_git_pass(git_index_add_bypath(index
, path
));
227 cl_repo_commit_from_index(NULL
, repo
, NULL
, 1323847743, "Initial commit\n");
228 git_index_free(index
);
231 void test_status_worktree__within_subdir(void)
233 status_entry_counts counts
;
234 git_repository
*repo
= cl_git_sandbox_init("status");
235 git_status_options opts
= GIT_STATUS_OPTIONS_INIT
;
236 char *paths
[] = { "zzz_new_dir" };
237 git_strarray pathsArray
;
239 /* first alter the contents of the worktree */
240 cl_git_mkfile("status/.new_file", "dummy");
241 cl_git_pass(git_futils_mkdir_r("status/zzz_new_dir", 0777));
242 cl_git_mkfile("status/zzz_new_dir/new_file", "dummy");
243 cl_git_mkfile("status/zzz_new_file", "dummy");
244 cl_git_mkfile("status/wut", "dummy");
246 stage_and_commit(repo
, "zzz_new_dir/new_file");
249 memset(&counts
, 0x0, sizeof(status_entry_counts
));
250 counts
.expected_entry_count
= entry_count4
;
251 counts
.expected_paths
= entry_paths4
;
252 counts
.expected_statuses
= entry_statuses4
;
255 opts
.flags
= GIT_STATUS_OPT_INCLUDE_UNTRACKED
|
256 GIT_STATUS_OPT_RECURSE_UNTRACKED_DIRS
|
257 GIT_STATUS_OPT_DISABLE_PATHSPEC_MATCH
;
259 pathsArray
.count
= 1;
260 pathsArray
.strings
= paths
;
261 opts
.pathspec
= pathsArray
;
263 /* We committed zzz_new_dir/new_file above. It shouldn't be reported. */
265 git_status_foreach_ext(repo
, &opts
, cb_status__normal
, &counts
)
268 cl_assert_equal_i(0, counts
.entry_count
);
269 cl_assert_equal_i(0, counts
.wrong_status_flags_count
);
270 cl_assert_equal_i(0, counts
.wrong_sorted_path
);
273 /* this test is equivalent to t18-status.c:singlestatus0 */
274 void test_status_worktree__single_file(void)
277 unsigned int status_flags
;
278 git_repository
*repo
= cl_git_sandbox_init("status");
280 for (i
= 0; i
< (int)entry_count0
; i
++) {
282 git_status_file(&status_flags
, repo
, entry_paths0
[i
])
284 cl_assert(entry_statuses0
[i
] == status_flags
);
288 /* this test is equivalent to t18-status.c:singlestatus1 */
289 void test_status_worktree__single_nonexistent_file(void)
292 unsigned int status_flags
;
293 git_repository
*repo
= cl_git_sandbox_init("status");
295 error
= git_status_file(&status_flags
, repo
, "nonexistent");
297 cl_assert(error
== GIT_ENOTFOUND
);
300 /* this test is equivalent to t18-status.c:singlestatus2 */
301 void test_status_worktree__single_nonexistent_file_empty_repo(void)
304 unsigned int status_flags
;
305 git_repository
*repo
= cl_git_sandbox_init("empty_standard_repo");
307 error
= git_status_file(&status_flags
, repo
, "nonexistent");
309 cl_assert(error
== GIT_ENOTFOUND
);
312 /* this test is equivalent to t18-status.c:singlestatus3 */
313 void test_status_worktree__single_file_empty_repo(void)
315 unsigned int status_flags
;
316 git_repository
*repo
= cl_git_sandbox_init("empty_standard_repo");
318 cl_git_mkfile("empty_standard_repo/new_file", "new_file\n");
320 cl_git_pass(git_status_file(&status_flags
, repo
, "new_file"));
321 cl_assert(status_flags
== GIT_STATUS_WT_NEW
);
324 /* this test is equivalent to t18-status.c:singlestatus4 */
325 void test_status_worktree__single_folder(void)
328 unsigned int status_flags
;
329 git_repository
*repo
= cl_git_sandbox_init("status");
331 error
= git_status_file(&status_flags
, repo
, "subdir");
333 cl_assert(error
!= GIT_ENOTFOUND
);
337 void test_status_worktree__ignores(void)
340 git_repository
*repo
= cl_git_sandbox_init("status");
342 for (i
= 0; i
< (int)entry_count0
; i
++) {
344 git_status_should_ignore(&ignored
, repo
, entry_paths0
[i
])
346 cl_assert(ignored
== (entry_statuses0
[i
] == GIT_STATUS_IGNORED
));
350 git_status_should_ignore(&ignored
, repo
, "nonexistent_file")
355 git_status_should_ignore(&ignored
, repo
, "ignored_nonexistent_file")
360 static int cb_status__check_592(const char *p
, unsigned int s
, void *payload
)
362 if (s
!= GIT_STATUS_WT_DELETED
||
363 (payload
!= NULL
&& strcmp(p
, (const char *)payload
) != 0))
369 void test_status_worktree__issue_592(void)
371 git_repository
*repo
;
372 git_str path
= GIT_STR_INIT
;
374 repo
= cl_git_sandbox_init("issue_592");
375 cl_git_pass(git_str_joinpath(&path
, git_repository_workdir(repo
), "l.txt"));
376 cl_git_pass(p_unlink(git_str_cstr(&path
)));
377 cl_assert(!git_fs_path_exists("issue_592/l.txt"));
379 cl_git_pass(git_status_foreach(repo
, cb_status__check_592
, "l.txt"));
381 git_str_dispose(&path
);
384 void test_status_worktree__issue_592_2(void)
386 git_repository
*repo
;
387 git_str path
= GIT_STR_INIT
;
389 repo
= cl_git_sandbox_init("issue_592");
390 cl_git_pass(git_str_joinpath(&path
, git_repository_workdir(repo
), "c/a.txt"));
391 cl_git_pass(p_unlink(git_str_cstr(&path
)));
392 cl_assert(!git_fs_path_exists("issue_592/c/a.txt"));
394 cl_git_pass(git_status_foreach(repo
, cb_status__check_592
, "c/a.txt"));
396 git_str_dispose(&path
);
399 void test_status_worktree__issue_592_3(void)
401 git_repository
*repo
;
402 git_str path
= GIT_STR_INIT
;
404 repo
= cl_git_sandbox_init("issue_592");
406 cl_git_pass(git_str_joinpath(&path
, git_repository_workdir(repo
), "c"));
407 cl_git_pass(git_futils_rmdir_r(git_str_cstr(&path
), NULL
, GIT_RMDIR_REMOVE_FILES
));
408 cl_assert(!git_fs_path_exists("issue_592/c/a.txt"));
410 cl_git_pass(git_status_foreach(repo
, cb_status__check_592
, "c/a.txt"));
412 git_str_dispose(&path
);
415 void test_status_worktree__issue_592_4(void)
417 git_repository
*repo
;
418 git_str path
= GIT_STR_INIT
;
420 repo
= cl_git_sandbox_init("issue_592");
422 cl_git_pass(git_str_joinpath(&path
, git_repository_workdir(repo
), "t/b.txt"));
423 cl_git_pass(p_unlink(git_str_cstr(&path
)));
425 cl_git_pass(git_status_foreach(repo
, cb_status__check_592
, "t/b.txt"));
427 git_str_dispose(&path
);
430 void test_status_worktree__issue_592_5(void)
432 git_repository
*repo
;
433 git_str path
= GIT_STR_INIT
;
435 repo
= cl_git_sandbox_init("issue_592");
437 cl_git_pass(git_str_joinpath(&path
, git_repository_workdir(repo
), "t"));
438 cl_git_pass(git_futils_rmdir_r(git_str_cstr(&path
), NULL
, GIT_RMDIR_REMOVE_FILES
));
439 cl_git_pass(p_mkdir(git_str_cstr(&path
), 0777));
441 cl_git_pass(git_status_foreach(repo
, cb_status__check_592
, NULL
));
443 git_str_dispose(&path
);
446 void test_status_worktree__issue_592_ignores_0(void)
449 status_entry_single st
;
450 git_repository
*repo
= cl_git_sandbox_init("issue_592");
452 cl_git_pass(git_status_foreach(repo
, cb_status__count
, &count
));
453 cl_assert_equal_i(0, count
);
455 cl_git_rewritefile("issue_592/.gitignore",
456 ".gitignore\n*.txt\nc/\n[tT]*/\n");
458 cl_git_pass(git_status_foreach(repo
, cb_status__count
, &count
));
459 cl_assert_equal_i(1, count
);
461 /* This is a situation where the behavior of libgit2 is
462 * different from core git. Core git will show ignored.txt
463 * in the list of ignored files, even though the directory
464 * "t" is ignored and the file is untracked because we have
465 * the explicit "*.txt" ignore rule. Libgit2 just excludes
466 * all untracked files that are contained within ignored
467 * directories without explicitly listing them.
469 cl_git_rewritefile("issue_592/t/ignored.txt", "ping");
471 memset(&st
, 0, sizeof(st
));
472 cl_git_pass(git_status_foreach(repo
, cb_status__single
, &st
));
473 cl_assert_equal_i(1, st
.count
);
474 cl_assert(st
.status
== GIT_STATUS_IGNORED
);
476 cl_git_rewritefile("issue_592/c/ignored_by_dir", "ping");
478 memset(&st
, 0, sizeof(st
));
479 cl_git_pass(git_status_foreach(repo
, cb_status__single
, &st
));
480 cl_assert_equal_i(1, st
.count
);
481 cl_assert(st
.status
== GIT_STATUS_IGNORED
);
483 cl_git_rewritefile("issue_592/t/ignored_by_dir_pattern", "ping");
485 memset(&st
, 0, sizeof(st
));
486 cl_git_pass(git_status_foreach(repo
, cb_status__single
, &st
));
487 cl_assert_equal_i(1, st
.count
);
488 cl_assert(st
.status
== GIT_STATUS_IGNORED
);
491 void test_status_worktree__issue_592_ignored_dirs_with_tracked_content(void)
494 git_repository
*repo
= cl_git_sandbox_init("issue_592b");
496 cl_git_pass(git_status_foreach(repo
, cb_status__count
, &count
));
497 cl_assert_equal_i(1, count
);
499 /* if we are really mimicking core git, then only ignored1.txt
500 * at the top level will show up in the ignores list here.
501 * everything else will be unmodified or skipped completely.
505 void test_status_worktree__conflict_with_diff3(void)
507 git_repository
*repo
= cl_git_sandbox_init("status");
510 git_index_entry ancestor_entry
, our_entry
, their_entry
;
512 memset(&ancestor_entry
, 0x0, sizeof(git_index_entry
));
513 memset(&our_entry
, 0x0, sizeof(git_index_entry
));
514 memset(&their_entry
, 0x0, sizeof(git_index_entry
));
516 ancestor_entry
.path
= "modified_file";
517 ancestor_entry
.mode
= 0100644;
518 git_oid_fromstr(&ancestor_entry
.id
,
519 "452e4244b5d083ddf0460acf1ecc74db9dcfa11a");
521 our_entry
.path
= "modified_file";
522 our_entry
.mode
= 0100644;
523 git_oid_fromstr(&our_entry
.id
,
524 "452e4244b5d083ddf0460acf1ecc74db9dcfa11a");
526 their_entry
.path
= "modified_file";
527 their_entry
.mode
= 0100644;
528 git_oid_fromstr(&their_entry
.id
,
529 "452e4244b5d083ddf0460acf1ecc74db9dcfa11a");
531 cl_git_pass(git_status_file(&status
, repo
, "modified_file"));
532 cl_assert_equal_i(GIT_STATUS_WT_MODIFIED
, status
);
534 cl_git_pass(git_repository_index(&index
, repo
));
535 cl_git_pass(git_index_remove(index
, "modified_file", 0));
536 cl_git_pass(git_index_conflict_add(
537 index
, &ancestor_entry
, &our_entry
, &their_entry
));
538 cl_git_pass(git_index_write(index
));
539 git_index_free(index
);
541 cl_git_pass(git_status_file(&status
, repo
, "modified_file"));
543 cl_assert_equal_i(GIT_STATUS_CONFLICTED
, status
);
546 static const char *filemode_paths
[] = {
548 "exec_off2on_staged",
549 "exec_off2on_workdir",
550 "exec_off_untracked",
552 "exec_on2off_staged",
553 "exec_on2off_workdir",
557 static unsigned int filemode_statuses
[] = {
559 GIT_STATUS_INDEX_MODIFIED
,
560 GIT_STATUS_WT_MODIFIED
,
563 GIT_STATUS_INDEX_MODIFIED
,
564 GIT_STATUS_WT_MODIFIED
,
568 static const int filemode_count
= 8;
570 void test_status_worktree__filemode_changes(void)
572 git_repository
*repo
= cl_git_sandbox_init("filemodes");
573 status_entry_counts counts
;
574 git_status_options opts
= GIT_STATUS_OPTIONS_INIT
;
576 /* overwrite stored filemode with platform appropriate value */
577 if (cl_is_chmod_supported())
578 cl_repo_set_bool(repo
, "core.filemode", true);
582 cl_repo_set_bool(repo
, "core.filemode", false);
584 /* won't trust filesystem mode diffs, so these will appear unchanged */
585 for (i
= 0; i
< filemode_count
; ++i
)
586 if (filemode_statuses
[i
] == GIT_STATUS_WT_MODIFIED
)
587 filemode_statuses
[i
] = GIT_STATUS_CURRENT
;
590 opts
.flags
= GIT_STATUS_OPT_INCLUDE_UNTRACKED
|
591 GIT_STATUS_OPT_INCLUDE_IGNORED
|
592 GIT_STATUS_OPT_INCLUDE_UNMODIFIED
;
594 memset(&counts
, 0, sizeof(counts
));
595 counts
.expected_entry_count
= filemode_count
;
596 counts
.expected_paths
= filemode_paths
;
597 counts
.expected_statuses
= filemode_statuses
;
600 git_status_foreach_ext(repo
, &opts
, cb_status__normal
, &counts
)
603 cl_assert_equal_i(counts
.expected_entry_count
, counts
.entry_count
);
604 cl_assert_equal_i(0, counts
.wrong_status_flags_count
);
605 cl_assert_equal_i(0, counts
.wrong_sorted_path
);
608 void test_status_worktree__filemode_non755(void)
610 git_repository
*repo
= cl_git_sandbox_init("filemodes");
611 status_entry_counts counts
;
612 git_status_options opts
= GIT_STATUS_OPTIONS_INIT
;
613 git_str executable_path
= GIT_STR_INIT
;
614 git_str nonexecutable_path
= GIT_STR_INIT
;
616 if (!cl_is_chmod_supported())
619 opts
.flags
= GIT_STATUS_OPT_INCLUDE_UNTRACKED
|
620 GIT_STATUS_OPT_INCLUDE_IGNORED
|
621 GIT_STATUS_OPT_INCLUDE_UNMODIFIED
;
623 git_str_joinpath(&executable_path
, git_repository_workdir(repo
), "exec_on");
624 cl_must_pass(p_chmod(git_str_cstr(&executable_path
), 0744));
625 git_str_dispose(&executable_path
);
627 git_str_joinpath(&nonexecutable_path
, git_repository_workdir(repo
), "exec_off");
629 cl_must_pass(p_chmod(git_str_cstr(&nonexecutable_path
), 0655));
630 git_str_dispose(&nonexecutable_path
);
632 memset(&counts
, 0, sizeof(counts
));
633 counts
.expected_entry_count
= filemode_count
;
634 counts
.expected_paths
= filemode_paths
;
635 counts
.expected_statuses
= filemode_statuses
;
638 git_status_foreach_ext(repo
, &opts
, cb_status__normal
, &counts
)
641 cl_assert_equal_i(counts
.expected_entry_count
, counts
.entry_count
);
642 cl_assert_equal_i(0, counts
.wrong_status_flags_count
);
643 cl_assert_equal_i(0, counts
.wrong_sorted_path
);
647 static int cb_status__interrupt(const char *p
, unsigned int s
, void *payload
)
649 volatile int *count
= (int *)payload
;
656 return (*count
== 8) ? -111 : 0;
659 void test_status_worktree__interruptable_foreach(void)
662 git_repository
*repo
= cl_git_sandbox_init("status");
665 -111, git_status_foreach(repo
, cb_status__interrupt
, &count
)
668 cl_assert_equal_i(8, count
);
671 void test_status_worktree__line_endings_dont_count_as_changes_with_autocrlf(void)
673 git_repository
*repo
= cl_git_sandbox_init("status");
676 cl_repo_set_bool(repo
, "core.autocrlf", true);
678 cl_git_rewritefile("status/current_file", "current_file\r\n");
680 cl_git_pass(git_status_file(&status
, repo
, "current_file"));
682 /* stat data on file should no longer match stat cache, even though
683 * file diff will be empty because of line-ending conversion - matches
684 * the Git command-line behavior here.
686 cl_assert_equal_i(GIT_STATUS_WT_MODIFIED
, status
);
689 void test_status_worktree__line_endings_dont_count_as_changes_with_autocrlf_issue_1397(void)
691 git_repository
*repo
= cl_git_sandbox_init("issue_1397");
694 cl_repo_set_bool(repo
, "core.autocrlf", true);
696 cl_git_pass(git_status_file(&status
, repo
, "crlf_file.txt"));
698 cl_assert_equal_i(GIT_STATUS_CURRENT
, status
);
701 void test_status_worktree__conflicted_item(void)
703 git_repository
*repo
= cl_git_sandbox_init("status");
706 git_index_entry ancestor_entry
, our_entry
, their_entry
;
708 memset(&ancestor_entry
, 0x0, sizeof(git_index_entry
));
709 memset(&our_entry
, 0x0, sizeof(git_index_entry
));
710 memset(&their_entry
, 0x0, sizeof(git_index_entry
));
712 ancestor_entry
.mode
= 0100644;
713 ancestor_entry
.path
= "modified_file";
714 git_oid_fromstr(&ancestor_entry
.id
,
715 "452e4244b5d083ddf0460acf1ecc74db9dcfa11a");
717 our_entry
.mode
= 0100644;
718 our_entry
.path
= "modified_file";
719 git_oid_fromstr(&our_entry
.id
,
720 "452e4244b5d083ddf0460acf1ecc74db9dcfa11a");
722 their_entry
.mode
= 0100644;
723 their_entry
.path
= "modified_file";
724 git_oid_fromstr(&their_entry
.id
,
725 "452e4244b5d083ddf0460acf1ecc74db9dcfa11a");
727 cl_git_pass(git_status_file(&status
, repo
, "modified_file"));
728 cl_assert_equal_i(GIT_STATUS_WT_MODIFIED
, status
);
730 cl_git_pass(git_repository_index(&index
, repo
));
731 cl_git_pass(git_index_conflict_add(index
, &ancestor_entry
,
732 &our_entry
, &their_entry
));
734 cl_git_pass(git_status_file(&status
, repo
, "modified_file"));
735 cl_assert_equal_i(GIT_STATUS_CONFLICTED
, status
);
737 git_index_free(index
);
740 void test_status_worktree__conflict_has_no_oid(void)
742 git_repository
*repo
= cl_git_sandbox_init("status");
744 git_index_entry entry
= {{0}};
745 git_status_list
*statuslist
;
746 const git_status_entry
*status
;
747 git_oid zero_id
= {{0}};
749 entry
.mode
= 0100644;
750 entry
.path
= "modified_file";
751 git_oid_fromstr(&entry
.id
, "452e4244b5d083ddf0460acf1ecc74db9dcfa11a");
753 cl_git_pass(git_repository_index(&index
, repo
));
754 cl_git_pass(git_index_conflict_add(index
, &entry
, &entry
, &entry
));
756 git_status_list_new(&statuslist
, repo
, NULL
);
758 cl_assert_equal_i(16, git_status_list_entrycount(statuslist
));
760 status
= git_status_byindex(statuslist
, 2);
762 cl_assert_equal_i(GIT_STATUS_CONFLICTED
, status
->status
);
763 cl_assert_equal_s("modified_file", status
->head_to_index
->old_file
.path
);
764 cl_assert(!git_oid_equal(&zero_id
, &status
->head_to_index
->old_file
.id
));
765 cl_assert(0 != status
->head_to_index
->old_file
.mode
);
766 cl_assert_equal_s("modified_file", status
->head_to_index
->new_file
.path
);
767 cl_assert_equal_oid(&zero_id
, &status
->head_to_index
->new_file
.id
);
768 cl_assert_equal_i(0, status
->head_to_index
->new_file
.mode
);
769 cl_assert_equal_i(0, status
->head_to_index
->new_file
.size
);
771 cl_assert_equal_s("modified_file", status
->index_to_workdir
->old_file
.path
);
772 cl_assert_equal_oid(&zero_id
, &status
->index_to_workdir
->old_file
.id
);
773 cl_assert_equal_i(0, status
->index_to_workdir
->old_file
.mode
);
774 cl_assert_equal_i(0, status
->index_to_workdir
->old_file
.size
);
775 cl_assert_equal_s("modified_file", status
->index_to_workdir
->new_file
.path
);
777 !git_oid_equal(&zero_id
, &status
->index_to_workdir
->new_file
.id
) ||
778 !(status
->index_to_workdir
->new_file
.flags
& GIT_DIFF_FLAG_VALID_ID
));
779 cl_assert(0 != status
->index_to_workdir
->new_file
.mode
);
780 cl_assert(0 != status
->index_to_workdir
->new_file
.size
);
782 git_index_free(index
);
783 git_status_list_free(statuslist
);
786 static void assert_ignore_case(
787 bool should_ignore_case
,
788 int expected_lower_cased_file_status
,
789 int expected_camel_cased_file_status
)
792 git_str lower_case_path
= GIT_STR_INIT
, camel_case_path
= GIT_STR_INIT
;
793 git_repository
*repo
, *repo2
;
795 repo
= cl_git_sandbox_init("empty_standard_repo");
796 cl_git_remove_placeholders(git_repository_path(repo
), "dummy-marker.txt");
798 cl_repo_set_bool(repo
, "core.ignorecase", should_ignore_case
);
800 cl_git_pass(git_str_joinpath(&lower_case_path
,
801 git_repository_workdir(repo
), "plop"));
803 cl_git_mkfile(git_str_cstr(&lower_case_path
), "");
805 stage_and_commit(repo
, "plop");
807 cl_git_pass(git_repository_open(&repo2
, "./empty_standard_repo"));
809 cl_git_pass(git_status_file(&status
, repo2
, "plop"));
810 cl_assert_equal_i(GIT_STATUS_CURRENT
, status
);
812 cl_git_pass(git_str_joinpath(&camel_case_path
,
813 git_repository_workdir(repo
), "Plop"));
815 cl_git_pass(p_rename(git_str_cstr(&lower_case_path
), git_str_cstr(&camel_case_path
)));
817 cl_git_pass(git_status_file(&status
, repo2
, "plop"));
818 cl_assert_equal_i(expected_lower_cased_file_status
, status
);
820 cl_git_pass(git_status_file(&status
, repo2
, "Plop"));
821 cl_assert_equal_i(expected_camel_cased_file_status
, status
);
823 git_repository_free(repo2
);
824 git_str_dispose(&lower_case_path
);
825 git_str_dispose(&camel_case_path
);
828 void test_status_worktree__file_status_honors_core_ignorecase_true(void)
830 assert_ignore_case(true, GIT_STATUS_CURRENT
, GIT_STATUS_CURRENT
);
833 void test_status_worktree__file_status_honors_core_ignorecase_false(void)
835 assert_ignore_case(false, GIT_STATUS_WT_DELETED
, GIT_STATUS_WT_NEW
);
838 void test_status_worktree__file_status_honors_case_ignorecase_regarding_untracked_files(void)
840 git_repository
*repo
= cl_git_sandbox_init("status");
844 cl_repo_set_bool(repo
, "core.ignorecase", false);
846 repo
= cl_git_sandbox_reopen();
848 /* Actually returns GIT_STATUS_IGNORED on Windows */
849 cl_git_fail_with(git_status_file(&status
, repo
, "NEW_FILE"), GIT_ENOTFOUND
);
851 cl_git_pass(git_repository_index(&index
, repo
));
853 cl_git_pass(git_index_add_bypath(index
, "new_file"));
854 cl_git_pass(git_index_write(index
));
855 git_index_free(index
);
857 /* Actually returns GIT_STATUS_IGNORED on Windows */
858 cl_git_fail_with(git_status_file(&status
, repo
, "NEW_FILE"), GIT_ENOTFOUND
);
861 void test_status_worktree__simple_delete(void)
863 git_repository
*repo
= cl_git_sandbox_init("renames");
864 git_status_options opts
= GIT_STATUS_OPTIONS_INIT
;
867 opts
.flags
= GIT_STATUS_OPT_INCLUDE_UNTRACKED
|
868 GIT_STATUS_OPT_DISABLE_PATHSPEC_MATCH
|
869 GIT_STATUS_OPT_EXCLUDE_SUBMODULES
|
870 GIT_STATUS_OPT_RECURSE_UNTRACKED_DIRS
;
874 git_status_foreach_ext(repo
, &opts
, cb_status__count
, &count
) );
875 cl_assert_equal_i(0, count
);
877 cl_must_pass(p_unlink("renames/untimely.txt"));
881 git_status_foreach_ext(repo
, &opts
, cb_status__count
, &count
) );
882 cl_assert_equal_i(1, count
);
885 void test_status_worktree__simple_delete_indexed(void)
887 git_repository
*repo
= cl_git_sandbox_init("renames");
888 git_status_options opts
= GIT_STATUS_OPTIONS_INIT
;
889 git_status_list
*status
;
891 opts
.flags
= GIT_STATUS_OPT_INCLUDE_UNTRACKED
|
892 GIT_STATUS_OPT_DISABLE_PATHSPEC_MATCH
|
893 GIT_STATUS_OPT_EXCLUDE_SUBMODULES
|
894 GIT_STATUS_OPT_RECURSE_UNTRACKED_DIRS
;
896 cl_git_pass(git_status_list_new(&status
, repo
, &opts
));
897 cl_assert_equal_sz(0, git_status_list_entrycount(status
));
898 git_status_list_free(status
);
900 cl_must_pass(p_unlink("renames/untimely.txt"));
902 cl_git_pass(git_status_list_new(&status
, repo
, &opts
));
903 cl_assert_equal_sz(1, git_status_list_entrycount(status
));
905 GIT_STATUS_WT_DELETED
, git_status_byindex(status
, 0)->status
);
906 git_status_list_free(status
);
909 static const char *icase_paths
[] = { "B", "c", "g", "H" };
910 static unsigned int icase_statuses
[] = {
911 GIT_STATUS_WT_MODIFIED
, GIT_STATUS_WT_DELETED
,
912 GIT_STATUS_WT_MODIFIED
, GIT_STATUS_WT_DELETED
,
915 static const char *case_paths
[] = { "B", "H", "c", "g" };
916 static unsigned int case_statuses
[] = {
917 GIT_STATUS_WT_MODIFIED
, GIT_STATUS_WT_DELETED
,
918 GIT_STATUS_WT_DELETED
, GIT_STATUS_WT_MODIFIED
,
921 void test_status_worktree__sorting_by_case(void)
923 git_repository
*repo
= cl_git_sandbox_init("icase");
925 git_status_options opts
= GIT_STATUS_OPTIONS_INIT
;
926 bool native_ignore_case
;
927 status_entry_counts counts
;
929 cl_git_pass(git_repository_index(&index
, repo
));
931 (git_index_caps(index
) & GIT_INDEX_CAPABILITY_IGNORE_CASE
) != 0;
932 git_index_free(index
);
934 memset(&counts
, 0, sizeof(counts
));
935 counts
.expected_entry_count
= 0;
936 counts
.expected_paths
= NULL
;
937 counts
.expected_statuses
= NULL
;
939 git_status_foreach_ext(repo
, &opts
, cb_status__normal
, &counts
));
940 cl_assert_equal_i(counts
.expected_entry_count
, counts
.entry_count
);
941 cl_assert_equal_i(0, counts
.wrong_status_flags_count
);
942 cl_assert_equal_i(0, counts
.wrong_sorted_path
);
944 cl_git_rewritefile("icase/B", "new stuff");
945 cl_must_pass(p_unlink("icase/c"));
946 cl_git_rewritefile("icase/g", "new stuff");
947 cl_must_pass(p_unlink("icase/H"));
949 memset(&counts
, 0, sizeof(counts
));
950 counts
.expected_entry_count
= 4;
951 if (native_ignore_case
) {
952 counts
.expected_paths
= icase_paths
;
953 counts
.expected_statuses
= icase_statuses
;
955 counts
.expected_paths
= case_paths
;
956 counts
.expected_statuses
= case_statuses
;
959 git_status_foreach_ext(repo
, &opts
, cb_status__normal
, &counts
));
960 cl_assert_equal_i(counts
.expected_entry_count
, counts
.entry_count
);
961 cl_assert_equal_i(0, counts
.wrong_status_flags_count
);
962 cl_assert_equal_i(0, counts
.wrong_sorted_path
);
964 opts
.flags
= GIT_STATUS_OPT_SORT_CASE_SENSITIVELY
;
966 memset(&counts
, 0, sizeof(counts
));
967 counts
.expected_entry_count
= 4;
968 counts
.expected_paths
= case_paths
;
969 counts
.expected_statuses
= case_statuses
;
971 git_status_foreach_ext(repo
, &opts
, cb_status__normal
, &counts
));
972 cl_assert_equal_i(counts
.expected_entry_count
, counts
.entry_count
);
973 cl_assert_equal_i(0, counts
.wrong_status_flags_count
);
974 cl_assert_equal_i(0, counts
.wrong_sorted_path
);
976 opts
.flags
= GIT_STATUS_OPT_SORT_CASE_INSENSITIVELY
;
978 memset(&counts
, 0, sizeof(counts
));
979 counts
.expected_entry_count
= 4;
980 counts
.expected_paths
= icase_paths
;
981 counts
.expected_statuses
= icase_statuses
;
983 git_status_foreach_ext(repo
, &opts
, cb_status__normal
, &counts
));
984 cl_assert_equal_i(counts
.expected_entry_count
, counts
.entry_count
);
985 cl_assert_equal_i(0, counts
.wrong_status_flags_count
);
986 cl_assert_equal_i(0, counts
.wrong_sorted_path
);
989 void test_status_worktree__long_filenames(void)
991 char path
[260*4+1] = {0};
992 const char *expected_paths
[] = {path
};
993 const unsigned int expected_statuses
[] = {GIT_STATUS_WT_NEW
};
995 git_repository
*repo
= cl_git_sandbox_init("empty_standard_repo");
996 git_status_options opts
= GIT_STATUS_OPTIONS_INIT
;
997 status_entry_counts counts
= {0};
999 /* Create directory with amazingly long filename */
1000 sprintf(path
, "empty_standard_repo/%s", longname
);
1001 cl_git_pass(git_futils_mkdir_r(path
, 0777));
1002 sprintf(path
, "empty_standard_repo/%s/foo", longname
);
1003 cl_git_mkfile(path
, "dummy");
1005 sprintf(path
, "%s/foo", longname
);
1006 counts
.expected_entry_count
= 1;
1007 counts
.expected_paths
= expected_paths
;
1008 counts
.expected_statuses
= expected_statuses
;
1010 opts
.show
= GIT_STATUS_SHOW_WORKDIR_ONLY
;
1011 opts
.flags
= GIT_STATUS_OPT_DEFAULTS
;
1014 git_status_foreach_ext(repo
, &opts
, cb_status__normal
, &counts
) );
1015 cl_assert_equal_i(counts
.expected_entry_count
, counts
.entry_count
);
1016 cl_assert_equal_i(0, counts
.wrong_status_flags_count
);
1017 cl_assert_equal_i(0, counts
.wrong_sorted_path
);
1020 /* The update stat cache tests mostly just mirror other tests and try
1021 * to make sure that updating the stat cache doesn't change the results
1022 * while reducing the amount of work that needs to be done
1025 static void check_status0(git_status_list
*status
)
1027 size_t i
, max_i
= git_status_list_entrycount(status
);
1028 cl_assert_equal_sz(entry_count0
, max_i
);
1029 for (i
= 0; i
< max_i
; ++i
) {
1030 const git_status_entry
*entry
= git_status_byindex(status
, i
);
1031 cl_assert_equal_i(entry_statuses0
[i
], entry
->status
);
1035 void test_status_worktree__update_stat_cache_0(void)
1037 git_repository
*repo
= cl_git_sandbox_init("status");
1038 git_status_options opts
= GIT_STATUS_OPTIONS_INIT
;
1039 git_status_list
*status
;
1040 git_diff_perfdata perf
= GIT_DIFF_PERFDATA_INIT
;
1043 opts
.flags
= GIT_STATUS_OPT_DEFAULTS
;
1045 cl_git_pass(git_status_list_new(&status
, repo
, &opts
));
1046 check_status0(status
);
1047 cl_git_pass(git_status_list_get_perfdata(&perf
, status
));
1048 cl_assert_equal_sz(13 + 3, perf
.stat_calls
);
1049 cl_assert_equal_sz(5, perf
.oid_calculations
);
1051 git_status_list_free(status
);
1053 /* tick the index so we avoid recalculating racily-clean entries */
1054 cl_git_pass(git_repository_index__weakptr(&index
, repo
));
1057 opts
.flags
|= GIT_STATUS_OPT_UPDATE_INDEX
;
1059 cl_git_pass(git_status_list_new(&status
, repo
, &opts
));
1060 check_status0(status
);
1061 cl_git_pass(git_status_list_get_perfdata(&perf
, status
));
1062 cl_assert_equal_sz(13 + 3, perf
.stat_calls
);
1063 cl_assert_equal_sz(5, perf
.oid_calculations
);
1065 git_status_list_free(status
);
1067 opts
.flags
&= ~GIT_STATUS_OPT_UPDATE_INDEX
;
1069 /* tick again as the index updating from the previous diff might have reset the timestamp */
1071 cl_git_pass(git_status_list_new(&status
, repo
, &opts
));
1072 check_status0(status
);
1073 cl_git_pass(git_status_list_get_perfdata(&perf
, status
));
1074 cl_assert_equal_sz(13 + 3, perf
.stat_calls
);
1075 cl_assert_equal_sz(0, perf
.oid_calculations
);
1077 git_status_list_free(status
);
1080 void test_status_worktree__unreadable(void)
1083 const char *expected_paths
[] = { "no_permission/foo" };
1084 const unsigned int expected_statuses
[] = {GIT_STATUS_WT_UNREADABLE
};
1086 git_repository
*repo
= cl_git_sandbox_init("empty_standard_repo");
1087 git_status_options opts
= GIT_STATUS_OPTIONS_INIT
;
1088 status_entry_counts counts
= {0};
1093 /* Create directory with no read permission */
1094 cl_git_pass(git_futils_mkdir_r("empty_standard_repo/no_permission", 0777));
1095 cl_git_mkfile("empty_standard_repo/no_permission/foo", "dummy");
1096 p_chmod("empty_standard_repo/no_permission", 0644);
1098 counts
.expected_entry_count
= 1;
1099 counts
.expected_paths
= expected_paths
;
1100 counts
.expected_statuses
= expected_statuses
;
1102 opts
.show
= GIT_STATUS_SHOW_WORKDIR_ONLY
;
1103 opts
.flags
= GIT_STATUS_OPT_DEFAULTS
| GIT_STATUS_OPT_INCLUDE_UNREADABLE
;
1106 git_status_foreach_ext(repo
, &opts
, cb_status__normal
, &counts
) );
1108 /* Restore permissions so we can cleanup :) */
1109 p_chmod("empty_standard_repo/no_permission", 0777);
1111 cl_assert_equal_i(counts
.expected_entry_count
, counts
.entry_count
);
1112 cl_assert_equal_i(0, counts
.wrong_status_flags_count
);
1113 cl_assert_equal_i(0, counts
.wrong_sorted_path
);
1119 void test_status_worktree__unreadable_not_included(void)
1122 const char *expected_paths
[] = { "no_permission/" };
1123 const unsigned int expected_statuses
[] = {GIT_STATUS_WT_NEW
};
1125 git_repository
*repo
= cl_git_sandbox_init("empty_standard_repo");
1126 git_status_options opts
= GIT_STATUS_OPTIONS_INIT
;
1127 status_entry_counts counts
= {0};
1129 /* Create directory with no read permission */
1130 cl_git_pass(git_futils_mkdir_r("empty_standard_repo/no_permission", 0777));
1131 cl_git_mkfile("empty_standard_repo/no_permission/foo", "dummy");
1132 p_chmod("empty_standard_repo/no_permission", 0644);
1134 counts
.expected_entry_count
= 1;
1135 counts
.expected_paths
= expected_paths
;
1136 counts
.expected_statuses
= expected_statuses
;
1138 opts
.show
= GIT_STATUS_SHOW_WORKDIR_ONLY
;
1139 opts
.flags
= (GIT_STATUS_OPT_INCLUDE_IGNORED
| GIT_STATUS_OPT_INCLUDE_UNTRACKED
);
1142 git_status_foreach_ext(repo
, &opts
, cb_status__normal
, &counts
) );
1144 /* Restore permissions so we can cleanup :) */
1145 p_chmod("empty_standard_repo/no_permission", 0777);
1147 cl_assert_equal_i(counts
.expected_entry_count
, counts
.entry_count
);
1148 cl_assert_equal_i(0, counts
.wrong_status_flags_count
);
1149 cl_assert_equal_i(0, counts
.wrong_sorted_path
);
1155 void test_status_worktree__unreadable_as_untracked(void)
1157 const char *expected_paths
[] = { "no_permission/foo" };
1158 const unsigned int expected_statuses
[] = {GIT_STATUS_WT_NEW
};
1160 git_repository
*repo
= cl_git_sandbox_init("empty_standard_repo");
1161 git_status_options opts
= GIT_STATUS_OPTIONS_INIT
;
1162 status_entry_counts counts
= {0};
1164 /* Create directory with no read permission */
1165 cl_git_pass(git_futils_mkdir_r("empty_standard_repo/no_permission", 0777));
1166 cl_git_mkfile("empty_standard_repo/no_permission/foo", "dummy");
1167 p_chmod("empty_standard_repo/no_permission", 0644);
1169 counts
.expected_entry_count
= 1;
1170 counts
.expected_paths
= expected_paths
;
1171 counts
.expected_statuses
= expected_statuses
;
1173 opts
.show
= GIT_STATUS_SHOW_WORKDIR_ONLY
;
1174 opts
.flags
= GIT_STATUS_OPT_DEFAULTS
|
1175 GIT_STATUS_OPT_INCLUDE_UNREADABLE
|
1176 GIT_STATUS_OPT_INCLUDE_UNREADABLE_AS_UNTRACKED
;
1179 git_status_foreach_ext(repo
, &opts
, cb_status__normal
, &counts
) );
1181 /* Restore permissions so we can cleanup :) */
1182 p_chmod("empty_standard_repo/no_permission", 0777);
1184 cl_assert_equal_i(counts
.expected_entry_count
, counts
.entry_count
);
1185 cl_assert_equal_i(0, counts
.wrong_status_flags_count
);
1186 cl_assert_equal_i(0, counts
.wrong_sorted_path
);
1189 void test_status_worktree__update_index_with_symlink_doesnt_change_mode(void)
1191 git_repository
*repo
= cl_git_sandbox_init("testrepo");
1192 git_reference
*head
;
1193 git_object
*head_object
;
1195 const git_index_entry
*idx_entry
;
1196 git_status_options opts
= GIT_STATUS_OPTIONS_INIT
;
1197 status_entry_counts counts
= {0};
1198 const char *expected_paths
[] = { "README" };
1199 const unsigned int expected_statuses
[] = {GIT_STATUS_WT_NEW
};
1201 opts
.show
= GIT_STATUS_SHOW_INDEX_AND_WORKDIR
;
1202 opts
.flags
= GIT_STATUS_OPT_DEFAULTS
| GIT_STATUS_OPT_UPDATE_INDEX
;
1204 cl_git_pass(git_repository_head(&head
, repo
));
1205 cl_git_pass(git_reference_peel(&head_object
, head
, GIT_OBJECT_COMMIT
));
1207 cl_git_pass(git_reset(repo
, head_object
, GIT_RESET_HARD
, NULL
));
1209 cl_git_rewritefile("testrepo/README", "This was rewritten.");
1211 /* this status rewrites the index because we have changed the
1212 * contents of a tracked file
1214 counts
.expected_entry_count
= 1;
1215 counts
.expected_paths
= expected_paths
;
1216 counts
.expected_statuses
= expected_statuses
;
1219 git_status_foreach_ext(repo
, &opts
, cb_status__normal
, &counts
));
1220 cl_assert_equal_i(1, counts
.entry_count
);
1222 /* now ensure that the status's rewrite of the index did not screw
1223 * up the mode of the symlink `link_to_new.txt`, particularly
1224 * on platforms that don't support symlinks
1226 cl_git_pass(git_repository_index(&index
, repo
));
1227 cl_git_pass(git_index_read(index
, true));
1229 cl_assert(idx_entry
= git_index_get_bypath(index
, "link_to_new.txt", 0));
1230 cl_assert(S_ISLNK(idx_entry
->mode
));
1232 git_index_free(index
);
1233 git_object_free(head_object
);
1234 git_reference_free(head
);
1237 static const char *testrepo2_subdir_paths
[] = {
1240 "subdir/subdir2/README",
1241 "subdir/subdir2/new.txt",
1244 static const char *testrepo2_subdir_paths_icase
[] = {
1247 "subdir/subdir2/new.txt",
1248 "subdir/subdir2/README"
1251 void test_status_worktree__with_directory_in_pathlist(void)
1253 git_repository
*repo
= cl_git_sandbox_init("testrepo2");
1255 git_status_options opts
= GIT_STATUS_OPTIONS_INIT
;
1256 git_status_list
*statuslist
;
1257 const git_status_entry
*status
;
1258 size_t i
, entrycount
;
1259 bool native_ignore_case
;
1260 char *subdir_path
= "subdir";
1262 cl_git_pass(git_repository_index(&index
, repo
));
1263 native_ignore_case
=
1264 (git_index_caps(index
) & GIT_INDEX_CAPABILITY_IGNORE_CASE
) != 0;
1265 git_index_free(index
);
1267 opts
.pathspec
.strings
= &subdir_path
;
1268 opts
.pathspec
.count
= 1;
1270 GIT_STATUS_OPT_DEFAULTS
|
1271 GIT_STATUS_OPT_INCLUDE_UNMODIFIED
|
1272 GIT_STATUS_OPT_DISABLE_PATHSPEC_MATCH
;
1274 opts
.show
= GIT_STATUS_SHOW_WORKDIR_ONLY
;
1275 git_status_list_new(&statuslist
, repo
, &opts
);
1277 entrycount
= git_status_list_entrycount(statuslist
);
1278 cl_assert_equal_i(4, entrycount
);
1280 for (i
= 0; i
< entrycount
; i
++) {
1281 status
= git_status_byindex(statuslist
, i
);
1282 cl_assert_equal_i(0, status
->status
);
1283 cl_assert_equal_s(native_ignore_case
?
1284 testrepo2_subdir_paths_icase
[i
] :
1285 testrepo2_subdir_paths
[i
],
1286 status
->index_to_workdir
->old_file
.path
);
1289 git_status_list_free(statuslist
);
1291 opts
.show
= GIT_STATUS_SHOW_INDEX_ONLY
;
1292 git_status_list_new(&statuslist
, repo
, &opts
);
1294 entrycount
= git_status_list_entrycount(statuslist
);
1295 cl_assert_equal_i(4, entrycount
);
1297 for (i
= 0; i
< entrycount
; i
++) {
1298 status
= git_status_byindex(statuslist
, i
);
1299 cl_assert_equal_i(0, status
->status
);
1300 cl_assert_equal_s(native_ignore_case
?
1301 testrepo2_subdir_paths_icase
[i
] :
1302 testrepo2_subdir_paths
[i
],
1303 status
->head_to_index
->old_file
.path
);
1306 git_status_list_free(statuslist
);
1308 opts
.show
= GIT_STATUS_SHOW_INDEX_AND_WORKDIR
;
1309 git_status_list_new(&statuslist
, repo
, &opts
);
1311 entrycount
= git_status_list_entrycount(statuslist
);
1312 cl_assert_equal_i(4, entrycount
);
1314 for (i
= 0; i
< entrycount
; i
++) {
1315 status
= git_status_byindex(statuslist
, i
);
1316 cl_assert_equal_i(0, status
->status
);
1317 cl_assert_equal_s(native_ignore_case
?
1318 testrepo2_subdir_paths_icase
[i
] :
1319 testrepo2_subdir_paths
[i
],
1320 status
->index_to_workdir
->old_file
.path
);
1323 git_status_list_free(statuslist
);
1326 void test_status_worktree__at_head_parent(void)
1328 git_repository
*repo
= cl_git_sandbox_init("empty_standard_repo");
1329 git_status_options opts
= GIT_STATUS_OPTIONS_INIT
;
1330 git_status_list
*statuslist
;
1331 git_tree
*parent_tree
;
1332 const git_status_entry
*status
;
1334 cl_git_mkfile("empty_standard_repo/file1", "ping");
1335 stage_and_commit(repo
, "file1");
1337 cl_git_pass(git_repository_head_tree(&parent_tree
, repo
));
1339 cl_git_mkfile("empty_standard_repo/file2", "pong");
1340 stage_and_commit(repo
, "file2");
1342 cl_git_rewritefile("empty_standard_repo/file2", "pyng");
1344 opts
.show
= GIT_STATUS_SHOW_INDEX_AND_WORKDIR
;
1345 opts
.baseline
= parent_tree
;
1346 cl_git_pass(git_status_list_new(&statuslist
, repo
, &opts
));
1348 cl_assert_equal_sz(1, git_status_list_entrycount(statuslist
));
1349 status
= git_status_byindex(statuslist
, 0);
1350 cl_assert(status
!= NULL
);
1351 cl_assert_equal_s("file2", status
->index_to_workdir
->old_file
.path
);
1352 cl_assert_equal_i(GIT_STATUS_WT_MODIFIED
| GIT_STATUS_INDEX_NEW
, status
->status
);
1354 git_tree_free(parent_tree
);
1355 git_status_list_free(statuslist
);