1 #include "clar_libgit2.h"
4 #include "status_helpers.h"
8 static git_repository
*g_repo
= NULL
;
10 void test_status_renames__initialize(void)
12 g_repo
= cl_git_sandbox_init("renames");
14 cl_repo_set_bool(g_repo
, "core.autocrlf", false);
17 void test_status_renames__cleanup(void)
19 cl_git_sandbox_cleanup();
22 static void _rename_helper(
23 git_repository
*repo
, const char *from
, const char *to
, const char *extra
)
25 git_str oldpath
= GIT_STR_INIT
, newpath
= GIT_STR_INIT
;
27 cl_git_pass(git_str_joinpath(
28 &oldpath
, git_repository_workdir(repo
), from
));
29 cl_git_pass(git_str_joinpath(
30 &newpath
, git_repository_workdir(repo
), to
));
32 cl_git_pass(p_rename(oldpath
.ptr
, newpath
.ptr
));
35 cl_git_append2file(newpath
.ptr
, extra
);
37 git_str_dispose(&oldpath
);
38 git_str_dispose(&newpath
);
41 #define rename_file(R,O,N) _rename_helper((R), (O), (N), NULL)
42 #define rename_and_edit_file(R,O,N) \
43 _rename_helper((R), (O), (N), "Added at the end to keep similarity!")
51 static void check_status(
52 git_status_list
*status_list
,
53 struct status_entry
*expected_list
,
56 const git_status_entry
*actual
;
57 const struct status_entry
*expected
;
58 const char *oldname
, *newname
;
59 size_t i
, files_in_status
= git_status_list_entrycount(status_list
);
61 cl_assert_equal_sz(expected_len
, files_in_status
);
63 for (i
= 0; i
< expected_len
; i
++) {
64 actual
= git_status_byindex(status_list
, i
);
65 expected
= &expected_list
[i
];
67 oldname
= actual
->head_to_index
? actual
->head_to_index
->old_file
.path
:
68 actual
->index_to_workdir
? actual
->index_to_workdir
->old_file
.path
: NULL
;
70 newname
= actual
->index_to_workdir
? actual
->index_to_workdir
->new_file
.path
:
71 actual
->head_to_index
? actual
->head_to_index
->new_file
.path
: NULL
;
73 cl_assert_equal_i_fmt(expected
->status
, actual
->status
, "%04x");
75 if (expected
->oldname
) {
76 cl_assert(oldname
!= NULL
);
77 cl_assert_equal_s(oldname
, expected
->oldname
);
79 cl_assert(oldname
== NULL
);
82 if (actual
->status
& (GIT_STATUS_INDEX_RENAMED
|GIT_STATUS_WT_RENAMED
)) {
83 if (expected
->newname
) {
84 cl_assert(newname
!= NULL
);
85 cl_assert_equal_s(newname
, expected
->newname
);
87 cl_assert(newname
== NULL
);
93 void test_status_renames__head2index_one(void)
96 git_status_list
*statuslist
;
97 git_status_options opts
= GIT_STATUS_OPTIONS_INIT
;
98 struct status_entry expected
[] = {
99 { GIT_STATUS_INDEX_RENAMED
, "ikeepsix.txt", "newname.txt" },
102 opts
.flags
|= GIT_STATUS_OPT_RENAMES_HEAD_TO_INDEX
;
104 cl_git_pass(git_repository_index(&index
, g_repo
));
106 rename_file(g_repo
, "ikeepsix.txt", "newname.txt");
108 cl_git_pass(git_index_remove_bypath(index
, "ikeepsix.txt"));
109 cl_git_pass(git_index_add_bypath(index
, "newname.txt"));
110 cl_git_pass(git_index_write(index
));
112 cl_git_pass(git_status_list_new(&statuslist
, g_repo
, &opts
));
113 check_status(statuslist
, expected
, 1);
114 git_status_list_free(statuslist
);
116 git_index_free(index
);
119 void test_status_renames__head2index_two(void)
122 git_status_list
*statuslist
;
123 git_status_options opts
= GIT_STATUS_OPTIONS_INIT
;
124 struct status_entry expected
[] = {
125 { GIT_STATUS_INDEX_RENAMED
| GIT_STATUS_INDEX_MODIFIED
,
126 "sixserving.txt", "aaa.txt" },
127 { GIT_STATUS_INDEX_RENAMED
| GIT_STATUS_INDEX_MODIFIED
,
128 "untimely.txt", "bbb.txt" },
129 { GIT_STATUS_INDEX_RENAMED
, "songof7cities.txt", "ccc.txt" },
130 { GIT_STATUS_INDEX_RENAMED
, "ikeepsix.txt", "ddd.txt" },
133 opts
.flags
|= GIT_STATUS_OPT_RENAMES_HEAD_TO_INDEX
;
135 cl_git_pass(git_repository_index(&index
, g_repo
));
137 rename_file(g_repo
, "ikeepsix.txt", "ddd.txt");
138 rename_and_edit_file(g_repo
, "sixserving.txt", "aaa.txt");
139 rename_file(g_repo
, "songof7cities.txt", "ccc.txt");
140 rename_and_edit_file(g_repo
, "untimely.txt", "bbb.txt");
142 cl_git_pass(git_index_remove_bypath(index
, "ikeepsix.txt"));
143 cl_git_pass(git_index_remove_bypath(index
, "sixserving.txt"));
144 cl_git_pass(git_index_remove_bypath(index
, "songof7cities.txt"));
145 cl_git_pass(git_index_remove_bypath(index
, "untimely.txt"));
146 cl_git_pass(git_index_add_bypath(index
, "ddd.txt"));
147 cl_git_pass(git_index_add_bypath(index
, "aaa.txt"));
148 cl_git_pass(git_index_add_bypath(index
, "ccc.txt"));
149 cl_git_pass(git_index_add_bypath(index
, "bbb.txt"));
150 cl_git_pass(git_index_write(index
));
152 cl_git_pass(git_status_list_new(&statuslist
, g_repo
, &opts
));
153 check_status(statuslist
, expected
, 4);
154 git_status_list_free(statuslist
);
156 git_index_free(index
);
159 void test_status_renames__head2index_no_rename_from_rewrite(void)
162 git_status_list
*statuslist
;
163 git_status_options opts
= GIT_STATUS_OPTIONS_INIT
;
164 struct status_entry expected
[] = {
165 { GIT_STATUS_INDEX_MODIFIED
, "ikeepsix.txt", "ikeepsix.txt" },
166 { GIT_STATUS_INDEX_MODIFIED
, "sixserving.txt", "sixserving.txt" },
169 opts
.flags
|= GIT_STATUS_OPT_RENAMES_HEAD_TO_INDEX
;
171 cl_git_pass(git_repository_index(&index
, g_repo
));
173 rename_file(g_repo
, "ikeepsix.txt", "_temp_.txt");
174 rename_file(g_repo
, "sixserving.txt", "ikeepsix.txt");
175 rename_file(g_repo
, "_temp_.txt", "sixserving.txt");
177 cl_git_pass(git_index_add_bypath(index
, "ikeepsix.txt"));
178 cl_git_pass(git_index_add_bypath(index
, "sixserving.txt"));
179 cl_git_pass(git_index_write(index
));
181 cl_git_pass(git_status_list_new(&statuslist
, g_repo
, &opts
));
182 check_status(statuslist
, expected
, 2);
183 git_status_list_free(statuslist
);
185 git_index_free(index
);
188 void test_status_renames__head2index_rename_from_rewrite(void)
191 git_status_list
*statuslist
;
192 git_status_options opts
= GIT_STATUS_OPTIONS_INIT
;
193 struct status_entry expected
[] = {
194 { GIT_STATUS_INDEX_RENAMED
, "sixserving.txt", "ikeepsix.txt" },
195 { GIT_STATUS_INDEX_RENAMED
, "ikeepsix.txt", "sixserving.txt" },
198 opts
.flags
|= GIT_STATUS_OPT_RENAMES_HEAD_TO_INDEX
;
199 opts
.flags
|= GIT_STATUS_OPT_RENAMES_FROM_REWRITES
;
201 cl_git_pass(git_repository_index(&index
, g_repo
));
203 rename_file(g_repo
, "ikeepsix.txt", "_temp_.txt");
204 rename_file(g_repo
, "sixserving.txt", "ikeepsix.txt");
205 rename_file(g_repo
, "_temp_.txt", "sixserving.txt");
207 cl_git_pass(git_index_add_bypath(index
, "ikeepsix.txt"));
208 cl_git_pass(git_index_add_bypath(index
, "sixserving.txt"));
209 cl_git_pass(git_index_write(index
));
211 cl_git_pass(git_status_list_new(&statuslist
, g_repo
, &opts
));
212 check_status(statuslist
, expected
, 2);
213 git_status_list_free(statuslist
);
215 git_index_free(index
);
218 void test_status_renames__index2workdir_one(void)
220 git_status_list
*statuslist
;
221 git_status_options opts
= GIT_STATUS_OPTIONS_INIT
;
222 struct status_entry expected
[] = {
223 { GIT_STATUS_WT_RENAMED
, "ikeepsix.txt", "newname.txt" },
226 opts
.flags
|= GIT_STATUS_OPT_INCLUDE_UNTRACKED
;
227 opts
.flags
|= GIT_STATUS_OPT_RENAMES_INDEX_TO_WORKDIR
;
229 rename_file(g_repo
, "ikeepsix.txt", "newname.txt");
231 cl_git_pass(git_status_list_new(&statuslist
, g_repo
, &opts
));
232 check_status(statuslist
, expected
, 1);
233 git_status_list_free(statuslist
);
236 void test_status_renames__index2workdir_two(void)
238 git_status_list
*statuslist
;
239 git_status_options opts
= GIT_STATUS_OPTIONS_INIT
;
240 struct status_entry expected
[] = {
241 { GIT_STATUS_WT_RENAMED
| GIT_STATUS_WT_MODIFIED
,
242 "sixserving.txt", "aaa.txt" },
243 { GIT_STATUS_WT_RENAMED
| GIT_STATUS_WT_MODIFIED
,
244 "untimely.txt", "bbb.txt" },
245 { GIT_STATUS_WT_RENAMED
, "songof7cities.txt", "ccc.txt" },
246 { GIT_STATUS_WT_RENAMED
, "ikeepsix.txt", "ddd.txt" },
249 opts
.flags
|= GIT_STATUS_OPT_INCLUDE_UNTRACKED
;
250 opts
.flags
|= GIT_STATUS_OPT_RENAMES_INDEX_TO_WORKDIR
;
252 rename_file(g_repo
, "ikeepsix.txt", "ddd.txt");
253 rename_and_edit_file(g_repo
, "sixserving.txt", "aaa.txt");
254 rename_file(g_repo
, "songof7cities.txt", "ccc.txt");
255 rename_and_edit_file(g_repo
, "untimely.txt", "bbb.txt");
257 cl_git_pass(git_status_list_new(&statuslist
, g_repo
, &opts
));
258 check_status(statuslist
, expected
, 4);
259 git_status_list_free(statuslist
);
262 void test_status_renames__index2workdir_rename_from_rewrite(void)
265 git_status_list
*statuslist
;
266 git_status_options opts
= GIT_STATUS_OPTIONS_INIT
;
267 struct status_entry expected
[] = {
268 { GIT_STATUS_WT_RENAMED
, "sixserving.txt", "ikeepsix.txt" },
269 { GIT_STATUS_WT_RENAMED
, "ikeepsix.txt", "sixserving.txt" },
272 opts
.flags
|= GIT_STATUS_OPT_RENAMES_INDEX_TO_WORKDIR
;
273 opts
.flags
|= GIT_STATUS_OPT_RENAMES_FROM_REWRITES
;
275 cl_git_pass(git_repository_index(&index
, g_repo
));
277 rename_file(g_repo
, "ikeepsix.txt", "_temp_.txt");
278 rename_file(g_repo
, "sixserving.txt", "ikeepsix.txt");
279 rename_file(g_repo
, "_temp_.txt", "sixserving.txt");
281 cl_git_pass(git_status_list_new(&statuslist
, g_repo
, &opts
));
282 check_status(statuslist
, expected
, 2);
283 git_status_list_free(statuslist
);
285 git_index_free(index
);
288 void test_status_renames__both_one(void)
291 git_status_list
*statuslist
;
292 git_status_options opts
= GIT_STATUS_OPTIONS_INIT
;
293 struct status_entry expected
[] = {
294 { GIT_STATUS_INDEX_RENAMED
| GIT_STATUS_WT_RENAMED
,
295 "ikeepsix.txt", "newname-workdir.txt" },
298 opts
.flags
|= GIT_STATUS_OPT_INCLUDE_UNTRACKED
;
299 opts
.flags
|= GIT_STATUS_OPT_RENAMES_HEAD_TO_INDEX
;
300 opts
.flags
|= GIT_STATUS_OPT_RENAMES_INDEX_TO_WORKDIR
;
302 cl_git_pass(git_repository_index(&index
, g_repo
));
304 rename_file(g_repo
, "ikeepsix.txt", "newname-index.txt");
306 cl_git_pass(git_index_remove_bypath(index
, "ikeepsix.txt"));
307 cl_git_pass(git_index_add_bypath(index
, "newname-index.txt"));
308 cl_git_pass(git_index_write(index
));
310 rename_file(g_repo
, "newname-index.txt", "newname-workdir.txt");
312 cl_git_pass(git_status_list_new(&statuslist
, g_repo
, &opts
));
313 check_status(statuslist
, expected
, 1);
314 git_status_list_free(statuslist
);
316 git_index_free(index
);
319 void test_status_renames__both_two(void)
322 git_status_list
*statuslist
;
323 git_status_options opts
= GIT_STATUS_OPTIONS_INIT
;
324 struct status_entry expected
[] = {
325 { GIT_STATUS_INDEX_RENAMED
| GIT_STATUS_INDEX_MODIFIED
|
326 GIT_STATUS_WT_RENAMED
| GIT_STATUS_WT_MODIFIED
,
327 "ikeepsix.txt", "ikeepsix-both.txt" },
328 { GIT_STATUS_INDEX_RENAMED
| GIT_STATUS_INDEX_MODIFIED
,
329 "sixserving.txt", "sixserving-index.txt" },
330 { GIT_STATUS_WT_RENAMED
| GIT_STATUS_WT_MODIFIED
,
331 "songof7cities.txt", "songof7cities-workdir.txt" },
332 { GIT_STATUS_INDEX_RENAMED
| GIT_STATUS_WT_RENAMED
,
333 "untimely.txt", "untimely-both.txt" },
336 opts
.flags
|= GIT_STATUS_OPT_INCLUDE_UNTRACKED
;
337 opts
.flags
|= GIT_STATUS_OPT_RENAMES_HEAD_TO_INDEX
;
338 opts
.flags
|= GIT_STATUS_OPT_RENAMES_INDEX_TO_WORKDIR
;
340 cl_git_pass(git_repository_index(&index
, g_repo
));
342 rename_and_edit_file(g_repo
, "ikeepsix.txt", "ikeepsix-index.txt");
343 rename_and_edit_file(g_repo
, "sixserving.txt", "sixserving-index.txt");
344 rename_file(g_repo
, "untimely.txt", "untimely-index.txt");
346 cl_git_pass(git_index_remove_bypath(index
, "ikeepsix.txt"));
347 cl_git_pass(git_index_remove_bypath(index
, "sixserving.txt"));
348 cl_git_pass(git_index_remove_bypath(index
, "untimely.txt"));
349 cl_git_pass(git_index_add_bypath(index
, "ikeepsix-index.txt"));
350 cl_git_pass(git_index_add_bypath(index
, "sixserving-index.txt"));
351 cl_git_pass(git_index_add_bypath(index
, "untimely-index.txt"));
352 cl_git_pass(git_index_write(index
));
354 rename_and_edit_file(g_repo
, "ikeepsix-index.txt", "ikeepsix-both.txt");
355 rename_and_edit_file(g_repo
, "songof7cities.txt", "songof7cities-workdir.txt");
356 rename_file(g_repo
, "untimely-index.txt", "untimely-both.txt");
358 cl_git_pass(git_status_list_new(&statuslist
, g_repo
, &opts
));
359 check_status(statuslist
, expected
, 4);
360 git_status_list_free(statuslist
);
362 git_index_free(index
);
366 void test_status_renames__both_rename_from_rewrite(void)
369 git_status_list
*statuslist
;
370 git_status_options opts
= GIT_STATUS_OPTIONS_INIT
;
371 struct status_entry expected
[] = {
372 { GIT_STATUS_INDEX_RENAMED
| GIT_STATUS_WT_RENAMED
,
373 "songof7cities.txt", "ikeepsix.txt" },
374 { GIT_STATUS_INDEX_RENAMED
| GIT_STATUS_WT_RENAMED
,
375 "ikeepsix.txt", "sixserving.txt" },
376 { GIT_STATUS_INDEX_RENAMED
| GIT_STATUS_WT_RENAMED
,
377 "sixserving.txt", "songof7cities.txt" },
380 opts
.flags
|= GIT_STATUS_OPT_INCLUDE_UNTRACKED
;
381 opts
.flags
|= GIT_STATUS_OPT_RENAMES_HEAD_TO_INDEX
;
382 opts
.flags
|= GIT_STATUS_OPT_RENAMES_INDEX_TO_WORKDIR
;
383 opts
.flags
|= GIT_STATUS_OPT_RENAMES_FROM_REWRITES
;
385 cl_git_pass(git_repository_index(&index
, g_repo
));
387 rename_file(g_repo
, "ikeepsix.txt", "_temp_.txt");
388 rename_file(g_repo
, "sixserving.txt", "ikeepsix.txt");
389 rename_file(g_repo
, "songof7cities.txt", "sixserving.txt");
390 rename_file(g_repo
, "_temp_.txt", "songof7cities.txt");
392 cl_git_pass(git_index_add_bypath(index
, "ikeepsix.txt"));
393 cl_git_pass(git_index_add_bypath(index
, "sixserving.txt"));
394 cl_git_pass(git_index_add_bypath(index
, "songof7cities.txt"));
395 cl_git_pass(git_index_write(index
));
397 rename_file(g_repo
, "songof7cities.txt", "_temp_.txt");
398 rename_file(g_repo
, "ikeepsix.txt", "songof7cities.txt");
399 rename_file(g_repo
, "sixserving.txt", "ikeepsix.txt");
400 rename_file(g_repo
, "_temp_.txt", "sixserving.txt");
402 cl_git_pass(git_status_list_new(&statuslist
, g_repo
, &opts
));
403 check_status(statuslist
, expected
, 3);
404 git_status_list_free(statuslist
);
406 git_index_free(index
);
409 void test_status_renames__rewrites_only_for_renames(void)
412 git_status_list
*statuslist
;
413 git_status_options opts
= GIT_STATUS_OPTIONS_INIT
;
414 struct status_entry expected
[] = {
415 { GIT_STATUS_WT_MODIFIED
, "ikeepsix.txt", "ikeepsix.txt" },
418 opts
.flags
|= GIT_STATUS_OPT_INCLUDE_UNTRACKED
;
419 opts
.flags
|= GIT_STATUS_OPT_RENAMES_HEAD_TO_INDEX
;
420 opts
.flags
|= GIT_STATUS_OPT_RENAMES_INDEX_TO_WORKDIR
;
421 opts
.flags
|= GIT_STATUS_OPT_RENAMES_FROM_REWRITES
;
423 cl_git_pass(git_repository_index(&index
, g_repo
));
425 cl_git_rewritefile("renames/ikeepsix.txt",
426 "This is enough content for the file to be rewritten.\n" \
427 "This is enough content for the file to be rewritten.\n" \
428 "This is enough content for the file to be rewritten.\n" \
429 "This is enough content for the file to be rewritten.\n" \
430 "This is enough content for the file to be rewritten.\n" \
431 "This is enough content for the file to be rewritten.\n" \
432 "This is enough content for the file to be rewritten.\n" \
433 "This is enough content for the file to be rewritten.\n" \
434 "This is enough content for the file to be rewritten.\n" \
435 "This is enough content for the file to be rewritten.\n" \
436 "This is enough content for the file to be rewritten.\n" \
437 "This is enough content for the file to be rewritten.\n" \
438 "This is enough content for the file to be rewritten.\n" \
439 "This is enough content for the file to be rewritten.\n" \
440 "This is enough content for the file to be rewritten.\n" \
441 "This is enough content for the file to be rewritten.\n");
443 cl_git_pass(git_status_list_new(&statuslist
, g_repo
, &opts
));
444 check_status(statuslist
, expected
, 1);
445 git_status_list_free(statuslist
);
447 git_index_free(index
);
450 void test_status_renames__both_casechange_one(void)
453 git_status_list
*statuslist
;
454 git_status_options opts
= GIT_STATUS_OPTIONS_INIT
;
456 struct status_entry expected_icase
[] = {
457 { GIT_STATUS_INDEX_RENAMED
,
458 "ikeepsix.txt", "IKeepSix.txt" },
460 struct status_entry expected_case
[] = {
461 { GIT_STATUS_INDEX_RENAMED
| GIT_STATUS_WT_RENAMED
,
462 "ikeepsix.txt", "IKEEPSIX.txt" },
465 opts
.flags
|= GIT_STATUS_OPT_INCLUDE_UNTRACKED
;
466 opts
.flags
|= GIT_STATUS_OPT_RENAMES_HEAD_TO_INDEX
;
467 opts
.flags
|= GIT_STATUS_OPT_RENAMES_INDEX_TO_WORKDIR
;
469 cl_git_pass(git_repository_index(&index
, g_repo
));
470 index_caps
= git_index_caps(index
);
472 rename_file(g_repo
, "ikeepsix.txt", "IKeepSix.txt");
474 cl_git_pass(git_index_remove_bypath(index
, "ikeepsix.txt"));
475 cl_git_pass(git_index_add_bypath(index
, "IKeepSix.txt"));
476 cl_git_pass(git_index_write(index
));
478 /* on a case-insensitive file system, this change won't matter.
479 * on a case-sensitive one, it will.
481 rename_file(g_repo
, "IKeepSix.txt", "IKEEPSIX.txt");
483 cl_git_pass(git_status_list_new(&statuslist
, g_repo
, &opts
));
485 check_status(statuslist
, (index_caps
& GIT_INDEX_CAPABILITY_IGNORE_CASE
) ?
486 expected_icase
: expected_case
, 1);
488 git_status_list_free(statuslist
);
490 git_index_free(index
);
493 void test_status_renames__both_casechange_two(void)
496 git_status_list
*statuslist
;
497 git_status_options opts
= GIT_STATUS_OPTIONS_INIT
;
499 struct status_entry expected_icase
[] = {
500 { GIT_STATUS_INDEX_RENAMED
| GIT_STATUS_INDEX_MODIFIED
|
501 GIT_STATUS_WT_MODIFIED
,
502 "ikeepsix.txt", "IKeepSix.txt" },
503 { GIT_STATUS_INDEX_MODIFIED
,
504 "sixserving.txt", "sixserving.txt" },
505 { GIT_STATUS_INDEX_RENAMED
| GIT_STATUS_WT_MODIFIED
,
506 "songof7cities.txt", "songof7.txt" },
507 { GIT_STATUS_INDEX_RENAMED
| GIT_STATUS_WT_RENAMED
,
508 "untimely.txt", "untimeliest.txt" }
510 struct status_entry expected_case
[] = {
511 { GIT_STATUS_INDEX_RENAMED
|
512 GIT_STATUS_WT_MODIFIED
| GIT_STATUS_WT_RENAMED
,
513 "songof7cities.txt", "SONGOF7.txt" },
514 { GIT_STATUS_INDEX_MODIFIED
| GIT_STATUS_WT_RENAMED
,
515 "sixserving.txt", "SixServing.txt" },
516 { GIT_STATUS_INDEX_RENAMED
| GIT_STATUS_INDEX_MODIFIED
|
517 GIT_STATUS_WT_RENAMED
| GIT_STATUS_WT_MODIFIED
,
518 "ikeepsix.txt", "ikeepsix.txt" },
519 { GIT_STATUS_INDEX_RENAMED
| GIT_STATUS_WT_RENAMED
,
520 "untimely.txt", "untimeliest.txt" }
523 opts
.flags
|= GIT_STATUS_OPT_INCLUDE_UNTRACKED
;
524 opts
.flags
|= GIT_STATUS_OPT_RENAMES_HEAD_TO_INDEX
;
525 opts
.flags
|= GIT_STATUS_OPT_RENAMES_INDEX_TO_WORKDIR
;
527 cl_git_pass(git_repository_index(&index
, g_repo
));
528 index_caps
= git_index_caps(index
);
530 rename_and_edit_file(g_repo
, "ikeepsix.txt", "IKeepSix.txt");
531 rename_and_edit_file(g_repo
, "sixserving.txt", "sixserving.txt");
532 rename_file(g_repo
, "songof7cities.txt", "songof7.txt");
533 rename_file(g_repo
, "untimely.txt", "untimelier.txt");
535 cl_git_pass(git_index_remove_bypath(index
, "ikeepsix.txt"));
536 cl_git_pass(git_index_remove_bypath(index
, "sixserving.txt"));
537 cl_git_pass(git_index_remove_bypath(index
, "songof7cities.txt"));
538 cl_git_pass(git_index_remove_bypath(index
, "untimely.txt"));
539 cl_git_pass(git_index_add_bypath(index
, "IKeepSix.txt"));
540 cl_git_pass(git_index_add_bypath(index
, "sixserving.txt"));
541 cl_git_pass(git_index_add_bypath(index
, "songof7.txt"));
542 cl_git_pass(git_index_add_bypath(index
, "untimelier.txt"));
543 cl_git_pass(git_index_write(index
));
545 rename_and_edit_file(g_repo
, "IKeepSix.txt", "ikeepsix.txt");
546 rename_file(g_repo
, "sixserving.txt", "SixServing.txt");
547 rename_and_edit_file(g_repo
, "songof7.txt", "SONGOF7.txt");
548 rename_file(g_repo
, "untimelier.txt", "untimeliest.txt");
550 cl_git_pass(git_status_list_new(&statuslist
, g_repo
, &opts
));
552 check_status(statuslist
, (index_caps
& GIT_INDEX_CAPABILITY_IGNORE_CASE
) ?
553 expected_icase
: expected_case
, 4);
555 git_status_list_free(statuslist
);
557 git_index_free(index
);
560 void test_status_renames__zero_byte_file_does_not_fail(void)
562 git_status_list
*statuslist
;
563 git_status_options opts
= GIT_STATUS_OPTIONS_INIT
;
565 struct status_entry expected
[] = {
566 { GIT_STATUS_WT_DELETED
, "ikeepsix.txt", "ikeepsix.txt" },
567 { GIT_STATUS_WT_NEW
, "zerobyte.txt", "zerobyte.txt" },
570 opts
.flags
|= GIT_STATUS_OPT_RENAMES_FROM_REWRITES
|
571 GIT_STATUS_OPT_RENAMES_HEAD_TO_INDEX
|
572 GIT_STATUS_OPT_RENAMES_INDEX_TO_WORKDIR
|
573 GIT_STATUS_OPT_INCLUDE_IGNORED
|
574 GIT_STATUS_OPT_INCLUDE_UNTRACKED
|
575 GIT_STATUS_OPT_RECURSE_UNTRACKED_DIRS
|
576 GIT_STATUS_SHOW_INDEX_AND_WORKDIR
|
577 GIT_STATUS_OPT_RECURSE_IGNORED_DIRS
;
579 p_unlink("renames/ikeepsix.txt");
580 cl_git_mkfile("renames/zerobyte.txt", "");
582 cl_git_pass(git_status_list_new(&statuslist
, g_repo
, &opts
));
583 check_status(statuslist
, expected
, 2);
584 git_status_list_free(statuslist
);
588 static char *nfc
= "\xC3\x85\x73\x74\x72\xC3\xB6\x6D";
589 static char *nfd
= "\x41\xCC\x8A\x73\x74\x72\x6F\xCC\x88\x6D";
593 * Create a file in NFD (canonically decomposed) format. Ensure
594 * that when core.precomposeunicode is false that we return paths
595 * in NFD, but when core.precomposeunicode is true, then we
596 * return paths precomposed (in NFC).
598 void test_status_renames__precomposed_unicode_rename(void)
601 git_status_list
*statuslist
;
602 git_status_options opts
= GIT_STATUS_OPTIONS_INIT
;
603 struct status_entry expected0
[] = {
604 { GIT_STATUS_WT_NEW
, nfd
, NULL
},
605 { GIT_STATUS_WT_DELETED
, "sixserving.txt", NULL
},
607 struct status_entry expected1
[] = {
608 { GIT_STATUS_WT_RENAMED
, "sixserving.txt", nfd
},
610 struct status_entry expected2
[] = {
611 { GIT_STATUS_WT_DELETED
, "sixserving.txt", NULL
},
612 { GIT_STATUS_WT_NEW
, nfc
, NULL
},
614 struct status_entry expected3
[] = {
615 { GIT_STATUS_WT_RENAMED
, "sixserving.txt", nfc
},
618 rename_file(g_repo
, "sixserving.txt", nfd
);
620 opts
.flags
|= GIT_STATUS_OPT_INCLUDE_UNTRACKED
;
622 cl_repo_set_bool(g_repo
, "core.precomposeunicode", false);
624 cl_git_pass(git_status_list_new(&statuslist
, g_repo
, &opts
));
625 check_status(statuslist
, expected0
, ARRAY_SIZE(expected0
));
626 git_status_list_free(statuslist
);
628 opts
.flags
|= GIT_STATUS_OPT_RENAMES_INDEX_TO_WORKDIR
;
630 cl_git_pass(git_status_list_new(&statuslist
, g_repo
, &opts
));
631 check_status(statuslist
, expected1
, ARRAY_SIZE(expected1
));
632 git_status_list_free(statuslist
);
634 cl_repo_set_bool(g_repo
, "core.precomposeunicode", true);
636 opts
.flags
&= ~GIT_STATUS_OPT_RENAMES_INDEX_TO_WORKDIR
;
638 cl_git_pass(git_status_list_new(&statuslist
, g_repo
, &opts
));
639 check_status(statuslist
, expected2
, ARRAY_SIZE(expected2
));
640 git_status_list_free(statuslist
);
642 opts
.flags
|= GIT_STATUS_OPT_RENAMES_INDEX_TO_WORKDIR
;
644 cl_git_pass(git_status_list_new(&statuslist
, g_repo
, &opts
));
645 check_status(statuslist
, expected3
, ARRAY_SIZE(expected3
));
646 git_status_list_free(statuslist
);
650 void test_status_renames__precomposed_unicode_toggle_is_rename(void)
653 git_status_list
*statuslist
;
654 git_status_options opts
= GIT_STATUS_OPTIONS_INIT
;
655 struct status_entry expected0
[] = {
656 { GIT_STATUS_INDEX_RENAMED
, "ikeepsix.txt", nfd
},
658 struct status_entry expected1
[] = {
659 { GIT_STATUS_WT_RENAMED
, nfd
, nfc
},
661 struct status_entry expected2
[] = {
662 { GIT_STATUS_INDEX_RENAMED
, nfd
, nfc
},
664 struct status_entry expected3
[] = {
665 { GIT_STATUS_INDEX_RENAMED
| GIT_STATUS_WT_RENAMED
, nfd
, nfd
},
668 cl_repo_set_bool(g_repo
, "core.precomposeunicode", false);
669 rename_file(g_repo
, "ikeepsix.txt", nfd
);
673 cl_git_pass(git_repository_index(&index
, g_repo
));
674 cl_git_pass(git_index_remove_bypath(index
, "ikeepsix.txt"));
675 cl_git_pass(git_index_add_bypath(index
, nfd
));
676 cl_git_pass(git_index_write(index
));
677 git_index_free(index
);
680 opts
.flags
|= GIT_STATUS_OPT_INCLUDE_UNTRACKED
|
681 GIT_STATUS_OPT_RENAMES_HEAD_TO_INDEX
|
682 GIT_STATUS_OPT_RENAMES_INDEX_TO_WORKDIR
;
684 cl_git_pass(git_status_list_new(&statuslist
, g_repo
, &opts
));
685 check_status(statuslist
, expected0
, ARRAY_SIZE(expected0
));
686 git_status_list_free(statuslist
);
688 cl_repo_commit_from_index(NULL
, g_repo
, NULL
, 0, "commit nfd");
690 cl_git_pass(git_status_list_new(&statuslist
, g_repo
, &opts
));
691 cl_assert_equal_sz(0, git_status_list_entrycount(statuslist
));
692 git_status_list_free(statuslist
);
694 cl_repo_set_bool(g_repo
, "core.precomposeunicode", true);
696 cl_git_pass(git_status_list_new(&statuslist
, g_repo
, &opts
));
697 check_status(statuslist
, expected1
, ARRAY_SIZE(expected1
));
698 git_status_list_free(statuslist
);
702 cl_git_pass(git_repository_index(&index
, g_repo
));
703 cl_git_pass(git_index_remove_bypath(index
, nfd
));
704 cl_git_pass(git_index_add_bypath(index
, nfc
));
705 cl_git_pass(git_index_write(index
));
706 git_index_free(index
);
709 cl_git_pass(git_status_list_new(&statuslist
, g_repo
, &opts
));
710 check_status(statuslist
, expected2
, ARRAY_SIZE(expected2
));
711 git_status_list_free(statuslist
);
713 cl_repo_set_bool(g_repo
, "core.precomposeunicode", false);
715 cl_git_pass(git_status_list_new(&statuslist
, g_repo
, &opts
));
716 check_status(statuslist
, expected3
, ARRAY_SIZE(expected3
));
717 git_status_list_free(statuslist
);
721 void test_status_renames__rename_threshold(void)
724 git_status_list
*statuslist
;
725 git_status_options opts
= GIT_STATUS_OPTIONS_INIT
;
727 _rename_helper(g_repo
, "ikeepsix.txt", "newname.txt",
739 opts
.flags
|= GIT_STATUS_OPT_RENAMES_INDEX_TO_WORKDIR
;
740 opts
.flags
|= GIT_STATUS_OPT_INCLUDE_UNTRACKED
;
742 cl_git_pass(git_repository_index(&index
, g_repo
));
744 /* Default threshold */
746 struct status_entry expected
[] = {
747 { GIT_STATUS_WT_RENAMED
| GIT_STATUS_WT_MODIFIED
, "ikeepsix.txt", "newname.txt" },
750 cl_git_pass(git_status_list_new(&statuslist
, g_repo
, &opts
));
751 check_status(statuslist
, expected
, 1);
752 git_status_list_free(statuslist
);
755 /* Threshold set to 90 */
757 struct status_entry expected
[] = {
758 { GIT_STATUS_WT_DELETED
, "ikeepsix.txt", NULL
},
759 { GIT_STATUS_WT_NEW
, "newname.txt", NULL
}
762 opts
.rename_threshold
= 90;
764 cl_git_pass(git_status_list_new(&statuslist
, g_repo
, &opts
));
765 check_status(statuslist
, expected
, 2);
766 git_status_list_free(statuslist
);
769 /* Threshold set to 25 */
771 struct status_entry expected
[] = {
772 { GIT_STATUS_WT_RENAMED
| GIT_STATUS_WT_MODIFIED
, "ikeepsix.txt", "newname.txt" },
775 opts
.rename_threshold
= 25;
777 cl_git_pass(git_status_list_new(&statuslist
, g_repo
, &opts
));
778 check_status(statuslist
, expected
, 1);
779 git_status_list_free(statuslist
);
782 git_index_free(index
);
785 void test_status_renames__case_insensitive_h2i_and_i2wc(void)
787 git_status_list
*statuslist
;
788 git_status_options opts
= GIT_STATUS_OPTIONS_INIT
;
789 git_reference
*head
, *test_branch
;
790 git_checkout_options checkout_opts
= GIT_CHECKOUT_OPTIONS_INIT
;
791 git_str path_to_delete
= GIT_STR_INIT
;
792 git_str path_to_edit
= GIT_STR_INIT
;
794 git_strarray paths
= { NULL
, 0 };
796 struct status_entry expected
[] = {
797 { GIT_STATUS_INDEX_RENAMED
| GIT_STATUS_WT_MODIFIED
, "sixserving.txt", "sixserving-renamed.txt" },
798 { GIT_STATUS_INDEX_DELETED
, "Wow.txt", "Wow.txt" }
802 /* Checkout the correct branch */
803 checkout_opts
.checkout_strategy
= GIT_CHECKOUT_FORCE
;
804 cl_git_pass(git_reference_lookup(&head
, g_repo
, "HEAD"));
805 cl_git_pass(git_reference_symbolic_set_target(
806 &test_branch
, head
, "refs/heads/case-insensitive-status", NULL
));
807 cl_git_pass(git_checkout_head(g_repo
, &checkout_opts
));
809 cl_git_pass(git_repository_index(&index
, g_repo
));
812 /* Rename sixserving.txt, delete Wow.txt, and stage those changes */
813 rename_file(g_repo
, "sixserving.txt", "sixserving-renamed.txt");
814 cl_git_pass(git_str_joinpath(
815 &path_to_delete
, git_repository_workdir(g_repo
), "Wow.txt"));
816 cl_git_rmfile(path_to_delete
.ptr
);
818 cl_git_pass(git_index_add_all(index
, &paths
, GIT_INDEX_ADD_FORCE
, NULL
, NULL
));
819 cl_git_pass(git_index_write(index
));
822 /* Change content of sixserving-renamed.txt */
823 cl_git_pass(git_str_joinpath(
824 &path_to_edit
, git_repository_workdir(g_repo
), "sixserving-renamed.txt"));
825 cl_git_append2file(path_to_edit
.ptr
, "New content\n");
828 opts
.flags
|= GIT_STATUS_OPT_INCLUDE_UNTRACKED
;
829 opts
.flags
|= GIT_STATUS_OPT_RENAMES_INDEX_TO_WORKDIR
;
830 opts
.flags
|= GIT_STATUS_OPT_RENAMES_HEAD_TO_INDEX
;
831 opts
.flags
|= GIT_STATUS_OPT_SORT_CASE_INSENSITIVELY
;
833 cl_git_pass(git_status_list_new(&statuslist
, g_repo
, &opts
));
834 check_status(statuslist
, expected
, 2);
835 git_status_list_free(statuslist
);
837 git_index_free(index
);
839 git_str_dispose(&path_to_delete
);
840 git_str_dispose(&path_to_edit
);
842 git_reference_free(head
);
843 git_reference_free(test_branch
);