]> git.proxmox.com Git - libgit2.git/blob - tests/index/tests.c
Merge pull request #1968 from libgit2/ntk/fix/bad_index
[libgit2.git] / tests / index / tests.c
1 #include "clar_libgit2.h"
2 #include "index.h"
3
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")
10
11
12 /* Suite data */
13 struct test_entry {
14 size_t index;
15 char path[128];
16 git_off_t file_size;
17 git_time_t mtime;
18 };
19
20 static struct test_entry test_entries[] = {
21 {4, "Makefile", 5064, 0x4C3F7F33},
22 {62, "tests/Makefile", 2631, 0x4C3F7F33},
23 {36, "src/index.c", 10014, 0x4C43368D},
24 {6, "git.git-authors", 2709, 0x4C3F7F33},
25 {48, "src/revobject.h", 1448, 0x4C3F7FE2}
26 };
27
28 /* Helpers */
29 static void copy_file(const char *src, const char *dst)
30 {
31 git_buf source_buf = GIT_BUF_INIT;
32 git_file dst_fd;
33
34 cl_git_pass(git_futils_readbuffer(&source_buf, src));
35
36 dst_fd = git_futils_creat_withpath(dst, 0777, 0666); /* -V536 */
37 if (dst_fd < 0)
38 goto cleanup;
39
40 cl_git_pass(p_write(dst_fd, source_buf.ptr, source_buf.size));
41
42 cleanup:
43 git_buf_free(&source_buf);
44 p_close(dst_fd);
45 }
46
47 static void files_are_equal(const char *a, const char *b)
48 {
49 git_buf buf_a = GIT_BUF_INIT;
50 git_buf buf_b = GIT_BUF_INIT;
51 int pass;
52
53 if (git_futils_readbuffer(&buf_a, a) < 0)
54 cl_assert(0);
55
56 if (git_futils_readbuffer(&buf_b, b) < 0) {
57 git_buf_free(&buf_a);
58 cl_assert(0);
59 }
60
61 pass = (buf_a.size == buf_b.size && !memcmp(buf_a.ptr, buf_b.ptr, buf_a.size));
62
63 git_buf_free(&buf_a);
64 git_buf_free(&buf_b);
65
66 cl_assert(pass);
67 }
68
69
70 /* Fixture setup and teardown */
71 void test_index_tests__initialize(void)
72 {
73 }
74
75 void test_index_tests__empty_index(void)
76 {
77 git_index *index;
78
79 cl_git_pass(git_index_open(&index, "in-memory-index"));
80 cl_assert(index->on_disk == 0);
81
82 cl_assert(git_index_entrycount(index) == 0);
83 cl_assert(index->entries.sorted);
84
85 git_index_free(index);
86 }
87
88 void test_index_tests__default_test_index(void)
89 {
90 git_index *index;
91 unsigned int i;
92 git_index_entry **entries;
93
94 cl_git_pass(git_index_open(&index, TEST_INDEX_PATH));
95 cl_assert(index->on_disk);
96
97 cl_assert(git_index_entrycount(index) == index_entry_count);
98 cl_assert(index->entries.sorted);
99
100 entries = (git_index_entry **)index->entries.contents;
101
102 for (i = 0; i < ARRAY_SIZE(test_entries); ++i) {
103 git_index_entry *e = entries[test_entries[i].index];
104
105 cl_assert_equal_s(e->path, test_entries[i].path);
106 cl_assert(e->mtime.seconds == test_entries[i].mtime);
107 cl_assert(e->file_size == test_entries[i].file_size);
108 }
109
110 git_index_free(index);
111 }
112
113 void test_index_tests__gitgit_index(void)
114 {
115 git_index *index;
116
117 cl_git_pass(git_index_open(&index, TEST_INDEX2_PATH));
118 cl_assert(index->on_disk);
119
120 cl_assert(git_index_entrycount(index) == index_entry_count_2);
121 cl_assert(index->entries.sorted);
122 cl_assert(index->tree != NULL);
123
124 git_index_free(index);
125 }
126
127 void test_index_tests__find_in_existing(void)
128 {
129 git_index *index;
130 unsigned int i;
131
132 cl_git_pass(git_index_open(&index, TEST_INDEX_PATH));
133
134 for (i = 0; i < ARRAY_SIZE(test_entries); ++i) {
135 size_t idx;
136
137 cl_assert(!git_index_find(&idx, index, test_entries[i].path));
138 cl_assert(idx == test_entries[i].index);
139 }
140
141 git_index_free(index);
142 }
143
144 void test_index_tests__find_in_empty(void)
145 {
146 git_index *index;
147 unsigned int i;
148
149 cl_git_pass(git_index_open(&index, "fake-index"));
150
151 for (i = 0; i < ARRAY_SIZE(test_entries); ++i) {
152 cl_assert(GIT_ENOTFOUND == git_index_find(NULL, index, test_entries[i].path));
153 }
154
155 git_index_free(index);
156 }
157
158 void test_index_tests__write(void)
159 {
160 git_index *index;
161
162 copy_file(TEST_INDEXBIG_PATH, "index_rewrite");
163
164 cl_git_pass(git_index_open(&index, "index_rewrite"));
165 cl_assert(index->on_disk);
166
167 cl_git_pass(git_index_write(index));
168 files_are_equal(TEST_INDEXBIG_PATH, "index_rewrite");
169
170 git_index_free(index);
171
172 p_unlink("index_rewrite");
173 }
174
175 void test_index_tests__sort0(void)
176 {
177 /* sort the entires in an index */
178
179 /*
180 * TODO: This no longer applies:
181 * index sorting in Git uses some specific changes to the way
182 * directories are sorted.
183 *
184 * We need to specificially check for this by creating a new
185 * index, adding entries in random order and then
186 * checking for consistency
187 */
188 }
189
190 void test_index_tests__sort1(void)
191 {
192 /* sort the entires in an empty index */
193 git_index *index;
194
195 cl_git_pass(git_index_open(&index, "fake-index"));
196
197 /* FIXME: this test is slightly dumb */
198 cl_assert(index->entries.sorted);
199
200 git_index_free(index);
201 }
202
203 static void cleanup_myrepo(void *opaque)
204 {
205 GIT_UNUSED(opaque);
206 cl_fixture_cleanup("myrepo");
207 }
208
209 void test_index_tests__add(void)
210 {
211 git_index *index;
212 git_filebuf file = GIT_FILEBUF_INIT;
213 git_repository *repo;
214 const git_index_entry *entry;
215 git_oid id1;
216
217 cl_set_cleanup(&cleanup_myrepo, NULL);
218
219 /* Intialize a new repository */
220 cl_git_pass(git_repository_init(&repo, "./myrepo", 0));
221
222 /* Ensure we're the only guy in the room */
223 cl_git_pass(git_repository_index(&index, repo));
224 cl_assert(git_index_entrycount(index) == 0);
225
226 /* Create a new file in the working directory */
227 cl_git_pass(git_futils_mkpath2file("myrepo/test.txt", 0777));
228 cl_git_pass(git_filebuf_open(&file, "myrepo/test.txt", 0, 0666));
229 cl_git_pass(git_filebuf_write(&file, "hey there\n", 10));
230 cl_git_pass(git_filebuf_commit(&file));
231
232 /* Store the expected hash of the file/blob
233 * This has been generated by executing the following
234 * $ echo "hey there" | git hash-object --stdin
235 */
236 cl_git_pass(git_oid_fromstr(&id1, "a8233120f6ad708f843d861ce2b7228ec4e3dec6"));
237
238 /* Add the new file to the index */
239 cl_git_pass(git_index_add_bypath(index, "test.txt"));
240
241 /* Wow... it worked! */
242 cl_assert(git_index_entrycount(index) == 1);
243 entry = git_index_get_byindex(index, 0);
244
245 /* And the built-in hashing mechanism worked as expected */
246 cl_assert(git_oid_cmp(&id1, &entry->oid) == 0);
247
248 /* Test access by path instead of index */
249 cl_assert((entry = git_index_get_bypath(index, "test.txt", 0)) != NULL);
250 cl_assert(git_oid_cmp(&id1, &entry->oid) == 0);
251
252 git_index_free(index);
253 git_repository_free(repo);
254 }
255
256 static void cleanup_1397(void *opaque)
257 {
258 GIT_UNUSED(opaque);
259 cl_git_sandbox_cleanup();
260 }
261
262 void test_index_tests__add_issue_1397(void)
263 {
264 git_index *index;
265 git_repository *repo;
266 const git_index_entry *entry;
267 git_oid id1;
268
269 cl_set_cleanup(&cleanup_1397, NULL);
270
271 repo = cl_git_sandbox_init("issue_1397");
272
273 cl_repo_set_bool(repo, "core.autocrlf", true);
274
275 /* Ensure we're the only guy in the room */
276 cl_git_pass(git_repository_index(&index, repo));
277
278 /* Store the expected hash of the file/blob
279 * This has been generated by executing the following
280 * $ git hash-object crlf_file.txt
281 */
282 cl_git_pass(git_oid_fromstr(&id1, "8312e0889a9cbab77c732b6bc39b51a683e3a318"));
283
284 /* Make sure the initial SHA-1 is correct */
285 cl_assert((entry = git_index_get_bypath(index, "crlf_file.txt", 0)) != NULL);
286 cl_assert_(git_oid_cmp(&id1, &entry->oid) == 0, "first oid check");
287
288 /* Update the index */
289 cl_git_pass(git_index_add_bypath(index, "crlf_file.txt"));
290
291 /* Check the new SHA-1 */
292 cl_assert((entry = git_index_get_bypath(index, "crlf_file.txt", 0)) != NULL);
293 cl_assert_(git_oid_cmp(&id1, &entry->oid) == 0, "second oid check");
294
295 git_index_free(index);
296 }
297
298 void test_index_tests__add_bypath_to_a_bare_repository_returns_EBAREPO(void)
299 {
300 git_repository *bare_repo;
301 git_index *index;
302
303 cl_git_pass(git_repository_open(&bare_repo, cl_fixture("testrepo.git")));
304 cl_git_pass(git_repository_index(&index, bare_repo));
305
306 cl_assert_equal_i(GIT_EBAREREPO, git_index_add_bypath(index, "test.txt"));
307
308 git_index_free(index);
309 git_repository_free(bare_repo);
310 }
311
312 /* Test that writing an invalid filename fails */
313 void test_index_tests__write_invalid_filename(void)
314 {
315 git_repository *repo;
316 git_index *index;
317 git_oid expected;
318
319 p_mkdir("read_tree", 0700);
320
321 cl_git_pass(git_repository_init(&repo, "./read_tree", 0));
322 cl_git_pass(git_repository_index(&index, repo));
323
324 cl_assert(git_index_entrycount(index) == 0);
325
326 cl_git_mkfile("./read_tree/.git/hello", NULL);
327
328 cl_git_pass(git_index_add_bypath(index, ".git/hello"));
329
330 /* write-tree */
331 cl_git_fail(git_index_write_tree(&expected, index));
332
333 git_index_free(index);
334 git_repository_free(repo);
335
336 cl_fixture_cleanup("read_tree");
337 }
338
339 void test_index_tests__remove_entry(void)
340 {
341 git_repository *repo;
342 git_index *index;
343
344 p_mkdir("index_test", 0770);
345
346 cl_git_pass(git_repository_init(&repo, "index_test", 0));
347 cl_git_pass(git_repository_index(&index, repo));
348 cl_assert(git_index_entrycount(index) == 0);
349
350 cl_git_mkfile("index_test/hello", NULL);
351 cl_git_pass(git_index_add_bypath(index, "hello"));
352 cl_git_pass(git_index_write(index));
353
354 cl_git_pass(git_index_read(index, true)); /* reload */
355 cl_assert(git_index_entrycount(index) == 1);
356 cl_assert(git_index_get_bypath(index, "hello", 0) != NULL);
357
358 cl_git_pass(git_index_remove(index, "hello", 0));
359 cl_git_pass(git_index_write(index));
360
361 cl_git_pass(git_index_read(index, true)); /* reload */
362 cl_assert(git_index_entrycount(index) == 0);
363 cl_assert(git_index_get_bypath(index, "hello", 0) == NULL);
364
365 git_index_free(index);
366 git_repository_free(repo);
367 cl_fixture_cleanup("index_test");
368 }
369
370 void test_index_tests__remove_directory(void)
371 {
372 git_repository *repo;
373 git_index *index;
374
375 p_mkdir("index_test", 0770);
376
377 cl_git_pass(git_repository_init(&repo, "index_test", 0));
378 cl_git_pass(git_repository_index(&index, repo));
379 cl_assert_equal_i(0, (int)git_index_entrycount(index));
380
381 p_mkdir("index_test/a", 0770);
382 cl_git_mkfile("index_test/a/1.txt", NULL);
383 cl_git_mkfile("index_test/a/2.txt", NULL);
384 cl_git_mkfile("index_test/a/3.txt", NULL);
385 cl_git_mkfile("index_test/b.txt", NULL);
386
387 cl_git_pass(git_index_add_bypath(index, "a/1.txt"));
388 cl_git_pass(git_index_add_bypath(index, "a/2.txt"));
389 cl_git_pass(git_index_add_bypath(index, "a/3.txt"));
390 cl_git_pass(git_index_add_bypath(index, "b.txt"));
391 cl_git_pass(git_index_write(index));
392
393 cl_git_pass(git_index_read(index, true)); /* reload */
394 cl_assert_equal_i(4, (int)git_index_entrycount(index));
395 cl_assert(git_index_get_bypath(index, "a/1.txt", 0) != NULL);
396 cl_assert(git_index_get_bypath(index, "a/2.txt", 0) != NULL);
397 cl_assert(git_index_get_bypath(index, "b.txt", 0) != NULL);
398
399 cl_git_pass(git_index_remove(index, "a/1.txt", 0));
400 cl_git_pass(git_index_write(index));
401
402 cl_git_pass(git_index_read(index, true)); /* reload */
403 cl_assert_equal_i(3, (int)git_index_entrycount(index));
404 cl_assert(git_index_get_bypath(index, "a/1.txt", 0) == NULL);
405 cl_assert(git_index_get_bypath(index, "a/2.txt", 0) != NULL);
406 cl_assert(git_index_get_bypath(index, "b.txt", 0) != NULL);
407
408 cl_git_pass(git_index_remove_directory(index, "a", 0));
409 cl_git_pass(git_index_write(index));
410
411 cl_git_pass(git_index_read(index, true)); /* reload */
412 cl_assert_equal_i(1, (int)git_index_entrycount(index));
413 cl_assert(git_index_get_bypath(index, "a/1.txt", 0) == NULL);
414 cl_assert(git_index_get_bypath(index, "a/2.txt", 0) == NULL);
415 cl_assert(git_index_get_bypath(index, "b.txt", 0) != NULL);
416
417 git_index_free(index);
418 git_repository_free(repo);
419 cl_fixture_cleanup("index_test");
420 }
421
422 void test_index_tests__preserves_case(void)
423 {
424 git_repository *repo;
425 git_index *index;
426 const git_index_entry *entry;
427 int index_caps;
428
429 cl_set_cleanup(&cleanup_myrepo, NULL);
430
431 cl_git_pass(git_repository_init(&repo, "./myrepo", 0));
432 cl_git_pass(git_repository_index(&index, repo));
433
434 index_caps = git_index_caps(index);
435
436 cl_git_rewritefile("myrepo/test.txt", "hey there\n");
437 cl_git_pass(git_index_add_bypath(index, "test.txt"));
438
439 cl_git_pass(p_rename("myrepo/test.txt", "myrepo/TEST.txt"));
440 cl_git_rewritefile("myrepo/TEST.txt", "hello again\n");
441 cl_git_pass(git_index_add_bypath(index, "TEST.txt"));
442
443 if (index_caps & GIT_INDEXCAP_IGNORE_CASE)
444 cl_assert_equal_i(1, (int)git_index_entrycount(index));
445 else
446 cl_assert_equal_i(2, (int)git_index_entrycount(index));
447
448 /* Test access by path instead of index */
449 cl_assert((entry = git_index_get_bypath(index, "test.txt", 0)) != NULL);
450 /* The path should *not* have changed without an explicit remove */
451 cl_assert(git__strcmp(entry->path, "test.txt") == 0);
452
453 cl_assert((entry = git_index_get_bypath(index, "TEST.txt", 0)) != NULL);
454 if (index_caps & GIT_INDEXCAP_IGNORE_CASE)
455 /* The path should *not* have changed without an explicit remove */
456 cl_assert(git__strcmp(entry->path, "test.txt") == 0);
457 else
458 cl_assert(git__strcmp(entry->path, "TEST.txt") == 0);
459
460 git_index_free(index);
461 git_repository_free(repo);
462 }
463
464 void test_index_tests__elocked(void)
465 {
466 git_repository *repo;
467 git_index *index;
468 git_filebuf file = GIT_FILEBUF_INIT;
469 const git_error *err;
470 int error;
471
472 cl_set_cleanup(&cleanup_myrepo, NULL);
473
474 cl_git_pass(git_repository_init(&repo, "./myrepo", 0));
475 cl_git_pass(git_repository_index(&index, repo));
476
477 /* Lock the index file so we fail to lock it */
478 cl_git_pass(git_filebuf_open(&file, index->index_file_path, 0, 0666));
479 error = git_index_write(index);
480 cl_assert_equal_i(GIT_ELOCKED, error);
481
482 err = giterr_last();
483 cl_assert_equal_i(err->klass, GITERR_INDEX);
484
485 git_filebuf_cleanup(&file);
486 git_index_free(index);
487 git_repository_free(repo);
488 }
489
490 void test_index_tests__reload_from_disk(void)
491 {
492 git_repository *repo;
493 git_index *read_index;
494 git_index *write_index;
495
496 cl_set_cleanup(&cleanup_myrepo, NULL);
497
498 cl_git_pass(git_futils_mkdir("./myrepo", NULL, 0777, GIT_MKDIR_PATH));
499 cl_git_mkfile("./myrepo/a.txt", "a\n");
500 cl_git_mkfile("./myrepo/b.txt", "b\n");
501
502 cl_git_pass(git_repository_init(&repo, "./myrepo", 0));
503 cl_git_pass(git_repository_index(&write_index, repo));
504 cl_assert_equal_i(false, write_index->on_disk);
505
506 cl_git_pass(git_index_open(&read_index, write_index->index_file_path));
507 cl_assert_equal_i(false, read_index->on_disk);
508
509 /* Stage two new files agaisnt the write_index */
510 cl_git_pass(git_index_add_bypath(write_index, "a.txt"));
511 cl_git_pass(git_index_add_bypath(write_index, "b.txt"));
512
513 cl_assert_equal_sz(2, git_index_entrycount(write_index));
514
515 /* Persist the index changes to disk */
516 cl_git_pass(git_index_write(write_index));
517 cl_assert_equal_i(true, write_index->on_disk);
518
519 /* Sync the changes back into the read_index */
520 cl_assert_equal_sz(0, git_index_entrycount(read_index));
521
522 cl_git_pass(git_index_read(read_index, true));
523 cl_assert_equal_i(true, read_index->on_disk);
524
525 cl_assert_equal_sz(2, git_index_entrycount(read_index));
526
527 /* Remove the index file from the filesystem */
528 cl_git_pass(p_unlink(write_index->index_file_path));
529
530 /* Sync the changes back into the read_index */
531 cl_git_pass(git_index_read(read_index, true));
532 cl_assert_equal_i(false, read_index->on_disk);
533 cl_assert_equal_sz(0, git_index_entrycount(read_index));
534
535 git_index_free(read_index);
536 git_index_free(write_index);
537 git_repository_free(repo);
538 }
539
540 void test_index_tests__corrupted_extension(void)
541 {
542 /* sort the entires in an empty index */
543 git_index *index;
544
545 cl_git_fail_with(git_index_open(&index, TEST_INDEXBAD_PATH), GIT_ERROR);
546 }