diff options
author | Ben Straub <bs@github.com> | 2013-11-14 14:05:52 -0800 |
---|---|---|
committer | Ben Straub <bs@github.com> | 2013-11-14 14:05:52 -0800 |
commit | 1782038144ef3413831801bb9c2f3038a84ac6f4 (patch) | |
tree | f074cc30890a20f5418c10fae1815ca516588a27 /tests/core | |
parent | 7b947bf5cc59eefa83c28eb5f5fd8434207ebb8b (diff) | |
download | libgit2-1782038144ef3413831801bb9c2f3038a84ac6f4.tar.gz |
Rename tests-clar to tests
Diffstat (limited to 'tests/core')
-rw-r--r-- | tests/core/bitvec.c | 64 | ||||
-rw-r--r-- | tests/core/buffer.c | 1039 | ||||
-rw-r--r-- | tests/core/caps.c | 31 | ||||
-rw-r--r-- | tests/core/copy.c | 126 | ||||
-rw-r--r-- | tests/core/dirent.c | 236 | ||||
-rw-r--r-- | tests/core/env.c | 303 | ||||
-rw-r--r-- | tests/core/errors.c | 87 | ||||
-rw-r--r-- | tests/core/filebuf.c | 126 | ||||
-rw-r--r-- | tests/core/hex.c | 22 | ||||
-rw-r--r-- | tests/core/iconv.c | 68 | ||||
-rw-r--r-- | tests/core/mkdir.c | 188 | ||||
-rw-r--r-- | tests/core/oid.c | 70 | ||||
-rw-r--r-- | tests/core/oidmap.c | 110 | ||||
-rw-r--r-- | tests/core/opts.c | 19 | ||||
-rw-r--r-- | tests/core/path.c | 583 | ||||
-rw-r--r-- | tests/core/pool.c | 145 | ||||
-rw-r--r-- | tests/core/posix.c | 99 | ||||
-rw-r--r-- | tests/core/rmdir.c | 98 | ||||
-rw-r--r-- | tests/core/sortedcache.c | 363 | ||||
-rw-r--r-- | tests/core/stat.c | 97 | ||||
-rw-r--r-- | tests/core/string.c | 41 | ||||
-rw-r--r-- | tests/core/strmap.c | 102 | ||||
-rw-r--r-- | tests/core/strtol.c | 37 | ||||
-rw-r--r-- | tests/core/vector.c | 275 |
24 files changed, 4329 insertions, 0 deletions
diff --git a/tests/core/bitvec.c b/tests/core/bitvec.c new file mode 100644 index 000000000..48d7b99f0 --- /dev/null +++ b/tests/core/bitvec.c @@ -0,0 +1,64 @@ +#include "clar_libgit2.h" +#include "bitvec.h" + +#if 0 +static void print_bitvec(git_bitvec *bv) +{ + int b; + + if (!bv->length) { + for (b = 63; b >= 0; --b) + fprintf(stderr, "%d", (bv->u.bits & (1ul << b)) ? 1 : 0); + } else { + for (b = bv->length * 8; b >= 0; --b) + fprintf(stderr, "%d", (bv->u.ptr[b >> 3] & (b & 0x0ff)) ? 1 : 0); + } + fprintf(stderr, "\n"); +} +#endif + +static void set_some_bits(git_bitvec *bv, size_t length) +{ + size_t i; + + for (i = 0; i < length; ++i) { + if (i % 3 == 0 || i % 7 == 0) + git_bitvec_set(bv, i, true); + } +} + +static void check_some_bits(git_bitvec *bv, size_t length) +{ + size_t i; + + for (i = 0; i < length; ++i) + cl_assert_equal_b(i % 3 == 0 || i % 7 == 0, git_bitvec_get(bv, i)); +} + +void test_core_bitvec__0(void) +{ + git_bitvec bv; + + cl_git_pass(git_bitvec_init(&bv, 32)); + set_some_bits(&bv, 16); + check_some_bits(&bv, 16); + git_bitvec_clear(&bv); + set_some_bits(&bv, 32); + check_some_bits(&bv, 32); + git_bitvec_clear(&bv); + set_some_bits(&bv, 64); + check_some_bits(&bv, 64); + git_bitvec_free(&bv); + + cl_git_pass(git_bitvec_init(&bv, 128)); + set_some_bits(&bv, 32); + check_some_bits(&bv, 32); + set_some_bits(&bv, 128); + check_some_bits(&bv, 128); + git_bitvec_free(&bv); + + cl_git_pass(git_bitvec_init(&bv, 4000)); + set_some_bits(&bv, 4000); + check_some_bits(&bv, 4000); + git_bitvec_free(&bv); +} diff --git a/tests/core/buffer.c b/tests/core/buffer.c new file mode 100644 index 000000000..11d173d49 --- /dev/null +++ b/tests/core/buffer.c @@ -0,0 +1,1039 @@ +#include "clar_libgit2.h" +#include "buffer.h" +#include "buf_text.h" +#include "hashsig.h" +#include "fileops.h" + +#define TESTSTR "Have you seen that? Have you seeeen that??" +const char *test_string = TESTSTR; +const char *test_string_x2 = TESTSTR TESTSTR; + +#define TESTSTR_4096 REP1024("1234") +#define TESTSTR_8192 REP1024("12341234") +const char *test_4096 = TESTSTR_4096; +const char *test_8192 = TESTSTR_8192; + +/* test basic data concatenation */ +void test_core_buffer__0(void) +{ + git_buf buf = GIT_BUF_INIT; + + cl_assert(buf.size == 0); + + git_buf_puts(&buf, test_string); + cl_assert(git_buf_oom(&buf) == 0); + cl_assert_equal_s(test_string, git_buf_cstr(&buf)); + + git_buf_puts(&buf, test_string); + cl_assert(git_buf_oom(&buf) == 0); + cl_assert_equal_s(test_string_x2, git_buf_cstr(&buf)); + + git_buf_free(&buf); +} + +/* test git_buf_printf */ +void test_core_buffer__1(void) +{ + git_buf buf = GIT_BUF_INIT; + + git_buf_printf(&buf, "%s %s %d ", "shoop", "da", 23); + cl_assert(git_buf_oom(&buf) == 0); + cl_assert_equal_s("shoop da 23 ", git_buf_cstr(&buf)); + + git_buf_printf(&buf, "%s %d", "woop", 42); + cl_assert(git_buf_oom(&buf) == 0); + cl_assert_equal_s("shoop da 23 woop 42", git_buf_cstr(&buf)); + + git_buf_free(&buf); +} + +/* more thorough test of concatenation options */ +void test_core_buffer__2(void) +{ + git_buf buf = GIT_BUF_INIT; + int i; + char data[128]; + + cl_assert(buf.size == 0); + + /* this must be safe to do */ + git_buf_free(&buf); + cl_assert(buf.size == 0); + cl_assert(buf.asize == 0); + + /* empty buffer should be empty string */ + cl_assert_equal_s("", git_buf_cstr(&buf)); + cl_assert(buf.size == 0); + /* cl_assert(buf.asize == 0); -- should not assume what git_buf does */ + + /* free should set us back to the beginning */ + git_buf_free(&buf); + cl_assert(buf.size == 0); + cl_assert(buf.asize == 0); + + /* add letter */ + git_buf_putc(&buf, '+'); + cl_assert(git_buf_oom(&buf) == 0); + cl_assert_equal_s("+", git_buf_cstr(&buf)); + + /* add letter again */ + git_buf_putc(&buf, '+'); + cl_assert(git_buf_oom(&buf) == 0); + cl_assert_equal_s("++", git_buf_cstr(&buf)); + + /* let's try that a few times */ + for (i = 0; i < 16; ++i) { + git_buf_putc(&buf, '+'); + cl_assert(git_buf_oom(&buf) == 0); + } + cl_assert_equal_s("++++++++++++++++++", git_buf_cstr(&buf)); + + git_buf_free(&buf); + + /* add data */ + git_buf_put(&buf, "xo", 2); + cl_assert(git_buf_oom(&buf) == 0); + cl_assert_equal_s("xo", git_buf_cstr(&buf)); + + /* add letter again */ + git_buf_put(&buf, "xo", 2); + cl_assert(git_buf_oom(&buf) == 0); + cl_assert_equal_s("xoxo", git_buf_cstr(&buf)); + + /* let's try that a few times */ + for (i = 0; i < 16; ++i) { + git_buf_put(&buf, "xo", 2); + cl_assert(git_buf_oom(&buf) == 0); + } + cl_assert_equal_s("xoxoxoxoxoxoxoxoxoxoxoxoxoxoxoxoxoxo", + git_buf_cstr(&buf)); + + git_buf_free(&buf); + + /* set to string */ + git_buf_sets(&buf, test_string); + cl_assert(git_buf_oom(&buf) == 0); + cl_assert_equal_s(test_string, git_buf_cstr(&buf)); + + /* append string */ + git_buf_puts(&buf, test_string); + cl_assert(git_buf_oom(&buf) == 0); + cl_assert_equal_s(test_string_x2, git_buf_cstr(&buf)); + + /* set to string again (should overwrite - not append) */ + git_buf_sets(&buf, test_string); + cl_assert(git_buf_oom(&buf) == 0); + cl_assert_equal_s(test_string, git_buf_cstr(&buf)); + + /* test clear */ + git_buf_clear(&buf); + cl_assert_equal_s("", git_buf_cstr(&buf)); + + git_buf_free(&buf); + + /* test extracting data into buffer */ + git_buf_puts(&buf, REP4("0123456789")); + cl_assert(git_buf_oom(&buf) == 0); + + git_buf_copy_cstr(data, sizeof(data), &buf); + cl_assert_equal_s(REP4("0123456789"), data); + git_buf_copy_cstr(data, 11, &buf); + cl_assert_equal_s("0123456789", data); + git_buf_copy_cstr(data, 3, &buf); + cl_assert_equal_s("01", data); + git_buf_copy_cstr(data, 1, &buf); + cl_assert_equal_s("", data); + + git_buf_copy_cstr(data, sizeof(data), &buf); + cl_assert_equal_s(REP4("0123456789"), data); + + git_buf_sets(&buf, REP256("x")); + git_buf_copy_cstr(data, sizeof(data), &buf); + /* since sizeof(data) == 128, only 127 bytes should be copied */ + cl_assert_equal_s(REP4(REP16("x")) REP16("x") REP16("x") + REP16("x") "xxxxxxxxxxxxxxx", data); + + git_buf_free(&buf); + + git_buf_copy_cstr(data, sizeof(data), &buf); + cl_assert_equal_s("", data); +} + +/* let's do some tests with larger buffers to push our limits */ +void test_core_buffer__3(void) +{ + git_buf buf = GIT_BUF_INIT; + + /* set to string */ + git_buf_set(&buf, test_4096, 4096); + cl_assert(git_buf_oom(&buf) == 0); + cl_assert_equal_s(test_4096, git_buf_cstr(&buf)); + + /* append string */ + git_buf_puts(&buf, test_4096); + cl_assert(git_buf_oom(&buf) == 0); + cl_assert_equal_s(test_8192, git_buf_cstr(&buf)); + + /* set to string again (should overwrite - not append) */ + git_buf_set(&buf, test_4096, 4096); + cl_assert(git_buf_oom(&buf) == 0); + cl_assert_equal_s(test_4096, git_buf_cstr(&buf)); + + git_buf_free(&buf); +} + +/* let's try some producer/consumer tests */ +void test_core_buffer__4(void) +{ + git_buf buf = GIT_BUF_INIT; + int i; + + for (i = 0; i < 10; ++i) { + git_buf_puts(&buf, "1234"); /* add 4 */ + cl_assert(git_buf_oom(&buf) == 0); + git_buf_consume(&buf, buf.ptr + 2); /* eat the first two */ + cl_assert(strlen(git_buf_cstr(&buf)) == (size_t)((i + 1) * 2)); + } + /* we have appended 1234 10x and removed the first 20 letters */ + cl_assert_equal_s("12341234123412341234", git_buf_cstr(&buf)); + + git_buf_consume(&buf, NULL); + cl_assert_equal_s("12341234123412341234", git_buf_cstr(&buf)); + + git_buf_consume(&buf, "invalid pointer"); + cl_assert_equal_s("12341234123412341234", git_buf_cstr(&buf)); + + git_buf_consume(&buf, buf.ptr); + cl_assert_equal_s("12341234123412341234", git_buf_cstr(&buf)); + + git_buf_consume(&buf, buf.ptr + 1); + cl_assert_equal_s("2341234123412341234", git_buf_cstr(&buf)); + + git_buf_consume(&buf, buf.ptr + buf.size); + cl_assert_equal_s("", git_buf_cstr(&buf)); + + git_buf_free(&buf); +} + + +static void +check_buf_append( + const char* data_a, + const char* data_b, + const char* expected_data, + size_t expected_size, + size_t expected_asize) +{ + git_buf tgt = GIT_BUF_INIT; + + git_buf_sets(&tgt, data_a); + cl_assert(git_buf_oom(&tgt) == 0); + git_buf_puts(&tgt, data_b); + cl_assert(git_buf_oom(&tgt) == 0); + cl_assert_equal_s(expected_data, git_buf_cstr(&tgt)); + cl_assert(tgt.size == expected_size); + if (expected_asize > 0) + cl_assert(tgt.asize == expected_asize); + + git_buf_free(&tgt); +} + +static void +check_buf_append_abc( + const char* buf_a, + const char* buf_b, + const char* buf_c, + const char* expected_ab, + const char* expected_abc, + const char* expected_abca, + const char* expected_abcab, + const char* expected_abcabc) +{ + git_buf buf = GIT_BUF_INIT; + + git_buf_sets(&buf, buf_a); + cl_assert(git_buf_oom(&buf) == 0); + cl_assert_equal_s(buf_a, git_buf_cstr(&buf)); + + git_buf_puts(&buf, buf_b); + cl_assert(git_buf_oom(&buf) == 0); + cl_assert_equal_s(expected_ab, git_buf_cstr(&buf)); + + git_buf_puts(&buf, buf_c); + cl_assert(git_buf_oom(&buf) == 0); + cl_assert_equal_s(expected_abc, git_buf_cstr(&buf)); + + git_buf_puts(&buf, buf_a); + cl_assert(git_buf_oom(&buf) == 0); + cl_assert_equal_s(expected_abca, git_buf_cstr(&buf)); + + git_buf_puts(&buf, buf_b); + cl_assert(git_buf_oom(&buf) == 0); + cl_assert_equal_s(expected_abcab, git_buf_cstr(&buf)); + + git_buf_puts(&buf, buf_c); + cl_assert(git_buf_oom(&buf) == 0); + cl_assert_equal_s(expected_abcabc, git_buf_cstr(&buf)); + + git_buf_free(&buf); +} + +/* more variations on append tests */ +void test_core_buffer__5(void) +{ + check_buf_append("", "", "", 0, 8); + check_buf_append("a", "", "a", 1, 8); + check_buf_append("", "a", "a", 1, 8); + check_buf_append("", "a", "a", 1, 8); + check_buf_append("a", "", "a", 1, 8); + check_buf_append("a", "b", "ab", 2, 8); + check_buf_append("", "abcdefgh", "abcdefgh", 8, 16); + check_buf_append("abcdefgh", "", "abcdefgh", 8, 16); + + /* buffer with starting asize will grow to: + * 1 -> 2, 2 -> 3, 3 -> 5, 4 -> 6, 5 -> 8, 6 -> 9, + * 7 -> 11, 8 -> 12, 9 -> 14, 10 -> 15, 11 -> 17, 12 -> 18, + * 13 -> 20, 14 -> 21, 15 -> 23, 16 -> 24, 17 -> 26, 18 -> 27, + * 19 -> 29, 20 -> 30, 21 -> 32, 22 -> 33, 23 -> 35, 24 -> 36, + * ... + * follow sequence until value > target size, + * then round up to nearest multiple of 8. + */ + + check_buf_append("abcdefgh", "/", "abcdefgh/", 9, 16); + check_buf_append("abcdefgh", "ijklmno", "abcdefghijklmno", 15, 16); + check_buf_append("abcdefgh", "ijklmnop", "abcdefghijklmnop", 16, 24); + check_buf_append("0123456789", "0123456789", + "01234567890123456789", 20, 24); + check_buf_append(REP16("x"), REP16("o"), + REP16("x") REP16("o"), 32, 40); + + check_buf_append(test_4096, "", test_4096, 4096, 4104); + check_buf_append(test_4096, test_4096, test_8192, 8192, 9240); + + /* check sequences of appends */ + check_buf_append_abc("a", "b", "c", + "ab", "abc", "abca", "abcab", "abcabc"); + check_buf_append_abc("a1", "b2", "c3", + "a1b2", "a1b2c3", "a1b2c3a1", + "a1b2c3a1b2", "a1b2c3a1b2c3"); + check_buf_append_abc("a1/", "b2/", "c3/", + "a1/b2/", "a1/b2/c3/", "a1/b2/c3/a1/", + "a1/b2/c3/a1/b2/", "a1/b2/c3/a1/b2/c3/"); +} + +/* test swap */ +void test_core_buffer__6(void) +{ + git_buf a = GIT_BUF_INIT; + git_buf b = GIT_BUF_INIT; + + git_buf_sets(&a, "foo"); + cl_assert(git_buf_oom(&a) == 0); + git_buf_sets(&b, "bar"); + cl_assert(git_buf_oom(&b) == 0); + + cl_assert_equal_s("foo", git_buf_cstr(&a)); + cl_assert_equal_s("bar", git_buf_cstr(&b)); + + git_buf_swap(&a, &b); + + cl_assert_equal_s("bar", git_buf_cstr(&a)); + cl_assert_equal_s("foo", git_buf_cstr(&b)); + + git_buf_free(&a); + git_buf_free(&b); +} + + +/* test detach/attach data */ +void test_core_buffer__7(void) +{ + const char *fun = "This is fun"; + git_buf a = GIT_BUF_INIT; + char *b = NULL; + + git_buf_sets(&a, "foo"); + cl_assert(git_buf_oom(&a) == 0); + cl_assert_equal_s("foo", git_buf_cstr(&a)); + + b = git_buf_detach(&a); + + cl_assert_equal_s("foo", b); + cl_assert_equal_s("", a.ptr); + git__free(b); + + b = git_buf_detach(&a); + + cl_assert_equal_s(NULL, b); + cl_assert_equal_s("", a.ptr); + + git_buf_free(&a); + + b = git__strdup(fun); + git_buf_attach(&a, b, 0); + + cl_assert_equal_s(fun, a.ptr); + cl_assert(a.size == strlen(fun)); + cl_assert(a.asize == strlen(fun) + 1); + + git_buf_free(&a); + + b = git__strdup(fun); + git_buf_attach(&a, b, strlen(fun) + 1); + + cl_assert_equal_s(fun, a.ptr); + cl_assert(a.size == strlen(fun)); + cl_assert(a.asize == strlen(fun) + 1); + + git_buf_free(&a); +} + + +static void +check_joinbuf_2( + const char *a, + const char *b, + const char *expected) +{ + char sep = '/'; + git_buf buf = GIT_BUF_INIT; + + git_buf_join(&buf, sep, a, b); + cl_assert(git_buf_oom(&buf) == 0); + cl_assert_equal_s(expected, git_buf_cstr(&buf)); + git_buf_free(&buf); +} + +static void +check_joinbuf_n_2( + const char *a, + const char *b, + const char *expected) +{ + char sep = '/'; + git_buf buf = GIT_BUF_INIT; + + git_buf_sets(&buf, a); + cl_assert(git_buf_oom(&buf) == 0); + + git_buf_join_n(&buf, sep, 1, b); + cl_assert(git_buf_oom(&buf) == 0); + cl_assert_equal_s(expected, git_buf_cstr(&buf)); + + git_buf_free(&buf); +} + +static void +check_joinbuf_n_4( + const char *a, + const char *b, + const char *c, + const char *d, + const char *expected) +{ + char sep = ';'; + git_buf buf = GIT_BUF_INIT; + git_buf_join_n(&buf, sep, 4, a, b, c, d); + cl_assert(git_buf_oom(&buf) == 0); + cl_assert_equal_s(expected, git_buf_cstr(&buf)); + git_buf_free(&buf); +} + +/* test join */ +void test_core_buffer__8(void) +{ + git_buf a = GIT_BUF_INIT; + + git_buf_join_n(&a, '/', 1, "foo"); + cl_assert(git_buf_oom(&a) == 0); + cl_assert_equal_s("foo", git_buf_cstr(&a)); + + git_buf_join_n(&a, '/', 1, "bar"); + cl_assert(git_buf_oom(&a) == 0); + cl_assert_equal_s("foo/bar", git_buf_cstr(&a)); + + git_buf_join_n(&a, '/', 1, "baz"); + cl_assert(git_buf_oom(&a) == 0); + cl_assert_equal_s("foo/bar/baz", git_buf_cstr(&a)); + + git_buf_free(&a); + + check_joinbuf_2(NULL, "", ""); + check_joinbuf_2(NULL, "a", "a"); + check_joinbuf_2(NULL, "/a", "/a"); + check_joinbuf_2("", "", ""); + check_joinbuf_2("", "a", "a"); + check_joinbuf_2("", "/a", "/a"); + check_joinbuf_2("a", "", "a/"); + check_joinbuf_2("a", "/", "a/"); + check_joinbuf_2("a", "b", "a/b"); + check_joinbuf_2("/", "a", "/a"); + check_joinbuf_2("/", "", "/"); + check_joinbuf_2("/a", "/b", "/a/b"); + check_joinbuf_2("/a", "/b/", "/a/b/"); + check_joinbuf_2("/a/", "b/", "/a/b/"); + check_joinbuf_2("/a/", "/b/", "/a/b/"); + check_joinbuf_2("/a/", "//b/", "/a/b/"); + check_joinbuf_2("/abcd", "/defg", "/abcd/defg"); + check_joinbuf_2("/abcd", "/defg/", "/abcd/defg/"); + check_joinbuf_2("/abcd/", "defg/", "/abcd/defg/"); + check_joinbuf_2("/abcd/", "/defg/", "/abcd/defg/"); + + check_joinbuf_n_2("", "", ""); + check_joinbuf_n_2("", "a", "a"); + check_joinbuf_n_2("", "/a", "/a"); + check_joinbuf_n_2("a", "", "a/"); + check_joinbuf_n_2("a", "/", "a/"); + check_joinbuf_n_2("a", "b", "a/b"); + check_joinbuf_n_2("/", "a", "/a"); + check_joinbuf_n_2("/", "", "/"); + check_joinbuf_n_2("/a", "/b", "/a/b"); + check_joinbuf_n_2("/a", "/b/", "/a/b/"); + check_joinbuf_n_2("/a/", "b/", "/a/b/"); + check_joinbuf_n_2("/a/", "/b/", "/a/b/"); + check_joinbuf_n_2("/abcd", "/defg", "/abcd/defg"); + check_joinbuf_n_2("/abcd", "/defg/", "/abcd/defg/"); + check_joinbuf_n_2("/abcd/", "defg/", "/abcd/defg/"); + check_joinbuf_n_2("/abcd/", "/defg/", "/abcd/defg/"); + + check_joinbuf_n_4("", "", "", "", ""); + check_joinbuf_n_4("", "a", "", "", "a;"); + check_joinbuf_n_4("a", "", "", "", "a;"); + check_joinbuf_n_4("", "", "", "a", "a"); + check_joinbuf_n_4("a", "b", "", ";c;d;", "a;b;c;d;"); + check_joinbuf_n_4("a", "b", "", ";c;d", "a;b;c;d"); + check_joinbuf_n_4("abcd", "efgh", "ijkl", "mnop", "abcd;efgh;ijkl;mnop"); + check_joinbuf_n_4("abcd;", "efgh;", "ijkl;", "mnop;", "abcd;efgh;ijkl;mnop;"); + check_joinbuf_n_4(";abcd;", ";efgh;", ";ijkl;", ";mnop;", ";abcd;efgh;ijkl;mnop;"); +} + +void test_core_buffer__9(void) +{ + git_buf buf = GIT_BUF_INIT; + + /* just some exhaustive tests of various separator placement */ + char *a[] = { "", "-", "a-", "-a", "-a-" }; + char *b[] = { "", "-", "b-", "-b", "-b-" }; + char sep[] = { 0, '-', '/' }; + char *expect_null[] = { "", "-", "a-", "-a", "-a-", + "-", "--", "a--", "-a-", "-a--", + "b-", "-b-", "a-b-", "-ab-", "-a-b-", + "-b", "--b", "a--b", "-a-b", "-a--b", + "-b-", "--b-", "a--b-", "-a-b-", "-a--b-" }; + char *expect_dash[] = { "", "-", "a-", "-a-", "-a-", + "-", "-", "a-", "-a-", "-a-", + "b-", "-b-", "a-b-", "-a-b-", "-a-b-", + "-b", "-b", "a-b", "-a-b", "-a-b", + "-b-", "-b-", "a-b-", "-a-b-", "-a-b-" }; + char *expect_slas[] = { "", "-/", "a-/", "-a/", "-a-/", + "-", "-/-", "a-/-", "-a/-", "-a-/-", + "b-", "-/b-", "a-/b-", "-a/b-", "-a-/b-", + "-b", "-/-b", "a-/-b", "-a/-b", "-a-/-b", + "-b-", "-/-b-", "a-/-b-", "-a/-b-", "-a-/-b-" }; + char **expect_values[] = { expect_null, expect_dash, expect_slas }; + char separator, **expect; + unsigned int s, i, j; + + for (s = 0; s < sizeof(sep) / sizeof(char); ++s) { + separator = sep[s]; + expect = expect_values[s]; + + for (j = 0; j < sizeof(b) / sizeof(char*); ++j) { + for (i = 0; i < sizeof(a) / sizeof(char*); ++i) { + git_buf_join(&buf, separator, a[i], b[j]); + cl_assert_equal_s(*expect, buf.ptr); + expect++; + } + } + } + + git_buf_free(&buf); +} + +void test_core_buffer__10(void) +{ + git_buf a = GIT_BUF_INIT; + + cl_git_pass(git_buf_join_n(&a, '/', 1, "test")); + cl_assert_equal_s(a.ptr, "test"); + cl_git_pass(git_buf_join_n(&a, '/', 1, "string")); + cl_assert_equal_s(a.ptr, "test/string"); + git_buf_clear(&a); + cl_git_pass(git_buf_join_n(&a, '/', 3, "test", "string", "join")); + cl_assert_equal_s(a.ptr, "test/string/join"); + cl_git_pass(git_buf_join_n(&a, '/', 2, a.ptr, "more")); + cl_assert_equal_s(a.ptr, "test/string/join/test/string/join/more"); + + git_buf_free(&a); +} + +void test_core_buffer__11(void) +{ + git_buf a = GIT_BUF_INIT; + git_strarray t; + char *t1[] = { "nothing", "in", "common" }; + char *t2[] = { "something", "something else", "some other" }; + char *t3[] = { "something", "some fun", "no fun" }; + char *t4[] = { "happy", "happier", "happiest" }; + char *t5[] = { "happiest", "happier", "happy" }; + char *t6[] = { "no", "nope", "" }; + char *t7[] = { "", "doesn't matter" }; + + t.strings = t1; + t.count = 3; + cl_git_pass(git_buf_text_common_prefix(&a, &t)); + cl_assert_equal_s(a.ptr, ""); + + t.strings = t2; + t.count = 3; + cl_git_pass(git_buf_text_common_prefix(&a, &t)); + cl_assert_equal_s(a.ptr, "some"); + + t.strings = t3; + t.count = 3; + cl_git_pass(git_buf_text_common_prefix(&a, &t)); + cl_assert_equal_s(a.ptr, ""); + + t.strings = t4; + t.count = 3; + cl_git_pass(git_buf_text_common_prefix(&a, &t)); + cl_assert_equal_s(a.ptr, "happ"); + + t.strings = t5; + t.count = 3; + cl_git_pass(git_buf_text_common_prefix(&a, &t)); + cl_assert_equal_s(a.ptr, "happ"); + + t.strings = t6; + t.count = 3; + cl_git_pass(git_buf_text_common_prefix(&a, &t)); + cl_assert_equal_s(a.ptr, ""); + + t.strings = t7; + t.count = 3; + cl_git_pass(git_buf_text_common_prefix(&a, &t)); + cl_assert_equal_s(a.ptr, ""); + + git_buf_free(&a); +} + +void test_core_buffer__rfind_variants(void) +{ + git_buf a = GIT_BUF_INIT; + ssize_t len; + + cl_git_pass(git_buf_sets(&a, "/this/is/it/")); + + len = (ssize_t)git_buf_len(&a); + + cl_assert(git_buf_rfind(&a, '/') == len - 1); + cl_assert(git_buf_rfind_next(&a, '/') == len - 4); + + cl_assert(git_buf_rfind(&a, 'i') == len - 3); + cl_assert(git_buf_rfind_next(&a, 'i') == len - 3); + + cl_assert(git_buf_rfind(&a, 'h') == 2); + cl_assert(git_buf_rfind_next(&a, 'h') == 2); + + cl_assert(git_buf_rfind(&a, 'q') == -1); + cl_assert(git_buf_rfind_next(&a, 'q') == -1); + + git_buf_free(&a); +} + +void test_core_buffer__puts_escaped(void) +{ + git_buf a = GIT_BUF_INIT; + + git_buf_clear(&a); + cl_git_pass(git_buf_text_puts_escaped(&a, "this is a test", "", "")); + cl_assert_equal_s("this is a test", a.ptr); + + git_buf_clear(&a); + cl_git_pass(git_buf_text_puts_escaped(&a, "this is a test", "t", "\\")); + cl_assert_equal_s("\\this is a \\tes\\t", a.ptr); + + git_buf_clear(&a); + cl_git_pass(git_buf_text_puts_escaped(&a, "this is a test", "i ", "__")); + cl_assert_equal_s("th__is__ __is__ a__ test", a.ptr); + + git_buf_clear(&a); + cl_git_pass(git_buf_text_puts_escape_regex(&a, "^match\\s*[A-Z]+.*")); + cl_assert_equal_s("\\^match\\\\s\\*\\[A-Z\\]\\+\\.\\*", a.ptr); + + git_buf_free(&a); +} + +static void assert_unescape(char *expected, char *to_unescape) { + git_buf buf = GIT_BUF_INIT; + + cl_git_pass(git_buf_sets(&buf, to_unescape)); + git_buf_text_unescape(&buf); + cl_assert_equal_s(expected, buf.ptr); + cl_assert_equal_sz(strlen(expected), buf.size); + + git_buf_free(&buf); +} + +void test_core_buffer__unescape(void) +{ + assert_unescape("Escaped\\", "Es\\ca\\ped\\"); + assert_unescape("Es\\caped\\", "Es\\\\ca\\ped\\\\"); + assert_unescape("\\", "\\"); + assert_unescape("\\", "\\\\"); + assert_unescape("", ""); +} + +void test_core_buffer__base64(void) +{ + git_buf buf = GIT_BUF_INIT; + + /* t h i s + * 0x 74 68 69 73 + * 0b 01110100 01101000 01101001 01110011 + * 0b 011101 000110 100001 101001 011100 110000 + * 0x 1d 06 21 29 1c 30 + * d G h p c w + */ + cl_git_pass(git_buf_put_base64(&buf, "this", 4)); + cl_assert_equal_s("dGhpcw==", buf.ptr); + + git_buf_clear(&buf); + cl_git_pass(git_buf_put_base64(&buf, "this!", 5)); + cl_assert_equal_s("dGhpcyE=", buf.ptr); + + git_buf_clear(&buf); + cl_git_pass(git_buf_put_base64(&buf, "this!\n", 6)); + cl_assert_equal_s("dGhpcyEK", buf.ptr); + + git_buf_free(&buf); +} + +void test_core_buffer__classify_with_utf8(void) +{ + char *data0 = "Simple text\n"; + size_t data0len = 12; + char *data1 = "Is that UTF-8 data I see…\nYep!\n"; + size_t data1len = 31; + char *data2 = "Internal NUL!!!\000\n\nI see you!\n"; + size_t data2len = 29; + char *data3 = "\xef\xbb\xbfThis is UTF-8 with a BOM.\n"; + size_t data3len = 20; + git_buf b; + + b.ptr = data0; b.size = b.asize = data0len; + cl_assert(!git_buf_text_is_binary(&b)); + cl_assert(!git_buf_text_contains_nul(&b)); + + b.ptr = data1; b.size = b.asize = data1len; + cl_assert(git_buf_text_is_binary(&b)); + cl_assert(!git_buf_text_contains_nul(&b)); + + b.ptr = data2; b.size = b.asize = data2len; + cl_assert(git_buf_text_is_binary(&b)); + cl_assert(git_buf_text_contains_nul(&b)); + + b.ptr = data3; b.size = b.asize = data3len; + cl_assert(!git_buf_text_is_binary(&b)); + cl_assert(!git_buf_text_contains_nul(&b)); +} + +#define SIMILARITY_TEST_DATA_1 \ + "000\n001\n002\n003\n004\n005\n006\n007\n008\n009\n" \ + "010\n011\n012\n013\n014\n015\n016\n017\n018\n019\n" \ + "020\n021\n022\n023\n024\n025\n026\n027\n028\n029\n" \ + "030\n031\n032\n033\n034\n035\n036\n037\n038\n039\n" \ + "040\n041\n042\n043\n044\n045\n046\n047\n048\n049\n" + +void test_core_buffer__similarity_metric(void) +{ + git_hashsig *a, *b; + git_buf buf = GIT_BUF_INIT; + int sim; + + /* in the first case, we compare data to itself and expect 100% match */ + + cl_git_pass(git_buf_sets(&buf, SIMILARITY_TEST_DATA_1)); + cl_git_pass(git_hashsig_create(&a, buf.ptr, buf.size, GIT_HASHSIG_NORMAL)); + cl_git_pass(git_hashsig_create(&b, buf.ptr, buf.size, GIT_HASHSIG_NORMAL)); + + cl_assert_equal_i(100, git_hashsig_compare(a, b)); + + git_hashsig_free(a); + git_hashsig_free(b); + + /* if we change just a single byte, how much does that change magnify? */ + + cl_git_pass(git_buf_sets(&buf, SIMILARITY_TEST_DATA_1)); + cl_git_pass(git_hashsig_create(&a, buf.ptr, buf.size, GIT_HASHSIG_NORMAL)); + cl_git_pass(git_buf_sets(&buf, + "000\n001\n002\n003\n004\n005\n006\n007\n008\n009\n" \ + "010\n011\n012\n013\n014\n015\n016\n017\n018\n019\n" \ + "x020x\n021\n022\n023\n024\n025\n026\n027\n028\n029\n" \ + "030\n031\n032\n033\n034\n035\n036\n037\n038\n039\n" \ + "040\n041\n042\n043\n044\n045\n046\n047\n048\n049\n" + )); + cl_git_pass(git_hashsig_create(&b, buf.ptr, buf.size, GIT_HASHSIG_NORMAL)); + + sim = git_hashsig_compare(a, b); + + cl_assert_in_range(95, sim, 100); /* expect >95% similarity */ + + git_hashsig_free(a); + git_hashsig_free(b); + + /* let's try comparing data to a superset of itself */ + + cl_git_pass(git_buf_sets(&buf, SIMILARITY_TEST_DATA_1)); + cl_git_pass(git_hashsig_create(&a, buf.ptr, buf.size, GIT_HASHSIG_NORMAL)); + cl_git_pass(git_buf_sets(&buf, SIMILARITY_TEST_DATA_1 + "050\n051\n052\n053\n054\n055\n056\n057\n058\n059\n")); + cl_git_pass(git_hashsig_create(&b, buf.ptr, buf.size, GIT_HASHSIG_NORMAL)); + + sim = git_hashsig_compare(a, b); + /* 20% lines added ~= 10% lines changed */ + + cl_assert_in_range(85, sim, 95); /* expect similarity around 90% */ + + git_hashsig_free(a); + git_hashsig_free(b); + + /* what if we keep about half the original data and add half new */ + + cl_git_pass(git_buf_sets(&buf, SIMILARITY_TEST_DATA_1)); + cl_git_pass(git_hashsig_create(&a, buf.ptr, buf.size, GIT_HASHSIG_NORMAL)); + cl_git_pass(git_buf_sets(&buf, + "000\n001\n002\n003\n004\n005\n006\n007\n008\n009\n" \ + "010\n011\n012\n013\n014\n015\n016\n017\n018\n019\n" \ + "020x\n021\n022\n023\n024\n" \ + "x25\nx26\nx27\nx28\nx29\n" \ + "x30\nx31\nx32\nx33\nx34\nx35\nx36\nx37\nx38\nx39\n" \ + "x40\nx41\nx42\nx43\nx44\nx45\nx46\nx47\nx48\nx49\n" + )); + cl_git_pass(git_hashsig_create(&b, buf.ptr, buf.size, GIT_HASHSIG_NORMAL)); + + sim = git_hashsig_compare(a, b); + /* 50% lines changed */ + + cl_assert_in_range(40, sim, 60); /* expect in the 40-60% similarity range */ + + git_hashsig_free(a); + git_hashsig_free(b); + + /* lastly, let's check that we can hash file content as well */ + + cl_git_pass(git_buf_sets(&buf, SIMILARITY_TEST_DATA_1)); + cl_git_pass(git_hashsig_create(&a, buf.ptr, buf.size, GIT_HASHSIG_NORMAL)); + + cl_git_pass(git_futils_mkdir("scratch", NULL, 0755, GIT_MKDIR_PATH)); + cl_git_mkfile("scratch/testdata", SIMILARITY_TEST_DATA_1); + cl_git_pass(git_hashsig_create_fromfile( + &b, "scratch/testdata", GIT_HASHSIG_NORMAL)); + + cl_assert_equal_i(100, git_hashsig_compare(a, b)); + + git_hashsig_free(a); + git_hashsig_free(b); + + git_buf_free(&buf); + git_futils_rmdir_r("scratch", NULL, GIT_RMDIR_REMOVE_FILES); +} + + +void test_core_buffer__similarity_metric_whitespace(void) +{ + git_hashsig *a, *b; + git_buf buf = GIT_BUF_INIT; + int sim, i, j; + git_hashsig_option_t opt; + const char *tabbed = + " for (s = 0; s < sizeof(sep) / sizeof(char); ++s) {\n" + " separator = sep[s];\n" + " expect = expect_values[s];\n" + "\n" + " for (j = 0; j < sizeof(b) / sizeof(char*); ++j) {\n" + " for (i = 0; i < sizeof(a) / sizeof(char*); ++i) {\n" + " git_buf_join(&buf, separator, a[i], b[j]);\n" + " cl_assert_equal_s(*expect, buf.ptr);\n" + " expect++;\n" + " }\n" + " }\n" + " }\n"; + const char *spaced = + " for (s = 0; s < sizeof(sep) / sizeof(char); ++s) {\n" + " separator = sep[s];\n" + " expect = expect_values[s];\n" + "\n" + " for (j = 0; j < sizeof(b) / sizeof(char*); ++j) {\n" + " for (i = 0; i < sizeof(a) / sizeof(char*); ++i) {\n" + " git_buf_join(&buf, separator, a[i], b[j]);\n" + " cl_assert_equal_s(*expect, buf.ptr);\n" + " expect++;\n" + " }\n" + " }\n" + " }\n"; + const char *crlf_spaced2 = + " for (s = 0; s < sizeof(sep) / sizeof(char); ++s) {\r\n" + " separator = sep[s];\r\n" + " expect = expect_values[s];\r\n" + "\r\n" + " for (j = 0; j < sizeof(b) / sizeof(char*); ++j) {\r\n" + " for (i = 0; i < sizeof(a) / sizeof(char*); ++i) {\r\n" + " git_buf_join(&buf, separator, a[i], b[j]);\r\n" + " cl_assert_equal_s(*expect, buf.ptr);\r\n" + " expect++;\r\n" + " }\r\n" + " }\r\n" + " }\r\n"; + const char *text[3] = { tabbed, spaced, crlf_spaced2 }; + + /* let's try variations of our own code with whitespace changes */ + + for (opt = GIT_HASHSIG_NORMAL; opt <= GIT_HASHSIG_SMART_WHITESPACE; ++opt) { + for (i = 0; i < 3; ++i) { + for (j = 0; j < 3; ++j) { + cl_git_pass(git_buf_sets(&buf, text[i])); + cl_git_pass(git_hashsig_create(&a, buf.ptr, buf.size, opt)); + + cl_git_pass(git_buf_sets(&buf, text[j])); + cl_git_pass(git_hashsig_create(&b, buf.ptr, buf.size, opt)); + + sim = git_hashsig_compare(a, b); + + if (opt == GIT_HASHSIG_NORMAL) { + if (i == j) + cl_assert_equal_i(100, sim); + else + cl_assert_in_range(0, sim, 30); /* pretty different */ + } else { + cl_assert_equal_i(100, sim); + } + + git_hashsig_free(a); + git_hashsig_free(b); + } + } + } + + git_buf_free(&buf); +} + +#include "../filter/crlf.h" + +#define check_buf(expected,buf) do { \ + cl_assert_equal_s(expected, buf.ptr); \ + cl_assert_equal_sz(strlen(expected), buf.size); } while (0) + +void test_core_buffer__lf_and_crlf_conversions(void) +{ + git_buf src = GIT_BUF_INIT, tgt = GIT_BUF_INIT; + + /* LF source */ + + git_buf_sets(&src, "lf\nlf\nlf\nlf\n"); + + cl_git_pass(git_buf_text_lf_to_crlf(&tgt, &src)); + check_buf("lf\r\nlf\r\nlf\r\nlf\r\n", tgt); + + cl_git_pass(git_buf_text_crlf_to_lf(&tgt, &src)); + check_buf(src.ptr, tgt); + + git_buf_sets(&src, "\nlf\nlf\nlf\nlf\nlf"); + + cl_git_pass(git_buf_text_lf_to_crlf(&tgt, &src)); + check_buf("\r\nlf\r\nlf\r\nlf\r\nlf\r\nlf", tgt); + + cl_git_pass(git_buf_text_crlf_to_lf(&tgt, &src)); + check_buf(src.ptr, tgt); + + /* CRLF source */ + + git_buf_sets(&src, "crlf\r\ncrlf\r\ncrlf\r\ncrlf\r\n"); + + cl_git_pass(git_buf_text_lf_to_crlf(&tgt, &src)); + check_buf("crlf\r\ncrlf\r\ncrlf\r\ncrlf\r\n", tgt); + check_buf(src.ptr, tgt); + + cl_git_pass(git_buf_text_crlf_to_lf(&tgt, &src)); + check_buf("crlf\ncrlf\ncrlf\ncrlf\n", tgt); + + git_buf_sets(&src, "\r\ncrlf\r\ncrlf\r\ncrlf\r\ncrlf\r\ncrlf"); + + cl_git_pass(git_buf_text_lf_to_crlf(&tgt, &src)); + check_buf("\r\ncrlf\r\ncrlf\r\ncrlf\r\ncrlf\r\ncrlf", tgt); + check_buf(src.ptr, tgt); + + cl_git_pass(git_buf_text_crlf_to_lf(&tgt, &src)); + check_buf("\ncrlf\ncrlf\ncrlf\ncrlf\ncrlf", tgt); + + /* CRLF in LF text */ + + git_buf_sets(&src, "\nlf\nlf\ncrlf\r\nlf\nlf\ncrlf\r\n"); + + cl_git_pass(git_buf_text_lf_to_crlf(&tgt, &src)); + check_buf("\r\nlf\r\nlf\r\ncrlf\r\nlf\r\nlf\r\ncrlf\r\n", tgt); + cl_git_pass(git_buf_text_crlf_to_lf(&tgt, &src)); + check_buf("\nlf\nlf\ncrlf\nlf\nlf\ncrlf\n", tgt); + + /* LF in CRLF text */ + + git_buf_sets(&src, "\ncrlf\r\ncrlf\r\nlf\ncrlf\r\ncrlf"); + + cl_git_pass(git_buf_text_lf_to_crlf(&tgt, &src)); + check_buf("\r\ncrlf\r\ncrlf\r\nlf\r\ncrlf\r\ncrlf", tgt); + cl_git_pass(git_buf_text_crlf_to_lf(&tgt, &src)); + check_buf("\ncrlf\ncrlf\nlf\ncrlf\ncrlf", tgt); + + /* bare CR test */ + + git_buf_sets(&src, "\rcrlf\r\nlf\nlf\ncr\rcrlf\r\nlf\ncr\r"); + + cl_git_pass(git_buf_text_lf_to_crlf(&tgt, &src)); + check_buf("\rcrlf\r\nlf\r\nlf\r\ncr\rcrlf\r\nlf\r\ncr\r", tgt); + cl_git_pass(git_buf_text_crlf_to_lf(&tgt, &src)); + check_buf("\rcrlf\nlf\nlf\ncr\rcrlf\nlf\ncr\r", tgt); + + git_buf_sets(&src, "\rcr\r"); + cl_git_pass(git_buf_text_lf_to_crlf(&tgt, &src)); + check_buf(src.ptr, tgt); + cl_git_pass(git_buf_text_crlf_to_lf(&tgt, &src)); + check_buf("\rcr\r", tgt); + + git_buf_free(&src); + git_buf_free(&tgt); + + /* blob correspondence tests */ + + git_buf_sets(&src, ALL_CRLF_TEXT_RAW); + cl_git_pass(git_buf_text_lf_to_crlf(&tgt, &src)); + check_buf(ALL_CRLF_TEXT_AS_CRLF, tgt); + cl_git_pass(git_buf_text_crlf_to_lf(&tgt, &src)); + check_buf(ALL_CRLF_TEXT_AS_LF, tgt); + git_buf_free(&src); + git_buf_free(&tgt); + + git_buf_sets(&src, ALL_LF_TEXT_RAW); + cl_git_pass(git_buf_text_lf_to_crlf(&tgt, &src)); + check_buf(ALL_LF_TEXT_AS_CRLF, tgt); + cl_git_pass(git_buf_text_crlf_to_lf(&tgt, &src)); + check_buf(ALL_LF_TEXT_AS_LF, tgt); + git_buf_free(&src); + git_buf_free(&tgt); + + git_buf_sets(&src, MORE_CRLF_TEXT_RAW); + cl_git_pass(git_buf_text_lf_to_crlf(&tgt, &src)); + check_buf(MORE_CRLF_TEXT_AS_CRLF, tgt); + cl_git_pass(git_buf_text_crlf_to_lf(&tgt, &src)); + check_buf(MORE_CRLF_TEXT_AS_LF, tgt); + git_buf_free(&src); + git_buf_free(&tgt); + + git_buf_sets(&src, MORE_LF_TEXT_RAW); + cl_git_pass(git_buf_text_lf_to_crlf(&tgt, &src)); + check_buf(MORE_LF_TEXT_AS_CRLF, tgt); + cl_git_pass(git_buf_text_crlf_to_lf(&tgt, &src)); + check_buf(MORE_LF_TEXT_AS_LF, tgt); + git_buf_free(&src); + git_buf_free(&tgt); +} diff --git a/tests/core/caps.c b/tests/core/caps.c new file mode 100644 index 000000000..68a518ed7 --- /dev/null +++ b/tests/core/caps.c @@ -0,0 +1,31 @@ +#include "clar_libgit2.h" + +void test_core_caps__0(void) +{ + int major, minor, rev, caps; + + git_libgit2_version(&major, &minor, &rev); + cl_assert_equal_i(LIBGIT2_VER_MAJOR, major); + cl_assert_equal_i(LIBGIT2_VER_MINOR, minor); + cl_assert_equal_i(LIBGIT2_VER_REVISION, rev); + + caps = git_libgit2_capabilities(); + +#ifdef GIT_THREADS + cl_assert((caps & GIT_CAP_THREADS) != 0); +#else + cl_assert((caps & GIT_CAP_THREADS) == 0); +#endif + +#if defined(GIT_SSL) || defined(GIT_WINHTTP) + cl_assert((caps & GIT_CAP_HTTPS) != 0); +#else + cl_assert((caps & GIT_CAP_HTTPS) == 0); +#endif + +#if defined(GIT_SSH) + cl_assert((caps & GIT_CAP_SSH) != 0); +#else + cl_assert((caps & GIT_CAP_SSH) == 0); +#endif +} diff --git a/tests/core/copy.c b/tests/core/copy.c new file mode 100644 index 000000000..c0c59c056 --- /dev/null +++ b/tests/core/copy.c @@ -0,0 +1,126 @@ +#include "clar_libgit2.h" +#include "fileops.h" +#include "path.h" +#include "posix.h" + +void test_core_copy__file(void) +{ + struct stat st; + const char *content = "This is some stuff to copy\n"; + + cl_git_mkfile("copy_me", content); + + cl_git_pass(git_futils_cp("copy_me", "copy_me_two", 0664)); + + cl_git_pass(git_path_lstat("copy_me_two", &st)); + cl_assert(S_ISREG(st.st_mode)); + cl_assert(strlen(content) == (size_t)st.st_size); + + cl_git_pass(p_unlink("copy_me_two")); + cl_git_pass(p_unlink("copy_me")); +} + +void test_core_copy__file_in_dir(void) +{ + struct stat st; + const char *content = "This is some other stuff to copy\n"; + + cl_git_pass(git_futils_mkdir("an_dir/in_a_dir", NULL, 0775, GIT_MKDIR_PATH)); + cl_git_mkfile("an_dir/in_a_dir/copy_me", content); + cl_assert(git_path_isdir("an_dir")); + + cl_git_pass(git_futils_mkpath2file + ("an_dir/second_dir/and_more/copy_me_two", 0775)); + + cl_git_pass(git_futils_cp + ("an_dir/in_a_dir/copy_me", + "an_dir/second_dir/and_more/copy_me_two", + 0664)); + + cl_git_pass(git_path_lstat("an_dir/second_dir/and_more/copy_me_two", &st)); + cl_assert(S_ISREG(st.st_mode)); + cl_assert(strlen(content) == (size_t)st.st_size); + + cl_git_pass(git_futils_rmdir_r("an_dir", NULL, GIT_RMDIR_REMOVE_FILES)); + cl_assert(!git_path_isdir("an_dir")); +} + +void test_core_copy__tree(void) +{ + struct stat st; + const char *content = "File content\n"; + + cl_git_pass(git_futils_mkdir("src/b", NULL, 0775, GIT_MKDIR_PATH)); + cl_git_pass(git_futils_mkdir("src/c/d", NULL, 0775, GIT_MKDIR_PATH)); + cl_git_pass(git_futils_mkdir("src/c/e", NULL, 0775, GIT_MKDIR_PATH)); + + cl_git_mkfile("src/f1", content); + cl_git_mkfile("src/b/f2", content); + cl_git_mkfile("src/c/f3", content); + cl_git_mkfile("src/c/d/f4", content); + cl_git_mkfile("src/c/d/.f5", content); + +#ifndef GIT_WIN32 + cl_assert(p_symlink("../../b/f2", "src/c/d/l1") == 0); +#endif + + cl_assert(git_path_isdir("src")); + cl_assert(git_path_isdir("src/b")); + cl_assert(git_path_isdir("src/c/d")); + cl_assert(git_path_isfile("src/c/d/f4")); + + /* copy with no empty dirs, yes links, no dotfiles, no overwrite */ + + cl_git_pass( + git_futils_cp_r("src", "t1", GIT_CPDIR_COPY_SYMLINKS, 0) ); + + cl_assert(git_path_isdir("t1")); + cl_assert(git_path_isdir("t1/b")); + cl_assert(git_path_isdir("t1/c")); + cl_assert(git_path_isdir("t1/c/d")); + cl_assert(!git_path_isdir("t1/c/e")); + + cl_assert(git_path_isfile("t1/f1")); + cl_assert(git_path_isfile("t1/b/f2")); + cl_assert(git_path_isfile("t1/c/f3")); + cl_assert(git_path_isfile("t1/c/d/f4")); + cl_assert(!git_path_isfile("t1/c/d/.f5")); + + cl_git_pass(git_path_lstat("t1/c/f3", &st)); + cl_assert(S_ISREG(st.st_mode)); + cl_assert(strlen(content) == (size_t)st.st_size); + +#ifndef GIT_WIN32 + cl_git_pass(git_path_lstat("t1/c/d/l1", &st)); + cl_assert(S_ISLNK(st.st_mode)); +#endif + + cl_git_pass(git_futils_rmdir_r("t1", NULL, GIT_RMDIR_REMOVE_FILES)); + cl_assert(!git_path_isdir("t1")); + + /* copy with empty dirs, no links, yes dotfiles, no overwrite */ + + cl_git_pass( + git_futils_cp_r("src", "t2", GIT_CPDIR_CREATE_EMPTY_DIRS | GIT_CPDIR_COPY_DOTFILES, 0) ); + + cl_assert(git_path_isdir("t2")); + cl_assert(git_path_isdir("t2/b")); + cl_assert(git_path_isdir("t2/c")); + cl_assert(git_path_isdir("t2/c/d")); + cl_assert(git_path_isdir("t2/c/e")); + + cl_assert(git_path_isfile("t2/f1")); + cl_assert(git_path_isfile("t2/b/f2")); + cl_assert(git_path_isfile("t2/c/f3")); + cl_assert(git_path_isfile("t2/c/d/f4")); + cl_assert(git_path_isfile("t2/c/d/.f5")); + +#ifndef GIT_WIN32 + cl_git_fail(git_path_lstat("t2/c/d/l1", &st)); +#endif + + cl_git_pass(git_futils_rmdir_r("t2", NULL, GIT_RMDIR_REMOVE_FILES)); + cl_assert(!git_path_isdir("t2")); + + cl_git_pass(git_futils_rmdir_r("src", NULL, GIT_RMDIR_REMOVE_FILES)); +} diff --git a/tests/core/dirent.c b/tests/core/dirent.c new file mode 100644 index 000000000..f17260362 --- /dev/null +++ b/tests/core/dirent.c @@ -0,0 +1,236 @@ +#include "clar_libgit2.h" +#include "fileops.h" + +typedef struct name_data { + int count; /* return count */ + char *name; /* filename */ +} name_data; + +typedef struct walk_data { + char *sub; /* sub-directory name */ + name_data *names; /* name state data */ + git_buf path; +} walk_data; + + +static char *top_dir = "dir-walk"; +static walk_data *state_loc; + +static void setup(walk_data *d) +{ + name_data *n; + + cl_must_pass(p_mkdir(top_dir, 0777)); + + cl_must_pass(p_chdir(top_dir)); + + if (strcmp(d->sub, ".") != 0) + cl_must_pass(p_mkdir(d->sub, 0777)); + + cl_git_pass(git_buf_sets(&d->path, d->sub)); + + state_loc = d; + + for (n = d->names; n->name; n++) { + git_file fd = p_creat(n->name, 0666); + cl_assert(fd >= 0); + p_close(fd); + n->count = 0; + } +} + +static void dirent_cleanup__cb(void *_d) +{ + walk_data *d = _d; + name_data *n; + + for (n = d->names; n->name; n++) { + cl_must_pass(p_unlink(n->name)); + } + + if (strcmp(d->sub, ".") != 0) + cl_must_pass(p_rmdir(d->sub)); + + cl_must_pass(p_chdir("..")); + + cl_must_pass(p_rmdir(top_dir)); + + git_buf_free(&d->path); +} + +static void check_counts(walk_data *d) +{ + name_data *n; + + for (n = d->names; n->name; n++) { + cl_assert(n->count == 1); + } +} + +static int one_entry(void *state, git_buf *path) +{ + walk_data *d = (walk_data *) state; + name_data *n; + + if (state != state_loc) + return GIT_ERROR; + + if (path != &d->path) + return GIT_ERROR; + + for (n = d->names; n->name; n++) { + if (!strcmp(n->name, path->ptr)) { + n->count++; + return 0; + } + } + + return GIT_ERROR; +} + + +static name_data dot_names[] = { + { 0, "./a" }, + { 0, "./asdf" }, + { 0, "./pack-foo.pack" }, + { 0, NULL } +}; +static walk_data dot = { + ".", + dot_names, + GIT_BUF_INIT +}; + +/* make sure that the '.' folder is not traversed */ +void test_core_dirent__dont_traverse_dot(void) +{ + cl_set_cleanup(&dirent_cleanup__cb, &dot); + setup(&dot); + + cl_git_pass(git_path_direach(&dot.path, 0, one_entry, &dot)); + + check_counts(&dot); +} + + +static name_data sub_names[] = { + { 0, "sub/a" }, + { 0, "sub/asdf" }, + { 0, "sub/pack-foo.pack" }, + { 0, NULL } +}; +static walk_data sub = { + "sub", + sub_names, + GIT_BUF_INIT +}; + +/* traverse a subfolder */ +void test_core_dirent__traverse_subfolder(void) +{ + cl_set_cleanup(&dirent_cleanup__cb, &sub); + setup(&sub); + + cl_git_pass(git_path_direach(&sub.path, 0, one_entry, &sub)); + + check_counts(&sub); +} + + +static walk_data sub_slash = { + "sub/", + sub_names, + GIT_BUF_INIT +}; + +/* traverse a slash-terminated subfolder */ +void test_core_dirent__traverse_slash_terminated_folder(void) +{ + cl_set_cleanup(&dirent_cleanup__cb, &sub_slash); + setup(&sub_slash); + + cl_git_pass(git_path_direach(&sub_slash.path, 0, one_entry, &sub_slash)); + + check_counts(&sub_slash); +} + + +static name_data empty_names[] = { + { 0, NULL } +}; +static walk_data empty = { + "empty", + empty_names, + GIT_BUF_INIT +}; + +/* make sure that empty folders are not traversed */ +void test_core_dirent__dont_traverse_empty_folders(void) +{ + cl_set_cleanup(&dirent_cleanup__cb, &empty); + setup(&empty); + + cl_git_pass(git_path_direach(&empty.path, 0, one_entry, &empty)); + + check_counts(&empty); + + /* make sure callback not called */ + cl_assert(git_path_is_empty_dir(empty.path.ptr)); +} + +static name_data odd_names[] = { + { 0, "odd/.a" }, + { 0, "odd/..c" }, + /* the following don't work on cygwin/win32 */ + /* { 0, "odd/.b." }, */ + /* { 0, "odd/..d.." }, */ + { 0, NULL } +}; +static walk_data odd = { + "odd", + odd_names, + GIT_BUF_INIT +}; + +/* make sure that strange looking filenames ('..c') are traversed */ +void test_core_dirent__traverse_weird_filenames(void) +{ + cl_set_cleanup(&dirent_cleanup__cb, &odd); + setup(&odd); + + cl_git_pass(git_path_direach(&odd.path, 0, one_entry, &odd)); + + check_counts(&odd); +} + +/* test filename length limits */ +void test_core_dirent__length_limits(void) +{ + char *big_filename = (char *)git__malloc(FILENAME_MAX + 1); + memset(big_filename, 'a', FILENAME_MAX + 1); + big_filename[FILENAME_MAX] = 0; + + cl_must_fail(p_creat(big_filename, 0666)); + + git__free(big_filename); +} + +void test_core_dirent__empty_dir(void) +{ + cl_must_pass(p_mkdir("empty_dir", 0777)); + cl_assert(git_path_is_empty_dir("empty_dir")); + + cl_git_mkfile("empty_dir/content", "whatever\n"); + cl_assert(!git_path_is_empty_dir("empty_dir")); + cl_assert(!git_path_is_empty_dir("empty_dir/content")); + + cl_must_pass(p_unlink("empty_dir/content")); + + cl_must_pass(p_mkdir("empty_dir/content", 0777)); + cl_assert(!git_path_is_empty_dir("empty_dir")); + cl_assert(git_path_is_empty_dir("empty_dir/content")); + + cl_must_pass(p_rmdir("empty_dir/content")); + + cl_must_pass(p_rmdir("empty_dir")); +} diff --git a/tests/core/env.c b/tests/core/env.c new file mode 100644 index 000000000..0fa6472d7 --- /dev/null +++ b/tests/core/env.c @@ -0,0 +1,303 @@ +#include "clar_libgit2.h" +#include "fileops.h" +#include "path.h" + +#ifdef GIT_WIN32 +#define NUM_VARS 5 +static const char *env_vars[NUM_VARS] = { + "HOME", "HOMEDRIVE", "HOMEPATH", "USERPROFILE", "PROGRAMFILES" +}; +#else +#define NUM_VARS 1 +static const char *env_vars[NUM_VARS] = { "HOME" }; +#endif + +static char *env_save[NUM_VARS]; + +static char *home_values[] = { + "fake_home", + "f\xc3\xa1ke_h\xc3\xb5me", /* all in latin-1 supplement */ + "f\xc4\x80ke_\xc4\xa4ome", /* latin extended */ + "f\xce\xb1\xce\xba\xce\xb5_h\xce\xbfm\xce\xad", /* having fun with greek */ + "fa\xe0" "\xb8" "\x87" "e_\xe0" "\xb8" "\x99" "ome", /* thai characters */ + "f\xe1\x9cx80ke_\xe1\x9c\x91ome", /* tagalog characters */ + "\xe1\xb8\x9f\xe1\xba\xa2" "ke_ho" "\xe1" "\xb9" "\x81" "e", /* latin extended additional */ + "\xf0\x9f\x98\x98\xf0\x9f\x98\x82", /* emoticons */ + NULL +}; + +void test_core_env__initialize(void) +{ + int i; + for (i = 0; i < NUM_VARS; ++i) { + const char *original = cl_getenv(env_vars[i]); +#ifdef GIT_WIN32 + env_save[i] = (char *)original; +#else + env_save[i] = original ? git__strdup(original) : NULL; +#endif + } +} + +static void reset_global_search_path(void) +{ + cl_git_pass(git_futils_dirs_set(GIT_FUTILS_DIR_GLOBAL, NULL)); +} + +static void reset_system_search_path(void) +{ + cl_git_pass(git_futils_dirs_set(GIT_FUTILS_DIR_SYSTEM, NULL)); +} + +void test_core_env__cleanup(void) +{ + int i; + char **val; + + for (i = 0; i < NUM_VARS; ++i) { + cl_setenv(env_vars[i], env_save[i]); + git__free(env_save[i]); + env_save[i] = NULL; + } + + /* these will probably have already been cleaned up, but if a test + * fails, then it's probably good to try and clear out these dirs + */ + for (val = home_values; *val != NULL; val++) { + if (**val != '\0') + (void)p_rmdir(*val); + } + + /* reset search paths to default */ + reset_global_search_path(); + reset_system_search_path(); +} + +static void setenv_and_check(const char *name, const char *value) +{ + char *check; + + cl_git_pass(cl_setenv(name, value)); + + check = cl_getenv(name); + cl_assert_equal_s(value, check); +#ifdef GIT_WIN32 + git__free(check); +#endif +} + +void test_core_env__0(void) +{ + git_buf path = GIT_BUF_INIT, found = GIT_BUF_INIT; + char testfile[16], tidx = '0'; + char **val; + const char *testname = "testfile"; + size_t testlen = strlen(testname); + + strncpy(testfile, testname, sizeof(testfile)); + cl_assert_equal_s(testname, testfile); + + for (val = home_values; *val != NULL; val++) { + + /* if we can't make the directory, let's just assume + * we are on a filesystem that doesn't support the + * characters in question and skip this test... + */ + if (p_mkdir(*val, 0777) != 0) { + *val = ""; /* mark as not created */ + continue; + } + + cl_git_pass(git_path_prettify(&path, *val, NULL)); + + /* vary testfile name in each directory so accidentally leaving + * an environment variable set from a previous iteration won't + * accidentally make this test pass... + */ + testfile[testlen] = tidx++; + cl_git_pass(git_buf_joinpath(&path, path.ptr, testfile)); + cl_git_mkfile(path.ptr, "find me"); + git_buf_rtruncate_at_char(&path, '/'); + + cl_assert_equal_i( + GIT_ENOTFOUND, git_futils_find_global_file(&found, testfile)); + + setenv_and_check("HOME", path.ptr); + reset_global_search_path(); + + cl_git_pass(git_futils_find_global_file(&found, testfile)); + + cl_setenv("HOME", env_save[0]); + reset_global_search_path(); + + cl_assert_equal_i( + GIT_ENOTFOUND, git_futils_find_global_file(&found, testfile)); + +#ifdef GIT_WIN32 + setenv_and_check("HOMEDRIVE", NULL); + setenv_and_check("HOMEPATH", NULL); + setenv_and_check("USERPROFILE", path.ptr); + reset_global_search_path(); + + cl_git_pass(git_futils_find_global_file(&found, testfile)); + + { + int root = git_path_root(path.ptr); + char old; + + if (root >= 0) { + setenv_and_check("USERPROFILE", NULL); + reset_global_search_path(); + + cl_assert_equal_i( + GIT_ENOTFOUND, git_futils_find_global_file(&found, testfile)); + + old = path.ptr[root]; + path.ptr[root] = '\0'; + setenv_and_check("HOMEDRIVE", path.ptr); + path.ptr[root] = old; + setenv_and_check("HOMEPATH", &path.ptr[root]); + reset_global_search_path(); + + cl_git_pass(git_futils_find_global_file(&found, testfile)); + } + } +#endif + + (void)p_rmdir(*val); + } + + git_buf_free(&path); + git_buf_free(&found); +} + + +void test_core_env__1(void) +{ + git_buf path = GIT_BUF_INIT; + + cl_assert_equal_i( + GIT_ENOTFOUND, git_futils_find_global_file(&path, "nonexistentfile")); + + cl_git_pass(cl_setenv("HOME", "doesnotexist")); +#ifdef GIT_WIN32 + cl_git_pass(cl_setenv("HOMEPATH", "doesnotexist")); + cl_git_pass(cl_setenv("USERPROFILE", "doesnotexist")); +#endif + reset_global_search_path(); + + cl_assert_equal_i( + GIT_ENOTFOUND, git_futils_find_global_file(&path, "nonexistentfile")); + + cl_git_pass(cl_setenv("HOME", NULL)); +#ifdef GIT_WIN32 + cl_git_pass(cl_setenv("HOMEPATH", NULL)); + cl_git_pass(cl_setenv("USERPROFILE", NULL)); +#endif + reset_global_search_path(); + reset_system_search_path(); + + cl_assert_equal_i( + GIT_ENOTFOUND, git_futils_find_global_file(&path, "nonexistentfile")); + + cl_assert_equal_i( + GIT_ENOTFOUND, git_futils_find_system_file(&path, "nonexistentfile")); + +#ifdef GIT_WIN32 + cl_git_pass(cl_setenv("PROGRAMFILES", NULL)); + reset_system_search_path(); + + cl_assert_equal_i( + GIT_ENOTFOUND, git_futils_find_system_file(&path, "nonexistentfile")); +#endif + + git_buf_free(&path); +} + +static void check_global_searchpath( + const char *path, int position, const char *file, git_buf *temp) +{ + char out[GIT_PATH_MAX]; + + /* build and set new path */ + if (position < 0) + cl_git_pass(git_buf_join(temp, GIT_PATH_LIST_SEPARATOR, path, "$PATH")); + else if (position > 0) + cl_git_pass(git_buf_join(temp, GIT_PATH_LIST_SEPARATOR, "$PATH", path)); + else + cl_git_pass(git_buf_sets(temp, path)); + + cl_git_pass(git_libgit2_opts( + GIT_OPT_SET_SEARCH_PATH, GIT_CONFIG_LEVEL_GLOBAL, temp->ptr)); + + /* get path and make sure $PATH expansion worked */ + cl_git_pass(git_libgit2_opts( + GIT_OPT_GET_SEARCH_PATH, GIT_CONFIG_LEVEL_GLOBAL, out, sizeof(out))); + + if (position < 0) + cl_assert(git__prefixcmp(out, path) == 0); + else if (position > 0) + cl_assert(git__suffixcmp(out, path) == 0); + else + cl_assert_equal_s(out, path); + + /* find file using new path */ + cl_git_pass(git_futils_find_global_file(temp, file)); + + /* reset path and confirm file not found */ + cl_git_pass(git_libgit2_opts( + GIT_OPT_SET_SEARCH_PATH, GIT_CONFIG_LEVEL_GLOBAL, NULL)); + cl_assert_equal_i( + GIT_ENOTFOUND, git_futils_find_global_file(temp, file)); +} + +void test_core_env__2(void) +{ + git_buf path = GIT_BUF_INIT, found = GIT_BUF_INIT; + char testfile[16], tidx = '0'; + char **val; + const char *testname = "alternate"; + size_t testlen = strlen(testname); + + strncpy(testfile, testname, sizeof(testfile)); + cl_assert_equal_s(testname, testfile); + + for (val = home_values; *val != NULL; val++) { + + /* if we can't make the directory, let's just assume + * we are on a filesystem that doesn't support the + * characters in question and skip this test... + */ + if (p_mkdir(*val, 0777) != 0 && errno != EEXIST) { + *val = ""; /* mark as not created */ + continue; + } + + cl_git_pass(git_path_prettify(&path, *val, NULL)); + + /* vary testfile name so any sloppiness is resetting variables or + * deleting files won't accidentally make a test pass. + */ + testfile[testlen] = tidx++; + cl_git_pass(git_buf_joinpath(&path, path.ptr, testfile)); + cl_git_mkfile(path.ptr, "find me"); + git_buf_rtruncate_at_char(&path, '/'); + + /* default should be NOTFOUND */ + cl_assert_equal_i( + GIT_ENOTFOUND, git_futils_find_global_file(&found, testfile)); + + /* try plain, append $PATH, and prepend $PATH */ + check_global_searchpath(path.ptr, 0, testfile, &found); + check_global_searchpath(path.ptr, -1, testfile, &found); + check_global_searchpath(path.ptr, 1, testfile, &found); + + /* cleanup */ + cl_git_pass(git_buf_joinpath(&path, path.ptr, testfile)); + (void)p_unlink(path.ptr); + (void)p_rmdir(*val); + } + + git_buf_free(&path); + git_buf_free(&found); +} diff --git a/tests/core/errors.c b/tests/core/errors.c new file mode 100644 index 000000000..512a4134d --- /dev/null +++ b/tests/core/errors.c @@ -0,0 +1,87 @@ +#include "clar_libgit2.h" + +void test_core_errors__public_api(void) +{ + char *str_in_error; + + giterr_clear(); + cl_assert(giterr_last() == NULL); + + giterr_set_oom(); + + cl_assert(giterr_last() != NULL); + cl_assert(giterr_last()->klass == GITERR_NOMEMORY); + str_in_error = strstr(giterr_last()->message, "memory"); + cl_assert(str_in_error != NULL); + + giterr_clear(); + + giterr_set_str(GITERR_REPOSITORY, "This is a test"); + + cl_assert(giterr_last() != NULL); + str_in_error = strstr(giterr_last()->message, "This is a test"); + cl_assert(str_in_error != NULL); + + giterr_clear(); + cl_assert(giterr_last() == NULL); +} + +#include "common.h" +#include "util.h" +#include "posix.h" + +void test_core_errors__new_school(void) +{ + char *str_in_error; + + giterr_clear(); + cl_assert(giterr_last() == NULL); + + giterr_set_oom(); /* internal fn */ + + cl_assert(giterr_last() != NULL); + cl_assert(giterr_last()->klass == GITERR_NOMEMORY); + str_in_error = strstr(giterr_last()->message, "memory"); + cl_assert(str_in_error != NULL); + + giterr_clear(); + + giterr_set(GITERR_REPOSITORY, "This is a test"); /* internal fn */ + + cl_assert(giterr_last() != NULL); + str_in_error = strstr(giterr_last()->message, "This is a test"); + cl_assert(str_in_error != NULL); + + giterr_clear(); + cl_assert(giterr_last() == NULL); + + do { + struct stat st; + memset(&st, 0, sizeof(st)); + cl_assert(p_lstat("this_file_does_not_exist", &st) < 0); + GIT_UNUSED(st); + } while (false); + giterr_set(GITERR_OS, "stat failed"); /* internal fn */ + + cl_assert(giterr_last() != NULL); + str_in_error = strstr(giterr_last()->message, "stat failed"); + cl_assert(str_in_error != NULL); + cl_assert(git__prefixcmp(str_in_error, "stat failed: ") == 0); + cl_assert(strlen(str_in_error) > strlen("stat failed: ")); + +#ifdef GIT_WIN32 + giterr_clear(); + + /* The MSDN docs use this to generate a sample error */ + cl_assert(GetProcessId(NULL) == 0); + giterr_set(GITERR_OS, "GetProcessId failed"); /* internal fn */ + + cl_assert(giterr_last() != NULL); + str_in_error = strstr(giterr_last()->message, "GetProcessId failed"); + cl_assert(str_in_error != NULL); + cl_assert(git__prefixcmp(str_in_error, "GetProcessId failed: ") == 0); + cl_assert(strlen(str_in_error) > strlen("GetProcessId failed: ")); +#endif + + giterr_clear(); +} diff --git a/tests/core/filebuf.c b/tests/core/filebuf.c new file mode 100644 index 000000000..5a3e7510f --- /dev/null +++ b/tests/core/filebuf.c @@ -0,0 +1,126 @@ +#include "clar_libgit2.h" +#include "filebuf.h" + +/* make sure git_filebuf_open doesn't delete an existing lock */ +void test_core_filebuf__0(void) +{ + git_filebuf file = GIT_FILEBUF_INIT; + int fd; + char test[] = "test", testlock[] = "test.lock"; + + fd = p_creat(testlock, 0744); //-V536 + + cl_must_pass(fd); + cl_must_pass(p_close(fd)); + + cl_git_fail(git_filebuf_open(&file, test, 0, 0666)); + cl_assert(git_path_exists(testlock)); + + cl_must_pass(p_unlink(testlock)); +} + + +/* make sure GIT_FILEBUF_APPEND works as expected */ +void test_core_filebuf__1(void) +{ + git_filebuf file = GIT_FILEBUF_INIT; + char test[] = "test"; + + cl_git_mkfile(test, "libgit2 rocks\n"); + + cl_git_pass(git_filebuf_open(&file, test, GIT_FILEBUF_APPEND, 0666)); + cl_git_pass(git_filebuf_printf(&file, "%s\n", "libgit2 rocks")); + cl_git_pass(git_filebuf_commit(&file)); + + cl_assert_equal_file("libgit2 rocks\nlibgit2 rocks\n", 0, test); + + cl_must_pass(p_unlink(test)); +} + + +/* make sure git_filebuf_write writes large buffer correctly */ +void test_core_filebuf__2(void) +{ + git_filebuf file = GIT_FILEBUF_INIT; + char test[] = "test"; + unsigned char buf[4096 * 4]; /* 2 * WRITE_BUFFER_SIZE */ + + memset(buf, 0xfe, sizeof(buf)); + + cl_git_pass(git_filebuf_open(&file, test, 0, 0666)); + cl_git_pass(git_filebuf_write(&file, buf, sizeof(buf))); + cl_git_pass(git_filebuf_commit(&file)); + + cl_assert_equal_file((char *)buf, sizeof(buf), test); + + cl_must_pass(p_unlink(test)); +} + +/* make sure git_filebuf_cleanup clears the buffer */ +void test_core_filebuf__4(void) +{ + git_filebuf file = GIT_FILEBUF_INIT; + char test[] = "test"; + + cl_assert(file.buffer == NULL); + + cl_git_pass(git_filebuf_open(&file, test, 0, 0666)); + cl_assert(file.buffer != NULL); + + git_filebuf_cleanup(&file); + cl_assert(file.buffer == NULL); +} + + +/* make sure git_filebuf_commit clears the buffer */ +void test_core_filebuf__5(void) +{ + git_filebuf file = GIT_FILEBUF_INIT; + char test[] = "test"; + + cl_assert(file.buffer == NULL); + + cl_git_pass(git_filebuf_open(&file, test, 0, 0666)); + cl_assert(file.buffer != NULL); + cl_git_pass(git_filebuf_printf(&file, "%s\n", "libgit2 rocks")); + cl_assert(file.buffer != NULL); + + cl_git_pass(git_filebuf_commit(&file)); + cl_assert(file.buffer == NULL); + + cl_must_pass(p_unlink(test)); +} + + +/* make sure git_filebuf_commit takes umask into account */ +void test_core_filebuf__umask(void) +{ + git_filebuf file = GIT_FILEBUF_INIT; + char test[] = "test"; + struct stat statbuf; + mode_t mask, os_mask; + +#ifdef GIT_WIN32 + os_mask = 0600; +#else + os_mask = 0777; +#endif + + p_umask(mask = p_umask(0)); + + cl_assert(file.buffer == NULL); + + cl_git_pass(git_filebuf_open(&file, test, 0, 0666)); + cl_assert(file.buffer != NULL); + cl_git_pass(git_filebuf_printf(&file, "%s\n", "libgit2 rocks")); + cl_assert(file.buffer != NULL); + + cl_git_pass(git_filebuf_commit(&file)); + cl_assert(file.buffer == NULL); + + cl_must_pass(p_stat("test", &statbuf)); + cl_assert_equal_i(statbuf.st_mode & os_mask, (0666 & ~mask) & os_mask); + + cl_must_pass(p_unlink(test)); +} + diff --git a/tests/core/hex.c b/tests/core/hex.c new file mode 100644 index 000000000..930af1670 --- /dev/null +++ b/tests/core/hex.c @@ -0,0 +1,22 @@ +#include "clar_libgit2.h" +#include "util.h" + +void test_core_hex__fromhex(void) +{ + /* Passing cases */ + cl_assert(git__fromhex('0') == 0x0); + cl_assert(git__fromhex('1') == 0x1); + cl_assert(git__fromhex('3') == 0x3); + cl_assert(git__fromhex('9') == 0x9); + cl_assert(git__fromhex('A') == 0xa); + cl_assert(git__fromhex('C') == 0xc); + cl_assert(git__fromhex('F') == 0xf); + cl_assert(git__fromhex('a') == 0xa); + cl_assert(git__fromhex('c') == 0xc); + cl_assert(git__fromhex('f') == 0xf); + + /* Failing cases */ + cl_assert(git__fromhex('g') == -1); + cl_assert(git__fromhex('z') == -1); + cl_assert(git__fromhex('X') == -1); +} diff --git a/tests/core/iconv.c b/tests/core/iconv.c new file mode 100644 index 000000000..8aedab206 --- /dev/null +++ b/tests/core/iconv.c @@ -0,0 +1,68 @@ +#include "clar_libgit2.h" +#include "path.h" + +#ifdef GIT_USE_ICONV +static git_path_iconv_t ic; +static char *nfc = "\xC3\x85\x73\x74\x72\xC3\xB6\x6D"; +static char *nfd = "\x41\xCC\x8A\x73\x74\x72\x6F\xCC\x88\x6D"; +#endif + +void test_core_iconv__initialize(void) +{ +#ifdef GIT_USE_ICONV + cl_git_pass(git_path_iconv_init_precompose(&ic)); +#endif +} + +void test_core_iconv__cleanup(void) +{ +#ifdef GIT_USE_ICONV + git_path_iconv_clear(&ic); +#endif +} + +void test_core_iconv__unchanged(void) +{ +#ifdef GIT_USE_ICONV + char *data = "Ascii data", *original = data; + size_t datalen = strlen(data); + + cl_git_pass(git_path_iconv(&ic, &data, &datalen)); + GIT_UNUSED(datalen); + + /* There are no high bits set, so this should leave data untouched */ + cl_assert(data == original); +#endif +} + +void test_core_iconv__decomposed_to_precomposed(void) +{ +#ifdef GIT_USE_ICONV + char *data = nfd; + size_t datalen = strlen(nfd); + + cl_git_pass(git_path_iconv(&ic, &data, &datalen)); + GIT_UNUSED(datalen); + + /* The decomposed nfd string should be transformed to the nfc form + * (on platforms where iconv is enabled, of course). + */ + cl_assert_equal_s(nfc, data); +#endif +} + +void test_core_iconv__precomposed_is_unmodified(void) +{ +#ifdef GIT_USE_ICONV + char *data = nfc; + size_t datalen = strlen(nfc); + + cl_git_pass(git_path_iconv(&ic, &data, &datalen)); + GIT_UNUSED(datalen); + + /* data is already in precomposed form, so even though some bytes have + * the high-bit set, the iconv transform should result in no change. + */ + cl_assert_equal_s(nfc, data); +#endif +} diff --git a/tests/core/mkdir.c b/tests/core/mkdir.c new file mode 100644 index 000000000..a8c5b10ae --- /dev/null +++ b/tests/core/mkdir.c @@ -0,0 +1,188 @@ +#include "clar_libgit2.h" +#include "fileops.h" +#include "path.h" +#include "posix.h" + +static void cleanup_basic_dirs(void *ref) +{ + GIT_UNUSED(ref); + git_futils_rmdir_r("d0", NULL, GIT_RMDIR_EMPTY_HIERARCHY); + git_futils_rmdir_r("d1", NULL, GIT_RMDIR_EMPTY_HIERARCHY); + git_futils_rmdir_r("d2", NULL, GIT_RMDIR_EMPTY_HIERARCHY); + git_futils_rmdir_r("d3", NULL, GIT_RMDIR_EMPTY_HIERARCHY); + git_futils_rmdir_r("d4", NULL, GIT_RMDIR_EMPTY_HIERARCHY); +} + +void test_core_mkdir__basic(void) +{ + cl_set_cleanup(cleanup_basic_dirs, NULL); + + /* make a directory */ + cl_assert(!git_path_isdir("d0")); + cl_git_pass(git_futils_mkdir("d0", NULL, 0755, 0)); + cl_assert(git_path_isdir("d0")); + + /* make a path */ + cl_assert(!git_path_isdir("d1")); + cl_git_pass(git_futils_mkdir("d1/d1.1/d1.2", NULL, 0755, GIT_MKDIR_PATH)); + cl_assert(git_path_isdir("d1")); + cl_assert(git_path_isdir("d1/d1.1")); + cl_assert(git_path_isdir("d1/d1.1/d1.2")); + + /* make a dir exclusively */ + cl_assert(!git_path_isdir("d2")); + cl_git_pass(git_futils_mkdir("d2", NULL, 0755, GIT_MKDIR_EXCL)); + cl_assert(git_path_isdir("d2")); + + /* make exclusive failure */ + cl_git_fail(git_futils_mkdir("d2", NULL, 0755, GIT_MKDIR_EXCL)); + + /* make a path exclusively */ + cl_assert(!git_path_isdir("d3")); + cl_git_pass(git_futils_mkdir("d3/d3.1/d3.2", NULL, 0755, GIT_MKDIR_PATH | GIT_MKDIR_EXCL)); + cl_assert(git_path_isdir("d3")); + cl_assert(git_path_isdir("d3/d3.1/d3.2")); + + /* make exclusive path failure */ + cl_git_fail(git_futils_mkdir("d3/d3.1/d3.2", NULL, 0755, GIT_MKDIR_PATH | GIT_MKDIR_EXCL)); + /* ??? Should EXCL only apply to the last item in the path? */ + + /* path with trailing slash? */ + cl_assert(!git_path_isdir("d4")); + cl_git_pass(git_futils_mkdir("d4/d4.1/", NULL, 0755, GIT_MKDIR_PATH)); + cl_assert(git_path_isdir("d4/d4.1")); +} + +static void cleanup_basedir(void *ref) +{ + GIT_UNUSED(ref); + git_futils_rmdir_r("base", NULL, GIT_RMDIR_EMPTY_HIERARCHY); +} + +void test_core_mkdir__with_base(void) +{ +#define BASEDIR "base/dir/here" + + cl_set_cleanup(cleanup_basedir, NULL); + + cl_git_pass(git_futils_mkdir(BASEDIR, NULL, 0755, GIT_MKDIR_PATH)); + + cl_git_pass(git_futils_mkdir("a", BASEDIR, 0755, 0)); + cl_assert(git_path_isdir(BASEDIR "/a")); + + cl_git_pass(git_futils_mkdir("b/b1/b2", BASEDIR, 0755, GIT_MKDIR_PATH)); + cl_assert(git_path_isdir(BASEDIR "/b/b1/b2")); + + /* exclusive with existing base */ + cl_git_pass(git_futils_mkdir("c/c1/c2", BASEDIR, 0755, GIT_MKDIR_PATH | GIT_MKDIR_EXCL)); + + /* fail: exclusive with duplicated suffix */ + cl_git_fail(git_futils_mkdir("c/c1/c3", BASEDIR, 0755, GIT_MKDIR_PATH | GIT_MKDIR_EXCL)); + + /* fail: exclusive with any duplicated component */ + cl_git_fail(git_futils_mkdir("c/cz/cz", BASEDIR, 0755, GIT_MKDIR_PATH | GIT_MKDIR_EXCL)); + + /* success: exclusive without path */ + cl_git_pass(git_futils_mkdir("c/c1/c3", BASEDIR, 0755, GIT_MKDIR_EXCL)); + + /* path with shorter base and existing dirs */ + cl_git_pass(git_futils_mkdir("dir/here/d/", "base", 0755, GIT_MKDIR_PATH)); + cl_assert(git_path_isdir("base/dir/here/d")); + + /* fail: path with shorter base and existing dirs */ + cl_git_fail(git_futils_mkdir("dir/here/e/", "base", 0755, GIT_MKDIR_PATH | GIT_MKDIR_EXCL)); + + /* fail: base with missing components */ + cl_git_fail(git_futils_mkdir("f/", "base/missing", 0755, GIT_MKDIR_PATH)); + + /* success: shift missing component to path */ + cl_git_pass(git_futils_mkdir("missing/f/", "base/", 0755, GIT_MKDIR_PATH)); +} + +static void cleanup_chmod_root(void *ref) +{ + mode_t *mode = ref; + + if (*mode != 0) { + (void)p_umask(*mode); + git__free(mode); + } + + git_futils_rmdir_r("r", NULL, GIT_RMDIR_EMPTY_HIERARCHY); +} + +#define check_mode(X,A) check_mode_at_line((X), (A), __FILE__, __LINE__) + +static void check_mode_at_line( + mode_t expected, mode_t actual, const char *file, int line) +{ + /* FAT filesystems don't support exec bit, nor group/world bits */ + if (!cl_is_chmod_supported()) { + expected &= 0600; + actual &= 0600; + } + + clar__assert_equal( + file, line, "expected_mode != actual_mode", 1, + "%07o", (int)expected, (int)(actual & 0777)); +} + +void test_core_mkdir__chmods(void) +{ + struct stat st; + mode_t *old = git__malloc(sizeof(mode_t)); + *old = p_umask(022); + + cl_set_cleanup(cleanup_chmod_root, old); + + cl_git_pass(git_futils_mkdir("r", NULL, 0777, 0)); + + cl_git_pass(git_futils_mkdir("mode/is/important", "r", 0777, GIT_MKDIR_PATH)); + + cl_git_pass(git_path_lstat("r/mode", &st)); + check_mode(0755, st.st_mode); + cl_git_pass(git_path_lstat("r/mode/is", &st)); + check_mode(0755, st.st_mode); + cl_git_pass(git_path_lstat("r/mode/is/important", &st)); + check_mode(0755, st.st_mode); + + cl_git_pass(git_futils_mkdir("mode2/is2/important2", "r", 0777, GIT_MKDIR_PATH | GIT_MKDIR_CHMOD)); + + cl_git_pass(git_path_lstat("r/mode2", &st)); + check_mode(0755, st.st_mode); + cl_git_pass(git_path_lstat("r/mode2/is2", &st)); + check_mode(0755, st.st_mode); + cl_git_pass(git_path_lstat("r/mode2/is2/important2", &st)); + check_mode(0777, st.st_mode); + + cl_git_pass(git_futils_mkdir("mode3/is3/important3", "r", 0777, GIT_MKDIR_PATH | GIT_MKDIR_CHMOD_PATH)); + + cl_git_pass(git_path_lstat("r/mode3", &st)); + check_mode(0777, st.st_mode); + cl_git_pass(git_path_lstat("r/mode3/is3", &st)); + check_mode(0777, st.st_mode); + cl_git_pass(git_path_lstat("r/mode3/is3/important3", &st)); + check_mode(0777, st.st_mode); + + /* test that we chmod existing dir */ + + cl_git_pass(git_futils_mkdir("mode/is/important", "r", 0777, GIT_MKDIR_PATH | GIT_MKDIR_CHMOD)); + + cl_git_pass(git_path_lstat("r/mode", &st)); + check_mode(0755, st.st_mode); + cl_git_pass(git_path_lstat("r/mode/is", &st)); + check_mode(0755, st.st_mode); + cl_git_pass(git_path_lstat("r/mode/is/important", &st)); + check_mode(0777, st.st_mode); + + /* test that we chmod even existing dirs if CHMOD_PATH is set */ + + cl_git_pass(git_futils_mkdir("mode2/is2/important2.1", "r", 0777, GIT_MKDIR_PATH | GIT_MKDIR_CHMOD_PATH)); + + cl_git_pass(git_path_lstat("r/mode2", &st)); + check_mode(0777, st.st_mode); + cl_git_pass(git_path_lstat("r/mode2/is2", &st)); + check_mode(0777, st.st_mode); + cl_git_pass(git_path_lstat("r/mode2/is2/important2.1", &st)); + check_mode(0777, st.st_mode); +} diff --git a/tests/core/oid.c b/tests/core/oid.c new file mode 100644 index 000000000..7ee6fb67d --- /dev/null +++ b/tests/core/oid.c @@ -0,0 +1,70 @@ +#include "clar_libgit2.h" + +static git_oid id; +static git_oid idp; +static git_oid idm; +const char *str_oid = "ae90f12eea699729ed24555e40b9fd669da12a12"; +const char *str_oid_p = "ae90f12eea699729ed"; +const char *str_oid_m = "ae90f12eea699729ed24555e40b9fd669da12a12THIS IS EXTRA TEXT THAT SHOULD GET IGNORED"; + +void test_core_oid__initialize(void) +{ + cl_git_pass(git_oid_fromstr(&id, str_oid)); + cl_git_pass(git_oid_fromstrp(&idp, str_oid_p)); + cl_git_fail(git_oid_fromstrp(&idm, str_oid_m)); +} + +void test_core_oid__streq(void) +{ + cl_assert_equal_i(0, git_oid_streq(&id, str_oid)); + cl_assert_equal_i(-1, git_oid_streq(&id, "deadbeefdeadbeefdeadbeefdeadbeefdeadbeef")); + + cl_assert_equal_i(-1, git_oid_streq(&id, "deadbeef")); + cl_assert_equal_i(-1, git_oid_streq(&id, "I'm not an oid.... :)")); + + cl_assert_equal_i(0, git_oid_streq(&idp, "ae90f12eea699729ed0000000000000000000000")); + cl_assert_equal_i(0, git_oid_streq(&idp, "ae90f12eea699729ed")); + cl_assert_equal_i(-1, git_oid_streq(&idp, "ae90f12eea699729ed1")); + cl_assert_equal_i(-1, git_oid_streq(&idp, "ae90f12eea699729ec")); + cl_assert_equal_i(-1, git_oid_streq(&idp, "deadbeefdeadbeefdeadbeefdeadbeefdeadbeef")); + + cl_assert_equal_i(-1, git_oid_streq(&idp, "deadbeef")); + cl_assert_equal_i(-1, git_oid_streq(&idp, "I'm not an oid.... :)")); +} + +void test_core_oid__strcmp(void) +{ + cl_assert_equal_i(0, git_oid_strcmp(&id, str_oid)); + cl_assert(git_oid_strcmp(&id, "deadbeefdeadbeefdeadbeefdeadbeefdeadbeef") < 0); + + cl_assert(git_oid_strcmp(&id, "deadbeef") < 0); + cl_assert_equal_i(-1, git_oid_strcmp(&id, "I'm not an oid.... :)")); + + cl_assert_equal_i(0, git_oid_strcmp(&idp, "ae90f12eea699729ed0000000000000000000000")); + cl_assert_equal_i(0, git_oid_strcmp(&idp, "ae90f12eea699729ed")); + cl_assert(git_oid_strcmp(&idp, "ae90f12eea699729ed1") < 0); + cl_assert(git_oid_strcmp(&idp, "ae90f12eea699729ec") > 0); + cl_assert(git_oid_strcmp(&idp, "deadbeefdeadbeefdeadbeefdeadbeefdeadbeef") < 0); + + cl_assert(git_oid_strcmp(&idp, "deadbeef") < 0); + cl_assert_equal_i(-1, git_oid_strcmp(&idp, "I'm not an oid.... :)")); +} + +void test_core_oid__ncmp(void) +{ + cl_assert(!git_oid_ncmp(&id, &idp, 0)); + cl_assert(!git_oid_ncmp(&id, &idp, 1)); + cl_assert(!git_oid_ncmp(&id, &idp, 2)); + cl_assert(!git_oid_ncmp(&id, &idp, 17)); + cl_assert(!git_oid_ncmp(&id, &idp, 18)); + cl_assert(git_oid_ncmp(&id, &idp, 19)); + cl_assert(git_oid_ncmp(&id, &idp, 40)); + cl_assert(git_oid_ncmp(&id, &idp, 41)); + cl_assert(git_oid_ncmp(&id, &idp, 42)); + + cl_assert(!git_oid_ncmp(&id, &id, 0)); + cl_assert(!git_oid_ncmp(&id, &id, 1)); + cl_assert(!git_oid_ncmp(&id, &id, 39)); + cl_assert(!git_oid_ncmp(&id, &id, 40)); + cl_assert(!git_oid_ncmp(&id, &id, 41)); +} diff --git a/tests/core/oidmap.c b/tests/core/oidmap.c new file mode 100644 index 000000000..ec4b5e775 --- /dev/null +++ b/tests/core/oidmap.c @@ -0,0 +1,110 @@ +#include "clar_libgit2.h" +#include "oidmap.h" + +GIT__USE_OIDMAP; + +typedef struct { + git_oid oid; + size_t extra; +} oidmap_item; + +#define NITEMS 0x0fff + +void test_core_oidmap__basic(void) +{ + git_oidmap *map; + oidmap_item items[NITEMS]; + uint32_t i, j; + + for (i = 0; i < NITEMS; ++i) { + items[i].extra = i; + for (j = 0; j < GIT_OID_RAWSZ / 4; ++j) { + items[i].oid.id[j * 4 ] = (unsigned char)i; + items[i].oid.id[j * 4 + 1] = (unsigned char)(i >> 8); + items[i].oid.id[j * 4 + 2] = (unsigned char)(i >> 16); + items[i].oid.id[j * 4 + 3] = (unsigned char)(i >> 24); + } + } + + map = git_oidmap_alloc(); + cl_assert(map != NULL); + + for (i = 0; i < NITEMS; ++i) { + khiter_t pos; + int ret; + + pos = kh_get(oid, map, &items[i].oid); + cl_assert(pos == kh_end(map)); + + pos = kh_put(oid, map, &items[i].oid, &ret); + cl_assert(ret != 0); + + kh_val(map, pos) = &items[i]; + } + + + for (i = 0; i < NITEMS; ++i) { + khiter_t pos; + + pos = kh_get(oid, map, &items[i].oid); + cl_assert(pos != kh_end(map)); + + cl_assert_equal_p(kh_val(map, pos), &items[i]); + } + + git_oidmap_free(map); +} + +void test_core_oidmap__hash_collision(void) +{ + git_oidmap *map; + oidmap_item items[NITEMS]; + uint32_t i, j; + + for (i = 0; i < NITEMS; ++i) { + uint32_t segment = i / 8; + int modi = i - (segment * 8); + + items[i].extra = i; + + for (j = 0; j < GIT_OID_RAWSZ / 4; ++j) { + items[i].oid.id[j * 4 ] = (unsigned char)modi; + items[i].oid.id[j * 4 + 1] = (unsigned char)(modi >> 8); + items[i].oid.id[j * 4 + 2] = (unsigned char)(modi >> 16); + items[i].oid.id[j * 4 + 3] = (unsigned char)(modi >> 24); + } + + items[i].oid.id[ 8] = (unsigned char)i; + items[i].oid.id[ 9] = (unsigned char)(i >> 8); + items[i].oid.id[10] = (unsigned char)(i >> 16); + items[i].oid.id[11] = (unsigned char)(i >> 24); + } + + map = git_oidmap_alloc(); + cl_assert(map != NULL); + + for (i = 0; i < NITEMS; ++i) { + khiter_t pos; + int ret; + + pos = kh_get(oid, map, &items[i].oid); + cl_assert(pos == kh_end(map)); + + pos = kh_put(oid, map, &items[i].oid, &ret); + cl_assert(ret != 0); + + kh_val(map, pos) = &items[i]; + } + + + for (i = 0; i < NITEMS; ++i) { + khiter_t pos; + + pos = kh_get(oid, map, &items[i].oid); + cl_assert(pos != kh_end(map)); + + cl_assert_equal_p(kh_val(map, pos), &items[i]); + } + + git_oidmap_free(map); +} diff --git a/tests/core/opts.c b/tests/core/opts.c new file mode 100644 index 000000000..3173c648b --- /dev/null +++ b/tests/core/opts.c @@ -0,0 +1,19 @@ +#include "clar_libgit2.h" +#include "cache.h" + +void test_core_opts__readwrite(void) +{ + size_t old_val = 0; + size_t new_val = 0; + + git_libgit2_opts(GIT_OPT_GET_MWINDOW_SIZE, &old_val); + git_libgit2_opts(GIT_OPT_SET_MWINDOW_SIZE, (size_t)1234); + git_libgit2_opts(GIT_OPT_GET_MWINDOW_SIZE, &new_val); + + cl_assert(new_val == 1234); + + git_libgit2_opts(GIT_OPT_SET_MWINDOW_SIZE, old_val); + git_libgit2_opts(GIT_OPT_GET_MWINDOW_SIZE, &new_val); + + cl_assert(new_val == old_val); +} diff --git a/tests/core/path.c b/tests/core/path.c new file mode 100644 index 000000000..cf2d5e944 --- /dev/null +++ b/tests/core/path.c @@ -0,0 +1,583 @@ +#include "clar_libgit2.h" +#include "fileops.h" + +static void +check_dirname(const char *A, const char *B) +{ + git_buf dir = GIT_BUF_INIT; + char *dir2; + + cl_assert(git_path_dirname_r(&dir, A) >= 0); + cl_assert_equal_s(B, dir.ptr); + git_buf_free(&dir); + + cl_assert((dir2 = git_path_dirname(A)) != NULL); + cl_assert_equal_s(B, dir2); + git__free(dir2); +} + +static void +check_basename(const char *A, const char *B) +{ + git_buf base = GIT_BUF_INIT; + char *base2; + + cl_assert(git_path_basename_r(&base, A) >= 0); + cl_assert_equal_s(B, base.ptr); + git_buf_free(&base); + + cl_assert((base2 = git_path_basename(A)) != NULL); + cl_assert_equal_s(B, base2); + git__free(base2); +} + +static void +check_topdir(const char *A, const char *B) +{ + const char *dir; + + cl_assert((dir = git_path_topdir(A)) != NULL); + cl_assert_equal_s(B, dir); +} + +static void +check_joinpath(const char *path_a, const char *path_b, const char *expected_path) +{ + git_buf joined_path = GIT_BUF_INIT; + + cl_git_pass(git_buf_joinpath(&joined_path, path_a, path_b)); + cl_assert_equal_s(expected_path, joined_path.ptr); + + git_buf_free(&joined_path); +} + +static void +check_joinpath_n( + const char *path_a, + const char *path_b, + const char *path_c, + const char *path_d, + const char *expected_path) +{ + git_buf joined_path = GIT_BUF_INIT; + + cl_git_pass(git_buf_join_n(&joined_path, '/', 4, + path_a, path_b, path_c, path_d)); + cl_assert_equal_s(expected_path, joined_path.ptr); + + git_buf_free(&joined_path); +} + + +/* get the dirname of a path */ +void test_core_path__00_dirname(void) +{ + check_dirname(NULL, "."); + check_dirname("", "."); + check_dirname("a", "."); + check_dirname("/", "/"); + check_dirname("/usr", "/"); + check_dirname("/usr/", "/"); + check_dirname("/usr/lib", "/usr"); + check_dirname("/usr/lib/", "/usr"); + check_dirname("/usr/lib//", "/usr"); + check_dirname("usr/lib", "usr"); + check_dirname("usr/lib/", "usr"); + check_dirname("usr/lib//", "usr"); + check_dirname(".git/", "."); + + check_dirname(REP16("/abc"), REP15("/abc")); + +#ifdef GIT_WIN32 + check_dirname("C:/path/", "C:/"); + check_dirname("C:/path", "C:/"); + check_dirname("//computername/path/", "//computername/"); + check_dirname("//computername/path", "//computername/"); + check_dirname("//computername/sub/path/", "//computername/sub"); + check_dirname("//computername/sub/path", "//computername/sub"); +#endif +} + +/* get the base name of a path */ +void test_core_path__01_basename(void) +{ + check_basename(NULL, "."); + check_basename("", "."); + check_basename("a", "a"); + check_basename("/", "/"); + check_basename("/usr", "usr"); + check_basename("/usr/", "usr"); + check_basename("/usr/lib", "lib"); + check_basename("/usr/lib//", "lib"); + check_basename("usr/lib", "lib"); + + check_basename(REP16("/abc"), "abc"); + check_basename(REP1024("/abc"), "abc"); +} + +/* get the latest component in a path */ +void test_core_path__02_topdir(void) +{ + check_topdir(".git/", ".git/"); + check_topdir("/.git/", ".git/"); + check_topdir("usr/local/.git/", ".git/"); + check_topdir("./.git/", ".git/"); + check_topdir("/usr/.git/", ".git/"); + check_topdir("/", "/"); + check_topdir("a/", "a/"); + + cl_assert(git_path_topdir("/usr/.git") == NULL); + cl_assert(git_path_topdir(".") == NULL); + cl_assert(git_path_topdir("") == NULL); + cl_assert(git_path_topdir("a") == NULL); +} + +/* properly join path components */ +void test_core_path__05_joins(void) +{ + check_joinpath("", "", ""); + check_joinpath("", "a", "a"); + check_joinpath("", "/a", "/a"); + check_joinpath("a", "", "a/"); + check_joinpath("a", "/", "a/"); + check_joinpath("a", "b", "a/b"); + check_joinpath("/", "a", "/a"); + check_joinpath("/", "", "/"); + check_joinpath("/a", "/b", "/a/b"); + check_joinpath("/a", "/b/", "/a/b/"); + check_joinpath("/a/", "b/", "/a/b/"); + check_joinpath("/a/", "/b/", "/a/b/"); + + check_joinpath("/abcd", "/defg", "/abcd/defg"); + check_joinpath("/abcd", "/defg/", "/abcd/defg/"); + check_joinpath("/abcd/", "defg/", "/abcd/defg/"); + check_joinpath("/abcd/", "/defg/", "/abcd/defg/"); + + check_joinpath("/abcdefgh", "/12345678", "/abcdefgh/12345678"); + check_joinpath("/abcdefgh", "/12345678/", "/abcdefgh/12345678/"); + check_joinpath("/abcdefgh/", "12345678/", "/abcdefgh/12345678/"); + + check_joinpath(REP1024("aaaa"), "", REP1024("aaaa") "/"); + check_joinpath(REP1024("aaaa/"), "", REP1024("aaaa/")); + check_joinpath(REP1024("/aaaa"), "", REP1024("/aaaa") "/"); + + check_joinpath(REP1024("aaaa"), REP1024("bbbb"), + REP1024("aaaa") "/" REP1024("bbbb")); + check_joinpath(REP1024("/aaaa"), REP1024("/bbbb"), + REP1024("/aaaa") REP1024("/bbbb")); +} + +/* properly join path components for more than one path */ +void test_core_path__06_long_joins(void) +{ + check_joinpath_n("", "", "", "", ""); + check_joinpath_n("", "a", "", "", "a/"); + check_joinpath_n("a", "", "", "", "a/"); + check_joinpath_n("", "", "", "a", "a"); + check_joinpath_n("a", "b", "", "/c/d/", "a/b/c/d/"); + check_joinpath_n("a", "b", "", "/c/d", "a/b/c/d"); + check_joinpath_n("abcd", "efgh", "ijkl", "mnop", "abcd/efgh/ijkl/mnop"); + check_joinpath_n("abcd/", "efgh/", "ijkl/", "mnop/", "abcd/efgh/ijkl/mnop/"); + check_joinpath_n("/abcd/", "/efgh/", "/ijkl/", "/mnop/", "/abcd/efgh/ijkl/mnop/"); + + check_joinpath_n(REP1024("a"), REP1024("b"), REP1024("c"), REP1024("d"), + REP1024("a") "/" REP1024("b") "/" + REP1024("c") "/" REP1024("d")); + check_joinpath_n(REP1024("/a"), REP1024("/b"), REP1024("/c"), REP1024("/d"), + REP1024("/a") REP1024("/b") + REP1024("/c") REP1024("/d")); +} + + +static void +check_path_to_dir( + const char* path, + const char* expected) +{ + git_buf tgt = GIT_BUF_INIT; + + git_buf_sets(&tgt, path); + cl_git_pass(git_path_to_dir(&tgt)); + cl_assert_equal_s(expected, tgt.ptr); + + git_buf_free(&tgt); +} + +static void +check_string_to_dir( + const char* path, + size_t maxlen, + const char* expected) +{ + size_t len = strlen(path); + char *buf = git__malloc(len + 2); + cl_assert(buf); + + strncpy(buf, path, len + 2); + + git_path_string_to_dir(buf, maxlen); + + cl_assert_equal_s(expected, buf); + + git__free(buf); +} + +/* convert paths to dirs */ +void test_core_path__07_path_to_dir(void) +{ + check_path_to_dir("", ""); + check_path_to_dir(".", "./"); + check_path_to_dir("./", "./"); + check_path_to_dir("a/", "a/"); + check_path_to_dir("ab", "ab/"); + /* make sure we try just under and just over an expansion that will + * require a realloc + */ + check_path_to_dir("abcdef", "abcdef/"); + check_path_to_dir("abcdefg", "abcdefg/"); + check_path_to_dir("abcdefgh", "abcdefgh/"); + check_path_to_dir("abcdefghi", "abcdefghi/"); + check_path_to_dir(REP1024("abcd") "/", REP1024("abcd") "/"); + check_path_to_dir(REP1024("abcd"), REP1024("abcd") "/"); + + check_string_to_dir("", 1, ""); + check_string_to_dir(".", 1, "."); + check_string_to_dir(".", 2, "./"); + check_string_to_dir(".", 3, "./"); + check_string_to_dir("abcd", 3, "abcd"); + check_string_to_dir("abcd", 4, "abcd"); + check_string_to_dir("abcd", 5, "abcd/"); + check_string_to_dir("abcd", 6, "abcd/"); +} + +/* join path to itself */ +void test_core_path__08_self_join(void) +{ + git_buf path = GIT_BUF_INIT; + size_t asize = 0; + + asize = path.asize; + cl_git_pass(git_buf_sets(&path, "/foo")); + cl_assert_equal_s(path.ptr, "/foo"); + cl_assert(asize < path.asize); + + asize = path.asize; + cl_git_pass(git_buf_joinpath(&path, path.ptr, "this is a new string")); + cl_assert_equal_s(path.ptr, "/foo/this is a new string"); + cl_assert(asize < path.asize); + + asize = path.asize; + cl_git_pass(git_buf_joinpath(&path, path.ptr, "/grow the buffer, grow the buffer, grow the buffer")); + cl_assert_equal_s(path.ptr, "/foo/this is a new string/grow the buffer, grow the buffer, grow the buffer"); + cl_assert(asize < path.asize); + + git_buf_free(&path); + cl_git_pass(git_buf_sets(&path, "/foo/bar")); + + cl_git_pass(git_buf_joinpath(&path, path.ptr + 4, "baz")); + cl_assert_equal_s(path.ptr, "/bar/baz"); + + asize = path.asize; + cl_git_pass(git_buf_joinpath(&path, path.ptr + 4, "somethinglongenoughtorealloc")); + cl_assert_equal_s(path.ptr, "/baz/somethinglongenoughtorealloc"); + cl_assert(asize < path.asize); + + git_buf_free(&path); +} + +static void check_percent_decoding(const char *expected_result, const char *input) +{ + git_buf buf = GIT_BUF_INIT; + + cl_git_pass(git__percent_decode(&buf, input)); + cl_assert_equal_s(expected_result, git_buf_cstr(&buf)); + + git_buf_free(&buf); +} + +void test_core_path__09_percent_decode(void) +{ + check_percent_decoding("abcd", "abcd"); + check_percent_decoding("a2%", "a2%"); + check_percent_decoding("a2%3", "a2%3"); + check_percent_decoding("a2%%3", "a2%%3"); + check_percent_decoding("a2%3z", "a2%3z"); + check_percent_decoding("a,", "a%2c"); + check_percent_decoding("a21", "a2%31"); + check_percent_decoding("a2%1", "a2%%31"); + check_percent_decoding("a bc ", "a%20bc%20"); + check_percent_decoding("Vicent Mart" "\355", "Vicent%20Mart%ED"); +} + +static void check_fromurl(const char *expected_result, const char *input, int should_fail) +{ + git_buf buf = GIT_BUF_INIT; + + assert(should_fail || expected_result); + + if (!should_fail) { + cl_git_pass(git_path_fromurl(&buf, input)); + cl_assert_equal_s(expected_result, git_buf_cstr(&buf)); + } else + cl_git_fail(git_path_fromurl(&buf, input)); + + git_buf_free(&buf); +} + +#ifdef GIT_WIN32 +#define ABS_PATH_MARKER "" +#else +#define ABS_PATH_MARKER "/" +#endif + +void test_core_path__10_fromurl(void) +{ + /* Failing cases */ + check_fromurl(NULL, "a", 1); + check_fromurl(NULL, "http:///c:/Temp%20folder/note.txt", 1); + check_fromurl(NULL, "file://c:/Temp%20folder/note.txt", 1); + check_fromurl(NULL, "file:////c:/Temp%20folder/note.txt", 1); + check_fromurl(NULL, "file:///", 1); + check_fromurl(NULL, "file:////", 1); + check_fromurl(NULL, "file://servername/c:/Temp%20folder/note.txt", 1); + + /* Passing cases */ + check_fromurl(ABS_PATH_MARKER "c:/Temp folder/note.txt", "file:///c:/Temp%20folder/note.txt", 0); + check_fromurl(ABS_PATH_MARKER "c:/Temp folder/note.txt", "file://localhost/c:/Temp%20folder/note.txt", 0); + check_fromurl(ABS_PATH_MARKER "c:/Temp+folder/note.txt", "file:///c:/Temp+folder/note.txt", 0); + check_fromurl(ABS_PATH_MARKER "a", "file:///a", 0); +} + +typedef struct { + int expect_idx; + char **expect; +} check_walkup_info; + +static int check_one_walkup_step(void *ref, git_buf *path) +{ + check_walkup_info *info = (check_walkup_info *)ref; + cl_assert(info->expect[info->expect_idx] != NULL); + cl_assert_equal_s(info->expect[info->expect_idx], path->ptr); + info->expect_idx++; + return 0; +} + +void test_core_path__11_walkup(void) +{ + git_buf p = GIT_BUF_INIT; + char *expect[] = { + "/a/b/c/d/e/", "/a/b/c/d/", "/a/b/c/", "/a/b/", "/a/", "/", NULL, + "/a/b/c/d/e", "/a/b/c/d/", "/a/b/c/", "/a/b/", "/a/", "/", NULL, + "/a/b/c/d/e", "/a/b/c/d/", "/a/b/c/", "/a/b/", "/a/", "/", NULL, + "/a/b/c/d/e", "/a/b/c/d/", "/a/b/c/", "/a/b/", "/a/", "/", NULL, + "/a/b/c/d/e", "/a/b/c/d/", "/a/b/c/", "/a/b/", NULL, + "/a/b/c/d/e", "/a/b/c/d/", "/a/b/c/", "/a/b/", NULL, + "this is a path", NULL, + "///a///b///c///d///e///", "///a///b///c///d///", "///a///b///c///", "///a///b///", "///a///", "///", NULL, + NULL + }; + char *root[] = { NULL, NULL, "/", "", "/a/b", "/a/b/", NULL, NULL, NULL }; + int i, j; + check_walkup_info info; + + info.expect = expect; + + for (i = 0, j = 0; expect[i] != NULL; i++, j++) { + + git_buf_sets(&p, expect[i]); + + info.expect_idx = i; + cl_git_pass( + git_path_walk_up(&p, root[j], check_one_walkup_step, &info) + ); + + cl_assert_equal_s(p.ptr, expect[i]); + + /* skip to next run of expectations */ + while (expect[i] != NULL) i++; + } + + git_buf_free(&p); +} + +void test_core_path__12_offset_to_path_root(void) +{ + cl_assert(git_path_root("non/rooted/path") == -1); + cl_assert(git_path_root("/rooted/path") == 0); + +#ifdef GIT_WIN32 + /* Windows specific tests */ + cl_assert(git_path_root("C:non/rooted/path") == -1); + cl_assert(git_path_root("C:/rooted/path") == 2); + cl_assert(git_path_root("//computername/sharefolder/resource") == 14); + cl_assert(git_path_root("//computername/sharefolder") == 14); + cl_assert(git_path_root("//computername") == -1); +#endif +} + +#define NON_EXISTING_FILEPATH "i_hope_i_do_not_exist" + +void test_core_path__13_cannot_prettify_a_non_existing_file(void) +{ + git_buf p = GIT_BUF_INIT; + + cl_must_pass(git_path_exists(NON_EXISTING_FILEPATH) == false); + cl_assert_equal_i(GIT_ENOTFOUND, git_path_prettify(&p, NON_EXISTING_FILEPATH, NULL)); + cl_assert_equal_i(GIT_ENOTFOUND, git_path_prettify(&p, NON_EXISTING_FILEPATH "/so-do-i", NULL)); + + git_buf_free(&p); +} + +void test_core_path__14_apply_relative(void) +{ + git_buf p = GIT_BUF_INIT; + + cl_git_pass(git_buf_sets(&p, "/this/is/a/base")); + + cl_git_pass(git_path_apply_relative(&p, "../test")); + cl_assert_equal_s("/this/is/a/test", p.ptr); + + cl_git_pass(git_path_apply_relative(&p, "../../the/./end")); + cl_assert_equal_s("/this/is/the/end", p.ptr); + + cl_git_pass(git_path_apply_relative(&p, "./of/this/../the/string")); + cl_assert_equal_s("/this/is/the/end/of/the/string", p.ptr); + + cl_git_pass(git_path_apply_relative(&p, "../../../../../..")); + cl_assert_equal_s("/this/", p.ptr); + + cl_git_pass(git_path_apply_relative(&p, "../")); + cl_assert_equal_s("/", p.ptr); + + cl_git_fail(git_path_apply_relative(&p, "../../..")); + + + cl_git_pass(git_buf_sets(&p, "d:/another/test")); + + cl_git_pass(git_path_apply_relative(&p, "../..")); + cl_assert_equal_s("d:/", p.ptr); + + cl_git_pass(git_path_apply_relative(&p, "from/here/to/../and/./back/.")); + cl_assert_equal_s("d:/from/here/and/back/", p.ptr); + + + cl_git_pass(git_buf_sets(&p, "https://my.url.com/test.git")); + + cl_git_pass(git_path_apply_relative(&p, "../another.git")); + cl_assert_equal_s("https://my.url.com/another.git", p.ptr); + + cl_git_pass(git_path_apply_relative(&p, "../full/path/url.patch")); + cl_assert_equal_s("https://my.url.com/full/path/url.patch", p.ptr); + + cl_git_pass(git_path_apply_relative(&p, "..")); + cl_assert_equal_s("https://my.url.com/full/path/", p.ptr); + + cl_git_pass(git_path_apply_relative(&p, "../../../")); + cl_assert_equal_s("https://", p.ptr); + + + cl_git_pass(git_buf_sets(&p, "../../this/is/relative")); + + cl_git_pass(git_path_apply_relative(&p, "../../preserves/the/prefix")); + cl_assert_equal_s("../../this/preserves/the/prefix", p.ptr); + + cl_git_pass(git_path_apply_relative(&p, "../../../../that")); + cl_assert_equal_s("../../that", p.ptr); + + cl_git_pass(git_path_apply_relative(&p, "../there")); + cl_assert_equal_s("../../there", p.ptr); + git_buf_free(&p); +} + +static void assert_resolve_relative( + git_buf *buf, const char *expected, const char *path) +{ + cl_git_pass(git_buf_sets(buf, path)); + cl_git_pass(git_path_resolve_relative(buf, 0)); + cl_assert_equal_s(expected, buf->ptr); +} + +void test_core_path__15_resolve_relative(void) +{ + git_buf buf = GIT_BUF_INIT; + + assert_resolve_relative(&buf, "", ""); + assert_resolve_relative(&buf, "", "."); + assert_resolve_relative(&buf, "", "./"); + assert_resolve_relative(&buf, "..", ".."); + assert_resolve_relative(&buf, "../", "../"); + assert_resolve_relative(&buf, "..", "./.."); + assert_resolve_relative(&buf, "../", "./../"); + assert_resolve_relative(&buf, "../", "../."); + assert_resolve_relative(&buf, "../", ".././"); + assert_resolve_relative(&buf, "../..", "../.."); + assert_resolve_relative(&buf, "../../", "../../"); + + assert_resolve_relative(&buf, "/", "/"); + assert_resolve_relative(&buf, "/", "/."); + + assert_resolve_relative(&buf, "", "a/.."); + assert_resolve_relative(&buf, "", "a/../"); + assert_resolve_relative(&buf, "", "a/../."); + + assert_resolve_relative(&buf, "/a", "/a"); + assert_resolve_relative(&buf, "/a/", "/a/."); + assert_resolve_relative(&buf, "/", "/a/../"); + assert_resolve_relative(&buf, "/", "/a/../."); + assert_resolve_relative(&buf, "/", "/a/.././"); + + assert_resolve_relative(&buf, "a", "a"); + assert_resolve_relative(&buf, "a/", "a/"); + assert_resolve_relative(&buf, "a/", "a/."); + assert_resolve_relative(&buf, "a/", "a/./"); + + assert_resolve_relative(&buf, "a/b", "a//b"); + assert_resolve_relative(&buf, "a/b/c", "a/b/c"); + assert_resolve_relative(&buf, "b/c", "./b/c"); + assert_resolve_relative(&buf, "a/c", "a/./c"); + assert_resolve_relative(&buf, "a/b/", "a/b/."); + + assert_resolve_relative(&buf, "/a/b/c", "///a/b/c"); + assert_resolve_relative(&buf, "/", "////"); + assert_resolve_relative(&buf, "/a", "///a"); + assert_resolve_relative(&buf, "/", "///."); + assert_resolve_relative(&buf, "/", "///a/.."); + + assert_resolve_relative(&buf, "../../path", "../../test//../././path"); + assert_resolve_relative(&buf, "../d", "a/b/../../../c/../d"); + + cl_git_pass(git_buf_sets(&buf, "/..")); + cl_git_fail(git_path_resolve_relative(&buf, 0)); + + cl_git_pass(git_buf_sets(&buf, "/./..")); + cl_git_fail(git_path_resolve_relative(&buf, 0)); + + cl_git_pass(git_buf_sets(&buf, "/.//..")); + cl_git_fail(git_path_resolve_relative(&buf, 0)); + + cl_git_pass(git_buf_sets(&buf, "/../.")); + cl_git_fail(git_path_resolve_relative(&buf, 0)); + + cl_git_pass(git_buf_sets(&buf, "/../.././../a")); + cl_git_fail(git_path_resolve_relative(&buf, 0)); + + cl_git_pass(git_buf_sets(&buf, "////..")); + cl_git_fail(git_path_resolve_relative(&buf, 0)); + + /* things that start with Windows network paths */ +#ifdef GIT_WIN32 + assert_resolve_relative(&buf, "//a/b/c", "//a/b/c"); + assert_resolve_relative(&buf, "//a/", "//a/b/.."); + assert_resolve_relative(&buf, "//a/b/c", "//a/Q/../b/x/y/../../c"); + + cl_git_pass(git_buf_sets(&buf, "//a/b/../..")); + cl_git_fail(git_path_resolve_relative(&buf, 0)); +#else + assert_resolve_relative(&buf, "/a/b/c", "//a/b/c"); + assert_resolve_relative(&buf, "/a/", "//a/b/.."); + assert_resolve_relative(&buf, "/a/b/c", "//a/Q/../b/x/y/../../c"); + assert_resolve_relative(&buf, "/", "//a/b/../.."); +#endif + + git_buf_free(&buf); +} diff --git a/tests/core/pool.c b/tests/core/pool.c new file mode 100644 index 000000000..3073c4a45 --- /dev/null +++ b/tests/core/pool.c @@ -0,0 +1,145 @@ +#include "clar_libgit2.h" +#include "pool.h" +#include "git2/oid.h" + +void test_core_pool__0(void) +{ + int i; + git_pool p; + void *ptr; + + cl_git_pass(git_pool_init(&p, 1, 4000)); + + for (i = 1; i < 10000; i *= 2) { + ptr = git_pool_malloc(&p, i); + cl_assert(ptr != NULL); + cl_assert(git_pool__ptr_in_pool(&p, ptr)); + cl_assert(!git_pool__ptr_in_pool(&p, &i)); + } + + /* 1+2+4+8+16+32+64+128+256+512+1024 -> original block */ + /* 2048 -> 1 block */ + /* 4096 -> 1 block */ + /* 8192 -> 1 block */ + + cl_assert(git_pool__open_pages(&p) + git_pool__full_pages(&p) == 4); + + git_pool_clear(&p); +} + +void test_core_pool__1(void) +{ + int i; + git_pool p; + + cl_git_pass(git_pool_init(&p, 1, 4000)); + + for (i = 2010; i > 0; i--) + cl_assert(git_pool_malloc(&p, i) != NULL); + + /* with fixed page size, allocation must end up with these values */ + cl_assert(git_pool__open_pages(&p) == 1); + cl_assert(git_pool__full_pages(&p) == 505); + + git_pool_clear(&p); + + cl_git_pass(git_pool_init(&p, 1, 4100)); + + for (i = 2010; i > 0; i--) + cl_assert(git_pool_malloc(&p, i) != NULL); + + /* with fixed page size, allocation must end up with these values */ + cl_assert(git_pool__open_pages(&p) == 1); + cl_assert(git_pool__full_pages(&p) == 492); + + git_pool_clear(&p); +} + +static char to_hex[] = "0123456789abcdef"; + +void test_core_pool__2(void) +{ + git_pool p; + char oid_hex[GIT_OID_HEXSZ]; + git_oid *oid; + int i, j; + + memset(oid_hex, '0', sizeof(oid_hex)); + + cl_git_pass(git_pool_init(&p, sizeof(git_oid), 100)); + + for (i = 1000; i < 10000; i++) { + oid = git_pool_malloc(&p, 1); + cl_assert(oid != NULL); + + for (j = 0; j < 8; j++) + oid_hex[j] = to_hex[(i >> (4 * j)) & 0x0f]; + cl_git_pass(git_oid_fromstr(oid, oid_hex)); + } + + /* with fixed page size, allocation must end up with these values */ + cl_assert(git_pool__open_pages(&p) == 0); + cl_assert(git_pool__full_pages(&p) == 90); + + git_pool_clear(&p); +} + +void test_core_pool__free_list(void) +{ + int i; + git_pool p; + void *ptr, *ptrs[50]; + + cl_git_pass(git_pool_init(&p, 100, 100)); + + for (i = 0; i < 10; ++i) { + ptr = git_pool_malloc(&p, 1); + cl_assert(ptr != NULL); + } + cl_assert_equal_i(10, (int)p.items); + + for (i = 0; i < 50; ++i) { + ptrs[i] = git_pool_malloc(&p, 1); + cl_assert(ptrs[i] != NULL); + } + cl_assert_equal_i(60, (int)p.items); + + git_pool_free(&p, ptr); + cl_assert_equal_i(60, (int)p.items); + + git_pool_free_array(&p, 50, ptrs); + cl_assert_equal_i(60, (int)p.items); + + for (i = 0; i < 50; ++i) { + ptrs[i] = git_pool_malloc(&p, 1); + cl_assert(ptrs[i] != NULL); + } + cl_assert_equal_i(60, (int)p.items); + + for (i = 0; i < 111; ++i) { + ptr = git_pool_malloc(&p, 1); + cl_assert(ptr != NULL); + } + cl_assert_equal_i(170, (int)p.items); + + git_pool_free_array(&p, 50, ptrs); + cl_assert_equal_i(170, (int)p.items); + + for (i = 0; i < 50; ++i) { + ptrs[i] = git_pool_malloc(&p, 1); + cl_assert(ptrs[i] != NULL); + } + cl_assert_equal_i(170, (int)p.items); + + git_pool_clear(&p); +} + +void test_core_pool__strndup_limit(void) +{ + git_pool p; + + cl_git_pass(git_pool_init(&p, 1, 100)); + cl_assert(git_pool_strndup(&p, "foo", -1) == NULL); + git_pool_clear(&p); +} + diff --git a/tests/core/posix.c b/tests/core/posix.c new file mode 100644 index 000000000..1cef937cd --- /dev/null +++ b/tests/core/posix.c @@ -0,0 +1,99 @@ +#ifndef _WIN32 +# include <arpa/inet.h> +# include <sys/socket.h> +# include <netinet/in.h> +#else +# include <ws2tcpip.h> +# ifdef _MSC_VER +# pragma comment(lib, "ws2_32") +# endif +#endif + +#include "clar_libgit2.h" +#include "posix.h" + +void test_core_posix__initialize(void) +{ +#ifdef GIT_WIN32 + /* on win32, the WSA context needs to be initialized + * before any socket calls can be performed */ + WSADATA wsd; + + cl_git_pass(WSAStartup(MAKEWORD(2,2), &wsd)); + cl_assert(LOBYTE(wsd.wVersion) == 2 && HIBYTE(wsd.wVersion) == 2); +#endif +} + +static bool supports_ipv6(void) +{ +#ifdef GIT_WIN32 + /* IPv6 is supported on Vista and newer */ + return git_has_win32_version(6, 0, 0); +#else + return 1; +#endif +} + +void test_core_posix__inet_pton(void) +{ + struct in_addr addr; + struct in6_addr addr6; + size_t i; + + struct in_addr_data { + const char *p; + const uint8_t n[4]; + }; + + struct in6_addr_data { + const char *p; + const uint8_t n[16]; + }; + + static struct in_addr_data in_addr_data[] = { + { "0.0.0.0", { 0, 0, 0, 0 } }, + { "10.42.101.8", { 10, 42, 101, 8 } }, + { "127.0.0.1", { 127, 0, 0, 1 } }, + { "140.177.10.12", { 140, 177, 10, 12 } }, + { "204.232.175.90", { 204, 232, 175, 90 } }, + { "255.255.255.255", { 255, 255, 255, 255 } }, + }; + + static struct in6_addr_data in6_addr_data[] = { + { "::", { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { "::1", { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 } }, + { "0:0:0:0:0:0:0:1", { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 } }, + { "2001:db8:8714:3a90::12", { 0x20, 0x01, 0x0d, 0xb8, 0x87, 0x14, 0x3a, 0x90, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12 } }, + { "fe80::f8ba:c2d6:86be:3645", { 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xba, 0xc2, 0xd6, 0x86, 0xbe, 0x36, 0x45 } }, + { "::ffff:204.152.189.116", { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xcc, 0x98, 0xbd, 0x74 } }, + }; + + /* Test some ipv4 addresses */ + for (i = 0; i < 6; i++) { + cl_assert(p_inet_pton(AF_INET, in_addr_data[i].p, &addr) == 1); + cl_assert(memcmp(&addr, in_addr_data[i].n, sizeof(struct in_addr)) == 0); + } + + /* Test some ipv6 addresses */ + if (supports_ipv6()) + { + for (i = 0; i < 6; i++) { + cl_assert(p_inet_pton(AF_INET6, in6_addr_data[i].p, &addr6) == 1); + cl_assert(memcmp(&addr6, in6_addr_data[i].n, sizeof(struct in6_addr)) == 0); + } + } + + /* Test some invalid strings */ + cl_assert(p_inet_pton(AF_INET, "", &addr) == 0); + cl_assert(p_inet_pton(AF_INET, "foo", &addr) == 0); + cl_assert(p_inet_pton(AF_INET, " 127.0.0.1", &addr) == 0); + cl_assert(p_inet_pton(AF_INET, "bar", &addr) == 0); + cl_assert(p_inet_pton(AF_INET, "10.foo.bar.1", &addr) == 0); + + /* Test unsupported address families */ + cl_git_fail(p_inet_pton(12, "52.472", NULL)); /* AF_DECnet */ + cl_assert_equal_i(EAFNOSUPPORT, errno); + + cl_git_fail(p_inet_pton(5, "315.124", NULL)); /* AF_CHAOS */ + cl_assert_equal_i(EAFNOSUPPORT, errno); +} diff --git a/tests/core/rmdir.c b/tests/core/rmdir.c new file mode 100644 index 000000000..f0b0bfa42 --- /dev/null +++ b/tests/core/rmdir.c @@ -0,0 +1,98 @@ +#include "clar_libgit2.h" +#include "fileops.h" + +static const char *empty_tmp_dir = "test_gitfo_rmdir_recurs_test"; + +void test_core_rmdir__initialize(void) +{ + git_buf path = GIT_BUF_INIT; + + cl_must_pass(p_mkdir(empty_tmp_dir, 0777)); + + cl_git_pass(git_buf_joinpath(&path, empty_tmp_dir, "/one")); + cl_must_pass(p_mkdir(path.ptr, 0777)); + + cl_git_pass(git_buf_joinpath(&path, empty_tmp_dir, "/one/two_one")); + cl_must_pass(p_mkdir(path.ptr, 0777)); + + cl_git_pass(git_buf_joinpath(&path, empty_tmp_dir, "/one/two_two")); + cl_must_pass(p_mkdir(path.ptr, 0777)); + + cl_git_pass(git_buf_joinpath(&path, empty_tmp_dir, "/one/two_two/three")); + cl_must_pass(p_mkdir(path.ptr, 0777)); + + cl_git_pass(git_buf_joinpath(&path, empty_tmp_dir, "/two")); + cl_must_pass(p_mkdir(path.ptr, 0777)); + + git_buf_free(&path); +} + +/* make sure empty dir can be deleted recusively */ +void test_core_rmdir__delete_recursive(void) +{ + cl_git_pass(git_futils_rmdir_r(empty_tmp_dir, NULL, GIT_RMDIR_EMPTY_HIERARCHY)); +} + +/* make sure non-empty dir cannot be deleted recusively */ +void test_core_rmdir__fail_to_delete_non_empty_dir(void) +{ + git_buf file = GIT_BUF_INIT; + + cl_git_pass(git_buf_joinpath(&file, empty_tmp_dir, "/two/file.txt")); + + cl_git_mkfile(git_buf_cstr(&file), "dummy"); + + cl_git_fail(git_futils_rmdir_r(empty_tmp_dir, NULL, GIT_RMDIR_EMPTY_HIERARCHY)); + + cl_must_pass(p_unlink(file.ptr)); + cl_git_pass(git_futils_rmdir_r(empty_tmp_dir, NULL, GIT_RMDIR_EMPTY_HIERARCHY)); + + git_buf_free(&file); +} + +void test_core_rmdir__can_skip_non_empty_dir(void) +{ + git_buf file = GIT_BUF_INIT; + + cl_git_pass(git_buf_joinpath(&file, empty_tmp_dir, "/two/file.txt")); + + cl_git_mkfile(git_buf_cstr(&file), "dummy"); + + cl_git_pass(git_futils_rmdir_r(empty_tmp_dir, NULL, GIT_RMDIR_SKIP_NONEMPTY)); + cl_assert(git_path_exists(git_buf_cstr(&file)) == true); + + cl_git_pass(git_futils_rmdir_r(empty_tmp_dir, NULL, GIT_RMDIR_REMOVE_FILES)); + cl_assert(git_path_exists(empty_tmp_dir) == false); + + git_buf_free(&file); +} + +void test_core_rmdir__can_remove_empty_parents(void) +{ + git_buf file = GIT_BUF_INIT; + + cl_git_pass( + git_buf_joinpath(&file, empty_tmp_dir, "/one/two_two/three/file.txt")); + cl_git_mkfile(git_buf_cstr(&file), "dummy"); + cl_assert(git_path_isfile(git_buf_cstr(&file))); + + cl_git_pass(git_futils_rmdir_r("one/two_two/three/file.txt", empty_tmp_dir, + GIT_RMDIR_REMOVE_FILES | GIT_RMDIR_EMPTY_PARENTS)); + + cl_assert(!git_path_exists(git_buf_cstr(&file))); + + git_buf_rtruncate_at_char(&file, '/'); /* three (only contained file.txt) */ + cl_assert(!git_path_exists(git_buf_cstr(&file))); + + git_buf_rtruncate_at_char(&file, '/'); /* two_two (only contained three) */ + cl_assert(!git_path_exists(git_buf_cstr(&file))); + + git_buf_rtruncate_at_char(&file, '/'); /* one (contained two_one also) */ + cl_assert(git_path_exists(git_buf_cstr(&file))); + + cl_assert(git_path_exists(empty_tmp_dir) == true); + + git_buf_free(&file); + + cl_git_pass(git_futils_rmdir_r(empty_tmp_dir, NULL, GIT_RMDIR_EMPTY_HIERARCHY)); +} diff --git a/tests/core/sortedcache.c b/tests/core/sortedcache.c new file mode 100644 index 000000000..c1869bee0 --- /dev/null +++ b/tests/core/sortedcache.c @@ -0,0 +1,363 @@ +#include "clar_libgit2.h" +#include "sortedcache.h" + +static int name_only_cmp(const void *a, const void *b) +{ + return strcmp(a, b); +} + +void test_core_sortedcache__name_only(void) +{ + git_sortedcache *sc; + void *item; + size_t pos; + + cl_git_pass(git_sortedcache_new( + &sc, 0, NULL, NULL, name_only_cmp, NULL)); + + cl_git_pass(git_sortedcache_wlock(sc)); + cl_git_pass(git_sortedcache_upsert(&item, sc, "aaa")); + cl_git_pass(git_sortedcache_upsert(&item, sc, "bbb")); + cl_git_pass(git_sortedcache_upsert(&item, sc, "zzz")); + cl_git_pass(git_sortedcache_upsert(&item, sc, "mmm")); + cl_git_pass(git_sortedcache_upsert(&item, sc, "iii")); + git_sortedcache_wunlock(sc); + + cl_assert_equal_sz(5, git_sortedcache_entrycount(sc)); + + cl_assert((item = git_sortedcache_lookup(sc, "aaa")) != NULL); + cl_assert_equal_s("aaa", item); + cl_assert((item = git_sortedcache_lookup(sc, "mmm")) != NULL); + cl_assert_equal_s("mmm", item); + cl_assert((item = git_sortedcache_lookup(sc, "zzz")) != NULL); + cl_assert_equal_s("zzz", item); + cl_assert(git_sortedcache_lookup(sc, "qqq") == NULL); + + cl_assert((item = git_sortedcache_entry(sc, 0)) != NULL); + cl_assert_equal_s("aaa", item); + cl_assert((item = git_sortedcache_entry(sc, 1)) != NULL); + cl_assert_equal_s("bbb", item); + cl_assert((item = git_sortedcache_entry(sc, 2)) != NULL); + cl_assert_equal_s("iii", item); + cl_assert((item = git_sortedcache_entry(sc, 3)) != NULL); + cl_assert_equal_s("mmm", item); + cl_assert((item = git_sortedcache_entry(sc, 4)) != NULL); + cl_assert_equal_s("zzz", item); + cl_assert(git_sortedcache_entry(sc, 5) == NULL); + + cl_git_pass(git_sortedcache_lookup_index(&pos, sc, "aaa")); + cl_assert_equal_sz(0, pos); + cl_git_pass(git_sortedcache_lookup_index(&pos, sc, "iii")); + cl_assert_equal_sz(2, pos); + cl_git_pass(git_sortedcache_lookup_index(&pos, sc, "zzz")); + cl_assert_equal_sz(4, pos); + cl_assert_equal_i( + GIT_ENOTFOUND, git_sortedcache_lookup_index(&pos, sc, "abc")); + + git_sortedcache_clear(sc, true); + + cl_assert_equal_sz(0, git_sortedcache_entrycount(sc)); + cl_assert(git_sortedcache_entry(sc, 0) == NULL); + cl_assert(git_sortedcache_lookup(sc, "aaa") == NULL); + cl_assert(git_sortedcache_entry(sc, 0) == NULL); + + git_sortedcache_free(sc); +} + +typedef struct { + int value; + char smaller_value; + char path[GIT_FLEX_ARRAY]; +} sortedcache_test_struct; + +static int sortedcache_test_struct_cmp(const void *a_, const void *b_) +{ + const sortedcache_test_struct *a = a_, *b = b_; + return strcmp(a->path, b->path); +} + +static void sortedcache_test_struct_free(void *payload, void *item_) +{ + sortedcache_test_struct *item = item_; + int *count = payload; + (*count)++; + item->smaller_value = 0; +} + +void test_core_sortedcache__in_memory(void) +{ + git_sortedcache *sc; + sortedcache_test_struct *item; + int free_count = 0; + + cl_git_pass(git_sortedcache_new( + &sc, offsetof(sortedcache_test_struct, path), + sortedcache_test_struct_free, &free_count, + sortedcache_test_struct_cmp, NULL)); + + cl_git_pass(git_sortedcache_wlock(sc)); + cl_git_pass(git_sortedcache_upsert((void **)&item, sc, "aaa")); + item->value = 10; + item->smaller_value = 1; + cl_git_pass(git_sortedcache_upsert((void **)&item, sc, "bbb")); + item->value = 20; + item->smaller_value = 2; + cl_git_pass(git_sortedcache_upsert((void **)&item, sc, "zzz")); + item->value = 30; + item->smaller_value = 26; + cl_git_pass(git_sortedcache_upsert((void **)&item, sc, "mmm")); + item->value = 40; + item->smaller_value = 14; + cl_git_pass(git_sortedcache_upsert((void **)&item, sc, "iii")); + item->value = 50; + item->smaller_value = 9; + git_sortedcache_wunlock(sc); + + cl_assert_equal_sz(5, git_sortedcache_entrycount(sc)); + + cl_git_pass(git_sortedcache_rlock(sc)); + + cl_assert((item = git_sortedcache_lookup(sc, "aaa")) != NULL); + cl_assert_equal_s("aaa", item->path); + cl_assert_equal_i(10, item->value); + cl_assert((item = git_sortedcache_lookup(sc, "mmm")) != NULL); + cl_assert_equal_s("mmm", item->path); + cl_assert_equal_i(40, item->value); + cl_assert((item = git_sortedcache_lookup(sc, "zzz")) != NULL); + cl_assert_equal_s("zzz", item->path); + cl_assert_equal_i(30, item->value); + cl_assert(git_sortedcache_lookup(sc, "abc") == NULL); + + /* not on Windows: + * cl_git_pass(git_sortedcache_rlock(sc)); -- grab more than one + */ + + cl_assert((item = git_sortedcache_entry(sc, 0)) != NULL); + cl_assert_equal_s("aaa", item->path); + cl_assert_equal_i(10, item->value); + cl_assert((item = git_sortedcache_entry(sc, 1)) != NULL); + cl_assert_equal_s("bbb", item->path); + cl_assert_equal_i(20, item->value); + cl_assert((item = git_sortedcache_entry(sc, 2)) != NULL); + cl_assert_equal_s("iii", item->path); + cl_assert_equal_i(50, item->value); + cl_assert((item = git_sortedcache_entry(sc, 3)) != NULL); + cl_assert_equal_s("mmm", item->path); + cl_assert_equal_i(40, item->value); + cl_assert((item = git_sortedcache_entry(sc, 4)) != NULL); + cl_assert_equal_s("zzz", item->path); + cl_assert_equal_i(30, item->value); + cl_assert(git_sortedcache_entry(sc, 5) == NULL); + + git_sortedcache_runlock(sc); + /* git_sortedcache_runlock(sc); */ + + cl_assert_equal_i(0, free_count); + + git_sortedcache_clear(sc, true); + + cl_assert_equal_i(5, free_count); + + cl_assert_equal_sz(0, git_sortedcache_entrycount(sc)); + cl_assert(git_sortedcache_entry(sc, 0) == NULL); + cl_assert(git_sortedcache_lookup(sc, "aaa") == NULL); + cl_assert(git_sortedcache_entry(sc, 0) == NULL); + + free_count = 0; + + cl_git_pass(git_sortedcache_wlock(sc)); + cl_git_pass(git_sortedcache_upsert((void **)&item, sc, "testing")); + item->value = 10; + item->smaller_value = 3; + cl_git_pass(git_sortedcache_upsert((void **)&item, sc, "again")); + item->value = 20; + item->smaller_value = 1; + cl_git_pass(git_sortedcache_upsert((void **)&item, sc, "final")); + item->value = 30; + item->smaller_value = 2; + git_sortedcache_wunlock(sc); + + cl_assert_equal_sz(3, git_sortedcache_entrycount(sc)); + + cl_assert((item = git_sortedcache_lookup(sc, "testing")) != NULL); + cl_assert_equal_s("testing", item->path); + cl_assert_equal_i(10, item->value); + cl_assert((item = git_sortedcache_lookup(sc, "again")) != NULL); + cl_assert_equal_s("again", item->path); + cl_assert_equal_i(20, item->value); + cl_assert((item = git_sortedcache_lookup(sc, "final")) != NULL); + cl_assert_equal_s("final", item->path); + cl_assert_equal_i(30, item->value); + cl_assert(git_sortedcache_lookup(sc, "zzz") == NULL); + + cl_assert((item = git_sortedcache_entry(sc, 0)) != NULL); + cl_assert_equal_s("again", item->path); + cl_assert_equal_i(20, item->value); + cl_assert((item = git_sortedcache_entry(sc, 1)) != NULL); + cl_assert_equal_s("final", item->path); + cl_assert_equal_i(30, item->value); + cl_assert((item = git_sortedcache_entry(sc, 2)) != NULL); + cl_assert_equal_s("testing", item->path); + cl_assert_equal_i(10, item->value); + cl_assert(git_sortedcache_entry(sc, 3) == NULL); + + { + size_t pos; + + cl_git_pass(git_sortedcache_wlock(sc)); + + cl_git_pass(git_sortedcache_lookup_index(&pos, sc, "again")); + cl_assert_equal_sz(0, pos); + cl_git_pass(git_sortedcache_remove(sc, pos)); + cl_assert_equal_i( + GIT_ENOTFOUND, git_sortedcache_lookup_index(&pos, sc, "again")); + + cl_assert_equal_sz(2, git_sortedcache_entrycount(sc)); + + cl_git_pass(git_sortedcache_lookup_index(&pos, sc, "testing")); + cl_assert_equal_sz(1, pos); + cl_git_pass(git_sortedcache_remove(sc, pos)); + cl_assert_equal_i( + GIT_ENOTFOUND, git_sortedcache_lookup_index(&pos, sc, "testing")); + + cl_assert_equal_sz(1, git_sortedcache_entrycount(sc)); + + cl_git_pass(git_sortedcache_lookup_index(&pos, sc, "final")); + cl_assert_equal_sz(0, pos); + cl_git_pass(git_sortedcache_remove(sc, pos)); + cl_assert_equal_i( + GIT_ENOTFOUND, git_sortedcache_lookup_index(&pos, sc, "final")); + + cl_assert_equal_sz(0, git_sortedcache_entrycount(sc)); + + git_sortedcache_wunlock(sc); + } + + git_sortedcache_free(sc); + + cl_assert_equal_i(3, free_count); +} + +static void sortedcache_test_reload(git_sortedcache *sc) +{ + int count = 0; + git_buf buf = GIT_BUF_INIT; + char *scan, *after; + sortedcache_test_struct *item; + + cl_assert(git_sortedcache_lockandload(sc, &buf) > 0); + + git_sortedcache_clear(sc, false); /* clear once we already have lock */ + + for (scan = buf.ptr; *scan; scan = after + 1) { + int val = strtol(scan, &after, 0); + cl_assert(after > scan); + scan = after; + + for (scan = after; git__isspace(*scan); ++scan) /* find start */; + for (after = scan; *after && *after != '\n'; ++after) /* find eol */; + *after = '\0'; + + cl_git_pass(git_sortedcache_upsert((void **)&item, sc, scan)); + + item->value = val; + item->smaller_value = (char)(count++); + } + + git_sortedcache_wunlock(sc); + + git_buf_free(&buf); +} + +void test_core_sortedcache__on_disk(void) +{ + git_sortedcache *sc; + sortedcache_test_struct *item; + int free_count = 0; + size_t pos; + + cl_git_mkfile("cacheitems.txt", "10 abc\n20 bcd\n30 cde\n"); + + cl_git_pass(git_sortedcache_new( + &sc, offsetof(sortedcache_test_struct, path), + sortedcache_test_struct_free, &free_count, + sortedcache_test_struct_cmp, "cacheitems.txt")); + + /* should need to reload the first time */ + + sortedcache_test_reload(sc); + + /* test what we loaded */ + + cl_assert_equal_sz(3, git_sortedcache_entrycount(sc)); + + cl_assert((item = git_sortedcache_lookup(sc, "abc")) != NULL); + cl_assert_equal_s("abc", item->path); + cl_assert_equal_i(10, item->value); + cl_assert((item = git_sortedcache_lookup(sc, "cde")) != NULL); + cl_assert_equal_s("cde", item->path); + cl_assert_equal_i(30, item->value); + cl_assert(git_sortedcache_lookup(sc, "aaa") == NULL); + + cl_assert((item = git_sortedcache_entry(sc, 0)) != NULL); + cl_assert_equal_s("abc", item->path); + cl_assert_equal_i(10, item->value); + cl_assert((item = git_sortedcache_entry(sc, 1)) != NULL); + cl_assert_equal_s("bcd", item->path); + cl_assert_equal_i(20, item->value); + cl_assert(git_sortedcache_entry(sc, 3) == NULL); + + /* should not need to reload this time */ + + cl_assert_equal_i(0, git_sortedcache_lockandload(sc, NULL)); + + /* rewrite ondisk file and reload */ + + cl_assert_equal_i(0, free_count); + + cl_git_rewritefile( + "cacheitems.txt", "100 abc\n200 zzz\n500 aaa\n10 final\n"); + sortedcache_test_reload(sc); + + cl_assert_equal_i(3, free_count); + + /* test what we loaded */ + + cl_assert_equal_sz(4, git_sortedcache_entrycount(sc)); + + cl_assert((item = git_sortedcache_lookup(sc, "abc")) != NULL); + cl_assert_equal_s("abc", item->path); + cl_assert_equal_i(100, item->value); + cl_assert((item = git_sortedcache_lookup(sc, "final")) != NULL); + cl_assert_equal_s("final", item->path); + cl_assert_equal_i(10, item->value); + cl_assert(git_sortedcache_lookup(sc, "cde") == NULL); + + cl_assert((item = git_sortedcache_entry(sc, 0)) != NULL); + cl_assert_equal_s("aaa", item->path); + cl_assert_equal_i(500, item->value); + cl_assert((item = git_sortedcache_entry(sc, 2)) != NULL); + cl_assert_equal_s("final", item->path); + cl_assert_equal_i(10, item->value); + cl_assert((item = git_sortedcache_entry(sc, 3)) != NULL); + cl_assert_equal_s("zzz", item->path); + cl_assert_equal_i(200, item->value); + + cl_git_pass(git_sortedcache_lookup_index(&pos, sc, "aaa")); + cl_assert_equal_sz(0, pos); + cl_git_pass(git_sortedcache_lookup_index(&pos, sc, "abc")); + cl_assert_equal_sz(1, pos); + cl_git_pass(git_sortedcache_lookup_index(&pos, sc, "final")); + cl_assert_equal_sz(2, pos); + cl_git_pass(git_sortedcache_lookup_index(&pos, sc, "zzz")); + cl_assert_equal_sz(3, pos); + cl_assert_equal_i( + GIT_ENOTFOUND, git_sortedcache_lookup_index(&pos, sc, "missing")); + cl_assert_equal_i( + GIT_ENOTFOUND, git_sortedcache_lookup_index(&pos, sc, "cde")); + + git_sortedcache_free(sc); + + cl_assert_equal_i(7, free_count); +} + diff --git a/tests/core/stat.c b/tests/core/stat.c new file mode 100644 index 000000000..2e4abfb79 --- /dev/null +++ b/tests/core/stat.c @@ -0,0 +1,97 @@ +#include "clar_libgit2.h" +#include "fileops.h" +#include "path.h" +#include "posix.h" + +void test_core_stat__initialize(void) +{ + cl_git_pass(git_futils_mkdir("root/d1/d2", NULL, 0755, GIT_MKDIR_PATH)); + cl_git_mkfile("root/file", "whatever\n"); + cl_git_mkfile("root/d1/file", "whatever\n"); +} + +void test_core_stat__cleanup(void) +{ + git_futils_rmdir_r("root", NULL, GIT_RMDIR_REMOVE_FILES); +} + +#define cl_assert_error(val) \ + do { err = errno; cl_assert_equal_i((val), err); } while (0) + +void test_core_stat__0(void) +{ + struct stat st; + int err; + + cl_assert_equal_i(0, p_lstat("root", &st)); + cl_assert(S_ISDIR(st.st_mode)); + cl_assert_error(0); + + cl_assert_equal_i(0, p_lstat("root/", &st)); + cl_assert(S_ISDIR(st.st_mode)); + cl_assert_error(0); + + cl_assert_equal_i(0, p_lstat("root/file", &st)); + cl_assert(S_ISREG(st.st_mode)); + cl_assert_error(0); + + cl_assert_equal_i(0, p_lstat("root/d1", &st)); + cl_assert(S_ISDIR(st.st_mode)); + cl_assert_error(0); + + cl_assert_equal_i(0, p_lstat("root/d1/", &st)); + cl_assert(S_ISDIR(st.st_mode)); + cl_assert_error(0); + + cl_assert_equal_i(0, p_lstat("root/d1/file", &st)); + cl_assert(S_ISREG(st.st_mode)); + cl_assert_error(0); + + cl_assert(p_lstat("root/missing", &st) < 0); + cl_assert_error(ENOENT); + + cl_assert(p_lstat("root/missing/but/could/be/created", &st) < 0); + cl_assert_error(ENOENT); + + cl_assert(p_lstat_posixly("root/missing/but/could/be/created", &st) < 0); + cl_assert_error(ENOENT); + + cl_assert(p_lstat("root/d1/missing", &st) < 0); + cl_assert_error(ENOENT); + + cl_assert(p_lstat("root/d1/missing/deeper/path", &st) < 0); + cl_assert_error(ENOENT); + + cl_assert(p_lstat_posixly("root/d1/missing/deeper/path", &st) < 0); + cl_assert_error(ENOENT); + + cl_assert(p_lstat_posixly("root/d1/file/deeper/path", &st) < 0); + cl_assert_error(ENOTDIR); + + cl_assert(p_lstat("root/file/invalid", &st) < 0); +#ifdef GIT_WIN32 + cl_assert_error(ENOENT); +#else + cl_assert_error(ENOTDIR); +#endif + + cl_assert(p_lstat_posixly("root/file/invalid", &st) < 0); + cl_assert_error(ENOTDIR); + + cl_assert(p_lstat("root/file/invalid/deeper_path", &st) < 0); +#ifdef GIT_WIN32 + cl_assert_error(ENOENT); +#else + cl_assert_error(ENOTDIR); +#endif + + cl_assert(p_lstat_posixly("root/file/invalid/deeper_path", &st) < 0); + cl_assert_error(ENOTDIR); + + cl_assert(p_lstat_posixly("root/d1/file/extra", &st) < 0); + cl_assert_error(ENOTDIR); + + cl_assert(p_lstat_posixly("root/d1/file/further/invalid/items", &st) < 0); + cl_assert_error(ENOTDIR); +} + diff --git a/tests/core/string.c b/tests/core/string.c new file mode 100644 index 000000000..ec9575685 --- /dev/null +++ b/tests/core/string.c @@ -0,0 +1,41 @@ +#include "clar_libgit2.h" + +/* compare prefixes */ +void test_core_string__0(void) +{ + cl_assert(git__prefixcmp("", "") == 0); + cl_assert(git__prefixcmp("a", "") == 0); + cl_assert(git__prefixcmp("", "a") < 0); + cl_assert(git__prefixcmp("a", "b") < 0); + cl_assert(git__prefixcmp("b", "a") > 0); + cl_assert(git__prefixcmp("ab", "a") == 0); + cl_assert(git__prefixcmp("ab", "ac") < 0); + cl_assert(git__prefixcmp("ab", "aa") > 0); +} + +/* compare suffixes */ +void test_core_string__1(void) +{ + cl_assert(git__suffixcmp("", "") == 0); + cl_assert(git__suffixcmp("a", "") == 0); + cl_assert(git__suffixcmp("", "a") < 0); + cl_assert(git__suffixcmp("a", "b") < 0); + cl_assert(git__suffixcmp("b", "a") > 0); + cl_assert(git__suffixcmp("ba", "a") == 0); + cl_assert(git__suffixcmp("zaa", "ac") < 0); + cl_assert(git__suffixcmp("zaz", "ac") > 0); +} + +/* compare icase sorting with case equality */ +void test_core_string__2(void) +{ + cl_assert(git__strcasesort_cmp("", "") == 0); + cl_assert(git__strcasesort_cmp("foo", "foo") == 0); + cl_assert(git__strcasesort_cmp("foo", "bar") > 0); + cl_assert(git__strcasesort_cmp("bar", "foo") < 0); + cl_assert(git__strcasesort_cmp("foo", "FOO") > 0); + cl_assert(git__strcasesort_cmp("FOO", "foo") < 0); + cl_assert(git__strcasesort_cmp("foo", "BAR") > 0); + cl_assert(git__strcasesort_cmp("BAR", "foo") < 0); + cl_assert(git__strcasesort_cmp("fooBar", "foobar") < 0); +} diff --git a/tests/core/strmap.c b/tests/core/strmap.c new file mode 100644 index 000000000..f34a4f89f --- /dev/null +++ b/tests/core/strmap.c @@ -0,0 +1,102 @@ +#include "clar_libgit2.h" +#include "strmap.h" + +GIT__USE_STRMAP; + +void test_core_strmap__0(void) +{ + git_strmap *table = git_strmap_alloc(); + cl_assert(table != NULL); + cl_assert(git_strmap_num_entries(table) == 0); + git_strmap_free(table); +} + +static void insert_strings(git_strmap *table, int count) +{ + int i, j, over, err; + char *str; + + for (i = 0; i < count; ++i) { + str = malloc(10); + for (j = 0; j < 10; ++j) + str[j] = 'a' + (i % 26); + str[9] = '\0'; + + /* if > 26, then encode larger value in first letters */ + for (j = 0, over = i / 26; over > 0; j++, over = over / 26) + str[j] = 'A' + (over % 26); + + git_strmap_insert(table, str, str, err); + cl_assert(err >= 0); + } + + cl_assert((int)git_strmap_num_entries(table) == count); +} + +void test_core_strmap__1(void) +{ + int i; + char *str; + git_strmap *table = git_strmap_alloc(); + cl_assert(table != NULL); + + insert_strings(table, 20); + + cl_assert(git_strmap_exists(table, "aaaaaaaaa")); + cl_assert(git_strmap_exists(table, "ggggggggg")); + cl_assert(!git_strmap_exists(table, "aaaaaaaab")); + cl_assert(!git_strmap_exists(table, "abcdefghi")); + + i = 0; + git_strmap_foreach_value(table, str, { i++; free(str); }); + cl_assert(i == 20); + + git_strmap_free(table); +} + +void test_core_strmap__2(void) +{ + khiter_t pos; + int i; + char *str; + git_strmap *table = git_strmap_alloc(); + cl_assert(table != NULL); + + insert_strings(table, 20); + + cl_assert(git_strmap_exists(table, "aaaaaaaaa")); + cl_assert(git_strmap_exists(table, "ggggggggg")); + cl_assert(!git_strmap_exists(table, "aaaaaaaab")); + cl_assert(!git_strmap_exists(table, "abcdefghi")); + + cl_assert(git_strmap_exists(table, "bbbbbbbbb")); + pos = git_strmap_lookup_index(table, "bbbbbbbbb"); + cl_assert(git_strmap_valid_index(table, pos)); + cl_assert_equal_s(git_strmap_value_at(table, pos), "bbbbbbbbb"); + free(git_strmap_value_at(table, pos)); + git_strmap_delete_at(table, pos); + + cl_assert(!git_strmap_exists(table, "bbbbbbbbb")); + + i = 0; + git_strmap_foreach_value(table, str, { i++; free(str); }); + cl_assert(i == 19); + + git_strmap_free(table); +} + +void test_core_strmap__3(void) +{ + int i; + char *str; + git_strmap *table = git_strmap_alloc(); + cl_assert(table != NULL); + + insert_strings(table, 10000); + + i = 0; + git_strmap_foreach_value(table, str, { i++; free(str); }); + cl_assert(i == 10000); + + git_strmap_free(table); +} diff --git a/tests/core/strtol.c b/tests/core/strtol.c new file mode 100644 index 000000000..8765e042b --- /dev/null +++ b/tests/core/strtol.c @@ -0,0 +1,37 @@ +#include "clar_libgit2.h" + +void test_core_strtol__int32(void) +{ + int32_t i; + + cl_git_pass(git__strtol32(&i, "123", NULL, 10)); + cl_assert(i == 123); + cl_git_pass(git__strtol32(&i, " +123 ", NULL, 10)); + cl_assert(i == 123); + cl_git_pass(git__strtol32(&i, " +2147483647 ", NULL, 10)); + cl_assert(i == 2147483647); + cl_git_pass(git__strtol32(&i, " -2147483648 ", NULL, 10)); + cl_assert(i == -2147483648LL); + + cl_git_fail(git__strtol32(&i, " 2147483657 ", NULL, 10)); + cl_git_fail(git__strtol32(&i, " -2147483657 ", NULL, 10)); +} + +void test_core_strtol__int64(void) +{ + int64_t i; + + cl_git_pass(git__strtol64(&i, "123", NULL, 10)); + cl_assert(i == 123); + cl_git_pass(git__strtol64(&i, " +123 ", NULL, 10)); + cl_assert(i == 123); + cl_git_pass(git__strtol64(&i, " +2147483647 ", NULL, 10)); + cl_assert(i == 2147483647); + cl_git_pass(git__strtol64(&i, " -2147483648 ", NULL, 10)); + cl_assert(i == -2147483648LL); + cl_git_pass(git__strtol64(&i, " 2147483657 ", NULL, 10)); + cl_assert(i == 2147483657LL); + cl_git_pass(git__strtol64(&i, " -2147483657 ", NULL, 10)); + cl_assert(i == -2147483657LL); +} + diff --git a/tests/core/vector.c b/tests/core/vector.c new file mode 100644 index 000000000..db52c004f --- /dev/null +++ b/tests/core/vector.c @@ -0,0 +1,275 @@ +#include "clar_libgit2.h" +#include "vector.h" + +/* initial size of 1 would cause writing past array bounds */ +void test_core_vector__0(void) +{ + git_vector x; + int i; + git_vector_init(&x, 1, NULL); + for (i = 0; i < 10; ++i) { + git_vector_insert(&x, (void*) 0xabc); + } + git_vector_free(&x); +} + + +/* don't read past array bounds on remove() */ +void test_core_vector__1(void) +{ + git_vector x; + // make initial capacity exact for our insertions. + git_vector_init(&x, 3, NULL); + git_vector_insert(&x, (void*) 0xabc); + git_vector_insert(&x, (void*) 0xdef); + git_vector_insert(&x, (void*) 0x123); + + git_vector_remove(&x, 0); // used to read past array bounds. + git_vector_free(&x); +} + + +static int test_cmp(const void *a, const void *b) +{ + return *(const int *)a - *(const int *)b; +} + +/* remove duplicates */ +void test_core_vector__2(void) +{ + git_vector x; + int *ptrs[2]; + + ptrs[0] = git__malloc(sizeof(int)); + ptrs[1] = git__malloc(sizeof(int)); + + *ptrs[0] = 2; + *ptrs[1] = 1; + + cl_git_pass(git_vector_init(&x, 5, test_cmp)); + cl_git_pass(git_vector_insert(&x, ptrs[0])); + cl_git_pass(git_vector_insert(&x, ptrs[1])); + cl_git_pass(git_vector_insert(&x, ptrs[1])); + cl_git_pass(git_vector_insert(&x, ptrs[0])); + cl_git_pass(git_vector_insert(&x, ptrs[1])); + cl_assert(x.length == 5); + + git_vector_uniq(&x, NULL); + cl_assert(x.length == 2); + + git_vector_free(&x); + + git__free(ptrs[0]); + git__free(ptrs[1]); +} + + +static int compare_them(const void *a, const void *b) +{ + return (int)((long)a - (long)b); +} + +/* insert_sorted */ +void test_core_vector__3(void) +{ + git_vector x; + long i; + git_vector_init(&x, 1, &compare_them); + + for (i = 0; i < 10; i += 2) { + git_vector_insert_sorted(&x, (void*)(i + 1), NULL); + } + + for (i = 9; i > 0; i -= 2) { + git_vector_insert_sorted(&x, (void*)(i + 1), NULL); + } + + cl_assert(x.length == 10); + for (i = 0; i < 10; ++i) { + cl_assert(git_vector_get(&x, i) == (void*)(i + 1)); + } + + git_vector_free(&x); +} + +/* insert_sorted with duplicates */ +void test_core_vector__4(void) +{ + git_vector x; + long i; + git_vector_init(&x, 1, &compare_them); + + for (i = 0; i < 10; i += 2) { + git_vector_insert_sorted(&x, (void*)(i + 1), NULL); + } + + for (i = 9; i > 0; i -= 2) { + git_vector_insert_sorted(&x, (void*)(i + 1), NULL); + } + + for (i = 0; i < 10; i += 2) { + git_vector_insert_sorted(&x, (void*)(i + 1), NULL); + } + + for (i = 9; i > 0; i -= 2) { + git_vector_insert_sorted(&x, (void*)(i + 1), NULL); + } + + cl_assert(x.length == 20); + for (i = 0; i < 20; ++i) { + cl_assert(git_vector_get(&x, i) == (void*)(i / 2 + 1)); + } + + git_vector_free(&x); +} + +typedef struct { + int content; + int count; +} my_struct; + +static int _struct_count = 0; + +static int compare_structs(const void *a, const void *b) +{ + return ((const my_struct *)a)->content - + ((const my_struct *)b)->content; +} + +static int merge_structs(void **old_raw, void *new) +{ + my_struct *old = *(my_struct **)old_raw; + cl_assert(((my_struct *)old)->content == ((my_struct *)new)->content); + ((my_struct *)old)->count += 1; + git__free(new); + _struct_count--; + return GIT_EEXISTS; +} + +static my_struct *alloc_struct(int value) +{ + my_struct *st = git__malloc(sizeof(my_struct)); + st->content = value; + st->count = 0; + _struct_count++; + return st; +} + +/* insert_sorted with duplicates and special handling */ +void test_core_vector__5(void) +{ + git_vector x; + int i; + + git_vector_init(&x, 1, &compare_structs); + + for (i = 0; i < 10; i += 2) + git_vector_insert_sorted(&x, alloc_struct(i), &merge_structs); + + for (i = 9; i > 0; i -= 2) + git_vector_insert_sorted(&x, alloc_struct(i), &merge_structs); + + cl_assert(x.length == 10); + cl_assert(_struct_count == 10); + + for (i = 0; i < 10; i += 2) + git_vector_insert_sorted(&x, alloc_struct(i), &merge_structs); + + for (i = 9; i > 0; i -= 2) + git_vector_insert_sorted(&x, alloc_struct(i), &merge_structs); + + cl_assert(x.length == 10); + cl_assert(_struct_count == 10); + + for (i = 0; i < 10; ++i) { + cl_assert(((my_struct *)git_vector_get(&x, i))->content == i); + git__free(git_vector_get(&x, i)); + _struct_count--; + } + + git_vector_free(&x); +} + +static int remove_ones(const git_vector *v, size_t idx) +{ + return (git_vector_get(v, idx) == (void *)0x001); +} + +/* Test removal based on callback */ +void test_core_vector__remove_matching(void) +{ + git_vector x; + size_t i; + void *compare; + + git_vector_init(&x, 1, NULL); + git_vector_insert(&x, (void*) 0x001); + + cl_assert(x.length == 1); + git_vector_remove_matching(&x, remove_ones); + cl_assert(x.length == 0); + + git_vector_insert(&x, (void*) 0x001); + git_vector_insert(&x, (void*) 0x001); + git_vector_insert(&x, (void*) 0x001); + + cl_assert(x.length == 3); + git_vector_remove_matching(&x, remove_ones); + cl_assert(x.length == 0); + + git_vector_insert(&x, (void*) 0x002); + git_vector_insert(&x, (void*) 0x001); + git_vector_insert(&x, (void*) 0x002); + git_vector_insert(&x, (void*) 0x001); + + cl_assert(x.length == 4); + git_vector_remove_matching(&x, remove_ones); + cl_assert(x.length == 2); + + git_vector_foreach(&x, i, compare) { + cl_assert(compare != (void *)0x001); + } + + git_vector_clear(&x); + + git_vector_insert(&x, (void*) 0x001); + git_vector_insert(&x, (void*) 0x002); + git_vector_insert(&x, (void*) 0x002); + git_vector_insert(&x, (void*) 0x001); + + cl_assert(x.length == 4); + git_vector_remove_matching(&x, remove_ones); + cl_assert(x.length == 2); + + git_vector_foreach(&x, i, compare) { + cl_assert(compare != (void *)0x001); + } + + git_vector_clear(&x); + + git_vector_insert(&x, (void*) 0x002); + git_vector_insert(&x, (void*) 0x001); + git_vector_insert(&x, (void*) 0x002); + git_vector_insert(&x, (void*) 0x001); + + cl_assert(x.length == 4); + git_vector_remove_matching(&x, remove_ones); + cl_assert(x.length == 2); + + git_vector_foreach(&x, i, compare) { + cl_assert(compare != (void *)0x001); + } + + git_vector_clear(&x); + + git_vector_insert(&x, (void*) 0x002); + git_vector_insert(&x, (void*) 0x003); + git_vector_insert(&x, (void*) 0x002); + git_vector_insert(&x, (void*) 0x003); + + cl_assert(x.length == 4); + git_vector_remove_matching(&x, remove_ones); + cl_assert(x.length == 4); + + git_vector_free(&x); +} |