summaryrefslogtreecommitdiff
path: root/tests/core
diff options
context:
space:
mode:
Diffstat (limited to 'tests/core')
-rw-r--r--tests/core/buffer.c83
-rw-r--r--tests/core/copy.c26
-rw-r--r--tests/core/env.c73
-rw-r--r--tests/core/errors.c24
-rw-r--r--tests/core/features.c (renamed from tests/core/caps.c)16
-rw-r--r--tests/core/iconv.c12
-rw-r--r--tests/core/link.c602
-rw-r--r--tests/core/path.c48
-rw-r--r--tests/core/pool.c3
-rw-r--r--tests/core/pqueue.c128
-rw-r--r--tests/core/strmap.c72
-rw-r--r--tests/core/vector.c15
-rw-r--r--tests/core/zstream.c143
13 files changed, 1155 insertions, 90 deletions
diff --git a/tests/core/buffer.c b/tests/core/buffer.c
index 11d173d49..da5ec605c 100644
--- a/tests/core/buffer.c
+++ b/tests/core/buffer.c
@@ -406,6 +406,23 @@ check_joinbuf_2(
}
static void
+check_joinbuf_overlapped(
+ const char *oldval,
+ int ofs_a,
+ const char *b,
+ const char *expected)
+{
+ char sep = '/';
+ git_buf buf = GIT_BUF_INIT;
+
+ git_buf_sets(&buf, oldval);
+ git_buf_join(&buf, sep, buf.ptr + ofs_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,
@@ -480,6 +497,20 @@ void test_core_buffer__8(void)
check_joinbuf_2("/abcd/", "defg/", "/abcd/defg/");
check_joinbuf_2("/abcd/", "/defg/", "/abcd/defg/");
+ check_joinbuf_overlapped("abcd", 0, "efg", "abcd/efg");
+ check_joinbuf_overlapped("abcd", 1, "efg", "bcd/efg");
+ check_joinbuf_overlapped("abcd", 2, "efg", "cd/efg");
+ check_joinbuf_overlapped("abcd", 3, "efg", "d/efg");
+ check_joinbuf_overlapped("abcd", 4, "efg", "efg");
+ check_joinbuf_overlapped("abc/", 2, "efg", "c/efg");
+ check_joinbuf_overlapped("abc/", 3, "efg", "/efg");
+ check_joinbuf_overlapped("abc/", 4, "efg", "efg");
+ check_joinbuf_overlapped("abcd", 3, "", "d/");
+ check_joinbuf_overlapped("abcd", 4, "", "");
+ check_joinbuf_overlapped("abc/", 2, "", "c/");
+ check_joinbuf_overlapped("abc/", 3, "", "/");
+ check_joinbuf_overlapped("abc/", 4, "", "");
+
check_joinbuf_n_2("", "", "");
check_joinbuf_n_2("", "a", "a");
check_joinbuf_n_2("", "/a", "/a");
@@ -568,6 +599,38 @@ void test_core_buffer__10(void)
git_buf_free(&a);
}
+void test_core_buffer__join3(void)
+{
+ git_buf a = GIT_BUF_INIT;
+
+ cl_git_pass(git_buf_join3(&a, '/', "test", "string", "join"));
+ cl_assert_equal_s("test/string/join", a.ptr);
+ cl_git_pass(git_buf_join3(&a, '/', "test/", "string", "join"));
+ cl_assert_equal_s("test/string/join", a.ptr);
+ cl_git_pass(git_buf_join3(&a, '/', "test/", "/string", "join"));
+ cl_assert_equal_s("test/string/join", a.ptr);
+ cl_git_pass(git_buf_join3(&a, '/', "test/", "/string/", "join"));
+ cl_assert_equal_s("test/string/join", a.ptr);
+ cl_git_pass(git_buf_join3(&a, '/', "test/", "/string/", "/join"));
+ cl_assert_equal_s("test/string/join", a.ptr);
+
+ cl_git_pass(git_buf_join3(&a, '/', "", "string", "join"));
+ cl_assert_equal_s("string/join", a.ptr);
+ cl_git_pass(git_buf_join3(&a, '/', "", "string/", "join"));
+ cl_assert_equal_s("string/join", a.ptr);
+ cl_git_pass(git_buf_join3(&a, '/', "", "string/", "/join"));
+ cl_assert_equal_s("string/join", a.ptr);
+
+ cl_git_pass(git_buf_join3(&a, '/', "string", "", "join"));
+ cl_assert_equal_s("string/join", a.ptr);
+ cl_git_pass(git_buf_join3(&a, '/', "string/", "", "join"));
+ cl_assert_equal_s("string/join", a.ptr);
+ cl_git_pass(git_buf_join3(&a, '/', "string/", "", "/join"));
+ cl_assert_equal_s("string/join", a.ptr);
+
+ git_buf_free(&a);
+}
+
void test_core_buffer__11(void)
{
git_buf a = GIT_BUF_INIT;
@@ -710,6 +773,26 @@ void test_core_buffer__base64(void)
git_buf_free(&buf);
}
+void test_core_buffer__base85(void)
+{
+ git_buf buf = GIT_BUF_INIT;
+
+ cl_git_pass(git_buf_put_base85(&buf, "this", 4));
+ cl_assert_equal_s("bZBXF", buf.ptr);
+ git_buf_clear(&buf);
+
+ cl_git_pass(git_buf_put_base85(&buf, "two rnds", 8));
+ cl_assert_equal_s("ba!tca&BaE", buf.ptr);
+ git_buf_clear(&buf);
+
+ cl_git_pass(git_buf_put_base85(&buf, "this is base 85 encoded",
+ strlen("this is base 85 encoded")));
+ cl_assert_equal_s("bZBXFAZc?TVqtS-AUHK3Wo~0{WMyOk", buf.ptr);
+ git_buf_clear(&buf);
+
+ git_buf_free(&buf);
+}
+
void test_core_buffer__classify_with_utf8(void)
{
char *data0 = "Simple text\n";
diff --git a/tests/core/copy.c b/tests/core/copy.c
index c0c59c056..04b2dfab5 100644
--- a/tests/core/copy.c
+++ b/tests/core/copy.c
@@ -45,6 +45,16 @@ void test_core_copy__file_in_dir(void)
cl_assert(!git_path_isdir("an_dir"));
}
+void assert_hard_link(const char *path)
+{
+ /* we assert this by checking that there's more than one link to the file */
+ struct stat st;
+
+ cl_assert(git_path_isfile(path));
+ cl_git_pass(p_stat(path, &st));
+ cl_assert(st.st_nlink > 1);
+}
+
void test_core_copy__tree(void)
{
struct stat st;
@@ -122,5 +132,21 @@ void test_core_copy__tree(void)
cl_git_pass(git_futils_rmdir_r("t2", NULL, GIT_RMDIR_REMOVE_FILES));
cl_assert(!git_path_isdir("t2"));
+#ifndef GIT_WIN32
+ cl_git_pass(git_futils_cp_r("src", "t3", GIT_CPDIR_CREATE_EMPTY_DIRS | GIT_CPDIR_LINK_FILES, 0));
+ cl_assert(git_path_isdir("t3"));
+
+ cl_assert(git_path_isdir("t3"));
+ cl_assert(git_path_isdir("t3/b"));
+ cl_assert(git_path_isdir("t3/c"));
+ cl_assert(git_path_isdir("t3/c/d"));
+ cl_assert(git_path_isdir("t3/c/e"));
+
+ assert_hard_link("t3/f1");
+ assert_hard_link("t3/b/f2");
+ assert_hard_link("t3/c/f3");
+ assert_hard_link("t3/c/d/f4");
+#endif
+
cl_git_pass(git_futils_rmdir_r("src", NULL, GIT_RMDIR_REMOVE_FILES));
}
diff --git a/tests/core/env.c b/tests/core/env.c
index 0fa6472d7..293b786db 100644
--- a/tests/core/env.c
+++ b/tests/core/env.c
@@ -1,5 +1,6 @@
#include "clar_libgit2.h"
#include "fileops.h"
+#include "sysdir.h"
#include "path.h"
#ifdef GIT_WIN32
@@ -20,7 +21,7 @@ static char *home_values[] = {
"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 */
+ "f\xe1\x9c\x80ke_\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
@@ -39,14 +40,14 @@ void test_core_env__initialize(void)
}
}
-static void reset_global_search_path(void)
+static void set_global_search_path_from_env(void)
{
- cl_git_pass(git_futils_dirs_set(GIT_FUTILS_DIR_GLOBAL, NULL));
+ cl_git_pass(git_sysdir_set(GIT_SYSDIR_GLOBAL, NULL));
}
-static void reset_system_search_path(void)
+static void set_system_search_path_from_env(void)
{
- cl_git_pass(git_futils_dirs_set(GIT_FUTILS_DIR_SYSTEM, NULL));
+ cl_git_pass(git_sysdir_set(GIT_SYSDIR_SYSTEM, NULL));
}
void test_core_env__cleanup(void)
@@ -68,9 +69,7 @@ void test_core_env__cleanup(void)
(void)p_rmdir(*val);
}
- /* reset search paths to default */
- reset_global_search_path();
- reset_system_search_path();
+ cl_sandbox_set_search_path_defaults();
}
static void setenv_and_check(const char *name, const char *value)
@@ -120,26 +119,26 @@ void test_core_env__0(void)
git_buf_rtruncate_at_char(&path, '/');
cl_assert_equal_i(
- GIT_ENOTFOUND, git_futils_find_global_file(&found, testfile));
+ GIT_ENOTFOUND, git_sysdir_find_global_file(&found, testfile));
setenv_and_check("HOME", path.ptr);
- reset_global_search_path();
+ set_global_search_path_from_env();
- cl_git_pass(git_futils_find_global_file(&found, testfile));
+ cl_git_pass(git_sysdir_find_global_file(&found, testfile));
cl_setenv("HOME", env_save[0]);
- reset_global_search_path();
+ set_global_search_path_from_env();
cl_assert_equal_i(
- GIT_ENOTFOUND, git_futils_find_global_file(&found, testfile));
+ GIT_ENOTFOUND, git_sysdir_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();
+ set_global_search_path_from_env();
- cl_git_pass(git_futils_find_global_file(&found, testfile));
+ cl_git_pass(git_sysdir_find_global_file(&found, testfile));
{
int root = git_path_root(path.ptr);
@@ -147,19 +146,19 @@ void test_core_env__0(void)
if (root >= 0) {
setenv_and_check("USERPROFILE", NULL);
- reset_global_search_path();
+ set_global_search_path_from_env();
cl_assert_equal_i(
- GIT_ENOTFOUND, git_futils_find_global_file(&found, testfile));
+ GIT_ENOTFOUND, git_sysdir_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();
+ set_global_search_path_from_env();
- cl_git_pass(git_futils_find_global_file(&found, testfile));
+ cl_git_pass(git_sysdir_find_global_file(&found, testfile));
}
}
#endif
@@ -177,38 +176,38 @@ 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"));
+ GIT_ENOTFOUND, git_sysdir_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();
+ set_global_search_path_from_env();
cl_assert_equal_i(
- GIT_ENOTFOUND, git_futils_find_global_file(&path, "nonexistentfile"));
+ GIT_ENOTFOUND, git_sysdir_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();
+ set_global_search_path_from_env();
+ set_system_search_path_from_env();
cl_assert_equal_i(
- GIT_ENOTFOUND, git_futils_find_global_file(&path, "nonexistentfile"));
+ GIT_ENOTFOUND, git_sysdir_find_global_file(&path, "nonexistentfile"));
cl_assert_equal_i(
- GIT_ENOTFOUND, git_futils_find_system_file(&path, "nonexistentfile"));
+ GIT_ENOTFOUND, git_sysdir_find_system_file(&path, "nonexistentfile"));
#ifdef GIT_WIN32
cl_git_pass(cl_setenv("PROGRAMFILES", NULL));
- reset_system_search_path();
+ set_system_search_path_from_env();
cl_assert_equal_i(
- GIT_ENOTFOUND, git_futils_find_system_file(&path, "nonexistentfile"));
+ GIT_ENOTFOUND, git_sysdir_find_system_file(&path, "nonexistentfile"));
#endif
git_buf_free(&path);
@@ -217,7 +216,7 @@ void test_core_env__1(void)
static void check_global_searchpath(
const char *path, int position, const char *file, git_buf *temp)
{
- char out[GIT_PATH_MAX];
+ git_buf out = GIT_BUF_INIT;
/* build and set new path */
if (position < 0)
@@ -232,23 +231,25 @@ static void check_global_searchpath(
/* 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)));
+ GIT_OPT_GET_SEARCH_PATH, GIT_CONFIG_LEVEL_GLOBAL, &out));
if (position < 0)
- cl_assert(git__prefixcmp(out, path) == 0);
+ cl_assert(git__prefixcmp(out.ptr, path) == 0);
else if (position > 0)
- cl_assert(git__suffixcmp(out, path) == 0);
+ cl_assert(git__suffixcmp(out.ptr, path) == 0);
else
- cl_assert_equal_s(out, path);
+ cl_assert_equal_s(out.ptr, path);
/* find file using new path */
- cl_git_pass(git_futils_find_global_file(temp, file));
+ cl_git_pass(git_sysdir_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));
+ GIT_ENOTFOUND, git_sysdir_find_global_file(temp, file));
+
+ git_buf_free(&out);
}
void test_core_env__2(void)
@@ -285,7 +286,7 @@ void test_core_env__2(void)
/* default should be NOTFOUND */
cl_assert_equal_i(
- GIT_ENOTFOUND, git_futils_find_global_file(&found, testfile));
+ GIT_ENOTFOUND, git_sysdir_find_global_file(&found, testfile));
/* try plain, append $PATH, and prepend $PATH */
check_global_searchpath(path.ptr, 0, testfile, &found);
diff --git a/tests/core/errors.c b/tests/core/errors.c
index 512a4134d..366d8f16a 100644
--- a/tests/core/errors.c
+++ b/tests/core/errors.c
@@ -85,3 +85,27 @@ void test_core_errors__new_school(void)
giterr_clear();
}
+
+void test_core_errors__restore(void)
+{
+ git_error_state err_state = {0};
+
+ giterr_clear();
+ cl_assert(giterr_last() == NULL);
+
+ cl_assert_equal_i(0, giterr_capture(&err_state, 0));
+
+ memset(&err_state, 0x0, sizeof(git_error_state));
+
+ giterr_set(42, "Foo: %s", "bar");
+ cl_assert_equal_i(-1, giterr_capture(&err_state, -1));
+
+ cl_assert(giterr_last() == NULL);
+
+ giterr_set(99, "Bar: %s", "foo");
+
+ giterr_restore(&err_state);
+
+ cl_assert_equal_i(42, giterr_last()->klass);
+ cl_assert_equal_s("Foo: bar", giterr_last()->message);
+}
diff --git a/tests/core/caps.c b/tests/core/features.c
index 68a518ed7..3ce02f4d6 100644
--- a/tests/core/caps.c
+++ b/tests/core/features.c
@@ -1,6 +1,6 @@
#include "clar_libgit2.h"
-void test_core_caps__0(void)
+void test_core_features__0(void)
{
int major, minor, rev, caps;
@@ -9,23 +9,23 @@ void test_core_caps__0(void)
cl_assert_equal_i(LIBGIT2_VER_MINOR, minor);
cl_assert_equal_i(LIBGIT2_VER_REVISION, rev);
- caps = git_libgit2_capabilities();
+ caps = git_libgit2_features();
#ifdef GIT_THREADS
- cl_assert((caps & GIT_CAP_THREADS) != 0);
+ cl_assert((caps & GIT_FEATURE_THREADS) != 0);
#else
- cl_assert((caps & GIT_CAP_THREADS) == 0);
+ cl_assert((caps & GIT_FEATURE_THREADS) == 0);
#endif
#if defined(GIT_SSL) || defined(GIT_WINHTTP)
- cl_assert((caps & GIT_CAP_HTTPS) != 0);
+ cl_assert((caps & GIT_FEATURE_HTTPS) != 0);
#else
- cl_assert((caps & GIT_CAP_HTTPS) == 0);
+ cl_assert((caps & GIT_FEATURE_HTTPS) == 0);
#endif
#if defined(GIT_SSH)
- cl_assert((caps & GIT_CAP_SSH) != 0);
+ cl_assert((caps & GIT_FEATURE_SSH) != 0);
#else
- cl_assert((caps & GIT_CAP_SSH) == 0);
+ cl_assert((caps & GIT_FEATURE_SSH) == 0);
#endif
}
diff --git a/tests/core/iconv.c b/tests/core/iconv.c
index 8aedab206..cb85f458a 100644
--- a/tests/core/iconv.c
+++ b/tests/core/iconv.c
@@ -39,8 +39,9 @@ void test_core_iconv__decomposed_to_precomposed(void)
{
#ifdef GIT_USE_ICONV
char *data = nfd;
- size_t datalen = strlen(nfd);
+ size_t datalen, nfdlen = strlen(nfd);
+ datalen = nfdlen;
cl_git_pass(git_path_iconv(&ic, &data, &datalen));
GIT_UNUSED(datalen);
@@ -48,6 +49,15 @@ void test_core_iconv__decomposed_to_precomposed(void)
* (on platforms where iconv is enabled, of course).
*/
cl_assert_equal_s(nfc, data);
+
+ /* should be able to do it multiple times with the same git_path_iconv_t */
+ data = nfd; datalen = nfdlen;
+ cl_git_pass(git_path_iconv(&ic, &data, &datalen));
+ cl_assert_equal_s(nfc, data);
+
+ data = nfd; datalen = nfdlen;
+ cl_git_pass(git_path_iconv(&ic, &data, &datalen));
+ cl_assert_equal_s(nfc, data);
#endif
}
diff --git a/tests/core/link.c b/tests/core/link.c
new file mode 100644
index 000000000..1794a3893
--- /dev/null
+++ b/tests/core/link.c
@@ -0,0 +1,602 @@
+#include "clar_libgit2.h"
+#include "posix.h"
+#include "buffer.h"
+#include "path.h"
+
+#ifdef GIT_WIN32
+# include "win32/reparse.h"
+#endif
+
+void test_core_link__cleanup(void)
+{
+#ifdef GIT_WIN32
+ RemoveDirectory("lstat_junction");
+ RemoveDirectory("lstat_dangling");
+ RemoveDirectory("lstat_dangling_dir");
+ RemoveDirectory("lstat_dangling_junction");
+
+ RemoveDirectory("stat_junction");
+ RemoveDirectory("stat_dangling");
+ RemoveDirectory("stat_dangling_dir");
+ RemoveDirectory("stat_dangling_junction");
+#endif
+}
+
+#ifdef GIT_WIN32
+static bool is_administrator(void)
+{
+ static SID_IDENTIFIER_AUTHORITY authority = { SECURITY_NT_AUTHORITY };
+ PSID admin_sid;
+ BOOL is_admin;
+
+ cl_win32_pass(AllocateAndInitializeSid(&authority, 2, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0, &admin_sid));
+ cl_win32_pass(CheckTokenMembership(NULL, admin_sid, &is_admin));
+ FreeSid(admin_sid);
+
+ return is_admin ? true : false;
+}
+#endif
+
+static void do_symlink(const char *old, const char *new, int is_dir)
+{
+#ifndef GIT_WIN32
+ GIT_UNUSED(is_dir);
+
+ cl_must_pass(symlink(old, new));
+#else
+ typedef DWORD (WINAPI *create_symlink_func)(LPCTSTR, LPCTSTR, DWORD);
+ HMODULE module;
+ create_symlink_func pCreateSymbolicLink;
+
+ if (!is_administrator())
+ clar__skip();
+
+ cl_assert(module = GetModuleHandle("kernel32"));
+ cl_assert(pCreateSymbolicLink = (create_symlink_func)GetProcAddress(module, "CreateSymbolicLinkA"));
+
+ cl_win32_pass(pCreateSymbolicLink(new, old, is_dir));
+#endif
+}
+
+static void do_hardlink(const char *old, const char *new)
+{
+#ifndef GIT_WIN32
+ cl_must_pass(link(old, new));
+#else
+ typedef DWORD (WINAPI *create_hardlink_func)(LPCTSTR, LPCTSTR, LPSECURITY_ATTRIBUTES);
+ HMODULE module;
+ create_hardlink_func pCreateHardLink;
+
+ if (!is_administrator())
+ clar__skip();
+
+ cl_assert(module = GetModuleHandle("kernel32"));
+ cl_assert(pCreateHardLink = (create_hardlink_func)GetProcAddress(module, "CreateHardLinkA"));
+
+ cl_win32_pass(pCreateHardLink(new, old, 0));
+#endif
+}
+
+#ifdef GIT_WIN32
+
+static void do_junction(const char *old, const char *new)
+{
+ GIT_REPARSE_DATA_BUFFER *reparse_buf;
+ HANDLE handle;
+ git_buf unparsed_buf = GIT_BUF_INIT;
+ wchar_t *subst_utf16, *print_utf16;
+ DWORD ioctl_ret;
+ int subst_utf16_len, subst_byte_len, print_utf16_len, print_byte_len, ret;
+ USHORT reparse_buflen;
+ size_t i;
+
+ /* Junction targets must be the unparsed name, starting with \??\, using
+ * backslashes instead of forward, and end in a trailing backslash.
+ * eg: \??\C:\Foo\
+ */
+ git_buf_puts(&unparsed_buf, "\\??\\");
+
+ for (i = 0; i < strlen(old); i++)
+ git_buf_putc(&unparsed_buf, old[i] == '/' ? '\\' : old[i]);
+
+ git_buf_putc(&unparsed_buf, '\\');
+
+ subst_utf16_len = git__utf8_to_16(NULL, 0, git_buf_cstr(&unparsed_buf));
+ subst_byte_len = subst_utf16_len * sizeof(WCHAR);
+
+ print_utf16_len = subst_utf16_len - 4;
+ print_byte_len = subst_byte_len - (4 * sizeof(WCHAR));
+
+ /* The junction must be an empty directory before the junction attribute
+ * can be added.
+ */
+ cl_win32_pass(CreateDirectoryA(new, NULL));
+
+ handle = CreateFileA(new, GENERIC_WRITE, 0, NULL, OPEN_EXISTING,
+ FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS, NULL);
+ cl_win32_pass(handle != INVALID_HANDLE_VALUE);
+
+ reparse_buflen = (USHORT)(REPARSE_DATA_HEADER_SIZE +
+ REPARSE_DATA_MOUNTPOINT_HEADER_SIZE +
+ subst_byte_len + sizeof(WCHAR) +
+ print_byte_len + sizeof(WCHAR));
+
+ reparse_buf = LocalAlloc(LMEM_FIXED|LMEM_ZEROINIT, reparse_buflen);
+ cl_assert(reparse_buf);
+
+ subst_utf16 = reparse_buf->MountPointReparseBuffer.PathBuffer;
+ print_utf16 = subst_utf16 + subst_utf16_len + 1;
+
+ ret = git__utf8_to_16(subst_utf16, subst_utf16_len + 1,
+ git_buf_cstr(&unparsed_buf));
+ cl_assert_equal_i(subst_utf16_len, ret);
+
+ ret = git__utf8_to_16(print_utf16,
+ print_utf16_len + 1, git_buf_cstr(&unparsed_buf) + 4);
+ cl_assert_equal_i(print_utf16_len, ret);
+
+ reparse_buf->ReparseTag = IO_REPARSE_TAG_MOUNT_POINT;
+ reparse_buf->MountPointReparseBuffer.SubstituteNameOffset = 0;
+ reparse_buf->MountPointReparseBuffer.SubstituteNameLength = subst_byte_len;
+ reparse_buf->MountPointReparseBuffer.PrintNameOffset = (USHORT)(subst_byte_len + sizeof(WCHAR));
+ reparse_buf->MountPointReparseBuffer.PrintNameLength = print_byte_len;
+ reparse_buf->ReparseDataLength = reparse_buflen - REPARSE_DATA_HEADER_SIZE;
+
+ cl_win32_pass(DeviceIoControl(handle, FSCTL_SET_REPARSE_POINT,
+ reparse_buf, reparse_buflen, NULL, 0, &ioctl_ret, NULL));
+
+ CloseHandle(handle);
+ LocalFree(reparse_buf);
+}
+
+static void do_custom_reparse(const char *path)
+{
+ REPARSE_GUID_DATA_BUFFER *reparse_buf;
+ HANDLE handle;
+ DWORD ioctl_ret;
+
+ const char *reparse_data = "Reparse points are silly.";
+ size_t reparse_buflen = REPARSE_GUID_DATA_BUFFER_HEADER_SIZE +
+ strlen(reparse_data) + 1;
+
+ reparse_buf = LocalAlloc(LMEM_FIXED|LMEM_ZEROINIT, reparse_buflen);
+ cl_assert(reparse_buf);
+
+ reparse_buf->ReparseTag = 42;
+ reparse_buf->ReparseDataLength = (WORD)(strlen(reparse_data) + 1);
+
+ reparse_buf->ReparseGuid.Data1 = 0xdeadbeef;
+ reparse_buf->ReparseGuid.Data2 = 0xdead;
+ reparse_buf->ReparseGuid.Data3 = 0xbeef;
+ reparse_buf->ReparseGuid.Data4[0] = 42;
+ reparse_buf->ReparseGuid.Data4[1] = 42;
+ reparse_buf->ReparseGuid.Data4[2] = 42;
+ reparse_buf->ReparseGuid.Data4[3] = 42;
+ reparse_buf->ReparseGuid.Data4[4] = 42;
+ reparse_buf->ReparseGuid.Data4[5] = 42;
+ reparse_buf->ReparseGuid.Data4[6] = 42;
+ reparse_buf->ReparseGuid.Data4[7] = 42;
+ reparse_buf->ReparseGuid.Data4[8] = 42;
+
+ memcpy(reparse_buf->GenericReparseBuffer.DataBuffer,
+ reparse_data, strlen(reparse_data) + 1);
+
+ handle = CreateFileA(path, GENERIC_WRITE, 0, NULL, OPEN_EXISTING,
+ FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS, NULL);
+ cl_win32_pass(handle != INVALID_HANDLE_VALUE);
+
+ cl_win32_pass(DeviceIoControl(handle, FSCTL_SET_REPARSE_POINT,
+ reparse_buf,
+ reparse_buf->ReparseDataLength + REPARSE_GUID_DATA_BUFFER_HEADER_SIZE,
+ NULL, 0, &ioctl_ret, NULL));
+
+ CloseHandle(handle);
+ LocalFree(reparse_buf);
+}
+
+#endif
+
+git_buf *unslashify(git_buf *buf)
+{
+#ifdef GIT_WIN32
+ size_t i;
+
+ for (i = 0; i < buf->size; i++)
+ if (buf->ptr[i] == '/')
+ buf->ptr[i] = '\\';
+#endif
+
+ return buf;
+}
+
+void test_core_link__stat_regular_file(void)
+{
+ struct stat st;
+
+ cl_git_rewritefile("stat_regfile", "This is a regular file!\n");
+
+ cl_must_pass(p_stat("stat_regfile", &st));
+ cl_assert(S_ISREG(st.st_mode));
+ cl_assert_equal_i(24, st.st_size);
+}
+
+void test_core_link__lstat_regular_file(void)
+{
+ struct stat st;
+
+ cl_git_rewritefile("lstat_regfile", "This is a regular file!\n");
+
+ cl_must_pass(p_stat("lstat_regfile", &st));
+ cl_assert(S_ISREG(st.st_mode));
+ cl_assert_equal_i(24, st.st_size);
+}
+
+void test_core_link__stat_symlink(void)
+{
+ struct stat st;
+
+ cl_git_rewritefile("stat_target", "This is the target of a symbolic link.\n");
+ do_symlink("stat_target", "stat_symlink", 0);
+
+ cl_must_pass(p_stat("stat_target", &st));
+ cl_assert(S_ISREG(st.st_mode));
+ cl_assert_equal_i(39, st.st_size);
+
+ cl_must_pass(p_stat("stat_symlink", &st));
+ cl_assert(S_ISREG(st.st_mode));
+ cl_assert_equal_i(39, st.st_size);
+}
+
+void test_core_link__stat_symlink_directory(void)
+{
+ struct stat st;
+
+ p_mkdir("stat_dirtarget", 0777);
+ do_symlink("stat_dirtarget", "stat_dirlink", 1);
+
+ cl_must_pass(p_stat("stat_dirtarget", &st));
+ cl_assert(S_ISDIR(st.st_mode));
+
+ cl_must_pass(p_stat("stat_dirlink", &st));
+ cl_assert(S_ISDIR(st.st_mode));
+}
+
+void test_core_link__stat_symlink_chain(void)
+{
+ struct stat st;
+
+ cl_git_rewritefile("stat_final_target", "Final target of some symbolic links...\n");
+ do_symlink("stat_final_target", "stat_chain_3", 0);
+ do_symlink("stat_chain_3", "stat_chain_2", 0);
+ do_symlink("stat_chain_2", "stat_chain_1", 0);
+
+ cl_must_pass(p_stat("stat_chain_1", &st));
+ cl_assert(S_ISREG(st.st_mode));
+ cl_assert_equal_i(39, st.st_size);
+}
+
+void test_core_link__stat_dangling_symlink(void)
+{
+ struct stat st;
+
+ do_symlink("stat_nonexistent", "stat_dangling", 0);
+
+ cl_must_fail(p_stat("stat_nonexistent", &st));
+ cl_must_fail(p_stat("stat_dangling", &st));
+}
+
+void test_core_link__stat_dangling_symlink_directory(void)
+{
+ struct stat st;
+
+ do_symlink("stat_nonexistent", "stat_dangling_dir", 1);
+
+ cl_must_fail(p_stat("stat_nonexistent_dir", &st));
+ cl_must_fail(p_stat("stat_dangling", &st));
+}
+
+void test_core_link__lstat_symlink(void)
+{
+ git_buf target_path = GIT_BUF_INIT;
+ struct stat st;
+
+ /* Windows always writes the canonical path as the link target, so
+ * write the full path on all platforms.
+ */
+ git_buf_join(&target_path, '/', clar_sandbox_path(), "lstat_target");
+
+ cl_git_rewritefile("lstat_target", "This is the target of a symbolic link.\n");
+ do_symlink(git_buf_cstr(&target_path), "lstat_symlink", 0);
+
+ cl_must_pass(p_lstat("lstat_target", &st));
+ cl_assert(S_ISREG(st.st_mode));
+ cl_assert_equal_i(39, st.st_size);
+
+ cl_must_pass(p_lstat("lstat_symlink", &st));
+ cl_assert(S_ISLNK(st.st_mode));
+ cl_assert_equal_i(git_buf_len(&target_path), st.st_size);
+
+ git_buf_free(&target_path);
+}
+
+void test_core_link__lstat_symlink_directory(void)
+{
+ git_buf target_path = GIT_BUF_INIT;
+ struct stat st;
+
+ git_buf_join(&target_path, '/', clar_sandbox_path(), "lstat_dirtarget");
+
+ p_mkdir("lstat_dirtarget", 0777);
+ do_symlink(git_buf_cstr(&target_path), "lstat_dirlink", 1);
+
+ cl_must_pass(p_lstat("lstat_dirtarget", &st));
+ cl_assert(S_ISDIR(st.st_mode));
+
+ cl_must_pass(p_lstat("lstat_dirlink", &st));
+ cl_assert(S_ISLNK(st.st_mode));
+ cl_assert_equal_i(git_buf_len(&target_path), st.st_size);
+
+ git_buf_free(&target_path);
+}
+
+void test_core_link__lstat_dangling_symlink(void)
+{
+ struct stat st;
+
+ do_symlink("lstat_nonexistent", "lstat_dangling", 0);
+
+ cl_must_fail(p_lstat("lstat_nonexistent", &st));
+
+ cl_must_pass(p_lstat("lstat_dangling", &st));
+ cl_assert(S_ISLNK(st.st_mode));
+ cl_assert_equal_i(strlen("lstat_nonexistent"), st.st_size);
+}
+
+void test_core_link__lstat_dangling_symlink_directory(void)
+{
+ struct stat st;
+
+ do_symlink("lstat_nonexistent", "lstat_dangling_dir", 1);
+
+ cl_must_fail(p_lstat("lstat_nonexistent", &st));
+
+ cl_must_pass(p_lstat("lstat_dangling_dir", &st));
+ cl_assert(S_ISLNK(st.st_mode));
+ cl_assert_equal_i(strlen("lstat_nonexistent"), st.st_size);
+}
+
+void test_core_link__stat_junction(void)
+{
+#ifdef GIT_WIN32
+ git_buf target_path = GIT_BUF_INIT;
+ struct stat st;
+
+ git_buf_join(&target_path, '/', clar_sandbox_path(), "stat_junctarget");
+
+ p_mkdir("stat_junctarget", 0777);
+ do_junction(git_buf_cstr(&target_path), "stat_junction");
+
+ cl_must_pass(p_stat("stat_junctarget", &st));
+ cl_assert(S_ISDIR(st.st_mode));
+
+ cl_must_pass(p_stat("stat_junction", &st));
+ cl_assert(S_ISDIR(st.st_mode));
+
+ git_buf_free(&target_path);
+#endif
+}
+
+void test_core_link__stat_dangling_junction(void)
+{
+#ifdef GIT_WIN32
+ git_buf target_path = GIT_BUF_INIT;
+ struct stat st;
+
+ git_buf_join(&target_path, '/', clar_sandbox_path(), "stat_nonexistent_junctarget");
+
+ p_mkdir("stat_nonexistent_junctarget", 0777);
+ do_junction(git_buf_cstr(&target_path), "stat_dangling_junction");
+
+ RemoveDirectory("stat_nonexistent_junctarget");
+
+ cl_must_fail(p_stat("stat_nonexistent_junctarget", &st));
+ cl_must_fail(p_stat("stat_dangling_junction", &st));
+
+ git_buf_free(&target_path);
+#endif
+}
+
+void test_core_link__lstat_junction(void)
+{
+#ifdef GIT_WIN32
+ git_buf target_path = GIT_BUF_INIT;
+ struct stat st;
+
+ git_buf_join(&target_path, '/', clar_sandbox_path(), "lstat_junctarget");
+
+ p_mkdir("lstat_junctarget", 0777);
+ do_junction(git_buf_cstr(&target_path), "lstat_junction");
+
+ cl_must_pass(p_lstat("lstat_junctarget", &st));
+ cl_assert(S_ISDIR(st.st_mode));
+
+ cl_must_pass(p_lstat("lstat_junction", &st));
+ cl_assert(S_ISLNK(st.st_mode));
+
+ git_buf_free(&target_path);
+#endif
+}
+
+void test_core_link__lstat_dangling_junction(void)
+{
+#ifdef GIT_WIN32
+ git_buf target_path = GIT_BUF_INIT;
+ struct stat st;
+
+ git_buf_join(&target_path, '/', clar_sandbox_path(), "lstat_nonexistent_junctarget");
+
+ p_mkdir("lstat_nonexistent_junctarget", 0777);
+ do_junction(git_buf_cstr(&target_path), "lstat_dangling_junction");
+
+ RemoveDirectory("lstat_nonexistent_junctarget");
+
+ cl_must_fail(p_lstat("lstat_nonexistent_junctarget", &st));
+
+ cl_must_pass(p_lstat("lstat_dangling_junction", &st));
+ cl_assert(S_ISLNK(st.st_mode));
+ cl_assert_equal_i(git_buf_len(&target_path), st.st_size);
+
+ git_buf_free(&target_path);
+#endif
+}
+
+void test_core_link__stat_hardlink(void)
+{
+ struct stat st;
+
+ cl_git_rewritefile("stat_hardlink1", "This file has many names!\n");
+ do_hardlink("stat_hardlink1", "stat_hardlink2");
+
+ cl_must_pass(p_stat("stat_hardlink1", &st));
+ cl_assert(S_ISREG(st.st_mode));
+ cl_assert_equal_i(26, st.st_size);
+
+ cl_must_pass(p_stat("stat_hardlink2", &st));
+ cl_assert(S_ISREG(st.st_mode));
+ cl_assert_equal_i(26, st.st_size);
+}
+
+void test_core_link__lstat_hardlink(void)
+{
+ struct stat st;
+
+ cl_git_rewritefile("lstat_hardlink1", "This file has many names!\n");
+ do_hardlink("lstat_hardlink1", "lstat_hardlink2");
+
+ cl_must_pass(p_lstat("lstat_hardlink1", &st));
+ cl_assert(S_ISREG(st.st_mode));
+ cl_assert_equal_i(26, st.st_size);
+
+ cl_must_pass(p_lstat("lstat_hardlink2", &st));
+ cl_assert(S_ISREG(st.st_mode));
+ cl_assert_equal_i(26, st.st_size);
+}
+
+void test_core_link__stat_reparse_point(void)
+{
+#ifdef GIT_WIN32
+ struct stat st;
+
+ /* Generic reparse points should be treated as regular files, only
+ * symlinks and junctions should be treated as links.
+ */
+
+ cl_git_rewritefile("stat_reparse", "This is a reparse point!\n");
+ do_custom_reparse("stat_reparse");
+
+ cl_must_pass(p_lstat("stat_reparse", &st));
+ cl_assert(S_ISREG(st.st_mode));
+ cl_assert_equal_i(25, st.st_size);
+#endif
+}
+
+void test_core_link__lstat_reparse_point(void)
+{
+#ifdef GIT_WIN32
+ struct stat st;
+
+ cl_git_rewritefile("lstat_reparse", "This is a reparse point!\n");
+ do_custom_reparse("lstat_reparse");
+
+ cl_must_pass(p_lstat("lstat_reparse", &st));
+ cl_assert(S_ISREG(st.st_mode));
+ cl_assert_equal_i(25, st.st_size);
+#endif
+}
+
+void test_core_link__readlink_nonexistent_file(void)
+{
+ char buf[2048];
+
+ cl_must_fail(p_readlink("readlink_nonexistent", buf, 2048));
+ cl_assert_equal_i(ENOENT, errno);
+}
+
+void test_core_link__readlink_normal_file(void)
+{
+ char buf[2048];
+
+ cl_git_rewritefile("readlink_regfile", "This is a regular file!\n");
+ cl_must_fail(p_readlink("readlink_regfile", buf, 2048));
+ cl_assert_equal_i(EINVAL, errno);
+}
+
+void test_core_link__readlink_symlink(void)
+{
+ git_buf target_path = GIT_BUF_INIT;
+ int len;
+ char buf[2048];
+
+ git_buf_join(&target_path, '/', clar_sandbox_path(), "readlink_target");
+
+ cl_git_rewritefile("readlink_target", "This is the target of a symlink\n");
+ do_symlink(git_buf_cstr(&target_path), "readlink_link", 0);
+
+ len = p_readlink("readlink_link", buf, 2048);
+ cl_must_pass(len);
+
+ buf[len] = 0;
+
+ cl_assert_equal_s(git_buf_cstr(unslashify(&target_path)), buf);
+
+ git_buf_free(&target_path);
+}
+
+void test_core_link__readlink_dangling(void)
+{
+ git_buf target_path = GIT_BUF_INIT;
+ int len;
+ char buf[2048];
+
+ git_buf_join(&target_path, '/', clar_sandbox_path(), "readlink_nonexistent");
+
+ do_symlink(git_buf_cstr(&target_path), "readlink_dangling", 0);
+
+ len = p_readlink("readlink_dangling", buf, 2048);
+ cl_must_pass(len);
+
+ buf[len] = 0;
+
+ cl_assert_equal_s(git_buf_cstr(unslashify(&target_path)), buf);
+
+ git_buf_free(&target_path);
+}
+
+void test_core_link__readlink_multiple(void)
+{
+ git_buf target_path = GIT_BUF_INIT,
+ path3 = GIT_BUF_INIT, path2 = GIT_BUF_INIT, path1 = GIT_BUF_INIT;
+ int len;
+ char buf[2048];
+
+ git_buf_join(&target_path, '/', clar_sandbox_path(), "readlink_final");
+ git_buf_join(&path3, '/', clar_sandbox_path(), "readlink_3");
+ git_buf_join(&path2, '/', clar_sandbox_path(), "readlink_2");
+ git_buf_join(&path1, '/', clar_sandbox_path(), "readlink_1");
+
+ do_symlink(git_buf_cstr(&target_path), git_buf_cstr(&path3), 0);
+ do_symlink(git_buf_cstr(&path3), git_buf_cstr(&path2), 0);
+ do_symlink(git_buf_cstr(&path2), git_buf_cstr(&path1), 0);
+
+ len = p_readlink("readlink_1", buf, 2048);
+ cl_must_pass(len);
+
+ buf[len] = 0;
+
+ cl_assert_equal_s(git_buf_cstr(unslashify(&path2)), buf);
+
+ git_buf_free(&path1);
+ git_buf_free(&path2);
+ git_buf_free(&path3);
+ git_buf_free(&target_path);
+}
diff --git a/tests/core/path.c b/tests/core/path.c
index cf2d5e944..471491b87 100644
--- a/tests/core/path.c
+++ b/tests/core/path.c
@@ -350,15 +350,26 @@ void test_core_path__10_fromurl(void)
typedef struct {
int expect_idx;
+ int cancel_after;
char **expect;
} check_walkup_info;
+#define CANCEL_VALUE 1234
+
static int check_one_walkup_step(void *ref, git_buf *path)
{
check_walkup_info *info = (check_walkup_info *)ref;
+
+ if (!info->cancel_after) {
+ cl_assert_equal_s(info->expect[info->expect_idx], "[CANCEL]");
+ return CANCEL_VALUE;
+ }
+ info->cancel_after--;
+
cl_assert(info->expect[info->expect_idx] != NULL);
cl_assert_equal_s(info->expect[info->expect_idx], path->ptr);
info->expect_idx++;
+
return 0;
}
@@ -381,6 +392,7 @@ void test_core_path__11_walkup(void)
check_walkup_info info;
info.expect = expect;
+ info.cancel_after = -1;
for (i = 0, j = 0; expect[i] != NULL; i++, j++) {
@@ -400,6 +412,42 @@ void test_core_path__11_walkup(void)
git_buf_free(&p);
}
+void test_core_path__11a_walkup_cancel(void)
+{
+ git_buf p = GIT_BUF_INIT;
+ int cancel[] = { 3, 2, 1, 0 };
+ char *expect[] = {
+ "/a/b/c/d/e/", "/a/b/c/d/", "/a/b/c/", "[CANCEL]", NULL,
+ "/a/b/c/d/e", "/a/b/c/d/", "[CANCEL]", NULL,
+ "/a/b/c/d/e", "[CANCEL]", NULL,
+ "[CANCEL]", NULL,
+ NULL
+ };
+ char *root[] = { 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.cancel_after = cancel[j];
+ info.expect_idx = i;
+
+ cl_assert_equal_i(
+ CANCEL_VALUE,
+ git_path_walk_up(&p, root[j], check_one_walkup_step, &info)
+ );
+
+ /* 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);
diff --git a/tests/core/pool.c b/tests/core/pool.c
index 3073c4a45..351d0c20f 100644
--- a/tests/core/pool.c
+++ b/tests/core/pool.c
@@ -139,7 +139,8 @@ 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);
+ /* ensure 64 bit doesn't overflow */
+ cl_assert(git_pool_strndup(&p, "foo", (size_t)-1) == NULL);
git_pool_clear(&p);
}
diff --git a/tests/core/pqueue.c b/tests/core/pqueue.c
new file mode 100644
index 000000000..bcd4eea9f
--- /dev/null
+++ b/tests/core/pqueue.c
@@ -0,0 +1,128 @@
+#include "clar_libgit2.h"
+#include "pqueue.h"
+
+static int cmp_ints(const void *v1, const void *v2)
+{
+ int i1 = *(int *)v1, i2 = *(int *)v2;
+ return (i1 < i2) ? -1 : (i1 > i2) ? 1 : 0;
+}
+
+void test_core_pqueue__items_are_put_in_order(void)
+{
+ git_pqueue pq;
+ int i, vals[20];
+
+ cl_git_pass(git_pqueue_init(&pq, 0, 20, cmp_ints));
+
+ for (i = 0; i < 20; ++i) {
+ if (i < 10)
+ vals[i] = 10 - i; /* 10 down to 1 */
+ else
+ vals[i] = i + 1; /* 11 up to 20 */
+
+ cl_git_pass(git_pqueue_insert(&pq, &vals[i]));
+ }
+
+ cl_assert_equal_i(20, git_pqueue_size(&pq));
+
+ for (i = 1; i <= 20; ++i) {
+ void *p = git_pqueue_pop(&pq);
+ cl_assert(p);
+ cl_assert_equal_i(i, *(int *)p);
+ }
+
+ cl_assert_equal_i(0, git_pqueue_size(&pq));
+
+ git_pqueue_free(&pq);
+}
+
+void test_core_pqueue__interleave_inserts_and_pops(void)
+{
+ git_pqueue pq;
+ int chunk, v, i, vals[200];
+
+ cl_git_pass(git_pqueue_init(&pq, 0, 20, cmp_ints));
+
+ for (v = 0, chunk = 20; chunk <= 200; chunk += 20) {
+ /* push the next 20 */
+ for (; v < chunk; ++v) {
+ vals[v] = (v & 1) ? 200 - v : v;
+ cl_git_pass(git_pqueue_insert(&pq, &vals[v]));
+ }
+
+ /* pop the lowest 10 */
+ for (i = 0; i < 10; ++i)
+ (void)git_pqueue_pop(&pq);
+ }
+
+ cl_assert_equal_i(100, git_pqueue_size(&pq));
+
+ /* at this point, we've popped 0-99 */
+
+ for (v = 100; v < 200; ++v) {
+ void *p = git_pqueue_pop(&pq);
+ cl_assert(p);
+ cl_assert_equal_i(v, *(int *)p);
+ }
+
+ cl_assert_equal_i(0, git_pqueue_size(&pq));
+
+ git_pqueue_free(&pq);
+}
+
+void test_core_pqueue__max_heap_size(void)
+{
+ git_pqueue pq;
+ int i, vals[100];
+
+ cl_git_pass(git_pqueue_init(&pq, GIT_PQUEUE_FIXED_SIZE, 50, cmp_ints));
+
+ for (i = 0; i < 100; ++i) {
+ vals[i] = (i & 1) ? 100 - i : i;
+ cl_git_pass(git_pqueue_insert(&pq, &vals[i]));
+ }
+
+ cl_assert_equal_i(50, git_pqueue_size(&pq));
+
+ for (i = 50; i < 100; ++i) {
+ void *p = git_pqueue_pop(&pq);
+ cl_assert(p);
+ cl_assert_equal_i(i, *(int *)p);
+ }
+
+ cl_assert_equal_i(0, git_pqueue_size(&pq));
+
+ git_pqueue_free(&pq);
+
+}
+
+static int cmp_ints_like_commit_time(const void *a, const void *b)
+{
+ return *((const int *)a) < *((const int *)b);
+}
+
+void test_core_pqueue__interleaved_pushes_and_pops(void)
+{
+ git_pqueue pq;
+ int i, j, *val;
+ static int commands[] =
+ { 6, 9, 8, 0, 5, 0, 7, 0, 4, 3, 0, 0, 0, 4, 0, 2, 0, 1, 0, 0, -1 };
+ static int expected[] =
+ { 9, 8, 7, 6, 5, 4, 4, 3, 2, 1, -1 };
+
+ cl_git_pass(git_pqueue_init(&pq, 0, 10, cmp_ints_like_commit_time));
+
+ for (i = 0, j = 0; commands[i] >= 0; ++i) {
+ if (!commands[i]) {
+ cl_assert((val = git_pqueue_pop(&pq)) != NULL);
+ cl_assert_equal_i(expected[j], *val);
+ ++j;
+ } else {
+ cl_git_pass(git_pqueue_insert(&pq, &commands[i]));
+ }
+ }
+
+ cl_assert_equal_i(0, git_pqueue_size(&pq));
+ git_pqueue_free(&pq);
+}
+
diff --git a/tests/core/strmap.c b/tests/core/strmap.c
index f34a4f89f..a120f1feb 100644
--- a/tests/core/strmap.c
+++ b/tests/core/strmap.c
@@ -3,12 +3,22 @@
GIT__USE_STRMAP;
+git_strmap *g_table;
+
+void test_core_strmap__initialize(void)
+{
+ cl_git_pass(git_strmap_alloc(&g_table));
+ cl_assert(g_table != NULL);
+}
+
+void test_core_strmap__cleanup(void)
+{
+ git_strmap_free(g_table);
+}
+
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);
+ cl_assert(git_strmap_num_entries(g_table) == 0);
}
static void insert_strings(git_strmap *table, int count)
@@ -37,21 +47,17 @@ void test_core_strmap__1(void)
{
int i;
char *str;
- git_strmap *table = git_strmap_alloc();
- cl_assert(table != NULL);
- insert_strings(table, 20);
+ insert_strings(g_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(g_table, "aaaaaaaaa"));
+ cl_assert(git_strmap_exists(g_table, "ggggggggg"));
+ cl_assert(!git_strmap_exists(g_table, "aaaaaaaab"));
+ cl_assert(!git_strmap_exists(g_table, "abcdefghi"));
i = 0;
- git_strmap_foreach_value(table, str, { i++; free(str); });
+ git_strmap_foreach_value(g_table, str, { i++; free(str); });
cl_assert(i == 20);
-
- git_strmap_free(table);
}
void test_core_strmap__2(void)
@@ -59,44 +65,36 @@ 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);
+ insert_strings(g_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(g_table, "aaaaaaaaa"));
+ cl_assert(git_strmap_exists(g_table, "ggggggggg"));
+ cl_assert(!git_strmap_exists(g_table, "aaaaaaaab"));
+ cl_assert(!git_strmap_exists(g_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(g_table, "bbbbbbbbb"));
+ pos = git_strmap_lookup_index(g_table, "bbbbbbbbb");
+ cl_assert(git_strmap_valid_index(g_table, pos));
+ cl_assert_equal_s(git_strmap_value_at(g_table, pos), "bbbbbbbbb");
+ free(git_strmap_value_at(g_table, pos));
+ git_strmap_delete_at(g_table, pos);
- cl_assert(!git_strmap_exists(table, "bbbbbbbbb"));
+ cl_assert(!git_strmap_exists(g_table, "bbbbbbbbb"));
i = 0;
- git_strmap_foreach_value(table, str, { i++; free(str); });
+ git_strmap_foreach_value(g_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);
+ insert_strings(g_table, 10000);
i = 0;
- git_strmap_foreach_value(table, str, { i++; free(str); });
+ git_strmap_foreach_value(g_table, str, { i++; free(str); });
cl_assert(i == 10000);
-
- git_strmap_free(table);
}
diff --git a/tests/core/vector.c b/tests/core/vector.c
index db52c004f..66f90b82b 100644
--- a/tests/core/vector.c
+++ b/tests/core/vector.c
@@ -190,8 +190,9 @@ void test_core_vector__5(void)
git_vector_free(&x);
}
-static int remove_ones(const git_vector *v, size_t idx)
+static int remove_ones(const git_vector *v, size_t idx, void *p)
{
+ GIT_UNUSED(p);
return (git_vector_get(v, idx) == (void *)0x001);
}
@@ -206,7 +207,7 @@ void test_core_vector__remove_matching(void)
git_vector_insert(&x, (void*) 0x001);
cl_assert(x.length == 1);
- git_vector_remove_matching(&x, remove_ones);
+ git_vector_remove_matching(&x, remove_ones, NULL);
cl_assert(x.length == 0);
git_vector_insert(&x, (void*) 0x001);
@@ -214,7 +215,7 @@ void test_core_vector__remove_matching(void)
git_vector_insert(&x, (void*) 0x001);
cl_assert(x.length == 3);
- git_vector_remove_matching(&x, remove_ones);
+ git_vector_remove_matching(&x, remove_ones, NULL);
cl_assert(x.length == 0);
git_vector_insert(&x, (void*) 0x002);
@@ -223,7 +224,7 @@ void test_core_vector__remove_matching(void)
git_vector_insert(&x, (void*) 0x001);
cl_assert(x.length == 4);
- git_vector_remove_matching(&x, remove_ones);
+ git_vector_remove_matching(&x, remove_ones, NULL);
cl_assert(x.length == 2);
git_vector_foreach(&x, i, compare) {
@@ -238,7 +239,7 @@ void test_core_vector__remove_matching(void)
git_vector_insert(&x, (void*) 0x001);
cl_assert(x.length == 4);
- git_vector_remove_matching(&x, remove_ones);
+ git_vector_remove_matching(&x, remove_ones, NULL);
cl_assert(x.length == 2);
git_vector_foreach(&x, i, compare) {
@@ -253,7 +254,7 @@ void test_core_vector__remove_matching(void)
git_vector_insert(&x, (void*) 0x001);
cl_assert(x.length == 4);
- git_vector_remove_matching(&x, remove_ones);
+ git_vector_remove_matching(&x, remove_ones, NULL);
cl_assert(x.length == 2);
git_vector_foreach(&x, i, compare) {
@@ -268,7 +269,7 @@ void test_core_vector__remove_matching(void)
git_vector_insert(&x, (void*) 0x003);
cl_assert(x.length == 4);
- git_vector_remove_matching(&x, remove_ones);
+ git_vector_remove_matching(&x, remove_ones, NULL);
cl_assert(x.length == 4);
git_vector_free(&x);
diff --git a/tests/core/zstream.c b/tests/core/zstream.c
new file mode 100644
index 000000000..7ba9424ba
--- /dev/null
+++ b/tests/core/zstream.c
@@ -0,0 +1,143 @@
+#include "clar_libgit2.h"
+#include "buffer.h"
+#include "zstream.h"
+
+static const char *data = "This is a test test test of This is a test";
+
+#define INFLATE_EXTRA 2
+
+static void assert_zlib_equal_(
+ const void *expected, size_t e_len,
+ const void *compressed, size_t c_len,
+ const char *msg, const char *file, int line)
+{
+ z_stream stream;
+ char *expanded = git__calloc(1, e_len + INFLATE_EXTRA);
+ cl_assert(expanded);
+
+ memset(&stream, 0, sizeof(stream));
+ stream.next_out = (Bytef *)expanded;
+ stream.avail_out = (uInt)(e_len + INFLATE_EXTRA);
+ stream.next_in = (Bytef *)compressed;
+ stream.avail_in = (uInt)c_len;
+
+ cl_assert(inflateInit(&stream) == Z_OK);
+ cl_assert(inflate(&stream, Z_FINISH));
+ inflateEnd(&stream);
+
+ clar__assert_equal(
+ file, line, msg, 1,
+ "%d", (int)stream.total_out, (int)e_len);
+ clar__assert_equal(
+ file, line, "Buffer len was not exact match", 1,
+ "%d", (int)stream.avail_out, (int)INFLATE_EXTRA);
+
+ clar__assert(
+ memcmp(expanded, expected, e_len) == 0,
+ file, line, "uncompressed data did not match", NULL, 1);
+
+ git__free(expanded);
+}
+
+#define assert_zlib_equal(E,EL,C,CL) \
+ assert_zlib_equal_(E, EL, C, CL, #EL " != " #CL, __FILE__, (int)__LINE__)
+
+void test_core_zstream__basic(void)
+{
+ git_zstream z = GIT_ZSTREAM_INIT;
+ char out[128];
+ size_t outlen = sizeof(out);
+
+ cl_git_pass(git_zstream_init(&z));
+ cl_git_pass(git_zstream_set_input(&z, data, strlen(data) + 1));
+ cl_git_pass(git_zstream_get_output(out, &outlen, &z));
+ cl_assert(git_zstream_done(&z));
+ cl_assert(outlen > 0);
+ git_zstream_free(&z);
+
+ assert_zlib_equal(data, strlen(data) + 1, out, outlen);
+}
+
+void test_core_zstream__buffer(void)
+{
+ git_buf out = GIT_BUF_INIT;
+ cl_git_pass(git_zstream_deflatebuf(&out, data, strlen(data) + 1));
+ assert_zlib_equal(data, strlen(data) + 1, out.ptr, out.size);
+ git_buf_free(&out);
+}
+
+#define BIG_STRING_PART "Big Data IS Big - Long Data IS Long - We need a buffer larger than 1024 x 1024 to make sure we trigger chunked compression - Big Big Data IS Bigger than Big - Long Long Data IS Longer than Long"
+
+static void compress_input_various_ways(git_buf *input)
+{
+ git_buf out1 = GIT_BUF_INIT, out2 = GIT_BUF_INIT;
+ size_t i, fixed_size = max(input->size / 2, 256);
+ char *fixed = git__malloc(fixed_size);
+ cl_assert(fixed);
+
+ /* compress with deflatebuf */
+
+ cl_git_pass(git_zstream_deflatebuf(&out1, input->ptr, input->size));
+ assert_zlib_equal(input->ptr, input->size, out1.ptr, out1.size);
+
+ /* compress with various fixed size buffer (accumulating the output) */
+
+ for (i = 0; i < 3; ++i) {
+ git_zstream zs = GIT_ZSTREAM_INIT;
+ size_t use_fixed_size;
+
+ switch (i) {
+ case 0: use_fixed_size = 256; break;
+ case 1: use_fixed_size = fixed_size / 2; break;
+ case 2: use_fixed_size = fixed_size; break;
+ }
+ cl_assert(use_fixed_size <= fixed_size);
+
+ cl_git_pass(git_zstream_init(&zs));
+ cl_git_pass(git_zstream_set_input(&zs, input->ptr, input->size));
+
+ while (!git_zstream_done(&zs)) {
+ size_t written = use_fixed_size;
+ cl_git_pass(git_zstream_get_output(fixed, &written, &zs));
+ cl_git_pass(git_buf_put(&out2, fixed, written));
+ }
+
+ git_zstream_free(&zs);
+ assert_zlib_equal(input->ptr, input->size, out2.ptr, out2.size);
+
+ /* did both approaches give the same data? */
+ cl_assert_equal_sz(out1.size, out2.size);
+ cl_assert(!memcmp(out1.ptr, out2.ptr, out1.size));
+
+ git_buf_free(&out2);
+ }
+
+ git_buf_free(&out1);
+ git__free(fixed);
+}
+
+void test_core_zstream__big_data(void)
+{
+ git_buf in = GIT_BUF_INIT;
+ size_t scan, target;
+
+ for (target = 1024; target <= 1024 * 1024 * 4; target *= 8) {
+
+ /* make a big string that's easy to compress */
+ git_buf_clear(&in);
+ while (in.size < target)
+ cl_git_pass(
+ git_buf_put(&in, BIG_STRING_PART, strlen(BIG_STRING_PART)));
+
+ compress_input_various_ways(&in);
+
+ /* make a big string that's hard to compress */
+ srand(0xabad1dea);
+ for (scan = 0; scan < in.size; ++scan)
+ in.ptr[scan] = (char)rand();
+
+ compress_input_various_ways(&in);
+ }
+
+ git_buf_free(&in);
+}