summaryrefslogtreecommitdiffstats
path: root/tests/util
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-21 05:03:04 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-21 05:03:04 +0000
commitb88736462df2c86a83f01dcc260b5463205819d2 (patch)
treeb1a9a5a5392a52ec4e5f60fb4b45083cf7fd65b0 /tests/util
parentAdding upstream version 1.7.2+ds. (diff)
downloadlibgit2-upstream.tar.xz
libgit2-upstream.zip
Adding upstream version 1.8.1+ds.upstream/1.8.1+dsupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'tests/util')
-rw-r--r--tests/util/assert.c3
-rw-r--r--tests/util/errors.c84
-rw-r--r--tests/util/path.c768
-rw-r--r--tests/util/path/core.c804
-rw-r--r--tests/util/path/win32.c33
-rw-r--r--tests/util/process/env.c111
-rw-r--r--tests/util/process/start.c247
-rw-r--r--tests/util/process/win32.c63
-rw-r--r--tests/util/string.c6
9 files changed, 1300 insertions, 819 deletions
diff --git a/tests/util/assert.c b/tests/util/assert.c
index 3babc47..4644f35 100644
--- a/tests/util/assert.c
+++ b/tests/util/assert.c
@@ -92,7 +92,8 @@ void test_assert__argument_with_void_return_type(void)
git_error_clear();
cl_assert_equal_p(foo, fn_returns_string(foo));
- cl_assert_equal_p(NULL, git_error_last());
+ cl_assert_equal_i(GIT_ERROR_NONE, git_error_last()->klass);
+ cl_assert_equal_s("no error", git_error_last()->message);
}
void test_assert__internal(void)
diff --git a/tests/util/errors.c b/tests/util/errors.c
index 78654a7..f9b85a6 100644
--- a/tests/util/errors.c
+++ b/tests/util/errors.c
@@ -5,7 +5,10 @@ void test_errors__public_api(void)
char *str_in_error;
git_error_clear();
- cl_assert(git_error_last() == NULL);
+
+ cl_assert(git_error_last() != NULL);
+ cl_assert(git_error_last()->klass == GIT_ERROR_NONE);
+ cl_assert(strcmp(git_error_last()->message, "no error") == 0);
git_error_set_oom();
@@ -23,7 +26,9 @@ void test_errors__public_api(void)
cl_assert(str_in_error != NULL);
git_error_clear();
- cl_assert(git_error_last() == NULL);
+ cl_assert(git_error_last() != NULL);
+ cl_assert(git_error_last()->klass == GIT_ERROR_NONE);
+ cl_assert(strcmp(git_error_last()->message, "no error") == 0);
}
#include "common.h"
@@ -35,7 +40,9 @@ void test_errors__new_school(void)
char *str_in_error;
git_error_clear();
- cl_assert(git_error_last() == NULL);
+ cl_assert(git_error_last() != NULL);
+ cl_assert(git_error_last()->klass == GIT_ERROR_NONE);
+ cl_assert(strcmp(git_error_last()->message, "no error") == 0);
git_error_set_oom(); /* internal fn */
@@ -53,7 +60,9 @@ void test_errors__new_school(void)
cl_assert(str_in_error != NULL);
git_error_clear();
- cl_assert(git_error_last() == NULL);
+ cl_assert(git_error_last() != NULL);
+ cl_assert(git_error_last()->klass == GIT_ERROR_NONE);
+ cl_assert(strcmp(git_error_last()->message, "no error") == 0);
do {
struct stat st;
@@ -88,52 +97,32 @@ void test_errors__new_school(void)
void test_errors__restore(void)
{
- git_error_state err_state = {0};
+ git_error *last_error;
git_error_clear();
- cl_assert(git_error_last() == NULL);
-
- cl_assert_equal_i(0, git_error_state_capture(&err_state, 0));
-
- memset(&err_state, 0x0, sizeof(git_error_state));
+ cl_assert(git_error_last() != NULL);
+ cl_assert(git_error_last()->klass == GIT_ERROR_NONE);
+ cl_assert(strcmp("no error", git_error_last()->message) == 0);
git_error_set(42, "Foo: %s", "bar");
- cl_assert_equal_i(-1, git_error_state_capture(&err_state, -1));
-
- cl_assert(git_error_last() == NULL);
-
- git_error_set(99, "Bar: %s", "foo");
-
- git_error_state_restore(&err_state);
-
- cl_assert_equal_i(42, git_error_last()->klass);
- cl_assert_equal_s("Foo: bar", git_error_last()->message);
-}
-
-void test_errors__free_state(void)
-{
- git_error_state err_state = {0};
+ cl_assert(git_error_save(&last_error) == 0);
git_error_clear();
-
- git_error_set(42, "Foo: %s", "bar");
- cl_assert_equal_i(-1, git_error_state_capture(&err_state, -1));
+ cl_assert(git_error_last() != NULL);
+ cl_assert(git_error_last()->klass == GIT_ERROR_NONE);
+ cl_assert(strcmp("no error", git_error_last()->message) == 0);
git_error_set(99, "Bar: %s", "foo");
- git_error_state_free(&err_state);
-
- cl_assert_equal_i(99, git_error_last()->klass);
- cl_assert_equal_s("Bar: foo", git_error_last()->message);
+ git_error_restore(last_error);
- git_error_state_restore(&err_state);
-
- cl_assert(git_error_last() == NULL);
+ cl_assert(git_error_last()->klass == 42);
+ cl_assert(strcmp("Foo: bar", git_error_last()->message) == 0);
}
void test_errors__restore_oom(void)
{
- git_error_state err_state = {0};
+ git_error *last_error;
const git_error *oom_error = NULL;
git_error_clear();
@@ -141,15 +130,18 @@ void test_errors__restore_oom(void)
git_error_set_oom(); /* internal fn */
oom_error = git_error_last();
cl_assert(oom_error);
+ cl_assert(oom_error->klass == GIT_ERROR_NOMEMORY);
- cl_assert_equal_i(-1, git_error_state_capture(&err_state, -1));
-
- cl_assert(git_error_last() == NULL);
- cl_assert_equal_i(GIT_ERROR_NOMEMORY, err_state.error_msg.klass);
- cl_assert_equal_s("Out of memory", err_state.error_msg.message);
+ cl_assert(git_error_save(&last_error) == 0);
+ cl_assert(last_error->klass == GIT_ERROR_NOMEMORY);
+ cl_assert(strcmp("Out of memory", last_error->message) == 0);
- git_error_state_restore(&err_state);
+ git_error_clear();
+ cl_assert(git_error_last() != NULL);
+ cl_assert(git_error_last()->klass == GIT_ERROR_NONE);
+ cl_assert(strcmp("no error", git_error_last()->message) == 0);
+ git_error_restore(last_error);
cl_assert(git_error_last()->klass == GIT_ERROR_NOMEMORY);
cl_assert_(git_error_last() == oom_error, "static oom error not restored");
@@ -204,11 +196,15 @@ void test_errors__integer_overflow_sets_oom(void)
git_error_clear();
cl_assert(!GIT_ADD_SIZET_OVERFLOW(&out, SIZE_MAX-1, 1));
- cl_assert_equal_p(NULL, git_error_last());
+ cl_assert(git_error_last() != NULL);
+ cl_assert(git_error_last()->klass == GIT_ERROR_NONE);
+ cl_assert(strcmp(git_error_last()->message, "no error") == 0);
git_error_clear();
cl_assert(!GIT_ADD_SIZET_OVERFLOW(&out, 42, 69));
- cl_assert_equal_p(NULL, git_error_last());
+ cl_assert(git_error_last() != NULL);
+ cl_assert(git_error_last()->klass == GIT_ERROR_NONE);
+ cl_assert(strcmp(git_error_last()->message, "no error") == 0);
git_error_clear();
cl_assert(GIT_ADD_SIZET_OVERFLOW(&out, SIZE_MAX, SIZE_MAX));
diff --git a/tests/util/path.c b/tests/util/path.c
deleted file mode 100644
index 02ec42f..0000000
--- a/tests/util/path.c
+++ /dev/null
@@ -1,768 +0,0 @@
-#include "clar_libgit2.h"
-#include "futils.h"
-#include "fs_path.h"
-
-#ifndef GIT_WIN32
-# include <unistd.h>
-#endif
-
-static char *path_save;
-
-void test_path__initialize(void)
-{
- path_save = cl_getenv("PATH");
-}
-
-void test_path__cleanup(void)
-{
- cl_setenv("PATH", path_save);
- git__free(path_save);
- path_save = NULL;
-}
-
-static void
-check_dirname(const char *A, const char *B)
-{
- git_str dir = GIT_STR_INIT;
- char *dir2;
-
- cl_assert(git_fs_path_dirname_r(&dir, A) >= 0);
- cl_assert_equal_s(B, dir.ptr);
- git_str_dispose(&dir);
-
- cl_assert((dir2 = git_fs_path_dirname(A)) != NULL);
- cl_assert_equal_s(B, dir2);
- git__free(dir2);
-}
-
-static void
-check_basename(const char *A, const char *B)
-{
- git_str base = GIT_STR_INIT;
- char *base2;
-
- cl_assert(git_fs_path_basename_r(&base, A) >= 0);
- cl_assert_equal_s(B, base.ptr);
- git_str_dispose(&base);
-
- cl_assert((base2 = git_fs_path_basename(A)) != NULL);
- cl_assert_equal_s(B, base2);
- git__free(base2);
-}
-
-static void
-check_joinpath(const char *path_a, const char *path_b, const char *expected_path)
-{
- git_str joined_path = GIT_STR_INIT;
-
- cl_git_pass(git_str_joinpath(&joined_path, path_a, path_b));
- cl_assert_equal_s(expected_path, joined_path.ptr);
-
- git_str_dispose(&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_str joined_path = GIT_STR_INIT;
-
- cl_git_pass(git_str_join_n(&joined_path, '/', 4,
- path_a, path_b, path_c, path_d));
- cl_assert_equal_s(expected_path, joined_path.ptr);
-
- git_str_dispose(&joined_path);
-}
-
-static void check_setenv(const char* name, const char* value)
-{
- char* check;
-
- cl_git_pass(cl_setenv(name, value));
- check = cl_getenv(name);
-
- if (value)
- cl_assert_equal_s(value, check);
- else
- cl_assert(check == NULL);
-
- git__free(check);
-}
-
-/* get the dirname of a path */
-void test_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:/", "C:/");
- check_dirname("C:", "C:/");
- check_dirname("C:/path/", "C:/");
- check_dirname("C:/path", "C:/");
- check_dirname("//computername/", "//computername/");
- check_dirname("//computername", "//computername/");
- 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_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");
-}
-
-/* properly join path components */
-void test_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_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_str tgt = GIT_STR_INIT;
-
- git_str_sets(&tgt, path);
- cl_git_pass(git_fs_path_to_dir(&tgt));
- cl_assert_equal_s(expected, tgt.ptr);
-
- git_str_dispose(&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_fs_path_string_to_dir(buf, maxlen);
-
- cl_assert_equal_s(expected, buf);
-
- git__free(buf);
-}
-
-/* convert paths to dirs */
-void test_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_path__08_self_join(void)
-{
- git_str path = GIT_STR_INIT;
- size_t asize = 0;
-
- asize = path.asize;
- cl_git_pass(git_str_sets(&path, "/foo"));
- cl_assert_equal_s(path.ptr, "/foo");
- cl_assert(asize < path.asize);
-
- asize = path.asize;
- cl_git_pass(git_str_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_str_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_str_dispose(&path);
- cl_git_pass(git_str_sets(&path, "/foo/bar"));
-
- cl_git_pass(git_str_joinpath(&path, path.ptr + 4, "baz"));
- cl_assert_equal_s(path.ptr, "/bar/baz");
-
- asize = path.asize;
- cl_git_pass(git_str_joinpath(&path, path.ptr + 4, "somethinglongenoughtorealloc"));
- cl_assert_equal_s(path.ptr, "/baz/somethinglongenoughtorealloc");
- cl_assert(asize < path.asize);
-
- git_str_dispose(&path);
-}
-
-static void check_percent_decoding(const char *expected_result, const char *input)
-{
- git_str buf = GIT_STR_INIT;
-
- cl_git_pass(git__percent_decode(&buf, input));
- cl_assert_equal_s(expected_result, git_str_cstr(&buf));
-
- git_str_dispose(&buf);
-}
-
-void test_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_str buf = GIT_STR_INIT;
-
- assert(should_fail || expected_result);
-
- if (!should_fail) {
- cl_git_pass(git_fs_path_fromurl(&buf, input));
- cl_assert_equal_s(expected_result, git_str_cstr(&buf));
- } else
- cl_git_fail(git_fs_path_fromurl(&buf, input));
-
- git_str_dispose(&buf);
-}
-
-#ifdef GIT_WIN32
-#define ABS_PATH_MARKER ""
-#else
-#define ABS_PATH_MARKER "/"
-#endif
-
-void test_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;
- int cancel_after;
- char **expect;
-} check_walkup_info;
-
-#define CANCEL_VALUE 1234
-
-static int check_one_walkup_step(void *ref, const char *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);
- info->expect_idx++;
-
- return 0;
-}
-
-void test_path__11_walkup(void)
-{
- git_str p = GIT_STR_INIT;
-
- char *expect[] = {
- /* 1 */ "/a/b/c/d/e/", "/a/b/c/d/", "/a/b/c/", "/a/b/", "/a/", "/", NULL,
- /* 2 */ "/a/b/c/d/e", "/a/b/c/d/", "/a/b/c/", "/a/b/", "/a/", "/", NULL,
- /* 3 */ "/a/b/c/d/e", "/a/b/c/d/", "/a/b/c/", "/a/b/", "/a/", "/", NULL,
- /* 4 */ "/a/b/c/d/e", "/a/b/c/d/", "/a/b/c/", "/a/b/", "/a/", "/", NULL,
- /* 5 */ "/a/b/c/d/e", "/a/b/c/d/", "/a/b/c/", "/a/b/", NULL,
- /* 6 */ "/a/b/c/d/e", "/a/b/c/d/", "/a/b/c/", "/a/b/", NULL,
- /* 7 */ "this_is_a_path", "", NULL,
- /* 8 */ "this_is_a_path/", "", NULL,
- /* 9 */ "///a///b///c///d///e///", "///a///b///c///d///", "///a///b///c///", "///a///b///", "///a///", "///", NULL,
- /* 10 */ "a/b/c/", "a/b/", "a/", "", NULL,
- /* 11 */ "a/b/c", "a/b/", "a/", "", NULL,
- /* 12 */ "a/b/c/", "a/b/", "a/", NULL,
- /* 13 */ "", NULL,
- /* 14 */ "/", NULL,
- /* 15 */ NULL
- };
-
- char *root[] = {
- /* 1 */ NULL,
- /* 2 */ NULL,
- /* 3 */ "/",
- /* 4 */ "",
- /* 5 */ "/a/b",
- /* 6 */ "/a/b/",
- /* 7 */ NULL,
- /* 8 */ NULL,
- /* 9 */ NULL,
- /* 10 */ NULL,
- /* 11 */ NULL,
- /* 12 */ "a/",
- /* 13 */ NULL,
- /* 14 */ NULL,
- };
-
- int i, j;
- check_walkup_info info;
-
- info.expect = expect;
- info.cancel_after = -1;
-
- for (i = 0, j = 0; expect[i] != NULL; i++, j++) {
-
- git_str_sets(&p, expect[i]);
-
- info.expect_idx = i;
- cl_git_pass(
- git_fs_path_walk_up(&p, root[j], check_one_walkup_step, &info)
- );
-
- cl_assert_equal_s(p.ptr, expect[i]);
- cl_assert(expect[info.expect_idx] == NULL);
- i = info.expect_idx;
- }
-
- git_str_dispose(&p);
-}
-
-void test_path__11a_walkup_cancel(void)
-{
- git_str p = GIT_STR_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_str_sets(&p, expect[i]);
-
- info.cancel_after = cancel[j];
- info.expect_idx = i;
-
- cl_assert_equal_i(
- CANCEL_VALUE,
- git_fs_path_walk_up(&p, root[j], check_one_walkup_step, &info)
- );
-
- /* skip to next run of expectations */
- while (expect[i] != NULL) i++;
- }
-
- git_str_dispose(&p);
-}
-
-void test_path__12_offset_to_path_root(void)
-{
- cl_assert(git_fs_path_root("non/rooted/path") == -1);
- cl_assert(git_fs_path_root("/rooted/path") == 0);
-
-#ifdef GIT_WIN32
- /* Windows specific tests */
- cl_assert(git_fs_path_root("C:non/rooted/path") == -1);
- cl_assert(git_fs_path_root("C:/rooted/path") == 2);
- cl_assert(git_fs_path_root("//computername/sharefolder/resource") == 14);
- cl_assert(git_fs_path_root("//computername/sharefolder") == 14);
- cl_assert(git_fs_path_root("//computername") == -1);
-#endif
-}
-
-#define NON_EXISTING_FILEPATH "i_hope_i_do_not_exist"
-
-void test_path__13_cannot_prettify_a_non_existing_file(void)
-{
- git_str p = GIT_STR_INIT;
-
- cl_assert_equal_b(git_fs_path_exists(NON_EXISTING_FILEPATH), false);
- cl_assert_equal_i(GIT_ENOTFOUND, git_fs_path_prettify(&p, NON_EXISTING_FILEPATH, NULL));
- cl_assert_equal_i(GIT_ENOTFOUND, git_fs_path_prettify(&p, NON_EXISTING_FILEPATH "/so-do-i", NULL));
-
- git_str_dispose(&p);
-}
-
-void test_path__14_apply_relative(void)
-{
- git_str p = GIT_STR_INIT;
-
- cl_git_pass(git_str_sets(&p, "/this/is/a/base"));
-
- cl_git_pass(git_fs_path_apply_relative(&p, "../test"));
- cl_assert_equal_s("/this/is/a/test", p.ptr);
-
- cl_git_pass(git_fs_path_apply_relative(&p, "../../the/./end"));
- cl_assert_equal_s("/this/is/the/end", p.ptr);
-
- cl_git_pass(git_fs_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_fs_path_apply_relative(&p, "../../../../../.."));
- cl_assert_equal_s("/this/", p.ptr);
-
- cl_git_pass(git_fs_path_apply_relative(&p, "../"));
- cl_assert_equal_s("/", p.ptr);
-
- cl_git_fail(git_fs_path_apply_relative(&p, "../../.."));
-
-
- cl_git_pass(git_str_sets(&p, "d:/another/test"));
-
- cl_git_pass(git_fs_path_apply_relative(&p, "../.."));
- cl_assert_equal_s("d:/", p.ptr);
-
- cl_git_pass(git_fs_path_apply_relative(&p, "from/here/to/../and/./back/."));
- cl_assert_equal_s("d:/from/here/and/back/", p.ptr);
-
-
- cl_git_pass(git_str_sets(&p, "https://my.url.com/test.git"));
-
- cl_git_pass(git_fs_path_apply_relative(&p, "../another.git"));
- cl_assert_equal_s("https://my.url.com/another.git", p.ptr);
-
- cl_git_pass(git_fs_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_fs_path_apply_relative(&p, ".."));
- cl_assert_equal_s("https://my.url.com/full/path/", p.ptr);
-
- cl_git_pass(git_fs_path_apply_relative(&p, "../../../"));
- cl_assert_equal_s("https://", p.ptr);
-
-
- cl_git_pass(git_str_sets(&p, "../../this/is/relative"));
-
- cl_git_pass(git_fs_path_apply_relative(&p, "../../preserves/the/prefix"));
- cl_assert_equal_s("../../this/preserves/the/prefix", p.ptr);
-
- cl_git_pass(git_fs_path_apply_relative(&p, "../../../../that"));
- cl_assert_equal_s("../../that", p.ptr);
-
- cl_git_pass(git_fs_path_apply_relative(&p, "../there"));
- cl_assert_equal_s("../../there", p.ptr);
- git_str_dispose(&p);
-}
-
-static void assert_resolve_relative(
- git_str *buf, const char *expected, const char *path)
-{
- cl_git_pass(git_str_sets(buf, path));
- cl_git_pass(git_fs_path_resolve_relative(buf, 0));
- cl_assert_equal_s(expected, buf->ptr);
-}
-
-void test_path__15_resolve_relative(void)
-{
- git_str buf = GIT_STR_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_str_sets(&buf, "/.."));
- cl_git_fail(git_fs_path_resolve_relative(&buf, 0));
-
- cl_git_pass(git_str_sets(&buf, "/./.."));
- cl_git_fail(git_fs_path_resolve_relative(&buf, 0));
-
- cl_git_pass(git_str_sets(&buf, "/.//.."));
- cl_git_fail(git_fs_path_resolve_relative(&buf, 0));
-
- cl_git_pass(git_str_sets(&buf, "/../."));
- cl_git_fail(git_fs_path_resolve_relative(&buf, 0));
-
- cl_git_pass(git_str_sets(&buf, "/../.././../a"));
- cl_git_fail(git_fs_path_resolve_relative(&buf, 0));
-
- cl_git_pass(git_str_sets(&buf, "////.."));
- cl_git_fail(git_fs_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_str_sets(&buf, "//a/b/../.."));
- cl_git_fail(git_fs_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_str_dispose(&buf);
-}
-
-#define assert_common_dirlen(i, p, q) \
- cl_assert_equal_i((i), git_fs_path_common_dirlen((p), (q)));
-
-void test_path__16_resolve_relative(void)
-{
- assert_common_dirlen(0, "", "");
- assert_common_dirlen(0, "", "bar.txt");
- assert_common_dirlen(0, "foo.txt", "bar.txt");
- assert_common_dirlen(0, "foo.txt", "");
- assert_common_dirlen(0, "foo/bar.txt", "bar/foo.txt");
- assert_common_dirlen(0, "foo/bar.txt", "../foo.txt");
-
- assert_common_dirlen(1, "/one.txt", "/two.txt");
- assert_common_dirlen(4, "foo/one.txt", "foo/two.txt");
- assert_common_dirlen(5, "/foo/one.txt", "/foo/two.txt");
-
- assert_common_dirlen(6, "a/b/c/foo.txt", "a/b/c/d/e/bar.txt");
- assert_common_dirlen(7, "/a/b/c/foo.txt", "/a/b/c/d/e/bar.txt");
-}
-
-static void fix_path(git_str *s)
-{
-#ifndef GIT_WIN32
- GIT_UNUSED(s);
-#else
- char* c;
-
- for (c = s->ptr; *c; c++) {
- if (*c == '/')
- *c = '\\';
- }
-#endif
-}
-
-void test_path__find_exe_in_path(void)
-{
- char *orig_path;
- git_str sandbox_path = GIT_STR_INIT;
- git_str new_path = GIT_STR_INIT, full_path = GIT_STR_INIT,
- dummy_path = GIT_STR_INIT;
-
-#ifdef GIT_WIN32
- static const char *bogus_path_1 = "c:\\does\\not\\exist\\";
- static const char *bogus_path_2 = "e:\\non\\existent";
-#else
- static const char *bogus_path_1 = "/this/path/does/not/exist/";
- static const char *bogus_path_2 = "/non/existent";
-#endif
-
- orig_path = cl_getenv("PATH");
-
- git_str_puts(&sandbox_path, clar_sandbox_path());
- git_str_joinpath(&dummy_path, sandbox_path.ptr, "dummmmmmmy_libgit2_file");
- cl_git_rewritefile(dummy_path.ptr, "this is a dummy file");
-
- fix_path(&sandbox_path);
- fix_path(&dummy_path);
-
- cl_git_pass(git_str_printf(&new_path, "%s%c%s%c%s%c%s",
- bogus_path_1, GIT_PATH_LIST_SEPARATOR,
- orig_path, GIT_PATH_LIST_SEPARATOR,
- sandbox_path.ptr, GIT_PATH_LIST_SEPARATOR,
- bogus_path_2));
-
- check_setenv("PATH", new_path.ptr);
-
- cl_git_fail_with(GIT_ENOTFOUND, git_fs_path_find_executable(&full_path, "this_file_does_not_exist"));
- cl_git_pass(git_fs_path_find_executable(&full_path, "dummmmmmmy_libgit2_file"));
-
- cl_assert_equal_s(full_path.ptr, dummy_path.ptr);
-
- git_str_dispose(&full_path);
- git_str_dispose(&new_path);
- git_str_dispose(&dummy_path);
- git_str_dispose(&sandbox_path);
- git__free(orig_path);
-}
-
-void test_path__validate_current_user_ownership(void)
-{
- bool is_cur;
-
- cl_must_pass(p_mkdir("testdir", 0777));
- cl_git_pass(git_fs_path_owner_is_current_user(&is_cur, "testdir"));
- cl_assert_equal_i(is_cur, 1);
-
- cl_git_rewritefile("testfile", "This is a test file.");
- cl_git_pass(git_fs_path_owner_is_current_user(&is_cur, "testfile"));
- cl_assert_equal_i(is_cur, 1);
-
-#ifdef GIT_WIN32
- cl_git_pass(git_fs_path_owner_is_current_user(&is_cur, "C:\\"));
- cl_assert_equal_i(is_cur, 0);
-
- cl_git_fail(git_fs_path_owner_is_current_user(&is_cur, "c:\\path\\does\\not\\exist"));
-#else
- cl_git_pass(git_fs_path_owner_is_current_user(&is_cur, "/"));
- cl_assert_equal_i(is_cur, (geteuid() == 0));
-
- cl_git_fail(git_fs_path_owner_is_current_user(&is_cur, "/path/does/not/exist"));
-#endif
-}
diff --git a/tests/util/path/core.c b/tests/util/path/core.c
index f30f6c0..d1935a8 100644
--- a/tests/util/path/core.c
+++ b/tests/util/path/core.c
@@ -1,6 +1,784 @@
#include "clar_libgit2.h"
+#include "futils.h"
#include "fs_path.h"
+#ifndef GIT_WIN32
+# include <unistd.h>
+#endif
+
+static char *path_save;
+
+void test_path_core__initialize(void)
+{
+ path_save = cl_getenv("PATH");
+}
+
+void test_path_core__cleanup(void)
+{
+ cl_setenv("PATH", path_save);
+ git__free(path_save);
+ path_save = NULL;
+}
+
+static void
+check_dirname(const char *A, const char *B)
+{
+ git_str dir = GIT_STR_INIT;
+ char *dir2;
+
+ cl_assert(git_fs_path_dirname_r(&dir, A) >= 0);
+ cl_assert_equal_s(B, dir.ptr);
+ git_str_dispose(&dir);
+
+ cl_assert((dir2 = git_fs_path_dirname(A)) != NULL);
+ cl_assert_equal_s(B, dir2);
+ git__free(dir2);
+}
+
+static void
+check_basename(const char *A, const char *B)
+{
+ git_str base = GIT_STR_INIT;
+ char *base2;
+
+ cl_assert(git_fs_path_basename_r(&base, A) >= 0);
+ cl_assert_equal_s(B, base.ptr);
+ git_str_dispose(&base);
+
+ cl_assert((base2 = git_fs_path_basename(A)) != NULL);
+ cl_assert_equal_s(B, base2);
+ git__free(base2);
+}
+
+static void
+check_joinpath(const char *path_a, const char *path_b, const char *expected_path)
+{
+ git_str joined_path = GIT_STR_INIT;
+
+ cl_git_pass(git_str_joinpath(&joined_path, path_a, path_b));
+ cl_assert_equal_s(expected_path, joined_path.ptr);
+
+ git_str_dispose(&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_str joined_path = GIT_STR_INIT;
+
+ cl_git_pass(git_str_join_n(&joined_path, '/', 4,
+ path_a, path_b, path_c, path_d));
+ cl_assert_equal_s(expected_path, joined_path.ptr);
+
+ git_str_dispose(&joined_path);
+}
+
+static void check_setenv(const char* name, const char* value)
+{
+ char* check;
+
+ cl_git_pass(cl_setenv(name, value));
+ check = cl_getenv(name);
+
+ if (value)
+ cl_assert_equal_s(value, check);
+ else
+ cl_assert(check == NULL);
+
+ git__free(check);
+}
+
+/* get the dirname of a path */
+void test_path_core__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:/", "C:/");
+ check_dirname("C:", "C:/");
+ check_dirname("C:/path/", "C:/");
+ check_dirname("C:/path", "C:/");
+ check_dirname("//computername/", "//computername/");
+ check_dirname("//computername", "//computername/");
+ 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_path_core__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");
+}
+
+/* properly join path components */
+void test_path_core__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_path_core__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_str tgt = GIT_STR_INIT;
+
+ git_str_sets(&tgt, path);
+ cl_git_pass(git_fs_path_to_dir(&tgt));
+ cl_assert_equal_s(expected, tgt.ptr);
+
+ git_str_dispose(&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_fs_path_string_to_dir(buf, maxlen);
+
+ cl_assert_equal_s(expected, buf);
+
+ git__free(buf);
+}
+
+/* convert paths to dirs */
+void test_path_core__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_path_core__08_self_join(void)
+{
+ git_str path = GIT_STR_INIT;
+ size_t asize = 0;
+
+ asize = path.asize;
+ cl_git_pass(git_str_sets(&path, "/foo"));
+ cl_assert_equal_s(path.ptr, "/foo");
+ cl_assert(asize < path.asize);
+
+ asize = path.asize;
+ cl_git_pass(git_str_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_str_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_str_dispose(&path);
+ cl_git_pass(git_str_sets(&path, "/foo/bar"));
+
+ cl_git_pass(git_str_joinpath(&path, path.ptr + 4, "baz"));
+ cl_assert_equal_s(path.ptr, "/bar/baz");
+
+ asize = path.asize;
+ cl_git_pass(git_str_joinpath(&path, path.ptr + 4, "somethinglongenoughtorealloc"));
+ cl_assert_equal_s(path.ptr, "/baz/somethinglongenoughtorealloc");
+ cl_assert(asize < path.asize);
+
+ git_str_dispose(&path);
+}
+
+static void check_percent_decoding(const char *expected_result, const char *input)
+{
+ git_str buf = GIT_STR_INIT;
+
+ cl_git_pass(git__percent_decode(&buf, input));
+ cl_assert_equal_s(expected_result, git_str_cstr(&buf));
+
+ git_str_dispose(&buf);
+}
+
+void test_path_core__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_str buf = GIT_STR_INIT;
+
+ assert(should_fail || expected_result);
+
+ if (!should_fail) {
+ cl_git_pass(git_fs_path_fromurl(&buf, input));
+ cl_assert_equal_s(expected_result, git_str_cstr(&buf));
+ } else
+ cl_git_fail(git_fs_path_fromurl(&buf, input));
+
+ git_str_dispose(&buf);
+}
+
+#ifdef GIT_WIN32
+#define ABS_PATH_MARKER ""
+#else
+#define ABS_PATH_MARKER "/"
+#endif
+
+void test_path_core__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;
+ int cancel_after;
+ char **expect;
+} check_walkup_info;
+
+#define CANCEL_VALUE 1234
+
+static int check_one_walkup_step(void *ref, const char *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);
+ info->expect_idx++;
+
+ return 0;
+}
+
+void test_path_core__11_walkup(void)
+{
+ git_str p = GIT_STR_INIT;
+
+ char *expect[] = {
+ /* 1 */ "/a/b/c/d/e/", "/a/b/c/d/", "/a/b/c/", "/a/b/", "/a/", "/", NULL,
+ /* 2 */ "/a/b/c/d/e", "/a/b/c/d/", "/a/b/c/", "/a/b/", "/a/", "/", NULL,
+ /* 3 */ "/a/b/c/d/e", "/a/b/c/d/", "/a/b/c/", "/a/b/", "/a/", "/", NULL,
+ /* 4 */ "/a/b/c/d/e", "/a/b/c/d/", "/a/b/c/", "/a/b/", "/a/", "/", NULL,
+ /* 5 */ "/a/b/c/d/e", "/a/b/c/d/", "/a/b/c/", "/a/b/", NULL,
+ /* 6 */ "/a/b/c/d/e", "/a/b/c/d/", "/a/b/c/", "/a/b/", NULL,
+ /* 7 */ "this_is_a_path", "", NULL,
+ /* 8 */ "this_is_a_path/", "", NULL,
+ /* 9 */ "///a///b///c///d///e///", "///a///b///c///d///", "///a///b///c///", "///a///b///", "///a///", "///", NULL,
+ /* 10 */ "a/b/c/", "a/b/", "a/", "", NULL,
+ /* 11 */ "a/b/c", "a/b/", "a/", "", NULL,
+ /* 12 */ "a/b/c/", "a/b/", "a/", NULL,
+ /* 13 */ "", NULL,
+ /* 14 */ "/", NULL,
+ /* 15 */ NULL
+ };
+
+ char *root[] = {
+ /* 1 */ NULL,
+ /* 2 */ NULL,
+ /* 3 */ "/",
+ /* 4 */ "",
+ /* 5 */ "/a/b",
+ /* 6 */ "/a/b/",
+ /* 7 */ NULL,
+ /* 8 */ NULL,
+ /* 9 */ NULL,
+ /* 10 */ NULL,
+ /* 11 */ NULL,
+ /* 12 */ "a/",
+ /* 13 */ NULL,
+ /* 14 */ NULL,
+ };
+
+ int i, j;
+ check_walkup_info info;
+
+ info.expect = expect;
+ info.cancel_after = -1;
+
+ for (i = 0, j = 0; expect[i] != NULL; i++, j++) {
+
+ git_str_sets(&p, expect[i]);
+
+ info.expect_idx = i;
+ cl_git_pass(
+ git_fs_path_walk_up(&p, root[j], check_one_walkup_step, &info)
+ );
+
+ cl_assert_equal_s(p.ptr, expect[i]);
+ cl_assert(expect[info.expect_idx] == NULL);
+ i = info.expect_idx;
+ }
+
+ git_str_dispose(&p);
+}
+
+void test_path_core__11a_walkup_cancel(void)
+{
+ git_str p = GIT_STR_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_str_sets(&p, expect[i]);
+
+ info.cancel_after = cancel[j];
+ info.expect_idx = i;
+
+ cl_assert_equal_i(
+ CANCEL_VALUE,
+ git_fs_path_walk_up(&p, root[j], check_one_walkup_step, &info)
+ );
+
+ /* skip to next run of expectations */
+ while (expect[i] != NULL) i++;
+ }
+
+ git_str_dispose(&p);
+}
+
+void test_path_core__12_offset_to_path_root(void)
+{
+ cl_assert(git_fs_path_root("non/rooted/path") == -1);
+ cl_assert(git_fs_path_root("/rooted/path") == 0);
+
+#ifdef GIT_WIN32
+ /* Windows specific tests */
+ cl_assert(git_fs_path_root("C:non/rooted/path") == -1);
+ cl_assert(git_fs_path_root("C:/rooted/path") == 2);
+ cl_assert(git_fs_path_root("//computername/sharefolder/resource") == 14);
+ cl_assert(git_fs_path_root("//computername/sharefolder") == 14);
+ cl_assert(git_fs_path_root("//computername") == -1);
+#endif
+}
+
+#define NON_EXISTING_FILEPATH "i_hope_i_do_not_exist"
+
+void test_path_core__13_cannot_prettify_a_non_existing_file(void)
+{
+ git_str p = GIT_STR_INIT;
+
+ cl_assert_equal_b(git_fs_path_exists(NON_EXISTING_FILEPATH), false);
+ cl_assert_equal_i(GIT_ENOTFOUND, git_fs_path_prettify(&p, NON_EXISTING_FILEPATH, NULL));
+ cl_assert_equal_i(GIT_ENOTFOUND, git_fs_path_prettify(&p, NON_EXISTING_FILEPATH "/so-do-i", NULL));
+
+ git_str_dispose(&p);
+}
+
+void test_path_core__14_apply_relative(void)
+{
+ git_str p = GIT_STR_INIT;
+
+ cl_git_pass(git_str_sets(&p, "/this/is/a/base"));
+
+ cl_git_pass(git_fs_path_apply_relative(&p, "../test"));
+ cl_assert_equal_s("/this/is/a/test", p.ptr);
+
+ cl_git_pass(git_fs_path_apply_relative(&p, "../../the/./end"));
+ cl_assert_equal_s("/this/is/the/end", p.ptr);
+
+ cl_git_pass(git_fs_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_fs_path_apply_relative(&p, "../../../../../.."));
+ cl_assert_equal_s("/this/", p.ptr);
+
+ cl_git_pass(git_fs_path_apply_relative(&p, "../"));
+ cl_assert_equal_s("/", p.ptr);
+
+ cl_git_fail(git_fs_path_apply_relative(&p, "../../.."));
+
+
+ cl_git_pass(git_str_sets(&p, "d:/another/test"));
+
+ cl_git_pass(git_fs_path_apply_relative(&p, "../.."));
+ cl_assert_equal_s("d:/", p.ptr);
+
+ cl_git_pass(git_fs_path_apply_relative(&p, "from/here/to/../and/./back/."));
+ cl_assert_equal_s("d:/from/here/and/back/", p.ptr);
+
+
+ cl_git_pass(git_str_sets(&p, "https://my.url.com/test.git"));
+
+ cl_git_pass(git_fs_path_apply_relative(&p, "../another.git"));
+ cl_assert_equal_s("https://my.url.com/another.git", p.ptr);
+
+ cl_git_pass(git_fs_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_fs_path_apply_relative(&p, ".."));
+ cl_assert_equal_s("https://my.url.com/full/path/", p.ptr);
+
+ cl_git_pass(git_fs_path_apply_relative(&p, "../../../"));
+ cl_assert_equal_s("https://", p.ptr);
+
+
+ cl_git_pass(git_str_sets(&p, "../../this/is/relative"));
+
+ cl_git_pass(git_fs_path_apply_relative(&p, "../../preserves/the/prefix"));
+ cl_assert_equal_s("../../this/preserves/the/prefix", p.ptr);
+
+ cl_git_pass(git_fs_path_apply_relative(&p, "../../../../that"));
+ cl_assert_equal_s("../../that", p.ptr);
+
+ cl_git_pass(git_fs_path_apply_relative(&p, "../there"));
+ cl_assert_equal_s("../../there", p.ptr);
+ git_str_dispose(&p);
+}
+
+static void assert_resolve_relative(
+ git_str *buf, const char *expected, const char *path)
+{
+ cl_git_pass(git_str_sets(buf, path));
+ cl_git_pass(git_fs_path_resolve_relative(buf, 0));
+ cl_assert_equal_s(expected, buf->ptr);
+}
+
+void test_path_core__15_resolve_relative(void)
+{
+ git_str buf = GIT_STR_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_str_sets(&buf, "/.."));
+ cl_git_fail(git_fs_path_resolve_relative(&buf, 0));
+
+ cl_git_pass(git_str_sets(&buf, "/./.."));
+ cl_git_fail(git_fs_path_resolve_relative(&buf, 0));
+
+ cl_git_pass(git_str_sets(&buf, "/.//.."));
+ cl_git_fail(git_fs_path_resolve_relative(&buf, 0));
+
+ cl_git_pass(git_str_sets(&buf, "/../."));
+ cl_git_fail(git_fs_path_resolve_relative(&buf, 0));
+
+ cl_git_pass(git_str_sets(&buf, "/../.././../a"));
+ cl_git_fail(git_fs_path_resolve_relative(&buf, 0));
+
+ cl_git_pass(git_str_sets(&buf, "////.."));
+ cl_git_fail(git_fs_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_str_sets(&buf, "//a/b/../.."));
+ cl_git_fail(git_fs_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_str_dispose(&buf);
+}
+
+#define assert_common_dirlen(i, p, q) \
+ cl_assert_equal_i((i), git_fs_path_common_dirlen((p), (q)));
+
+void test_path_core__16_resolve_relative(void)
+{
+ assert_common_dirlen(0, "", "");
+ assert_common_dirlen(0, "", "bar.txt");
+ assert_common_dirlen(0, "foo.txt", "bar.txt");
+ assert_common_dirlen(0, "foo.txt", "");
+ assert_common_dirlen(0, "foo/bar.txt", "bar/foo.txt");
+ assert_common_dirlen(0, "foo/bar.txt", "../foo.txt");
+
+ assert_common_dirlen(1, "/one.txt", "/two.txt");
+ assert_common_dirlen(4, "foo/one.txt", "foo/two.txt");
+ assert_common_dirlen(5, "/foo/one.txt", "/foo/two.txt");
+
+ assert_common_dirlen(6, "a/b/c/foo.txt", "a/b/c/d/e/bar.txt");
+ assert_common_dirlen(7, "/a/b/c/foo.txt", "/a/b/c/d/e/bar.txt");
+}
+
+static void fix_path(git_str *s)
+{
+#ifndef GIT_WIN32
+ GIT_UNUSED(s);
+#else
+ char* c;
+
+ for (c = s->ptr; *c; c++) {
+ if (*c == '/')
+ *c = '\\';
+ }
+#endif
+}
+
+void test_path_core__find_exe_in_path(void)
+{
+ char *orig_path;
+ git_str sandbox_path = GIT_STR_INIT;
+ git_str new_path = GIT_STR_INIT, full_path = GIT_STR_INIT,
+ dummy_path = GIT_STR_INIT;
+
+#ifdef GIT_WIN32
+ static const char *bogus_path_1 = "c:\\does\\not\\exist\\";
+ static const char *bogus_path_2 = "e:\\non\\existent";
+#else
+ static const char *bogus_path_1 = "/this/path/does/not/exist/";
+ static const char *bogus_path_2 = "/non/existent";
+#endif
+
+ orig_path = cl_getenv("PATH");
+
+ git_str_puts(&sandbox_path, clar_sandbox_path());
+ git_str_joinpath(&dummy_path, sandbox_path.ptr, "dummmmmmmy_libgit2_file");
+ cl_git_rewritefile(dummy_path.ptr, "this is a dummy file");
+
+ fix_path(&sandbox_path);
+ fix_path(&dummy_path);
+
+ cl_git_pass(git_str_printf(&new_path, "%s%c%s%c%s%c%s",
+ bogus_path_1, GIT_PATH_LIST_SEPARATOR,
+ orig_path, GIT_PATH_LIST_SEPARATOR,
+ sandbox_path.ptr, GIT_PATH_LIST_SEPARATOR,
+ bogus_path_2));
+
+ check_setenv("PATH", new_path.ptr);
+
+ cl_git_fail_with(GIT_ENOTFOUND, git_fs_path_find_executable(&full_path, "this_file_does_not_exist"));
+ cl_git_pass(git_fs_path_find_executable(&full_path, "dummmmmmmy_libgit2_file"));
+
+ cl_assert_equal_s(full_path.ptr, dummy_path.ptr);
+
+ git_str_dispose(&full_path);
+ git_str_dispose(&new_path);
+ git_str_dispose(&dummy_path);
+ git_str_dispose(&sandbox_path);
+ git__free(orig_path);
+}
+
+void test_path_core__validate_current_user_ownership(void)
+{
+ bool is_cur;
+
+ cl_must_pass(p_mkdir("testdir", 0777));
+ cl_git_pass(git_fs_path_owner_is_current_user(&is_cur, "testdir"));
+ cl_assert_equal_i(is_cur, 1);
+
+ cl_git_rewritefile("testfile", "This is a test file.");
+ cl_git_pass(git_fs_path_owner_is_current_user(&is_cur, "testfile"));
+ cl_assert_equal_i(is_cur, 1);
+
+#ifdef GIT_WIN32
+ cl_git_pass(git_fs_path_owner_is_current_user(&is_cur, "C:\\"));
+ cl_assert_equal_i(is_cur, 0);
+
+ cl_git_fail(git_fs_path_owner_is_current_user(&is_cur, "c:\\path\\does\\not\\exist"));
+#else
+ cl_git_pass(git_fs_path_owner_is_current_user(&is_cur, "/"));
+ cl_assert_equal_i(is_cur, (geteuid() == 0));
+
+ cl_git_fail(git_fs_path_owner_is_current_user(&is_cur, "/path/does/not/exist"));
+#endif
+}
+
+void test_path_core__dirlen(void)
+{
+ cl_assert_equal_sz(13, git_fs_path_dirlen("/foo/bar/asdf"));
+ cl_assert_equal_sz(13, git_fs_path_dirlen("/foo/bar/asdf/"));
+ cl_assert_equal_sz(13, git_fs_path_dirlen("/foo/bar/asdf//"));
+ cl_assert_equal_sz(3, git_fs_path_dirlen("foo////"));
+ cl_assert_equal_sz(3, git_fs_path_dirlen("foo"));
+ cl_assert_equal_sz(1, git_fs_path_dirlen("/"));
+ cl_assert_equal_sz(1, git_fs_path_dirlen("////"));
+ cl_assert_equal_sz(0, git_fs_path_dirlen(""));
+}
+
static void test_make_relative(
const char *expected_path,
const char *path,
@@ -341,3 +1119,29 @@ void test_path_core__join_unrooted_respects_funny_windows_roots(void)
test_join_unrooted("💩:/foo/bar/foobar", 13, "💩:/foo/bar/foobar", "💩:/foo/bar");
test_join_unrooted("💩:/foo/bar/foobar", 9, "💩:/foo/bar/foobar", "💩:/foo/");
}
+
+void test_path_core__is_root(void)
+{
+ cl_assert_equal_b(true, git_fs_path_is_root("/"));
+ cl_assert_equal_b(false, git_fs_path_is_root("//"));
+ cl_assert_equal_b(false, git_fs_path_is_root("foo/"));
+ cl_assert_equal_b(false, git_fs_path_is_root("/foo/"));
+ cl_assert_equal_b(false, git_fs_path_is_root("/foo"));
+ cl_assert_equal_b(false, git_fs_path_is_root("\\"));
+
+#ifdef GIT_WIN32
+ cl_assert_equal_b(true, git_fs_path_is_root("A:\\"));
+ cl_assert_equal_b(false, git_fs_path_is_root("B:\\foo"));
+ cl_assert_equal_b(false, git_fs_path_is_root("B:\\foo\\"));
+ cl_assert_equal_b(true, git_fs_path_is_root("C:\\"));
+ cl_assert_equal_b(true, git_fs_path_is_root("c:\\"));
+ cl_assert_equal_b(true, git_fs_path_is_root("z:\\"));
+ cl_assert_equal_b(false, git_fs_path_is_root("z:\\\\"));
+ cl_assert_equal_b(false, git_fs_path_is_root("\\\\localhost"));
+ cl_assert_equal_b(false, git_fs_path_is_root("\\\\localhost\\"));
+ cl_assert_equal_b(false, git_fs_path_is_root("\\\\localhost\\c$\\"));
+ cl_assert_equal_b(false, git_fs_path_is_root("\\\\localhost\\c$\\Foo"));
+ cl_assert_equal_b(false, git_fs_path_is_root("\\\\localhost\\c$\\Foo\\"));
+ cl_assert_equal_b(false, git_fs_path_is_root("\\\\Volume\\12345\\Foo\\Bar.txt"));
+#endif
+}
diff --git a/tests/util/path/win32.c b/tests/util/path/win32.c
index 1aaf686..6f90b44 100644
--- a/tests/util/path/win32.c
+++ b/tests/util/path/win32.c
@@ -278,5 +278,38 @@ void test_path_win32__8dot3_name(void)
cl_must_pass(p_mkdir(".bar", 0777));
cl_assert_equal_s("BAR~2", (shortname = git_win32_path_8dot3_name(".bar")));
git__free(shortname);
+
+ p_rmdir(".foo");
+ p_rmdir(".bar");
+ p_unlink("bar~1");
+#endif
+}
+
+void test_path_win32__realpath(void)
+{
+#ifdef GIT_WIN32
+ git_str expected = GIT_STR_INIT;
+ char result[GIT_PATH_MAX];
+
+ /* Ensure relative paths become absolute */
+ cl_must_pass(git_str_joinpath(&expected, clar_sandbox_path(), "abcdef"));
+ cl_must_pass(p_mkdir("abcdef", 0777));
+ cl_assert(p_realpath("./abcdef", result) != NULL);
+ cl_assert_equal_s(expected.ptr, result);
+
+ /* Ensure case is canonicalized */
+ git_str_clear(&expected);
+ cl_must_pass(git_str_joinpath(&expected, clar_sandbox_path(), "FOO"));
+ cl_must_pass(p_mkdir("FOO", 0777));
+ cl_assert(p_realpath("foo", result) != NULL);
+ cl_assert_equal_s(expected.ptr, result);
+
+ cl_assert(p_realpath("nonexistent", result) == NULL);
+ cl_assert_equal_i(ENOENT, errno);
+
+ git_str_dispose(&expected);
+
+ p_rmdir("abcdef");
+ p_rmdir("FOO");
#endif
}
diff --git a/tests/util/process/env.c b/tests/util/process/env.c
new file mode 100644
index 0000000..bb7dbcd
--- /dev/null
+++ b/tests/util/process/env.c
@@ -0,0 +1,111 @@
+#include "clar_libgit2.h"
+#include "process.h"
+#include "vector.h"
+
+static git_str env_cmd = GIT_STR_INIT;
+static git_str accumulator = GIT_STR_INIT;
+static git_vector env_result = GIT_VECTOR_INIT;
+
+void test_process_env__initialize(void)
+{
+#ifdef GIT_WIN32
+ git_str_printf(&env_cmd, "%s/env.cmd", cl_fixture("process"));
+#else
+ git_str_puts(&env_cmd, "/usr/bin/env");
+#endif
+
+ cl_git_pass(git_vector_init(&env_result, 32, git__strcmp_cb));
+}
+
+void test_process_env__cleanup(void)
+{
+ git_vector_free(&env_result);
+ git_str_dispose(&accumulator);
+ git_str_dispose(&env_cmd);
+}
+
+static void run_env(const char **env_array, size_t env_len, bool exclude_env)
+{
+ const char *args_array[] = { env_cmd.ptr };
+
+ git_process *process;
+ git_process_options opts = GIT_PROCESS_OPTIONS_INIT;
+ git_process_result result = GIT_PROCESS_RESULT_INIT;
+
+ char buf[1024], *tok;
+ ssize_t ret;
+
+ opts.capture_out = 1;
+ opts.exclude_env = exclude_env;
+
+ cl_git_pass(git_process_new(&process, args_array, ARRAY_SIZE(args_array), env_array, env_len, &opts));
+ cl_git_pass(git_process_start(process));
+
+ while ((ret = git_process_read(process, buf, 1024)) > 0)
+ cl_git_pass(git_str_put(&accumulator, buf, (size_t)ret));
+
+ cl_assert_equal_i(0, ret);
+
+ cl_git_pass(git_process_wait(&result, process));
+
+ cl_assert_equal_i(GIT_PROCESS_STATUS_NORMAL, result.status);
+ cl_assert_equal_i(0, result.exitcode);
+ cl_assert_equal_i(0, result.signal);
+
+ for (tok = strtok(accumulator.ptr, "\n"); tok; tok = strtok(NULL, "\n")) {
+#ifdef GIT_WIN32
+ if (strlen(tok) && tok[strlen(tok) - 1] == '\r')
+ tok[strlen(tok) - 1] = '\0';
+#endif
+
+ cl_git_pass(git_vector_insert(&env_result, tok));
+ }
+
+ git_process_close(process);
+ git_process_free(process);
+}
+
+void test_process_env__can_add_env(void)
+{
+ const char *env_array[] = { "TEST_NEW_ENV=added", "TEST_OTHER_ENV=also_added" };
+ run_env(env_array, 2, false);
+
+ cl_git_pass(git_vector_search(NULL, &env_result, "TEST_NEW_ENV=added"));
+ cl_git_pass(git_vector_search(NULL, &env_result, "TEST_OTHER_ENV=also_added"));
+}
+
+void test_process_env__can_propagate_env(void)
+{
+ cl_setenv("TEST_NEW_ENV", "propagated");
+ run_env(NULL, 0, false);
+
+ cl_git_pass(git_vector_search(NULL, &env_result, "TEST_NEW_ENV=propagated"));
+}
+
+void test_process_env__can_remove_env(void)
+{
+ const char *env_array[] = { "TEST_NEW_ENV=" };
+ char *str;
+ size_t i;
+
+ cl_setenv("TEST_NEW_ENV", "propagated");
+ run_env(env_array, 1, false);
+
+ git_vector_foreach(&env_result, i, str)
+ cl_assert(git__prefixcmp(str, "TEST_NEW_ENV=") != 0);
+}
+
+void test_process_env__can_clear_env(void)
+{
+ const char *env_array[] = { "TEST_NEW_ENV=added", "TEST_OTHER_ENV=also_added" };
+
+ cl_setenv("SOME_EXISTING_ENV", "propagated");
+ run_env(env_array, 2, true);
+
+ /*
+ * We can't simply test that the environment is precisely what we
+ * provided. Some systems (eg win32) will add environment variables
+ * to all processes.
+ */
+ cl_assert_equal_i(GIT_ENOTFOUND, git_vector_search(NULL, &env_result, "SOME_EXISTING_ENV=propagated"));
+}
diff --git a/tests/util/process/start.c b/tests/util/process/start.c
new file mode 100644
index 0000000..19ae5e3
--- /dev/null
+++ b/tests/util/process/start.c
@@ -0,0 +1,247 @@
+#include "clar_libgit2.h"
+#include "process.h"
+#include "vector.h"
+
+#ifndef GIT_WIN32
+# include <signal.h>
+#endif
+
+#ifndef SIGTERM
+# define SIGTERM 42
+#endif
+
+#ifndef SIGPIPE
+# define SIGPIPE 42
+#endif
+
+static git_str helloworld_cmd = GIT_STR_INIT;
+static git_str cat_cmd = GIT_STR_INIT;
+static git_str pwd_cmd = GIT_STR_INIT;
+
+void test_process_start__initialize(void)
+{
+#ifdef GIT_WIN32
+ git_str_printf(&helloworld_cmd, "%s/helloworld.bat", cl_fixture("process"));
+ git_str_printf(&cat_cmd, "%s/cat.bat", cl_fixture("process"));
+ git_str_printf(&pwd_cmd, "%s/pwd.bat", cl_fixture("process"));
+#else
+ git_str_printf(&helloworld_cmd, "%s/helloworld.sh", cl_fixture("process"));
+#endif
+}
+
+void test_process_start__cleanup(void)
+{
+ git_str_dispose(&pwd_cmd);
+ git_str_dispose(&cat_cmd);
+ git_str_dispose(&helloworld_cmd);
+}
+
+void test_process_start__returncode(void)
+{
+#if defined(GIT_WIN32)
+ const char *args_array[] = { "C:\\Windows\\System32\\cmd.exe", "/c", "exit", "1" };
+#elif defined(__APPLE__) || defined(__NetBSD__) || defined(__FreeBSD__) || \
+ defined(__MidnightBSD__) || defined(__DragonFly__)
+ const char *args_array[] = { "/usr/bin/false" };
+#else
+ const char *args_array[] = { "/bin/false" };
+#endif
+
+ git_process *process;
+ git_process_options opts = GIT_PROCESS_OPTIONS_INIT;
+ git_process_result result = GIT_PROCESS_RESULT_INIT;
+
+ cl_git_pass(git_process_new(&process, args_array, ARRAY_SIZE(args_array), NULL, 0, &opts));
+ cl_git_pass(git_process_start(process));
+ cl_git_pass(git_process_wait(&result, process));
+
+ cl_assert_equal_i(GIT_PROCESS_STATUS_NORMAL, result.status);
+ cl_assert_equal_i(1, result.exitcode);
+ cl_assert_equal_i(0, result.signal);
+
+ git_process_free(process);
+}
+
+void test_process_start__not_found(void)
+{
+#ifdef GIT_WIN32
+ const char *args_array[] = { "C:\\a\\b\\z\\y\\not_found" };
+#else
+ const char *args_array[] = { "/a/b/z/y/not_found" };
+#endif
+
+ git_process *process;
+ git_process_options opts = GIT_PROCESS_OPTIONS_INIT;
+
+ cl_git_pass(git_process_new(&process, args_array, ARRAY_SIZE(args_array), NULL, 0, &opts));
+ cl_git_fail(git_process_start(process));
+ git_process_free(process);
+}
+
+static void write_all(git_process *process, char *buf)
+{
+ size_t buf_len = strlen(buf);
+ ssize_t ret;
+
+ while (buf_len) {
+ ret = git_process_write(process, buf, buf_len);
+ cl_git_pass(ret < 0 ? (int)ret : 0);
+
+ buf += ret;
+ buf_len -= ret;
+ }
+}
+
+static void read_all(git_str *out, git_process *process)
+{
+ char buf[32];
+ size_t buf_len = 32;
+ ssize_t ret;
+
+ while ((ret = git_process_read(process, buf, buf_len)) > 0)
+ cl_git_pass(git_str_put(out, buf, ret));
+
+ cl_git_pass(ret < 0 ? (int)ret : 0);
+}
+
+void test_process_start__redirect_stdio(void)
+{
+#ifdef GIT_WIN32
+ const char *args_array[] = { "C:\\Windows\\System32\\cmd.exe", "/c", cat_cmd.ptr };
+#else
+ const char *args_array[] = { "/bin/cat" };
+#endif
+
+ git_process *process;
+ git_process_options opts = GIT_PROCESS_OPTIONS_INIT;
+ git_process_result result = GIT_PROCESS_RESULT_INIT;
+ git_str buf = GIT_STR_INIT;
+
+ opts.capture_in = 1;
+ opts.capture_out = 1;
+
+ cl_git_pass(git_process_new(&process, args_array, ARRAY_SIZE(args_array), NULL, 0, &opts));
+ cl_git_pass(git_process_start(process));
+
+ write_all(process, "Hello, world.\r\nHello!\r\n");
+ cl_git_pass(git_process_close_in(process));
+
+ read_all(&buf, process);
+ cl_assert_equal_s("Hello, world.\r\nHello!\r\n", buf.ptr);
+
+ cl_git_pass(git_process_wait(&result, process));
+
+ cl_assert_equal_i(GIT_PROCESS_STATUS_NORMAL, result.status);
+ cl_assert_equal_i(0, result.exitcode);
+ cl_assert_equal_i(0, result.signal);
+
+ git_str_dispose(&buf);
+ git_process_free(process);
+}
+
+/*
+void test_process_start__catch_sigterm(void)
+{
+ const char *args_array[] = { "/bin/cat" };
+
+ git_process *process;
+ git_process_options opts = GIT_PROCESS_OPTIONS_INIT;
+ git_process_result result = GIT_PROCESS_RESULT_INIT;
+ p_pid_t pid;
+
+ opts.capture_out = 1;
+
+ cl_git_pass(git_process_new(&process, args_array, ARRAY_SIZE(args_array), NULL, 0, &opts));
+ cl_git_pass(git_process_start(process));
+ cl_git_pass(git_process_id(&pid, process));
+
+ cl_must_pass(kill(pid, SIGTERM));
+
+ cl_git_pass(git_process_wait(&result, process));
+
+ cl_assert_equal_i(GIT_PROCESS_STATUS_ERROR, result.status);
+ cl_assert_equal_i(0, result.exitcode);
+ cl_assert_equal_i(SIGTERM, result.signal);
+
+ git_process_free(process);
+}
+
+void test_process_start__catch_sigpipe(void)
+{
+ const char *args_array[] = { helloworld_cmd.ptr };
+
+ git_process *process;
+ git_process_options opts = GIT_PROCESS_OPTIONS_INIT;
+ git_process_result result = GIT_PROCESS_RESULT_INIT;
+
+ opts.capture_out = 1;
+
+ cl_git_pass(git_process_new(&process, args_array, ARRAY_SIZE(args_array), NULL, 0, &opts));
+ cl_git_pass(git_process_start(process));
+ cl_git_pass(git_process_close(process));
+ cl_git_pass(git_process_wait(&result, process));
+
+ cl_assert_equal_i(GIT_PROCESS_STATUS_ERROR, result.status);
+ cl_assert_equal_i(0, result.exitcode);
+ cl_assert_equal_i(SIGPIPE, result.signal);
+
+ git_process_free(process);
+}
+*/
+
+void test_process_start__can_chdir(void)
+{
+#ifdef GIT_WIN32
+ const char *args_array[] = { "C:\\Windows\\System32\\cmd.exe", "/c", pwd_cmd.ptr };
+ char *startwd = "C:\\";
+#else
+ const char *args_array[] = { "/bin/pwd" };
+ char *startwd = "/";
+#endif
+
+ git_process *process;
+ git_process_options opts = GIT_PROCESS_OPTIONS_INIT;
+ git_process_result result = GIT_PROCESS_RESULT_INIT;
+ git_str buf = GIT_STR_INIT;
+
+ opts.cwd = startwd;
+ opts.capture_out = 1;
+
+ cl_git_pass(git_process_new(&process, args_array, ARRAY_SIZE(args_array), NULL, 0, &opts));
+ cl_git_pass(git_process_start(process));
+
+ read_all(&buf, process);
+ git_str_rtrim(&buf);
+
+ cl_assert_equal_s(startwd, buf.ptr);
+
+ cl_git_pass(git_process_wait(&result, process));
+
+ cl_assert_equal_i(GIT_PROCESS_STATUS_NORMAL, result.status);
+ cl_assert_equal_i(0, result.exitcode);
+ cl_assert_equal_i(0, result.signal);
+
+ git_str_dispose(&buf);
+ git_process_free(process);
+}
+
+void test_process_start__cannot_chdir_to_nonexistent_dir(void)
+{
+#ifdef GIT_WIN32
+ const char *args_array[] = { "C:\\Windows\\System32\\cmd.exe", "/c", pwd_cmd.ptr };
+ char *startwd = "C:\\a\\b\\z\\y\\not_found";
+#else
+ const char *args_array[] = { "/bin/pwd" };
+ char *startwd = "/a/b/z/y/not_found";
+#endif
+
+ git_process *process;
+ git_process_options opts = GIT_PROCESS_OPTIONS_INIT;
+
+ opts.cwd = startwd;
+ opts.capture_out = 1;
+
+ cl_git_pass(git_process_new(&process, args_array, ARRAY_SIZE(args_array), NULL, 0, &opts));
+ cl_git_fail(git_process_start(process));
+ git_process_free(process);
+}
diff --git a/tests/util/process/win32.c b/tests/util/process/win32.c
new file mode 100644
index 0000000..c04a56e
--- /dev/null
+++ b/tests/util/process/win32.c
@@ -0,0 +1,63 @@
+#include "clar_libgit2.h"
+#include "process.h"
+#include "vector.h"
+
+#ifdef GIT_WIN32
+static git_str result;
+
+# define assert_cmdline(expected, given) do { \
+ cl_git_pass(git_process__cmdline(&result, given, ARRAY_SIZE(given))); \
+ cl_assert_equal_s(expected, result.ptr); \
+ git_str_dispose(&result); \
+ } while(0)
+
+#endif
+
+
+void test_process_win32__cmdline_is_whitespace_delimited(void)
+{
+#ifdef GIT_WIN32
+ const char *one[] = { "one" };
+ const char *two[] = { "one", "two" };
+ const char *three[] = { "one", "two", "three" };
+ const char *four[] = { "one", "two", "three", "four" };
+
+ assert_cmdline("one", one);
+ assert_cmdline("one two", two);
+ assert_cmdline("one two three", three);
+ assert_cmdline("one two three four", four);
+#endif
+}
+
+void test_process_win32__cmdline_escapes_whitespace(void)
+{
+#ifdef GIT_WIN32
+ const char *spaces[] = { "one with spaces" };
+ const char *tabs[] = { "one\twith\ttabs" };
+ const char *multiple[] = { "one with many spaces" };
+
+ assert_cmdline("one\" \"with\" \"spaces", spaces);
+ assert_cmdline("one\"\t\"with\"\t\"tabs", tabs);
+ assert_cmdline("one\" \"with\" \"many\" \"spaces", multiple);
+#endif
+}
+
+void test_process_win32__cmdline_escapes_quotes(void)
+{
+#ifdef GIT_WIN32
+ const char *one[] = { "echo", "\"hello world\"" };
+
+ assert_cmdline("echo \\\"hello\" \"world\\\"", one);
+#endif
+}
+
+void test_process_win32__cmdline_escapes_backslash(void)
+{
+#ifdef GIT_WIN32
+ const char *one[] = { "foo\\bar", "foo\\baz" };
+ const char *two[] = { "c:\\program files\\foo bar\\foo bar.exe", "c:\\path\\to\\other\\", "/a", "/b" };
+
+ assert_cmdline("foo\\\\bar foo\\\\baz", one);
+ assert_cmdline("c:\\\\program\" \"files\\\\foo\" \"bar\\\\foo\" \"bar.exe c:\\\\path\\\\to\\\\other\\\\ /a /b", two);
+#endif
+}
diff --git a/tests/util/string.c b/tests/util/string.c
index de04dea..051f8c3 100644
--- a/tests/util/string.c
+++ b/tests/util/string.c
@@ -111,12 +111,6 @@ void test_string__strcasecmp(void)
cl_assert(git__strcasecmp("foo", "FOO") == 0);
cl_assert(git__strcasecmp("foo", "fOO") == 0);
- cl_assert(strcasecmp("rt\303\202of", "rt dev\302\266h") > 0);
- cl_assert(strcasecmp("e\342\202\254ghi=", "et") > 0);
- cl_assert(strcasecmp("rt dev\302\266h", "rt\303\202of") < 0);
- cl_assert(strcasecmp("et", "e\342\202\254ghi=") < 0);
- cl_assert(strcasecmp("\303\215", "\303\255") < 0);
-
cl_assert(git__strcasecmp("rt\303\202of", "rt dev\302\266h") > 0);
cl_assert(git__strcasecmp("e\342\202\254ghi=", "et") > 0);
cl_assert(git__strcasecmp("rt dev\302\266h", "rt\303\202of") < 0);