1 #include "clar_libgit2.h"
4 static const size_t index_entry_count
= 109;
5 static const size_t index_entry_count_2
= 1437;
6 #define TEST_INDEX_PATH cl_fixture("testrepo.git/index")
7 #define TEST_INDEX2_PATH cl_fixture("gitgit.index")
8 #define TEST_INDEXBIG_PATH cl_fixture("big.index")
9 #define TEST_INDEXBAD_PATH cl_fixture("bad.index")
20 static struct test_entry test_entries
[] = {
21 {4, "Makefile", 5064, 0x4C3F7F33},
22 {6, "git.git-authors", 2709, 0x4C3F7F33},
23 {36, "src/index.c", 10014, 0x4C43368D},
24 {48, "src/revobject.h", 1448, 0x4C3F7FE2},
25 {62, "tests/Makefile", 2631, 0x4C3F7F33}
29 static void copy_file(const char *src
, const char *dst
)
31 git_buf source_buf
= GIT_BUF_INIT
;
34 cl_git_pass(git_futils_readbuffer(&source_buf
, src
));
36 dst_fd
= git_futils_creat_withpath(dst
, 0777, 0666); /* -V536 */
40 cl_git_pass(p_write(dst_fd
, source_buf
.ptr
, source_buf
.size
));
43 git_buf_dispose(&source_buf
);
47 static void files_are_equal(const char *a
, const char *b
)
49 git_buf buf_a
= GIT_BUF_INIT
;
50 git_buf buf_b
= GIT_BUF_INIT
;
53 if (git_futils_readbuffer(&buf_a
, a
) < 0)
56 if (git_futils_readbuffer(&buf_b
, b
) < 0) {
57 git_buf_dispose(&buf_a
);
61 pass
= (buf_a
.size
== buf_b
.size
&& !memcmp(buf_a
.ptr
, buf_b
.ptr
, buf_a
.size
));
63 git_buf_dispose(&buf_a
);
64 git_buf_dispose(&buf_b
);
70 /* Fixture setup and teardown */
71 void test_index_tests__initialize(void)
75 void test_index_tests__cleanup(void)
77 cl_git_pass(git_libgit2_opts(GIT_OPT_ENABLE_UNSAVED_INDEX_SAFETY
, 0));
80 void test_index_tests__empty_index(void)
84 cl_git_pass(git_index_open(&index
, "in-memory-index"));
85 cl_assert(index
->on_disk
== 0);
87 cl_assert(git_index_entrycount(index
) == 0);
88 cl_assert(git_vector_is_sorted(&index
->entries
));
90 git_index_free(index
);
93 void test_index_tests__default_test_index(void)
97 git_index_entry
**entries
;
99 cl_git_pass(git_index_open(&index
, TEST_INDEX_PATH
));
100 cl_assert(index
->on_disk
);
102 cl_assert(git_index_entrycount(index
) == index_entry_count
);
103 cl_assert(git_vector_is_sorted(&index
->entries
));
105 entries
= (git_index_entry
**)index
->entries
.contents
;
107 for (i
= 0; i
< ARRAY_SIZE(test_entries
); ++i
) {
108 git_index_entry
*e
= entries
[test_entries
[i
].index
];
110 cl_assert_equal_s(e
->path
, test_entries
[i
].path
);
111 cl_assert_equal_i(e
->mtime
.seconds
, test_entries
[i
].mtime
);
112 cl_assert_equal_i(e
->file_size
, test_entries
[i
].file_size
);
115 git_index_free(index
);
118 void test_index_tests__gitgit_index(void)
122 cl_git_pass(git_index_open(&index
, TEST_INDEX2_PATH
));
123 cl_assert(index
->on_disk
);
125 cl_assert(git_index_entrycount(index
) == index_entry_count_2
);
126 cl_assert(git_vector_is_sorted(&index
->entries
));
127 cl_assert(index
->tree
!= NULL
);
129 git_index_free(index
);
132 void test_index_tests__find_in_existing(void)
137 cl_git_pass(git_index_open(&index
, TEST_INDEX_PATH
));
139 for (i
= 0; i
< ARRAY_SIZE(test_entries
); ++i
) {
142 cl_assert(!git_index_find(&idx
, index
, test_entries
[i
].path
));
143 cl_assert(idx
== test_entries
[i
].index
);
146 git_index_free(index
);
149 void test_index_tests__find_in_empty(void)
154 cl_git_pass(git_index_open(&index
, "fake-index"));
156 for (i
= 0; i
< ARRAY_SIZE(test_entries
); ++i
) {
157 cl_assert(GIT_ENOTFOUND
== git_index_find(NULL
, index
, test_entries
[i
].path
));
160 git_index_free(index
);
163 void test_index_tests__find_prefix(void)
166 const git_index_entry
*entry
;
169 cl_git_pass(git_index_open(&index
, TEST_INDEX_PATH
));
171 cl_git_pass(git_index_find_prefix(&pos
, index
, "src"));
172 entry
= git_index_get_byindex(index
, pos
);
173 cl_assert(git__strcmp(entry
->path
, "src/block-sha1/sha1.c") == 0);
175 cl_git_pass(git_index_find_prefix(&pos
, index
, "src/co"));
176 entry
= git_index_get_byindex(index
, pos
);
177 cl_assert(git__strcmp(entry
->path
, "src/commit.c") == 0);
179 cl_assert(GIT_ENOTFOUND
== git_index_find_prefix(NULL
, index
, "blah"));
181 git_index_free(index
);
184 void test_index_tests__write(void)
188 copy_file(TEST_INDEXBIG_PATH
, "index_rewrite");
190 cl_git_pass(git_index_open(&index
, "index_rewrite"));
191 cl_assert(index
->on_disk
);
193 cl_git_pass(git_index_write(index
));
194 files_are_equal(TEST_INDEXBIG_PATH
, "index_rewrite");
196 git_index_free(index
);
198 p_unlink("index_rewrite");
201 void test_index_tests__sort0(void)
203 /* sort the entires in an index */
206 * TODO: This no longer applies:
207 * index sorting in Git uses some specific changes to the way
208 * directories are sorted.
210 * We need to specificially check for this by creating a new
211 * index, adding entries in random order and then
212 * checking for consistency
216 void test_index_tests__sort1(void)
218 /* sort the entires in an empty index */
221 cl_git_pass(git_index_open(&index
, "fake-index"));
223 /* FIXME: this test is slightly dumb */
224 cl_assert(git_vector_is_sorted(&index
->entries
));
226 git_index_free(index
);
229 static void cleanup_myrepo(void *opaque
)
232 cl_fixture_cleanup("myrepo");
235 void test_index_tests__add(void)
238 git_filebuf file
= GIT_FILEBUF_INIT
;
239 git_repository
*repo
;
240 const git_index_entry
*entry
;
243 cl_set_cleanup(&cleanup_myrepo
, NULL
);
245 /* Intialize a new repository */
246 cl_git_pass(git_repository_init(&repo
, "./myrepo", 0));
248 /* Ensure we're the only guy in the room */
249 cl_git_pass(git_repository_index(&index
, repo
));
250 cl_assert(git_index_entrycount(index
) == 0);
252 /* Create a new file in the working directory */
253 cl_git_pass(git_futils_mkpath2file("myrepo/test.txt", 0777));
254 cl_git_pass(git_filebuf_open(&file
, "myrepo/test.txt", 0, 0666));
255 cl_git_pass(git_filebuf_write(&file
, "hey there\n", 10));
256 cl_git_pass(git_filebuf_commit(&file
));
258 /* Store the expected hash of the file/blob
259 * This has been generated by executing the following
260 * $ echo "hey there" | git hash-object --stdin
262 cl_git_pass(git_oid_fromstr(&id1
, "a8233120f6ad708f843d861ce2b7228ec4e3dec6"));
264 /* Add the new file to the index */
265 cl_git_pass(git_index_add_bypath(index
, "test.txt"));
267 /* Wow... it worked! */
268 cl_assert(git_index_entrycount(index
) == 1);
269 entry
= git_index_get_byindex(index
, 0);
271 /* And the built-in hashing mechanism worked as expected */
272 cl_assert_equal_oid(&id1
, &entry
->id
);
274 /* Test access by path instead of index */
275 cl_assert((entry
= git_index_get_bypath(index
, "test.txt", 0)) != NULL
);
276 cl_assert_equal_oid(&id1
, &entry
->id
);
278 git_index_free(index
);
279 git_repository_free(repo
);
282 void test_index_tests__add_frombuffer(void)
285 git_repository
*repo
;
286 git_index_entry entry
;
287 const git_index_entry
*returned_entry
;
292 const char *content
= "hey there\n";
294 cl_set_cleanup(&cleanup_myrepo
, NULL
);
296 /* Intialize a new repository */
297 cl_git_pass(git_repository_init(&repo
, "./myrepo", 0));
299 /* Ensure we're the only guy in the room */
300 cl_git_pass(git_repository_index(&index
, repo
));
301 cl_assert(git_index_entrycount(index
) == 0);
303 /* Store the expected hash of the file/blob
304 * This has been generated by executing the following
305 * $ echo "hey there" | git hash-object --stdin
307 cl_git_pass(git_oid_fromstr(&id1
, "a8233120f6ad708f843d861ce2b7228ec4e3dec6"));
309 /* Add the new file to the index */
310 memset(&entry
, 0x0, sizeof(git_index_entry
));
311 entry
.mode
= GIT_FILEMODE_BLOB
;
312 entry
.path
= "test.txt";
313 cl_git_pass(git_index_add_from_buffer(index
, &entry
,
314 content
, strlen(content
)));
316 /* Wow... it worked! */
317 cl_assert(git_index_entrycount(index
) == 1);
318 returned_entry
= git_index_get_byindex(index
, 0);
320 /* And the built-in hashing mechanism worked as expected */
321 cl_assert_equal_oid(&id1
, &returned_entry
->id
);
322 /* And mode is the one asked */
323 cl_assert_equal_i(GIT_FILEMODE_BLOB
, returned_entry
->mode
);
325 /* Test access by path instead of index */
326 cl_assert((returned_entry
= git_index_get_bypath(index
, "test.txt", 0)) != NULL
);
327 cl_assert_equal_oid(&id1
, &returned_entry
->id
);
329 /* Test the blob is in the repository */
330 cl_git_pass(git_blob_lookup(&blob
, repo
, &id1
));
332 content
, git_blob_rawcontent(blob
));
335 git_index_free(index
);
336 git_repository_free(repo
);
339 void test_index_tests__dirty_and_clean(void)
341 git_repository
*repo
;
343 git_index_entry entry
= {{0}};
345 /* Index is not dirty after opening */
346 cl_git_pass(git_repository_init(&repo
, "./myrepo", 0));
347 cl_git_pass(git_repository_index(&index
, repo
));
349 cl_assert(git_index_entrycount(index
) == 0);
350 cl_assert(!git_index_is_dirty(index
));
352 /* Index is dirty after adding an entry */
353 entry
.mode
= GIT_FILEMODE_BLOB
;
354 entry
.path
= "test.txt";
355 cl_git_pass(git_index_add_from_buffer(index
, &entry
, "Hi.\n", 4));
356 cl_assert(git_index_entrycount(index
) == 1);
357 cl_assert(git_index_is_dirty(index
));
359 /* Index is not dirty after write */
360 cl_git_pass(git_index_write(index
));
361 cl_assert(!git_index_is_dirty(index
));
363 /* Index is dirty after removing an entry */
364 cl_git_pass(git_index_remove_bypath(index
, "test.txt"));
365 cl_assert(git_index_entrycount(index
) == 0);
366 cl_assert(git_index_is_dirty(index
));
368 /* Index is not dirty after write */
369 cl_git_pass(git_index_write(index
));
370 cl_assert(!git_index_is_dirty(index
));
372 /* Index remains not dirty after read */
373 cl_git_pass(git_index_read(index
, 0));
374 cl_assert(!git_index_is_dirty(index
));
376 /* Index is dirty when we do an unforced read with dirty content */
377 cl_git_pass(git_index_add_from_buffer(index
, &entry
, "Hi.\n", 4));
378 cl_assert(git_index_entrycount(index
) == 1);
379 cl_assert(git_index_is_dirty(index
));
381 cl_git_pass(git_index_read(index
, 0));
382 cl_assert(git_index_is_dirty(index
));
384 /* Index is clean when we force a read with dirty content */
385 cl_git_pass(git_index_read(index
, 1));
386 cl_assert(!git_index_is_dirty(index
));
388 git_index_free(index
);
389 git_repository_free(repo
);
392 void test_index_tests__dirty_fails_optionally(void)
394 git_repository
*repo
;
396 git_index_entry entry
= {{0}};
398 /* Index is not dirty after opening */
399 repo
= cl_git_sandbox_init("testrepo");
400 cl_git_pass(git_repository_index(&index
, repo
));
402 /* Index is dirty after adding an entry */
403 entry
.mode
= GIT_FILEMODE_BLOB
;
404 entry
.path
= "test.txt";
405 cl_git_pass(git_index_add_from_buffer(index
, &entry
, "Hi.\n", 4));
406 cl_assert(git_index_is_dirty(index
));
408 cl_git_pass(git_checkout_head(repo
, NULL
));
410 /* Index is dirty (again) after adding an entry */
411 entry
.mode
= GIT_FILEMODE_BLOB
;
412 entry
.path
= "test.txt";
413 cl_git_pass(git_index_add_from_buffer(index
, &entry
, "Hi.\n", 4));
414 cl_assert(git_index_is_dirty(index
));
416 cl_git_pass(git_libgit2_opts(GIT_OPT_ENABLE_UNSAVED_INDEX_SAFETY
, 1));
417 cl_git_fail_with(GIT_EINDEXDIRTY
, git_checkout_head(repo
, NULL
));
419 git_index_free(index
);
420 cl_git_sandbox_cleanup();
423 void test_index_tests__add_frombuffer_reset_entry(void)
426 git_repository
*repo
;
427 git_index_entry entry
;
428 const git_index_entry
*returned_entry
;
429 git_filebuf file
= GIT_FILEBUF_INIT
;
433 const char *old_content
= "here\n";
434 const char *content
= "hey there\n";
436 cl_set_cleanup(&cleanup_myrepo
, NULL
);
438 /* Intialize a new repository */
439 cl_git_pass(git_repository_init(&repo
, "./myrepo", 0));
440 cl_git_pass(git_repository_index(&index
, repo
));
441 cl_git_pass(git_futils_mkpath2file("myrepo/test.txt", 0777));
442 cl_git_pass(git_filebuf_open(&file
, "myrepo/test.txt", 0, 0666));
443 cl_git_pass(git_filebuf_write(&file
, old_content
, strlen(old_content
)));
444 cl_git_pass(git_filebuf_commit(&file
));
446 /* Store the expected hash of the file/blob
447 * This has been generated by executing the following
448 * $ echo "hey there" | git hash-object --stdin
450 cl_git_pass(git_oid_fromstr(&id1
, "a8233120f6ad708f843d861ce2b7228ec4e3dec6"));
452 cl_git_pass(git_index_add_bypath(index
, "test.txt"));
454 /* Add the new file to the index */
455 memset(&entry
, 0x0, sizeof(git_index_entry
));
456 entry
.mode
= GIT_FILEMODE_BLOB
;
457 entry
.path
= "test.txt";
458 cl_git_pass(git_index_add_from_buffer(index
, &entry
,
459 content
, strlen(content
)));
461 /* Wow... it worked! */
462 cl_assert(git_index_entrycount(index
) == 1);
463 returned_entry
= git_index_get_byindex(index
, 0);
465 /* And the built-in hashing mechanism worked as expected */
466 cl_assert_equal_oid(&id1
, &returned_entry
->id
);
467 /* And mode is the one asked */
468 cl_assert_equal_i(GIT_FILEMODE_BLOB
, returned_entry
->mode
);
470 /* Test access by path instead of index */
471 cl_assert((returned_entry
= git_index_get_bypath(index
, "test.txt", 0)) != NULL
);
472 cl_assert_equal_oid(&id1
, &returned_entry
->id
);
473 cl_assert_equal_i(0, returned_entry
->dev
);
474 cl_assert_equal_i(0, returned_entry
->ino
);
475 cl_assert_equal_i(0, returned_entry
->uid
);
476 cl_assert_equal_i(0, returned_entry
->uid
);
477 cl_assert_equal_i(10, returned_entry
->file_size
);
479 /* Test the blob is in the repository */
480 cl_git_pass(git_blob_lookup(&blob
, repo
, &id1
));
481 cl_assert_equal_s(content
, git_blob_rawcontent(blob
));
484 git_index_free(index
);
485 git_repository_free(repo
);
488 static void cleanup_1397(void *opaque
)
491 cl_git_sandbox_cleanup();
494 void test_index_tests__add_issue_1397(void)
497 git_repository
*repo
;
498 const git_index_entry
*entry
;
501 cl_set_cleanup(&cleanup_1397
, NULL
);
503 repo
= cl_git_sandbox_init("issue_1397");
505 cl_repo_set_bool(repo
, "core.autocrlf", true);
507 /* Ensure we're the only guy in the room */
508 cl_git_pass(git_repository_index(&index
, repo
));
510 /* Store the expected hash of the file/blob
511 * This has been generated by executing the following
512 * $ git hash-object crlf_file.txt
514 cl_git_pass(git_oid_fromstr(&id1
, "8312e0889a9cbab77c732b6bc39b51a683e3a318"));
516 /* Make sure the initial SHA-1 is correct */
517 cl_assert((entry
= git_index_get_bypath(index
, "crlf_file.txt", 0)) != NULL
);
518 cl_assert_equal_oid(&id1
, &entry
->id
);
520 /* Update the index */
521 cl_git_pass(git_index_add_bypath(index
, "crlf_file.txt"));
523 /* Check the new SHA-1 */
524 cl_assert((entry
= git_index_get_bypath(index
, "crlf_file.txt", 0)) != NULL
);
525 cl_assert_equal_oid(&id1
, &entry
->id
);
527 git_index_free(index
);
530 void test_index_tests__add_bypath_to_a_bare_repository_returns_EBAREPO(void)
532 git_repository
*bare_repo
;
535 cl_git_pass(git_repository_open(&bare_repo
, cl_fixture("testrepo.git")));
536 cl_git_pass(git_repository_index(&index
, bare_repo
));
538 cl_assert_equal_i(GIT_EBAREREPO
, git_index_add_bypath(index
, "test.txt"));
540 git_index_free(index
);
541 git_repository_free(bare_repo
);
544 static void assert_add_bypath_fails(git_repository
*repo
, const char *fn
)
547 git_buf path
= GIT_BUF_INIT
;
549 cl_git_pass(git_repository_index(&index
, repo
));
550 cl_assert(git_index_entrycount(index
) == 0);
552 git_buf_joinpath(&path
, "./invalid", fn
);
554 cl_git_mkfile(path
.ptr
, NULL
);
555 cl_git_fail(git_index_add_bypath(index
, fn
));
556 cl_must_pass(p_unlink(path
.ptr
));
558 cl_assert(git_index_entrycount(index
) == 0);
560 git_buf_dispose(&path
);
561 git_index_free(index
);
564 /* Test that writing an invalid filename fails */
565 void test_index_tests__cannot_add_invalid_filename(void)
567 git_repository
*repo
;
569 p_mkdir("invalid", 0700);
571 cl_git_pass(git_repository_init(&repo
, "./invalid", 0));
572 cl_must_pass(p_mkdir("./invalid/subdir", 0777));
574 /* cl_git_mkfile() needs the dir to exist */
575 if (!git_path_exists("./invalid/.GIT"))
576 cl_must_pass(p_mkdir("./invalid/.GIT", 0777));
577 if (!git_path_exists("./invalid/.GiT"))
578 cl_must_pass(p_mkdir("./invalid/.GiT", 0777));
580 assert_add_bypath_fails(repo
, ".git/hello");
581 assert_add_bypath_fails(repo
, ".GIT/hello");
582 assert_add_bypath_fails(repo
, ".GiT/hello");
583 assert_add_bypath_fails(repo
, "./.git/hello");
584 assert_add_bypath_fails(repo
, "./foo");
585 assert_add_bypath_fails(repo
, "./bar");
586 assert_add_bypath_fails(repo
, "subdir/../bar");
588 git_repository_free(repo
);
590 cl_fixture_cleanup("invalid");
593 static void assert_add_fails(git_repository
*repo
, const char *fn
)
596 git_buf path
= GIT_BUF_INIT
;
597 git_index_entry entry
= {{0}};
599 cl_git_pass(git_repository_index(&index
, repo
));
600 cl_assert(git_index_entrycount(index
) == 0);
603 entry
.mode
= GIT_FILEMODE_BLOB
;
604 cl_git_pass(git_oid_fromstr(&entry
.id
, "e69de29bb2d1d6434b8b29ae775ad8c2e48c5391"));
606 cl_git_fail(git_index_add(index
, &entry
));
608 cl_assert(git_index_entrycount(index
) == 0);
610 git_buf_dispose(&path
);
611 git_index_free(index
);
615 * Test that writing an invalid filename fails on filesystem
616 * specific protected names
618 void test_index_tests__cannot_add_protected_invalid_filename(void)
620 git_repository
*repo
;
623 cl_must_pass(p_mkdir("invalid", 0700));
625 cl_git_pass(git_repository_init(&repo
, "./invalid", 0));
627 /* add a file to the repository so we can reference it later */
628 cl_git_pass(git_repository_index(&index
, repo
));
629 cl_git_mkfile("invalid/dummy.txt", "");
630 cl_git_pass(git_index_add_bypath(index
, "dummy.txt"));
631 cl_must_pass(p_unlink("invalid/dummy.txt"));
632 cl_git_pass(git_index_remove_bypath(index
, "dummy.txt"));
633 git_index_free(index
);
635 cl_repo_set_bool(repo
, "core.protectHFS", true);
636 cl_repo_set_bool(repo
, "core.protectNTFS", true);
638 assert_add_fails(repo
, ".git./hello");
639 assert_add_fails(repo
, ".git\xe2\x80\xad/hello");
640 assert_add_fails(repo
, "git~1/hello");
641 assert_add_fails(repo
, ".git\xe2\x81\xaf/hello");
642 assert_add_fails(repo
, ".git::$INDEX_ALLOCATION/dummy-file");
644 git_repository_free(repo
);
646 cl_fixture_cleanup("invalid");
649 static void replace_char(char *str
, char in
, char out
)
658 static void assert_write_fails(git_repository
*repo
, const char *fn_orig
)
662 const git_index_entry
*entry
;
663 git_buf path
= GIT_BUF_INIT
;
666 cl_git_pass(git_repository_index(&index
, repo
));
667 cl_assert(git_index_entrycount(index
) == 0);
670 * Sneak a valid path into the index, we'll update it
671 * to an invalid path when we try to write the index.
673 fn
= git__strdup(fn_orig
);
674 replace_char(fn
, '/', '_');
675 replace_char(fn
, ':', '!');
677 git_buf_joinpath(&path
, "./invalid", fn
);
679 cl_git_mkfile(path
.ptr
, NULL
);
681 cl_git_pass(git_index_add_bypath(index
, fn
));
683 cl_assert(entry
= git_index_get_bypath(index
, fn
, 0));
685 /* kids, don't try this at home */
686 replace_char((char *)entry
->path
, '_', '/');
687 replace_char((char *)entry
->path
, '!', ':');
690 cl_git_fail(git_index_write_tree(&expected
, index
));
694 cl_git_pass(git_index_remove_all(index
, NULL
, NULL
, NULL
));
695 git_buf_dispose(&path
);
696 git_index_free(index
);
700 void test_index_tests__write_tree_invalid_unowned_index(void)
703 git_repository
*repo
;
704 git_index_entry entry
= {{0}};
707 cl_git_pass(git_index_new(&idx
));
709 cl_git_pass(git_oid_fromstr(&entry
.id
, "8312e0a89a9cbab77c732b6bc39b51a783e3a318"));
711 entry
.mode
= GIT_FILEMODE_BLOB
;
712 cl_git_pass(git_index_add(idx
, &entry
));
714 cl_git_pass(git_repository_init(&repo
, "./invalid-id", 0));
716 cl_git_fail(git_index_write_tree_to(&tree_id
, idx
, repo
));
719 git_repository_free(repo
);
721 cl_fixture_cleanup("invalid-id");
724 /* Test that writing an invalid filename fails */
725 void test_index_tests__write_invalid_filename(void)
727 git_repository
*repo
;
729 p_mkdir("invalid", 0700);
731 cl_git_pass(git_repository_init(&repo
, "./invalid", 0));
733 assert_write_fails(repo
, ".git/hello");
734 assert_write_fails(repo
, ".GIT/hello");
735 assert_write_fails(repo
, ".GiT/hello");
736 assert_write_fails(repo
, "./.git/hello");
737 assert_write_fails(repo
, "./foo");
738 assert_write_fails(repo
, "./bar");
739 assert_write_fails(repo
, "foo/../bar");
741 git_repository_free(repo
);
743 cl_fixture_cleanup("invalid");
746 void test_index_tests__honors_protect_filesystems(void)
748 git_repository
*repo
;
750 p_mkdir("invalid", 0700);
752 cl_git_pass(git_repository_init(&repo
, "./invalid", 0));
754 cl_repo_set_bool(repo
, "core.protectHFS", true);
755 cl_repo_set_bool(repo
, "core.protectNTFS", true);
757 assert_write_fails(repo
, ".git./hello");
758 assert_write_fails(repo
, ".git\xe2\x80\xad/hello");
759 assert_write_fails(repo
, "git~1/hello");
760 assert_write_fails(repo
, ".git\xe2\x81\xaf/hello");
761 assert_write_fails(repo
, ".git::$INDEX_ALLOCATION/dummy-file");
763 git_repository_free(repo
);
765 cl_fixture_cleanup("invalid");
768 void test_index_tests__protectntfs_on_by_default(void)
770 git_repository
*repo
;
772 p_mkdir("invalid", 0700);
774 cl_git_pass(git_repository_init(&repo
, "./invalid", 0));
775 assert_write_fails(repo
, ".git./hello");
776 assert_write_fails(repo
, "git~1/hello");
778 git_repository_free(repo
);
780 cl_fixture_cleanup("invalid");
783 void test_index_tests__can_disable_protectntfs(void)
785 git_repository
*repo
;
788 cl_must_pass(p_mkdir("valid", 0700));
789 cl_git_rewritefile("valid/git~1", "steal the shortname");
791 cl_git_pass(git_repository_init(&repo
, "./valid", 0));
792 cl_git_pass(git_repository_index(&index
, repo
));
793 cl_repo_set_bool(repo
, "core.protectNTFS", false);
795 cl_git_pass(git_index_add_bypath(index
, "git~1"));
797 git_index_free(index
);
798 git_repository_free(repo
);
800 cl_fixture_cleanup("valid");
803 void test_index_tests__remove_entry(void)
805 git_repository
*repo
;
808 p_mkdir("index_test", 0770);
810 cl_git_pass(git_repository_init(&repo
, "index_test", 0));
811 cl_git_pass(git_repository_index(&index
, repo
));
812 cl_assert(git_index_entrycount(index
) == 0);
814 cl_git_mkfile("index_test/hello", NULL
);
815 cl_git_pass(git_index_add_bypath(index
, "hello"));
816 cl_git_pass(git_index_write(index
));
818 cl_git_pass(git_index_read(index
, true)); /* reload */
819 cl_assert(git_index_entrycount(index
) == 1);
820 cl_assert(git_index_get_bypath(index
, "hello", 0) != NULL
);
822 cl_git_pass(git_index_remove(index
, "hello", 0));
823 cl_git_pass(git_index_write(index
));
825 cl_git_pass(git_index_read(index
, true)); /* reload */
826 cl_assert(git_index_entrycount(index
) == 0);
827 cl_assert(git_index_get_bypath(index
, "hello", 0) == NULL
);
829 git_index_free(index
);
830 git_repository_free(repo
);
831 cl_fixture_cleanup("index_test");
834 void test_index_tests__remove_directory(void)
836 git_repository
*repo
;
839 p_mkdir("index_test", 0770);
841 cl_git_pass(git_repository_init(&repo
, "index_test", 0));
842 cl_git_pass(git_repository_index(&index
, repo
));
843 cl_assert_equal_i(0, (int)git_index_entrycount(index
));
845 p_mkdir("index_test/a", 0770);
846 cl_git_mkfile("index_test/a/1.txt", NULL
);
847 cl_git_mkfile("index_test/a/2.txt", NULL
);
848 cl_git_mkfile("index_test/a/3.txt", NULL
);
849 cl_git_mkfile("index_test/b.txt", NULL
);
851 cl_git_pass(git_index_add_bypath(index
, "a/1.txt"));
852 cl_git_pass(git_index_add_bypath(index
, "a/2.txt"));
853 cl_git_pass(git_index_add_bypath(index
, "a/3.txt"));
854 cl_git_pass(git_index_add_bypath(index
, "b.txt"));
855 cl_git_pass(git_index_write(index
));
857 cl_git_pass(git_index_read(index
, true)); /* reload */
858 cl_assert_equal_i(4, (int)git_index_entrycount(index
));
859 cl_assert(git_index_get_bypath(index
, "a/1.txt", 0) != NULL
);
860 cl_assert(git_index_get_bypath(index
, "a/2.txt", 0) != NULL
);
861 cl_assert(git_index_get_bypath(index
, "b.txt", 0) != NULL
);
863 cl_git_pass(git_index_remove(index
, "a/1.txt", 0));
864 cl_git_pass(git_index_write(index
));
866 cl_git_pass(git_index_read(index
, true)); /* reload */
867 cl_assert_equal_i(3, (int)git_index_entrycount(index
));
868 cl_assert(git_index_get_bypath(index
, "a/1.txt", 0) == NULL
);
869 cl_assert(git_index_get_bypath(index
, "a/2.txt", 0) != NULL
);
870 cl_assert(git_index_get_bypath(index
, "b.txt", 0) != NULL
);
872 cl_git_pass(git_index_remove_directory(index
, "a", 0));
873 cl_git_pass(git_index_write(index
));
875 cl_git_pass(git_index_read(index
, true)); /* reload */
876 cl_assert_equal_i(1, (int)git_index_entrycount(index
));
877 cl_assert(git_index_get_bypath(index
, "a/1.txt", 0) == NULL
);
878 cl_assert(git_index_get_bypath(index
, "a/2.txt", 0) == NULL
);
879 cl_assert(git_index_get_bypath(index
, "b.txt", 0) != NULL
);
881 git_index_free(index
);
882 git_repository_free(repo
);
883 cl_fixture_cleanup("index_test");
886 void test_index_tests__preserves_case(void)
888 git_repository
*repo
;
890 const git_index_entry
*entry
;
893 cl_set_cleanup(&cleanup_myrepo
, NULL
);
895 cl_git_pass(git_repository_init(&repo
, "./myrepo", 0));
896 cl_git_pass(git_repository_index(&index
, repo
));
898 index_caps
= git_index_caps(index
);
900 cl_git_rewritefile("myrepo/test.txt", "hey there\n");
901 cl_git_pass(git_index_add_bypath(index
, "test.txt"));
903 cl_git_pass(p_rename("myrepo/test.txt", "myrepo/TEST.txt"));
904 cl_git_rewritefile("myrepo/TEST.txt", "hello again\n");
905 cl_git_pass(git_index_add_bypath(index
, "TEST.txt"));
907 if (index_caps
& GIT_INDEX_CAPABILITY_IGNORE_CASE
)
908 cl_assert_equal_i(1, (int)git_index_entrycount(index
));
910 cl_assert_equal_i(2, (int)git_index_entrycount(index
));
912 /* Test access by path instead of index */
913 cl_assert((entry
= git_index_get_bypath(index
, "test.txt", 0)) != NULL
);
914 /* The path should *not* have changed without an explicit remove */
915 cl_assert(git__strcmp(entry
->path
, "test.txt") == 0);
917 cl_assert((entry
= git_index_get_bypath(index
, "TEST.txt", 0)) != NULL
);
918 if (index_caps
& GIT_INDEX_CAPABILITY_IGNORE_CASE
)
919 /* The path should *not* have changed without an explicit remove */
920 cl_assert(git__strcmp(entry
->path
, "test.txt") == 0);
922 cl_assert(git__strcmp(entry
->path
, "TEST.txt") == 0);
924 git_index_free(index
);
925 git_repository_free(repo
);
928 void test_index_tests__elocked(void)
930 git_repository
*repo
;
932 git_filebuf file
= GIT_FILEBUF_INIT
;
933 const git_error
*err
;
936 cl_set_cleanup(&cleanup_myrepo
, NULL
);
938 cl_git_pass(git_repository_init(&repo
, "./myrepo", 0));
939 cl_git_pass(git_repository_index(&index
, repo
));
941 /* Lock the index file so we fail to lock it */
942 cl_git_pass(git_filebuf_open(&file
, index
->index_file_path
, 0, 0666));
943 error
= git_index_write(index
);
944 cl_assert_equal_i(GIT_ELOCKED
, error
);
946 err
= git_error_last();
947 cl_assert_equal_i(err
->klass
, GIT_ERROR_INDEX
);
949 git_filebuf_cleanup(&file
);
950 git_index_free(index
);
951 git_repository_free(repo
);
954 void test_index_tests__reload_from_disk(void)
956 git_repository
*repo
;
957 git_index
*read_index
;
958 git_index
*write_index
;
960 cl_set_cleanup(&cleanup_myrepo
, NULL
);
962 cl_git_pass(git_futils_mkdir("./myrepo", 0777, GIT_MKDIR_PATH
));
963 cl_git_mkfile("./myrepo/a.txt", "a\n");
964 cl_git_mkfile("./myrepo/b.txt", "b\n");
966 cl_git_pass(git_repository_init(&repo
, "./myrepo", 0));
967 cl_git_pass(git_repository_index(&write_index
, repo
));
968 cl_assert_equal_i(false, write_index
->on_disk
);
970 cl_git_pass(git_index_open(&read_index
, write_index
->index_file_path
));
971 cl_assert_equal_i(false, read_index
->on_disk
);
973 /* Stage two new files against the write_index */
974 cl_git_pass(git_index_add_bypath(write_index
, "a.txt"));
975 cl_git_pass(git_index_add_bypath(write_index
, "b.txt"));
977 cl_assert_equal_sz(2, git_index_entrycount(write_index
));
979 /* Persist the index changes to disk */
980 cl_git_pass(git_index_write(write_index
));
981 cl_assert_equal_i(true, write_index
->on_disk
);
983 /* Sync the changes back into the read_index */
984 cl_assert_equal_sz(0, git_index_entrycount(read_index
));
986 cl_git_pass(git_index_read(read_index
, true));
987 cl_assert_equal_i(true, read_index
->on_disk
);
989 cl_assert_equal_sz(2, git_index_entrycount(read_index
));
991 /* Remove the index file from the filesystem */
992 cl_git_pass(p_unlink(write_index
->index_file_path
));
994 /* Sync the changes back into the read_index */
995 cl_git_pass(git_index_read(read_index
, true));
996 cl_assert_equal_i(false, read_index
->on_disk
);
997 cl_assert_equal_sz(0, git_index_entrycount(read_index
));
999 git_index_free(read_index
);
1000 git_index_free(write_index
);
1001 git_repository_free(repo
);
1004 void test_index_tests__corrupted_extension(void)
1008 cl_git_fail_with(git_index_open(&index
, TEST_INDEXBAD_PATH
), GIT_ERROR
);
1011 void test_index_tests__reload_while_ignoring_case(void)
1016 cl_git_pass(git_index_open(&index
, TEST_INDEX_PATH
));
1017 cl_git_pass(git_vector_verify_sorted(&index
->entries
));
1019 caps
= git_index_caps(index
);
1020 cl_git_pass(git_index_set_caps(index
, caps
&= ~GIT_INDEX_CAPABILITY_IGNORE_CASE
));
1021 cl_git_pass(git_index_read(index
, true));
1022 cl_git_pass(git_vector_verify_sorted(&index
->entries
));
1023 cl_assert(git_index_get_bypath(index
, ".HEADER", 0));
1024 cl_assert_equal_p(NULL
, git_index_get_bypath(index
, ".header", 0));
1026 cl_git_pass(git_index_set_caps(index
, caps
| GIT_INDEX_CAPABILITY_IGNORE_CASE
));
1027 cl_git_pass(git_index_read(index
, true));
1028 cl_git_pass(git_vector_verify_sorted(&index
->entries
));
1029 cl_assert(git_index_get_bypath(index
, ".HEADER", 0));
1030 cl_assert(git_index_get_bypath(index
, ".header", 0));
1032 git_index_free(index
);
1035 void test_index_tests__change_icase_on_instance(void)
1039 const git_index_entry
*e
;
1041 cl_git_pass(git_index_open(&index
, TEST_INDEX_PATH
));
1042 cl_git_pass(git_vector_verify_sorted(&index
->entries
));
1044 caps
= git_index_caps(index
);
1045 cl_git_pass(git_index_set_caps(index
, caps
&= ~GIT_INDEX_CAPABILITY_IGNORE_CASE
));
1046 cl_assert_equal_i(false, index
->ignore_case
);
1047 cl_git_pass(git_vector_verify_sorted(&index
->entries
));
1048 cl_assert(e
= git_index_get_bypath(index
, "src/common.h", 0));
1049 cl_assert_equal_p(NULL
, e
= git_index_get_bypath(index
, "SRC/Common.h", 0));
1050 cl_assert(e
= git_index_get_bypath(index
, "COPYING", 0));
1051 cl_assert_equal_p(NULL
, e
= git_index_get_bypath(index
, "copying", 0));
1053 cl_git_pass(git_index_set_caps(index
, caps
| GIT_INDEX_CAPABILITY_IGNORE_CASE
));
1054 cl_assert_equal_i(true, index
->ignore_case
);
1055 cl_git_pass(git_vector_verify_sorted(&index
->entries
));
1056 cl_assert(e
= git_index_get_bypath(index
, "COPYING", 0));
1057 cl_assert_equal_s("COPYING", e
->path
);
1058 cl_assert(e
= git_index_get_bypath(index
, "copying", 0));
1059 cl_assert_equal_s("COPYING", e
->path
);
1061 git_index_free(index
);
1064 void test_index_tests__can_lock_index(void)
1066 git_repository
*repo
;
1068 git_indexwriter one
= GIT_INDEXWRITER_INIT
,
1069 two
= GIT_INDEXWRITER_INIT
;
1071 repo
= cl_git_sandbox_init("testrepo.git");
1073 cl_git_pass(git_repository_index(&index
, repo
));
1074 cl_git_pass(git_indexwriter_init(&one
, index
));
1076 cl_git_fail_with(GIT_ELOCKED
, git_indexwriter_init(&two
, index
));
1077 cl_git_fail_with(GIT_ELOCKED
, git_index_write(index
));
1079 cl_git_pass(git_indexwriter_commit(&one
));
1081 cl_git_pass(git_index_write(index
));
1083 git_indexwriter_cleanup(&one
);
1084 git_indexwriter_cleanup(&two
);
1085 git_index_free(index
);
1086 cl_git_sandbox_cleanup();
1089 void test_index_tests__can_iterate(void)
1092 git_index_iterator
*iterator
;
1093 const git_index_entry
*entry
;
1094 size_t i
, iterator_idx
= 0, found
= 0;
1097 cl_git_pass(git_index_open(&index
, TEST_INDEX_PATH
));
1098 cl_git_pass(git_index_iterator_new(&iterator
, index
));
1100 cl_assert(git_vector_is_sorted(&iterator
->snap
));
1102 for (i
= 0; i
< ARRAY_SIZE(test_entries
); i
++) {
1103 /* Advance iterator to next test entry index */
1105 ret
= git_index_iterator_next(&entry
, iterator
);
1107 if (ret
== GIT_ITEROVER
)
1108 cl_fail("iterator did not contain all test entries");
1111 } while (iterator_idx
++ < test_entries
[i
].index
);
1113 cl_assert_equal_s(entry
->path
, test_entries
[i
].path
);
1114 cl_assert_equal_i(entry
->mtime
.seconds
, test_entries
[i
].mtime
);
1115 cl_assert_equal_i(entry
->file_size
, test_entries
[i
].file_size
);
1119 while ((ret
= git_index_iterator_next(&entry
, iterator
)) == 0)
1122 if (ret
!= GIT_ITEROVER
)
1125 cl_assert_equal_i(found
, ARRAY_SIZE(test_entries
));
1127 git_index_iterator_free(iterator
);
1128 git_index_free(index
);
1131 void test_index_tests__can_modify_while_iterating(void)
1134 git_index_iterator
*iterator
;
1135 const git_index_entry
*entry
;
1136 git_index_entry new_entry
= {{0}};
1137 size_t expected
= 0, seen
= 0;
1140 cl_git_pass(git_index_open(&index
, TEST_INDEX_PATH
));
1141 cl_git_pass(git_index_iterator_new(&iterator
, index
));
1143 expected
= git_index_entrycount(index
);
1144 cl_assert(git_vector_is_sorted(&iterator
->snap
));
1147 * After we've counted the entries, add a new one and change another;
1148 * ensure that our iterator is backed by a snapshot and thus returns
1149 * the number of entries from when the iterator was created.
1151 cl_git_pass(git_oid_fromstr(&new_entry
.id
, "8312e0a89a9cbab77c732b6bc39b51a783e3a318"));
1152 new_entry
.path
= "newfile";
1153 new_entry
.mode
= GIT_FILEMODE_BLOB
;
1154 cl_git_pass(git_index_add(index
, &new_entry
));
1156 cl_git_pass(git_oid_fromstr(&new_entry
.id
, "4141414141414141414141414141414141414141"));
1157 new_entry
.path
= "Makefile";
1158 new_entry
.mode
= GIT_FILEMODE_BLOB
;
1159 cl_git_pass(git_index_add(index
, &new_entry
));
1162 ret
= git_index_iterator_next(&entry
, iterator
);
1164 if (ret
== GIT_ITEROVER
)
1170 cl_assert_equal_i(expected
, seen
);
1172 git_index_iterator_free(iterator
);
1173 git_index_free(index
);