]> git.proxmox.com Git - libgit2.git/blame - tests/index/tests.c
New upstream version 1.4.3+dfsg.1
[libgit2.git] / tests / index / tests.c
CommitLineData
6c106eec
BS
1#include "clar_libgit2.h"
2#include "index.h"
3
a8122b5d
RB
4static const size_t index_entry_count = 109;
5static const size_t index_entry_count_2 = 1437;
6c106eec
BS
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")
3d523345 9#define TEST_INDEXBAD_PATH cl_fixture("bad.index")
6c106eec
BS
10
11
8e5a8ef8 12/* Suite data */
6c106eec 13struct test_entry {
11d9f6b3 14 size_t index;
6c106eec 15 char path[128];
22a2d3d5 16 off64_t file_size;
6c106eec
BS
17 git_time_t mtime;
18};
19
b482c420 20static struct test_entry test_entries[] = {
6c106eec 21 {4, "Makefile", 5064, 0x4C3F7F33},
6c106eec 22 {6, "git.git-authors", 2709, 0x4C3F7F33},
ac3d33df
JK
23 {36, "src/index.c", 10014, 0x4C43368D},
24 {48, "src/revobject.h", 1448, 0x4C3F7FE2},
25 {62, "tests/Makefile", 2631, 0x4C3F7F33}
6c106eec
BS
26};
27
8e5a8ef8 28/* Helpers */
270303ca 29static void copy_file(const char *src, const char *dst)
6c106eec 30{
e579e0f7 31 git_str source_buf = GIT_STR_INIT;
6c106eec 32 git_file dst_fd;
6c106eec 33
270303ca 34 cl_git_pass(git_futils_readbuffer(&source_buf, src));
6c106eec 35
8e5a8ef8 36 dst_fd = git_futils_creat_withpath(dst, 0777, 0666); /* -V536 */
6c106eec
BS
37 if (dst_fd < 0)
38 goto cleanup;
39
270303ca 40 cl_git_pass(p_write(dst_fd, source_buf.ptr, source_buf.size));
6c106eec
BS
41
42cleanup:
e579e0f7 43 git_str_dispose(&source_buf);
6c106eec 44 p_close(dst_fd);
6c106eec
BS
45}
46
270303ca 47static void files_are_equal(const char *a, const char *b)
6c106eec 48{
e579e0f7
MB
49 git_str buf_a = GIT_STR_INIT;
50 git_str buf_b = GIT_STR_INIT;
270303ca 51 int pass;
6c106eec 52
e172cf08 53 if (git_futils_readbuffer(&buf_a, a) < 0)
270303ca 54 cl_assert(0);
6c106eec 55
e172cf08 56 if (git_futils_readbuffer(&buf_b, b) < 0) {
e579e0f7 57 git_str_dispose(&buf_a);
270303ca 58 cl_assert(0);
6c106eec
BS
59 }
60
270303ca 61 pass = (buf_a.size == buf_b.size && !memcmp(buf_a.ptr, buf_b.ptr, buf_a.size));
6c106eec 62
e579e0f7
MB
63 git_str_dispose(&buf_a);
64 git_str_dispose(&buf_b);
13ed2966
MS
65
66 cl_assert(pass);
6c106eec
BS
67}
68
69
8e5a8ef8 70/* Fixture setup and teardown */
6c106eec
BS
71void test_index_tests__initialize(void)
72{
73}
74
ac3d33df
JK
75void test_index_tests__cleanup(void)
76{
77 cl_git_pass(git_libgit2_opts(GIT_OPT_ENABLE_UNSAVED_INDEX_SAFETY, 0));
78}
79
6c106eec
BS
80void test_index_tests__empty_index(void)
81{
82 git_index *index;
83
84 cl_git_pass(git_index_open(&index, "in-memory-index"));
85 cl_assert(index->on_disk == 0);
86
87 cl_assert(git_index_entrycount(index) == 0);
882c7742 88 cl_assert(git_vector_is_sorted(&index->entries));
6c106eec
BS
89
90 git_index_free(index);
91}
92
93void test_index_tests__default_test_index(void)
94{
95 git_index *index;
96 unsigned int i;
97 git_index_entry **entries;
98
99 cl_git_pass(git_index_open(&index, TEST_INDEX_PATH));
100 cl_assert(index->on_disk);
101
a8122b5d 102 cl_assert(git_index_entrycount(index) == index_entry_count);
882c7742 103 cl_assert(git_vector_is_sorted(&index->entries));
6c106eec
BS
104
105 entries = (git_index_entry **)index->entries.contents;
106
b482c420 107 for (i = 0; i < ARRAY_SIZE(test_entries); ++i) {
34b8eafc 108 git_index_entry *e = entries[test_entries[i].index];
6c106eec 109
34b8eafc 110 cl_assert_equal_s(e->path, test_entries[i].path);
46c84c72
CMN
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);
6c106eec
BS
113 }
114
115 git_index_free(index);
116}
117
118void test_index_tests__gitgit_index(void)
119{
120 git_index *index;
121
122 cl_git_pass(git_index_open(&index, TEST_INDEX2_PATH));
123 cl_assert(index->on_disk);
124
a8122b5d 125 cl_assert(git_index_entrycount(index) == index_entry_count_2);
882c7742 126 cl_assert(git_vector_is_sorted(&index->entries));
6c106eec
BS
127 cl_assert(index->tree != NULL);
128
129 git_index_free(index);
130}
131
132void test_index_tests__find_in_existing(void)
133{
134 git_index *index;
135 unsigned int i;
136
137 cl_git_pass(git_index_open(&index, TEST_INDEX_PATH));
138
b482c420 139 for (i = 0; i < ARRAY_SIZE(test_entries); ++i) {
34b8eafc 140 size_t idx;
11d9f6b3 141
34b8eafc 142 cl_assert(!git_index_find(&idx, index, test_entries[i].path));
143 cl_assert(idx == test_entries[i].index);
6c106eec
BS
144 }
145
146 git_index_free(index);
147}
148
149void test_index_tests__find_in_empty(void)
150{
151 git_index *index;
152 unsigned int i;
153
154 cl_git_pass(git_index_open(&index, "fake-index"));
155
b482c420 156 for (i = 0; i < ARRAY_SIZE(test_entries); ++i) {
34b8eafc 157 cl_assert(GIT_ENOTFOUND == git_index_find(NULL, index, test_entries[i].path));
6c106eec
BS
158 }
159
160 git_index_free(index);
161}
162
c097f717
LY
163void test_index_tests__find_prefix(void)
164{
165 git_index *index;
166 const git_index_entry *entry;
167 size_t pos;
168
169 cl_git_pass(git_index_open(&index, TEST_INDEX_PATH));
170
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);
174
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);
178
179 cl_assert(GIT_ENOTFOUND == git_index_find_prefix(NULL, index, "blah"));
180
181 git_index_free(index);
182}
183
6c106eec
BS
184void test_index_tests__write(void)
185{
186 git_index *index;
187
270303ca 188 copy_file(TEST_INDEXBIG_PATH, "index_rewrite");
6c106eec
BS
189
190 cl_git_pass(git_index_open(&index, "index_rewrite"));
191 cl_assert(index->on_disk);
192
193 cl_git_pass(git_index_write(index));
270303ca 194 files_are_equal(TEST_INDEXBIG_PATH, "index_rewrite");
6c106eec
BS
195
196 git_index_free(index);
197
198 p_unlink("index_rewrite");
199}
200
201void test_index_tests__sort0(void)
202{
e579e0f7 203 /* sort the entries in an index */
8e5a8ef8 204
6c106eec
BS
205 /*
206 * TODO: This no longer applies:
207 * index sorting in Git uses some specific changes to the way
208 * directories are sorted.
209 *
e579e0f7 210 * We need to specifically check for this by creating a new
6c106eec
BS
211 * index, adding entries in random order and then
212 * checking for consistency
213 */
214}
215
216void test_index_tests__sort1(void)
217{
e579e0f7 218 /* sort the entries in an empty index */
6c106eec
BS
219 git_index *index;
220
221 cl_git_pass(git_index_open(&index, "fake-index"));
222
223 /* FIXME: this test is slightly dumb */
882c7742 224 cl_assert(git_vector_is_sorted(&index->entries));
6c106eec
BS
225
226 git_index_free(index);
227}
228
f6fded8f
VM
229static void cleanup_myrepo(void *opaque)
230{
231 GIT_UNUSED(opaque);
232 cl_fixture_cleanup("myrepo");
233}
234
6c106eec
BS
235void test_index_tests__add(void)
236{
f6fded8f
VM
237 git_index *index;
238 git_filebuf file = GIT_FILEBUF_INIT;
239 git_repository *repo;
240 const git_index_entry *entry;
241 git_oid id1;
6c106eec 242
f6fded8f 243 cl_set_cleanup(&cleanup_myrepo, NULL);
6c106eec 244
e579e0f7 245 /* Initialize a new repository */
f6fded8f 246 cl_git_pass(git_repository_init(&repo, "./myrepo", 0));
6c106eec 247
f6fded8f
VM
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);
6c106eec 251
f6fded8f
VM
252 /* Create a new file in the working directory */
253 cl_git_pass(git_futils_mkpath2file("myrepo/test.txt", 0777));
1d3a8aeb 254 cl_git_pass(git_filebuf_open(&file, "myrepo/test.txt", 0, 0666));
f6fded8f 255 cl_git_pass(git_filebuf_write(&file, "hey there\n", 10));
1d3a8aeb 256 cl_git_pass(git_filebuf_commit(&file));
6c106eec 257
f6fded8f
VM
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
261 */
262 cl_git_pass(git_oid_fromstr(&id1, "a8233120f6ad708f843d861ce2b7228ec4e3dec6"));
6c106eec 263
f6fded8f 264 /* Add the new file to the index */
25743bd7 265 cl_git_pass(git_index_add_bypath(index, "test.txt"));
6c106eec 266
f6fded8f
VM
267 /* Wow... it worked! */
268 cl_assert(git_index_entrycount(index) == 1);
269 entry = git_index_get_byindex(index, 0);
6c106eec 270
f6fded8f 271 /* And the built-in hashing mechanism worked as expected */
0cee70eb 272 cl_assert_equal_oid(&id1, &entry->id);
f45ec1a0 273
f6fded8f
VM
274 /* Test access by path instead of index */
275 cl_assert((entry = git_index_get_bypath(index, "test.txt", 0)) != NULL);
0cee70eb 276 cl_assert_equal_oid(&id1, &entry->id);
f6fded8f
VM
277
278 git_index_free(index);
279 git_repository_free(repo);
6c106eec
BS
280}
281
a275fbc0
DP
282void test_index_tests__add_frombuffer(void)
283{
284 git_index *index;
285 git_repository *repo;
286 git_index_entry entry;
287 const git_index_entry *returned_entry;
288
289 git_oid id1;
290 git_blob *blob;
291
292 const char *content = "hey there\n";
293
294 cl_set_cleanup(&cleanup_myrepo, NULL);
295
e579e0f7 296 /* Initialize a new repository */
a275fbc0
DP
297 cl_git_pass(git_repository_init(&repo, "./myrepo", 0));
298
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);
302
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
306 */
307 cl_git_pass(git_oid_fromstr(&id1, "a8233120f6ad708f843d861ce2b7228ec4e3dec6"));
308
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";
22a2d3d5 313 cl_git_pass(git_index_add_from_buffer(index, &entry,
a275fbc0
DP
314 content, strlen(content)));
315
316 /* Wow... it worked! */
317 cl_assert(git_index_entrycount(index) == 1);
318 returned_entry = git_index_get_byindex(index, 0);
319
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);
324
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);
328
329 /* Test the blob is in the repository */
330 cl_git_pass(git_blob_lookup(&blob, repo, &id1));
331 cl_assert_equal_s(
332 content, git_blob_rawcontent(blob));
333 git_blob_free(blob);
334
335 git_index_free(index);
336 git_repository_free(repo);
337}
338
ac3d33df
JK
339void test_index_tests__dirty_and_clean(void)
340{
341 git_repository *repo;
342 git_index *index;
343 git_index_entry entry = {{0}};
344
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));
348
349 cl_assert(git_index_entrycount(index) == 0);
350 cl_assert(!git_index_is_dirty(index));
351
352 /* Index is dirty after adding an entry */
353 entry.mode = GIT_FILEMODE_BLOB;
354 entry.path = "test.txt";
22a2d3d5 355 cl_git_pass(git_index_add_from_buffer(index, &entry, "Hi.\n", 4));
ac3d33df
JK
356 cl_assert(git_index_entrycount(index) == 1);
357 cl_assert(git_index_is_dirty(index));
358
359 /* Index is not dirty after write */
360 cl_git_pass(git_index_write(index));
361 cl_assert(!git_index_is_dirty(index));
362
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));
367
368 /* Index is not dirty after write */
369 cl_git_pass(git_index_write(index));
370 cl_assert(!git_index_is_dirty(index));
371
372 /* Index remains not dirty after read */
373 cl_git_pass(git_index_read(index, 0));
374 cl_assert(!git_index_is_dirty(index));
375
376 /* Index is dirty when we do an unforced read with dirty content */
22a2d3d5 377 cl_git_pass(git_index_add_from_buffer(index, &entry, "Hi.\n", 4));
ac3d33df
JK
378 cl_assert(git_index_entrycount(index) == 1);
379 cl_assert(git_index_is_dirty(index));
380
381 cl_git_pass(git_index_read(index, 0));
382 cl_assert(git_index_is_dirty(index));
383
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));
387
388 git_index_free(index);
389 git_repository_free(repo);
390}
391
392void test_index_tests__dirty_fails_optionally(void)
393{
394 git_repository *repo;
395 git_index *index;
396 git_index_entry entry = {{0}};
397
398 /* Index is not dirty after opening */
399 repo = cl_git_sandbox_init("testrepo");
400 cl_git_pass(git_repository_index(&index, repo));
401
402 /* Index is dirty after adding an entry */
403 entry.mode = GIT_FILEMODE_BLOB;
404 entry.path = "test.txt";
22a2d3d5 405 cl_git_pass(git_index_add_from_buffer(index, &entry, "Hi.\n", 4));
ac3d33df
JK
406 cl_assert(git_index_is_dirty(index));
407
408 cl_git_pass(git_checkout_head(repo, NULL));
409
410 /* Index is dirty (again) after adding an entry */
411 entry.mode = GIT_FILEMODE_BLOB;
412 entry.path = "test.txt";
22a2d3d5 413 cl_git_pass(git_index_add_from_buffer(index, &entry, "Hi.\n", 4));
ac3d33df
JK
414 cl_assert(git_index_is_dirty(index));
415
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));
418
419 git_index_free(index);
420 cl_git_sandbox_cleanup();
421}
422
a275fbc0
DP
423void test_index_tests__add_frombuffer_reset_entry(void)
424{
425 git_index *index;
426 git_repository *repo;
427 git_index_entry entry;
428 const git_index_entry *returned_entry;
429 git_filebuf file = GIT_FILEBUF_INIT;
430
431 git_oid id1;
432 git_blob *blob;
433 const char *old_content = "here\n";
434 const char *content = "hey there\n";
435
436 cl_set_cleanup(&cleanup_myrepo, NULL);
437
e579e0f7 438 /* Initialize a new repository */
a275fbc0
DP
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));
445
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
449 */
450 cl_git_pass(git_oid_fromstr(&id1, "a8233120f6ad708f843d861ce2b7228ec4e3dec6"));
451
452 cl_git_pass(git_index_add_bypath(index, "test.txt"));
453
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";
22a2d3d5 458 cl_git_pass(git_index_add_from_buffer(index, &entry,
a275fbc0
DP
459 content, strlen(content)));
460
461 /* Wow... it worked! */
462 cl_assert(git_index_entrycount(index) == 1);
463 returned_entry = git_index_get_byindex(index, 0);
464
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);
469
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);
478
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));
482 git_blob_free(blob);
483
484 git_index_free(index);
485 git_repository_free(repo);
486}
487
1098cfae
RB
488static void cleanup_1397(void *opaque)
489{
490 GIT_UNUSED(opaque);
491 cl_git_sandbox_cleanup();
492}
493
b8acb775
SS
494void test_index_tests__add_issue_1397(void)
495{
496 git_index *index;
b8acb775
SS
497 git_repository *repo;
498 const git_index_entry *entry;
499 git_oid id1;
500
1098cfae 501 cl_set_cleanup(&cleanup_1397, NULL);
b8acb775
SS
502
503 repo = cl_git_sandbox_init("issue_1397");
504
1098cfae 505 cl_repo_set_bool(repo, "core.autocrlf", true);
b8acb775
SS
506
507 /* Ensure we're the only guy in the room */
508 cl_git_pass(git_repository_index(&index, repo));
509
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
513 */
514 cl_git_pass(git_oid_fromstr(&id1, "8312e0889a9cbab77c732b6bc39b51a683e3a318"));
515
516 /* Make sure the initial SHA-1 is correct */
517 cl_assert((entry = git_index_get_bypath(index, "crlf_file.txt", 0)) != NULL);
0cee70eb 518 cl_assert_equal_oid(&id1, &entry->id);
b8acb775
SS
519
520 /* Update the index */
521 cl_git_pass(git_index_add_bypath(index, "crlf_file.txt"));
522
523 /* Check the new SHA-1 */
524 cl_assert((entry = git_index_get_bypath(index, "crlf_file.txt", 0)) != NULL);
0cee70eb 525 cl_assert_equal_oid(&id1, &entry->id);
b8acb775
SS
526
527 git_index_free(index);
b8acb775
SS
528}
529
25743bd7 530void test_index_tests__add_bypath_to_a_bare_repository_returns_EBAREPO(void)
33f95a9b 531{
532 git_repository *bare_repo;
533 git_index *index;
534
535 cl_git_pass(git_repository_open(&bare_repo, cl_fixture("testrepo.git")));
536 cl_git_pass(git_repository_index(&index, bare_repo));
537
25743bd7 538 cl_assert_equal_i(GIT_EBAREREPO, git_index_add_bypath(index, "test.txt"));
33f95a9b 539
540 git_index_free(index);
541 git_repository_free(bare_repo);
542}
1876360f 543
b6832cbf 544static void assert_add_bypath_fails(git_repository *repo, const char *fn)
0d388adc
VM
545{
546 git_index *index;
e579e0f7 547 git_str path = GIT_STR_INIT;
0d388adc
VM
548
549 cl_git_pass(git_repository_index(&index, repo));
550 cl_assert(git_index_entrycount(index) == 0);
551
e579e0f7 552 git_str_joinpath(&path, "./invalid", fn);
0d388adc
VM
553
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));
557
558 cl_assert(git_index_entrycount(index) == 0);
559
e579e0f7 560 git_str_dispose(&path);
0d388adc
VM
561 git_index_free(index);
562}
563
1876360f 564/* Test that writing an invalid filename fails */
b6832cbf 565void test_index_tests__cannot_add_invalid_filename(void)
1876360f
SG
566{
567 git_repository *repo;
0d388adc 568
22a2d3d5 569 cl_must_pass(p_mkdir("invalid", 0700));
0d388adc
VM
570 cl_git_pass(git_repository_init(&repo, "./invalid", 0));
571 cl_must_pass(p_mkdir("./invalid/subdir", 0777));
572
c679bf42 573 /* cl_git_mkfile() needs the dir to exist */
e579e0f7 574 if (!git_fs_path_exists("./invalid/.GIT"))
28428318 575 cl_must_pass(p_mkdir("./invalid/.GIT", 0777));
e579e0f7 576 if (!git_fs_path_exists("./invalid/.GiT"))
28428318 577 cl_must_pass(p_mkdir("./invalid/.GiT", 0777));
c679bf42 578
b6832cbf
UG
579 assert_add_bypath_fails(repo, ".git/hello");
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, "./foo");
584 assert_add_bypath_fails(repo, "./bar");
585 assert_add_bypath_fails(repo, "subdir/../bar");
586
587 git_repository_free(repo);
588
589 cl_fixture_cleanup("invalid");
590}
591
592static void assert_add_fails(git_repository *repo, const char *fn)
593{
594 git_index *index;
e579e0f7 595 git_str path = GIT_STR_INIT;
b6832cbf
UG
596 git_index_entry entry = {{0}};
597
598 cl_git_pass(git_repository_index(&index, repo));
599 cl_assert(git_index_entrycount(index) == 0);
600
601 entry.path = fn;
602 entry.mode = GIT_FILEMODE_BLOB;
603 cl_git_pass(git_oid_fromstr(&entry.id, "e69de29bb2d1d6434b8b29ae775ad8c2e48c5391"));
604
605 cl_git_fail(git_index_add(index, &entry));
606
607 cl_assert(git_index_entrycount(index) == 0);
608
e579e0f7 609 git_str_dispose(&path);
b6832cbf
UG
610 git_index_free(index);
611}
612
613/*
614 * Test that writing an invalid filename fails on filesystem
615 * specific protected names
616 */
617void test_index_tests__cannot_add_protected_invalid_filename(void)
618{
619 git_repository *repo;
620 git_index *index;
621
622 cl_must_pass(p_mkdir("invalid", 0700));
623
624 cl_git_pass(git_repository_init(&repo, "./invalid", 0));
625
626 /* add a file to the repository so we can reference it later */
627 cl_git_pass(git_repository_index(&index, repo));
628 cl_git_mkfile("invalid/dummy.txt", "");
629 cl_git_pass(git_index_add_bypath(index, "dummy.txt"));
630 cl_must_pass(p_unlink("invalid/dummy.txt"));
631 cl_git_pass(git_index_remove_bypath(index, "dummy.txt"));
632 git_index_free(index);
633
634 cl_repo_set_bool(repo, "core.protectHFS", true);
635 cl_repo_set_bool(repo, "core.protectNTFS", true);
636
637 assert_add_fails(repo, ".git./hello");
638 assert_add_fails(repo, ".git\xe2\x80\xad/hello");
639 assert_add_fails(repo, "git~1/hello");
640 assert_add_fails(repo, ".git\xe2\x81\xaf/hello");
641 assert_add_fails(repo, ".git::$INDEX_ALLOCATION/dummy-file");
0d388adc
VM
642
643 git_repository_free(repo);
644
645 cl_fixture_cleanup("invalid");
646}
647
648static void replace_char(char *str, char in, char out)
649{
650 char *c = str;
651
652 while (*c++)
653 if (*c == in)
654 *c = out;
655}
656
b6832cbf 657static void assert_write_fails(git_repository *repo, const char *fn_orig)
0d388adc 658{
1876360f
SG
659 git_index *index;
660 git_oid expected;
0d388adc 661 const git_index_entry *entry;
e579e0f7 662 git_str path = GIT_STR_INIT;
0d388adc 663 char *fn;
1876360f 664
1876360f 665 cl_git_pass(git_repository_index(&index, repo));
1876360f
SG
666 cl_assert(git_index_entrycount(index) == 0);
667
0d388adc
VM
668 /*
669 * Sneak a valid path into the index, we'll update it
670 * to an invalid path when we try to write the index.
671 */
672 fn = git__strdup(fn_orig);
673 replace_char(fn, '/', '_');
b6832cbf 674 replace_char(fn, ':', '!');
0d388adc 675
e579e0f7 676 git_str_joinpath(&path, "./invalid", fn);
0d388adc
VM
677
678 cl_git_mkfile(path.ptr, NULL);
679
680 cl_git_pass(git_index_add_bypath(index, fn));
681
682 cl_assert(entry = git_index_get_bypath(index, fn, 0));
1876360f 683
0d388adc
VM
684 /* kids, don't try this at home */
685 replace_char((char *)entry->path, '_', '/');
b6832cbf 686 replace_char((char *)entry->path, '!', ':');
1876360f
SG
687
688 /* write-tree */
689 cl_git_fail(git_index_write_tree(&expected, index));
690
0d388adc
VM
691 p_unlink(path.ptr);
692
693 cl_git_pass(git_index_remove_all(index, NULL, NULL, NULL));
e579e0f7 694 git_str_dispose(&path);
1876360f 695 git_index_free(index);
0d388adc
VM
696 git__free(fn);
697}
698
ac3d33df
JK
699void test_index_tests__write_tree_invalid_unowned_index(void)
700{
701 git_index *idx;
702 git_repository *repo;
703 git_index_entry entry = {{0}};
704 git_oid tree_id;
705
706 cl_git_pass(git_index_new(&idx));
707
708 cl_git_pass(git_oid_fromstr(&entry.id, "8312e0a89a9cbab77c732b6bc39b51a783e3a318"));
709 entry.path = "foo";
710 entry.mode = GIT_FILEMODE_BLOB;
711 cl_git_pass(git_index_add(idx, &entry));
712
713 cl_git_pass(git_repository_init(&repo, "./invalid-id", 0));
714
715 cl_git_fail(git_index_write_tree_to(&tree_id, idx, repo));
716
717 git_index_free(idx);
718 git_repository_free(repo);
719
720 cl_fixture_cleanup("invalid-id");
721}
722
0d388adc
VM
723/* Test that writing an invalid filename fails */
724void test_index_tests__write_invalid_filename(void)
725{
726 git_repository *repo;
727
728 p_mkdir("invalid", 0700);
729
730 cl_git_pass(git_repository_init(&repo, "./invalid", 0));
731
b6832cbf
UG
732 assert_write_fails(repo, ".git/hello");
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, "./foo");
737 assert_write_fails(repo, "./bar");
738 assert_write_fails(repo, "foo/../bar");
0d388adc 739
1876360f
SG
740 git_repository_free(repo);
741
0d388adc 742 cl_fixture_cleanup("invalid");
1876360f 743}
7fc00435 744
dce7b1a4
ET
745void test_index_tests__honors_protect_filesystems(void)
746{
747 git_repository *repo;
748
749 p_mkdir("invalid", 0700);
750
751 cl_git_pass(git_repository_init(&repo, "./invalid", 0));
752
753 cl_repo_set_bool(repo, "core.protectHFS", true);
754 cl_repo_set_bool(repo, "core.protectNTFS", true);
755
b6832cbf
UG
756 assert_write_fails(repo, ".git./hello");
757 assert_write_fails(repo, ".git\xe2\x80\xad/hello");
758 assert_write_fails(repo, "git~1/hello");
759 assert_write_fails(repo, ".git\xe2\x81\xaf/hello");
760 assert_write_fails(repo, ".git::$INDEX_ALLOCATION/dummy-file");
761
762 git_repository_free(repo);
763
764 cl_fixture_cleanup("invalid");
765}
766
767void test_index_tests__protectntfs_on_by_default(void)
768{
769 git_repository *repo;
770
771 p_mkdir("invalid", 0700);
772
773 cl_git_pass(git_repository_init(&repo, "./invalid", 0));
774 assert_write_fails(repo, ".git./hello");
775 assert_write_fails(repo, "git~1/hello");
dce7b1a4
ET
776
777 git_repository_free(repo);
778
779 cl_fixture_cleanup("invalid");
780}
781
b6832cbf
UG
782void test_index_tests__can_disable_protectntfs(void)
783{
784 git_repository *repo;
785 git_index *index;
786
787 cl_must_pass(p_mkdir("valid", 0700));
788 cl_git_rewritefile("valid/git~1", "steal the shortname");
789
790 cl_git_pass(git_repository_init(&repo, "./valid", 0));
791 cl_git_pass(git_repository_index(&index, repo));
792 cl_repo_set_bool(repo, "core.protectNTFS", false);
793
794 cl_git_pass(git_index_add_bypath(index, "git~1"));
795
796 git_index_free(index);
797 git_repository_free(repo);
798
799 cl_fixture_cleanup("valid");
800}
801
7fc00435
RB
802void test_index_tests__remove_entry(void)
803{
804 git_repository *repo;
805 git_index *index;
806
807 p_mkdir("index_test", 0770);
808
809 cl_git_pass(git_repository_init(&repo, "index_test", 0));
810 cl_git_pass(git_repository_index(&index, repo));
811 cl_assert(git_index_entrycount(index) == 0);
812
813 cl_git_mkfile("index_test/hello", NULL);
25743bd7 814 cl_git_pass(git_index_add_bypath(index, "hello"));
7fc00435
RB
815 cl_git_pass(git_index_write(index));
816
8e5a8ef8 817 cl_git_pass(git_index_read(index, true)); /* reload */
7fc00435
RB
818 cl_assert(git_index_entrycount(index) == 1);
819 cl_assert(git_index_get_bypath(index, "hello", 0) != NULL);
820
821 cl_git_pass(git_index_remove(index, "hello", 0));
822 cl_git_pass(git_index_write(index));
823
8e5a8ef8 824 cl_git_pass(git_index_read(index, true)); /* reload */
7fc00435
RB
825 cl_assert(git_index_entrycount(index) == 0);
826 cl_assert(git_index_get_bypath(index, "hello", 0) == NULL);
827
828 git_index_free(index);
829 git_repository_free(repo);
830 cl_fixture_cleanup("index_test");
831}
832
833void test_index_tests__remove_directory(void)
834{
835 git_repository *repo;
836 git_index *index;
837
838 p_mkdir("index_test", 0770);
839
840 cl_git_pass(git_repository_init(&repo, "index_test", 0));
841 cl_git_pass(git_repository_index(&index, repo));
842 cl_assert_equal_i(0, (int)git_index_entrycount(index));
843
844 p_mkdir("index_test/a", 0770);
845 cl_git_mkfile("index_test/a/1.txt", NULL);
846 cl_git_mkfile("index_test/a/2.txt", NULL);
847 cl_git_mkfile("index_test/a/3.txt", NULL);
848 cl_git_mkfile("index_test/b.txt", NULL);
849
25743bd7
ET
850 cl_git_pass(git_index_add_bypath(index, "a/1.txt"));
851 cl_git_pass(git_index_add_bypath(index, "a/2.txt"));
852 cl_git_pass(git_index_add_bypath(index, "a/3.txt"));
853 cl_git_pass(git_index_add_bypath(index, "b.txt"));
7fc00435
RB
854 cl_git_pass(git_index_write(index));
855
8e5a8ef8 856 cl_git_pass(git_index_read(index, true)); /* reload */
7fc00435
RB
857 cl_assert_equal_i(4, (int)git_index_entrycount(index));
858 cl_assert(git_index_get_bypath(index, "a/1.txt", 0) != NULL);
859 cl_assert(git_index_get_bypath(index, "a/2.txt", 0) != NULL);
860 cl_assert(git_index_get_bypath(index, "b.txt", 0) != NULL);
861
862 cl_git_pass(git_index_remove(index, "a/1.txt", 0));
863 cl_git_pass(git_index_write(index));
864
8e5a8ef8 865 cl_git_pass(git_index_read(index, true)); /* reload */
7fc00435
RB
866 cl_assert_equal_i(3, (int)git_index_entrycount(index));
867 cl_assert(git_index_get_bypath(index, "a/1.txt", 0) == NULL);
868 cl_assert(git_index_get_bypath(index, "a/2.txt", 0) != NULL);
869 cl_assert(git_index_get_bypath(index, "b.txt", 0) != NULL);
870
871 cl_git_pass(git_index_remove_directory(index, "a", 0));
872 cl_git_pass(git_index_write(index));
873
8e5a8ef8 874 cl_git_pass(git_index_read(index, true)); /* reload */
7fc00435
RB
875 cl_assert_equal_i(1, (int)git_index_entrycount(index));
876 cl_assert(git_index_get_bypath(index, "a/1.txt", 0) == NULL);
877 cl_assert(git_index_get_bypath(index, "a/2.txt", 0) == NULL);
878 cl_assert(git_index_get_bypath(index, "b.txt", 0) != NULL);
879
880 git_index_free(index);
881 git_repository_free(repo);
882 cl_fixture_cleanup("index_test");
883}
1540b199
ET
884
885void test_index_tests__preserves_case(void)
886{
887 git_repository *repo;
888 git_index *index;
889 const git_index_entry *entry;
fb03a223 890 int index_caps;
1540b199
ET
891
892 cl_set_cleanup(&cleanup_myrepo, NULL);
893
894 cl_git_pass(git_repository_init(&repo, "./myrepo", 0));
895 cl_git_pass(git_repository_index(&index, repo));
896
fb03a223
RB
897 index_caps = git_index_caps(index);
898
1540b199
ET
899 cl_git_rewritefile("myrepo/test.txt", "hey there\n");
900 cl_git_pass(git_index_add_bypath(index, "test.txt"));
901
902 cl_git_pass(p_rename("myrepo/test.txt", "myrepo/TEST.txt"));
903 cl_git_rewritefile("myrepo/TEST.txt", "hello again\n");
904 cl_git_pass(git_index_add_bypath(index, "TEST.txt"));
905
ac3d33df 906 if (index_caps & GIT_INDEX_CAPABILITY_IGNORE_CASE)
fb03a223
RB
907 cl_assert_equal_i(1, (int)git_index_entrycount(index));
908 else
909 cl_assert_equal_i(2, (int)git_index_entrycount(index));
1540b199
ET
910
911 /* Test access by path instead of index */
912 cl_assert((entry = git_index_get_bypath(index, "test.txt", 0)) != NULL);
1540b199
ET
913 /* The path should *not* have changed without an explicit remove */
914 cl_assert(git__strcmp(entry->path, "test.txt") == 0);
915
fb03a223 916 cl_assert((entry = git_index_get_bypath(index, "TEST.txt", 0)) != NULL);
ac3d33df 917 if (index_caps & GIT_INDEX_CAPABILITY_IGNORE_CASE)
fb03a223
RB
918 /* The path should *not* have changed without an explicit remove */
919 cl_assert(git__strcmp(entry->path, "test.txt") == 0);
920 else
921 cl_assert(git__strcmp(entry->path, "TEST.txt") == 0);
922
1540b199
ET
923 git_index_free(index);
924 git_repository_free(repo);
925}
926
3d276874
CMN
927void test_index_tests__elocked(void)
928{
929 git_repository *repo;
930 git_index *index;
931 git_filebuf file = GIT_FILEBUF_INIT;
932 const git_error *err;
933 int error;
934
935 cl_set_cleanup(&cleanup_myrepo, NULL);
936
937 cl_git_pass(git_repository_init(&repo, "./myrepo", 0));
938 cl_git_pass(git_repository_index(&index, repo));
939
940 /* Lock the index file so we fail to lock it */
1d3a8aeb 941 cl_git_pass(git_filebuf_open(&file, index->index_file_path, 0, 0666));
3d276874
CMN
942 error = git_index_write(index);
943 cl_assert_equal_i(GIT_ELOCKED, error);
944
ac3d33df
JK
945 err = git_error_last();
946 cl_assert_equal_i(err->klass, GIT_ERROR_INDEX);
3d276874
CMN
947
948 git_filebuf_cleanup(&file);
949 git_index_free(index);
950 git_repository_free(repo);
951}
da7b78fa 952
953void test_index_tests__reload_from_disk(void)
954{
955 git_repository *repo;
956 git_index *read_index;
957 git_index *write_index;
958
959 cl_set_cleanup(&cleanup_myrepo, NULL);
960
ac2fba0e 961 cl_git_pass(git_futils_mkdir("./myrepo", 0777, GIT_MKDIR_PATH));
da7b78fa 962 cl_git_mkfile("./myrepo/a.txt", "a\n");
963 cl_git_mkfile("./myrepo/b.txt", "b\n");
964
965 cl_git_pass(git_repository_init(&repo, "./myrepo", 0));
966 cl_git_pass(git_repository_index(&write_index, repo));
967 cl_assert_equal_i(false, write_index->on_disk);
968
969 cl_git_pass(git_index_open(&read_index, write_index->index_file_path));
970 cl_assert_equal_i(false, read_index->on_disk);
971
b874629b 972 /* Stage two new files against the write_index */
da7b78fa 973 cl_git_pass(git_index_add_bypath(write_index, "a.txt"));
974 cl_git_pass(git_index_add_bypath(write_index, "b.txt"));
975
976 cl_assert_equal_sz(2, git_index_entrycount(write_index));
977
978 /* Persist the index changes to disk */
979 cl_git_pass(git_index_write(write_index));
980 cl_assert_equal_i(true, write_index->on_disk);
981
982 /* Sync the changes back into the read_index */
983 cl_assert_equal_sz(0, git_index_entrycount(read_index));
984
8e5a8ef8 985 cl_git_pass(git_index_read(read_index, true));
da7b78fa 986 cl_assert_equal_i(true, read_index->on_disk);
987
988 cl_assert_equal_sz(2, git_index_entrycount(read_index));
989
990 /* Remove the index file from the filesystem */
991 cl_git_pass(p_unlink(write_index->index_file_path));
992
993 /* Sync the changes back into the read_index */
8e5a8ef8 994 cl_git_pass(git_index_read(read_index, true));
da7b78fa 995 cl_assert_equal_i(false, read_index->on_disk);
996 cl_assert_equal_sz(0, git_index_entrycount(read_index));
997
998 git_index_free(read_index);
999 git_index_free(write_index);
1000 git_repository_free(repo);
1001}
3d523345 1002
1003void test_index_tests__corrupted_extension(void)
1004{
3d523345 1005 git_index *index;
1006
1007 cl_git_fail_with(git_index_open(&index, TEST_INDEXBAD_PATH), GIT_ERROR);
1008}
43709ca8 1009
43709ca8
RB
1010void test_index_tests__reload_while_ignoring_case(void)
1011{
1012 git_index *index;
1013 unsigned int caps;
1014
1015 cl_git_pass(git_index_open(&index, TEST_INDEX_PATH));
c67fd4c9 1016 cl_git_pass(git_vector_verify_sorted(&index->entries));
43709ca8
RB
1017
1018 caps = git_index_caps(index);
ac3d33df 1019 cl_git_pass(git_index_set_caps(index, caps &= ~GIT_INDEX_CAPABILITY_IGNORE_CASE));
43709ca8 1020 cl_git_pass(git_index_read(index, true));
c67fd4c9 1021 cl_git_pass(git_vector_verify_sorted(&index->entries));
c232d6c3
CMN
1022 cl_assert(git_index_get_bypath(index, ".HEADER", 0));
1023 cl_assert_equal_p(NULL, git_index_get_bypath(index, ".header", 0));
43709ca8 1024
ac3d33df 1025 cl_git_pass(git_index_set_caps(index, caps | GIT_INDEX_CAPABILITY_IGNORE_CASE));
43709ca8 1026 cl_git_pass(git_index_read(index, true));
c67fd4c9 1027 cl_git_pass(git_vector_verify_sorted(&index->entries));
c232d6c3
CMN
1028 cl_assert(git_index_get_bypath(index, ".HEADER", 0));
1029 cl_assert(git_index_get_bypath(index, ".header", 0));
1030
1031 git_index_free(index);
1032}
1033
1034void test_index_tests__change_icase_on_instance(void)
1035{
1036 git_index *index;
1037 unsigned int caps;
1038 const git_index_entry *e;
1039
1040 cl_git_pass(git_index_open(&index, TEST_INDEX_PATH));
1041 cl_git_pass(git_vector_verify_sorted(&index->entries));
1042
1043 caps = git_index_caps(index);
ac3d33df 1044 cl_git_pass(git_index_set_caps(index, caps &= ~GIT_INDEX_CAPABILITY_IGNORE_CASE));
c232d6c3
CMN
1045 cl_assert_equal_i(false, index->ignore_case);
1046 cl_git_pass(git_vector_verify_sorted(&index->entries));
1047 cl_assert(e = git_index_get_bypath(index, "src/common.h", 0));
1048 cl_assert_equal_p(NULL, e = git_index_get_bypath(index, "SRC/Common.h", 0));
1049 cl_assert(e = git_index_get_bypath(index, "COPYING", 0));
1050 cl_assert_equal_p(NULL, e = git_index_get_bypath(index, "copying", 0));
1051
ac3d33df 1052 cl_git_pass(git_index_set_caps(index, caps | GIT_INDEX_CAPABILITY_IGNORE_CASE));
c232d6c3
CMN
1053 cl_assert_equal_i(true, index->ignore_case);
1054 cl_git_pass(git_vector_verify_sorted(&index->entries));
1055 cl_assert(e = git_index_get_bypath(index, "COPYING", 0));
1056 cl_assert_equal_s("COPYING", e->path);
1057 cl_assert(e = git_index_get_bypath(index, "copying", 0));
1058 cl_assert_equal_s("COPYING", e->path);
43709ca8
RB
1059
1060 git_index_free(index);
1061}
55798fd1
ET
1062
1063void test_index_tests__can_lock_index(void)
1064{
eae0bfdc 1065 git_repository *repo;
55798fd1
ET
1066 git_index *index;
1067 git_indexwriter one = GIT_INDEXWRITER_INIT,
1068 two = GIT_INDEXWRITER_INIT;
1069
eae0bfdc
PP
1070 repo = cl_git_sandbox_init("testrepo.git");
1071
1072 cl_git_pass(git_repository_index(&index, repo));
55798fd1
ET
1073 cl_git_pass(git_indexwriter_init(&one, index));
1074
1075 cl_git_fail_with(GIT_ELOCKED, git_indexwriter_init(&two, index));
1076 cl_git_fail_with(GIT_ELOCKED, git_index_write(index));
1077
1078 cl_git_pass(git_indexwriter_commit(&one));
1079
1080 cl_git_pass(git_index_write(index));
1081
1082 git_indexwriter_cleanup(&one);
1083 git_indexwriter_cleanup(&two);
1084 git_index_free(index);
eae0bfdc 1085 cl_git_sandbox_cleanup();
55798fd1 1086}
ac3d33df
JK
1087
1088void test_index_tests__can_iterate(void)
1089{
1090 git_index *index;
1091 git_index_iterator *iterator;
1092 const git_index_entry *entry;
1093 size_t i, iterator_idx = 0, found = 0;
1094 int ret;
1095
1096 cl_git_pass(git_index_open(&index, TEST_INDEX_PATH));
1097 cl_git_pass(git_index_iterator_new(&iterator, index));
1098
1099 cl_assert(git_vector_is_sorted(&iterator->snap));
1100
1101 for (i = 0; i < ARRAY_SIZE(test_entries); i++) {
1102 /* Advance iterator to next test entry index */
1103 do {
1104 ret = git_index_iterator_next(&entry, iterator);
1105
1106 if (ret == GIT_ITEROVER)
1107 cl_fail("iterator did not contain all test entries");
1108
1109 cl_git_pass(ret);
1110 } while (iterator_idx++ < test_entries[i].index);
1111
1112 cl_assert_equal_s(entry->path, test_entries[i].path);
1113 cl_assert_equal_i(entry->mtime.seconds, test_entries[i].mtime);
1114 cl_assert_equal_i(entry->file_size, test_entries[i].file_size);
1115 found++;
1116 }
1117
1118 while ((ret = git_index_iterator_next(&entry, iterator)) == 0)
1119 ;
1120
1121 if (ret != GIT_ITEROVER)
1122 cl_git_fail(ret);
1123
1124 cl_assert_equal_i(found, ARRAY_SIZE(test_entries));
1125
1126 git_index_iterator_free(iterator);
1127 git_index_free(index);
1128}
1129
1130void test_index_tests__can_modify_while_iterating(void)
1131{
1132 git_index *index;
1133 git_index_iterator *iterator;
1134 const git_index_entry *entry;
1135 git_index_entry new_entry = {{0}};
1136 size_t expected = 0, seen = 0;
1137 int ret;
1138
1139 cl_git_pass(git_index_open(&index, TEST_INDEX_PATH));
1140 cl_git_pass(git_index_iterator_new(&iterator, index));
1141
1142 expected = git_index_entrycount(index);
1143 cl_assert(git_vector_is_sorted(&iterator->snap));
1144
1145 /*
1146 * After we've counted the entries, add a new one and change another;
1147 * ensure that our iterator is backed by a snapshot and thus returns
1148 * the number of entries from when the iterator was created.
1149 */
1150 cl_git_pass(git_oid_fromstr(&new_entry.id, "8312e0a89a9cbab77c732b6bc39b51a783e3a318"));
1151 new_entry.path = "newfile";
1152 new_entry.mode = GIT_FILEMODE_BLOB;
1153 cl_git_pass(git_index_add(index, &new_entry));
1154
1155 cl_git_pass(git_oid_fromstr(&new_entry.id, "4141414141414141414141414141414141414141"));
1156 new_entry.path = "Makefile";
1157 new_entry.mode = GIT_FILEMODE_BLOB;
1158 cl_git_pass(git_index_add(index, &new_entry));
1159
1160 while (true) {
1161 ret = git_index_iterator_next(&entry, iterator);
1162
1163 if (ret == GIT_ITEROVER)
1164 break;
1165
1166 seen++;
1167 }
1168
1169 cl_assert_equal_i(expected, seen);
1170
1171 git_index_iterator_free(iterator);
1172 git_index_free(index);
1173}