diff options
Diffstat (limited to '')
-rw-r--r-- | tests/util/assert.c | 3 | ||||
-rw-r--r-- | tests/util/errors.c | 84 | ||||
-rw-r--r-- | tests/util/path.c | 768 | ||||
-rw-r--r-- | tests/util/path/core.c | 804 | ||||
-rw-r--r-- | tests/util/path/win32.c | 33 | ||||
-rw-r--r-- | tests/util/process/env.c | 111 | ||||
-rw-r--r-- | tests/util/process/start.c | 247 | ||||
-rw-r--r-- | tests/util/process/win32.c | 63 | ||||
-rw-r--r-- | tests/util/string.c | 6 |
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); |