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_frombuffer(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_frombuffer(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_frombuffer(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_frombuffer(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_frombuffer(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_frombuffer(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 add_invalid_filename(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__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 add_invalid_filename(repo
, ".git/hello");
581 add_invalid_filename(repo
, ".GIT/hello");
582 add_invalid_filename(repo
, ".GiT/hello");
583 add_invalid_filename(repo
, "./.git/hello");
584 add_invalid_filename(repo
, "./foo");
585 add_invalid_filename(repo
, "./bar");
586 add_invalid_filename(repo
, "subdir/../bar");
588 git_repository_free(repo
);
590 cl_fixture_cleanup("invalid");
593 static void replace_char(char *str
, char in
, char out
)
602 static void write_invalid_filename(git_repository
*repo
, const char *fn_orig
)
606 const git_index_entry
*entry
;
607 git_buf path
= GIT_BUF_INIT
;
610 cl_git_pass(git_repository_index(&index
, repo
));
611 cl_assert(git_index_entrycount(index
) == 0);
614 * Sneak a valid path into the index, we'll update it
615 * to an invalid path when we try to write the index.
617 fn
= git__strdup(fn_orig
);
618 replace_char(fn
, '/', '_');
620 git_buf_joinpath(&path
, "./invalid", fn
);
622 cl_git_mkfile(path
.ptr
, NULL
);
624 cl_git_pass(git_index_add_bypath(index
, fn
));
626 cl_assert(entry
= git_index_get_bypath(index
, fn
, 0));
628 /* kids, don't try this at home */
629 replace_char((char *)entry
->path
, '_', '/');
632 cl_git_fail(git_index_write_tree(&expected
, index
));
636 cl_git_pass(git_index_remove_all(index
, NULL
, NULL
, NULL
));
637 git_buf_dispose(&path
);
638 git_index_free(index
);
642 void test_index_tests__write_tree_invalid_unowned_index(void)
645 git_repository
*repo
;
646 git_index_entry entry
= {{0}};
649 cl_git_pass(git_index_new(&idx
));
651 cl_git_pass(git_oid_fromstr(&entry
.id
, "8312e0a89a9cbab77c732b6bc39b51a783e3a318"));
653 entry
.mode
= GIT_FILEMODE_BLOB
;
654 cl_git_pass(git_index_add(idx
, &entry
));
656 cl_git_pass(git_repository_init(&repo
, "./invalid-id", 0));
658 cl_git_fail(git_index_write_tree_to(&tree_id
, idx
, repo
));
661 git_repository_free(repo
);
663 cl_fixture_cleanup("invalid-id");
666 /* Test that writing an invalid filename fails */
667 void test_index_tests__write_invalid_filename(void)
669 git_repository
*repo
;
671 p_mkdir("invalid", 0700);
673 cl_git_pass(git_repository_init(&repo
, "./invalid", 0));
675 write_invalid_filename(repo
, ".git/hello");
676 write_invalid_filename(repo
, ".GIT/hello");
677 write_invalid_filename(repo
, ".GiT/hello");
678 write_invalid_filename(repo
, "./.git/hello");
679 write_invalid_filename(repo
, "./foo");
680 write_invalid_filename(repo
, "./bar");
681 write_invalid_filename(repo
, "foo/../bar");
683 git_repository_free(repo
);
685 cl_fixture_cleanup("invalid");
688 void test_index_tests__honors_protect_filesystems(void)
690 git_repository
*repo
;
692 p_mkdir("invalid", 0700);
694 cl_git_pass(git_repository_init(&repo
, "./invalid", 0));
696 cl_repo_set_bool(repo
, "core.protectHFS", true);
697 cl_repo_set_bool(repo
, "core.protectNTFS", true);
699 write_invalid_filename(repo
, ".git./hello");
700 write_invalid_filename(repo
, ".git\xe2\x80\xad/hello");
701 write_invalid_filename(repo
, "git~1/hello");
702 write_invalid_filename(repo
, ".git\xe2\x81\xaf/hello");
704 git_repository_free(repo
);
706 cl_fixture_cleanup("invalid");
709 void test_index_tests__remove_entry(void)
711 git_repository
*repo
;
714 p_mkdir("index_test", 0770);
716 cl_git_pass(git_repository_init(&repo
, "index_test", 0));
717 cl_git_pass(git_repository_index(&index
, repo
));
718 cl_assert(git_index_entrycount(index
) == 0);
720 cl_git_mkfile("index_test/hello", NULL
);
721 cl_git_pass(git_index_add_bypath(index
, "hello"));
722 cl_git_pass(git_index_write(index
));
724 cl_git_pass(git_index_read(index
, true)); /* reload */
725 cl_assert(git_index_entrycount(index
) == 1);
726 cl_assert(git_index_get_bypath(index
, "hello", 0) != NULL
);
728 cl_git_pass(git_index_remove(index
, "hello", 0));
729 cl_git_pass(git_index_write(index
));
731 cl_git_pass(git_index_read(index
, true)); /* reload */
732 cl_assert(git_index_entrycount(index
) == 0);
733 cl_assert(git_index_get_bypath(index
, "hello", 0) == NULL
);
735 git_index_free(index
);
736 git_repository_free(repo
);
737 cl_fixture_cleanup("index_test");
740 void test_index_tests__remove_directory(void)
742 git_repository
*repo
;
745 p_mkdir("index_test", 0770);
747 cl_git_pass(git_repository_init(&repo
, "index_test", 0));
748 cl_git_pass(git_repository_index(&index
, repo
));
749 cl_assert_equal_i(0, (int)git_index_entrycount(index
));
751 p_mkdir("index_test/a", 0770);
752 cl_git_mkfile("index_test/a/1.txt", NULL
);
753 cl_git_mkfile("index_test/a/2.txt", NULL
);
754 cl_git_mkfile("index_test/a/3.txt", NULL
);
755 cl_git_mkfile("index_test/b.txt", NULL
);
757 cl_git_pass(git_index_add_bypath(index
, "a/1.txt"));
758 cl_git_pass(git_index_add_bypath(index
, "a/2.txt"));
759 cl_git_pass(git_index_add_bypath(index
, "a/3.txt"));
760 cl_git_pass(git_index_add_bypath(index
, "b.txt"));
761 cl_git_pass(git_index_write(index
));
763 cl_git_pass(git_index_read(index
, true)); /* reload */
764 cl_assert_equal_i(4, (int)git_index_entrycount(index
));
765 cl_assert(git_index_get_bypath(index
, "a/1.txt", 0) != NULL
);
766 cl_assert(git_index_get_bypath(index
, "a/2.txt", 0) != NULL
);
767 cl_assert(git_index_get_bypath(index
, "b.txt", 0) != NULL
);
769 cl_git_pass(git_index_remove(index
, "a/1.txt", 0));
770 cl_git_pass(git_index_write(index
));
772 cl_git_pass(git_index_read(index
, true)); /* reload */
773 cl_assert_equal_i(3, (int)git_index_entrycount(index
));
774 cl_assert(git_index_get_bypath(index
, "a/1.txt", 0) == NULL
);
775 cl_assert(git_index_get_bypath(index
, "a/2.txt", 0) != NULL
);
776 cl_assert(git_index_get_bypath(index
, "b.txt", 0) != NULL
);
778 cl_git_pass(git_index_remove_directory(index
, "a", 0));
779 cl_git_pass(git_index_write(index
));
781 cl_git_pass(git_index_read(index
, true)); /* reload */
782 cl_assert_equal_i(1, (int)git_index_entrycount(index
));
783 cl_assert(git_index_get_bypath(index
, "a/1.txt", 0) == NULL
);
784 cl_assert(git_index_get_bypath(index
, "a/2.txt", 0) == NULL
);
785 cl_assert(git_index_get_bypath(index
, "b.txt", 0) != NULL
);
787 git_index_free(index
);
788 git_repository_free(repo
);
789 cl_fixture_cleanup("index_test");
792 void test_index_tests__preserves_case(void)
794 git_repository
*repo
;
796 const git_index_entry
*entry
;
799 cl_set_cleanup(&cleanup_myrepo
, NULL
);
801 cl_git_pass(git_repository_init(&repo
, "./myrepo", 0));
802 cl_git_pass(git_repository_index(&index
, repo
));
804 index_caps
= git_index_caps(index
);
806 cl_git_rewritefile("myrepo/test.txt", "hey there\n");
807 cl_git_pass(git_index_add_bypath(index
, "test.txt"));
809 cl_git_pass(p_rename("myrepo/test.txt", "myrepo/TEST.txt"));
810 cl_git_rewritefile("myrepo/TEST.txt", "hello again\n");
811 cl_git_pass(git_index_add_bypath(index
, "TEST.txt"));
813 if (index_caps
& GIT_INDEX_CAPABILITY_IGNORE_CASE
)
814 cl_assert_equal_i(1, (int)git_index_entrycount(index
));
816 cl_assert_equal_i(2, (int)git_index_entrycount(index
));
818 /* Test access by path instead of index */
819 cl_assert((entry
= git_index_get_bypath(index
, "test.txt", 0)) != NULL
);
820 /* The path should *not* have changed without an explicit remove */
821 cl_assert(git__strcmp(entry
->path
, "test.txt") == 0);
823 cl_assert((entry
= git_index_get_bypath(index
, "TEST.txt", 0)) != NULL
);
824 if (index_caps
& GIT_INDEX_CAPABILITY_IGNORE_CASE
)
825 /* The path should *not* have changed without an explicit remove */
826 cl_assert(git__strcmp(entry
->path
, "test.txt") == 0);
828 cl_assert(git__strcmp(entry
->path
, "TEST.txt") == 0);
830 git_index_free(index
);
831 git_repository_free(repo
);
834 void test_index_tests__elocked(void)
836 git_repository
*repo
;
838 git_filebuf file
= GIT_FILEBUF_INIT
;
839 const git_error
*err
;
842 cl_set_cleanup(&cleanup_myrepo
, NULL
);
844 cl_git_pass(git_repository_init(&repo
, "./myrepo", 0));
845 cl_git_pass(git_repository_index(&index
, repo
));
847 /* Lock the index file so we fail to lock it */
848 cl_git_pass(git_filebuf_open(&file
, index
->index_file_path
, 0, 0666));
849 error
= git_index_write(index
);
850 cl_assert_equal_i(GIT_ELOCKED
, error
);
852 err
= git_error_last();
853 cl_assert_equal_i(err
->klass
, GIT_ERROR_INDEX
);
855 git_filebuf_cleanup(&file
);
856 git_index_free(index
);
857 git_repository_free(repo
);
860 void test_index_tests__reload_from_disk(void)
862 git_repository
*repo
;
863 git_index
*read_index
;
864 git_index
*write_index
;
866 cl_set_cleanup(&cleanup_myrepo
, NULL
);
868 cl_git_pass(git_futils_mkdir("./myrepo", 0777, GIT_MKDIR_PATH
));
869 cl_git_mkfile("./myrepo/a.txt", "a\n");
870 cl_git_mkfile("./myrepo/b.txt", "b\n");
872 cl_git_pass(git_repository_init(&repo
, "./myrepo", 0));
873 cl_git_pass(git_repository_index(&write_index
, repo
));
874 cl_assert_equal_i(false, write_index
->on_disk
);
876 cl_git_pass(git_index_open(&read_index
, write_index
->index_file_path
));
877 cl_assert_equal_i(false, read_index
->on_disk
);
879 /* Stage two new files against the write_index */
880 cl_git_pass(git_index_add_bypath(write_index
, "a.txt"));
881 cl_git_pass(git_index_add_bypath(write_index
, "b.txt"));
883 cl_assert_equal_sz(2, git_index_entrycount(write_index
));
885 /* Persist the index changes to disk */
886 cl_git_pass(git_index_write(write_index
));
887 cl_assert_equal_i(true, write_index
->on_disk
);
889 /* Sync the changes back into the read_index */
890 cl_assert_equal_sz(0, git_index_entrycount(read_index
));
892 cl_git_pass(git_index_read(read_index
, true));
893 cl_assert_equal_i(true, read_index
->on_disk
);
895 cl_assert_equal_sz(2, git_index_entrycount(read_index
));
897 /* Remove the index file from the filesystem */
898 cl_git_pass(p_unlink(write_index
->index_file_path
));
900 /* Sync the changes back into the read_index */
901 cl_git_pass(git_index_read(read_index
, true));
902 cl_assert_equal_i(false, read_index
->on_disk
);
903 cl_assert_equal_sz(0, git_index_entrycount(read_index
));
905 git_index_free(read_index
);
906 git_index_free(write_index
);
907 git_repository_free(repo
);
910 void test_index_tests__corrupted_extension(void)
914 cl_git_fail_with(git_index_open(&index
, TEST_INDEXBAD_PATH
), GIT_ERROR
);
917 void test_index_tests__reload_while_ignoring_case(void)
922 cl_git_pass(git_index_open(&index
, TEST_INDEX_PATH
));
923 cl_git_pass(git_vector_verify_sorted(&index
->entries
));
925 caps
= git_index_caps(index
);
926 cl_git_pass(git_index_set_caps(index
, caps
&= ~GIT_INDEX_CAPABILITY_IGNORE_CASE
));
927 cl_git_pass(git_index_read(index
, true));
928 cl_git_pass(git_vector_verify_sorted(&index
->entries
));
929 cl_assert(git_index_get_bypath(index
, ".HEADER", 0));
930 cl_assert_equal_p(NULL
, git_index_get_bypath(index
, ".header", 0));
932 cl_git_pass(git_index_set_caps(index
, caps
| GIT_INDEX_CAPABILITY_IGNORE_CASE
));
933 cl_git_pass(git_index_read(index
, true));
934 cl_git_pass(git_vector_verify_sorted(&index
->entries
));
935 cl_assert(git_index_get_bypath(index
, ".HEADER", 0));
936 cl_assert(git_index_get_bypath(index
, ".header", 0));
938 git_index_free(index
);
941 void test_index_tests__change_icase_on_instance(void)
945 const git_index_entry
*e
;
947 cl_git_pass(git_index_open(&index
, TEST_INDEX_PATH
));
948 cl_git_pass(git_vector_verify_sorted(&index
->entries
));
950 caps
= git_index_caps(index
);
951 cl_git_pass(git_index_set_caps(index
, caps
&= ~GIT_INDEX_CAPABILITY_IGNORE_CASE
));
952 cl_assert_equal_i(false, index
->ignore_case
);
953 cl_git_pass(git_vector_verify_sorted(&index
->entries
));
954 cl_assert(e
= git_index_get_bypath(index
, "src/common.h", 0));
955 cl_assert_equal_p(NULL
, e
= git_index_get_bypath(index
, "SRC/Common.h", 0));
956 cl_assert(e
= git_index_get_bypath(index
, "COPYING", 0));
957 cl_assert_equal_p(NULL
, e
= git_index_get_bypath(index
, "copying", 0));
959 cl_git_pass(git_index_set_caps(index
, caps
| GIT_INDEX_CAPABILITY_IGNORE_CASE
));
960 cl_assert_equal_i(true, index
->ignore_case
);
961 cl_git_pass(git_vector_verify_sorted(&index
->entries
));
962 cl_assert(e
= git_index_get_bypath(index
, "COPYING", 0));
963 cl_assert_equal_s("COPYING", e
->path
);
964 cl_assert(e
= git_index_get_bypath(index
, "copying", 0));
965 cl_assert_equal_s("COPYING", e
->path
);
967 git_index_free(index
);
970 void test_index_tests__can_lock_index(void)
972 git_repository
*repo
;
974 git_indexwriter one
= GIT_INDEXWRITER_INIT
,
975 two
= GIT_INDEXWRITER_INIT
;
977 repo
= cl_git_sandbox_init("testrepo.git");
979 cl_git_pass(git_repository_index(&index
, repo
));
980 cl_git_pass(git_indexwriter_init(&one
, index
));
982 cl_git_fail_with(GIT_ELOCKED
, git_indexwriter_init(&two
, index
));
983 cl_git_fail_with(GIT_ELOCKED
, git_index_write(index
));
985 cl_git_pass(git_indexwriter_commit(&one
));
987 cl_git_pass(git_index_write(index
));
989 git_indexwriter_cleanup(&one
);
990 git_indexwriter_cleanup(&two
);
991 git_index_free(index
);
992 cl_git_sandbox_cleanup();
995 void test_index_tests__can_iterate(void)
998 git_index_iterator
*iterator
;
999 const git_index_entry
*entry
;
1000 size_t i
, iterator_idx
= 0, found
= 0;
1003 cl_git_pass(git_index_open(&index
, TEST_INDEX_PATH
));
1004 cl_git_pass(git_index_iterator_new(&iterator
, index
));
1006 cl_assert(git_vector_is_sorted(&iterator
->snap
));
1008 for (i
= 0; i
< ARRAY_SIZE(test_entries
); i
++) {
1009 /* Advance iterator to next test entry index */
1011 ret
= git_index_iterator_next(&entry
, iterator
);
1013 if (ret
== GIT_ITEROVER
)
1014 cl_fail("iterator did not contain all test entries");
1017 } while (iterator_idx
++ < test_entries
[i
].index
);
1019 cl_assert_equal_s(entry
->path
, test_entries
[i
].path
);
1020 cl_assert_equal_i(entry
->mtime
.seconds
, test_entries
[i
].mtime
);
1021 cl_assert_equal_i(entry
->file_size
, test_entries
[i
].file_size
);
1025 while ((ret
= git_index_iterator_next(&entry
, iterator
)) == 0)
1028 if (ret
!= GIT_ITEROVER
)
1031 cl_assert_equal_i(found
, ARRAY_SIZE(test_entries
));
1033 git_index_iterator_free(iterator
);
1034 git_index_free(index
);
1037 void test_index_tests__can_modify_while_iterating(void)
1040 git_index_iterator
*iterator
;
1041 const git_index_entry
*entry
;
1042 git_index_entry new_entry
= {{0}};
1043 size_t expected
= 0, seen
= 0;
1046 cl_git_pass(git_index_open(&index
, TEST_INDEX_PATH
));
1047 cl_git_pass(git_index_iterator_new(&iterator
, index
));
1049 expected
= git_index_entrycount(index
);
1050 cl_assert(git_vector_is_sorted(&iterator
->snap
));
1053 * After we've counted the entries, add a new one and change another;
1054 * ensure that our iterator is backed by a snapshot and thus returns
1055 * the number of entries from when the iterator was created.
1057 cl_git_pass(git_oid_fromstr(&new_entry
.id
, "8312e0a89a9cbab77c732b6bc39b51a783e3a318"));
1058 new_entry
.path
= "newfile";
1059 new_entry
.mode
= GIT_FILEMODE_BLOB
;
1060 cl_git_pass(git_index_add(index
, &new_entry
));
1062 cl_git_pass(git_oid_fromstr(&new_entry
.id
, "4141414141414141414141414141414141414141"));
1063 new_entry
.path
= "Makefile";
1064 new_entry
.mode
= GIT_FILEMODE_BLOB
;
1065 cl_git_pass(git_index_add(index
, &new_entry
));
1068 ret
= git_index_iterator_next(&entry
, iterator
);
1070 if (ret
== GIT_ITEROVER
)
1076 cl_assert_equal_i(expected
, seen
);
1078 git_index_iterator_free(iterator
);
1079 git_index_free(index
);