]> git.proxmox.com Git - libgit2.git/blame - tests/t00-core.c
Merge pull request #384 from kiryl/warnings
[libgit2.git] / tests / t00-core.c
CommitLineData
2a1732b4
VM
1/*
2 * This file is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License, version 2,
4 * as published by the Free Software Foundation.
5 *
6 * In addition to the permissions in the GNU General Public License,
7 * the authors give you unlimited permission to link the compiled
8 * version of this file into combinations with other programs,
9 * and to distribute those combinations without any restriction
10 * coming from the use of this file. (The General Public License
11 * restrictions do apply in other respects; for example, they cover
12 * modification of the file, and distribution when not linked into
13 * a combined executable.)
14 *
15 * This file is distributed in the hope that it will be useful, but
16 * WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; see the file COPYING. If not, write to
22 * the Free Software Foundation, 51 Franklin Street, Fifth Floor,
23 * Boston, MA 02110-1301, USA.
24 */
25#include "test_lib.h"
26
27#include "vector.h"
28#include "fileops.h"
8102a961 29#include "filebuf.h"
2a1732b4 30
3dccfed1 31BEGIN_TEST(string0, "compare prefixes")
2a1732b4
VM
32 must_be_true(git__prefixcmp("", "") == 0);
33 must_be_true(git__prefixcmp("a", "") == 0);
34 must_be_true(git__prefixcmp("", "a") < 0);
35 must_be_true(git__prefixcmp("a", "b") < 0);
36 must_be_true(git__prefixcmp("b", "a") > 0);
37 must_be_true(git__prefixcmp("ab", "a") == 0);
38 must_be_true(git__prefixcmp("ab", "ac") < 0);
39 must_be_true(git__prefixcmp("ab", "aa") > 0);
40END_TEST
41
3dccfed1 42BEGIN_TEST(string1, "compare suffixes")
2a1732b4
VM
43 must_be_true(git__suffixcmp("", "") == 0);
44 must_be_true(git__suffixcmp("a", "") == 0);
45 must_be_true(git__suffixcmp("", "a") < 0);
46 must_be_true(git__suffixcmp("a", "b") < 0);
47 must_be_true(git__suffixcmp("b", "a") > 0);
48 must_be_true(git__suffixcmp("ba", "a") == 0);
49 must_be_true(git__suffixcmp("zaa", "ac") < 0);
50 must_be_true(git__suffixcmp("zaz", "ac") > 0);
51END_TEST
52
3dccfed1
VM
53
54BEGIN_TEST(vector0, "initial size of 1 would cause writing past array bounds")
55 git_vector x;
56 int i;
86d7e1ca 57 git_vector_init(&x, 1, NULL);
3dccfed1
VM
58 for (i = 0; i < 10; ++i) {
59 git_vector_insert(&x, (void*) 0xabc);
60 }
61 git_vector_free(&x);
62END_TEST
63
64BEGIN_TEST(vector1, "don't read past array bounds on remove()")
65 git_vector x;
66 // make initial capacity exact for our insertions.
86d7e1ca 67 git_vector_init(&x, 3, NULL);
3dccfed1
VM
68 git_vector_insert(&x, (void*) 0xabc);
69 git_vector_insert(&x, (void*) 0xdef);
70 git_vector_insert(&x, (void*) 0x123);
71
72 git_vector_remove(&x, 0); // used to read past array bounds.
73 git_vector_free(&x);
74END_TEST
75
476c42ac
KS
76static int test_cmp(const void *a, const void *b)
77{
84ef7f36 78 return *(const int *)a - *(const int *)b;
476c42ac
KS
79}
80
81BEGIN_TEST(vector2, "remove duplicates")
82 git_vector x;
c1e85748
VM
83 int *ptrs[2];
84
85 ptrs[0] = git__malloc(sizeof(int));
86 ptrs[1] = git__malloc(sizeof(int));
87
88 *ptrs[0] = 2;
89 *ptrs[1] = 1;
90
476c42ac 91 must_pass(git_vector_init(&x, 5, test_cmp));
c1e85748
VM
92 must_pass(git_vector_insert(&x, ptrs[0]));
93 must_pass(git_vector_insert(&x, ptrs[1]));
94 must_pass(git_vector_insert(&x, ptrs[1]));
95 must_pass(git_vector_insert(&x, ptrs[0]));
96 must_pass(git_vector_insert(&x, ptrs[1]));
476c42ac
KS
97 must_be_true(x.length == 5);
98 git_vector_uniq(&x);
99 must_be_true(x.length == 2);
100 git_vector_free(&x);
c1e85748
VM
101
102 free(ptrs[0]);
103 free(ptrs[1]);
476c42ac
KS
104END_TEST
105
3dccfed1
VM
106
107BEGIN_TEST(path0, "get the dirname of a path")
f725931b
VM
108 char dir[64], *dir2;
109
110#define DIRNAME_TEST(A, B) { \
f79026b4 111 must_be_true(git_path_dirname_r(dir, sizeof(dir), A) >= 0); \
f725931b 112 must_be_true(strcmp(dir, B) == 0); \
f79026b4 113 must_be_true((dir2 = git_path_dirname(A)) != NULL); \
f725931b
VM
114 must_be_true(strcmp(dir2, B) == 0); \
115 free(dir2); \
116}
2a1732b4 117
f725931b
VM
118 DIRNAME_TEST(NULL, ".");
119 DIRNAME_TEST("", ".");
120 DIRNAME_TEST("a", ".");
121 DIRNAME_TEST("/", "/");
122 DIRNAME_TEST("/usr", "/");
123 DIRNAME_TEST("/usr/", "/");
124 DIRNAME_TEST("/usr/lib", "/usr");
47d0db78 125 DIRNAME_TEST("/usr/lib/", "/usr");
126 DIRNAME_TEST("/usr/lib//", "/usr");
f725931b 127 DIRNAME_TEST("usr/lib", "usr");
47d0db78 128 DIRNAME_TEST("usr/lib/", "usr");
129 DIRNAME_TEST("usr/lib//", "usr");
f725931b 130 DIRNAME_TEST(".git/", ".");
2a1732b4 131
f725931b 132#undef DIRNAME_TEST
2a1732b4 133
2a1732b4
VM
134END_TEST
135
3dccfed1 136BEGIN_TEST(path1, "get the base name of a path")
f725931b
VM
137 char base[64], *base2;
138
139#define BASENAME_TEST(A, B) { \
f79026b4 140 must_be_true(git_path_basename_r(base, sizeof(base), A) >= 0); \
f725931b 141 must_be_true(strcmp(base, B) == 0); \
f79026b4 142 must_be_true((base2 = git_path_basename(A)) != NULL); \
f725931b
VM
143 must_be_true(strcmp(base2, B) == 0); \
144 free(base2); \
145}
2a1732b4 146
f725931b
VM
147 BASENAME_TEST(NULL, ".");
148 BASENAME_TEST("", ".");
149 BASENAME_TEST("a", "a");
150 BASENAME_TEST("/", "/");
151 BASENAME_TEST("/usr", "usr");
152 BASENAME_TEST("/usr/", "usr");
153 BASENAME_TEST("/usr/lib", "lib");
47d0db78 154 BASENAME_TEST("/usr/lib//", "lib");
f725931b 155 BASENAME_TEST("usr/lib", "lib");
2a1732b4 156
f725931b 157#undef BASENAME_TEST
2a1732b4 158
f725931b 159END_TEST
2a1732b4 160
3dccfed1 161BEGIN_TEST(path2, "get the latest component in a path")
f725931b 162 const char *dir;
2a1732b4 163
f725931b 164#define TOPDIR_TEST(A, B) { \
f79026b4 165 must_be_true((dir = git_path_topdir(A)) != NULL); \
f725931b
VM
166 must_be_true(strcmp(dir, B) == 0); \
167}
2a1732b4 168
f725931b
VM
169 TOPDIR_TEST(".git/", ".git/");
170 TOPDIR_TEST("/.git/", ".git/");
171 TOPDIR_TEST("usr/local/.git/", ".git/");
172 TOPDIR_TEST("./.git/", ".git/");
173 TOPDIR_TEST("/usr/.git/", ".git/");
174 TOPDIR_TEST("/", "/");
175 TOPDIR_TEST("a/", "a/");
2a1732b4 176
f79026b4
VM
177 must_be_true(git_path_topdir("/usr/.git") == NULL);
178 must_be_true(git_path_topdir(".") == NULL);
179 must_be_true(git_path_topdir("") == NULL);
180 must_be_true(git_path_topdir("a") == NULL);
2a1732b4 181
f725931b 182#undef TOPDIR_TEST
2a1732b4
VM
183END_TEST
184
a79e8e63 185static int ensure_joinpath(const char *path_a, const char *path_b, const char *expected_path)
186{
995f9c34 187 char joined_path[GIT_PATH_MAX];
f79026b4 188 git_path_join(joined_path, path_a, path_b);
995f9c34 189 return strcmp(joined_path, expected_path) == 0 ? GIT_SUCCESS : GIT_ERROR;
a79e8e63 190}
191
3dccfed1 192BEGIN_TEST(path5, "properly join path components")
669db21b 193 must_pass(ensure_joinpath("", "", ""));
194 must_pass(ensure_joinpath("", "a", "a"));
195 must_pass(ensure_joinpath("", "/a", "/a"));
995f9c34 196 must_pass(ensure_joinpath("a", "", "a/"));
669db21b 197 must_pass(ensure_joinpath("a", "/", "a/"));
a79e8e63 198 must_pass(ensure_joinpath("a", "b", "a/b"));
199 must_pass(ensure_joinpath("/", "a", "/a"));
200 must_pass(ensure_joinpath("/", "", "/"));
201 must_pass(ensure_joinpath("/a", "/b", "/a/b"));
202 must_pass(ensure_joinpath("/a", "/b/", "/a/b/"));
203 must_pass(ensure_joinpath("/a/", "b/", "/a/b/"));
204 must_pass(ensure_joinpath("/a/", "/b/", "/a/b/"));
205END_TEST
206
669db21b 207static int ensure_joinpath_n(const char *path_a, const char *path_b, const char *path_c, const char *path_d, const char *expected_path)
208{
209 char joined_path[GIT_PATH_MAX];
f79026b4 210 git_path_join_n(joined_path, 4, path_a, path_b, path_c, path_d);
669db21b 211 return strcmp(joined_path, expected_path) == 0 ? GIT_SUCCESS : GIT_ERROR;
212}
213
3dccfed1 214BEGIN_TEST(path6, "properly join path components for more than one path")
669db21b 215 must_pass(ensure_joinpath_n("", "", "", "", ""));
216 must_pass(ensure_joinpath_n("", "a", "", "", "a/"));
217 must_pass(ensure_joinpath_n("a", "", "", "", "a/"));
218 must_pass(ensure_joinpath_n("", "", "", "a", "a"));
219 must_pass(ensure_joinpath_n("a", "b", "", "/c/d/", "a/b/c/d/"));
220 must_pass(ensure_joinpath_n("a", "b", "", "/c/d", "a/b/c/d"));
221END_TEST
222
2a1732b4
VM
223typedef struct name_data {
224 int count; /* return count */
225 char *name; /* filename */
226} name_data;
227
228typedef struct walk_data {
229 char *sub; /* sub-directory name */
230 name_data *names; /* name state data */
231} walk_data;
232
233
234static char path_buffer[GIT_PATH_MAX];
235static char *top_dir = "dir-walk";
236static walk_data *state_loc;
237
238static int error(const char *fmt, ...)
239{
240 va_list ap;
241
242 va_start(ap, fmt);
243 vfprintf(stderr, fmt, ap);
244 va_end(ap);
245 fprintf(stderr, "\n");
246 return -1;
247}
248
249static int setup(walk_data *d)
250{
251 name_data *n;
252
f79026b4 253 if (p_mkdir(top_dir, 0755) < 0)
2a1732b4
VM
254 return error("can't mkdir(\"%s\")", top_dir);
255
f79026b4 256 if (p_chdir(top_dir) < 0)
2a1732b4
VM
257 return error("can't chdir(\"%s\")", top_dir);
258
259 if (strcmp(d->sub, ".") != 0)
f79026b4 260 if (p_mkdir(d->sub, 0755) < 0)
2a1732b4
VM
261 return error("can't mkdir(\"%s\")", d->sub);
262
263 strcpy(path_buffer, d->sub);
264 state_loc = d;
265
266 for (n = d->names; n->name; n++) {
f79026b4 267 git_file fd = p_creat(n->name, 0600);
2a1732b4
VM
268 if (fd < 0)
269 return GIT_ERROR;
f79026b4 270 p_close(fd);
2a1732b4
VM
271 n->count = 0;
272 }
273
274 return 0;
275}
276
277static int knockdown(walk_data *d)
278{
279 name_data *n;
280
281 for (n = d->names; n->name; n++) {
f79026b4 282 if (p_unlink(n->name) < 0)
2a1732b4
VM
283 return error("can't unlink(\"%s\")", n->name);
284 }
285
286 if (strcmp(d->sub, ".") != 0)
f79026b4 287 if (p_rmdir(d->sub) < 0)
2a1732b4
VM
288 return error("can't rmdir(\"%s\")", d->sub);
289
f79026b4 290 if (p_chdir("..") < 0)
2a1732b4
VM
291 return error("can't chdir(\"..\")");
292
f79026b4 293 if (p_rmdir(top_dir) < 0)
2a1732b4
VM
294 return error("can't rmdir(\"%s\")", top_dir);
295
296 return 0;
297}
298
299static int check_counts(walk_data *d)
300{
301 int ret = 0;
302 name_data *n;
303
304 for (n = d->names; n->name; n++) {
305 if (n->count != 1)
306 ret = error("count (%d, %s)", n->count, n->name);
307 }
308 return ret;
309}
310
311static int one_entry(void *state, char *path)
312{
313 walk_data *d = (walk_data *) state;
314 name_data *n;
315
316 if (state != state_loc)
317 return GIT_ERROR;
318
319 if (path != path_buffer)
320 return GIT_ERROR;
321
322 for (n = d->names; n->name; n++) {
323 if (!strcmp(n->name, path)) {
324 n->count++;
325 return 0;
326 }
327 }
328
329 return GIT_ERROR;
330}
331
332
333static name_data dot_names[] = {
334 { 0, "./a" },
335 { 0, "./asdf" },
336 { 0, "./pack-foo.pack" },
337 { 0, NULL }
338};
339static walk_data dot = {
340 ".",
341 dot_names
342};
343
3dccfed1 344BEGIN_TEST(dirent0, "make sure that the '.' folder is not traversed")
2a1732b4
VM
345
346 must_pass(setup(&dot));
347
f79026b4 348 must_pass(git_futils_direach(path_buffer,
2a1732b4
VM
349 sizeof(path_buffer),
350 one_entry,
351 &dot));
352
353 must_pass(check_counts(&dot));
354
355 must_pass(knockdown(&dot));
356END_TEST
357
358static name_data sub_names[] = {
359 { 0, "sub/a" },
360 { 0, "sub/asdf" },
361 { 0, "sub/pack-foo.pack" },
362 { 0, NULL }
363};
364static walk_data sub = {
365 "sub",
366 sub_names
367};
368
3dccfed1 369BEGIN_TEST(dirent1, "traverse a subfolder")
2a1732b4
VM
370
371 must_pass(setup(&sub));
372
f79026b4 373 must_pass(git_futils_direach(path_buffer,
2a1732b4
VM
374 sizeof(path_buffer),
375 one_entry,
376 &sub));
377
378 must_pass(check_counts(&sub));
379
380 must_pass(knockdown(&sub));
381END_TEST
382
383static walk_data sub_slash = {
384 "sub/",
385 sub_names
386};
387
3dccfed1 388BEGIN_TEST(dirent2, "traverse a slash-terminated subfolder")
2a1732b4
VM
389
390 must_pass(setup(&sub_slash));
391
f79026b4 392 must_pass(git_futils_direach(path_buffer,
2a1732b4
VM
393 sizeof(path_buffer),
394 one_entry,
395 &sub_slash));
396
397 must_pass(check_counts(&sub_slash));
398
399 must_pass(knockdown(&sub_slash));
400END_TEST
401
402static name_data empty_names[] = {
403 { 0, NULL }
404};
405static walk_data empty = {
406 "empty",
407 empty_names
408};
409
410static int dont_call_me(void *GIT_UNUSED(state), char *GIT_UNUSED(path))
411{
412 GIT_UNUSED_ARG(state)
413 GIT_UNUSED_ARG(path)
414 return GIT_ERROR;
415}
416
3dccfed1 417BEGIN_TEST(dirent3, "make sure that empty folders are not traversed")
2a1732b4
VM
418
419 must_pass(setup(&empty));
420
f79026b4 421 must_pass(git_futils_direach(path_buffer,
2a1732b4
VM
422 sizeof(path_buffer),
423 one_entry,
424 &empty));
425
426 must_pass(check_counts(&empty));
427
428 /* make sure callback not called */
f79026b4 429 must_pass(git_futils_direach(path_buffer,
2a1732b4
VM
430 sizeof(path_buffer),
431 dont_call_me,
432 &empty));
433
434 must_pass(knockdown(&empty));
435END_TEST
436
437static name_data odd_names[] = {
438 { 0, "odd/.a" },
439 { 0, "odd/..c" },
440 /* the following don't work on cygwin/win32 */
441 /* { 0, "odd/.b." }, */
442 /* { 0, "odd/..d.." }, */
443 { 0, NULL }
444};
445static walk_data odd = {
446 "odd",
447 odd_names
448};
449
3dccfed1 450BEGIN_TEST(dirent4, "make sure that strange looking filenames ('..c') are traversed")
2a1732b4
VM
451
452 must_pass(setup(&odd));
453
f79026b4 454 must_pass(git_futils_direach(path_buffer,
2a1732b4
VM
455 sizeof(path_buffer),
456 one_entry,
457 &odd));
458
459 must_pass(check_counts(&odd));
460
461 must_pass(knockdown(&odd));
462END_TEST
463
8102a961
CMN
464BEGIN_TEST(filebuf0, "make sure git_filebuf_open doesn't delete an existing lock")
465 git_filebuf file;
95818ff7 466 int fd;
8102a961
CMN
467 char test[] = "test", testlock[] = "test.lock";
468
f79026b4 469 fd = p_creat(testlock, 0744);
95818ff7 470 must_pass(fd);
f79026b4 471 must_pass(p_close(fd));
8102a961 472 must_fail(git_filebuf_open(&file, test, 0));
f79026b4
VM
473 must_pass(git_futils_exists(testlock));
474 must_pass(p_unlink(testlock));
8102a961 475END_TEST
2a1732b4 476
24bd5e55
MS
477BEGIN_TEST(filebuf1, "make sure GIT_FILEBUF_APPEND works as expected")
478 git_filebuf file;
479 int fd;
480 char test[] = "test";
481
f79026b4 482 fd = p_creat(test, 0644);
24bd5e55 483 must_pass(fd);
f79026b4
VM
484 must_pass(p_write(fd, "libgit2 rocks\n", 14));
485 must_pass(p_close(fd));
24bd5e55
MS
486
487 must_pass(git_filebuf_open(&file, test, GIT_FILEBUF_APPEND));
488 must_pass(git_filebuf_printf(&file, "%s\n", "libgit2 rocks"));
489 must_pass(git_filebuf_commit(&file));
490
f79026b4 491 must_pass(p_unlink(test));
24bd5e55
MS
492END_TEST
493
fe5babac
KS
494BEGIN_TEST(filebuf2, "make sure git_filebuf_write writes large buffer correctly")
495 git_filebuf file;
496 char test[] = "test";
497 unsigned char buf[4096 * 4]; /* 2 * WRITE_BUFFER_SIZE */
498
499 memset(buf, 0xfe, sizeof(buf));
500 must_pass(git_filebuf_open(&file, test, 0));
501 must_pass(git_filebuf_write(&file, buf, sizeof(buf)));
502 must_pass(git_filebuf_commit(&file));
503
f79026b4 504 must_pass(p_unlink(test));
fe5babac
KS
505END_TEST
506
7ea50f60
MS
507static char *empty_tmp_dir = "test_gitfo_rmdir_recurs_test";
508
51d00446 509static int setup_empty_tmp_dir(void)
7ea50f60
MS
510{
511 char path[GIT_PATH_MAX];
512
26911cbd 513 if (p_mkdir(empty_tmp_dir, 0755))
7ea50f60
MS
514 return -1;
515
516 git_path_join(path, empty_tmp_dir, "/one");
26911cbd 517 if (p_mkdir(path, 0755))
7ea50f60
MS
518 return -1;
519
520 git_path_join(path, empty_tmp_dir, "/one/two_one");
26911cbd 521 if (p_mkdir(path, 0755))
7ea50f60
MS
522 return -1;
523
524 git_path_join(path, empty_tmp_dir, "/one/two_two");
26911cbd 525 if (p_mkdir(path, 0755))
7ea50f60
MS
526 return -1;
527
528 git_path_join(path, empty_tmp_dir, "/one/two_two/three");
26911cbd 529 if (p_mkdir(path, 0755))
7ea50f60
MS
530 return -1;
531
532 git_path_join(path, empty_tmp_dir, "/two");
26911cbd 533 if (p_mkdir(path, 0755))
7ea50f60
MS
534 return -1;
535
536 return 0;
537}
538
539BEGIN_TEST(rmdir0, "make sure empty dir can be deleted recusively")
540 must_pass(setup_empty_tmp_dir());
858dba58 541 must_pass(git_futils_rmdir_r(empty_tmp_dir, 0));
7ea50f60
MS
542END_TEST
543
544BEGIN_TEST(rmdir1, "make sure non-empty dir cannot be deleted recusively")
545 char file[GIT_PATH_MAX];
1ee5fd90 546 int fd;
7ea50f60
MS
547
548 must_pass(setup_empty_tmp_dir());
549 git_path_join(file, empty_tmp_dir, "/two/file.txt");
1ee5fd90 550 fd = p_creat(file, 0755);
7ea50f60 551 must_pass(fd);
7ea50f60 552 must_pass(p_close(fd));
858dba58 553 must_fail(git_futils_rmdir_r(empty_tmp_dir, 0));
7ea50f60 554 must_pass(p_unlink(file));
858dba58 555 must_pass(git_futils_rmdir_r(empty_tmp_dir, 0));
7ea50f60
MS
556END_TEST
557
3dccfed1 558BEGIN_SUITE(core)
3dccfed1
VM
559 ADD_TEST(string0);
560 ADD_TEST(string1);
2a1732b4 561
3dccfed1
VM
562 ADD_TEST(vector0);
563 ADD_TEST(vector1);
476c42ac 564 ADD_TEST(vector2);
2a1732b4 565
3dccfed1
VM
566 ADD_TEST(path0);
567 ADD_TEST(path1);
568 ADD_TEST(path2);
3dccfed1
VM
569 ADD_TEST(path5);
570 ADD_TEST(path6);
2a1732b4 571
3dccfed1
VM
572 ADD_TEST(dirent0);
573 ADD_TEST(dirent1);
574 ADD_TEST(dirent2);
575 ADD_TEST(dirent3);
576 ADD_TEST(dirent4);
8102a961
CMN
577
578 ADD_TEST(filebuf0);
24bd5e55 579 ADD_TEST(filebuf1);
fe5babac 580 ADD_TEST(filebuf2);
7ea50f60
MS
581
582 ADD_TEST(rmdir0);
583 ADD_TEST(rmdir1);
3dccfed1 584END_SUITE