diff options
Diffstat (limited to 'tests')
226 files changed, 4809 insertions, 482 deletions
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt new file mode 100644 index 000000000..5aba2914a --- /dev/null +++ b/tests/CMakeLists.txt @@ -0,0 +1,63 @@ +FIND_PACKAGE(PythonInterp) + +IF(NOT PYTHONINTERP_FOUND) + MESSAGE(FATAL_ERROR "Could not find a python interpeter, which is needed to build the tests. " + "Make sure python is available, or pass -DBUILD_CLAR=OFF to skip building the tests") +ENDIF() + +SET(CLAR_FIXTURES "${CMAKE_CURRENT_SOURCE_DIR}/resources/") +SET(CLAR_PATH "${CMAKE_CURRENT_SOURCE_DIR}") +ADD_DEFINITIONS(-DCLAR_FIXTURE_PATH=\"${CLAR_FIXTURES}\") +ADD_DEFINITIONS(-DCLAR_TMPDIR=\"libgit2_tests\") + +INCLUDE_DIRECTORIES(${CLAR_PATH} ${CMAKE_BINARY_DIR}/src) +FILE(GLOB_RECURSE SRC_TEST ${CLAR_PATH}/*/*.c ${CLAR_PATH}/*/*.h) +SET(SRC_CLAR "main.c" "clar_libgit2.c" "clar_libgit2_trace.c" "clar_libgit2_timer.c" "clar.c") + +IF(MSVC_IDE) + LIST(APPEND SRC_CLAR "precompiled.c") +ENDIF() + +ADD_CUSTOM_COMMAND( + OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/clar.suite + COMMAND ${PYTHON_EXECUTABLE} generate.py -o "${CMAKE_CURRENT_BINARY_DIR}" -f -xonline -xstress . + DEPENDS ${SRC_TEST} + WORKING_DIRECTORY ${CLAR_PATH} +) +INCLUDE_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR}) + +SET_SOURCE_FILES_PROPERTIES( + ${CLAR_PATH}/clar.c + PROPERTIES OBJECT_DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/clar.suite) + +LINK_DIRECTORIES(${LIBGIT2_LIBDIRS}) +INCLUDE_DIRECTORIES(${LIBGIT2_INCLUDES}) + +ADD_EXECUTABLE(libgit2_clar ${SRC_CLAR} ${SRC_TEST} ${GIT2INTERNAL_OBJECTS}) + +SET_TARGET_PROPERTIES(libgit2_clar PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}) + +IF (${CMAKE_VERSION} VERSION_GREATER 2.8.11) + TARGET_INCLUDE_DIRECTORIES(libgit2_clar PRIVATE ../src PUBLIC ../include) +ENDIF() + +TARGET_LINK_LIBRARIES(libgit2_clar ${LIBGIT2_LIBS}) +IDE_SPLIT_SOURCES(libgit2_clar) + +IF (MSVC_IDE) + # Precompiled headers + SET_TARGET_PROPERTIES(libgit2_clar PROPERTIES COMPILE_FLAGS "/Yuprecompiled.h /FIprecompiled.h") + SET_SOURCE_FILES_PROPERTIES("precompiled.c" COMPILE_FLAGS "/Ycprecompiled.h") +ENDIF () + +IF (WINHTTP OR OPENSSL_FOUND OR SECURITY_FOUND) + ADD_TEST(libgit2_clar "${CMAKE_BINARY_DIR}/libgit2_clar" -ionline -xclone::local::git_style_unc_paths -xclone::local::standard_unc_paths_are_written_git_style) +ELSE () + ADD_TEST(libgit2_clar "${CMAKE_BINARY_DIR}/libgit2_clar" -v -xclone::local::git_style_unc_paths -xclone::local::standard_unc_paths_are_written_git_style) +ENDIF () + +# Add a test target which runs the cred callback tests, to be +# called after setting the url and user +ADD_TEST(libgit2_clar-cred_callback "${CMAKE_BINARY_DIR}/libgit2_clar" -v -sonline::clone::cred_callback) +ADD_TEST(libgit2_clar-proxy_credentials_in_url "${CMAKE_BINARY_DIR}/libgit2_clar" -v -sonline::clone::proxy_credentials_in_url) +ADD_TEST(libgit2_clar-proxy_credentials_request "${CMAKE_BINARY_DIR}/libgit2_clar" -v -sonline::clone::proxy_credentials_request) diff --git a/tests/attr/ignore.c b/tests/attr/ignore.c index f1fe1c71f..856e61f90 100644 --- a/tests/attr/ignore.c +++ b/tests/attr/ignore.c @@ -21,8 +21,8 @@ static void assert_is_ignored_( { int is_ignored = 0; - cl_git_pass_( - git_ignore_path_is_ignored(&is_ignored, g_repo, filepath), file, line); + cl_git_expect( + git_ignore_path_is_ignored(&is_ignored, g_repo, filepath), 0, file, line); clar__assert_equal( file, line, "expected != is_ignored", 1, "%d", @@ -291,3 +291,58 @@ void test_attr_ignore__symlink_to_outside(void) assert_is_ignored(true, "symlink"); assert_is_ignored(true, "lala/../symlink"); } + +void test_attr_ignore__test(void) +{ + cl_git_rewritefile("attr/.gitignore", + "/*/\n" + "!/src\n"); + assert_is_ignored(false, "src/foo.c"); + assert_is_ignored(false, "src/foo/foo.c"); + assert_is_ignored(false, "README.md"); + assert_is_ignored(true, "dist/foo.o"); + assert_is_ignored(true, "bin/foo"); +} + +void test_attr_ignore__unignore_dir_succeeds(void) +{ + cl_git_rewritefile("attr/.gitignore", + "*.c\n" + "!src/*.c\n"); + assert_is_ignored(false, "src/foo.c"); + assert_is_ignored(true, "src/foo/foo.c"); +} + +void test_attr_ignore__case_insensitive_unignores_previous_rule(void) +{ + git_config *cfg; + + cl_git_rewritefile("attr/.gitignore", + "/case\n" + "!/Case/\n"); + + cl_git_pass(git_repository_config(&cfg, g_repo)); + cl_git_pass(git_config_set_bool(cfg, "core.ignorecase", true)); + + cl_must_pass(p_mkdir("attr/case", 0755)); + cl_git_mkfile("attr/case/file", "content"); + + assert_is_ignored(false, "case/file"); +} + +void test_attr_ignore__case_sensitive_unignore_does_nothing(void) +{ + git_config *cfg; + + cl_git_rewritefile("attr/.gitignore", + "/case\n" + "!/Case/\n"); + + cl_git_pass(git_repository_config(&cfg, g_repo)); + cl_git_pass(git_config_set_bool(cfg, "core.ignorecase", false)); + + cl_must_pass(p_mkdir("attr/case", 0755)); + cl_git_mkfile("attr/case/file", "content"); + + assert_is_ignored(true, "case/file"); +} diff --git a/tests/checkout/head.c b/tests/checkout/head.c index 07cc1d209..ded86df33 100644 --- a/tests/checkout/head.c +++ b/tests/checkout/head.c @@ -38,7 +38,7 @@ void test_checkout_head__with_index_only_tree(void) cl_git_pass(git_repository_index(&index, g_repo)); p_mkdir("testrepo/newdir", 0777); - cl_git_mkfile("testrepo/newdir/newfile.txt", "new file\n"); + cl_git_mkfile("testrepo/newdir/newfile.txt", "new file\n"); cl_git_pass(git_index_add_bypath(index, "newdir/newfile.txt")); cl_git_pass(git_index_write(index)); @@ -60,3 +60,79 @@ void test_checkout_head__with_index_only_tree(void) git_index_free(index); } + +void test_checkout_head__do_not_remove_untracked_file(void) +{ + git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT; + git_index *index; + + cl_git_pass(p_mkdir("testrepo/tracked", 0755)); + cl_git_mkfile("testrepo/tracked/tracked", "tracked\n"); + cl_git_mkfile("testrepo/tracked/untracked", "untracked\n"); + + cl_git_pass(git_repository_index(&index, g_repo)); + cl_git_pass(git_index_add_bypath(index, "tracked/tracked")); + cl_git_pass(git_index_write(index)); + + git_index_free(index); + + opts.checkout_strategy = GIT_CHECKOUT_FORCE; + cl_git_pass(git_checkout_head(g_repo, &opts)); + + cl_assert(!git_path_isfile("testrepo/tracked/tracked")); + cl_assert(git_path_isfile("testrepo/tracked/untracked")); +} + +void test_checkout_head__do_not_remove_untracked_file_in_subdir(void) +{ + git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT; + git_index *index; + + cl_git_pass(p_mkdir("testrepo/tracked", 0755)); + cl_git_pass(p_mkdir("testrepo/tracked/subdir", 0755)); + cl_git_mkfile("testrepo/tracked/tracked", "tracked\n"); + cl_git_mkfile("testrepo/tracked/subdir/tracked", "tracked\n"); + cl_git_mkfile("testrepo/tracked/subdir/untracked", "untracked\n"); + + cl_git_pass(git_repository_index(&index, g_repo)); + cl_git_pass(git_index_add_bypath(index, "tracked/tracked")); + cl_git_pass(git_index_add_bypath(index, "tracked/subdir/tracked")); + cl_git_pass(git_index_write(index)); + + git_index_free(index); + + opts.checkout_strategy = GIT_CHECKOUT_FORCE; + cl_git_pass(git_checkout_head(g_repo, &opts)); + + cl_assert(!git_path_isfile("testrepo/tracked/tracked")); + cl_assert(!git_path_isfile("testrepo/tracked/subdir/tracked")); + cl_assert(git_path_isfile("testrepo/tracked/subdir/untracked")); +} + +void test_checkout_head__do_remove_tracked_subdir(void) +{ + git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT; + git_index *index; + + cl_git_pass(p_mkdir("testrepo/subdir", 0755)); + cl_git_pass(p_mkdir("testrepo/subdir/tracked", 0755)); + cl_git_mkfile("testrepo/subdir/tracked-file", "tracked\n"); + cl_git_mkfile("testrepo/subdir/untracked-file", "untracked\n"); + cl_git_mkfile("testrepo/subdir/tracked/tracked1", "tracked\n"); + cl_git_mkfile("testrepo/subdir/tracked/tracked2", "tracked\n"); + + cl_git_pass(git_repository_index(&index, g_repo)); + cl_git_pass(git_index_add_bypath(index, "subdir/tracked-file")); + cl_git_pass(git_index_add_bypath(index, "subdir/tracked/tracked1")); + cl_git_pass(git_index_add_bypath(index, "subdir/tracked/tracked2")); + cl_git_pass(git_index_write(index)); + + git_index_free(index); + + opts.checkout_strategy = GIT_CHECKOUT_FORCE; + cl_git_pass(git_checkout_head(g_repo, &opts)); + + cl_assert(!git_path_isdir("testrepo/subdir/tracked")); + cl_assert(!git_path_isfile("testrepo/subdir/tracked-file")); + cl_assert(git_path_isfile("testrepo/subdir/untracked-file")); +} diff --git a/tests/checkout/tree.c b/tests/checkout/tree.c index 4a0314a9e..b3b860c63 100644 --- a/tests/checkout/tree.c +++ b/tests/checkout/tree.c @@ -422,6 +422,41 @@ void test_checkout_tree__can_checkout_with_pattern(void) cl_assert(git_path_exists("testrepo/new.txt")); } +void test_checkout_tree__pathlist_checkout_ignores_non_matches(void) +{ + char *entries[] = { "branch_file.txt", "link_to_new.txt" }; + + /* reset to beginning of history (i.e. just a README file) */ + + g_opts.checkout_strategy = + GIT_CHECKOUT_FORCE | GIT_CHECKOUT_REMOVE_UNTRACKED; + + cl_git_pass(git_revparse_single(&g_object, g_repo, "refs/heads/master")); + + cl_git_pass(git_checkout_tree(g_repo, g_object, &g_opts)); + cl_git_pass(git_repository_set_head(g_repo, "refs/heads/master")); + + cl_assert(git_path_exists("testrepo/README")); + cl_assert(git_path_exists("testrepo/branch_file.txt")); + cl_assert(git_path_exists("testrepo/link_to_new.txt")); + cl_assert(git_path_exists("testrepo/new.txt")); + + git_object_free(g_object); + cl_git_pass(git_revparse_single(&g_object, g_repo, "8496071c1b46c854b31185ea97743be6a8774479")); + + g_opts.checkout_strategy = + GIT_CHECKOUT_FORCE | GIT_CHECKOUT_DISABLE_PATHSPEC_MATCH; + g_opts.paths.strings = entries; + g_opts.paths.count = 2; + + cl_git_pass(git_checkout_tree(g_repo, g_object, &g_opts)); + + cl_assert(git_path_exists("testrepo/README")); + cl_assert(!git_path_exists("testrepo/branch_file.txt")); + cl_assert(!git_path_exists("testrepo/link_to_new.txt")); + cl_assert(git_path_exists("testrepo/new.txt")); +} + void test_checkout_tree__can_disable_pattern_match(void) { char *entries[] = { "b*.txt" }; diff --git a/tests/clar_libgit2.c b/tests/clar_libgit2.c index 314d3441e..bd10c009d 100644 --- a/tests/clar_libgit2.c +++ b/tests/clar_libgit2.c @@ -4,12 +4,20 @@ #include "git2/sys/repository.h" void cl_git_report_failure( - int error, const char *file, int line, const char *fncall) + int error, int expected, const char *file, int line, const char *fncall) { char msg[4096]; const git_error *last = giterr_last(); - p_snprintf(msg, 4096, "error %d - %s", - error, last ? last->message : "<no message>"); + + if (expected) + p_snprintf(msg, 4096, "error %d (expected %d) - %s", + error, expected, last ? last->message : "<no message>"); + else if (error || last) + p_snprintf(msg, 4096, "error %d - %s", + error, last ? last->message : "<no message>"); + else + p_snprintf(msg, 4096, "no error, expected non-zero return"); + clar__assert(0, file, line, fncall, msg, 1); } diff --git a/tests/clar_libgit2.h b/tests/clar_libgit2.h index d7e635302..c72d37db3 100644 --- a/tests/clar_libgit2.h +++ b/tests/clar_libgit2.h @@ -12,13 +12,15 @@ * * Use this wrapper around all `git_` library calls that return error codes! */ -#define cl_git_pass(expr) cl_git_pass_((expr), __FILE__, __LINE__) +#define cl_git_pass(expr) cl_git_expect((expr), 0, __FILE__, __LINE__) -#define cl_git_pass_(expr, file, line) do { \ +#define cl_git_fail_with(error, expr) cl_git_expect((expr), error, __FILE__, __LINE__) + +#define cl_git_expect(expr, expected, file, line) do { \ int _lg2_error; \ giterr_clear(); \ - if ((_lg2_error = (expr)) != 0) \ - cl_git_report_failure(_lg2_error, file, line, "Function call failed: " #expr); \ + if ((_lg2_error = (expr)) != expected) \ + cl_git_report_failure(_lg2_error, expected, file, line, "Function call failed: " #expr); \ } while (0) /** @@ -26,9 +28,11 @@ * just for consistency. Use with `git_` library * calls that are supposed to fail! */ -#define cl_git_fail(expr) cl_must_fail(expr) - -#define cl_git_fail_with(expr, error) cl_assert_equal_i(error,expr) +#define cl_git_fail(expr) do { \ + giterr_clear(); \ + if ((expr) == 0) \ + cl_git_report_failure(0, 0, __FILE__, __LINE__, "Function call succeeded: " #expr); \ + } while (0) /** * Like cl_git_pass, only for Win32 error code conventions @@ -37,11 +41,56 @@ int _win32_res; \ if ((_win32_res = (expr)) == 0) { \ giterr_set(GITERR_OS, "Returned: %d, system error code: %d", _win32_res, GetLastError()); \ - cl_git_report_failure(_win32_res, __FILE__, __LINE__, "System call failed: " #expr); \ + cl_git_report_failure(_win32_res, 0, __FILE__, __LINE__, "System call failed: " #expr); \ } \ } while(0) -void cl_git_report_failure(int, const char *, int, const char *); +/** + * Thread safe assertions; you cannot use `cl_git_report_failure` from a + * child thread since it will try to `longjmp` to abort and "the effect of + * a call to longjmp() where initialization of the jmp_buf structure was + * not performed in the calling thread is undefined." + * + * Instead, callers can provide a clar thread error context to a thread, + * which will populate and return it on failure. Callers can check the + * status with `cl_git_thread_check`. + */ +typedef struct { + int error; + const char *file; + int line; + const char *expr; + char error_msg[4096]; +} cl_git_thread_err; + +#ifdef GIT_THREADS +# define cl_git_thread_pass(threaderr, expr) cl_git_thread_pass_(threaderr, (expr), __FILE__, __LINE__) +#else +# define cl_git_thread_pass(threaderr, expr) cl_git_pass(expr) +#endif + +#define cl_git_thread_pass_(__threaderr, __expr, __file, __line) do { \ + giterr_clear(); \ + if ((((cl_git_thread_err *)__threaderr)->error = (__expr)) != 0) { \ + const git_error *_last = giterr_last(); \ + ((cl_git_thread_err *)__threaderr)->file = __file; \ + ((cl_git_thread_err *)__threaderr)->line = __line; \ + ((cl_git_thread_err *)__threaderr)->expr = "Function call failed: " #__expr; \ + p_snprintf(((cl_git_thread_err *)__threaderr)->error_msg, 4096, "thread 0x%" PRIxZ " - error %d - %s", \ + git_thread_currentid(), ((cl_git_thread_err *)__threaderr)->error, \ + _last ? _last->message : "<no message>"); \ + git_thread_exit(__threaderr); \ + } \ + } while (0) + +GIT_INLINE(void) cl_git_thread_check(void *data) +{ + cl_git_thread_err *threaderr = (cl_git_thread_err *)data; + if (threaderr->error != 0) + clar__assert(0, threaderr->file, threaderr->line, threaderr->expr, threaderr->error_msg, 1); +} + +void cl_git_report_failure(int, int, const char *, int, const char *); #define cl_assert_at_line(expr,file,line) \ clar__assert((expr) != 0, file, line, "Expression is not true: " #expr, NULL, 1) diff --git a/tests/clone/local.c b/tests/clone/local.c index 91a0a1c2a..7f54d05de 100644 --- a/tests/clone/local.c +++ b/tests/clone/local.c @@ -16,6 +16,7 @@ static int file_url(git_buf *buf, const char *host, const char *path) return git_buf_printf(buf, "file://%s/%s", host, path); } +#ifdef GIT_WIN32 static int git_style_unc_path(git_buf *buf, const char *host, const char *path) { git_buf_clear(buf); @@ -49,6 +50,7 @@ static int unc_path(git_buf *buf, const char *host, const char *path) return 0; } +#endif void test_clone_local__should_clone_local(void) { diff --git a/tests/config/include.c b/tests/config/include.c index 882b89b16..e440b9a78 100644 --- a/tests/config/include.c +++ b/tests/config/include.c @@ -2,25 +2,31 @@ #include "buffer.h" #include "fileops.h" -void test_config_include__relative(void) +static git_config *cfg; +static git_buf buf; + +void test_config_include__initialize(void) { - git_config *cfg; - git_buf buf = GIT_BUF_INIT; + cfg = NULL; + git_buf_init(&buf, 0); +} +void test_config_include__cleanup(void) +{ + git_config_free(cfg); + git_buf_free(&buf); +} + +void test_config_include__relative(void) +{ cl_git_pass(git_config_open_ondisk(&cfg, cl_fixture("config/config-include"))); cl_git_pass(git_config_get_string_buf(&buf, cfg, "foo.bar.baz")); cl_assert_equal_s("huzzah", git_buf_cstr(&buf)); - - git_buf_free(&buf); - git_config_free(cfg); } void test_config_include__absolute(void) { - git_config *cfg; - git_buf buf = GIT_BUF_INIT; - cl_git_pass(git_buf_printf(&buf, "[include]\npath = %s/config-included", cl_fixture("config"))); cl_git_mkfile("config-include-absolute", git_buf_cstr(&buf)); @@ -29,16 +35,10 @@ void test_config_include__absolute(void) cl_git_pass(git_config_get_string_buf(&buf, cfg, "foo.bar.baz")); cl_assert_equal_s("huzzah", git_buf_cstr(&buf)); - - git_buf_free(&buf); - git_config_free(cfg); } void test_config_include__homedir(void) { - git_config *cfg; - git_buf buf = GIT_BUF_INIT; - cl_git_pass(git_libgit2_opts(GIT_OPT_SET_SEARCH_PATH, GIT_CONFIG_LEVEL_GLOBAL, cl_fixture("config"))); cl_git_mkfile("config-include-homedir", "[include]\npath = ~/config-included"); @@ -47,18 +47,12 @@ void test_config_include__homedir(void) cl_git_pass(git_config_get_string_buf(&buf, cfg, "foo.bar.baz")); cl_assert_equal_s("huzzah", git_buf_cstr(&buf)); - git_buf_free(&buf); - git_config_free(cfg); - cl_sandbox_set_search_path_defaults(); } /* We need to pretend that the variables were defined where the file was included */ void test_config_include__ordering(void) { - git_config *cfg; - git_buf buf = GIT_BUF_INIT; - cl_git_mkfile("included", "[foo \"bar\"]\nbaz = hurrah\nfrotz = hiya"); cl_git_mkfile("including", "[foo \"bar\"]\nfrotz = hello\n" @@ -72,16 +66,11 @@ void test_config_include__ordering(void) git_buf_clear(&buf); cl_git_pass(git_config_get_string_buf(&buf, cfg, "foo.bar.baz")); cl_assert_equal_s("huzzah", git_buf_cstr(&buf)); - - git_buf_free(&buf); - git_config_free(cfg); } /* We need to pretend that the variables were defined where the file was included */ void test_config_include__depth(void) { - git_config *cfg; - cl_git_mkfile("a", "[include]\npath = b"); cl_git_mkfile("b", "[include]\npath = a"); @@ -93,9 +82,6 @@ void test_config_include__depth(void) void test_config_include__missing(void) { - git_config *cfg; - git_buf buf = GIT_BUF_INIT; - cl_git_mkfile("including", "[include]\npath = nonexistentfile\n[foo]\nbar = baz"); giterr_clear(); @@ -103,16 +89,25 @@ void test_config_include__missing(void) cl_assert(giterr_last() == NULL); cl_git_pass(git_config_get_string_buf(&buf, cfg, "foo.bar")); cl_assert_equal_s("baz", git_buf_cstr(&buf)); +} - git_buf_free(&buf); - git_config_free(cfg); +void test_config_include__missing_homedir(void) +{ + cl_git_pass(git_libgit2_opts(GIT_OPT_SET_SEARCH_PATH, GIT_CONFIG_LEVEL_GLOBAL, cl_fixture("config"))); + cl_git_mkfile("including", "[include]\npath = ~/.nonexistentfile\n[foo]\nbar = baz"); + + giterr_clear(); + cl_git_pass(git_config_open_ondisk(&cfg, "including")); + cl_assert(giterr_last() == NULL); + cl_git_pass(git_config_get_string_buf(&buf, cfg, "foo.bar")); + cl_assert_equal_s("baz", git_buf_cstr(&buf)); + + cl_sandbox_set_search_path_defaults(); } #define replicate10(s) s s s s s s s s s s void test_config_include__depth2(void) { - git_config *cfg; - git_buf buf = GIT_BUF_INIT; const char *content = "[include]\n" replicate10(replicate10("path=bottom\n")); cl_git_mkfile("top-level", "[include]\npath = middle\n[foo]\nbar = baz"); @@ -127,7 +122,45 @@ void test_config_include__depth2(void) git_buf_clear(&buf); cl_git_pass(git_config_get_string_buf(&buf, cfg, "foo.bar2")); cl_assert_equal_s("baz2", git_buf_cstr(&buf)); +} - git_buf_free(&buf); - git_config_free(cfg); +void test_config_include__removing_include_removes_values(void) +{ + cl_git_mkfile("top-level", "[include]\npath = included"); + cl_git_mkfile("included", "[foo]\nbar = value"); + + cl_git_pass(git_config_open_ondisk(&cfg, "top-level")); + cl_git_mkfile("top-level", ""); + cl_git_fail(git_config_get_string_buf(&buf, cfg, "foo.bar")); +} + +void test_config_include__rewriting_include_refreshes_values(void) +{ + cl_git_mkfile("top-level", "[include]\npath = first\n[include]\npath = second"); + cl_git_mkfile("first", "[first]\nfoo = bar"); + cl_git_mkfile("second", "[second]\nfoo = bar"); + + cl_git_pass(git_config_open_ondisk(&cfg, "top-level")); + cl_git_mkfile("first", "[first]\nother = value"); + cl_git_fail(git_config_get_string_buf(&buf, cfg, "foo.bar")); + cl_git_pass(git_config_get_string_buf(&buf, cfg, "first.other")); + cl_assert_equal_s(buf.ptr, "value"); +} + +void test_config_include__included_variables_cannot_be_deleted(void) +{ + cl_git_mkfile("top-level", "[include]\npath = included\n"); + cl_git_mkfile("included", "[foo]\nbar = value"); + + cl_git_pass(git_config_open_ondisk(&cfg, "top-level")); + cl_git_fail(git_config_delete_entry(cfg, "foo.bar")); +} + +void test_config_include__included_variables_cannot_be_modified(void) +{ + cl_git_mkfile("top-level", "[include]\npath = included\n"); + cl_git_mkfile("included", "[foo]\nbar = value"); + + cl_git_pass(git_config_open_ondisk(&cfg, "top-level")); + cl_git_fail(git_config_set_string(cfg, "foo.bar", "other-value")); } diff --git a/tests/config/readonly.c b/tests/config/readonly.c new file mode 100644 index 000000000..6d6819eef --- /dev/null +++ b/tests/config/readonly.c @@ -0,0 +1,65 @@ +#include "clar_libgit2.h" +#include "config_file.h" +#include "config.h" +#include "path.h" + +static git_config *cfg; + +void test_config_readonly__initialize(void) +{ + cl_git_pass(git_config_new(&cfg)); +} + +void test_config_readonly__cleanup(void) +{ + git_config_free(cfg); + cfg = NULL; +} + +void test_config_readonly__writing_to_readonly_fails(void) +{ + git_config_backend *backend; + + cl_git_pass(git_config_file__ondisk(&backend, "global")); + backend->readonly = 1; + cl_git_pass(git_config_add_backend(cfg, backend, GIT_CONFIG_LEVEL_GLOBAL, 0)); + + cl_git_fail_with(GIT_ENOTFOUND, git_config_set_string(cfg, "foo.bar", "baz")); + cl_assert(!git_path_exists("global")); +} + +void test_config_readonly__writing_to_cfg_with_rw_precedence_succeeds(void) +{ + git_config_backend *backend; + + cl_git_pass(git_config_file__ondisk(&backend, "global")); + backend->readonly = 1; + cl_git_pass(git_config_add_backend(cfg, backend, GIT_CONFIG_LEVEL_GLOBAL, 0)); + + cl_git_pass(git_config_file__ondisk(&backend, "local")); + cl_git_pass(git_config_add_backend(cfg, backend, GIT_CONFIG_LEVEL_LOCAL, 0)); + + cl_git_pass(git_config_set_string(cfg, "foo.bar", "baz")); + + cl_assert(git_path_exists("local")); + cl_assert(!git_path_exists("global")); + cl_git_pass(p_unlink("local")); +} + +void test_config_readonly__writing_to_cfg_with_ro_precedence_succeeds(void) +{ + git_config_backend *backend; + + cl_git_pass(git_config_file__ondisk(&backend, "local")); + backend->readonly = 1; + cl_git_pass(git_config_add_backend(cfg, backend, GIT_CONFIG_LEVEL_LOCAL, 0)); + + cl_git_pass(git_config_file__ondisk(&backend, "global")); + cl_git_pass(git_config_add_backend(cfg, backend, GIT_CONFIG_LEVEL_GLOBAL, 0)); + + cl_git_pass(git_config_set_string(cfg, "foo.bar", "baz")); + + cl_assert(!git_path_exists("local")); + cl_assert(git_path_exists("global")); + cl_git_pass(p_unlink("global")); +} diff --git a/tests/core/encoding.c b/tests/core/encoding.c index 7d91720f4..a677afe2e 100644 --- a/tests/core/encoding.c +++ b/tests/core/encoding.c @@ -29,6 +29,9 @@ void test_core_encoding__encode(void) cl_assert(git_encode_varint(buf, 100, 65) == 1); cl_assert(buf[0] == 'A'); + cl_assert(git_encode_varint(buf, 1, 1) == 1); + cl_assert(!memcmp(buf, "\x01", 1)); + cl_assert(git_encode_varint(buf, 100, 267869656) == 4); cl_assert(!memcmp(buf, "\xfe\xdc\xbaX", 4)); diff --git a/tests/core/env.c b/tests/core/env.c index ee08258a6..1af0e6e5d 100644 --- a/tests/core/env.c +++ b/tests/core/env.c @@ -298,3 +298,24 @@ void test_core_env__2(void) git_buf_free(&path); git_buf_free(&found); } + +void test_core_env__substitution(void) +{ + git_buf buf = GIT_BUF_INIT, expected = GIT_BUF_INIT; + + /* Set it to something non-default so we have controllable values */ + cl_git_pass(git_libgit2_opts(GIT_OPT_SET_SEARCH_PATH, GIT_CONFIG_LEVEL_GLOBAL, "/tmp/a")); + cl_git_pass(git_libgit2_opts(GIT_OPT_GET_SEARCH_PATH, GIT_CONFIG_LEVEL_GLOBAL, &buf)); + cl_assert_equal_s("/tmp/a", buf.ptr); + + git_buf_clear(&buf); + cl_git_pass(git_buf_join(&buf, GIT_PATH_LIST_SEPARATOR, "$PATH", "/tmp/b")); + cl_git_pass(git_libgit2_opts(GIT_OPT_SET_SEARCH_PATH, GIT_CONFIG_LEVEL_GLOBAL, buf.ptr)); + cl_git_pass(git_libgit2_opts(GIT_OPT_GET_SEARCH_PATH, GIT_CONFIG_LEVEL_GLOBAL, &buf)); + + cl_git_pass(git_buf_join(&expected, GIT_PATH_LIST_SEPARATOR, "/tmp/a", "/tmp/b")); + cl_assert_equal_s(expected.ptr, buf.ptr); + + git_buf_free(&expected); + git_buf_free(&buf); +} diff --git a/tests/core/features.c b/tests/core/features.c index cf5e19063..7b28cc0cb 100644 --- a/tests/core/features.c +++ b/tests/core/features.c @@ -17,7 +17,9 @@ void test_core_features__0(void) cl_assert((caps & GIT_FEATURE_THREADS) == 0); #endif +#ifdef GIT_HTTPS cl_assert((caps & GIT_FEATURE_HTTPS) != 0); +#endif #if defined(GIT_SSH) cl_assert((caps & GIT_FEATURE_SSH) != 0); diff --git a/tests/core/filebuf.c b/tests/core/filebuf.c index 04a380b20..ef7ac6bd9 100644 --- a/tests/core/filebuf.c +++ b/tests/core/filebuf.c @@ -187,6 +187,35 @@ void test_core_filebuf__symlink_follow(void) cl_git_pass(git_futils_rmdir_r(dir, NULL, GIT_RMDIR_REMOVE_FILES)); } +void test_core_filebuf__symlink_follow_absolute_paths(void) +{ + git_filebuf file = GIT_FILEBUF_INIT; + git_buf source = GIT_BUF_INIT, target = GIT_BUF_INIT; + +#ifdef GIT_WIN32 + cl_skip(); +#endif + + cl_git_pass(git_buf_joinpath(&source, clar_sandbox_path(), "linkdir/link")); + cl_git_pass(git_buf_joinpath(&target, clar_sandbox_path(), "linkdir/target")); + cl_git_pass(p_mkdir("linkdir", 0777)); + cl_git_pass(p_symlink(target.ptr, source.ptr)); + + cl_git_pass(git_filebuf_open(&file, source.ptr, 0, 0666)); + cl_git_pass(git_filebuf_printf(&file, "%s\n", "libgit2 rocks")); + + cl_assert_equal_i(true, git_path_exists("linkdir/target.lock")); + + cl_git_pass(git_filebuf_commit(&file)); + cl_assert_equal_i(true, git_path_exists("linkdir/target")); + + git_filebuf_cleanup(&file); + git_buf_free(&source); + git_buf_free(&target); + + cl_git_pass(git_futils_rmdir_r("linkdir", NULL, GIT_RMDIR_REMOVE_FILES)); +} + void test_core_filebuf__symlink_depth(void) { git_filebuf file = GIT_FILEBUF_INIT; diff --git a/tests/core/init.c b/tests/core/init.c index e17b7845f..a8cbd930b 100644 --- a/tests/core/init.c +++ b/tests/core/init.c @@ -12,3 +12,43 @@ void test_core_init__returns_count(void) cl_assert_equal_i(1, git_libgit2_shutdown()); } +void test_core_init__reinit_succeeds(void) +{ + cl_assert_equal_i(0, git_libgit2_shutdown()); + cl_assert_equal_i(1, git_libgit2_init()); + cl_sandbox_set_search_path_defaults(); +} + +#ifdef GIT_THREADS +static void *reinit(void *unused) +{ + unsigned i; + + for (i = 0; i < 20; i++) { + cl_assert(git_libgit2_init() > 0); + cl_assert(git_libgit2_shutdown() >= 0); + } + + return unused; +} +#endif + +void test_core_init__concurrent_init_succeeds(void) +{ +#ifdef GIT_THREADS + git_thread threads[10]; + unsigned i; + + cl_assert_equal_i(2, git_libgit2_init()); + + for (i = 0; i < ARRAY_SIZE(threads); i++) + git_thread_create(&threads[i], reinit, NULL); + for (i = 0; i < ARRAY_SIZE(threads); i++) + git_thread_join(&threads[i], NULL); + + cl_assert_equal_i(1, git_libgit2_shutdown()); + cl_sandbox_set_search_path_defaults(); +#else + cl_skip(); +#endif +} diff --git a/tests/core/oidmap.c b/tests/core/oidmap.c index 556a6ca4a..617da5483 100644 --- a/tests/core/oidmap.c +++ b/tests/core/oidmap.c @@ -1,8 +1,6 @@ #include "clar_libgit2.h" #include "oidmap.h" -GIT__USE_OIDMAP - typedef struct { git_oid oid; size_t extra; @@ -33,23 +31,23 @@ void test_core_oidmap__basic(void) khiter_t pos; int ret; - pos = kh_get(oid, map, &items[i].oid); - cl_assert(pos == kh_end(map)); + pos = git_oidmap_lookup_index(map, &items[i].oid); + cl_assert(!git_oidmap_valid_index(map, pos)); - pos = kh_put(oid, map, &items[i].oid, &ret); + pos = git_oidmap_put(map, &items[i].oid, &ret); cl_assert(ret != 0); - kh_val(map, pos) = &items[i]; + git_oidmap_set_value_at(map, pos, &items[i]); } for (i = 0; i < NITEMS; ++i) { khiter_t pos; - pos = kh_get(oid, map, &items[i].oid); - cl_assert(pos != kh_end(map)); + pos = git_oidmap_lookup_index(map, &items[i].oid); + cl_assert(git_oidmap_valid_index(map, pos)); - cl_assert_equal_p(kh_val(map, pos), &items[i]); + cl_assert_equal_p(git_oidmap_value_at(map, pos), &items[i]); } git_oidmap_free(map); @@ -87,23 +85,23 @@ void test_core_oidmap__hash_collision(void) khiter_t pos; int ret; - pos = kh_get(oid, map, &items[i].oid); - cl_assert(pos == kh_end(map)); + pos = git_oidmap_lookup_index(map, &items[i].oid); + cl_assert(!git_oidmap_valid_index(map, pos)); - pos = kh_put(oid, map, &items[i].oid, &ret); + pos = git_oidmap_put(map, &items[i].oid, &ret); cl_assert(ret != 0); - kh_val(map, pos) = &items[i]; + git_oidmap_set_value_at(map, pos, &items[i]); } for (i = 0; i < NITEMS; ++i) { khiter_t pos; - pos = kh_get(oid, map, &items[i].oid); - cl_assert(pos != kh_end(map)); + pos = git_oidmap_lookup_index(map, &items[i].oid); + cl_assert(git_oidmap_valid_index(map, pos)); - cl_assert_equal_p(kh_val(map, pos), &items[i]); + cl_assert_equal_p(git_oidmap_value_at(map, pos), &items[i]); } git_oidmap_free(map); diff --git a/tests/core/path.c b/tests/core/path.c index 71c6eda58..fefe2aeac 100644 --- a/tests/core/path.c +++ b/tests/core/path.c @@ -89,8 +89,12 @@ void test_core_path__00_dirname(void) 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"); diff --git a/tests/core/posix.c b/tests/core/posix.c index 34a67bf47..172462073 100644 --- a/tests/core/posix.c +++ b/tests/core/posix.c @@ -9,8 +9,11 @@ # endif #endif +#include <locale.h> + #include "clar_libgit2.h" #include "posix.h" +#include "userdiff.h" void test_core_posix__initialize(void) { @@ -39,7 +42,7 @@ void test_core_posix__inet_pton(void) struct in_addr addr; struct in6_addr addr6; size_t i; - + struct in_addr_data { const char *p; const uint8_t n[4]; @@ -91,10 +94,7 @@ void test_core_posix__inet_pton(void) cl_assert(p_inet_pton(AF_INET, "10.foo.bar.1", &addr) == 0); /* Test unsupported address families */ - cl_git_fail(p_inet_pton(12, "52.472", NULL)); /* AF_DECnet */ - cl_assert_equal_i(EAFNOSUPPORT, errno); - - cl_git_fail(p_inet_pton(5, "315.124", NULL)); /* AF_CHAOS */ + cl_git_fail(p_inet_pton(INT_MAX-1, "52.472", &addr)); cl_assert_equal_i(EAFNOSUPPORT, errno); } @@ -146,3 +146,47 @@ void test_core_posix__utimes(void) p_unlink("foo"); } + +void test_core_posix__p_regcomp_ignores_global_locale_ctype(void) +{ + regex_t preg; + int error = 0; + + const char* oldlocale = setlocale(LC_CTYPE, NULL); + + if (!setlocale(LC_CTYPE, "UTF-8") && + !setlocale(LC_CTYPE, "c.utf8") && + !setlocale(LC_CTYPE, "en_US.UTF-8")) + cl_skip(); + + if (MB_CUR_MAX == 1) { + setlocale(LC_CTYPE, oldlocale); + cl_fail("Expected locale to be switched to multibyte"); + } + + p_regcomp(&preg, "[\xc0-\xff][\x80-\xbf]", REG_EXTENDED); + regfree(&preg); + + setlocale(LC_CTYPE, oldlocale); + + cl_must_pass(error); +} + +void test_core_posix__p_regcomp_compile_userdiff_regexps(void) +{ + size_t idx; + + for (idx = 0; idx < ARRAY_SIZE(builtin_defs); ++idx) { + git_diff_driver_definition ddef = builtin_defs[idx]; + int error = 0; + regex_t preg; + + error = p_regcomp(&preg, ddef.fns, REG_EXTENDED | ddef.flags); + regfree(&preg); + cl_must_pass(error); + + error = p_regcomp(&preg, ddef.words, REG_EXTENDED); + regfree(&preg); + cl_must_pass(error); + } +} diff --git a/tests/core/pqueue.c b/tests/core/pqueue.c index bcd4eea9f..2b90f4172 100644 --- a/tests/core/pqueue.c +++ b/tests/core/pqueue.c @@ -93,7 +93,29 @@ void test_core_pqueue__max_heap_size(void) cl_assert_equal_i(0, git_pqueue_size(&pq)); git_pqueue_free(&pq); +} + +void test_core_pqueue__max_heap_size_without_comparison(void) +{ + git_pqueue pq; + int i, vals[100] = { 0 }; + + cl_git_pass(git_pqueue_init(&pq, GIT_PQUEUE_FIXED_SIZE, 50, NULL)); + + for (i = 0; i < 100; ++i) + cl_git_pass(git_pqueue_insert(&pq, &vals[i])); + cl_assert_equal_i(50, git_pqueue_size(&pq)); + + /* As we have no comparison function, we cannot make any + * actual assumptions about which entries are part of the + * pqueue */ + for (i = 0; i < 50; ++i) + cl_assert(git_pqueue_pop(&pq)); + + cl_assert_equal_i(0, git_pqueue_size(&pq)); + + git_pqueue_free(&pq); } static int cmp_ints_like_commit_time(const void *a, const void *b) diff --git a/tests/core/sha1.c b/tests/core/sha1.c new file mode 100644 index 000000000..c5b20f6e0 --- /dev/null +++ b/tests/core/sha1.c @@ -0,0 +1,64 @@ +#include "clar_libgit2.h" +#include "hash.h" + +#define FIXTURE_DIR "sha1" + +void test_core_sha1__initialize(void) +{ + cl_fixture_sandbox(FIXTURE_DIR); +} + +void test_core_sha1__cleanup(void) +{ + cl_fixture_cleanup(FIXTURE_DIR); +} + +static int sha1_file(git_oid *oid, const char *filename) +{ + git_hash_ctx ctx; + char buf[2048]; + int fd, ret; + ssize_t read_len; + + fd = p_open(filename, O_RDONLY); + cl_assert(fd >= 0); + + cl_git_pass(git_hash_ctx_init(&ctx)); + + while ((read_len = p_read(fd, buf, 2048)) > 0) + cl_git_pass(git_hash_update(&ctx, buf, (size_t)read_len)); + + cl_assert_equal_i(0, read_len); + p_close(fd); + + ret = git_hash_final(oid, &ctx); + git_hash_ctx_cleanup(&ctx); + + return ret; +} + +void test_core_sha1__sum(void) +{ + git_oid oid, expected; + + cl_git_pass(sha1_file(&oid, FIXTURE_DIR "/hello_c")); + git_oid_fromstr(&expected, "4e72679e3ea4d04e0c642f029e61eb8056c7ed94"); + cl_assert_equal_oid(&expected, &oid); +} + +/* test that sha1 collision detection works when enabled */ +void test_core_sha1__detect_collision_attack(void) +{ + git_oid oid, expected; + +#ifdef GIT_SHA1_COLLISIONDETECT + GIT_UNUSED(expected); + cl_git_fail(sha1_file(&oid, FIXTURE_DIR "/shattered-1.pdf")); + cl_assert_equal_s("SHA1 collision attack detected", giterr_last()->message); +#else + cl_git_pass(sha1_file(&oid, FIXTURE_DIR "/shattered-1.pdf")); + git_oid_fromstr(&expected, "38762cf7f55934b34d179ae6a4c80cadccbb7f0a"); + cl_assert_equal_oid(&expected, &oid); +#endif +} + diff --git a/tests/core/strmap.c b/tests/core/strmap.c index 3b4276aea..2fa594d43 100644 --- a/tests/core/strmap.c +++ b/tests/core/strmap.c @@ -1,8 +1,6 @@ #include "clar_libgit2.h" #include "strmap.h" -GIT__USE_STRMAP - git_strmap *g_table; void test_core_strmap__initialize(void) @@ -36,7 +34,7 @@ static void insert_strings(git_strmap *table, int count) for (j = 0, over = i / 26; over > 0; j++, over = over / 26) str[j] = 'A' + (over % 26); - git_strmap_insert(table, str, str, err); + git_strmap_insert(table, str, str, &err); cl_assert(err >= 0); } diff --git a/tests/core/structinit.c b/tests/core/structinit.c index e9f7b4a74..8feba864e 100644 --- a/tests/core/structinit.c +++ b/tests/core/structinit.c @@ -1,5 +1,6 @@ #include "clar_libgit2.h" #include <git2/sys/config.h> +#include <git2/sys/filter.h> #include <git2/sys/odb_backend.h> #include <git2/sys/refdb_backend.h> #include <git2/sys/transport.h> @@ -96,6 +97,11 @@ void test_core_structinit__compare(void) git_diff_find_options, GIT_DIFF_FIND_OPTIONS_VERSION, \ GIT_DIFF_FIND_OPTIONS_INIT, git_diff_find_init_options); + /* filter */ + CHECK_MACRO_FUNC_INIT_EQUAL( \ + git_filter, GIT_FILTER_VERSION, \ + GIT_FILTER_INIT, git_filter_init); + /* merge_file_input */ CHECK_MACRO_FUNC_INIT_EQUAL( \ git_merge_file_input, GIT_MERGE_FILE_INPUT_VERSION, \ @@ -165,4 +171,13 @@ void test_core_structinit__compare(void) CHECK_MACRO_FUNC_INIT_EQUAL( \ git_submodule_update_options, GIT_SUBMODULE_UPDATE_OPTIONS_VERSION, \ GIT_SUBMODULE_UPDATE_OPTIONS_INIT, git_submodule_update_init_options); + + /* submodule update */ + CHECK_MACRO_FUNC_INIT_EQUAL( \ + git_proxy_options, GIT_PROXY_OPTIONS_VERSION, \ + GIT_PROXY_OPTIONS_INIT, git_proxy_init_options); + + CHECK_MACRO_FUNC_INIT_EQUAL( \ + git_diff_patchid_options, GIT_DIFF_PATCHID_OPTIONS_VERSION, \ + GIT_DIFF_PATCHID_OPTIONS_INIT, git_diff_patchid_init_options); } diff --git a/tests/core/vector.c b/tests/core/vector.c index c351655a7..c2e5d3f34 100644 --- a/tests/core/vector.c +++ b/tests/core/vector.c @@ -376,3 +376,34 @@ void test_core_vector__grow_and_shrink(void) git_vector_free(&x); } + +void test_core_vector__reverse(void) +{ + git_vector v = GIT_VECTOR_INIT; + size_t i; + + void *in1[] = {(void *) 0x0, (void *) 0x1, (void *) 0x2, (void *) 0x3}; + void *out1[] = {(void *) 0x3, (void *) 0x2, (void *) 0x1, (void *) 0x0}; + + void *in2[] = {(void *) 0x0, (void *) 0x1, (void *) 0x2, (void *) 0x3, (void *) 0x4}; + void *out2[] = {(void *) 0x4, (void *) 0x3, (void *) 0x2, (void *) 0x1, (void *) 0x0}; + + for (i = 0; i < 4; i++) + cl_git_pass(git_vector_insert(&v, in1[i])); + + git_vector_reverse(&v); + + for (i = 0; i < 4; i++) + cl_assert_equal_p(out1[i], git_vector_get(&v, i)); + + git_vector_clear(&v); + for (i = 0; i < 5; i++) + cl_git_pass(git_vector_insert(&v, in2[i])); + + git_vector_reverse(&v); + + for (i = 0; i < 5; i++) + cl_assert_equal_p(out2[i], git_vector_get(&v, i)); + + git_vector_free(&v); +} diff --git a/tests/diff/format_email.c b/tests/diff/format_email.c index 9f8fe3142..c3c04107b 100644 --- a/tests/diff/format_email.c +++ b/tests/diff/format_email.c @@ -113,7 +113,7 @@ void test_diff_format_email__with_message(void) "Also test if new paragraphs are included correctly.\n" \ "---\n" \ " file3.txt | 1 +\n" \ - " 1 file changed, 1 insertion(+), 0 deletions(-)\n" \ + " 1 file changed, 1 insertion(+)\n" \ "\n" \ "diff --git a/file3.txt b/file3.txt\n" \ "index 9a2d780..7309653 100644\n" \ @@ -156,7 +156,7 @@ void test_diff_format_email__multiple(void) "---\n" \ " file2.txt | 5 +++++\n" \ " file3.txt | 5 +++++\n" \ - " 2 files changed, 10 insertions(+), 0 deletions(-)\n" \ + " 2 files changed, 10 insertions(+)\n" \ " create mode 100644 file2.txt\n" \ " create mode 100644 file3.txt\n" \ "\n" \ diff --git a/tests/diff/parse.c b/tests/diff/parse.c index a06813d1b..acb6eb8a5 100644 --- a/tests/diff/parse.c +++ b/tests/diff/parse.c @@ -196,3 +196,74 @@ void test_diff_parse__get_patch_from_diff(void) cl_git_sandbox_cleanup(); } + +static int file_cb(const git_diff_delta *delta, float progress, void *payload) +{ + int *called = (int *) payload; + GIT_UNUSED(delta); + GIT_UNUSED(progress); + (*called)++; + return 0; +} + +void test_diff_parse__foreach_works_with_parsed_patch(void) +{ + const char patch[] = + "diff --git a/obj1 b/obj2\n" + "index 1234567..7654321 10644\n" + "--- a/obj1\n" + "+++ b/obj2\n" + "@@ -1 +1 @@\n" + "-abcde\n" + "+12345\n"; + int called = 0; + git_diff *diff; + + cl_git_pass(git_diff_from_buffer(&diff, patch, strlen(patch))); + cl_git_pass(git_diff_foreach(diff, file_cb, NULL, NULL, NULL, &called)); + cl_assert_equal_i(called, 1); + + git_diff_free(diff); +} + +void test_diff_parse__parsing_minimal_patch_succeeds(void) +{ + const char patch[] = + "diff --git a/obj1 b/obj2\n" + "index 1234567..7654321 10644\n" + "--- a/obj1\n" + "+++ b/obj2\n" + "@@ -1 +1 @@\n" + "-a\n" + "+\n"; + git_buf buf = GIT_BUF_INIT; + git_diff *diff; + + cl_git_pass(git_diff_from_buffer(&diff, patch, strlen(patch))); + cl_git_pass(git_diff_to_buf(&buf, diff, GIT_DIFF_FORMAT_PATCH)); + cl_assert_equal_s(patch, buf.ptr); + + git_diff_free(diff); + git_buf_free(&buf); +} + +void test_diff_parse__patch_roundtrip_succeeds(void) +{ + const char buf1[] = "a\n", buf2[] = "b\n"; + git_buf patchbuf = GIT_BUF_INIT, diffbuf = GIT_BUF_INIT; + git_patch *patch; + git_diff *diff; + + cl_git_pass(git_patch_from_buffers(&patch, buf1, strlen(buf1), "obj1", buf2, strlen(buf2), "obj2", NULL)); + cl_git_pass(git_patch_to_buf(&patchbuf, patch)); + + cl_git_pass(git_diff_from_buffer(&diff, patchbuf.ptr, patchbuf.size)); + cl_git_pass(git_diff_to_buf(&diffbuf, diff, GIT_DIFF_FORMAT_PATCH)); + + cl_assert_equal_s(patchbuf.ptr, diffbuf.ptr); + + git_patch_free(patch); + git_diff_free(diff); + git_buf_free(&patchbuf); + git_buf_free(&diffbuf); +} diff --git a/tests/diff/patchid.c b/tests/diff/patchid.c new file mode 100644 index 000000000..75a2aa814 --- /dev/null +++ b/tests/diff/patchid.c @@ -0,0 +1,60 @@ +#include "clar_libgit2.h" +#include "patch/patch_common.h" + +static void verify_patch_id(const char *diff_content, const char *expected_id) +{ + git_oid expected_oid, actual_oid; + git_diff *diff; + + cl_git_pass(git_oid_fromstr(&expected_oid, expected_id)); + cl_git_pass(git_diff_from_buffer(&diff, diff_content, strlen(diff_content))); + cl_git_pass(git_diff_patchid(&actual_oid, diff, NULL)); + + cl_assert_equal_oid(&expected_oid, &actual_oid); + + git_diff_free(diff); +} + +void test_diff_patchid__simple_commit(void) +{ + verify_patch_id(PATCH_SIMPLE_COMMIT, "06094b1948b878b7d9ff7560b4eae672a014b0ec"); +} + +void test_diff_patchid__filename_with_spaces(void) +{ + verify_patch_id(PATCH_APPEND_NO_NL, "f0ba05413beaef743b630e796153839462ee477a"); +} + +void test_diff_patchid__multiple_hunks(void) +{ + verify_patch_id(PATCH_MULTIPLE_HUNKS, "81e26c34643d17f521e57c483a6a637e18ba1f57"); +} + +void test_diff_patchid__multiple_files(void) +{ + verify_patch_id(PATCH_MULTIPLE_FILES, "192d1f49d23f2004517963aecd3f8a6c467f50ff"); +} + +void test_diff_patchid__same_diff_with_differing_whitespace_has_same_id(void) +{ + const char *tabs = + "diff --git a/file.txt b/file.txt\n" + "index 8fecc09..1d43a92 100644\n" + "--- a/file.txt\n" + "+++ b/file.txt\n" + "@@ -1 +1 @@\n" + "-old text\n" + "+ new text\n"; + const char *spaces = + "diff --git a/file.txt b/file.txt\n" + "index 8fecc09..1d43a92 100644\n" + "--- a/file.txt\n" + "+++ b/file.txt\n" + "@@ -1 +1 @@\n" + "-old text\n" + "+ new text\n"; + const char *id = "11efdd13c30f7a1056eac2ae2fb952da475e2c23"; + + verify_patch_id(tabs, id); + verify_patch_id(spaces, id); +} diff --git a/tests/diff/stats.c b/tests/diff/stats.c index 8f146e2a4..3171a4486 100644 --- a/tests/diff/stats.c +++ b/tests/diff/stats.c @@ -114,6 +114,42 @@ void test_diff_stats__shortstat(void) git_buf_free(&buf); } +void test_diff_stats__shortstat_noinsertions(void) +{ + git_buf buf = GIT_BUF_INIT; + const char *stat = + " 1 file changed, 2 deletions(-)\n"; + + diff_stats_from_commit_oid( + &_stats, "06b7b69a62cbd1e53c6c4e0c3f16473dcfdb4af6", false); + + cl_assert_equal_sz(1, git_diff_stats_files_changed(_stats)); + cl_assert_equal_sz(0, git_diff_stats_insertions(_stats)); + cl_assert_equal_sz(2, git_diff_stats_deletions(_stats)); + + cl_git_pass(git_diff_stats_to_buf(&buf, _stats, GIT_DIFF_STATS_SHORT, 0)); + cl_assert_equal_s(stat, git_buf_cstr(&buf)); + git_buf_free(&buf); +} + +void test_diff_stats__shortstat_nodeletions(void) +{ + git_buf buf = GIT_BUF_INIT; + const char *stat = + " 1 file changed, 3 insertions(+)\n"; + + diff_stats_from_commit_oid( + &_stats, "5219b9784f9a92d7bd7cb567a6d6a21bfb86697e", false); + + cl_assert_equal_sz(1, git_diff_stats_files_changed(_stats)); + cl_assert_equal_sz(3, git_diff_stats_insertions(_stats)); + cl_assert_equal_sz(0, git_diff_stats_deletions(_stats)); + + cl_git_pass(git_diff_stats_to_buf(&buf, _stats, GIT_DIFF_STATS_SHORT, 0)); + cl_assert_equal_s(stat, git_buf_cstr(&buf)); + git_buf_free(&buf); +} + void test_diff_stats__rename(void) { git_buf buf = GIT_BUF_INIT; diff --git a/tests/fetchhead/nonetwork.c b/tests/fetchhead/nonetwork.c index 3b750af5e..ea4b70e4a 100644 --- a/tests/fetchhead/nonetwork.c +++ b/tests/fetchhead/nonetwork.c @@ -293,7 +293,7 @@ void test_fetchhead_nonetwork__invalid_for_merge(void) cl_git_rewritefile("./test1/.git/FETCH_HEAD", "49322bb17d3acc9146f98c97d078513228bbf3c0\tinvalid-merge\t\n"); cl_git_fail(git_repository_fetchhead_foreach(g_repo, read_noop, NULL)); - cl_assert(git__prefixcmp(giterr_last()->message, "Invalid for-merge") == 0); + cl_assert(git__prefixcmp(giterr_last()->message, "invalid for-merge") == 0); } void test_fetchhead_nonetwork__invalid_description(void) @@ -304,7 +304,7 @@ void test_fetchhead_nonetwork__invalid_description(void) cl_git_rewritefile("./test1/.git/FETCH_HEAD", "49322bb17d3acc9146f98c97d078513228bbf3c0\tnot-for-merge\n"); cl_git_fail(git_repository_fetchhead_foreach(g_repo, read_noop, NULL)); - cl_assert(git__prefixcmp(giterr_last()->message, "Invalid description") == 0); + cl_assert(git__prefixcmp(giterr_last()->message, "invalid description") == 0); } static int assert_master_for_merge(const char *ref, const char *url, const git_oid *id, unsigned int is_merge, void *data) diff --git a/tests/filter/custom.c b/tests/filter/custom.c index fd1cd271c..799beef62 100644 --- a/tests/filter/custom.c +++ b/tests/filter/custom.c @@ -55,6 +55,7 @@ void test_filter_custom__initialize(void) "hero* bitflip reverse\n" "herofile text\n" "heroflip -reverse binary\n" + "villain erroneous\n" "*.bin binary\n"); } @@ -82,6 +83,11 @@ static void register_custom_filters(void) create_reverse_filter("+prereverse"), GIT_FILTER_DRIVER_PRIORITY)); + cl_git_pass(git_filter_register( + "erroneous", + create_erroneous_filter("+erroneous"), + GIT_FILTER_DRIVER_PRIORITY)); + filters_registered = 1; } } @@ -235,3 +241,18 @@ void test_filter_custom__filter_registry_failure_cases(void) cl_git_fail(git_filter_unregister(GIT_FILTER_IDENT)); cl_assert_equal_i(GIT_ENOTFOUND, git_filter_unregister("not-a-filter")); } + +void test_filter_custom__erroneous_filter_fails(void) +{ + git_filter_list *filters; + git_buf out = GIT_BUF_INIT; + git_buf in = GIT_BUF_INIT_CONST(workdir_data, strlen(workdir_data)); + + cl_git_pass(git_filter_list_load( + &filters, g_repo, NULL, "villain", GIT_FILTER_TO_WORKTREE, 0)); + + cl_git_fail(git_filter_list_apply_to_data(&out, filters, &in)); + + git_filter_list_free(filters); + git_buf_free(&out); +} diff --git a/tests/filter/custom_helpers.c b/tests/filter/custom_helpers.c index 2c80212be..d7f2afe7a 100644 --- a/tests/filter/custom_helpers.c +++ b/tests/filter/custom_helpers.c @@ -106,3 +106,36 @@ git_filter *create_reverse_filter(const char *attrs) return filter; } + +int erroneous_filter_stream( + git_writestream **out, + git_filter *self, + void **payload, + const git_filter_source *src, + git_writestream *next) +{ + GIT_UNUSED(out); + GIT_UNUSED(self); + GIT_UNUSED(payload); + GIT_UNUSED(src); + GIT_UNUSED(next); + return -1; +} + +static void erroneous_filter_free(git_filter *f) +{ + git__free(f); +} + +git_filter *create_erroneous_filter(const char *attrs) +{ + git_filter *filter = git__calloc(1, sizeof(git_filter)); + cl_assert(filter); + + filter->version = GIT_FILTER_VERSION; + filter->attributes = attrs; + filter->stream = erroneous_filter_stream; + filter->shutdown = erroneous_filter_free; + + return filter; +} diff --git a/tests/filter/custom_helpers.h b/tests/filter/custom_helpers.h index 13cfb23ae..537a51da2 100644 --- a/tests/filter/custom_helpers.h +++ b/tests/filter/custom_helpers.h @@ -2,6 +2,7 @@ extern git_filter *create_bitflip_filter(void); extern git_filter *create_reverse_filter(const char *attr); +extern git_filter *create_erroneous_filter(const char *attr); extern int bitflip_filter_apply( git_filter *self, diff --git a/tests/generate.py b/tests/generate.py index 587efb519..0a94d4952 100644 --- a/tests/generate.py +++ b/tests/generate.py @@ -8,7 +8,7 @@ from __future__ import with_statement from string import Template -import re, fnmatch, os, codecs, pickle +import re, fnmatch, os, sys, codecs, pickle class Module(object): class Template(object): @@ -128,8 +128,9 @@ class Module(object): class TestSuite(object): - def __init__(self, path): + def __init__(self, path, output): self.path = path + self.output = output def should_generate(self, path): if not os.path.isfile(path): @@ -157,7 +158,7 @@ class TestSuite(object): return modules def load_cache(self): - path = os.path.join(self.path, '.clarcache') + path = os.path.join(self.output, '.clarcache') cache = {} try: @@ -170,7 +171,7 @@ class TestSuite(object): return cache def save_cache(self): - path = os.path.join(self.path, '.clarcache') + path = os.path.join(self.output, '.clarcache') with open(path, 'wb') as cache: pickle.dump(self.modules, cache) @@ -200,22 +201,24 @@ class TestSuite(object): return sum(len(module.callbacks) for module in self.modules.values()) def write(self): - output = os.path.join(self.path, 'clar.suite') + output = os.path.join(self.output, 'clar.suite') if not self.should_generate(output): return False with open(output, 'w') as data: - for module in self.modules.values(): + modules = sorted(self.modules.values(), key=lambda module: module.name) + + for module in modules: t = Module.DeclarationTemplate(module) data.write(t.render()) - for module in self.modules.values(): + for module in modules: t = Module.CallbacksTemplate(module) data.write(t.render()) suites = "static struct clar_suite _clar_suites[] = {" + ','.join( - Module.InfoTemplate(module).render() for module in sorted(self.modules.values(), key=lambda module: module.name) + Module.InfoTemplate(module).render() for module in modules ) + "\n};\n" data.write(suites) @@ -232,13 +235,18 @@ if __name__ == '__main__': parser = OptionParser() parser.add_option('-f', '--force', action="store_true", dest='force', default=False) parser.add_option('-x', '--exclude', dest='excluded', action='append', default=[]) + parser.add_option('-o', '--output', dest='output') options, args = parser.parse_args() - - for path in args or ['.']: - suite = TestSuite(path) - suite.load(options.force) - suite.disable(options.excluded) - if suite.write(): - print("Written `clar.suite` (%d tests in %d suites)" % (suite.callback_count(), suite.suite_count())) + if len(args) > 1: + print("More than one path given") + sys.exit(1) + + path = args.pop() if args else '.' + output = options.output or path + suite = TestSuite(path, output) + suite.load(options.force) + suite.disable(options.excluded) + if suite.write(): + print("Written `clar.suite` (%d tests in %d suites)" % (suite.callback_count(), suite.suite_count())) diff --git a/tests/index/tests.c b/tests/index/tests.c index 1498196b2..ea8335b48 100644 --- a/tests/index/tests.c +++ b/tests/index/tests.c @@ -856,11 +856,14 @@ void test_index_tests__change_icase_on_instance(void) void test_index_tests__can_lock_index(void) { + git_repository *repo; git_index *index; git_indexwriter one = GIT_INDEXWRITER_INIT, two = GIT_INDEXWRITER_INIT; - cl_git_pass(git_index_open(&index, TEST_INDEX_PATH)); + repo = cl_git_sandbox_init("testrepo.git"); + + cl_git_pass(git_repository_index(&index, repo)); cl_git_pass(git_indexwriter_init(&one, index)); cl_git_fail_with(GIT_ELOCKED, git_indexwriter_init(&two, index)); @@ -873,4 +876,5 @@ void test_index_tests__can_lock_index(void) git_indexwriter_cleanup(&one); git_indexwriter_cleanup(&two); git_index_free(index); + cl_git_sandbox_cleanup(); } diff --git a/tests/index/version.c b/tests/index/version.c index 3fd240d3c..7ada302b5 100644 --- a/tests/index/version.c +++ b/tests/index/version.c @@ -3,39 +3,135 @@ static git_repository *g_repo = NULL; -void test_index_version__can_write_v4(void) +void test_index_version__cleanup(void) +{ + cl_git_sandbox_cleanup(); + g_repo = NULL; +} + +void test_index_version__can_read_v4(void) { + const char *paths[] = { + "file.tx", "file.txt", "file.txz", "foo", "zzz", + }; git_index *index; - const git_index_entry *entry; + size_t i; + + g_repo = cl_git_sandbox_init("indexv4"); - g_repo = cl_git_sandbox_init("filemodes"); cl_git_pass(git_repository_index(&index, g_repo)); + cl_assert_equal_sz(git_index_entrycount(index), 5); - cl_assert(index->on_disk); - cl_assert(git_index_version(index) == 2); + for (i = 0; i < ARRAY_SIZE(paths); i++) { + const git_index_entry *entry = + git_index_get_bypath(index, paths[i], GIT_INDEX_STAGE_NORMAL); - cl_assert(git_index_entrycount(index) == 6); + cl_assert(entry != NULL); + } + git_index_free(index); +} + +void test_index_version__can_write_v4(void) +{ + const char *paths[] = { + "foo", + "foox", + "foobar", + "foobal", + "x", + "xz", + "xyzzyx" + }; + git_index_entry entry; + git_index *index; + size_t i; + + g_repo = cl_git_sandbox_init("empty_standard_repo"); + cl_git_pass(git_repository_index(&index, g_repo)); cl_git_pass(git_index_set_version(index, 4)); + for (i = 0; i < ARRAY_SIZE(paths); i++) { + memset(&entry, 0, sizeof(entry)); + entry.path = paths[i]; + entry.mode = GIT_FILEMODE_BLOB; + cl_git_pass(git_index_add_frombuffer(index, &entry, paths[i], + strlen(paths[i]) + 1)); + } + cl_assert_equal_sz(git_index_entrycount(index), ARRAY_SIZE(paths)); + cl_git_pass(git_index_write(index)); git_index_free(index); cl_git_pass(git_repository_index(&index, g_repo)); cl_assert(git_index_version(index) == 4); - entry = git_index_get_bypath(index, "exec_off", 0); - cl_assert(entry); - entry = git_index_get_bypath(index, "exec_off2on_staged", 0); - cl_assert(entry); - entry = git_index_get_bypath(index, "exec_on", 0); - cl_assert(entry); + for (i = 0; i < ARRAY_SIZE(paths); i++) { + const git_index_entry *e; + + cl_assert(e = git_index_get_bypath(index, paths[i], 0)); + cl_assert_equal_s(paths[i], e->path); + } git_index_free(index); } -void test_index_version__cleanup(void) +void test_index_version__v4_uses_path_compression(void) { - cl_git_sandbox_cleanup(); - g_repo = NULL; + git_index_entry entry; + git_index *index; + char path[250], buf[1]; + struct stat st; + char i, j; + + memset(path, 'a', sizeof(path)); + memset(buf, 'a', sizeof(buf)); + + memset(&entry, 0, sizeof(entry)); + entry.path = path; + entry.mode = GIT_FILEMODE_BLOB; + + g_repo = cl_git_sandbox_init("indexv4"); + cl_git_pass(git_repository_index(&index, g_repo)); + + /* write 676 paths of 250 bytes length */ + for (i = 'a'; i <= 'z'; i++) { + for (j = 'a'; j < 'z'; j++) { + path[ARRAY_SIZE(path) - 3] = i; + path[ARRAY_SIZE(path) - 2] = j; + path[ARRAY_SIZE(path) - 1] = '\0'; + cl_git_pass(git_index_add_frombuffer(index, &entry, buf, sizeof(buf))); + } + } + + cl_git_pass(git_index_write(index)); + cl_git_pass(p_stat(git_index_path(index), &st)); + + /* + * Without path compression, the written paths would at + * least take + * + * (entries * pathlen) = len + * (676 * 250) = 169000 + * + * bytes. As index v4 uses suffix-compression and our + * written paths only differ in the last two entries, + * this number will be much smaller, e.g. + * + * (1 * pathlen) + (675 * 2) = len + * 676 + 1350 = 2026 + * + * bytes. + * + * Note that the above calculations do not include + * additional metadata of the index, e.g. OIDs or + * index extensions. Including those we get an index + * of approx. 200kB without compression and 40kB with + * compression. As this is a lot smaller than without + * compression, we can verify that path compression is + * used. + */ + cl_assert_(st.st_size < 75000, "path compression not enabled"); + + git_index_free(index); } diff --git a/tests/iterator/workdir.c b/tests/iterator/workdir.c index 28fcc0d23..f33fd98f1 100644 --- a/tests/iterator/workdir.c +++ b/tests/iterator/workdir.c @@ -613,9 +613,11 @@ void test_iterator_workdir__filesystem2(void) "heads/ident", "heads/long-file-name", "heads/master", + "heads/merge-conflict", "heads/packed-test", "heads/subtrees", "heads/test", + "heads/testrepo-worktree", "tags/e90810b", "tags/foo/bar", "tags/foo/foo/bar", @@ -628,7 +630,7 @@ void test_iterator_workdir__filesystem2(void) cl_git_pass(git_iterator_for_filesystem( &i, "testrepo/.git/refs", NULL)); - expect_iterator_items(i, 13, expect_base, 13, expect_base); + expect_iterator_items(i, 15, expect_base, 15, expect_base); git_iterator_free(i); } diff --git a/tests/merge/trees/renames.c b/tests/merge/trees/renames.c index d7721c894..853bf2fa0 100644 --- a/tests/merge/trees/renames.c +++ b/tests/merge/trees/renames.c @@ -242,6 +242,8 @@ void test_merge_trees_renames__no_rename_index(void) { 0100644, "b69fe837e4cecfd4c9a40cdca7c138468687df07", 3, "7-both-renamed.txt" }, }; + opts.flags &= ~GIT_MERGE_FIND_RENAMES; + cl_git_pass(merge_trees_from_branches(&index, repo, BRANCH_RENAME_OURS, BRANCH_RENAME_THEIRS, &opts)); @@ -250,3 +252,25 @@ void test_merge_trees_renames__no_rename_index(void) git_index_free(index); } + +void test_merge_trees_renames__submodules(void) +{ + git_index *index; + git_merge_options *opts = NULL; + + struct merge_index_entry merge_index_entries[] = { + { 0100644, "cd3e8d4aa06bdc781f264171030bc28f2b370fee", 0, ".gitmodules" }, + { 0100644, "4dd1ef7569b18d92d93c0a35bb6b93049137b355", 1, "file.txt" }, + { 0100644, "a2d8d1824c68541cca94ffb90f79291eba495921", 2, "file.txt" }, + { 0100644, "63ec604d491161ddafdae4179843c26d54bd999a", 3, "file.txt" }, + { 0160000, "0000000000000000000000000000000000000001", 1, "submodule1" }, + { 0160000, "0000000000000000000000000000000000000002", 3, "submodule1" }, + { 0160000, "0000000000000000000000000000000000000003", 0, "submodule2" }, + }; + + cl_git_pass(merge_trees_from_branches(&index, repo, + "submodule_rename1", "submodule_rename2", + opts)); + cl_assert(merge_test_index(index, merge_index_entries, 7)); + git_index_free(index); +} diff --git a/tests/network/remote/local.c b/tests/network/remote/local.c index 6194802af..76872e51f 100644 --- a/tests/network/remote/local.c +++ b/tests/network/remote/local.c @@ -2,6 +2,7 @@ #include "buffer.h" #include "path.h" #include "posix.h" +#include "git2/sys/repository.h" static git_repository *repo; static git_buf file_path_buf = GIT_BUF_INIT; @@ -465,3 +466,19 @@ void test_network_remote_local__push_delete(void) cl_fixture_cleanup("target.git"); cl_git_sandbox_cleanup(); } + +void test_network_remote_local__anonymous_remote_inmemory_repo(void) +{ + git_repository *inmemory; + git_remote *remote; + + git_buf_sets(&file_path_buf, cl_git_path_url(cl_fixture("testrepo.git"))); + + cl_git_pass(git_repository_new(&inmemory)); + cl_git_pass(git_remote_create_anonymous(&remote, inmemory, git_buf_cstr(&file_path_buf))); + cl_git_pass(git_remote_connect(remote, GIT_DIRECTION_FETCH, NULL, NULL, NULL)); + cl_assert(git_remote_connected(remote)); + git_remote_disconnect(remote); + git_remote_free(remote); + git_repository_free(inmemory); +} diff --git a/tests/object/lookup.c b/tests/object/lookup.c index cfa6d4678..544f32bc4 100644 --- a/tests/object/lookup.c +++ b/tests/object/lookup.c @@ -6,13 +6,12 @@ static git_repository *g_repo; void test_object_lookup__initialize(void) { - cl_git_pass(git_repository_open(&g_repo, cl_fixture("testrepo.git"))); + g_repo = cl_git_sandbox_init("testrepo.git"); } void test_object_lookup__cleanup(void) { - git_repository_free(g_repo); - g_repo = NULL; + cl_git_sandbox_cleanup(); } void test_object_lookup__lookup_wrong_type_returns_enotfound(void) @@ -63,3 +62,61 @@ void test_object_lookup__lookup_wrong_type_eventually_returns_enotfound(void) GIT_ENOTFOUND, git_object_lookup(&object, g_repo, &oid, GIT_OBJ_TAG)); } +void test_object_lookup__lookup_corrupt_object_returns_error(void) +{ + const char *commit = "8e73b769e97678d684b809b163bebdae2911720f", + *file = "objects/8e/73b769e97678d684b809b163bebdae2911720f"; + git_buf path = GIT_BUF_INIT, contents = GIT_BUF_INIT; + git_oid oid; + git_object *object; + size_t i; + + cl_git_pass(git_oid_fromstr(&oid, commit)); + cl_git_pass(git_buf_joinpath(&path, git_repository_path(g_repo), file)); + cl_git_pass(git_futils_readbuffer(&contents, path.ptr)); + + /* Corrupt and try to read the object */ + for (i = 0; i < contents.size; i++) { + contents.ptr[i] ^= 0x1; + cl_git_pass(git_futils_writebuffer(&contents, path.ptr, O_RDWR, 0644)); + cl_git_fail(git_object_lookup(&object, g_repo, &oid, GIT_OBJ_COMMIT)); + contents.ptr[i] ^= 0x1; + } + + /* Restore original content and assert we can read the object */ + cl_git_pass(git_futils_writebuffer(&contents, path.ptr, O_RDWR, 0644)); + cl_git_pass(git_object_lookup(&object, g_repo, &oid, GIT_OBJ_COMMIT)); + + git_object_free(object); + git_buf_free(&path); + git_buf_free(&contents); +} + +void test_object_lookup__lookup_object_with_wrong_hash_returns_error(void) +{ + const char *oldloose = "objects/8e/73b769e97678d684b809b163bebdae2911720f", + *newloose = "objects/8e/73b769e97678d684b809b163bebdae2911720e", + *commit = "8e73b769e97678d684b809b163bebdae2911720e"; + git_buf oldpath = GIT_BUF_INIT, newpath = GIT_BUF_INIT; + git_object *object; + git_oid oid; + + cl_git_pass(git_oid_fromstr(&oid, commit)); + + /* Copy object to another location with wrong hash */ + cl_git_pass(git_buf_joinpath(&oldpath, git_repository_path(g_repo), oldloose)); + cl_git_pass(git_buf_joinpath(&newpath, git_repository_path(g_repo), newloose)); + cl_git_pass(git_futils_cp(oldpath.ptr, newpath.ptr, 0644)); + + /* Verify that lookup fails due to a hashsum mismatch */ + cl_git_fail_with(GIT_EMISMATCH, git_object_lookup(&object, g_repo, &oid, GIT_OBJ_COMMIT)); + + /* Disable verification and try again */ + cl_git_pass(git_libgit2_opts(GIT_OPT_ENABLE_STRICT_HASH_VERIFICATION, 0)); + cl_git_pass(git_object_lookup(&object, g_repo, &oid, GIT_OBJ_COMMIT)); + cl_git_pass(git_libgit2_opts(GIT_OPT_ENABLE_STRICT_HASH_VERIFICATION, 1)); + + git_object_free(object); + git_buf_free(&oldpath); + git_buf_free(&newpath); +} diff --git a/tests/object/tree/update.c b/tests/object/tree/update.c index 54c4335f5..b76e8612a 100644 --- a/tests/object/tree/update.c +++ b/tests/object/tree/update.c @@ -196,6 +196,63 @@ void test_object_tree_update__add_blobs(void) git_tree_free(base_tree); } +void test_object_tree_update__add_blobs_unsorted(void) +{ + git_oid tree_index_id, tree_updater_id, base_id; + git_tree *base_tree; + git_index *idx; + git_index_entry entry = { {0} }; + int i; + const char *paths[] = { + "some/deep/path", + "a/path/elsewhere", + "some/other/path", + }; + + git_tree_update updates[] = { + { GIT_TREE_UPDATE_UPSERT, {{0}}, GIT_FILEMODE_BLOB, paths[0]}, + { GIT_TREE_UPDATE_UPSERT, {{0}}, GIT_FILEMODE_BLOB, paths[1]}, + { GIT_TREE_UPDATE_UPSERT, {{0}}, GIT_FILEMODE_BLOB, paths[2]}, + }; + + cl_git_pass(git_oid_fromstr(&base_id, "c4dc1555e4d4fa0e0c9c3fc46734c7c35b3ce90b")); + + entry.mode = GIT_FILEMODE_BLOB; + cl_git_pass(git_oid_fromstr(&entry.id, "fa49b077972391ad58037050f2a75f74e3671e92")); + + for (i = 0; i < 3; i++) { + cl_git_pass(git_oid_fromstr(&updates[i].id, "fa49b077972391ad58037050f2a75f74e3671e92")); + } + + for (i = 0; i < 2; i++) { + int j; + + /* Create it with an index */ + cl_git_pass(git_index_new(&idx)); + + base_tree = NULL; + if (i == 1) { + cl_git_pass(git_tree_lookup(&base_tree, g_repo, &base_id)); + cl_git_pass(git_index_read_tree(idx, base_tree)); + } + + for (j = 0; j < 3; j++) { + entry.path = paths[j]; + cl_git_pass(git_index_add(idx, &entry)); + } + + cl_git_pass(git_index_write_tree_to(&tree_index_id, idx, g_repo)); + git_index_free(idx); + + /* Perform the same operations via the tree updater */ + cl_git_pass(git_tree_create_updated(&tree_updater_id, g_repo, base_tree, 3, updates)); + + cl_assert_equal_oid(&tree_index_id, &tree_updater_id); + } + + git_tree_free(base_tree); +} + void test_object_tree_update__add_conflict(void) { int i; diff --git a/tests/odb/backend/backend_helpers.c b/tests/odb/backend/backend_helpers.c new file mode 100644 index 000000000..37a8fd200 --- /dev/null +++ b/tests/odb/backend/backend_helpers.c @@ -0,0 +1,159 @@ +#include "clar_libgit2.h" +#include "git2/sys/odb_backend.h" +#include "backend_helpers.h" + +static int search_object(const fake_object **out, fake_backend *fake, const git_oid *oid, size_t len) +{ + const fake_object *obj = fake->objects, *found = NULL; + + while (obj && obj->oid) { + git_oid current_oid; + + git_oid_fromstr(¤t_oid, obj->oid); + + if (git_oid_ncmp(¤t_oid, oid, len) == 0) { + if (found) + return GIT_EAMBIGUOUS; + found = obj; + } + + obj++; + } + + if (found && out) + *out = found; + + return found ? GIT_OK : GIT_ENOTFOUND; +} + +static int fake_backend__exists(git_odb_backend *backend, const git_oid *oid) +{ + fake_backend *fake; + + fake = (fake_backend *)backend; + + fake->exists_calls++; + + return search_object(NULL, fake, oid, GIT_OID_HEXSZ) == GIT_OK; +} + +static int fake_backend__exists_prefix( + git_oid *out, git_odb_backend *backend, const git_oid *oid, size_t len) +{ + const fake_object *obj; + fake_backend *fake; + int error; + + fake = (fake_backend *)backend; + + fake->exists_prefix_calls++; + + if ((error = search_object(&obj, fake, oid, len)) < 0) + return error; + + if (out) + git_oid_fromstr(out, obj->oid); + + return 0; +} + +static int fake_backend__read( + void **buffer_p, size_t *len_p, git_otype *type_p, + git_odb_backend *backend, const git_oid *oid) +{ + const fake_object *obj; + fake_backend *fake; + int error; + + fake = (fake_backend *)backend; + + fake->read_calls++; + + if ((error = search_object(&obj, fake, oid, GIT_OID_HEXSZ)) < 0) + return error; + + *len_p = strlen(obj->content); + *buffer_p = git__strdup(obj->content); + *type_p = GIT_OBJ_BLOB; + + return 0; +} + +static int fake_backend__read_header( + size_t *len_p, git_otype *type_p, + git_odb_backend *backend, const git_oid *oid) +{ + const fake_object *obj; + fake_backend *fake; + int error; + + fake = (fake_backend *)backend; + + fake->read_header_calls++; + + if ((error = search_object(&obj, fake, oid, GIT_OID_HEXSZ)) < 0) + return error; + + *len_p = strlen(obj->content); + *type_p = GIT_OBJ_BLOB; + + return 0; +} + +static int fake_backend__read_prefix( + git_oid *out_oid, void **buffer_p, size_t *len_p, git_otype *type_p, + git_odb_backend *backend, const git_oid *short_oid, size_t len) +{ + const fake_object *obj; + fake_backend *fake; + int error; + + fake = (fake_backend *)backend; + + fake->read_prefix_calls++; + + if ((error = search_object(&obj, fake, short_oid, len)) < 0) + return error; + + git_oid_fromstr(out_oid, obj->oid); + *len_p = strlen(obj->content); + *buffer_p = git__strdup(obj->content); + *type_p = GIT_OBJ_BLOB; + + return 0; +} + +static void fake_backend__free(git_odb_backend *_backend) +{ + fake_backend *backend; + + backend = (fake_backend *)_backend; + + git__free(backend); +} + +int build_fake_backend( + git_odb_backend **out, + const fake_object *objects) +{ + fake_backend *backend; + + backend = git__calloc(1, sizeof(fake_backend)); + GITERR_CHECK_ALLOC(backend); + + backend->parent.version = GIT_ODB_BACKEND_VERSION; + + backend->parent.refresh = NULL; + backend->objects = objects; + + backend->parent.read = fake_backend__read; + backend->parent.read_prefix = fake_backend__read_prefix; + backend->parent.read_header = fake_backend__read_header; + backend->parent.exists = fake_backend__exists; + backend->parent.exists_prefix = fake_backend__exists_prefix; + backend->parent.free = &fake_backend__free; + + *out = (git_odb_backend *)backend; + + return 0; +} diff --git a/tests/odb/backend/backend_helpers.h b/tests/odb/backend/backend_helpers.h new file mode 100644 index 000000000..5c393c0a5 --- /dev/null +++ b/tests/odb/backend/backend_helpers.h @@ -0,0 +1,22 @@ +#include "git2/sys/odb_backend.h" + +typedef struct { + const char *oid; + const char *content; +} fake_object; + +typedef struct { + git_odb_backend parent; + + int exists_calls; + int exists_prefix_calls; + int read_calls; + int read_header_calls; + int read_prefix_calls; + + const fake_object *objects; +} fake_backend; + +int build_fake_backend( + git_odb_backend **out, + const fake_object *objects); diff --git a/tests/odb/backend/multiple.c b/tests/odb/backend/multiple.c new file mode 100644 index 000000000..1c6068df3 --- /dev/null +++ b/tests/odb/backend/multiple.c @@ -0,0 +1,121 @@ +#include "clar_libgit2.h" +#include "repository.h" +#include "backend_helpers.h" + +#define EXISTING_HASH "e69de29bb2d1d6434b8b29ae775ad8c2e48c5391" + +static git_repository *_repo; +static git_odb_object *_obj; +static fake_backend *_fake_empty; +static fake_backend *_fake_filled; + +static git_oid _existing_oid; + +static const fake_object _objects_filled[] = { + { EXISTING_HASH, "" }, + { NULL, NULL } +}; + +static const fake_object _objects_empty[] = { + { NULL, NULL } +}; + +void test_odb_backend_multiple__initialize(void) +{ + git_odb_backend *backend; + + git_oid_fromstr(&_existing_oid, EXISTING_HASH); + + _obj = NULL; + _repo = cl_git_sandbox_init("testrepo.git"); + + cl_git_pass(build_fake_backend(&backend, _objects_filled)); + _fake_filled = (fake_backend *)backend; + + cl_git_pass(build_fake_backend(&backend, _objects_empty)); + _fake_empty = (fake_backend *)backend; +} + +void test_odb_backend_multiple__cleanup(void) +{ + git_odb_object_free(_obj); + cl_git_sandbox_cleanup(); +} + +void test_odb_backend_multiple__read_with_empty_first_succeeds(void) +{ + git_odb *odb; + + cl_git_pass(git_repository_odb__weakptr(&odb, _repo)); + cl_git_pass(git_odb_add_backend(odb, (git_odb_backend *)_fake_filled, 10)); + cl_git_pass(git_odb_add_backend(odb, (git_odb_backend *)_fake_empty, 50)); + + cl_git_pass(git_odb_read(&_obj, odb, &_existing_oid)); + + cl_assert_equal_i(1, _fake_filled->read_calls); + cl_assert_equal_i(1, _fake_empty->read_calls); +} + +void test_odb_backend_multiple__read_with_first_matching_stops(void) +{ + git_odb *odb; + + cl_git_pass(git_repository_odb__weakptr(&odb, _repo)); + cl_git_pass(git_odb_add_backend(odb, (git_odb_backend *)_fake_empty, 10)); + cl_git_pass(git_odb_add_backend(odb, (git_odb_backend *)_fake_filled, 50)); + + cl_git_pass(git_odb_read(&_obj, odb, &_existing_oid)); + + cl_assert_equal_i(1, _fake_filled->read_calls); + cl_assert_equal_i(0, _fake_empty->read_calls); +} + +void test_odb_backend_multiple__read_prefix_with_first_empty_succeeds(void) +{ + git_odb *odb; + + cl_git_pass(git_repository_odb__weakptr(&odb, _repo)); + cl_git_pass(git_odb_add_backend(odb, (git_odb_backend *)_fake_filled, 10)); + cl_git_pass(git_odb_add_backend(odb, (git_odb_backend *)_fake_empty, 50)); + + cl_git_pass(git_odb_read_prefix(&_obj, odb, &_existing_oid, 7)); + + cl_assert_equal_i(1, _fake_filled->read_prefix_calls); + cl_assert_equal_i(1, _fake_empty->read_prefix_calls); +} + +void test_odb_backend_multiple__read_prefix_with_first_matching_reads_both(void) +{ + git_odb *odb; + + cl_git_pass(git_repository_odb__weakptr(&odb, _repo)); + cl_git_pass(git_odb_add_backend(odb, (git_odb_backend *)_fake_empty, -10)); + cl_git_pass(git_odb_add_backend(odb, (git_odb_backend *)_fake_filled, 50)); + + cl_git_pass(git_odb_read_prefix(&_obj, odb, &_existing_oid, 7)); + + cl_assert_equal_i(1, _fake_filled->read_prefix_calls); + cl_assert_equal_i(1, _fake_empty->read_prefix_calls); +} + +void test_odb_backend_multiple__read_prefix_with_first_matching_succeeds_without_hash_verification(void) +{ + git_odb *odb; + + git_libgit2_opts(GIT_OPT_ENABLE_STRICT_HASH_VERIFICATION, 0); + + cl_git_pass(git_repository_odb__weakptr(&odb, _repo)); + cl_git_pass(git_odb_add_backend(odb, (git_odb_backend *)_fake_empty, -10)); + cl_git_pass(git_odb_add_backend(odb, (git_odb_backend *)_fake_filled, 50)); + + cl_git_pass(git_odb_read_prefix(&_obj, odb, &_existing_oid, 7)); + + /* + * Both backends should be checked as we have to check + * for collisions + */ + cl_assert_equal_i(1, _fake_filled->read_prefix_calls); + cl_assert_equal_i(1, _fake_empty->read_prefix_calls); + + git_libgit2_opts(GIT_OPT_ENABLE_STRICT_HASH_VERIFICATION, 1); +} diff --git a/tests/odb/backend/nobackend.c b/tests/odb/backend/nobackend.c index 783641e8f..3c4f344b1 100644 --- a/tests/odb/backend/nobackend.c +++ b/tests/odb/backend/nobackend.c @@ -40,7 +40,7 @@ void test_odb_backend_nobackend__write_fails_gracefully(void) cl_git_fail(git_odb_write(&id, odb, "Hello world!\n", 13, GIT_OBJ_BLOB)); err = giterr_last(); - cl_assert_equal_s(err->message, "Cannot write object - unsupported in the loaded odb backends"); + cl_assert_equal_s(err->message, "cannot write object - unsupported in the loaded odb backends"); git_odb_free(odb); } diff --git a/tests/odb/backend/nonrefreshing.c b/tests/odb/backend/nonrefreshing.c index b43529479..6abc0c6d2 100644 --- a/tests/odb/backend/nonrefreshing.c +++ b/tests/odb/backend/nonrefreshing.c @@ -1,150 +1,41 @@ #include "clar_libgit2.h" -#include "git2/sys/odb_backend.h" #include "repository.h" - -typedef struct fake_backend { - git_odb_backend parent; - - git_error_code error_code; - - int exists_calls; - int read_calls; - int read_header_calls; - int read_prefix_calls; -} fake_backend; +#include "backend_helpers.h" static git_repository *_repo; static fake_backend *_fake; -static git_oid _oid; - -static int fake_backend__exists(git_odb_backend *backend, const git_oid *oid) -{ - fake_backend *fake; - - GIT_UNUSED(oid); - - fake = (fake_backend *)backend; - - fake->exists_calls++; - - return (fake->error_code == GIT_OK); -} - -static int fake_backend__read( - void **buffer_p, size_t *len_p, git_otype *type_p, - git_odb_backend *backend, const git_oid *oid) -{ - fake_backend *fake; - - GIT_UNUSED(buffer_p); - GIT_UNUSED(len_p); - GIT_UNUSED(type_p); - GIT_UNUSED(oid); - - fake = (fake_backend *)backend; - - fake->read_calls++; - - *len_p = 0; - *buffer_p = NULL; - *type_p = GIT_OBJ_BLOB; - - return fake->error_code; -} - -static int fake_backend__read_header( - size_t *len_p, git_otype *type_p, - git_odb_backend *backend, const git_oid *oid) -{ - fake_backend *fake; - - GIT_UNUSED(len_p); - GIT_UNUSED(type_p); - GIT_UNUSED(oid); - - fake = (fake_backend *)backend; - - fake->read_header_calls++; - - *len_p = 0; - *type_p = GIT_OBJ_BLOB; - - return fake->error_code; -} - -static int fake_backend__read_prefix( - git_oid *out_oid, void **buffer_p, size_t *len_p, git_otype *type_p, - git_odb_backend *backend, const git_oid *short_oid, size_t len) -{ - fake_backend *fake; - GIT_UNUSED(out_oid); - GIT_UNUSED(buffer_p); - GIT_UNUSED(len_p); - GIT_UNUSED(type_p); - GIT_UNUSED(short_oid); - GIT_UNUSED(len); +#define NONEXISTING_HASH "deadbeefdeadbeefdeadbeefdeadbeefdeadbeef" +#define EXISTING_HASH "e69de29bb2d1d6434b8b29ae775ad8c2e48c5391" - fake = (fake_backend *)backend; +static const fake_object _objects[] = { + { EXISTING_HASH, "" }, + { NULL, NULL } +}; - fake->read_prefix_calls++; +static git_oid _nonexisting_oid; +static git_oid _existing_oid; - *len_p = 0; - *buffer_p = NULL; - *type_p = GIT_OBJ_BLOB; - - return fake->error_code; -} - -static void fake_backend__free(git_odb_backend *_backend) -{ - fake_backend *backend; - - backend = (fake_backend *)_backend; - - git__free(backend); -} - -static int build_fake_backend( - git_odb_backend **out, - git_error_code error_code) -{ - fake_backend *backend; - - backend = git__calloc(1, sizeof(fake_backend)); - GITERR_CHECK_ALLOC(backend); - - backend->parent.version = GIT_ODB_BACKEND_VERSION; - - backend->parent.refresh = NULL; - backend->error_code = error_code; - - backend->parent.read = fake_backend__read; - backend->parent.read_prefix = fake_backend__read_prefix; - backend->parent.read_header = fake_backend__read_header; - backend->parent.exists = fake_backend__exists; - backend->parent.free = &fake_backend__free; - - *out = (git_odb_backend *)backend; - - return 0; -} - -static void setup_repository_and_backend(git_error_code error_code) +static void setup_repository_and_backend(void) { git_odb *odb = NULL; git_odb_backend *backend = NULL; _repo = cl_git_sandbox_init("testrepo.git"); - cl_git_pass(build_fake_backend(&backend, error_code)); + cl_git_pass(build_fake_backend(&backend, _objects)); cl_git_pass(git_repository_odb__weakptr(&odb, _repo)); cl_git_pass(git_odb_add_backend(odb, backend, 10)); _fake = (fake_backend *)backend; +} - cl_git_pass(git_oid_fromstr(&_oid, "deadbeefdeadbeefdeadbeefdeadbeefdeadbeef")); +void test_odb_backend_nonrefreshing__initialize(void) +{ + git_oid_fromstr(&_nonexisting_oid, NONEXISTING_HASH); + git_oid_fromstr(&_existing_oid, EXISTING_HASH); + setup_repository_and_backend(); } void test_odb_backend_nonrefreshing__cleanup(void) @@ -156,10 +47,8 @@ void test_odb_backend_nonrefreshing__exists_is_invoked_once_on_failure(void) { git_odb *odb; - setup_repository_and_backend(GIT_ENOTFOUND); - cl_git_pass(git_repository_odb__weakptr(&odb, _repo)); - cl_assert_equal_b(false, git_odb_exists(odb, &_oid)); + cl_assert_equal_b(false, git_odb_exists(odb, &_nonexisting_oid)); cl_assert_equal_i(1, _fake->exists_calls); } @@ -168,10 +57,8 @@ void test_odb_backend_nonrefreshing__read_is_invoked_once_on_failure(void) { git_object *obj; - setup_repository_and_backend(GIT_ENOTFOUND); - cl_git_fail_with( - git_object_lookup(&obj, _repo, &_oid, GIT_OBJ_ANY), + git_object_lookup(&obj, _repo, &_nonexisting_oid, GIT_OBJ_ANY), GIT_ENOTFOUND); cl_assert_equal_i(1, _fake->read_calls); @@ -181,10 +68,8 @@ void test_odb_backend_nonrefreshing__readprefix_is_invoked_once_on_failure(void) { git_object *obj; - setup_repository_and_backend(GIT_ENOTFOUND); - cl_git_fail_with( - git_object_lookup_prefix(&obj, _repo, &_oid, 7, GIT_OBJ_ANY), + git_object_lookup_prefix(&obj, _repo, &_nonexisting_oid, 7, GIT_OBJ_ANY), GIT_ENOTFOUND); cl_assert_equal_i(1, _fake->read_prefix_calls); @@ -196,12 +81,10 @@ void test_odb_backend_nonrefreshing__readheader_is_invoked_once_on_failure(void) size_t len; git_otype type; - setup_repository_and_backend(GIT_ENOTFOUND); - cl_git_pass(git_repository_odb__weakptr(&odb, _repo)); cl_git_fail_with( - git_odb_read_header(&len, &type, odb, &_oid), + git_odb_read_header(&len, &type, odb, &_nonexisting_oid), GIT_ENOTFOUND); cl_assert_equal_i(1, _fake->read_header_calls); @@ -211,10 +94,8 @@ void test_odb_backend_nonrefreshing__exists_is_invoked_once_on_success(void) { git_odb *odb; - setup_repository_and_backend(GIT_OK); - cl_git_pass(git_repository_odb__weakptr(&odb, _repo)); - cl_assert_equal_b(true, git_odb_exists(odb, &_oid)); + cl_assert_equal_b(true, git_odb_exists(odb, &_existing_oid)); cl_assert_equal_i(1, _fake->exists_calls); } @@ -223,9 +104,7 @@ void test_odb_backend_nonrefreshing__read_is_invoked_once_on_success(void) { git_object *obj; - setup_repository_and_backend(GIT_OK); - - cl_git_pass(git_object_lookup(&obj, _repo, &_oid, GIT_OBJ_ANY)); + cl_git_pass(git_object_lookup(&obj, _repo, &_existing_oid, GIT_OBJ_ANY)); cl_assert_equal_i(1, _fake->read_calls); @@ -236,9 +115,7 @@ void test_odb_backend_nonrefreshing__readprefix_is_invoked_once_on_success(void) { git_object *obj; - setup_repository_and_backend(GIT_OK); - - cl_git_pass(git_object_lookup_prefix(&obj, _repo, &_oid, 7, GIT_OBJ_ANY)); + cl_git_pass(git_object_lookup_prefix(&obj, _repo, &_existing_oid, 7, GIT_OBJ_ANY)); cl_assert_equal_i(1, _fake->read_prefix_calls); @@ -251,11 +128,9 @@ void test_odb_backend_nonrefreshing__readheader_is_invoked_once_on_success(void) size_t len; git_otype type; - setup_repository_and_backend(GIT_OK); - cl_git_pass(git_repository_odb__weakptr(&odb, _repo)); - cl_git_pass(git_odb_read_header(&len, &type, odb, &_oid)); + cl_git_pass(git_odb_read_header(&len, &type, odb, &_existing_oid)); cl_assert_equal_i(1, _fake->read_header_calls); } @@ -264,8 +139,6 @@ void test_odb_backend_nonrefreshing__read_is_invoked_once_when_revparsing_a_full { git_object *obj; - setup_repository_and_backend(GIT_ENOTFOUND); - cl_git_fail_with( git_revparse_single(&obj, _repo, "deadbeefdeadbeefdeadbeefdeadbeefdeadbeef"), GIT_ENOTFOUND); diff --git a/tests/odb/backend/simple.c b/tests/odb/backend/simple.c new file mode 100644 index 000000000..c0fcd403b --- /dev/null +++ b/tests/odb/backend/simple.c @@ -0,0 +1,232 @@ +#include "clar_libgit2.h" +#include "repository.h" +#include "backend_helpers.h" + +#define EMPTY_HASH "e69de29bb2d1d6434b8b29ae775ad8c2e48c5391" + +static git_repository *_repo; +static git_odb *_odb; +static git_odb_object *_obj; +static git_oid _oid; + +static void setup_backend(const fake_object *objs) +{ + git_odb_backend *backend; + + cl_git_pass(build_fake_backend(&backend, objs)); + + cl_git_pass(git_repository_odb__weakptr(&_odb, _repo)); + cl_git_pass(git_odb_add_backend(_odb, backend, 10)); +} + +static void assert_object_contains(git_odb_object *obj, const char *expected) +{ + const char *actual = (const char *) git_odb_object_data(obj); + + cl_assert_equal_s(actual, expected); +} + +void test_odb_backend_simple__initialize(void) +{ + _repo = cl_git_sandbox_init("testrepo.git"); + _odb = NULL; + _obj = NULL; +} + +void test_odb_backend_simple__cleanup(void) +{ + git_odb_object_free(_obj); + cl_git_sandbox_cleanup(); + cl_git_pass(git_libgit2_opts(GIT_OPT_ENABLE_STRICT_HASH_VERIFICATION, 1)); +} + +void test_odb_backend_simple__read_of_object_succeeds(void) +{ + const fake_object objs[] = { + { "f6ea0495187600e7b2288c8ac19c5886383a4632", "foobar" }, + { NULL, NULL } + }; + + setup_backend(objs); + + cl_git_pass(git_oid_fromstr(&_oid, objs[0].oid)); + cl_git_pass(git_odb_read(&_obj, _odb, &_oid)); + + assert_object_contains(_obj, objs[0].content); +} + +void test_odb_backend_simple__read_of_nonexisting_object_fails(void) +{ + const fake_object objs[] = { + { "f6ea0495187600e7b2288c8ac19c5886383a4632", "foobar" }, + { NULL, NULL } + }; + + setup_backend(objs); + + cl_git_pass(git_oid_fromstr(&_oid, "f6ea0495187600e7b2288c8ac19c5886383a4633")); + cl_git_fail_with(GIT_ENOTFOUND, git_odb_read(&_obj, _odb, &_oid)); +} + +void test_odb_backend_simple__read_with_hash_mismatch_fails(void) +{ + const fake_object objs[] = { + { "1234567890123456789012345678901234567890", "nonmatching content" }, + { NULL, NULL } + }; + + setup_backend(objs); + + cl_git_pass(git_oid_fromstr(&_oid, objs[0].oid)); + cl_git_fail_with(GIT_EMISMATCH, git_odb_read(&_obj, _odb, &_oid)); +} + +void test_odb_backend_simple__read_with_hash_mismatch_succeeds_without_verification(void) +{ + const fake_object objs[] = { + { "1234567890123456789012345678901234567890", "nonmatching content" }, + { NULL, NULL } + }; + + setup_backend(objs); + cl_git_pass(git_oid_fromstr(&_oid, objs[0].oid)); + + cl_git_pass(git_libgit2_opts(GIT_OPT_ENABLE_STRICT_HASH_VERIFICATION, 0)); + cl_git_pass(git_odb_read(&_obj, _odb, &_oid)); + + assert_object_contains(_obj, objs[0].content); +} + +void test_odb_backend_simple__read_prefix_succeeds(void) +{ + const fake_object objs[] = { + { "f6ea0495187600e7b2288c8ac19c5886383a4632", "foobar" }, + { NULL, NULL } + }; + + setup_backend(objs); + + cl_git_pass(git_oid_fromstr(&_oid, "f6ea0495187600e7b2288c8ac19c5886383a4632")); + cl_git_pass(git_odb_read(&_obj, _odb, &_oid)); + + assert_object_contains(_obj, objs[0].content); +} + +void test_odb_backend_simple__read_prefix_of_nonexisting_object_fails(void) +{ + const fake_object objs[] = { + { "f6ea0495187600e7b2288c8ac19c5886383a4632", "foobar" }, + { NULL, NULL } + }; + char *hash = "f6ea0495187600e8"; + + setup_backend(objs); + + cl_git_pass(git_oid_fromstrn(&_oid, hash, strlen(hash))); + cl_git_fail_with(GIT_ENOTFOUND, git_odb_read(&_obj, _odb, &_oid)); +} + +void test_odb_backend_simple__read_with_ambiguous_prefix_fails(void) +{ + const fake_object objs[] = { + { "1234567890111111111111111111111111111111", "first content" }, + { "1234567890222222222222222222222222222222", "second content" }, + { NULL, NULL } + }; + + setup_backend(objs); + + cl_git_pass(git_oid_fromstr(&_oid, objs[0].oid)); + cl_git_fail_with(GIT_EAMBIGUOUS, git_odb_read_prefix(&_obj, _odb, &_oid, 7)); +} + +void test_odb_backend_simple__read_with_highly_ambiguous_prefix(void) +{ + const fake_object objs[] = { + { "1234567890111111111111111111111111111111", "first content" }, + { "1234567890111111111111111111111111111112", "second content" }, + { NULL, NULL } + }; + + setup_backend(objs); + + cl_git_pass(git_oid_fromstr(&_oid, objs[0].oid)); + cl_git_pass(git_libgit2_opts(GIT_OPT_ENABLE_STRICT_HASH_VERIFICATION, 0)); + cl_git_fail_with(GIT_EAMBIGUOUS, git_odb_read_prefix(&_obj, _odb, &_oid, 39)); + cl_git_pass(git_odb_read_prefix(&_obj, _odb, &_oid, 40)); + assert_object_contains(_obj, objs[0].content); +} + +void test_odb_backend_simple__exists_succeeds(void) +{ + const fake_object objs[] = { + { "f6ea0495187600e7b2288c8ac19c5886383a4632", "foobar" }, + { NULL, NULL } + }; + + setup_backend(objs); + + cl_git_pass(git_oid_fromstr(&_oid, objs[0].oid)); + cl_assert(git_odb_exists(_odb, &_oid)); +} + +void test_odb_backend_simple__exists_fails_for_nonexisting_object(void) +{ + const fake_object objs[] = { + { "f6ea0495187600e7b2288c8ac19c5886383a4632", "foobar" }, + { NULL, NULL } + }; + + setup_backend(objs); + + cl_git_pass(git_oid_fromstr(&_oid, "f6ea0495187600e7b2288c8ac19c5886383a4633")); + cl_assert(git_odb_exists(_odb, &_oid) == 0); +} + +void test_odb_backend_simple__exists_prefix_succeeds(void) +{ + const fake_object objs[] = { + { "1234567890111111111111111111111111111111", "first content" }, + { "1234567890222222222222222222222222222222", "second content" }, + { NULL, NULL } + }; + git_oid found; + + setup_backend(objs); + + cl_git_pass(git_oid_fromstr(&_oid, objs[0].oid)); + cl_git_pass(git_odb_exists_prefix(&found, _odb, &_oid, 12)); + cl_assert(git_oid_equal(&found, &_oid)); +} + +void test_odb_backend_simple__exists_with_ambiguous_prefix_fails(void) +{ + const fake_object objs[] = { + { "1234567890111111111111111111111111111111", "first content" }, + { "1234567890222222222222222222222222222222", "second content" }, + { NULL, NULL } + }; + + setup_backend(objs); + + cl_git_pass(git_oid_fromstr(&_oid, objs[0].oid)); + cl_git_fail_with(GIT_EAMBIGUOUS, git_odb_exists_prefix(NULL, _odb, &_oid, 7)); +} + +void test_odb_backend_simple__exists_with_highly_ambiguous_prefix(void) +{ + const fake_object objs[] = { + { "1234567890111111111111111111111111111111", "first content" }, + { "1234567890111111111111111111111111111112", "second content" }, + { NULL, NULL } + }; + git_oid found; + + setup_backend(objs); + + cl_git_pass(git_oid_fromstr(&_oid, objs[0].oid)); + cl_git_pass(git_libgit2_opts(GIT_OPT_ENABLE_STRICT_HASH_VERIFICATION, 0)); + cl_git_fail_with(GIT_EAMBIGUOUS, git_odb_exists_prefix(&found, _odb, &_oid, 39)); + cl_git_pass(git_odb_exists_prefix(&found, _odb, &_oid, 40)); + cl_assert(git_oid_equal(&found, &_oid)); +} diff --git a/tests/odb/foreach.c b/tests/odb/foreach.c index 12b81b4f1..42d706467 100644 --- a/tests/odb/foreach.c +++ b/tests/odb/foreach.c @@ -28,8 +28,8 @@ static int foreach_cb(const git_oid *oid, void *data) /* * $ git --git-dir tests/resources/testrepo.git count-objects --verbose - * count: 47 - * size: 4 + * count: 60 + * size: 240 * in-pack: 1640 * packs: 3 * size-pack: 425 @@ -44,7 +44,7 @@ void test_odb_foreach__foreach(void) git_repository_odb(&_odb, _repo); cl_git_pass(git_odb_foreach(_odb, foreach_cb, &nobj)); - cl_assert_equal_i(47 + 1640, nobj); /* count + in-pack */ + cl_assert_equal_i(60 + 1640, nobj); /* count + in-pack */ } void test_odb_foreach__one_pack(void) @@ -118,7 +118,7 @@ void test_odb_foreach__files_in_objects_dir(void) cl_git_pass(git_repository_odb(&odb, repo)); cl_git_pass(git_odb_foreach(odb, foreach_cb, &nobj)); - cl_assert_equal_i(47 + 1640, nobj); /* count + in-pack */ + cl_assert_equal_i(60 + 1640, nobj); /* count + in-pack */ git_odb_free(odb); git_repository_free(repo); diff --git a/tests/odb/freshen.c b/tests/odb/freshen.c index d8d6c029a..9d3cf51dc 100644 --- a/tests/odb/freshen.c +++ b/tests/odb/freshen.c @@ -17,36 +17,126 @@ void test_odb_freshen__cleanup(void) cl_git_sandbox_cleanup(); } -#define LOOSE_STR "hey\n" -#define LOOSE_ID "1385f264afb75a56a5bec74243be9b367ba4ca08" -#define LOOSE_FN "13/85f264afb75a56a5bec74243be9b367ba4ca08" +static void set_time_wayback(struct stat *out, const char *fn) +{ + git_buf fullpath = GIT_BUF_INIT; + struct p_timeval old[2]; + + old[0].tv_sec = 1234567890; + old[0].tv_usec = 0; + old[1].tv_sec = 1234567890; + old[1].tv_usec = 0; -void test_odb_freshen__loose_object(void) + git_buf_joinpath(&fullpath, "testrepo.git/objects", fn); + + cl_must_pass(p_utimes(git_buf_cstr(&fullpath), old)); + cl_must_pass(p_lstat(git_buf_cstr(&fullpath), out)); + git_buf_free(&fullpath); +} + +#define LOOSE_STR "my new file\n" +#define LOOSE_BLOB_ID "a71586c1dfe8a71c6cbf6c129f404c5642ff31bd" +#define LOOSE_BLOB_FN "a7/1586c1dfe8a71c6cbf6c129f404c5642ff31bd" + +void test_odb_freshen__loose_blob(void) { git_oid expected_id, id; struct stat before, after; - struct p_timeval old_times[2]; - cl_git_pass(git_oid_fromstr(&expected_id, LOOSE_ID)); + cl_git_pass(git_oid_fromstr(&expected_id, LOOSE_BLOB_ID)); + set_time_wayback(&before, LOOSE_BLOB_FN); - old_times[0].tv_sec = 1234567890; - old_times[0].tv_usec = 0; - old_times[1].tv_sec = 1234567890; - old_times[1].tv_usec = 0; + /* make sure we freshen a blob */ + cl_git_pass(git_blob_create_frombuffer(&id, repo, LOOSE_STR, CONST_STRLEN(LOOSE_STR))); + cl_assert_equal_oid(&expected_id, &id); + cl_must_pass(p_lstat("testrepo.git/objects/" LOOSE_BLOB_FN, &after)); - /* set time to way back */ - cl_must_pass(p_utimes("testrepo.git/objects/" LOOSE_FN, old_times)); - cl_must_pass(p_lstat("testrepo.git/objects/" LOOSE_FN, &before)); + cl_assert(before.st_atime < after.st_atime); + cl_assert(before.st_mtime < after.st_mtime); +} + +#define UNIQUE_STR "doesnt exist in the odb yet\n" +#define UNIQUE_BLOB_ID "78a87d0b8878c5953b9a63015ff4e22a3d898826" +#define UNIQUE_BLOB_FN "78/a87d0b8878c5953b9a63015ff4e22a3d898826" - cl_git_pass(git_odb_write(&id, odb, LOOSE_STR, CONST_STRLEN(LOOSE_STR), - GIT_OBJ_BLOB)); +void test_odb_freshen__readonly_object(void) +{ + git_oid expected_id, id; + struct stat before, after; + + cl_git_pass(git_oid_fromstr(&expected_id, UNIQUE_BLOB_ID)); + + cl_git_pass(git_blob_create_frombuffer(&id, repo, UNIQUE_STR, CONST_STRLEN(UNIQUE_STR))); + cl_assert_equal_oid(&expected_id, &id); + + set_time_wayback(&before, UNIQUE_BLOB_FN); + cl_assert((before.st_mode & S_IWUSR) == 0); + + cl_git_pass(git_blob_create_frombuffer(&id, repo, UNIQUE_STR, CONST_STRLEN(UNIQUE_STR))); cl_assert_equal_oid(&expected_id, &id); - cl_must_pass(p_lstat("testrepo.git/objects/" LOOSE_FN, &after)); + cl_must_pass(p_lstat("testrepo.git/objects/" UNIQUE_BLOB_FN, &after)); cl_assert(before.st_atime < after.st_atime); cl_assert(before.st_mtime < after.st_mtime); } +#define LOOSE_TREE_ID "944c0f6e4dfa41595e6eb3ceecdb14f50fe18162" +#define LOOSE_TREE_FN "94/4c0f6e4dfa41595e6eb3ceecdb14f50fe18162" + +void test_odb_freshen__loose_tree(void) +{ + git_oid expected_id, id; + git_tree *tree; + struct stat before, after; + + cl_git_pass(git_oid_fromstr(&expected_id, LOOSE_TREE_ID)); + set_time_wayback(&before, LOOSE_TREE_FN); + + cl_git_pass(git_tree_lookup(&tree, repo, &expected_id)); + cl_git_pass(git_tree_create_updated(&id, repo, tree, 0, NULL)); + + /* make sure we freshen a tree */ + cl_assert_equal_oid(&expected_id, &id); + cl_must_pass(p_lstat("testrepo.git/objects/" LOOSE_TREE_FN, &after)); + + cl_assert(before.st_atime < after.st_atime); + cl_assert(before.st_mtime < after.st_mtime); + + git_tree_free(tree); +} + +void test_odb_freshen__tree_during_commit(void) +{ + git_oid tree_id, parent_id, commit_id; + git_tree *tree; + git_commit *parent; + git_signature *signature; + struct stat before, after; + + cl_git_pass(git_oid_fromstr(&tree_id, LOOSE_TREE_ID)); + cl_git_pass(git_tree_lookup(&tree, repo, &tree_id)); + set_time_wayback(&before, LOOSE_TREE_FN); + + cl_git_pass(git_oid_fromstr(&parent_id, "a65fedf39aefe402d3bb6e24df4d4f5fe4547750")); + cl_git_pass(git_commit_lookup(&parent, repo, &parent_id)); + + cl_git_pass(git_signature_new(&signature, + "Refresher", "refresher@example.com", 1488547083, 0)); + + cl_git_pass(git_commit_create(&commit_id, repo, NULL, + signature, signature, NULL, "New commit pointing to old tree", + tree, 1, (const git_commit **)&parent)); + + /* make sure we freshen the tree the commit points to */ + cl_must_pass(p_lstat("testrepo.git/objects/" LOOSE_TREE_FN, &after)); + cl_assert(before.st_atime < after.st_atime); + cl_assert(before.st_mtime < after.st_mtime); + + git_signature_free(signature); + git_commit_free(parent); + git_tree_free(tree); +} + #define PACKED_STR "Testing a readme.txt\n" #define PACKED_ID "6336846bd5c88d32f93ae57d846683e61ab5c530" #define PACKED_FN "pack-d85f5d483273108c9d8dd0e4728ccf0b2982423a.pack" diff --git a/tests/odb/loose.c b/tests/odb/loose.c index c91927c4a..2e24d6723 100644 --- a/tests/odb/loose.c +++ b/tests/odb/loose.c @@ -3,6 +3,7 @@ #include "git2/odb_backend.h" #include "posix.h" #include "loose_data.h" +#include "repository.h" #ifdef __ANDROID_API__ # define S_IREAD S_IRUSR @@ -56,11 +57,13 @@ static void test_read_object(object_data *data) void test_odb_loose__initialize(void) { + p_fsync__cnt = 0; cl_must_pass(p_mkdir("test-objects", GIT_OBJECT_DIR_MODE)); } void test_odb_loose__cleanup(void) { + cl_git_pass(git_libgit2_opts(GIT_OPT_ENABLE_FSYNC_GITDIR, 0)); cl_fixture_cleanup("test-objects"); } @@ -150,3 +153,55 @@ void test_odb_loose__permissions_readwrite(void) { test_write_object_permission(0777, 0666, 0777, 0666); } + +static void write_object_to_loose_odb(int fsync) +{ + git_odb *odb; + git_odb_backend *backend; + git_oid oid; + + cl_git_pass(git_odb_new(&odb)); + cl_git_pass(git_odb_backend_loose(&backend, "test-objects", -1, fsync, 0777, 0666)); + cl_git_pass(git_odb_add_backend(odb, backend, 1)); + cl_git_pass(git_odb_write(&oid, odb, "Test data\n", 10, GIT_OBJ_BLOB)); + git_odb_free(odb); +} + +void test_odb_loose__does_not_fsync_by_default(void) +{ + write_object_to_loose_odb(0); + cl_assert_equal_sz(0, p_fsync__cnt); +} + +void test_odb_loose__fsync_obeys_odb_option(void) +{ + write_object_to_loose_odb(1); + cl_assert(p_fsync__cnt > 0); +} + +void test_odb_loose__fsync_obeys_global_setting(void) +{ + cl_git_pass(git_libgit2_opts(GIT_OPT_ENABLE_FSYNC_GITDIR, 1)); + write_object_to_loose_odb(0); + cl_assert(p_fsync__cnt > 0); +} + +void test_odb_loose__fsync_obeys_repo_setting(void) +{ + git_repository *repo; + git_odb *odb; + git_oid oid; + + cl_git_pass(git_repository_init(&repo, "test-objects", 1)); + cl_git_pass(git_repository_odb__weakptr(&odb, repo)); + cl_git_pass(git_odb_write(&oid, odb, "No fsync here\n", 14, GIT_OBJ_BLOB)); + cl_assert(p_fsync__cnt == 0); + git_repository_free(repo); + + cl_git_pass(git_repository_open(&repo, "test-objects")); + cl_repo_set_bool(repo, "core.fsyncObjectFiles", true); + cl_git_pass(git_repository_odb__weakptr(&odb, repo)); + cl_git_pass(git_odb_write(&oid, odb, "Now fsync\n", 10, GIT_OBJ_BLOB)); + cl_assert(p_fsync__cnt > 0); + git_repository_free(repo); +} diff --git a/tests/online/badssl.c b/tests/online/badssl.c index 66b090df4..6524fcd8e 100644 --- a/tests/online/badssl.c +++ b/tests/online/badssl.c @@ -4,43 +4,77 @@ static git_repository *g_repo; -#if defined(GIT_OPENSSL) || defined(GIT_WINHTTP) || defined(GIT_SECURE_TRANSPORT) +#ifdef GIT_HTTPS static bool g_has_ssl = true; #else static bool g_has_ssl = false; #endif +static int cert_check_assert_invalid(git_cert *cert, int valid, const char* host, void *payload) +{ + GIT_UNUSED(cert); GIT_UNUSED(host); GIT_UNUSED(payload); + + cl_assert_equal_i(0, valid); + + return GIT_ECERTIFICATE; +} + void test_online_badssl__expired(void) { + git_clone_options opts = GIT_CLONE_OPTIONS_INIT; + opts.fetch_opts.callbacks.certificate_check = cert_check_assert_invalid; + if (!g_has_ssl) cl_skip(); cl_git_fail_with(GIT_ECERTIFICATE, git_clone(&g_repo, "https://expired.badssl.com/fake.git", "./fake", NULL)); + + cl_git_fail_with(GIT_ECERTIFICATE, + git_clone(&g_repo, "https://expired.badssl.com/fake.git", "./fake", &opts)); } void test_online_badssl__wrong_host(void) { + git_clone_options opts = GIT_CLONE_OPTIONS_INIT; + opts.fetch_opts.callbacks.certificate_check = cert_check_assert_invalid; + if (!g_has_ssl) cl_skip(); cl_git_fail_with(GIT_ECERTIFICATE, git_clone(&g_repo, "https://wrong.host.badssl.com/fake.git", "./fake", NULL)); + cl_git_fail_with(GIT_ECERTIFICATE, + git_clone(&g_repo, "https://wrong.host.badssl.com/fake.git", "./fake", &opts)); } void test_online_badssl__self_signed(void) { + git_clone_options opts = GIT_CLONE_OPTIONS_INIT; + opts.fetch_opts.callbacks.certificate_check = cert_check_assert_invalid; + if (!g_has_ssl) cl_skip(); cl_git_fail_with(GIT_ECERTIFICATE, git_clone(&g_repo, "https://self-signed.badssl.com/fake.git", "./fake", NULL)); + cl_git_fail_with(GIT_ECERTIFICATE, + git_clone(&g_repo, "https://self-signed.badssl.com/fake.git", "./fake", &opts)); } void test_online_badssl__old_cipher(void) { + git_clone_options opts = GIT_CLONE_OPTIONS_INIT; + opts.fetch_opts.callbacks.certificate_check = cert_check_assert_invalid; + + /* FIXME: we don't actually reject RC4 anywhere, figure out what to tweak */ + cl_skip(); + if (!g_has_ssl) cl_skip(); - cl_git_fail(git_clone(&g_repo, "https://rc4.badssl.com/fake.git", "./fake", NULL)); + cl_git_fail_with(GIT_ECERTIFICATE, + git_clone(&g_repo, "https://rc4.badssl.com/fake.git", "./fake", NULL)); + cl_git_fail_with(GIT_ECERTIFICATE, + git_clone(&g_repo, "https://rc4.badssl.com/fake.git", "./fake", &opts)); } diff --git a/tests/online/clone.c b/tests/online/clone.c index 04fd22d45..5eda73f87 100644 --- a/tests/online/clone.c +++ b/tests/online/clone.c @@ -547,7 +547,7 @@ void test_online_clone__ssh_cert(void) if (!_remote_ssh_fingerprint) cl_skip(); - cl_git_fail_with(GIT_EUSER, git_clone(&g_repo, "ssh://localhost/foo", "./foo", &g_options)); + cl_git_fail_with(GIT_EUSER, git_clone(&g_repo, _remote_url, "./foo", &g_options)); } static char *read_key_file(const char *path) diff --git a/tests/online/fetchhead.c b/tests/online/fetchhead.c index 9aaad253c..c1ac06dbe 100644 --- a/tests/online/fetchhead.c +++ b/tests/online/fetchhead.c @@ -126,6 +126,8 @@ void test_online_fetchhead__explicit_dst_refspec_creates_branch(void) cl_git_pass(git_branch_lookup(&ref, g_repo, "explicit-refspec", GIT_BRANCH_ALL)); cl_assert_equal_i(refs + 1, count_references()); + + git_reference_free(ref); } void test_online_fetchhead__empty_dst_refspec_creates_no_branch(void) diff --git a/tests/online/remotes.c b/tests/online/remotes.c index a86f2d9ae..d79eb1f59 100644 --- a/tests/online/remotes.c +++ b/tests/online/remotes.c @@ -1,12 +1,13 @@ #include "clar_libgit2.h" -static const char *refspec = "refs/heads/first-merge:refs/remotes/origin/first-merge"; +#define URL "git://github.com/libgit2/TestGitRepository" +#define REFSPEC "refs/heads/first-merge:refs/remotes/origin/first-merge" static int remote_single_branch(git_remote **out, git_repository *repo, const char *name, const char *url, void *payload) { GIT_UNUSED(payload); - cl_git_pass(git_remote_create_with_fetchspec(out, repo, name, url, refspec)); + cl_git_pass(git_remote_create_with_fetchspec(out, repo, name, url, REFSPEC)); return 0; } @@ -22,7 +23,7 @@ void test_online_remotes__single_branch(void) opts.remote_cb = remote_single_branch; opts.checkout_branch = "first-merge"; - cl_git_pass(git_clone(&repo, "git://github.com/libgit2/TestGitRepository", "./single-branch", &opts)); + cl_git_pass(git_clone(&repo, URL, "./single-branch", &opts)); cl_git_pass(git_reference_list(&refs, repo)); for (i = 0; i < refs.count; i++) { @@ -37,7 +38,7 @@ void test_online_remotes__single_branch(void) cl_git_pass(git_remote_get_fetch_refspecs(&refs, remote)); cl_assert_equal_i(1, refs.count); - cl_assert_equal_s(refspec, refs.strings[0]); + cl_assert_equal_s(REFSPEC, refs.strings[0]); git_strarray_free(&refs); git_remote_free(remote); @@ -51,5 +52,76 @@ void test_online_remotes__restricted_refspecs(void) opts.remote_cb = remote_single_branch; - cl_git_fail_with(GIT_EINVALIDSPEC, git_clone(&repo, "git://github.com/libgit2/TestGitRepository", "./restrict-refspec", &opts)); + cl_git_fail_with(GIT_EINVALIDSPEC, git_clone(&repo, URL, "./restrict-refspec", &opts)); +} + +void test_online_remotes__detached_remote_fails_downloading(void) +{ + git_remote *remote; + + cl_git_pass(git_remote_create_detached(&remote, URL)); + cl_git_pass(git_remote_connect(remote, GIT_DIRECTION_FETCH, NULL, NULL, NULL)); + cl_git_fail(git_remote_download(remote, NULL, NULL)); + + git_remote_free(remote); +} + +void test_online_remotes__detached_remote_fails_uploading(void) +{ + git_remote *remote; + + cl_git_pass(git_remote_create_detached(&remote, URL)); + cl_git_pass(git_remote_connect(remote, GIT_DIRECTION_FETCH, NULL, NULL, NULL)); + cl_git_fail(git_remote_upload(remote, NULL, NULL)); + + git_remote_free(remote); +} + +void test_online_remotes__detached_remote_fails_pushing(void) +{ + git_remote *remote; + + cl_git_pass(git_remote_create_detached(&remote, URL)); + cl_git_pass(git_remote_connect(remote, GIT_DIRECTION_FETCH, NULL, NULL, NULL)); + cl_git_fail(git_remote_push(remote, NULL, NULL)); + + git_remote_free(remote); +} + +void test_online_remotes__detached_remote_succeeds_ls(void) +{ + const char *refs[] = { + "HEAD", + "refs/heads/first-merge", + "refs/heads/master", + "refs/heads/no-parent", + "refs/tags/annotated_tag", + "refs/tags/annotated_tag^{}", + "refs/tags/blob", + "refs/tags/commit_tree", + "refs/tags/nearly-dangling", + }; + const git_remote_head **heads; + git_remote *remote; + size_t i, j, n; + + cl_git_pass(git_remote_create_detached(&remote, URL)); + cl_git_pass(git_remote_connect(remote, GIT_DIRECTION_FETCH, NULL, NULL, NULL)); + cl_git_pass(git_remote_ls(&heads, &n, remote)); + + cl_assert_equal_sz(n, 9); + for (i = 0; i < n; i++) { + char found = false; + + for (j = 0; j < ARRAY_SIZE(refs); j++) { + if (!strcmp(heads[i]->name, refs[j])) { + found = true; + break; + } + } + + cl_assert_(found, heads[i]->name); + } + + git_remote_free(remote); } diff --git a/tests/pack/indexer.c b/tests/pack/indexer.c index 49a106d98..c73d3974e 100644 --- a/tests/pack/indexer.c +++ b/tests/pack/indexer.c @@ -85,7 +85,7 @@ void test_pack_indexer__fix_thin(void) cl_assert_equal_i(stats.indexed_objects, 2); cl_assert_equal_i(stats.local_objects, 1); - git_oid_fromstr(&should_id, "11f0f69b334728fdd8bc86b80499f22f29d85b15"); + git_oid_fromstr(&should_id, "fefdb2d740a3a6b6c03a0c7d6ce431c6d5810e13"); cl_assert_equal_oid(&should_id, git_indexer_hash(idx)); git_indexer_free(idx); @@ -102,7 +102,7 @@ void test_pack_indexer__fix_thin(void) int fd; ssize_t read; struct stat st; - const char *name = "pack-11f0f69b334728fdd8bc86b80499f22f29d85b15.pack"; + const char *name = "pack-fefdb2d740a3a6b6c03a0c7d6ce431c6d5810e13.pack"; fd = p_open(name, O_RDONLY); cl_assert(fd != -1); @@ -125,3 +125,44 @@ void test_pack_indexer__fix_thin(void) git_indexer_free(idx); } } + +static int find_tmp_file_recurs(void *opaque, git_buf *path) +{ + int error = 0; + git_buf *first_tmp_file = opaque; + struct stat st; + + if ((error = p_lstat_posixly(path->ptr, &st)) < 0) + return error; + + if (S_ISDIR(st.st_mode)) + return git_path_direach(path, 0, find_tmp_file_recurs, opaque); + + /* This is the template that's used in git_futils_mktmp. */ + if (strstr(git_buf_cstr(path), "_git2_") != NULL) + return git_buf_sets(first_tmp_file, git_buf_cstr(path)); + + return 0; +} + +void test_pack_indexer__no_tmp_files(void) +{ + git_indexer *idx = NULL; + git_buf path = GIT_BUF_INIT; + git_buf first_tmp_file = GIT_BUF_INIT; + + /* Precondition: there are no temporary files. */ + cl_git_pass(git_buf_sets(&path, clar_sandbox_path())); + cl_git_pass(find_tmp_file_recurs(&first_tmp_file, &path)); + git_buf_free(&path); + cl_assert(git_buf_len(&first_tmp_file) == 0); + + cl_git_pass(git_indexer_new(&idx, ".", 0, NULL, NULL, NULL)); + git_indexer_free(idx); + + cl_git_pass(git_buf_sets(&path, clar_sandbox_path())); + cl_git_pass(find_tmp_file_recurs(&first_tmp_file, &path)); + git_buf_free(&path); + cl_assert(git_buf_len(&first_tmp_file) == 0); + git_buf_free(&first_tmp_file); +} diff --git a/tests/pack/packbuilder.c b/tests/pack/packbuilder.c index 29f3e2d64..13ee07353 100644 --- a/tests/pack/packbuilder.c +++ b/tests/pack/packbuilder.c @@ -23,6 +23,7 @@ void test_pack_packbuilder__initialize(void) cl_git_pass(git_vector_init(&_commits, 0, NULL)); _commits_is_initialized = 1; memset(&_stats, 0, sizeof(_stats)); + p_fsync__cnt = 0; } void test_pack_packbuilder__cleanup(void) @@ -30,6 +31,8 @@ void test_pack_packbuilder__cleanup(void) git_oid *o; unsigned int i; + cl_git_pass(git_libgit2_opts(GIT_OPT_ENABLE_FSYNC_GITDIR, 0)); + if (_commits_is_initialized) { _commits_is_initialized = 0; git_vector_foreach(&_commits, i, o) { @@ -113,7 +116,7 @@ void test_pack_packbuilder__create_pack(void) * $ cd tests/resources/testrepo.git * $ git rev-list --objects HEAD | \ * git pack-objects -q --no-reuse-delta --threads=1 pack - * $ sha1sum git-80e61eb315239ef3c53033e37fee43b744d57122.pack + * $ sha1sum pack-7f5fa362c664d68ba7221259be1cbd187434b2f0.pack * 5d410bdf97cf896f9007681b92868471d636954b * */ @@ -142,7 +145,7 @@ void test_pack_packbuilder__get_hash(void) git_packbuilder_write(_packbuilder, ".", 0, NULL, NULL); git_oid_fmt(hex, git_packbuilder_hash(_packbuilder)); - cl_assert_equal_s(hex, "80e61eb315239ef3c53033e37fee43b744d57122"); + cl_assert_equal_s(hex, "7f5fa362c664d68ba7221259be1cbd187434b2f0"); } static void test_write_pack_permission(mode_t given, mode_t expected) @@ -166,10 +169,10 @@ static void test_write_pack_permission(mode_t given, mode_t expected) mask = p_umask(0); p_umask(mask); - cl_git_pass(p_stat("pack-80e61eb315239ef3c53033e37fee43b744d57122.idx", &statbuf)); + cl_git_pass(p_stat("pack-7f5fa362c664d68ba7221259be1cbd187434b2f0.idx", &statbuf)); cl_assert_equal_i(statbuf.st_mode & os_mask, (expected & ~mask) & os_mask); - cl_git_pass(p_stat("pack-80e61eb315239ef3c53033e37fee43b744d57122.pack", &statbuf)); + cl_git_pass(p_stat("pack-7f5fa362c664d68ba7221259be1cbd187434b2f0.pack", &statbuf)); cl_assert_equal_i(statbuf.st_mode & os_mask, (expected & ~mask) & os_mask); } @@ -188,6 +191,40 @@ void test_pack_packbuilder__permissions_readwrite(void) test_write_pack_permission(0666, 0666); } +void test_pack_packbuilder__does_not_fsync_by_default(void) +{ + seed_packbuilder(); + git_packbuilder_write(_packbuilder, ".", 0666, NULL, NULL); + cl_assert_equal_sz(0, p_fsync__cnt); +} + +/* We fsync the packfile and index. On non-Windows, we also fsync + * the parent directories. + */ +#ifdef GIT_WIN32 +static int expected_fsyncs = 2; +#else +static int expected_fsyncs = 4; +#endif + +void test_pack_packbuilder__fsync_global_setting(void) +{ + cl_git_pass(git_libgit2_opts(GIT_OPT_ENABLE_FSYNC_GITDIR, 1)); + p_fsync__cnt = 0; + seed_packbuilder(); + git_packbuilder_write(_packbuilder, ".", 0666, NULL, NULL); + cl_assert_equal_sz(expected_fsyncs, p_fsync__cnt); +} + +void test_pack_packbuilder__fsync_repo_setting(void) +{ + cl_repo_set_bool(_repo, "core.fsyncObjectFiles", true); + p_fsync__cnt = 0; + seed_packbuilder(); + git_packbuilder_write(_packbuilder, ".", 0666, NULL, NULL); + cl_assert_equal_sz(expected_fsyncs, p_fsync__cnt); +} + static int foreach_cb(void *buf, size_t len, void *payload) { git_indexer *idx = (git_indexer *) payload; diff --git a/tests/patch/patch_common.h b/tests/patch/patch_common.h index 6ec554690..a20ebd617 100644 --- a/tests/patch/patch_common.h +++ b/tests/patch/patch_common.h @@ -253,7 +253,66 @@ "@@ -9,0 +10 @@ below it!\n" \ "+insert at end\n" -/* An insertion at the beginning and end of file (and the resultant patch) */ +#define PATCH_SIMPLE_COMMIT \ + "commit 15e119375018fba121cf58e02a9f17fe22df0df8\n" \ + "Author: Edward Thomson <ethomson@edwardthomson.com>\n" \ + "Date: Wed Jun 14 13:31:20 2017 +0200\n" \ + "\n" \ + " CHANGELOG: document git_filter_init and GIT_FILTER_INIT\n" \ + "\n" \ + "diff --git a/CHANGELOG.md b/CHANGELOG.md\n" \ + "index 1b9e0c90a..24ecba426 100644\n" \ + "--- a/CHANGELOG.md\n" \ + "+++ b/CHANGELOG.md\n" \ + "@@ -96,6 +96,9 @@ v0.26\n" \ + " * `git_transport_smart_proxy_options()' enables you to get the proxy options for\n" \ + " smart transports.\n" \ + "\n" \ + "+* The `GIT_FILTER_INIT` macro and the `git_filter_init` function are provided\n" \ + "+ to initialize a `git_filter` structure.\n" \ + "+\n" \ + " ### Breaking API changes\n" \ + "\n" \ + " * `clone_checkout_strategy` has been removed from\n" + +#define PATCH_MULTIPLE_HUNKS \ + "diff --git a/x b/x\n" \ + "index 0719398..fa0350c 100644\n" \ + "--- a/x\n" \ + "+++ b/x\n" \ + "@@ -1,5 +1,4 @@\n" \ + " 1\n" \ + "-2\n" \ + " 3\n" \ + " 4\n" \ + " 5\n" \ + "@@ -7,3 +6,4 @@\n" \ + " 7\n" \ + " 8\n" \ + " 9\n" \ + "+10\n" + +#define PATCH_MULTIPLE_FILES \ + "diff --git a/x b/x\n" \ + "index 8a1218a..7059ba5 100644\n" \ + "--- a/x\n" \ + "+++ b/x\n" \ + "@@ -1,5 +1,4 @@\n" \ + " 1\n" \ + " 2\n" \ + "-3\n" \ + " 4\n" \ + " 5\n" \ + "diff --git a/y b/y\n" \ + "index e006065..9405325 100644\n" \ + "--- a/y\n" \ + "+++ b/y\n" \ + "@@ -1,4 +1,5 @@\n" \ + " a\n" \ + " b\n" \ + "+c\n" \ + " d\n" \ + " e\n" #define FILE_PREPEND_AND_APPEND \ "first and\n" \ diff --git a/tests/precompiled.c b/tests/precompiled.c new file mode 100644 index 000000000..5f656a45d --- /dev/null +++ b/tests/precompiled.c @@ -0,0 +1 @@ +#include "precompiled.h" diff --git a/tests/precompiled.h b/tests/precompiled.h new file mode 100644 index 000000000..ea53a60e9 --- /dev/null +++ b/tests/precompiled.h @@ -0,0 +1,4 @@ +#include "common.h" +#include "git2.h" +#include "clar.h" +#include "clar_libgit2.h" diff --git a/tests/rebase/merge.c b/tests/rebase/merge.c index 0f06ed153..7b2d6876c 100644 --- a/tests/rebase/merge.c +++ b/tests/rebase/merge.c @@ -1,4 +1,5 @@ #include "clar_libgit2.h" +#include "git2/checkout.h" #include "git2/rebase.h" #include "posix.h" #include "signature.h" @@ -475,6 +476,59 @@ void test_rebase_merge__finish(void) git_rebase_free(rebase); } +void test_rebase_merge__detached_finish(void) +{ + git_rebase *rebase; + git_reference *branch_ref, *upstream_ref, *head_ref; + git_annotated_commit *branch_head, *upstream_head; + git_rebase_operation *rebase_operation; + git_oid commit_id; + git_reflog *reflog; + const git_reflog_entry *reflog_entry; + git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT; + int error; + + cl_git_pass(git_reference_lookup(&branch_ref, repo, "refs/heads/gravy")); + cl_git_pass(git_reference_lookup(&upstream_ref, repo, "refs/heads/veal")); + + cl_git_pass(git_annotated_commit_from_ref(&branch_head, repo, branch_ref)); + cl_git_pass(git_annotated_commit_from_ref(&upstream_head, repo, upstream_ref)); + + cl_git_pass(git_repository_set_head_detached_from_annotated(repo, branch_head)); + opts.checkout_strategy = GIT_CHECKOUT_FORCE; + git_checkout_head(repo, &opts); + + cl_git_pass(git_rebase_init(&rebase, repo, NULL, upstream_head, NULL, NULL)); + + cl_git_pass(git_rebase_next(&rebase_operation, rebase)); + cl_git_pass(git_rebase_commit(&commit_id, rebase, NULL, signature, + NULL, NULL)); + + cl_git_fail(error = git_rebase_next(&rebase_operation, rebase)); + cl_assert_equal_i(GIT_ITEROVER, error); + + cl_git_pass(git_rebase_finish(rebase, signature)); + + cl_assert_equal_i(GIT_REPOSITORY_STATE_NONE, git_repository_state(repo)); + + cl_git_pass(git_reference_lookup(&head_ref, repo, "HEAD")); + cl_assert_equal_i(GIT_REF_OID, git_reference_type(head_ref)); + + /* Make sure the reflogs are updated appropriately */ + cl_git_pass(git_reflog_read(&reflog, repo, "HEAD")); + cl_assert(reflog_entry = git_reflog_entry_byindex(reflog, 0)); + cl_assert_equal_oid(git_annotated_commit_id(upstream_head), git_reflog_entry_id_old(reflog_entry)); + cl_assert_equal_oid(&commit_id, git_reflog_entry_id_new(reflog_entry)); + + git_reflog_free(reflog); + git_annotated_commit_free(branch_head); + git_annotated_commit_free(upstream_head); + git_reference_free(head_ref); + git_reference_free(branch_ref); + git_reference_free(upstream_ref); + git_rebase_free(rebase); +} + void test_rebase_merge__finish_with_ids(void) { git_rebase *rebase; diff --git a/tests/rebase/submodule.c b/tests/rebase/submodule.c new file mode 100644 index 000000000..8ae78ce5b --- /dev/null +++ b/tests/rebase/submodule.c @@ -0,0 +1,94 @@ +#include "clar_libgit2.h" +#include "git2/checkout.h" +#include "git2/rebase.h" +#include "posix.h" +#include "signature.h" +#include "../submodule/submodule_helpers.h" + +#include <fcntl.h> + +static git_repository *repo; +static git_signature *signature; + +// Fixture setup and teardown +void test_rebase_submodule__initialize(void) +{ + git_index *index; + git_oid tree_oid, commit_id; + git_tree *tree; + git_commit *parent; + git_object *obj; + git_reference *master_ref; + git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT; + opts.checkout_strategy = GIT_CHECKOUT_FORCE; + + repo = cl_git_sandbox_init("rebase-submodule"); + cl_git_pass(git_signature_new(&signature, + "Rebaser", "rebaser@rebaser.rb", 1405694510, 0)); + + rewrite_gitmodules(git_repository_workdir(repo)); + + cl_git_pass(git_submodule_set_url(repo, "my-submodule", git_repository_path(repo))); + + /* We have to commit the rewritten .gitmodules file */ + cl_git_pass(git_repository_index(&index, repo)); + cl_git_pass(git_index_add_bypath(index, ".gitmodules")); + cl_git_pass(git_index_write_tree(&tree_oid, index)); + + cl_git_pass(git_tree_lookup(&tree, repo, &tree_oid)); + + cl_git_pass(git_repository_head(&master_ref, repo)); + cl_git_pass(git_commit_lookup(&parent, repo, git_reference_target(master_ref))); + + cl_git_pass(git_commit_create_v(&commit_id, repo, git_reference_name(master_ref), signature, signature, NULL, "Fixup .gitmodules", tree, 1, parent)); + + /* And a final reset, for good measure */ + cl_git_pass(git_object_lookup(&obj, repo, &commit_id, GIT_OBJ_COMMIT)); + cl_git_pass(git_reset(repo, obj, GIT_RESET_HARD, &opts)); + + git_index_free(index); + git_object_free(obj); + git_commit_free(parent); + git_reference_free(master_ref); + git_tree_free(tree); +} + +void test_rebase_submodule__cleanup(void) +{ + git_signature_free(signature); + cl_git_sandbox_cleanup(); +} + +void test_rebase_submodule__init_untracked(void) +{ + git_rebase *rebase; + git_reference *branch_ref, *upstream_ref; + git_annotated_commit *branch_head, *upstream_head; + git_buf untracked_path = GIT_BUF_INIT; + FILE *fp; + git_submodule *submodule; + + cl_git_pass(git_reference_lookup(&branch_ref, repo, "refs/heads/asparagus")); + cl_git_pass(git_reference_lookup(&upstream_ref, repo, "refs/heads/master")); + + cl_git_pass(git_annotated_commit_from_ref(&branch_head, repo, branch_ref)); + cl_git_pass(git_annotated_commit_from_ref(&upstream_head, repo, upstream_ref)); + + cl_git_pass(git_submodule_lookup(&submodule, repo, "my-submodule")); + cl_git_pass(git_submodule_update(submodule, 1, NULL)); + + git_buf_printf(&untracked_path, "%s/my-submodule/untracked", git_repository_workdir(repo)); + fp = fopen(git_buf_cstr(&untracked_path), "w"); + fprintf(fp, "An untracked file in a submodule should not block a rebase\n"); + fclose(fp); + git_buf_free(&untracked_path); + + cl_git_pass(git_rebase_init(&rebase, repo, branch_head, upstream_head, NULL, NULL)); + + git_submodule_free(submodule); + git_annotated_commit_free(branch_head); + git_annotated_commit_free(upstream_head); + git_reference_free(branch_ref); + git_reference_free(upstream_ref); + git_rebase_free(rebase); +} diff --git a/tests/refs/branches/create.c b/tests/refs/branches/create.c index 31dec0678..69488e6c7 100644 --- a/tests/refs/branches/create.c +++ b/tests/refs/branches/create.c @@ -65,10 +65,14 @@ void test_refs_branches_create__can_force_create_over_an_existing_branch(void) cl_assert_equal_s("refs/heads/br2", git_reference_name(branch)); } -void test_refs_branches_create__cannot_force_create_over_current_branch(void) +void test_refs_branches_create__cannot_force_create_over_current_branch_in_nonbare_repo(void) { const git_oid *oid; git_reference *branch2; + + /* Default repo for these tests is a bare repo, but this test requires a non-bare one */ + cl_git_sandbox_cleanup(); + repo = cl_git_sandbox_init("testrepo"); retrieve_known_commit(&target, repo); cl_git_pass(git_branch_lookup(&branch2, repo, "master", GIT_BRANCH_LOCAL)); @@ -84,6 +88,26 @@ void test_refs_branches_create__cannot_force_create_over_current_branch(void) git_reference_free(branch2); } +void test_refs_branches_create__can_force_create_over_current_branch_in_bare_repo(void) +{ + const git_oid *oid; + git_reference *branch2; + retrieve_known_commit(&target, repo); + + cl_git_pass(git_branch_lookup(&branch2, repo, "master", GIT_BRANCH_LOCAL)); + cl_assert_equal_s("refs/heads/master", git_reference_name(branch2)); + cl_assert_equal_i(true, git_branch_is_head(branch2)); + oid = git_commit_id(target); + + cl_git_pass(git_branch_create(&branch, repo, "master", target, 1)); + git_reference_free(branch); + branch = NULL; + cl_git_pass(git_branch_lookup(&branch, repo, "master", GIT_BRANCH_LOCAL)); + cl_assert_equal_s("refs/heads/master", git_reference_name(branch)); + cl_git_pass(git_oid_cmp(git_reference_target(branch), oid)); + git_reference_free(branch2); +} + void test_refs_branches_create__creating_a_branch_with_an_invalid_name_returns_EINVALIDSPEC(void) { retrieve_known_commit(&target, repo); diff --git a/tests/refs/branches/upstream.c b/tests/refs/branches/upstream.c index 8f2e7a2ca..82f5665d8 100644 --- a/tests/refs/branches/upstream.c +++ b/tests/refs/branches/upstream.c @@ -175,7 +175,7 @@ void test_refs_branches_upstream__no_fetch_refspec(void) cl_git_pass(git_reference_lookup(&branch, repo, "refs/heads/test")); cl_git_pass(git_reference_create(&ref, repo, "refs/remotes/matching/master", git_reference_target(branch), 1, "fetch")); cl_git_fail(git_branch_set_upstream(branch, "matching/master")); - cl_assert_equal_s("Could not determine remote for 'refs/remotes/matching/master'", + cl_assert_equal_s("could not determine remote for 'refs/remotes/matching/master'", giterr_last()->message); /* we can't set it automatically, so let's test the user setting it by hand */ diff --git a/tests/refs/crashes.c b/tests/refs/crashes.c index 7a10411c8..228f479a0 100644 --- a/tests/refs/crashes.c +++ b/tests/refs/crashes.c @@ -6,7 +6,7 @@ void test_refs_crashes__double_free(void) git_reference *ref, *ref2; const char *REFNAME = "refs/heads/xxx"; - cl_git_pass(git_repository_open(&repo, cl_fixture("testrepo.git"))); + repo = cl_git_sandbox_init("testrepo.git"); cl_git_pass(git_reference_symbolic_create(&ref, repo, REFNAME, "refs/heads/master", 0, NULL)); cl_git_pass(git_reference_lookup(&ref2, repo, REFNAME)); cl_git_pass(git_reference_delete(ref)); @@ -16,5 +16,5 @@ void test_refs_crashes__double_free(void) /* reference is gone from disk, so reloading it will fail */ cl_git_fail(git_reference_lookup(&ref2, repo, REFNAME)); - git_repository_free(repo); + cl_git_sandbox_cleanup(); } diff --git a/tests/refs/create.c b/tests/refs/create.c index 6d5a5f1f6..469cddd1e 100644 --- a/tests/refs/create.c +++ b/tests/refs/create.c @@ -12,19 +12,22 @@ static git_repository *g_repo; void test_refs_create__initialize(void) { - g_repo = cl_git_sandbox_init("testrepo"); + g_repo = cl_git_sandbox_init("testrepo"); + p_fsync__cnt = 0; } void test_refs_create__cleanup(void) { - cl_git_sandbox_cleanup(); + cl_git_sandbox_cleanup(); cl_git_pass(git_libgit2_opts(GIT_OPT_ENABLE_STRICT_OBJECT_CREATION, 1)); + cl_git_pass(git_libgit2_opts(GIT_OPT_ENABLE_STRICT_SYMBOLIC_REF_CREATION, 1)); + cl_git_pass(git_libgit2_opts(GIT_OPT_ENABLE_FSYNC_GITDIR, 0)); } void test_refs_create__symbolic(void) { - // create a new symbolic reference + /* create a new symbolic reference */ git_reference *new_reference, *looked_up_ref, *resolved_ref; git_repository *repo2; git_oid id; @@ -65,9 +68,57 @@ void test_refs_create__symbolic(void) git_reference_free(resolved_ref); } +void test_refs_create__symbolic_with_arbitrary_content(void) +{ + git_reference *new_reference, *looked_up_ref; + git_repository *repo2; + git_oid id; + + const char *new_head_tracker = "ANOTHER_HEAD_TRACKER"; + const char *arbitrary_target = "ARBITRARY DATA"; + + git_oid_fromstr(&id, current_master_tip); + + /* Attempt to create symbolic ref with arbitrary data in target + * fails by default + */ + cl_git_fail(git_reference_symbolic_create(&new_reference, g_repo, new_head_tracker, arbitrary_target, 0, NULL)); + + git_libgit2_opts(GIT_OPT_ENABLE_STRICT_SYMBOLIC_REF_CREATION, 0); + + /* With strict target validation disabled, ref creation succeeds */ + cl_git_pass(git_reference_symbolic_create(&new_reference, g_repo, new_head_tracker, arbitrary_target, 0, NULL)); + + /* Ensure the reference can be looked-up... */ + cl_git_pass(git_reference_lookup(&looked_up_ref, g_repo, new_head_tracker)); + cl_assert(git_reference_type(looked_up_ref) & GIT_REF_SYMBOLIC); + cl_assert(reference_is_packed(looked_up_ref) == 0); + cl_assert_equal_s(looked_up_ref->name, new_head_tracker); + git_reference_free(looked_up_ref); + + /* Ensure the target is what we expect it to be */ + cl_assert_equal_s(git_reference_symbolic_target(new_reference), arbitrary_target); + + /* Similar test with a fresh new repository object */ + cl_git_pass(git_repository_open(&repo2, "testrepo")); + + /* Ensure the reference can be looked-up... */ + cl_git_pass(git_reference_lookup(&looked_up_ref, repo2, new_head_tracker)); + cl_assert(git_reference_type(looked_up_ref) & GIT_REF_SYMBOLIC); + cl_assert(reference_is_packed(looked_up_ref) == 0); + cl_assert_equal_s(looked_up_ref->name, new_head_tracker); + + /* Ensure the target is what we expect it to be */ + cl_assert_equal_s(git_reference_symbolic_target(new_reference), arbitrary_target); + + git_repository_free(repo2); + git_reference_free(new_reference); + git_reference_free(looked_up_ref); +} + void test_refs_create__deep_symbolic(void) { - // create a deep symbolic reference + /* create a deep symbolic reference */ git_reference *new_reference, *looked_up_ref, *resolved_ref; git_oid id; @@ -87,7 +138,7 @@ void test_refs_create__deep_symbolic(void) void test_refs_create__oid(void) { - // create a new OID reference + /* create a new OID reference */ git_reference *new_reference, *looked_up_ref; git_repository *repo2; git_oid id; @@ -248,3 +299,69 @@ void test_refs_create__creating_a_loose_ref_with_invalid_windows_name(void) test_win32_name("refs/heads/com1"); } + +/* Creating a loose ref involves fsync'ing the reference, the + * reflog and (on non-Windows) the containing directories. + * Creating a packed ref involves fsync'ing the packed ref file + * and (on non-Windows) the containing directory. + */ +#ifdef GIT_WIN32 +static int expected_fsyncs_create = 2, expected_fsyncs_compress = 1; +#else +static int expected_fsyncs_create = 4, expected_fsyncs_compress = 2; +#endif + +static void count_fsyncs(size_t *create_count, size_t *compress_count) +{ + git_reference *ref = NULL; + git_refdb *refdb; + git_oid id; + + p_fsync__cnt = 0; + + git_oid_fromstr(&id, current_master_tip); + cl_git_pass(git_reference_create(&ref, g_repo, "refs/heads/fsync_test", &id, 0, "log message")); + git_reference_free(ref); + + *create_count = p_fsync__cnt; + p_fsync__cnt = 0; + + cl_git_pass(git_repository_refdb(&refdb, g_repo)); + cl_git_pass(git_refdb_compress(refdb)); + git_refdb_free(refdb); + + *compress_count = p_fsync__cnt; + p_fsync__cnt = 0; +} + +void test_refs_create__does_not_fsync_by_default(void) +{ + size_t create_count, compress_count; + count_fsyncs(&create_count, &compress_count); + + cl_assert_equal_i(0, create_count); + cl_assert_equal_i(0, compress_count); +} + +void test_refs_create__fsyncs_when_global_opt_set(void) +{ + size_t create_count, compress_count; + + cl_git_pass(git_libgit2_opts(GIT_OPT_ENABLE_FSYNC_GITDIR, 1)); + count_fsyncs(&create_count, &compress_count); + + cl_assert_equal_i(expected_fsyncs_create, create_count); + cl_assert_equal_i(expected_fsyncs_compress, compress_count); +} + +void test_refs_create__fsyncs_when_repo_config_set(void) +{ + size_t create_count, compress_count; + + cl_repo_set_bool(g_repo, "core.fsyncObjectFiles", true); + + count_fsyncs(&create_count, &compress_count); + + cl_assert_equal_i(expected_fsyncs_create, create_count); + cl_assert_equal_i(expected_fsyncs_compress, compress_count); +} diff --git a/tests/refs/list.c b/tests/refs/list.c index 374943b05..f7ca3f707 100644 --- a/tests/refs/list.c +++ b/tests/refs/list.c @@ -36,7 +36,7 @@ void test_refs_list__all(void) /* We have exactly 12 refs in total if we include the packed ones: * there is a reference that exists both in the packfile and as * loose, but we only list it once */ - cl_assert_equal_i((int)ref_list.count, 15); + cl_assert_equal_i((int)ref_list.count, 17); git_strarray_free(&ref_list); } @@ -51,7 +51,7 @@ void test_refs_list__do_not_retrieve_references_which_name_end_with_a_lock_exten "144344043ba4d4a405da03de3844aa829ae8be0e\n"); cl_git_pass(git_reference_list(&ref_list, g_repo)); - cl_assert_equal_i((int)ref_list.count, 15); + cl_assert_equal_i((int)ref_list.count, 17); git_strarray_free(&ref_list); } diff --git a/tests/refs/namespaces.c b/tests/refs/namespaces.c new file mode 100644 index 000000000..bb6bb1ce0 --- /dev/null +++ b/tests/refs/namespaces.c @@ -0,0 +1,36 @@ +#include "clar_libgit2.h" + +#include "repository.h" + +static git_repository *g_repo; + +void test_refs_namespaces__initialize(void) +{ + g_repo = cl_git_sandbox_init("testrepo"); +} + +void test_refs_namespaces__cleanup(void) +{ + cl_git_sandbox_cleanup(); +} + +void test_refs_namespaces__get_and_set(void) +{ + cl_assert_equal_s(NULL, git_repository_get_namespace(g_repo)); + + cl_git_pass(git_repository_set_namespace(g_repo, "namespace")); + cl_assert_equal_s("namespace", git_repository_get_namespace(g_repo)); + + cl_git_pass(git_repository_set_namespace(g_repo, NULL)); + cl_assert_equal_s(NULL, git_repository_get_namespace(g_repo)); +} + +void test_refs_namespaces__namespace_doesnt_show_normal_refs(void) +{ + static git_strarray ref_list; + + cl_git_pass(git_repository_set_namespace(g_repo, "namespace")); + cl_git_pass(git_reference_list(&ref_list, g_repo)); + cl_assert_equal_i(0, ref_list.count); + git_strarray_free(&ref_list); +} diff --git a/tests/refs/reflog/reflog.c b/tests/refs/reflog/reflog.c index fdb15502c..252242152 100644 --- a/tests/refs/reflog/reflog.c +++ b/tests/refs/reflog/reflog.c @@ -4,7 +4,7 @@ #include "git2/reflog.h" #include "reflog.h" - +static const char *merge_reflog_message = "commit (merge): Merge commit"; static const char *new_ref = "refs/heads/test-reflog"; static const char *current_master_tip = "a65fedf39aefe402d3bb6e24df4d4f5fe4547750"; #define commit_msg "commit: bla bla" @@ -261,7 +261,7 @@ void test_refs_reflog_reflog__reading_a_reflog_with_invalid_format_returns_error error = giterr_last(); cl_assert(error != NULL); - cl_assert_equal_s("Unable to parse OID - contains invalid characters", error->message); + cl_assert_equal_s("unable to parse OID - contains invalid characters", error->message); git_reference_free(ref); git_buf_free(&logpath); @@ -448,3 +448,45 @@ void test_refs_reflog_reflog__logallrefupdates_nonbare_set_false(void) assert_no_reflog_update(); } + +void test_refs_reflog_reflog__show_merge_for_merge_commits(void) +{ + git_oid b1_oid; + git_oid b2_oid; + git_oid merge_commit_oid; + git_commit *b1_commit; + git_commit *b2_commit; + git_signature *s; + git_commit *parent_commits[2]; + git_tree *tree; + git_reflog *log; + const git_reflog_entry *entry; + + cl_git_pass(git_signature_now(&s, "alice", "alice@example.com")); + + cl_git_pass(git_reference_name_to_id(&b1_oid, g_repo, "HEAD")); + cl_git_pass(git_reference_name_to_id(&b2_oid, g_repo, "refs/heads/test")); + + cl_git_pass(git_commit_lookup(&b1_commit, g_repo, &b1_oid)); + cl_git_pass(git_commit_lookup(&b2_commit, g_repo, &b2_oid)); + + parent_commits[0] = b1_commit; + parent_commits[1] = b2_commit; + + cl_git_pass(git_commit_tree(&tree, b1_commit)); + + cl_git_pass(git_commit_create(&merge_commit_oid, + g_repo, "HEAD", s, s, NULL, + "Merge commit", tree, + 2, (const struct git_commit **) parent_commits)); + + cl_git_pass(git_reflog_read(&log, g_repo, "HEAD")); + entry = git_reflog_entry_byindex(log, 0); + cl_assert_equal_s(merge_reflog_message, git_reflog_entry_message(entry)); + + git_reflog_free(log); + git_tree_free(tree); + git_commit_free(b1_commit); + git_commit_free(b2_commit); + git_signature_free(s); +} diff --git a/tests/refs/revparse.c b/tests/refs/revparse.c index c22c30440..459188cf7 100644 --- a/tests/refs/revparse.c +++ b/tests/refs/revparse.c @@ -122,6 +122,14 @@ static void test_id( test_id_inrepo(spec, expected_left, expected_right, expected_flags, g_repo); } +static void test_invalid_revspec(const char* invalid_spec) +{ + git_revspec revspec; + + cl_assert_equal_i( + GIT_EINVALIDSPEC, git_revparse(&revspec, g_repo, invalid_spec)); +} + void test_refs_revparse__initialize(void) { cl_git_pass(git_repository_open(&g_repo, cl_fixture("testrepo.git"))); @@ -749,6 +757,33 @@ void test_refs_revparse__parses_range_operator(void) "4a202b346bb0fb0db7eff3cffeb3c70babbd2045", "a65fedf39aefe402d3bb6e24df4d4f5fe4547750", GIT_REVPARSE_RANGE | GIT_REVPARSE_MERGE_BASE); + + test_id("HEAD~3..", + "4a202b346bb0fb0db7eff3cffeb3c70babbd2045", + "a65fedf39aefe402d3bb6e24df4d4f5fe4547750", + GIT_REVPARSE_RANGE); + + test_id("HEAD~3...", + "4a202b346bb0fb0db7eff3cffeb3c70babbd2045", + "a65fedf39aefe402d3bb6e24df4d4f5fe4547750", + GIT_REVPARSE_RANGE | GIT_REVPARSE_MERGE_BASE); + + test_id("..HEAD~3", + "a65fedf39aefe402d3bb6e24df4d4f5fe4547750", + "4a202b346bb0fb0db7eff3cffeb3c70babbd2045", + GIT_REVPARSE_RANGE); + + test_id("...HEAD~3", + "a65fedf39aefe402d3bb6e24df4d4f5fe4547750", + "4a202b346bb0fb0db7eff3cffeb3c70babbd2045", + GIT_REVPARSE_RANGE | GIT_REVPARSE_MERGE_BASE); + + test_id("...", + "a65fedf39aefe402d3bb6e24df4d4f5fe4547750", + "a65fedf39aefe402d3bb6e24df4d4f5fe4547750", + GIT_REVPARSE_RANGE | GIT_REVPARSE_MERGE_BASE); + + test_invalid_revspec(".."); } void test_refs_revparse__ext_retrieves_both_the_reference_and_its_target(void) diff --git a/tests/repo/discover.c b/tests/repo/discover.c index 358daee9f..eadd055e9 100644 --- a/tests/repo/discover.c +++ b/tests/repo/discover.c @@ -9,6 +9,7 @@ #define SUB_REPOSITORY_FOLDER_NAME "sub_repo" #define SUB_REPOSITORY_FOLDER DISCOVER_FOLDER "/" SUB_REPOSITORY_FOLDER_NAME +#define SUB_REPOSITORY_GITDIR SUB_REPOSITORY_FOLDER "/.git" #define SUB_REPOSITORY_FOLDER_SUB SUB_REPOSITORY_FOLDER "/sub" #define SUB_REPOSITORY_FOLDER_SUB_SUB SUB_REPOSITORY_FOLDER_SUB "/subsub" #define SUB_REPOSITORY_FOLDER_SUB_SUB_SUB SUB_REPOSITORY_FOLDER_SUB_SUB "/subsubsub" @@ -24,20 +25,26 @@ #define ALTERNATE_NOT_FOUND_FOLDER DISCOVER_FOLDER "/alternate_not_found_repo" static void ensure_repository_discover(const char *start_path, - const char *ceiling_dirs, - git_buf *expected_path) + const char *ceiling_dirs, + const char *expected_path) { - git_buf found_path = GIT_BUF_INIT; - cl_git_pass(git_repository_discover(&found_path, start_path, 0, ceiling_dirs)); - //across_fs is always 0 as we can't automate the filesystem change tests - cl_assert_equal_s(found_path.ptr, expected_path->ptr); + git_buf found_path = GIT_BUF_INIT, resolved = GIT_BUF_INIT; + + git_buf_attach(&resolved, p_realpath(expected_path, NULL), 0); + cl_assert(resolved.size > 0); + cl_git_pass(git_path_to_dir(&resolved)); + cl_git_pass(git_repository_discover(&found_path, start_path, 1, ceiling_dirs)); + + cl_assert_equal_s(found_path.ptr, resolved.ptr); + + git_buf_free(&resolved); git_buf_free(&found_path); } static void write_file(const char *path, const char *content) { git_file file; - int error; + int error; if (git_path_exists(path)) { cl_git_pass(p_unlink(path)); @@ -68,42 +75,30 @@ static void append_ceiling_dir(git_buf *ceiling_dirs, const char *path) cl_assert(git_buf_oom(ceiling_dirs) == 0); } -void test_repo_discover__0(void) +static git_buf discovered; +static git_buf ceiling_dirs; + +void test_repo_discover__initialize(void) { - // test discover git_repository *repo; - git_buf ceiling_dirs_buf = GIT_BUF_INIT, repository_path = GIT_BUF_INIT, - sub_repository_path = GIT_BUF_INIT, found_path = GIT_BUF_INIT; - const char *ceiling_dirs; const mode_t mode = 0777; - git_futils_mkdir_r(DISCOVER_FOLDER, mode); - append_ceiling_dir(&ceiling_dirs_buf, TEMP_REPO_FOLDER); - ceiling_dirs = git_buf_cstr(&ceiling_dirs_buf); - cl_assert_equal_i(GIT_ENOTFOUND, git_repository_discover(&repository_path, DISCOVER_FOLDER, 0, ceiling_dirs)); + git_buf_init(&discovered, 0); + git_buf_init(&ceiling_dirs, 0); + append_ceiling_dir(&ceiling_dirs, TEMP_REPO_FOLDER); cl_git_pass(git_repository_init(&repo, DISCOVER_FOLDER, 1)); - cl_git_pass(git_repository_discover(&repository_path, DISCOVER_FOLDER, 0, ceiling_dirs)); git_repository_free(repo); cl_git_pass(git_repository_init(&repo, SUB_REPOSITORY_FOLDER, 0)); cl_git_pass(git_futils_mkdir_r(SUB_REPOSITORY_FOLDER_SUB_SUB_SUB, mode)); - cl_git_pass(git_repository_discover(&sub_repository_path, SUB_REPOSITORY_FOLDER, 0, ceiling_dirs)); - cl_git_pass(git_futils_mkdir_r(SUB_REPOSITORY_FOLDER_SUB_SUB_SUB, mode)); - ensure_repository_discover(SUB_REPOSITORY_FOLDER_SUB, ceiling_dirs, &sub_repository_path); - ensure_repository_discover(SUB_REPOSITORY_FOLDER_SUB_SUB, ceiling_dirs, &sub_repository_path); - ensure_repository_discover(SUB_REPOSITORY_FOLDER_SUB_SUB_SUB, ceiling_dirs, &sub_repository_path); cl_git_pass(git_futils_mkdir_r(REPOSITORY_ALTERNATE_FOLDER_SUB_SUB_SUB, mode)); write_file(REPOSITORY_ALTERNATE_FOLDER "/" DOT_GIT, "gitdir: ../" SUB_REPOSITORY_FOLDER_NAME "/" DOT_GIT); write_file(REPOSITORY_ALTERNATE_FOLDER_SUB_SUB "/" DOT_GIT, "gitdir: ../../../" SUB_REPOSITORY_FOLDER_NAME "/" DOT_GIT); write_file(REPOSITORY_ALTERNATE_FOLDER_SUB_SUB_SUB "/" DOT_GIT, "gitdir: ../../../../"); - ensure_repository_discover(REPOSITORY_ALTERNATE_FOLDER, ceiling_dirs, &sub_repository_path); - ensure_repository_discover(REPOSITORY_ALTERNATE_FOLDER_SUB, ceiling_dirs, &sub_repository_path); - ensure_repository_discover(REPOSITORY_ALTERNATE_FOLDER_SUB_SUB, ceiling_dirs, &sub_repository_path); - ensure_repository_discover(REPOSITORY_ALTERNATE_FOLDER_SUB_SUB_SUB, ceiling_dirs, &repository_path); cl_git_pass(git_futils_mkdir_r(ALTERNATE_MALFORMED_FOLDER1, mode)); write_file(ALTERNATE_MALFORMED_FOLDER1 "/" DOT_GIT, "Anything but not gitdir:"); @@ -113,41 +108,103 @@ void test_repo_discover__0(void) write_file(ALTERNATE_MALFORMED_FOLDER3 "/" DOT_GIT, "gitdir: \n\n\n"); cl_git_pass(git_futils_mkdir_r(ALTERNATE_NOT_FOUND_FOLDER, mode)); write_file(ALTERNATE_NOT_FOUND_FOLDER "/" DOT_GIT, "gitdir: a_repository_that_surely_does_not_exist"); - cl_git_fail(git_repository_discover(&found_path, ALTERNATE_MALFORMED_FOLDER1, 0, ceiling_dirs)); - cl_git_fail(git_repository_discover(&found_path, ALTERNATE_MALFORMED_FOLDER2, 0, ceiling_dirs)); - cl_git_fail(git_repository_discover(&found_path, ALTERNATE_MALFORMED_FOLDER3, 0, ceiling_dirs)); - cl_assert_equal_i(GIT_ENOTFOUND, git_repository_discover(&found_path, ALTERNATE_NOT_FOUND_FOLDER, 0, ceiling_dirs)); - append_ceiling_dir(&ceiling_dirs_buf, SUB_REPOSITORY_FOLDER_SUB); - ceiling_dirs = git_buf_cstr(&ceiling_dirs_buf); + git_repository_free(repo); +} + +void test_repo_discover__cleanup(void) +{ + git_buf_free(&discovered); + git_buf_free(&ceiling_dirs); + cl_git_pass(git_futils_rmdir_r(TEMP_REPO_FOLDER, NULL, GIT_RMDIR_REMOVE_FILES)); +} + +void test_repo_discover__discovering_repo_with_exact_path_succeeds(void) +{ + cl_git_pass(git_repository_discover(&discovered, DISCOVER_FOLDER, 0, ceiling_dirs.ptr)); + cl_git_pass(git_repository_discover(&discovered, SUB_REPOSITORY_FOLDER, 0, ceiling_dirs.ptr)); +} + +void test_repo_discover__discovering_nonexistent_dir_fails(void) +{ + cl_assert_equal_i(GIT_ENOTFOUND, git_repository_discover(&discovered, DISCOVER_FOLDER "-nonexistent", 0, NULL)); +} + +void test_repo_discover__discovering_repo_with_subdirectory_succeeds(void) +{ + ensure_repository_discover(SUB_REPOSITORY_FOLDER_SUB, ceiling_dirs.ptr, SUB_REPOSITORY_GITDIR); + ensure_repository_discover(SUB_REPOSITORY_FOLDER_SUB_SUB, ceiling_dirs.ptr, SUB_REPOSITORY_GITDIR); + ensure_repository_discover(SUB_REPOSITORY_FOLDER_SUB_SUB_SUB, ceiling_dirs.ptr, SUB_REPOSITORY_GITDIR); +} + +void test_repo_discover__discovering_repository_with_alternative_gitdir_succeeds(void) +{ + ensure_repository_discover(REPOSITORY_ALTERNATE_FOLDER, ceiling_dirs.ptr, SUB_REPOSITORY_GITDIR); + ensure_repository_discover(REPOSITORY_ALTERNATE_FOLDER_SUB, ceiling_dirs.ptr, SUB_REPOSITORY_GITDIR); + ensure_repository_discover(REPOSITORY_ALTERNATE_FOLDER_SUB_SUB, ceiling_dirs.ptr, SUB_REPOSITORY_GITDIR); + ensure_repository_discover(REPOSITORY_ALTERNATE_FOLDER_SUB_SUB_SUB, ceiling_dirs.ptr, DISCOVER_FOLDER); +} + +void test_repo_discover__discovering_repository_with_malformed_alternative_gitdir_fails(void) +{ + cl_git_fail(git_repository_discover(&discovered, ALTERNATE_MALFORMED_FOLDER1, 0, ceiling_dirs.ptr)); + cl_git_fail(git_repository_discover(&discovered, ALTERNATE_MALFORMED_FOLDER2, 0, ceiling_dirs.ptr)); + cl_git_fail(git_repository_discover(&discovered, ALTERNATE_MALFORMED_FOLDER3, 0, ceiling_dirs.ptr)); + cl_assert_equal_i(GIT_ENOTFOUND, git_repository_discover(&discovered, ALTERNATE_NOT_FOUND_FOLDER, 0, ceiling_dirs.ptr)); +} + +void test_repo_discover__discovering_repository_with_ceiling(void) +{ + append_ceiling_dir(&ceiling_dirs, SUB_REPOSITORY_FOLDER_SUB); /* this must pass as ceiling_directories cannot prevent the current * working directory to be checked */ - ensure_repository_discover(SUB_REPOSITORY_FOLDER, ceiling_dirs, &sub_repository_path); - ensure_repository_discover(SUB_REPOSITORY_FOLDER_SUB, ceiling_dirs, &sub_repository_path); - cl_assert_equal_i(GIT_ENOTFOUND, git_repository_discover(&found_path, SUB_REPOSITORY_FOLDER_SUB_SUB, 0, ceiling_dirs)); - cl_assert_equal_i(GIT_ENOTFOUND, git_repository_discover(&found_path, SUB_REPOSITORY_FOLDER_SUB_SUB_SUB, 0, ceiling_dirs)); - - append_ceiling_dir(&ceiling_dirs_buf, SUB_REPOSITORY_FOLDER); - ceiling_dirs = git_buf_cstr(&ceiling_dirs_buf); - - //this must pass as ceiling_directories cannot predent the current - //working directory to be checked - ensure_repository_discover(SUB_REPOSITORY_FOLDER, ceiling_dirs, &sub_repository_path); - cl_assert_equal_i(GIT_ENOTFOUND, git_repository_discover(&found_path, SUB_REPOSITORY_FOLDER_SUB, 0, ceiling_dirs)); - cl_assert_equal_i(GIT_ENOTFOUND, git_repository_discover(&found_path, SUB_REPOSITORY_FOLDER_SUB_SUB, 0, ceiling_dirs)); - cl_assert_equal_i(GIT_ENOTFOUND, git_repository_discover(&found_path, SUB_REPOSITORY_FOLDER_SUB_SUB_SUB, 0, ceiling_dirs)); - - //.gitfile redirection should not be affected by ceiling directories - ensure_repository_discover(REPOSITORY_ALTERNATE_FOLDER, ceiling_dirs, &sub_repository_path); - ensure_repository_discover(REPOSITORY_ALTERNATE_FOLDER_SUB, ceiling_dirs, &sub_repository_path); - ensure_repository_discover(REPOSITORY_ALTERNATE_FOLDER_SUB_SUB, ceiling_dirs, &sub_repository_path); - ensure_repository_discover(REPOSITORY_ALTERNATE_FOLDER_SUB_SUB_SUB, ceiling_dirs, &repository_path); + ensure_repository_discover(SUB_REPOSITORY_FOLDER, ceiling_dirs.ptr, SUB_REPOSITORY_GITDIR); - cl_git_pass(git_futils_rmdir_r(TEMP_REPO_FOLDER, NULL, GIT_RMDIR_REMOVE_FILES)); - git_repository_free(repo); - git_buf_free(&ceiling_dirs_buf); - git_buf_free(&repository_path); - git_buf_free(&sub_repository_path); + ensure_repository_discover(SUB_REPOSITORY_FOLDER_SUB, ceiling_dirs.ptr, SUB_REPOSITORY_GITDIR); + cl_assert_equal_i(GIT_ENOTFOUND, git_repository_discover(&discovered, SUB_REPOSITORY_FOLDER_SUB_SUB, 0, ceiling_dirs.ptr)); + cl_assert_equal_i(GIT_ENOTFOUND, git_repository_discover(&discovered, SUB_REPOSITORY_FOLDER_SUB_SUB_SUB, 0, ceiling_dirs.ptr)); +} + +void test_repo_discover__other_ceiling(void) +{ + append_ceiling_dir(&ceiling_dirs, SUB_REPOSITORY_FOLDER); + + /* this must pass as ceiling_directories cannot predent the current + * working directory to be checked */ + ensure_repository_discover(SUB_REPOSITORY_FOLDER, ceiling_dirs.ptr, SUB_REPOSITORY_GITDIR); + + cl_assert_equal_i(GIT_ENOTFOUND, git_repository_discover(&discovered, SUB_REPOSITORY_FOLDER_SUB, 0, ceiling_dirs.ptr)); + cl_assert_equal_i(GIT_ENOTFOUND, git_repository_discover(&discovered, SUB_REPOSITORY_FOLDER_SUB_SUB, 0, ceiling_dirs.ptr)); + cl_assert_equal_i(GIT_ENOTFOUND, git_repository_discover(&discovered, SUB_REPOSITORY_FOLDER_SUB_SUB_SUB, 0, ceiling_dirs.ptr)); +} + +void test_repo_discover__ceiling_should_not_affect_gitdir_redirection(void) +{ + append_ceiling_dir(&ceiling_dirs, SUB_REPOSITORY_FOLDER); + + /* gitfile redirection should not be affected by ceiling directories */ + ensure_repository_discover(REPOSITORY_ALTERNATE_FOLDER, ceiling_dirs.ptr, SUB_REPOSITORY_GITDIR); + ensure_repository_discover(REPOSITORY_ALTERNATE_FOLDER_SUB, ceiling_dirs.ptr, SUB_REPOSITORY_GITDIR); + ensure_repository_discover(REPOSITORY_ALTERNATE_FOLDER_SUB_SUB, ceiling_dirs.ptr, SUB_REPOSITORY_GITDIR); + ensure_repository_discover(REPOSITORY_ALTERNATE_FOLDER_SUB_SUB_SUB, ceiling_dirs.ptr, DISCOVER_FOLDER); +} + +void test_repo_discover__discovery_starting_at_file_succeeds(void) +{ + int fd; + + cl_assert((fd = p_creat(SUB_REPOSITORY_FOLDER "/file", 0600)) >= 0); + cl_assert(p_close(fd) == 0); + + ensure_repository_discover(SUB_REPOSITORY_FOLDER "/file", ceiling_dirs.ptr, SUB_REPOSITORY_GITDIR); } +void test_repo_discover__discovery_starting_at_system_root_causes_no_hang(void) +{ +#ifdef GIT_WIN32 + git_buf out = GIT_BUF_INIT; + cl_git_fail(git_repository_discover(&out, "C:/", 0, NULL)); + cl_git_fail(git_repository_discover(&out, "//localhost/", 0, NULL)); +#endif +} diff --git a/tests/repo/env.c b/tests/repo/env.c index 5a89c0d49..6404f88e9 100644 --- a/tests/repo/env.c +++ b/tests/repo/env.c @@ -56,8 +56,8 @@ static int GIT_FORMAT_PRINTF(2, 3) cl_setenv_printf(const char *name, const char static void env_pass_(const char *path, const char *file, int line) { git_repository *repo; - cl_git_pass_(git_repository_open_ext(NULL, path, GIT_REPOSITORY_OPEN_FROM_ENV, NULL), file, line); - cl_git_pass_(git_repository_open_ext(&repo, path, GIT_REPOSITORY_OPEN_FROM_ENV, NULL), file, line); + cl_git_expect(git_repository_open_ext(NULL, path, GIT_REPOSITORY_OPEN_FROM_ENV, NULL), 0, file, line); + cl_git_expect(git_repository_open_ext(&repo, path, GIT_REPOSITORY_OPEN_FROM_ENV, NULL), 0, file, line); cl_assert_at_line(git__suffixcmp(git_repository_path(repo), "attr/.git/") == 0, file, line); cl_assert_at_line(git__suffixcmp(git_repository_workdir(repo), "attr/") == 0, file, line); cl_assert_at_line(!git_repository_is_bare(repo), file, line); @@ -98,24 +98,24 @@ static void env_check_objects_(bool a, bool t, bool p, const char *file, int lin cl_git_pass(git_oid_fromstr(&oid_a, "45141a79a77842c59a63229403220a4e4be74e3d")); cl_git_pass(git_oid_fromstr(&oid_t, "1385f264afb75a56a5bec74243be9b367ba4ca08")); cl_git_pass(git_oid_fromstr(&oid_p, "0df1a5865c8abfc09f1f2182e6a31be550e99f07")); - cl_git_pass_(git_repository_open_ext(&repo, "attr", GIT_REPOSITORY_OPEN_FROM_ENV, NULL), file, line); + cl_git_expect(git_repository_open_ext(&repo, "attr", GIT_REPOSITORY_OPEN_FROM_ENV, NULL), 0, file, line); if (a) { - cl_git_pass_(git_object_lookup(&object, repo, &oid_a, GIT_OBJ_BLOB), file, line); + cl_git_expect(git_object_lookup(&object, repo, &oid_a, GIT_OBJ_BLOB), 0, file, line); git_object_free(object); } else { cl_git_fail_at_line(git_object_lookup(&object, repo, &oid_a, GIT_OBJ_BLOB), file, line); } if (t) { - cl_git_pass_(git_object_lookup(&object, repo, &oid_t, GIT_OBJ_BLOB), file, line); + cl_git_expect(git_object_lookup(&object, repo, &oid_t, GIT_OBJ_BLOB), 0, file, line); git_object_free(object); } else { cl_git_fail_at_line(git_object_lookup(&object, repo, &oid_t, GIT_OBJ_BLOB), file, line); } if (p) { - cl_git_pass_(git_object_lookup(&object, repo, &oid_p, GIT_OBJ_COMMIT), file, line); + cl_git_expect(git_object_lookup(&object, repo, &oid_p, GIT_OBJ_COMMIT), 0, file, line); git_object_free(object); } else { cl_git_fail_at_line(git_object_lookup(&object, repo, &oid_p, GIT_OBJ_COMMIT), file, line); diff --git a/tests/repo/head.c b/tests/repo/head.c index 31c228777..d02116087 100644 --- a/tests/repo/head.c +++ b/tests/repo/head.c @@ -261,15 +261,19 @@ void test_repo_head__setting_head_updates_reflog(void) cl_git_pass(git_revparse_single(&tag, repo, "tags/test")); cl_git_pass(git_repository_set_head_detached(repo, git_object_id(tag))); cl_git_pass(git_repository_set_head(repo, "refs/heads/haacked")); + cl_git_pass(git_repository_set_head(repo, "refs/tags/test")); + cl_git_pass(git_repository_set_head(repo, "refs/remotes/test/master")); - test_reflog(repo, 2, NULL, "refs/heads/haacked", "foo@example.com", "checkout: moving from master to haacked"); - test_reflog(repo, 1, NULL, "tags/test^{commit}", "foo@example.com", "checkout: moving from unborn to e90810b8df3e80c413d903f631643c716887138d"); - test_reflog(repo, 0, "tags/test^{commit}", "refs/heads/haacked", "foo@example.com", "checkout: moving from e90810b8df3e80c413d903f631643c716887138d to haacked"); + test_reflog(repo, 4, NULL, "refs/heads/haacked", "foo@example.com", "checkout: moving from master to haacked"); + test_reflog(repo, 3, NULL, "tags/test^{commit}", "foo@example.com", "checkout: moving from unborn to e90810b8df3e80c413d903f631643c716887138d"); + test_reflog(repo, 2, "tags/test^{commit}", "refs/heads/haacked", "foo@example.com", "checkout: moving from e90810b8df3e80c413d903f631643c716887138d to haacked"); + test_reflog(repo, 1, "refs/heads/haacked", "tags/test^{commit}", "foo@example.com", "checkout: moving from haacked to test"); + test_reflog(repo, 0, "tags/test^{commit}", "refs/remotes/test/master", "foo@example.com", "checkout: moving from e90810b8df3e80c413d903f631643c716887138d to test/master"); cl_git_pass(git_annotated_commit_from_revspec(&annotated, repo, "haacked~0")); cl_git_pass(git_repository_set_head_detached_from_annotated(repo, annotated)); - test_reflog(repo, 0, NULL, "refs/heads/haacked", "foo@example.com", "checkout: moving from haacked to haacked~0"); + test_reflog(repo, 0, NULL, "refs/heads/haacked", "foo@example.com", "checkout: moving from be3563ae3f795b2b4353bcce3a527ad0a4f7f644 to haacked~0"); git_annotated_commit_free(annotated); git_object_free(tag); diff --git a/tests/repo/init.c b/tests/repo/init.c index 04d4a5c5e..6a455bfa6 100644 --- a/tests/repo/init.c +++ b/tests/repo/init.c @@ -320,6 +320,17 @@ void test_repo_init__sets_logAllRefUpdates_according_to_type_of_repository(void) assert_config_entry_on_init_bytype("core.logallrefupdates", true, false); } +void test_repo_init__empty_template_path(void) +{ + git_repository_init_options opts = GIT_REPOSITORY_INIT_OPTIONS_INIT; + opts.template_path = ""; + + cl_git_pass(git_futils_mkdir("foo", 0755, 0)); + cl_git_pass(git_repository_init_ext(&_repo, "foo", &opts)); + + cleanup_repository("foo"); +} + void test_repo_init__extended_0(void) { git_repository_init_options opts = GIT_REPOSITORY_INIT_OPTIONS_INIT; diff --git a/tests/repo/open.c b/tests/repo/open.c index 6114ad2e1..3239b6fec 100644 --- a/tests/repo/open.c +++ b/tests/repo/open.c @@ -398,7 +398,8 @@ void test_repo_open__force_bare(void) cl_git_fail(git_repository_open_bare(&barerepo, "alternate/subdir/sub2")); cl_git_pass(git_repository_open_ext( - &barerepo, "alternate/subdir/sub2", GIT_REPOSITORY_OPEN_BARE, NULL)); + &barerepo, "alternate/subdir/sub2", + GIT_REPOSITORY_OPEN_BARE|GIT_REPOSITORY_OPEN_CROSS_FS, NULL)); cl_assert(git_repository_is_bare(barerepo)); git_repository_free(barerepo); } diff --git a/tests/resources/diff_format_email/.gitted/index b/tests/resources/diff_format_email/.gitted/index Binary files differindex d94f87de8..092a888e7 100644 --- a/tests/resources/diff_format_email/.gitted/index +++ b/tests/resources/diff_format_email/.gitted/index diff --git a/tests/resources/diff_format_email/.gitted/objects/06/b7b69a62cbd1e53c6c4e0c3f16473dcfdb4af6 b/tests/resources/diff_format_email/.gitted/objects/06/b7b69a62cbd1e53c6c4e0c3f16473dcfdb4af6 Binary files differnew file mode 100644 index 000000000..37588f169 --- /dev/null +++ b/tests/resources/diff_format_email/.gitted/objects/06/b7b69a62cbd1e53c6c4e0c3f16473dcfdb4af6 diff --git a/tests/resources/diff_format_email/.gitted/objects/52/19b9784f9a92d7bd7cb567a6d6a21bfb86697e b/tests/resources/diff_format_email/.gitted/objects/52/19b9784f9a92d7bd7cb567a6d6a21bfb86697e Binary files differnew file mode 100644 index 000000000..534e3b07d --- /dev/null +++ b/tests/resources/diff_format_email/.gitted/objects/52/19b9784f9a92d7bd7cb567a6d6a21bfb86697e diff --git a/tests/resources/diff_format_email/.gitted/objects/53/525d4cc3ef3ba4a5cbf69492fdffb4e4a74558 b/tests/resources/diff_format_email/.gitted/objects/53/525d4cc3ef3ba4a5cbf69492fdffb4e4a74558 Binary files differnew file mode 100644 index 000000000..b74d31f4f --- /dev/null +++ b/tests/resources/diff_format_email/.gitted/objects/53/525d4cc3ef3ba4a5cbf69492fdffb4e4a74558 diff --git a/tests/resources/diff_format_email/.gitted/objects/a7/a65f98355b5a7567bcc395f6f7936c9252cf57 b/tests/resources/diff_format_email/.gitted/objects/a7/a65f98355b5a7567bcc395f6f7936c9252cf57 Binary files differnew file mode 100644 index 000000000..36a4b7be6 --- /dev/null +++ b/tests/resources/diff_format_email/.gitted/objects/a7/a65f98355b5a7567bcc395f6f7936c9252cf57 diff --git a/tests/resources/diff_format_email/.gitted/objects/c7/1a05d36025c806496a74d46d7d596eb23295c4 b/tests/resources/diff_format_email/.gitted/objects/c7/1a05d36025c806496a74d46d7d596eb23295c4 Binary files differnew file mode 100644 index 000000000..2822fe3e4 --- /dev/null +++ b/tests/resources/diff_format_email/.gitted/objects/c7/1a05d36025c806496a74d46d7d596eb23295c4 diff --git a/tests/resources/diff_format_email/.gitted/objects/d3/b6b38486f620b5b532a8cc6e0198ab7c3f52e4 b/tests/resources/diff_format_email/.gitted/objects/d3/b6b38486f620b5b532a8cc6e0198ab7c3f52e4 Binary files differnew file mode 100644 index 000000000..5b2e664f4 --- /dev/null +++ b/tests/resources/diff_format_email/.gitted/objects/d3/b6b38486f620b5b532a8cc6e0198ab7c3f52e4 diff --git a/tests/resources/diff_format_email/.gitted/refs/heads/master b/tests/resources/diff_format_email/.gitted/refs/heads/master index 3bc734d47..4024b97cd 100644 --- a/tests/resources/diff_format_email/.gitted/refs/heads/master +++ b/tests/resources/diff_format_email/.gitted/refs/heads/master @@ -1 +1 @@ -627e7e12d87e07a83fad5b6bfa25e86ead4a5270 +5219b9784f9a92d7bd7cb567a6d6a21bfb86697e diff --git a/tests/resources/diff_format_email/file3.txt b/tests/resources/diff_format_email/file3.txt index 730965344..c71a05d36 100644 --- a/tests/resources/diff_format_email/file3.txt +++ b/tests/resources/diff_format_email/file3.txt @@ -4,3 +4,4 @@ file3 file3 file3 file3 +file3 diff --git a/tests/resources/indexv4/.gitted/HEAD b/tests/resources/indexv4/.gitted/HEAD new file mode 100644 index 000000000..cb089cd89 --- /dev/null +++ b/tests/resources/indexv4/.gitted/HEAD @@ -0,0 +1 @@ +ref: refs/heads/master diff --git a/tests/resources/indexv4/.gitted/config b/tests/resources/indexv4/.gitted/config new file mode 100644 index 000000000..515f48362 --- /dev/null +++ b/tests/resources/indexv4/.gitted/config @@ -0,0 +1,5 @@ +[core] + repositoryformatversion = 0 + filemode = true + bare = false + logallrefupdates = true diff --git a/tests/resources/indexv4/.gitted/index b/tests/resources/indexv4/.gitted/index Binary files differnew file mode 100644 index 000000000..e8fc61736 --- /dev/null +++ b/tests/resources/indexv4/.gitted/index diff --git a/tests/resources/indexv4/.gitted/objects/4c/9109b3e671d851eec87e0e72f6305b582e7e99 b/tests/resources/indexv4/.gitted/objects/4c/9109b3e671d851eec87e0e72f6305b582e7e99 Binary files differnew file mode 100644 index 000000000..cedd594b0 --- /dev/null +++ b/tests/resources/indexv4/.gitted/objects/4c/9109b3e671d851eec87e0e72f6305b582e7e99 diff --git a/tests/resources/indexv4/.gitted/objects/b0/952dbb50bed5f01e03e31b296184cb183e54a7 b/tests/resources/indexv4/.gitted/objects/b0/952dbb50bed5f01e03e31b296184cb183e54a7 Binary files differnew file mode 100644 index 000000000..0ddc1d1a9 --- /dev/null +++ b/tests/resources/indexv4/.gitted/objects/b0/952dbb50bed5f01e03e31b296184cb183e54a7 diff --git a/tests/resources/indexv4/.gitted/objects/e6/9de29bb2d1d6434b8b29ae775ad8c2e48c5391 b/tests/resources/indexv4/.gitted/objects/e6/9de29bb2d1d6434b8b29ae775ad8c2e48c5391 Binary files differnew file mode 100644 index 000000000..711223894 --- /dev/null +++ b/tests/resources/indexv4/.gitted/objects/e6/9de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/tests/resources/indexv4/.gitted/refs/heads/master b/tests/resources/indexv4/.gitted/refs/heads/master new file mode 100644 index 000000000..f3e960eb3 --- /dev/null +++ b/tests/resources/indexv4/.gitted/refs/heads/master @@ -0,0 +1 @@ +b0952dbb50bed5f01e03e31b296184cb183e54a7 diff --git a/tests/resources/indexv4/file.tx b/tests/resources/indexv4/file.tx new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/tests/resources/indexv4/file.tx diff --git a/tests/resources/indexv4/file.txt b/tests/resources/indexv4/file.txt new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/tests/resources/indexv4/file.txt diff --git a/tests/resources/indexv4/file.txz b/tests/resources/indexv4/file.txz new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/tests/resources/indexv4/file.txz diff --git a/tests/resources/indexv4/foo b/tests/resources/indexv4/foo new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/tests/resources/indexv4/foo diff --git a/tests/resources/indexv4/zzz b/tests/resources/indexv4/zzz new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/tests/resources/indexv4/zzz diff --git a/tests/resources/merge-resolve/.gitted/objects/2a/f2d9bcbc73723ac988bb202d4397f72a6ca7a0 b/tests/resources/merge-resolve/.gitted/objects/2a/f2d9bcbc73723ac988bb202d4397f72a6ca7a0 Binary files differnew file mode 100644 index 000000000..0d658237b --- /dev/null +++ b/tests/resources/merge-resolve/.gitted/objects/2a/f2d9bcbc73723ac988bb202d4397f72a6ca7a0 diff --git a/tests/resources/merge-resolve/.gitted/objects/37/f53a5a14f64e91089a39ea58e71c87d81df765 b/tests/resources/merge-resolve/.gitted/objects/37/f53a5a14f64e91089a39ea58e71c87d81df765 new file mode 100644 index 000000000..95327ed64 --- /dev/null +++ b/tests/resources/merge-resolve/.gitted/objects/37/f53a5a14f64e91089a39ea58e71c87d81df765 @@ -0,0 +1 @@ +x•ŽAjC1D»ö)´Ù‘e}%zƒ^Àß–ã,þwprý:tVÃÀ›™Ô¶í6ÀÃÇèªÀRBB‡Lh—,‹ª·9„À+‹%r¹Ç®û€h1¨•è¥%£p’"Åæ”=¥ÙâIue£¶ßù{†ŸÚ¶ß¶ÃIgúrçëmÔÇú™Úö–„ÙÏ-œ23/‡þ“'|óæRã~U˜‹k{ªæ£dJï
\ No newline at end of file diff --git a/tests/resources/merge-resolve/.gitted/objects/4d/d1ef7569b18d92d93c0a35bb6b93049137b355 b/tests/resources/merge-resolve/.gitted/objects/4d/d1ef7569b18d92d93c0a35bb6b93049137b355 Binary files differnew file mode 100644 index 000000000..86a21ad50 --- /dev/null +++ b/tests/resources/merge-resolve/.gitted/objects/4d/d1ef7569b18d92d93c0a35bb6b93049137b355 diff --git a/tests/resources/merge-resolve/.gitted/objects/63/ec604d491161ddafdae4179843c26d54bd999a b/tests/resources/merge-resolve/.gitted/objects/63/ec604d491161ddafdae4179843c26d54bd999a Binary files differnew file mode 100644 index 000000000..bc74da5ba --- /dev/null +++ b/tests/resources/merge-resolve/.gitted/objects/63/ec604d491161ddafdae4179843c26d54bd999a diff --git a/tests/resources/merge-resolve/.gitted/objects/68/f7c02064019d89e40e51d7776b6f67914420a2 b/tests/resources/merge-resolve/.gitted/objects/68/f7c02064019d89e40e51d7776b6f67914420a2 Binary files differnew file mode 100644 index 000000000..809a5b38b --- /dev/null +++ b/tests/resources/merge-resolve/.gitted/objects/68/f7c02064019d89e40e51d7776b6f67914420a2 diff --git a/tests/resources/merge-resolve/.gitted/objects/94/29c05dd6f6f39fc567b4ce923b16df5d3d7a7a b/tests/resources/merge-resolve/.gitted/objects/94/29c05dd6f6f39fc567b4ce923b16df5d3d7a7a Binary files differnew file mode 100644 index 000000000..d4d93f508 --- /dev/null +++ b/tests/resources/merge-resolve/.gitted/objects/94/29c05dd6f6f39fc567b4ce923b16df5d3d7a7a diff --git a/tests/resources/merge-resolve/.gitted/objects/a1/07e18a58f38c46086c8f8f1dcd54c40154eeb6 b/tests/resources/merge-resolve/.gitted/objects/a1/07e18a58f38c46086c8f8f1dcd54c40154eeb6 new file mode 100644 index 000000000..598c6a7a6 --- /dev/null +++ b/tests/resources/merge-resolve/.gitted/objects/a1/07e18a58f38c46086c8f8f1dcd54c40154eeb6 @@ -0,0 +1,3 @@ +xK +1]ç½$“Ä|`7.Ü{Îgœ“@&£×7^ÁZ= +jÎÔa²îÐ[J pÑùàƒ‘FHÎZïQIg#P4Èî}
nñƒ-Âcy«æ4ìo]ŸÔ×ÝŸB͘”Õúl¬Vpä6ì¨öôïŸÝu´ô¦ja_É?H
\ No newline at end of file diff --git a/tests/resources/merge-resolve/.gitted/objects/a2/d8d1824c68541cca94ffb90f79291eba495921 b/tests/resources/merge-resolve/.gitted/objects/a2/d8d1824c68541cca94ffb90f79291eba495921 Binary files differnew file mode 100644 index 000000000..2d3d94718 --- /dev/null +++ b/tests/resources/merge-resolve/.gitted/objects/a2/d8d1824c68541cca94ffb90f79291eba495921 diff --git a/tests/resources/merge-resolve/.gitted/objects/bc/85d1aad435ff3705a8c30ace85f7542c5736cb b/tests/resources/merge-resolve/.gitted/objects/bc/85d1aad435ff3705a8c30ace85f7542c5736cb Binary files differnew file mode 100644 index 000000000..ae529fe87 --- /dev/null +++ b/tests/resources/merge-resolve/.gitted/objects/bc/85d1aad435ff3705a8c30ace85f7542c5736cb diff --git a/tests/resources/merge-resolve/.gitted/objects/c8/26ef8b17b5cd2c4a0023f265f3a423b3aa0388 b/tests/resources/merge-resolve/.gitted/objects/c8/26ef8b17b5cd2c4a0023f265f3a423b3aa0388 Binary files differnew file mode 100644 index 000000000..b655d7c40 --- /dev/null +++ b/tests/resources/merge-resolve/.gitted/objects/c8/26ef8b17b5cd2c4a0023f265f3a423b3aa0388 diff --git a/tests/resources/merge-resolve/.gitted/objects/cd/3e8d4aa06bdc781f264171030bc28f2b370fee b/tests/resources/merge-resolve/.gitted/objects/cd/3e8d4aa06bdc781f264171030bc28f2b370fee Binary files differnew file mode 100644 index 000000000..144225df1 --- /dev/null +++ b/tests/resources/merge-resolve/.gitted/objects/cd/3e8d4aa06bdc781f264171030bc28f2b370fee diff --git a/tests/resources/merge-resolve/.gitted/objects/e2/6b8888956137218d8589368a3e606cf50fbb56 b/tests/resources/merge-resolve/.gitted/objects/e2/6b8888956137218d8589368a3e606cf50fbb56 Binary files differnew file mode 100644 index 000000000..d4ec2b972 --- /dev/null +++ b/tests/resources/merge-resolve/.gitted/objects/e2/6b8888956137218d8589368a3e606cf50fbb56 diff --git a/tests/resources/merge-resolve/.gitted/objects/e6/9de29bb2d1d6434b8b29ae775ad8c2e48c5391 b/tests/resources/merge-resolve/.gitted/objects/e6/9de29bb2d1d6434b8b29ae775ad8c2e48c5391 Binary files differnew file mode 100644 index 000000000..711223894 --- /dev/null +++ b/tests/resources/merge-resolve/.gitted/objects/e6/9de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/tests/resources/merge-resolve/.gitted/objects/f9/7da95f156121bea8f978623628f4cbdbf30b36 b/tests/resources/merge-resolve/.gitted/objects/f9/7da95f156121bea8f978623628f4cbdbf30b36 new file mode 100644 index 000000000..d785511fb --- /dev/null +++ b/tests/resources/merge-resolve/.gitted/objects/f9/7da95f156121bea8f978623628f4cbdbf30b36 @@ -0,0 +1 @@ +xŽ1!E9½‰…)Œ±±´óÃ0¸[¬–ׯà¯^^ò’Ïu]—®§)zщ²%ÊÞA). dgˆ¡DðCt“zS“W×dM‹X²cÁb3gðì/’‚¢½Ïµé[þPËú1×u«/}–at}.}ÞÓ‰ëzÑÖc€Æ¡>š15ìxÙåß^ÝiµúêòHø
\ No newline at end of file diff --git a/tests/resources/merge-resolve/.gitted/refs/heads/submodule_rename1 b/tests/resources/merge-resolve/.gitted/refs/heads/submodule_rename1 new file mode 100644 index 000000000..0ed914fef --- /dev/null +++ b/tests/resources/merge-resolve/.gitted/refs/heads/submodule_rename1 @@ -0,0 +1 @@ +f97da95f156121bea8f978623628f4cbdbf30b36 diff --git a/tests/resources/merge-resolve/.gitted/refs/heads/submodule_rename2 b/tests/resources/merge-resolve/.gitted/refs/heads/submodule_rename2 new file mode 100644 index 000000000..8e020ccfc --- /dev/null +++ b/tests/resources/merge-resolve/.gitted/refs/heads/submodule_rename2 @@ -0,0 +1 @@ +37f53a5a14f64e91089a39ea58e71c87d81df765 diff --git a/tests/resources/rebase-submodule/.gitted/HEAD b/tests/resources/rebase-submodule/.gitted/HEAD new file mode 100644 index 000000000..cb089cd89 --- /dev/null +++ b/tests/resources/rebase-submodule/.gitted/HEAD @@ -0,0 +1 @@ +ref: refs/heads/master diff --git a/tests/resources/rebase-submodule/.gitted/ORIG_HEAD b/tests/resources/rebase-submodule/.gitted/ORIG_HEAD new file mode 100644 index 000000000..a1ccbb40d --- /dev/null +++ b/tests/resources/rebase-submodule/.gitted/ORIG_HEAD @@ -0,0 +1 @@ +5fdf086684daae0a8bc61a81afe178edc1e556e7 diff --git a/tests/resources/rebase-submodule/.gitted/config b/tests/resources/rebase-submodule/.gitted/config new file mode 100644 index 000000000..af2095f84 --- /dev/null +++ b/tests/resources/rebase-submodule/.gitted/config @@ -0,0 +1,9 @@ +[core] + repositoryformatversion = 0 + filemode = true + bare = false + logallrefupdates = true +[branch "asparagus"] + rebase = true +[branch "master"] + rebase = true diff --git a/tests/resources/rebase-submodule/.gitted/description b/tests/resources/rebase-submodule/.gitted/description new file mode 100644 index 000000000..498b267a8 --- /dev/null +++ b/tests/resources/rebase-submodule/.gitted/description @@ -0,0 +1 @@ +Unnamed repository; edit this file 'description' to name the repository. diff --git a/tests/resources/rebase-submodule/.gitted/index b/tests/resources/rebase-submodule/.gitted/index Binary files differnew file mode 100644 index 000000000..b63efabdb --- /dev/null +++ b/tests/resources/rebase-submodule/.gitted/index diff --git a/tests/resources/rebase-submodule/.gitted/info/exclude b/tests/resources/rebase-submodule/.gitted/info/exclude new file mode 100644 index 000000000..a5196d1be --- /dev/null +++ b/tests/resources/rebase-submodule/.gitted/info/exclude @@ -0,0 +1,6 @@ +# git ls-files --others --exclude-from=.git/info/exclude +# Lines that start with '#' are comments. +# For a project mostly in C, the following would be a good set of +# exclude patterns (uncomment them if you want to use them): +# *.[oa] +# *~ diff --git a/tests/resources/rebase-submodule/.gitted/info/refs b/tests/resources/rebase-submodule/.gitted/info/refs new file mode 100644 index 000000000..230a6494b --- /dev/null +++ b/tests/resources/rebase-submodule/.gitted/info/refs @@ -0,0 +1,4 @@ +c64ea52df5b31efd7b73769418dc9e25b8803d25 refs/heads/asparagus +c64ea52df5b31efd7b73769418dc9e25b8803d25 refs/remotes/origin/HEAD +c64ea52df5b31efd7b73769418dc9e25b8803d25 refs/remotes/origin/asparagus +02a35db3f24db554b757b3009bc782784267c743 refs/remotes/origin/master diff --git a/tests/resources/rebase-submodule/.gitted/objects/01/971e2453a407e4b9f6c865e2c37f4db21da294 b/tests/resources/rebase-submodule/.gitted/objects/01/971e2453a407e4b9f6c865e2c37f4db21da294 new file mode 100644 index 000000000..308b38697 --- /dev/null +++ b/tests/resources/rebase-submodule/.gitted/objects/01/971e2453a407e4b9f6c865e2c37f4db21da294 @@ -0,0 +1 @@ +xUÎAjÃ0ЮuŠ¹@ÂX–fd%¡4Rjˆ¬"ËÉõë–tÑÕ|>ÿÁÄZÊÜAã[o)G2R1ä qbthçˆ&BÔ—oié?ûM»<Èà"Z¢Ì¨EÇÀL¦èÄdå·þY\ýcøØÚ’œ¤ÿ†sÖu¾Œµ¼Ã`œ³dˆhÕÞîOö]üçK}øû¼ž_÷XÛíO;Ãú¥ÕE<¬[(U¶{Rß1ØJ
\ No newline at end of file diff --git a/tests/resources/rebase-submodule/.gitted/objects/17/f8ae8ebdd08a4bb272f61b897b308ad42b1b12 b/tests/resources/rebase-submodule/.gitted/objects/17/f8ae8ebdd08a4bb272f61b897b308ad42b1b12 new file mode 100644 index 000000000..79e4c484f --- /dev/null +++ b/tests/resources/rebase-submodule/.gitted/objects/17/f8ae8ebdd08a4bb272f61b897b308ad42b1b12 @@ -0,0 +1 @@ +x-KnÃ0D»Ö)xMý€ È¢Yv×P'j«åôú•‹¬ÈâqÈX—¥t@=½õ–3p0qFe´ÄìÒ¤‚vÖ&©ì"²â‡[^;HåÊHzb’6Sð³‰ÎèŒq²3¥€*1z¼÷GmpK¿Ü|=ê²Õ.y¸GwÍÿƒ—:Ǻ¼ƒ"©
*CN’¤ÃÇöÜàƒŸelÙÛ:ÄeOþ.ÛõUϵÝÚ9m¹ƒÖƒŸ5•¹Dîe$+èxoð}ßIJÑRC
\ No newline at end of file diff --git a/tests/resources/rebase-submodule/.gitted/objects/42/cdad903aef3e7b614675e6584a8be417941911 b/tests/resources/rebase-submodule/.gitted/objects/42/cdad903aef3e7b614675e6584a8be417941911 Binary files differnew file mode 100644 index 000000000..99b5e6d2c --- /dev/null +++ b/tests/resources/rebase-submodule/.gitted/objects/42/cdad903aef3e7b614675e6584a8be417941911 diff --git a/tests/resources/rebase-submodule/.gitted/objects/4b/7c5650008b2e747fe1809eeb5a1dde0e80850a b/tests/resources/rebase-submodule/.gitted/objects/4b/7c5650008b2e747fe1809eeb5a1dde0e80850a Binary files differnew file mode 100644 index 000000000..016398531 --- /dev/null +++ b/tests/resources/rebase-submodule/.gitted/objects/4b/7c5650008b2e747fe1809eeb5a1dde0e80850a diff --git a/tests/resources/rebase-submodule/.gitted/objects/5b/1e8bccf7787e942aecf61912f94a2c274f85a5 b/tests/resources/rebase-submodule/.gitted/objects/5b/1e8bccf7787e942aecf61912f94a2c274f85a5 Binary files differnew file mode 100644 index 000000000..d4776d883 --- /dev/null +++ b/tests/resources/rebase-submodule/.gitted/objects/5b/1e8bccf7787e942aecf61912f94a2c274f85a5 diff --git a/tests/resources/rebase-submodule/.gitted/objects/68/af1fc7407fd9addf1701a87eb1c95c7494c598 b/tests/resources/rebase-submodule/.gitted/objects/68/af1fc7407fd9addf1701a87eb1c95c7494c598 Binary files differnew file mode 100644 index 000000000..6aaf79fcb --- /dev/null +++ b/tests/resources/rebase-submodule/.gitted/objects/68/af1fc7407fd9addf1701a87eb1c95c7494c598 diff --git a/tests/resources/rebase-submodule/.gitted/objects/68/f6182f4c85d39e1309d97c7e456156dc9c0096 b/tests/resources/rebase-submodule/.gitted/objects/68/f6182f4c85d39e1309d97c7e456156dc9c0096 Binary files differnew file mode 100644 index 000000000..ed1de3ada --- /dev/null +++ b/tests/resources/rebase-submodule/.gitted/objects/68/f6182f4c85d39e1309d97c7e456156dc9c0096 diff --git a/tests/resources/rebase-submodule/.gitted/objects/7c/71f7606bd3bfb25d063c970804e7fc00b9605b b/tests/resources/rebase-submodule/.gitted/objects/7c/71f7606bd3bfb25d063c970804e7fc00b9605b Binary files differnew file mode 100644 index 000000000..ef923e714 --- /dev/null +++ b/tests/resources/rebase-submodule/.gitted/objects/7c/71f7606bd3bfb25d063c970804e7fc00b9605b diff --git a/tests/resources/rebase-submodule/.gitted/objects/7c/7bf85e978f1d18c0566f702d2cb7766b9c8d4f b/tests/resources/rebase-submodule/.gitted/objects/7c/7bf85e978f1d18c0566f702d2cb7766b9c8d4f new file mode 100644 index 000000000..fe8b15777 --- /dev/null +++ b/tests/resources/rebase-submodule/.gitted/objects/7c/7bf85e978f1d18c0566f702d2cb7766b9c8d4f @@ -0,0 +1 @@ +x¥±NÄ0D©ý««ádç'‘‚ úýÆÞ\VŠ½‘í\~Ÿ€øº™÷¤/1r…¦w5m|À0èÒt¡ntƺ®%×öû‘¬ékcnu–ïaÇà:K,’à™ú“^éWüµ³—øÆêÖ5¦í5<i«µ:èq^éŸ3ê3qe\ ÓKRê
&ڡȶÐóJ¦,N×™à‹ó#|ÈVhç‰N€wäÇ…€Ô™Ôº{‘ÓY}RYa)
\ No newline at end of file diff --git a/tests/resources/rebase-submodule/.gitted/objects/a7/b066537e6be7109abfe4ff97b675d4e077da20 b/tests/resources/rebase-submodule/.gitted/objects/a7/b066537e6be7109abfe4ff97b675d4e077da20 Binary files differnew file mode 100644 index 000000000..54f9b6617 --- /dev/null +++ b/tests/resources/rebase-submodule/.gitted/objects/a7/b066537e6be7109abfe4ff97b675d4e077da20 diff --git a/tests/resources/rebase-submodule/.gitted/objects/ab/6cf22b4c67a274aa8d31b5877d92341e8c2a9c b/tests/resources/rebase-submodule/.gitted/objects/ab/6cf22b4c67a274aa8d31b5877d92341e8c2a9c Binary files differnew file mode 100644 index 000000000..5acdf362e --- /dev/null +++ b/tests/resources/rebase-submodule/.gitted/objects/ab/6cf22b4c67a274aa8d31b5877d92341e8c2a9c diff --git a/tests/resources/rebase-submodule/.gitted/objects/c4/e6cca3ec6ae0148ed231f97257df8c311e015f b/tests/resources/rebase-submodule/.gitted/objects/c4/e6cca3ec6ae0148ed231f97257df8c311e015f new file mode 100644 index 000000000..2bbf28f57 --- /dev/null +++ b/tests/resources/rebase-submodule/.gitted/objects/c4/e6cca3ec6ae0148ed231f97257df8c311e015f @@ -0,0 +1 @@ +x%P1nÄ0ëìWð¹CNE§N7¶è¡:*‰’p¬Ô’/¸ßWÎmI‘”ú$=^^ŸŸ._ï?¿¸~|žC¸°ã¼6©yTÈ„A¨(#1eôÌÓé´“.ˆ†áÀ(Hto@̸K-aë°Õ°…¡´²“sá1r6)&)8¸Å·TêÖa¶<0ׇ¿JÙ¢Ý[‡ŒK‡5IJ²²ÈÀªcáÁ¸q͓쌫r_ÍÛ‡"u^@ÐÈ7~X)—›÷2¸ Ýâ G…,æ¥f¬R¸ùå`BÚúÂ4¶3£½ÁvQŸø¤›HÖ©¦Öuêa²b SwÞcJ q…)fÆ”èæO‚ùvû×;‡í«ŒŸ
\ No newline at end of file diff --git a/tests/resources/rebase-submodule/.gitted/objects/f3/6de77de6f53dddafeb024ecaf375e45c3d9ddd b/tests/resources/rebase-submodule/.gitted/objects/f3/6de77de6f53dddafeb024ecaf375e45c3d9ddd Binary files differnew file mode 100644 index 000000000..cd330a71f --- /dev/null +++ b/tests/resources/rebase-submodule/.gitted/objects/f3/6de77de6f53dddafeb024ecaf375e45c3d9ddd diff --git a/tests/resources/rebase-submodule/.gitted/objects/ff/b36e513f5fdf8a6ba850a20142676a2ac4807d b/tests/resources/rebase-submodule/.gitted/objects/ff/b36e513f5fdf8a6ba850a20142676a2ac4807d Binary files differnew file mode 100644 index 000000000..f655d12ea --- /dev/null +++ b/tests/resources/rebase-submodule/.gitted/objects/ff/b36e513f5fdf8a6ba850a20142676a2ac4807d diff --git a/tests/resources/rebase-submodule/.gitted/packed-refs b/tests/resources/rebase-submodule/.gitted/packed-refs new file mode 100644 index 000000000..44ac842a1 --- /dev/null +++ b/tests/resources/rebase-submodule/.gitted/packed-refs @@ -0,0 +1,2 @@ +# pack-refs with: peeled fully-peeled +c64ea52df5b31efd7b73769418dc9e25b8803d25 refs/heads/asparagus diff --git a/tests/resources/rebase-submodule/.gitted/refs/heads/asparagus b/tests/resources/rebase-submodule/.gitted/refs/heads/asparagus new file mode 100644 index 000000000..e6adde8e6 --- /dev/null +++ b/tests/resources/rebase-submodule/.gitted/refs/heads/asparagus @@ -0,0 +1 @@ +17f8ae8ebdd08a4bb272f61b897b308ad42b1b12 diff --git a/tests/resources/rebase-submodule/.gitted/refs/heads/master b/tests/resources/rebase-submodule/.gitted/refs/heads/master new file mode 100644 index 000000000..2523d491d --- /dev/null +++ b/tests/resources/rebase-submodule/.gitted/refs/heads/master @@ -0,0 +1 @@ +01971e2453a407e4b9f6c865e2c37f4db21da294 diff --git a/tests/resources/rebase-submodule/asparagus.txt b/tests/resources/rebase-submodule/asparagus.txt new file mode 100644 index 000000000..ffb36e513 --- /dev/null +++ b/tests/resources/rebase-submodule/asparagus.txt @@ -0,0 +1,10 @@ +ASPARAGUS SOUP. + +Take four large bunches of asparagus, scrape it nicely, cut off one inch +of the tops, and lay them in water, chop the stalks and put them on the +fire with a piece of bacon, a large onion cut up, and pepper and salt; +add two quarts of water, boil them till the stalks are quite soft, then +pulp them through a sieve, and strain the water to it, which must be put +back in the pot; put into it a chicken cut up, with the tops of +asparagus which had been laid by, boil it until these last articles are +sufficiently done, thicken with flour, butter and milk, and serve it up. diff --git a/tests/resources/rebase-submodule/beef.txt b/tests/resources/rebase-submodule/beef.txt new file mode 100644 index 000000000..68f6182f4 --- /dev/null +++ b/tests/resources/rebase-submodule/beef.txt @@ -0,0 +1,22 @@ +BEEF SOUP. + +Take the hind shin of beef, cut off all the flesh off the leg-bone, +which must be taken away entirely, or the soup will be greasy. Wash the +meat clean and lay it in a pot, sprinkle over it one small +table-spoonful of pounded black pepper, and two of salt; three onions +the size of a hen's egg, cut small, six small carrots scraped and cut +up, two small turnips pared and cut into dice; pour on three quarts of +water, cover the pot close, and keep it gently and steadily boiling five +hours, which will leave about three pints of clear soup; do not let the +pot boil over, but take off the scum carefully, as it rises. When it has +boiled four hours, put in a small bundle of thyme and parsley, and a +pint of celery cut small, or a tea-spoonful of celery seed pounded. +These latter ingredients would lose their delicate flavour if boiled too +much. Just before you take it up, brown it in the following manner: put +a small table-spoonful of nice brown sugar into an iron skillet, set it +on the fire and stir it till it melts and looks very dark, pour into it +a ladle full of the soup, a little at a time; stirring it all the while. +Strain this browning and mix it well with the soup; take out the bundle +of thyme and parsley, put the nicest pieces of meat in your tureen, and +pour on the soup and vegetables; put in some toasted bread cut in dice, +and serve it up. diff --git a/tests/resources/rebase-submodule/bouilli.txt b/tests/resources/rebase-submodule/bouilli.txt new file mode 100644 index 000000000..4b7c56500 --- /dev/null +++ b/tests/resources/rebase-submodule/bouilli.txt @@ -0,0 +1,18 @@ +SOUP WITH BOUILLI. + +Take the nicest part of the thick brisket of beef, about eight pounds, +put it into a pot with every thing directed for the other soup; make it +exactly in the same way, only put it on an hour sooner, that you may +have time to prepare the bouilli; after it has boiled five hours, take +out the beef, cover up the soup and set it near the fire that it may +keep hot. Take the skin off the beef, have the yelk of an egg well +beaten, dip a feather in it and wash the top of your beef, sprinkle over +it the crumb of stale bread finely grated, put it in a Dutch oven +previously heated, put the top on with coals enough to brown, but not +burn the beef; let it stand nearly an hour, and prepare your gravy +thus:--Take a sufficient quantity of soup and the vegetables boiled in +it; add to it a table-spoonful of red wine, and two of mushroom catsup, +thicken with a little bit of butter and a little brown flour; make it +very hot, pour it in your dish, and put the beef on it. Garnish it with +green pickle, cut in thin slices, serve up the soup in a tureen with +bits of toasted bread. diff --git a/tests/resources/rebase-submodule/gitmodules b/tests/resources/rebase-submodule/gitmodules new file mode 100644 index 000000000..f36de77de --- /dev/null +++ b/tests/resources/rebase-submodule/gitmodules @@ -0,0 +1,3 @@ +[submodule "my-submodule"] + path = my-submodule + url = bogus diff --git a/tests/resources/rebase-submodule/gravy.txt b/tests/resources/rebase-submodule/gravy.txt new file mode 100644 index 000000000..c4e6cca3e --- /dev/null +++ b/tests/resources/rebase-submodule/gravy.txt @@ -0,0 +1,8 @@ +GRAVY SOUP. + +Get eight pounds of coarse lean beef--wash it clean and lay it in your +pot, put in the same ingredients as for the shin soup, with the same +quantity of water, and follow the process directed for that. Strain the +soup through a sieve, and serve it up clear, with nothing more than +toasted bread in it; two table-spoonsful of mushroom catsup will add a +fine flavour to the soup. diff --git a/tests/resources/rebase-submodule/oyster.txt b/tests/resources/rebase-submodule/oyster.txt new file mode 100644 index 000000000..68af1fc74 --- /dev/null +++ b/tests/resources/rebase-submodule/oyster.txt @@ -0,0 +1,13 @@ +OYSTER SOUP. + +Wash and drain two quarts of oysters, put them on with three quarts of +water, three onions chopped up, two or three slices of lean ham, pepper +and salt; boil it till reduced one-half, strain it through a sieve, +return the liquid into the pot, put in one quart of fresh oysters, boil +it till they are sufficiently done, and thicken the soup with four +spoonsful of flour, two gills of rich cream, and the yelks of six new +laid eggs beaten well; boil it a few minutes after the thickening is put +in. Take care that it does not curdle, and that the flour is not in +lumps; serve it up with the last oysters that were put in. If the +flavour of thyme be agreeable, you may put in a little, but take care +that it does not boil in it long enough to discolour the soup. diff --git a/tests/resources/rebase-submodule/veal.txt b/tests/resources/rebase-submodule/veal.txt new file mode 100644 index 000000000..a7b066537 --- /dev/null +++ b/tests/resources/rebase-submodule/veal.txt @@ -0,0 +1,18 @@ +VEAL SOUP. + +Put into a pot three quarts of water, three onions cut small, one +spoonful of black pepper pounded, and two of salt, with two or three +slices of lean ham; let it boil steadily two hours; skim it +occasionally, then put into it a shin of veal, let it boil two hours +longer; take out the slices of ham, and skim off the grease if any +should rise, take a gill of good cream, mix with it two table-spoonsful +of flour very nicely, and the yelks of two eggs beaten well, strain this +mixture, and add some chopped parsley; pour some soup on by degrees, +stir it well, and pour it into the pot, continuing to stir until it has +boiled two or three minutes to take off the raw taste of the eggs. If +the cream be not perfectly sweet, and the eggs quite new, the thickening +will curdle in the soup. For a change you may put a dozen ripe tomatos +in, first taking off their skins, by letting them stand a few minutes in +hot water, when they may be easily peeled. When made in this way you +must thicken it with the flour only. Any part of the veal may be used, +but the shin or knuckle is the nicest. diff --git a/tests/resources/sha1/hello_c b/tests/resources/sha1/hello_c new file mode 100644 index 000000000..45950b2ad --- /dev/null +++ b/tests/resources/sha1/hello_c @@ -0,0 +1,6 @@ +#include <stdio.h> + +int main(int argc, char **argv) +{ + printf("Hello, %s\n", "world"); +} diff --git a/tests/resources/sha1/shattered-1.pdf b/tests/resources/sha1/shattered-1.pdf Binary files differnew file mode 100644 index 000000000..ba9aaa145 --- /dev/null +++ b/tests/resources/sha1/shattered-1.pdf diff --git a/tests/resources/submodules-worktree-child/.gitted b/tests/resources/submodules-worktree-child/.gitted new file mode 100644 index 000000000..03286f522 --- /dev/null +++ b/tests/resources/submodules-worktree-child/.gitted @@ -0,0 +1 @@ +gitdir: ../submodules/testrepo/.git/worktrees/submodules-worktree-child diff --git a/tests/resources/submodules-worktree-child/README b/tests/resources/submodules-worktree-child/README new file mode 100644 index 000000000..a8233120f --- /dev/null +++ b/tests/resources/submodules-worktree-child/README @@ -0,0 +1 @@ +hey there diff --git a/tests/resources/submodules-worktree-child/branch_file.txt b/tests/resources/submodules-worktree-child/branch_file.txt new file mode 100644 index 000000000..3697d64be --- /dev/null +++ b/tests/resources/submodules-worktree-child/branch_file.txt @@ -0,0 +1,2 @@ +hi +bye! diff --git a/tests/resources/submodules-worktree-child/new.txt b/tests/resources/submodules-worktree-child/new.txt new file mode 100644 index 000000000..a71586c1d --- /dev/null +++ b/tests/resources/submodules-worktree-child/new.txt @@ -0,0 +1 @@ +my new file diff --git a/tests/resources/submodules-worktree-parent/.gitmodules b/tests/resources/submodules-worktree-parent/.gitmodules new file mode 100644 index 000000000..78308c925 --- /dev/null +++ b/tests/resources/submodules-worktree-parent/.gitmodules @@ -0,0 +1,3 @@ +[submodule "testrepo"] + path = testrepo + url = /Users/rb/src/libgit2/tests/resources/testrepo.git diff --git a/tests/resources/submodules-worktree-parent/.gitted b/tests/resources/submodules-worktree-parent/.gitted new file mode 100644 index 000000000..87bd9ae29 --- /dev/null +++ b/tests/resources/submodules-worktree-parent/.gitted @@ -0,0 +1 @@ +gitdir: ../submodules/.git/worktrees/submodules-worktree-parent diff --git a/tests/resources/submodules-worktree-parent/deleted b/tests/resources/submodules-worktree-parent/deleted new file mode 100644 index 000000000..092bfb9bd --- /dev/null +++ b/tests/resources/submodules-worktree-parent/deleted @@ -0,0 +1 @@ +yo diff --git a/tests/resources/submodules-worktree-parent/modified b/tests/resources/submodules-worktree-parent/modified new file mode 100644 index 000000000..092bfb9bd --- /dev/null +++ b/tests/resources/submodules-worktree-parent/modified @@ -0,0 +1 @@ +yo diff --git a/tests/resources/submodules-worktree-parent/unmodified b/tests/resources/submodules-worktree-parent/unmodified new file mode 100644 index 000000000..092bfb9bd --- /dev/null +++ b/tests/resources/submodules-worktree-parent/unmodified @@ -0,0 +1 @@ +yo diff --git a/tests/resources/submodules.git/HEAD b/tests/resources/submodules.git/HEAD new file mode 100644 index 000000000..cb089cd89 --- /dev/null +++ b/tests/resources/submodules.git/HEAD @@ -0,0 +1 @@ +ref: refs/heads/master diff --git a/tests/resources/submodules.git/config b/tests/resources/submodules.git/config new file mode 100644 index 000000000..07d359d07 --- /dev/null +++ b/tests/resources/submodules.git/config @@ -0,0 +1,4 @@ +[core] + repositoryformatversion = 0 + filemode = true + bare = true diff --git a/tests/resources/submodules.git/objects/26/a3b32a9b7d97486c5557f5902e8ac94638145e b/tests/resources/submodules.git/objects/26/a3b32a9b7d97486c5557f5902e8ac94638145e new file mode 100644 index 000000000..2c3c2cb61 --- /dev/null +++ b/tests/resources/submodules.git/objects/26/a3b32a9b7d97486c5557f5902e8ac94638145e @@ -0,0 +1,2 @@ +x%‰= +€0F]í)Š0à"ÃIŒ*•|Éý-t{?œ2ÇilV8¿ùô$±«Øm¡ýv»ãkk*FDAÊ=(=|=6 ¬DAv=ÛÍA}™&'…Oò$=
\ No newline at end of file diff --git a/tests/resources/submodules.git/objects/78/308c9251cf4eee8b25a76c7d2790c73d797357 b/tests/resources/submodules.git/objects/78/308c9251cf4eee8b25a76c7d2790c73d797357 Binary files differnew file mode 100644 index 000000000..c85fb5512 --- /dev/null +++ b/tests/resources/submodules.git/objects/78/308c9251cf4eee8b25a76c7d2790c73d797357 diff --git a/tests/resources/submodules.git/objects/97/896810b3210244a62a82458b8e0819ecfc6850 b/tests/resources/submodules.git/objects/97/896810b3210244a62a82458b8e0819ecfc6850 new file mode 100644 index 000000000..1c8dbdf9f --- /dev/null +++ b/tests/resources/submodules.git/objects/97/896810b3210244a62a82458b8e0819ecfc6850 @@ -0,0 +1,3 @@ +xŽ[ +Â0EýÎ*fʤS“ ˆˆKФéú4Ý¿wà×…Ã9pÓ2MC¥FôP@ãÜu.„.¶pÚ!²OYáƒdiYUÍ'Ì•8XïbPn¼ôÊ6 +ħԞ“¶1[qîÌ}0q«ï¥Ðc[WŒ#Ý1fºÄR:àö›SZ¦+Y‘Æ+{µtdÏlvº¬»þOmž¨u˜_´}è5Ôié·«ù` Kæ
\ No newline at end of file diff --git a/tests/resources/submodules.git/objects/b6/0fd986699ba4e9e68bea07cf8e793f323ef888 b/tests/resources/submodules.git/objects/b6/0fd986699ba4e9e68bea07cf8e793f323ef888 Binary files differnew file mode 100644 index 000000000..3d78bd6be --- /dev/null +++ b/tests/resources/submodules.git/objects/b6/0fd986699ba4e9e68bea07cf8e793f323ef888 diff --git a/tests/resources/submodules.git/objects/d5/f7fc3f74f7dec08280f370a975b112e8f60818 b/tests/resources/submodules.git/objects/d5/f7fc3f74f7dec08280f370a975b112e8f60818 Binary files differnew file mode 100644 index 000000000..6e0b49e86 --- /dev/null +++ b/tests/resources/submodules.git/objects/d5/f7fc3f74f7dec08280f370a975b112e8f60818 diff --git a/tests/resources/submodules.git/objects/e3/50052cc767cd1fcb37e84e9a89e701925be4ae b/tests/resources/submodules.git/objects/e3/50052cc767cd1fcb37e84e9a89e701925be4ae Binary files differnew file mode 100644 index 000000000..082a58941 --- /dev/null +++ b/tests/resources/submodules.git/objects/e3/50052cc767cd1fcb37e84e9a89e701925be4ae diff --git a/tests/resources/submodules.git/objects/info/packs b/tests/resources/submodules.git/objects/info/packs new file mode 100644 index 000000000..0785ef698 --- /dev/null +++ b/tests/resources/submodules.git/objects/info/packs @@ -0,0 +1,2 @@ +P pack-b69d04bb39ac274669e2184e45bd90015d02ef5b.pack + diff --git a/tests/resources/submodules.git/objects/pack/pack-b69d04bb39ac274669e2184e45bd90015d02ef5b.idx b/tests/resources/submodules.git/objects/pack/pack-b69d04bb39ac274669e2184e45bd90015d02ef5b.idx Binary files differnew file mode 100644 index 000000000..810fc3181 --- /dev/null +++ b/tests/resources/submodules.git/objects/pack/pack-b69d04bb39ac274669e2184e45bd90015d02ef5b.idx diff --git a/tests/resources/submodules.git/objects/pack/pack-b69d04bb39ac274669e2184e45bd90015d02ef5b.pack b/tests/resources/submodules.git/objects/pack/pack-b69d04bb39ac274669e2184e45bd90015d02ef5b.pack Binary files differnew file mode 100644 index 000000000..c25c4a73f --- /dev/null +++ b/tests/resources/submodules.git/objects/pack/pack-b69d04bb39ac274669e2184e45bd90015d02ef5b.pack diff --git a/tests/resources/submodules.git/refs/heads/master b/tests/resources/submodules.git/refs/heads/master new file mode 100644 index 000000000..32b935853 --- /dev/null +++ b/tests/resources/submodules.git/refs/heads/master @@ -0,0 +1 @@ +97896810b3210244a62a82458b8e0819ecfc6850 diff --git a/tests/resources/submodules/.gitted/logs/refs/heads/submodules-worktree-parent b/tests/resources/submodules/.gitted/logs/refs/heads/submodules-worktree-parent new file mode 100644 index 000000000..65e988535 --- /dev/null +++ b/tests/resources/submodules/.gitted/logs/refs/heads/submodules-worktree-parent @@ -0,0 +1 @@ +0000000000000000000000000000000000000000 97896810b3210244a62a82458b8e0819ecfc6850 Patrick Steinhardt <ps@pks.im> 1447084240 +0100 branch: Created from HEAD diff --git a/tests/resources/submodules/.gitted/refs/heads/submodules-worktree-parent b/tests/resources/submodules/.gitted/refs/heads/submodules-worktree-parent new file mode 100644 index 000000000..32b935853 --- /dev/null +++ b/tests/resources/submodules/.gitted/refs/heads/submodules-worktree-parent @@ -0,0 +1 @@ +97896810b3210244a62a82458b8e0819ecfc6850 diff --git a/tests/resources/submodules/.gitted/worktrees/submodules-worktree-parent/HEAD b/tests/resources/submodules/.gitted/worktrees/submodules-worktree-parent/HEAD new file mode 100644 index 000000000..a07134b85 --- /dev/null +++ b/tests/resources/submodules/.gitted/worktrees/submodules-worktree-parent/HEAD @@ -0,0 +1 @@ +ref: refs/heads/submodules-worktree-parent diff --git a/tests/resources/submodules/.gitted/worktrees/submodules-worktree-parent/ORIG_HEAD b/tests/resources/submodules/.gitted/worktrees/submodules-worktree-parent/ORIG_HEAD new file mode 100644 index 000000000..32b935853 --- /dev/null +++ b/tests/resources/submodules/.gitted/worktrees/submodules-worktree-parent/ORIG_HEAD @@ -0,0 +1 @@ +97896810b3210244a62a82458b8e0819ecfc6850 diff --git a/tests/resources/submodules/.gitted/worktrees/submodules-worktree-parent/commondir b/tests/resources/submodules/.gitted/worktrees/submodules-worktree-parent/commondir new file mode 100644 index 000000000..aab0408ce --- /dev/null +++ b/tests/resources/submodules/.gitted/worktrees/submodules-worktree-parent/commondir @@ -0,0 +1 @@ +../.. diff --git a/tests/resources/submodules/.gitted/worktrees/submodules-worktree-parent/gitdir b/tests/resources/submodules/.gitted/worktrees/submodules-worktree-parent/gitdir new file mode 100644 index 000000000..eaaf13b95 --- /dev/null +++ b/tests/resources/submodules/.gitted/worktrees/submodules-worktree-parent/gitdir @@ -0,0 +1 @@ +../../../../submodules-worktree-parent/.git diff --git a/tests/resources/submodules/.gitted/worktrees/submodules-worktree-parent/index b/tests/resources/submodules/.gitted/worktrees/submodules-worktree-parent/index Binary files differnew file mode 100644 index 000000000..5b68f18a4 --- /dev/null +++ b/tests/resources/submodules/.gitted/worktrees/submodules-worktree-parent/index diff --git a/tests/resources/submodules/testrepo/.gitted/config b/tests/resources/submodules/testrepo/.gitted/config index d6dcad12b..8e5571191 100644 --- a/tests/resources/submodules/testrepo/.gitted/config +++ b/tests/resources/submodules/testrepo/.gitted/config @@ -4,9 +4,6 @@ bare = false logallrefupdates = true ignorecase = true -[remote "origin"] - fetch = +refs/heads/*:refs/remotes/origin/* - url = /Users/rb/src/libgit2/tests/resources/testrepo.git [branch "master"] remote = origin merge = refs/heads/master diff --git a/tests/resources/submodules/testrepo/.gitted/logs/refs/heads/submodules-worktree-child b/tests/resources/submodules/testrepo/.gitted/logs/refs/heads/submodules-worktree-child new file mode 100644 index 000000000..dd4650ff8 --- /dev/null +++ b/tests/resources/submodules/testrepo/.gitted/logs/refs/heads/submodules-worktree-child @@ -0,0 +1 @@ +0000000000000000000000000000000000000000 a65fedf39aefe402d3bb6e24df4d4f5fe4547750 Patrick Steinhardt <ps@pks.im> 1447084252 +0100 branch: Created from HEAD diff --git a/tests/resources/submodules/testrepo/.gitted/refs/heads/submodules-worktree-child b/tests/resources/submodules/testrepo/.gitted/refs/heads/submodules-worktree-child new file mode 100644 index 000000000..3d8f0a402 --- /dev/null +++ b/tests/resources/submodules/testrepo/.gitted/refs/heads/submodules-worktree-child @@ -0,0 +1 @@ +a65fedf39aefe402d3bb6e24df4d4f5fe4547750 diff --git a/tests/resources/submodules/testrepo/.gitted/worktrees/submodules-worktree-child/HEAD b/tests/resources/submodules/testrepo/.gitted/worktrees/submodules-worktree-child/HEAD new file mode 100644 index 000000000..ef82bd4df --- /dev/null +++ b/tests/resources/submodules/testrepo/.gitted/worktrees/submodules-worktree-child/HEAD @@ -0,0 +1 @@ +ref: refs/heads/submodules-worktree-child diff --git a/tests/resources/submodules/testrepo/.gitted/worktrees/submodules-worktree-child/ORIG_HEAD b/tests/resources/submodules/testrepo/.gitted/worktrees/submodules-worktree-child/ORIG_HEAD new file mode 100644 index 000000000..3d8f0a402 --- /dev/null +++ b/tests/resources/submodules/testrepo/.gitted/worktrees/submodules-worktree-child/ORIG_HEAD @@ -0,0 +1 @@ +a65fedf39aefe402d3bb6e24df4d4f5fe4547750 diff --git a/tests/resources/submodules/testrepo/.gitted/worktrees/submodules-worktree-child/commondir b/tests/resources/submodules/testrepo/.gitted/worktrees/submodules-worktree-child/commondir new file mode 100644 index 000000000..aab0408ce --- /dev/null +++ b/tests/resources/submodules/testrepo/.gitted/worktrees/submodules-worktree-child/commondir @@ -0,0 +1 @@ +../.. diff --git a/tests/resources/submodules/testrepo/.gitted/worktrees/submodules-worktree-child/gitdir b/tests/resources/submodules/testrepo/.gitted/worktrees/submodules-worktree-child/gitdir new file mode 100644 index 000000000..b0ef96e11 --- /dev/null +++ b/tests/resources/submodules/testrepo/.gitted/worktrees/submodules-worktree-child/gitdir @@ -0,0 +1 @@ +../../../../../submodules-worktree-child/.git diff --git a/tests/resources/submodules/testrepo/.gitted/worktrees/submodules-worktree-child/index b/tests/resources/submodules/testrepo/.gitted/worktrees/submodules-worktree-child/index Binary files differnew file mode 100644 index 000000000..52a42f966 --- /dev/null +++ b/tests/resources/submodules/testrepo/.gitted/worktrees/submodules-worktree-child/index diff --git a/tests/resources/testrepo-worktree/.gitted b/tests/resources/testrepo-worktree/.gitted new file mode 100644 index 000000000..fe4556a92 --- /dev/null +++ b/tests/resources/testrepo-worktree/.gitted @@ -0,0 +1 @@ +gitdir: ../testrepo/.git/worktrees/testrepo-worktree diff --git a/tests/resources/testrepo-worktree/README b/tests/resources/testrepo-worktree/README new file mode 100644 index 000000000..a8233120f --- /dev/null +++ b/tests/resources/testrepo-worktree/README @@ -0,0 +1 @@ +hey there diff --git a/tests/resources/testrepo-worktree/branch_file.txt b/tests/resources/testrepo-worktree/branch_file.txt new file mode 100644 index 000000000..3697d64be --- /dev/null +++ b/tests/resources/testrepo-worktree/branch_file.txt @@ -0,0 +1,2 @@ +hi +bye! diff --git a/tests/resources/testrepo-worktree/link_to_new.txt b/tests/resources/testrepo-worktree/link_to_new.txt new file mode 120000 index 000000000..c0528fd6c --- /dev/null +++ b/tests/resources/testrepo-worktree/link_to_new.txt @@ -0,0 +1 @@ +new.txt
\ No newline at end of file diff --git a/tests/resources/testrepo-worktree/new.txt b/tests/resources/testrepo-worktree/new.txt new file mode 100644 index 000000000..a71586c1d --- /dev/null +++ b/tests/resources/testrepo-worktree/new.txt @@ -0,0 +1 @@ +my new file diff --git a/tests/resources/testrepo.git/objects/43/da5ec3274dd061df152ff5e69853d562b01842 b/tests/resources/testrepo.git/objects/43/da5ec3274dd061df152ff5e69853d562b01842 new file mode 100644 index 000000000..298feece4 --- /dev/null +++ b/tests/resources/testrepo.git/objects/43/da5ec3274dd061df152ff5e69853d562b01842 @@ -0,0 +1,2 @@ +x-Ž]jC!Fûì*f)þ]¡”@è +Ú
è8ÆõZŒ¡Û¯iûvøà>êí´±Os0ƒB%s)fŒÎÉMélÑhöV4¢5‰²øŠƒ Å&4Ñ•@:¡DÅ)oIr`’½$íLДˆ÷Yû€wêsÂ¥Fê¼ÜèÎ×÷Ïgêí”ö•Á`á$½”bëáäoù;Žµ·ÛÃæU|ÐùºÏzOÿ¾u}ÐÚ/ß._¤ªð×~°øÕäJ
\ No newline at end of file diff --git a/tests/resources/testrepo.git/objects/43/e968a905a821532069bb413801d35b200631cf b/tests/resources/testrepo.git/objects/43/e968a905a821532069bb413801d35b200631cf new file mode 100644 index 000000000..ec04abf68 --- /dev/null +++ b/tests/resources/testrepo.git/objects/43/e968a905a821532069bb413801d35b200631cf @@ -0,0 +1,4 @@ +xŽK +1]ç}%ŸN'7ÞÀäÓã8‰¼¾ñ +îê¼\×ué 5zc†¤
6¤Ç8ùb,â”ÊDÎ2º0†'«Q¼bãƒÇ@Ò©¬Rö“QÊ[ŽÁ94‰)ú£qïsmp+ŸØ +Ü纾ëgöG×ÇÒç=r]/ ´3š((‚£tRŠaÇËÎÿö¢>‹ø±EÎ
\ No newline at end of file diff --git a/tests/resources/testrepo.git/objects/5d/0f8f7891e872d284beef38254882dc879b2602 b/tests/resources/testrepo.git/objects/5d/0f8f7891e872d284beef38254882dc879b2602 Binary files differnew file mode 100644 index 000000000..7a22451ed --- /dev/null +++ b/tests/resources/testrepo.git/objects/5d/0f8f7891e872d284beef38254882dc879b2602 diff --git a/tests/resources/testrepo.git/objects/5f/34cd6e3285089647165983482cf90873d50940 b/tests/resources/testrepo.git/objects/5f/34cd6e3285089647165983482cf90873d50940 Binary files differnew file mode 100644 index 000000000..b1df3bdd5 --- /dev/null +++ b/tests/resources/testrepo.git/objects/5f/34cd6e3285089647165983482cf90873d50940 diff --git a/tests/resources/testrepo.git/objects/8e/73b769e97678d684b809b163bebdae2911720f b/tests/resources/testrepo.git/objects/8e/73b769e97678d684b809b163bebdae2911720f new file mode 100644 index 000000000..d75977a25 --- /dev/null +++ b/tests/resources/testrepo.git/objects/8e/73b769e97678d684b809b163bebdae2911720f @@ -0,0 +1,2 @@ +x½jÄ0„Sû)¶»*aõ»„ãš”éò+íúl8[A–ÉëÇ×äÒ
33¥®ëÒÁ¡yéM$ÌmÈ*Öç ã$q²äG?YŒAœ5<
ßÜtëà¦8rÂÀ£5ÁŽ”³7nD#.d‹)~ŠNÈ0Ë„‰)R,‰|,h½’jQ*töóÑçÚàC~¸ |ÍuÝëïzÒ§ºÝ—>ùÔõ +Æ’³d¼ðŠ„8œô\Õõ¿ùáSÛ]!7ÞÊ—ýÈÏsö,[¯P2üfw^Ä
\ No newline at end of file diff --git a/tests/resources/testrepo.git/objects/b2/04707bbc546a1a770ef6ced37c7089cc3bfe6b b/tests/resources/testrepo.git/objects/b2/04707bbc546a1a770ef6ced37c7089cc3bfe6b new file mode 100644 index 000000000..f9ec61c1e --- /dev/null +++ b/tests/resources/testrepo.git/objects/b2/04707bbc546a1a770ef6ced37c7089cc3bfe6b @@ -0,0 +1,2 @@ +x-Î]ŠÃ0à}Î)t.þQJ),{‚öŽ-7º^\‡^Ò·AÌ7(”œ×FÓW«"ÀˆA%ŒÉ£y’Ù‘giTI´Ód†?_åÑÀ™#ê•Ø[‰Ó(-§DÎ0wdp²ƒßÚR*\Bi
~ÊŽÏðç[öëý;”|mµa´djRjè×þa“ +¿ñåk„ëRòs×Ò÷t¾mÙæG"7±á©{ì~ø¥LD›
\ No newline at end of file diff --git a/tests/resources/testrepo.git/objects/b2/35959d89084af8d3544fbdf675e47944f86524 b/tests/resources/testrepo.git/objects/b2/35959d89084af8d3544fbdf675e47944f86524 Binary files differnew file mode 100644 index 000000000..7d563dbd3 --- /dev/null +++ b/tests/resources/testrepo.git/objects/b2/35959d89084af8d3544fbdf675e47944f86524 diff --git a/tests/resources/testrepo.git/objects/b9/1e763008b10db366442469339f90a2b8400d0a b/tests/resources/testrepo.git/objects/b9/1e763008b10db366442469339f90a2b8400d0a Binary files differnew file mode 100644 index 000000000..7bab59be8 --- /dev/null +++ b/tests/resources/testrepo.git/objects/b9/1e763008b10db366442469339f90a2b8400d0a diff --git a/tests/resources/testrepo.git/objects/bd/758010071961f28336333bc41e9c64c9a64866 b/tests/resources/testrepo.git/objects/bd/758010071961f28336333bc41e9c64c9a64866 Binary files differnew file mode 100644 index 000000000..c5e3b87ad --- /dev/null +++ b/tests/resources/testrepo.git/objects/bd/758010071961f28336333bc41e9c64c9a64866 diff --git a/tests/resources/testrepo.git/objects/db/4df74a2fc340a0d0cb0cafc0db471fdfff1048 b/tests/resources/testrepo.git/objects/db/4df74a2fc340a0d0cb0cafc0db471fdfff1048 new file mode 100644 index 000000000..5f3d50efa --- /dev/null +++ b/tests/resources/testrepo.git/objects/db/4df74a2fc340a0d0cb0cafc0db471fdfff1048 @@ -0,0 +1,2 @@ +x-ÎQJ1P¿sŠ¾€ÒIz2= ² ž@/tz7f"Ù,^߬úW¼¢¤ÕºpžFWËgkÙÊÆÑë¶`â$´8JñŽ0c¸˜¯Øõ˜¹˜5 +ÉIÒˆŠJ>!+…³N–UÈÄÛ(û´1àµDi<_å7œ.5îŸOÒêX·[ÏÁ#®ˆf¶óáÐoù;ö¥Õë]ë\¼§Óeå–þ=…À[@tÓÓô&õxH¿h‡šûYJn
\ No newline at end of file diff --git a/tests/resources/testrepo.git/objects/db/793a00a5615eca1aac97e42b3a68b1acfa8bfd b/tests/resources/testrepo.git/objects/db/793a00a5615eca1aac97e42b3a68b1acfa8bfd Binary files differnew file mode 100644 index 000000000..ae82880de --- /dev/null +++ b/tests/resources/testrepo.git/objects/db/793a00a5615eca1aac97e42b3a68b1acfa8bfd diff --git a/tests/resources/testrepo.git/objects/db/c0be625bed24b5d8f5d9a927484f2065d321af b/tests/resources/testrepo.git/objects/db/c0be625bed24b5d8f5d9a927484f2065d321af Binary files differnew file mode 100644 index 000000000..b966b0b2f --- /dev/null +++ b/tests/resources/testrepo.git/objects/db/c0be625bed24b5d8f5d9a927484f2065d321af diff --git a/tests/resources/testrepo.git/objects/f0/a2a10243ca64f935dbe3dccb89ec8bf16bdace b/tests/resources/testrepo.git/objects/f0/a2a10243ca64f935dbe3dccb89ec8bf16bdace Binary files differnew file mode 100644 index 000000000..1b299dc25 --- /dev/null +++ b/tests/resources/testrepo.git/objects/f0/a2a10243ca64f935dbe3dccb89ec8bf16bdace diff --git a/tests/resources/testrepo/.gitted/logs/refs/heads/testrepo-worktree b/tests/resources/testrepo/.gitted/logs/refs/heads/testrepo-worktree new file mode 100644 index 000000000..93ab5f06f --- /dev/null +++ b/tests/resources/testrepo/.gitted/logs/refs/heads/testrepo-worktree @@ -0,0 +1 @@ +0000000000000000000000000000000000000000 099fabac3a9ea935598528c27f866e34089c2eff Patrick Steinhardt <ps@pks.im> 1442484463 +0200 branch: Created from HEAD diff --git a/tests/resources/testrepo/.gitted/objects/9b/1719f5cf069568785080a0bbabbe7c377e22ae b/tests/resources/testrepo/.gitted/objects/9b/1719f5cf069568785080a0bbabbe7c377e22ae Binary files differnew file mode 100644 index 000000000..13e3f581a --- /dev/null +++ b/tests/resources/testrepo/.gitted/objects/9b/1719f5cf069568785080a0bbabbe7c377e22ae diff --git a/tests/resources/testrepo/.gitted/objects/a3/8d028f71eaa590febb7d716b1ca32350cf70da b/tests/resources/testrepo/.gitted/objects/a3/8d028f71eaa590febb7d716b1ca32350cf70da Binary files differnew file mode 100644 index 000000000..4df22ec17 --- /dev/null +++ b/tests/resources/testrepo/.gitted/objects/a3/8d028f71eaa590febb7d716b1ca32350cf70da diff --git a/tests/resources/testrepo/.gitted/objects/ad/edac69457183c8265c8a9614c1c4fed31d1ff3 b/tests/resources/testrepo/.gitted/objects/ad/edac69457183c8265c8a9614c1c4fed31d1ff3 Binary files differnew file mode 100644 index 000000000..c054fc0c4 --- /dev/null +++ b/tests/resources/testrepo/.gitted/objects/ad/edac69457183c8265c8a9614c1c4fed31d1ff3 diff --git a/tests/resources/testrepo/.gitted/refs/heads/merge-conflict b/tests/resources/testrepo/.gitted/refs/heads/merge-conflict new file mode 100644 index 000000000..3e24a24e0 --- /dev/null +++ b/tests/resources/testrepo/.gitted/refs/heads/merge-conflict @@ -0,0 +1 @@ +a38d028f71eaa590febb7d716b1ca32350cf70da diff --git a/tests/resources/testrepo/.gitted/refs/heads/testrepo-worktree b/tests/resources/testrepo/.gitted/refs/heads/testrepo-worktree new file mode 100644 index 000000000..f31fe781b --- /dev/null +++ b/tests/resources/testrepo/.gitted/refs/heads/testrepo-worktree @@ -0,0 +1 @@ +099fabac3a9ea935598528c27f866e34089c2eff diff --git a/tests/resources/testrepo/.gitted/worktrees/testrepo-worktree/HEAD b/tests/resources/testrepo/.gitted/worktrees/testrepo-worktree/HEAD new file mode 100644 index 000000000..1b8637e32 --- /dev/null +++ b/tests/resources/testrepo/.gitted/worktrees/testrepo-worktree/HEAD @@ -0,0 +1 @@ +ref: refs/heads/testrepo-worktree diff --git a/tests/resources/testrepo/.gitted/worktrees/testrepo-worktree/commondir b/tests/resources/testrepo/.gitted/worktrees/testrepo-worktree/commondir new file mode 100644 index 000000000..aab0408ce --- /dev/null +++ b/tests/resources/testrepo/.gitted/worktrees/testrepo-worktree/commondir @@ -0,0 +1 @@ +../.. diff --git a/tests/resources/testrepo/.gitted/worktrees/testrepo-worktree/gitdir b/tests/resources/testrepo/.gitted/worktrees/testrepo-worktree/gitdir new file mode 100644 index 000000000..0d37a5792 --- /dev/null +++ b/tests/resources/testrepo/.gitted/worktrees/testrepo-worktree/gitdir @@ -0,0 +1 @@ +../../../../testrepo-worktree/.git diff --git a/tests/resources/testrepo/.gitted/worktrees/testrepo-worktree/index b/tests/resources/testrepo/.gitted/worktrees/testrepo-worktree/index Binary files differnew file mode 100644 index 000000000..41141906e --- /dev/null +++ b/tests/resources/testrepo/.gitted/worktrees/testrepo-worktree/index diff --git a/tests/resources/testrepo/.gitted/worktrees/testrepo-worktree/logs/HEAD b/tests/resources/testrepo/.gitted/worktrees/testrepo-worktree/logs/HEAD new file mode 100644 index 000000000..3bede502e --- /dev/null +++ b/tests/resources/testrepo/.gitted/worktrees/testrepo-worktree/logs/HEAD @@ -0,0 +1 @@ +099fabac3a9ea935598528c27f866e34089c2eff 099fabac3a9ea935598528c27f866e34089c2eff Patrick Steinhardt <ps@pks.im> 1442484463 +0200 checkout: moving from 099fabac3a9ea935598528c27f866e34089c2eff to testrepo-worktree diff --git a/tests/revwalk/basic.c b/tests/revwalk/basic.c index 5ed7da4eb..547050c68 100644 --- a/tests/revwalk/basic.c +++ b/tests/revwalk/basic.c @@ -38,8 +38,9 @@ static const int commit_sorting_time_reverse[][6] = { {4, 5, 2, 1, 3, 0} }; +/* This is specified unsorted, so both combinations are possible */ static const int commit_sorting_segment[][6] = { - {1, 2, -1, -1, -1, -1} + {1, 2, -1, -1, -1, -1}, {2, 1, -1, -1, -1, -1} }; #define commit_count 6 @@ -155,9 +156,8 @@ void test_revwalk_basic__glob_heads(void) cl_git_pass(git_revwalk_push_glob(_walk, "heads")); - while (git_revwalk_next(&oid, _walk) == 0) { + while (git_revwalk_next(&oid, _walk) == 0) i++; - } /* git log --branches --oneline | wc -l => 14 */ cl_assert_equal_i(i, 14); @@ -177,7 +177,7 @@ void test_revwalk_basic__glob_heads_with_invalid(void) /* walking */; /* git log --branches --oneline | wc -l => 16 */ - cl_assert_equal_i(18, i); + cl_assert_equal_i(19, i); } void test_revwalk_basic__push_head(void) @@ -331,6 +331,40 @@ void test_revwalk_basic__hide_then_push(void) cl_assert_equal_i(i, 0); } +void test_revwalk_basic__topo_crash(void) +{ + git_oid oid; + git_oid_fromstr(&oid, "5b5b025afb0b4c913b4c338a42934a3863bf3644"); + + revwalk_basic_setup_walk(NULL); + git_revwalk_sorting(_walk, GIT_SORT_TOPOLOGICAL); + + cl_git_pass(git_revwalk_push(_walk, &oid)); + cl_git_pass(git_revwalk_hide(_walk, &oid)); + + git_revwalk_next(&oid, _walk); +} + +void test_revwalk_basic__from_new_to_old(void) +{ + git_oid from_oid, to_oid, oid; + int i = 0; + + revwalk_basic_setup_walk(NULL); + git_revwalk_sorting(_walk, GIT_SORT_TIME); + + cl_git_pass(git_oid_fromstr(&to_oid, "5b5b025afb0b4c913b4c338a42934a3863bf3644")); + cl_git_pass(git_oid_fromstr(&from_oid, "a4a7dce85cf63874e984719f4fdd239f5145052f")); + + cl_git_pass(git_revwalk_push(_walk, &to_oid)); + cl_git_pass(git_revwalk_hide(_walk, &from_oid)); + + while (git_revwalk_next(&oid, _walk) == 0) + i++; + + cl_assert_equal_i(i, 0); +} + void test_revwalk_basic__push_range(void) { revwalk_basic_setup_walk(NULL); @@ -338,7 +372,7 @@ void test_revwalk_basic__push_range(void) git_revwalk_reset(_walk); git_revwalk_sorting(_walk, 0); cl_git_pass(git_revwalk_push_range(_walk, "9fd738e~2..9fd738e")); - cl_git_pass(test_walk_only(_walk, commit_sorting_segment, 1)); + cl_git_pass(test_walk_only(_walk, commit_sorting_segment, 2)); } void test_revwalk_basic__push_mixed(void) @@ -473,3 +507,51 @@ void test_revwalk_basic__big_timestamp(void) git_signature_free(sig); } + +/* Ensure that we correctly hide a commit that is (timewise) older + * than the commits that we are showing. + * + * % git rev-list 8e73b76..bd75801 + * bd758010071961f28336333bc41e9c64c9a64866 + */ +void test_revwalk_basic__old_hidden_commit_one(void) +{ + git_oid new_id, old_id, oid; + + revwalk_basic_setup_walk("testrepo.git"); + + cl_git_pass(git_oid_fromstr(&new_id, "bd758010071961f28336333bc41e9c64c9a64866")); + cl_git_pass(git_revwalk_push(_walk, &new_id)); + + cl_git_pass(git_oid_fromstr(&old_id, "8e73b769e97678d684b809b163bebdae2911720f")); + cl_git_pass(git_revwalk_hide(_walk, &old_id)); + + cl_git_pass(git_revwalk_next(&oid, _walk)); + cl_assert(!git_oid_streq(&oid, "bd758010071961f28336333bc41e9c64c9a64866")); + + cl_git_fail_with(GIT_ITEROVER, git_revwalk_next(&oid, _walk)); +} + +/* Ensure that we correctly hide a commit that is (timewise) older + * than the commits that we are showing. + * + * % git rev-list bd75801 ^b91e763 + * bd758010071961f28336333bc41e9c64c9a64866 + */ +void test_revwalk_basic__old_hidden_commit_two(void) +{ + git_oid new_id, old_id, oid; + + revwalk_basic_setup_walk("testrepo.git"); + + cl_git_pass(git_oid_fromstr(&new_id, "bd758010071961f28336333bc41e9c64c9a64866")); + cl_git_pass(git_revwalk_push(_walk, &new_id)); + + cl_git_pass(git_oid_fromstr(&old_id, "b91e763008b10db366442469339f90a2b8400d0a")); + cl_git_pass(git_revwalk_hide(_walk, &old_id)); + + cl_git_pass(git_revwalk_next(&oid, _walk)); + cl_assert(!git_oid_streq(&oid, "bd758010071961f28336333bc41e9c64c9a64866")); + + cl_git_fail_with(GIT_ITEROVER, git_revwalk_next(&oid, _walk)); +} diff --git a/tests/revwalk/hidecb.c b/tests/revwalk/hidecb.c index 14cf39afd..b274ed86a 100644 --- a/tests/revwalk/hidecb.c +++ b/tests/revwalk/hidecb.c @@ -158,6 +158,7 @@ void test_revwalk_hidecb__hide_some_commits(void) cl_git_pass(git_revwalk_new(&walk, _repo)); cl_git_pass(git_revwalk_push(walk, &_head_id)); + git_revwalk_sorting(walk, GIT_SORT_TOPOLOGICAL); /* Add hide callback */ cl_git_pass(git_revwalk_add_hide_cb(walk, hide_commit_cb, NULL)); @@ -182,6 +183,7 @@ void test_revwalk_hidecb__test_payload(void) cl_git_pass(git_revwalk_new(&walk, _repo)); cl_git_pass(git_revwalk_push(walk, &_head_id)); + git_revwalk_sorting(walk, GIT_SORT_TOPOLOGICAL); /* Add hide callback, pass id of parent of initial commit as payload data */ cl_git_pass(git_revwalk_add_hide_cb(walk, hide_commit_use_payload_cb, &commit_ids[5])); diff --git a/tests/revwalk/simplify.c b/tests/revwalk/simplify.c index f65ce6c59..6dd068a42 100644 --- a/tests/revwalk/simplify.c +++ b/tests/revwalk/simplify.c @@ -40,6 +40,7 @@ void test_revwalk_simplify__first_parent(void) git_oid_fromstr(&id, commit_head); cl_git_pass(git_revwalk_push(walk, &id)); + git_revwalk_sorting(walk, GIT_SORT_TOPOLOGICAL); git_revwalk_simplify_first_parent(walk); i = 0; diff --git a/tests/status/ignore.c b/tests/status/ignore.c index c4878b2dd..dc58e8b45 100644 --- a/tests/status/ignore.c +++ b/tests/status/ignore.c @@ -20,8 +20,8 @@ static void assert_ignored_( bool expected, const char *filepath, const char *file, int line) { int is_ignored = 0; - cl_git_pass_( - git_status_should_ignore(&is_ignored, g_repo, filepath), file, line); + cl_git_expect( + git_status_should_ignore(&is_ignored, g_repo, filepath), 0, file, line); clar__assert( (expected != 0) == (is_ignored != 0), file, line, "expected != is_ignored", filepath, 1); @@ -1077,3 +1077,108 @@ void test_status_ignore__negate_starstar(void) cl_git_pass(git_ignore_path_is_ignored(&ignored, g_repo, "code/projects/foo/bar/packages/repositories.config")); cl_assert_equal_i(0, ignored); } + +void test_status_ignore__ignore_all_toplevel_dirs_include_files(void) +{ + static const char *test_files[] = { + "empty_standard_repo/README.md", + "empty_standard_repo/src/main.c", + "empty_standard_repo/src/foo/foo.c", + "empty_standard_repo/dist/foo.o", + "empty_standard_repo/dist/main.o", + NULL + }; + + make_test_data("empty_standard_repo", test_files); + cl_git_mkfile( + "empty_standard_repo/.gitignore", + "/*/\n" + "!/src\n"); + + assert_is_ignored("dist/foo.o"); + assert_is_ignored("dist/main.o"); + + refute_is_ignored("README.md"); + refute_is_ignored("src/foo.c"); + refute_is_ignored("src/foo/foo.c"); +} + +void test_status_ignore__subdir_ignore_all_toplevel_dirs_include_files(void) +{ + static const char *test_files[] = { + "empty_standard_repo/project/README.md", + "empty_standard_repo/project/src/main.c", + "empty_standard_repo/project/src/foo/foo.c", + "empty_standard_repo/project/dist/foo.o", + "empty_standard_repo/project/dist/main.o", + NULL + }; + + make_test_data("empty_standard_repo", test_files); + cl_git_mkfile( + "empty_standard_repo/project/.gitignore", + "/*/\n" + "!/src\n"); + + assert_is_ignored("project/dist/foo.o"); + assert_is_ignored("project/dist/main.o"); + + refute_is_ignored("project/src/foo.c"); + refute_is_ignored("project/src/foo/foo.c"); + refute_is_ignored("project/README.md"); +} + +void test_status_ignore__subdir_ignore_everything_except_certain_files(void) +{ + static const char *test_files[] = { + "empty_standard_repo/project/README.md", + "empty_standard_repo/project/some_file", + "empty_standard_repo/project/src/main.c", + "empty_standard_repo/project/src/foo/foo.c", + "empty_standard_repo/project/dist/foo.o", + "empty_standard_repo/project/dist/main.o", + NULL + }; + + make_test_data("empty_standard_repo", test_files); + cl_git_mkfile( + "empty_standard_repo/project/.gitignore", + "/*\n" + "!/src\n" + "!README.md\n"); + + assert_is_ignored("project/some_file"); + assert_is_ignored("project/dist/foo.o"); + assert_is_ignored("project/dist/main.o"); + + refute_is_ignored("project/README.md"); + refute_is_ignored("project/src/foo.c"); + refute_is_ignored("project/src/foo/foo.c"); +} + +void test_status_ignore__deeper(void) +{ + int ignored; + + g_repo = cl_git_sandbox_init("empty_standard_repo"); + + cl_git_mkfile("empty_standard_repo/.gitignore", + "*.data\n" + "!dont_ignore/*.data\n"); + + cl_git_pass(p_mkdir("empty_standard_repo/dont_ignore", 0777)); + cl_git_mkfile("empty_standard_repo/foo.data", ""); + cl_git_mkfile("empty_standard_repo/bar.data", ""); + cl_git_mkfile("empty_standard_repo/dont_ignore/foo.data", ""); + cl_git_mkfile("empty_standard_repo/dont_ignore/bar.data", ""); + + cl_git_pass(git_ignore_path_is_ignored(&ignored, g_repo, "foo.data")); + cl_assert_equal_i(1, ignored); + cl_git_pass(git_ignore_path_is_ignored(&ignored, g_repo, "bar.data")); + cl_assert_equal_i(1, ignored); + + cl_git_pass(git_ignore_path_is_ignored(&ignored, g_repo, "dont_ignore/foo.data")); + cl_assert_equal_i(0, ignored); + cl_git_pass(git_ignore_path_is_ignored(&ignored, g_repo, "dont_ignore/bar.data")); + cl_assert_equal_i(0, ignored); +} diff --git a/tests/submodule/lookup.c b/tests/submodule/lookup.c index 148f9273e..f84f07c60 100644 --- a/tests/submodule/lookup.c +++ b/tests/submodule/lookup.c @@ -11,6 +11,11 @@ void test_submodule_lookup__initialize(void) g_repo = setup_fixture_submod2(); } +void test_submodule_lookup__cleanup(void) +{ + cl_git_sandbox_cleanup(); +} + void test_submodule_lookup__simple_lookup(void) { assert_submodule_exists(g_repo, "sm_unchanged"); @@ -388,3 +393,55 @@ void test_submodule_lookup__renamed(void) cl_git_pass(git_submodule_foreach(g_repo, sm_lookup_cb, &data)); cl_assert_equal_i(8, data.count); } + +void test_submodule_lookup__cached(void) +{ + git_submodule *sm; + git_submodule *sm2; + /* See that the simple tests still pass. */ + + git_repository_submodule_cache_all(g_repo); + test_submodule_lookup__simple_lookup(); + git_repository_submodule_cache_clear(g_repo); + test_submodule_lookup__simple_lookup(); + + /* Check that subsequent calls return different objects when cached. */ + git_repository_submodule_cache_all(g_repo); + cl_git_pass(git_submodule_lookup(&sm, g_repo, "sm_unchanged")); + cl_git_pass(git_submodule_lookup(&sm2, g_repo, "sm_unchanged")); + cl_assert_equal_p(sm, sm2); + git_submodule_free(sm2); + + /* and that we get new objects again after clearing the cache. */ + git_repository_submodule_cache_clear(g_repo); + cl_git_pass(git_submodule_lookup(&sm2, g_repo, "sm_unchanged")); + cl_assert(sm != sm2); + git_submodule_free(sm); + git_submodule_free(sm2); +} + +void test_submodule_lookup__lookup_in_bare_repository_fails(void) +{ + git_submodule *sm; + + cl_git_sandbox_cleanup(); + g_repo = cl_git_sandbox_init("submodules.git"); + + cl_git_fail(git_submodule_lookup(&sm, g_repo, "nonexisting")); +} + +static int foreach_cb(git_submodule *sm, const char *name, void *payload) +{ + GIT_UNUSED(sm); + GIT_UNUSED(name); + GIT_UNUSED(payload); + return 0; +} + +void test_submodule_lookup__foreach_in_bare_repository_fails(void) +{ + cl_git_sandbox_cleanup(); + g_repo = cl_git_sandbox_init("submodules.git"); + + cl_git_fail(git_submodule_foreach(g_repo, foreach_cb, NULL)); +} diff --git a/tests/submodule/open.c b/tests/submodule/open.c new file mode 100644 index 000000000..0ef01ec24 --- /dev/null +++ b/tests/submodule/open.c @@ -0,0 +1,90 @@ +#include "clar_libgit2.h" +#include "submodule_helpers.h" +#include "path.h" + +static git_repository *g_parent; +static git_repository *g_child; +static git_submodule *g_module; + +void test_submodule_open__initialize(void) +{ + g_parent = setup_fixture_submod2(); +} + +void test_submodule_open__cleanup(void) +{ + git_submodule_free(g_module); + git_repository_free(g_child); + cl_git_sandbox_cleanup(); + g_parent = NULL; + g_child = NULL; + g_module = NULL; +} + +static void assert_sm_valid(git_repository *parent, git_repository *child, const char *sm_name) +{ + git_buf expected = GIT_BUF_INIT, actual = GIT_BUF_INIT; + + /* assert working directory */ + cl_git_pass(git_buf_joinpath(&expected, git_repository_workdir(parent), sm_name)); + cl_git_pass(git_path_prettify_dir(&expected, expected.ptr, NULL)); + cl_git_pass(git_buf_sets(&actual, git_repository_workdir(child))); + cl_git_pass(git_path_prettify_dir(&actual, actual.ptr, NULL)); + cl_assert_equal_s(expected.ptr, actual.ptr); + + git_buf_clear(&expected); + git_buf_clear(&actual); + + /* assert common directory */ + cl_git_pass(git_buf_joinpath(&expected, git_repository_commondir(parent), "modules")); + cl_git_pass(git_buf_joinpath(&expected, expected.ptr, sm_name)); + cl_git_pass(git_path_prettify_dir(&expected, expected.ptr, NULL)); + cl_git_pass(git_buf_sets(&actual, git_repository_commondir(child))); + cl_git_pass(git_path_prettify_dir(&actual, actual.ptr, NULL)); + cl_assert_equal_s(expected.ptr, actual.ptr); + + /* assert git directory */ + cl_git_pass(git_buf_sets(&actual, git_repository_path(child))); + cl_git_pass(git_path_prettify_dir(&actual, actual.ptr, NULL)); + cl_assert_equal_s(expected.ptr, actual.ptr); + + git_buf_free(&expected); + git_buf_free(&actual); +} + +void test_submodule_open__opening_via_lookup_succeeds(void) +{ + cl_git_pass(git_submodule_lookup(&g_module, g_parent, "sm_unchanged")); + cl_git_pass(git_submodule_open(&g_child, g_module)); + assert_sm_valid(g_parent, g_child, "sm_unchanged"); +} + +void test_submodule_open__direct_open_succeeds(void) +{ + git_buf path = GIT_BUF_INIT; + + cl_git_pass(git_buf_joinpath(&path, git_repository_workdir(g_parent), "sm_unchanged")); + cl_git_pass(git_repository_open(&g_child, path.ptr)); + assert_sm_valid(g_parent, g_child, "sm_unchanged"); + + git_buf_free(&path); +} + +void test_submodule_open__direct_open_succeeds_for_broken_sm_with_gitdir(void) +{ + git_buf path = GIT_BUF_INIT; + + /* + * This is actually not a valid submodule, but we + * encountered at least one occasion where the gitdir + * file existed inside of a submodule's gitdir. As we are + * now able to open these submodules correctly, we still + * add a test for this. + */ + cl_git_mkfile("submod2/.git/modules/sm_unchanged/gitdir", ".git"); + cl_git_pass(git_buf_joinpath(&path, git_repository_workdir(g_parent), "sm_unchanged")); + cl_git_pass(git_repository_open(&g_child, path.ptr)); + assert_sm_valid(g_parent, g_child, "sm_unchanged"); + + git_buf_free(&path); +} diff --git a/tests/submodule/submodule_helpers.c b/tests/submodule/submodule_helpers.c index 6c2b9cf78..cd541ea86 100644 --- a/tests/submodule/submodule_helpers.c +++ b/tests/submodule/submodule_helpers.c @@ -204,7 +204,7 @@ void assert__submodule_exists( git_submodule *sm; int error = git_submodule_lookup(&sm, repo, name); if (error) - cl_git_report_failure(error, file, line, msg); + cl_git_report_failure(error, 0, file, line, msg); cl_assert_at_line(sm != NULL, file, line); git_submodule_free(sm); } diff --git a/tests/threads/basic.c b/tests/threads/basic.c index 9c342bc42..af6049090 100644 --- a/tests/threads/basic.c +++ b/tests/threads/basic.c @@ -48,3 +48,30 @@ void test_threads_basic__set_error(void) { run_in_parallel(1, 4, set_error, NULL, NULL); } + +#ifdef GIT_THREADS +static void *return_normally(void *param) +{ + return param; +} +#endif + +void test_threads_basic__exit(void) +{ +#ifndef GIT_THREADS + clar__skip(); +#else + git_thread thread; + void *result; + + /* Ensure that the return value of the threadproc is returned. */ + cl_git_pass(git_thread_create(&thread, return_normally, (void *)424242)); + cl_git_pass(git_thread_join(&thread, &result)); + cl_assert_equal_sz(424242, (size_t)result); + + /* Ensure that the return value of `git_thread_exit` is returned. */ + cl_git_pass(git_thread_create(&thread, return_normally, (void *)232323)); + cl_git_pass(git_thread_join(&thread, &result)); + cl_assert_equal_sz(232323, (size_t)result); +#endif +} diff --git a/tests/threads/diff.c b/tests/threads/diff.c index c32811469..256040265 100644 --- a/tests/threads/diff.c +++ b/tests/threads/diff.c @@ -19,12 +19,27 @@ static git_repository *_repo; static git_tree *_a, *_b; static git_atomic _counts[4]; static int _check_counts; +#ifdef GIT_WIN32 +static int _retries; +#endif #define THREADS 20 +void test_threads_diff__initialize(void) +{ +#ifdef GIT_WIN32 + _retries = git_win32__retries; + git_win32__retries = 1; +#endif +} + void test_threads_diff__cleanup(void) { cl_git_sandbox_cleanup(); + +#ifdef GIT_WIN32 + git_win32__retries = _retries; +#endif } static void setup_trees(void) diff --git a/tests/threads/refdb.c b/tests/threads/refdb.c index f869bcb44..94c5f5057 100644 --- a/tests/threads/refdb.c +++ b/tests/threads/refdb.c @@ -5,6 +5,12 @@ static git_repository *g_repo; static int g_expected = 0; +#ifdef GIT_WIN32 +static bool concurrent_compress = false; +#else +static bool concurrent_compress = true; +#endif + void test_threads_refdb__initialize(void) { g_repo = NULL; @@ -18,14 +24,28 @@ void test_threads_refdb__cleanup(void) #define REPEAT 20 #define THREADS 20 +/* Number of references to create or delete in each thread */ +#define NREFS 10 + +struct th_data { + cl_git_thread_err error; + int id; + const char *path; +}; static void *iterate_refs(void *arg) { + struct th_data *data = (struct th_data *) arg; git_reference_iterator *i; git_reference *ref; - int count = 0; + int count = 0, error; + git_repository *repo; - cl_git_pass(git_reference_iterator_new(&i, g_repo)); + cl_git_thread_pass(data, git_repository_open(&repo, data->path)); + do { + error = git_reference_iterator_new(&i, repo); + } while (error == GIT_ELOCKED); + cl_git_thread_pass(data, error); for (count = 0; !git_reference_next(&ref, i); ++count) { cl_assert(ref != NULL); @@ -37,112 +57,92 @@ static void *iterate_refs(void *arg) git_reference_iterator_free(i); + git_repository_free(repo); giterr_clear(); return arg; } -void test_threads_refdb__iterator(void) -{ - int r, t; - git_thread th[THREADS]; - int id[THREADS]; - git_oid head; - git_reference *ref; - char name[128]; - git_refdb *refdb; - - g_repo = cl_git_sandbox_init("testrepo2"); - - cl_git_pass(git_reference_name_to_id(&head, g_repo, "HEAD")); - - /* make a bunch of references */ - - for (r = 0; r < 200; ++r) { - p_snprintf(name, sizeof(name), "refs/heads/direct-%03d", r); - cl_git_pass(git_reference_create(&ref, g_repo, name, &head, 0, NULL)); - git_reference_free(ref); - } - - cl_git_pass(git_repository_refdb(&refdb, g_repo)); - cl_git_pass(git_refdb_compress(refdb)); - git_refdb_free(refdb); - - g_expected = 206; - - for (r = 0; r < REPEAT; ++r) { - g_repo = cl_git_sandbox_reopen(); /* reopen to flush caches */ - - for (t = 0; t < THREADS; ++t) { - id[t] = t; -#ifdef GIT_THREADS - cl_git_pass(git_thread_create(&th[t], iterate_refs, &id[t])); -#else - th[t] = t; - iterate_refs(&id[t]); -#endif - } - -#ifdef GIT_THREADS - for (t = 0; t < THREADS; ++t) { - cl_git_pass(git_thread_join(&th[t], NULL)); - } -#endif - - memset(th, 0, sizeof(th)); - } -} - static void *create_refs(void *arg) { - int *id = arg, i; + int i, error; + struct th_data *data = (struct th_data *) arg; git_oid head; char name[128]; - git_reference *ref[10]; + git_reference *ref[NREFS]; + git_repository *repo; - cl_git_pass(git_reference_name_to_id(&head, g_repo, "HEAD")); + cl_git_thread_pass(data, git_repository_open(&repo, data->path)); - for (i = 0; i < 10; ++i) { - p_snprintf(name, sizeof(name), "refs/heads/thread-%03d-%02d", *id, i); - cl_git_pass(git_reference_create(&ref[i], g_repo, name, &head, 0, NULL)); + do { + error = git_reference_name_to_id(&head, repo, "HEAD"); + } while (error == GIT_ELOCKED); + cl_git_thread_pass(data, error); - if (i == 5) { + for (i = 0; i < NREFS; ++i) { + p_snprintf(name, sizeof(name), "refs/heads/thread-%03d-%02d", data->id, i); + do { + error = git_reference_create(&ref[i], repo, name, &head, 0, NULL); + } while (error == GIT_ELOCKED); + cl_git_thread_pass(data, error); + + if (concurrent_compress && i == NREFS/2) { git_refdb *refdb; - cl_git_pass(git_repository_refdb(&refdb, g_repo)); - cl_git_pass(git_refdb_compress(refdb)); + cl_git_thread_pass(data, git_repository_refdb(&refdb, repo)); + do { + error = git_refdb_compress(refdb); + } while (error == GIT_ELOCKED); + cl_git_thread_pass(data, error); git_refdb_free(refdb); } } - for (i = 0; i < 10; ++i) + for (i = 0; i < NREFS; ++i) git_reference_free(ref[i]); + git_repository_free(repo); + giterr_clear(); return arg; } static void *delete_refs(void *arg) { - int *id = arg, i; + int i, error; + struct th_data *data = (struct th_data *) arg; git_reference *ref; char name[128]; + git_repository *repo; - for (i = 0; i < 10; ++i) { + cl_git_thread_pass(data, git_repository_open(&repo, data->path)); + + for (i = 0; i < NREFS; ++i) { p_snprintf( - name, sizeof(name), "refs/heads/thread-%03d-%02d", (*id) & ~0x3, i); + name, sizeof(name), "refs/heads/thread-%03d-%02d", (data->id) & ~0x3, i); + + if (!git_reference_lookup(&ref, repo, name)) { + do { + error = git_reference_delete(ref); + } while (error == GIT_ELOCKED); + /* Sometimes we race with other deleter threads */ + if (error == GIT_ENOTFOUND) + error = 0; - if (!git_reference_lookup(&ref, g_repo, name)) { - cl_git_pass(git_reference_delete(ref)); + cl_git_thread_pass(data, error); git_reference_free(ref); } - if (i == 5) { + if (concurrent_compress && i == NREFS/2) { git_refdb *refdb; - cl_git_pass(git_repository_refdb(&refdb, g_repo)); - cl_git_pass(git_refdb_compress(refdb)); + cl_git_thread_pass(data, git_repository_refdb(&refdb, repo)); + do { + error = git_refdb_compress(refdb); + } while (error == GIT_ELOCKED); + cl_git_thread_pass(data, error); git_refdb_free(refdb); } } + git_repository_free(repo); giterr_clear(); return arg; } @@ -150,7 +150,7 @@ static void *delete_refs(void *arg) void test_threads_refdb__edit_while_iterate(void) { int r, t; - int id[THREADS]; + struct th_data th_data[THREADS]; git_oid head; git_reference *ref; char name[128]; @@ -189,33 +189,32 @@ void test_threads_refdb__edit_while_iterate(void) default: fn = iterate_refs; break; } - id[t] = t; - - /* It appears with all reflog writing changes, etc., that this - * test has started to fail quite frequently, so let's disable it - * for now by just running on a single thread... - */ -/* #ifdef GIT_THREADS */ -/* cl_git_pass(git_thread_create(&th[t], fn, &id[t])); */ -/* #else */ - fn(&id[t]); -/* #endif */ + th_data[t].id = t; + th_data[t].path = git_repository_path(g_repo); + +#ifdef GIT_THREADS + cl_git_pass(git_thread_create(&th[t], fn, &th_data[t])); +#else + fn(&th_data[t]); +#endif } #ifdef GIT_THREADS -/* for (t = 0; t < THREADS; ++t) { */ -/* cl_git_pass(git_thread_join(th[t], NULL)); */ -/* } */ + for (t = 0; t < THREADS; ++t) { + cl_git_pass(git_thread_join(&th[t], NULL)); + cl_git_thread_check(&th_data[t]); + } memset(th, 0, sizeof(th)); for (t = 0; t < THREADS; ++t) { - id[t] = t; - cl_git_pass(git_thread_create(&th[t], iterate_refs, &id[t])); + th_data[t].id = t; + cl_git_pass(git_thread_create(&th[t], iterate_refs, &th_data[t])); } for (t = 0; t < THREADS; ++t) { cl_git_pass(git_thread_join(&th[t], NULL)); + cl_git_thread_check(&th_data[t]); } #endif } diff --git a/tests/worktree/config.c b/tests/worktree/config.c new file mode 100644 index 000000000..3ab317bb5 --- /dev/null +++ b/tests/worktree/config.c @@ -0,0 +1,45 @@ +#include "clar_libgit2.h" +#include "worktree_helpers.h" + +#define COMMON_REPO "testrepo" +#define WORKTREE_REPO "testrepo-worktree" + +static worktree_fixture fixture = + WORKTREE_FIXTURE_INIT(COMMON_REPO, WORKTREE_REPO); + +void test_worktree_config__initialize(void) +{ + setup_fixture_worktree(&fixture); +} + +void test_worktree_config__cleanup(void) +{ + cleanup_fixture_worktree(&fixture); +} + +void test_worktree_config__open(void) +{ + git_config *cfg; + + cl_git_pass(git_repository_config(&cfg, fixture.worktree)); + cl_assert(cfg != NULL); + + git_config_free(cfg); +} + +void test_worktree_config__set(void) +{ + git_config *cfg; + int32_t val; + + cl_git_pass(git_repository_config(&cfg, fixture.worktree)); + cl_git_pass(git_config_set_int32(cfg, "core.dummy", 5)); + git_config_free(cfg); + + // reopen to verify configuration has been set in the + // common dir + cl_git_pass(git_repository_config(&cfg, fixture.repo)); + cl_git_pass(git_config_get_int32(&val, cfg, "core.dummy")); + cl_assert_equal_i(val, 5); + git_config_free(cfg); +} diff --git a/tests/worktree/merge.c b/tests/worktree/merge.c new file mode 100644 index 000000000..36cc2a6c1 --- /dev/null +++ b/tests/worktree/merge.c @@ -0,0 +1,121 @@ +#include "clar_libgit2.h" + +#include "worktree_helpers.h" +#include "merge/merge_helpers.h" + +#define COMMON_REPO "testrepo" +#define WORKTREE_REPO "testrepo-worktree" + +#define MASTER_BRANCH "refs/heads/master" +#define CONFLICT_BRANCH "refs/heads/merge-conflict" + +#define CONFLICT_BRANCH_FILE_TXT \ + "<<<<<<< HEAD\n" \ + "hi\n" \ + "bye!\n" \ + "=======\n" \ + "conflict\n" \ + ">>>>>>> merge-conflict\n" \ + +static worktree_fixture fixture = + WORKTREE_FIXTURE_INIT(COMMON_REPO, WORKTREE_REPO); + +static const char *merge_files[] = { + GIT_MERGE_HEAD_FILE, + GIT_ORIG_HEAD_FILE, + GIT_MERGE_MODE_FILE, + GIT_MERGE_MSG_FILE, +}; + +void test_worktree_merge__initialize(void) +{ + setup_fixture_worktree(&fixture); +} + +void test_worktree_merge__cleanup(void) +{ + cleanup_fixture_worktree(&fixture); +} + +void test_worktree_merge__merge_head(void) +{ + git_reference *theirs_ref, *ref; + git_annotated_commit *theirs; + + cl_git_pass(git_reference_lookup(&theirs_ref, fixture.worktree, CONFLICT_BRANCH)); + cl_git_pass(git_annotated_commit_from_ref(&theirs, fixture.worktree, theirs_ref)); + cl_git_pass(git_merge(fixture.worktree, (const git_annotated_commit **)&theirs, 1, NULL, NULL)); + + cl_git_pass(git_reference_lookup(&ref, fixture.worktree, GIT_MERGE_HEAD_FILE)); + + git_reference_free(ref); + git_reference_free(theirs_ref); + git_annotated_commit_free(theirs); +} + +void test_worktree_merge__merge_setup(void) +{ + git_reference *ours_ref, *theirs_ref; + git_annotated_commit *ours, *theirs; + git_buf path = GIT_BUF_INIT; + unsigned i; + + cl_git_pass(git_reference_lookup(&ours_ref, fixture.worktree, MASTER_BRANCH)); + cl_git_pass(git_annotated_commit_from_ref(&ours, fixture.worktree, ours_ref)); + + cl_git_pass(git_reference_lookup(&theirs_ref, fixture.worktree, CONFLICT_BRANCH)); + cl_git_pass(git_annotated_commit_from_ref(&theirs, fixture.worktree, theirs_ref)); + + cl_git_pass(git_merge__setup(fixture.worktree, + ours, (const git_annotated_commit **)&theirs, 1)); + + for (i = 0; i < ARRAY_SIZE(merge_files); i++) { + git_buf_clear(&path); + cl_git_pass(git_buf_printf(&path, "%s/%s", + fixture.worktree->gitdir, merge_files[i])); + cl_assert(git_path_exists(path.ptr)); + } + + git_buf_free(&path); + git_reference_free(ours_ref); + git_reference_free(theirs_ref); + git_annotated_commit_free(ours); + git_annotated_commit_free(theirs); +} + +void test_worktree_merge__merge_conflict(void) +{ + git_buf path = GIT_BUF_INIT, buf = GIT_BUF_INIT; + git_reference *theirs_ref; + git_annotated_commit *theirs; + git_index *index; + const git_index_entry *entry; + size_t i, conflicts = 0; + + cl_git_pass(git_reference_lookup(&theirs_ref, fixture.worktree, CONFLICT_BRANCH)); + cl_git_pass(git_annotated_commit_from_ref(&theirs, fixture.worktree, theirs_ref)); + + cl_git_pass(git_merge(fixture.worktree, + (const git_annotated_commit **)&theirs, 1, NULL, NULL)); + + cl_git_pass(git_repository_index(&index, fixture.worktree)); + for (i = 0; i < git_index_entrycount(index); i++) { + cl_assert(entry = git_index_get_byindex(index, i)); + + if (git_index_entry_is_conflict(entry)) + conflicts++; + } + cl_assert_equal_sz(conflicts, 3); + + git_reference_free(theirs_ref); + git_annotated_commit_free(theirs); + git_index_free(index); + + cl_git_pass(git_buf_joinpath(&path, fixture.worktree->workdir, "branch_file.txt")); + cl_git_pass(git_futils_readbuffer(&buf, path.ptr)); + cl_assert_equal_s(buf.ptr, CONFLICT_BRANCH_FILE_TXT); + + git_buf_free(&path); + git_buf_free(&buf); +} + diff --git a/tests/worktree/open.c b/tests/worktree/open.c new file mode 100644 index 000000000..74b9007d9 --- /dev/null +++ b/tests/worktree/open.c @@ -0,0 +1,143 @@ +#include "clar_libgit2.h" +#include "repository.h" +#include "worktree.h" +#include "worktree_helpers.h" + +#define COMMON_REPO "testrepo" +#define WORKTREE_REPO "testrepo-worktree" + +static worktree_fixture fixture = + WORKTREE_FIXTURE_INIT(COMMON_REPO, WORKTREE_REPO); + +static void assert_worktree_valid(git_repository *wt, const char *parentdir, const char *wtdir) +{ + git_buf path = GIT_BUF_INIT; + + cl_assert(wt->is_worktree); + + cl_git_pass(git_buf_joinpath(&path, clar_sandbox_path(), wtdir)); + cl_git_pass(git_path_prettify(&path, path.ptr, NULL)); + cl_git_pass(git_path_to_dir(&path)); + cl_assert_equal_s(wt->workdir, path.ptr); + + cl_git_pass(git_buf_joinpath(&path, path.ptr, ".git")); + cl_git_pass(git_path_prettify(&path, path.ptr, NULL)); + cl_assert_equal_s(wt->gitlink, path.ptr); + + cl_git_pass(git_buf_joinpath(&path, clar_sandbox_path(), parentdir)); + cl_git_pass(git_buf_joinpath(&path, path.ptr, ".git")); + cl_git_pass(git_buf_joinpath(&path, path.ptr, "worktrees")); + cl_git_pass(git_buf_joinpath(&path, path.ptr, wtdir)); + cl_git_pass(git_path_prettify(&path, path.ptr, NULL)); + cl_git_pass(git_path_to_dir(&path)); + cl_assert_equal_s(wt->gitdir, path.ptr); + + git_buf_free(&path); +} + +void test_worktree_open__initialize(void) +{ + setup_fixture_worktree(&fixture); +} + +void test_worktree_open__cleanup(void) +{ + cleanup_fixture_worktree(&fixture); +} + +void test_worktree_open__repository(void) +{ + assert_worktree_valid(fixture.worktree, COMMON_REPO, WORKTREE_REPO); +} + +void test_worktree_open__repository_through_workdir(void) +{ + git_repository *wt; + + cl_git_pass(git_repository_open(&wt, WORKTREE_REPO)); + assert_worktree_valid(wt, COMMON_REPO, WORKTREE_REPO); + + git_repository_free(wt); +} + +void test_worktree_open__repository_through_gitlink(void) +{ + git_repository *wt; + + cl_git_pass(git_repository_open(&wt, WORKTREE_REPO "/.git")); + assert_worktree_valid(wt, COMMON_REPO, WORKTREE_REPO); + + git_repository_free(wt); +} + +void test_worktree_open__repository_through_gitdir(void) +{ + git_buf gitdir_path = GIT_BUF_INIT; + git_repository *wt; + + cl_git_pass(git_buf_joinpath(&gitdir_path, COMMON_REPO, ".git")); + cl_git_pass(git_buf_joinpath(&gitdir_path, gitdir_path.ptr, "worktrees")); + cl_git_pass(git_buf_joinpath(&gitdir_path, gitdir_path.ptr, "testrepo-worktree")); + + cl_git_pass(git_repository_open(&wt, gitdir_path.ptr)); + assert_worktree_valid(wt, COMMON_REPO, WORKTREE_REPO); + + git_buf_free(&gitdir_path); + git_repository_free(wt); +} + +void test_worktree_open__open_discovered_worktree(void) +{ + git_buf path = GIT_BUF_INIT; + git_repository *repo; + + cl_git_pass(git_repository_discover(&path, + git_repository_workdir(fixture.worktree), false, NULL)); + cl_git_pass(git_repository_open(&repo, path.ptr)); + cl_assert_equal_s(git_repository_workdir(fixture.worktree), + git_repository_workdir(repo)); + + git_buf_free(&path); + git_repository_free(repo); +} + +void test_worktree_open__repository_with_nonexistent_parent(void) +{ + git_repository *repo; + + cleanup_fixture_worktree(&fixture); + + cl_fixture_sandbox(WORKTREE_REPO); + cl_git_pass(p_chdir(WORKTREE_REPO)); + cl_git_pass(cl_rename(".gitted", ".git")); + cl_git_pass(p_chdir("..")); + + cl_git_fail(git_repository_open(&repo, WORKTREE_REPO)); + + cl_fixture_cleanup(WORKTREE_REPO); +} + +void test_worktree_open__open_from_repository(void) +{ + git_worktree *opened, *lookedup; + + cl_git_pass(git_worktree_open_from_repository(&opened, fixture.worktree)); + cl_git_pass(git_worktree_lookup(&lookedup, fixture.repo, WORKTREE_REPO)); + + cl_assert_equal_s(opened->name, lookedup->name); + cl_assert_equal_s(opened->gitdir_path, lookedup->gitdir_path); + cl_assert_equal_s(opened->gitlink_path, lookedup->gitlink_path); + cl_assert_equal_s(opened->parent_path, lookedup->parent_path); + cl_assert_equal_s(opened->commondir_path, lookedup->commondir_path); + cl_assert_equal_i(opened->locked, lookedup->locked); + + git_worktree_free(opened); + git_worktree_free(lookedup); +} + +void test_worktree_open__open_from_nonworktree_fails(void) +{ + git_worktree *wt; + + cl_git_fail(git_worktree_open_from_repository(&wt, fixture.repo)); +} diff --git a/tests/worktree/reflog.c b/tests/worktree/reflog.c new file mode 100644 index 000000000..6152eb385 --- /dev/null +++ b/tests/worktree/reflog.c @@ -0,0 +1,65 @@ +#include "clar_libgit2.h" +#include "worktree_helpers.h" + +#include "reflog.h" + +#define COMMON_REPO "testrepo" +#define WORKTREE_REPO "testrepo-worktree" + +#define REFLOG "refs/heads/testrepo-worktree" +#define REFLOG_MESSAGE "reflog message" + +static worktree_fixture fixture = + WORKTREE_FIXTURE_INIT(COMMON_REPO, WORKTREE_REPO); + +void test_worktree_reflog__initialize(void) +{ + setup_fixture_worktree(&fixture); +} + +void test_worktree_reflog__cleanup(void) +{ + cleanup_fixture_worktree(&fixture); +} + +void test_worktree_reflog__read(void) +{ + git_reflog *reflog; + const git_reflog_entry *entry; + + cl_git_pass(git_reflog_read(&reflog, fixture.worktree, REFLOG)); + cl_assert_equal_i(git_reflog_entrycount(reflog), 1); + + entry = git_reflog_entry_byindex(reflog, 0); + cl_assert(entry != NULL); + cl_assert_equal_s(git_reflog_entry_message(entry), "branch: Created from HEAD"); + + git_reflog_free(reflog); +} + +void test_worktree_reflog__append_then_read(void) +{ + git_reflog *reflog, *parent_reflog; + const git_reflog_entry *entry; + git_reference *head; + git_signature *sig; + const git_oid *oid; + + cl_git_pass(git_repository_head(&head, fixture.worktree)); + cl_assert((oid = git_reference_target(head)) != NULL); + cl_git_pass(git_signature_now(&sig, "foo", "foo@bar")); + + cl_git_pass(git_reflog_read(&reflog, fixture.worktree, REFLOG)); + cl_git_pass(git_reflog_append(reflog, oid, sig, REFLOG_MESSAGE)); + git_reflog_write(reflog); + + cl_git_pass(git_reflog_read(&parent_reflog, fixture.repo, REFLOG)); + entry = git_reflog_entry_byindex(parent_reflog, 0); + cl_assert(git_oid_cmp(oid, &entry->oid_old) == 0); + cl_assert(git_oid_cmp(oid, &entry->oid_cur) == 0); + + git_reference_free(head); + git_signature_free(sig); + git_reflog_free(reflog); + git_reflog_free(parent_reflog); +} diff --git a/tests/worktree/refs.c b/tests/worktree/refs.c new file mode 100644 index 000000000..a10f50a2c --- /dev/null +++ b/tests/worktree/refs.c @@ -0,0 +1,173 @@ +#include "clar_libgit2.h" +#include "path.h" +#include "refs.h" +#include "worktree.h" +#include "worktree_helpers.h" + +#define COMMON_REPO "testrepo" +#define WORKTREE_REPO "testrepo-worktree" + +static worktree_fixture fixture = + WORKTREE_FIXTURE_INIT(COMMON_REPO, WORKTREE_REPO); + +void test_worktree_refs__initialize(void) +{ + setup_fixture_worktree(&fixture); +} + +void test_worktree_refs__cleanup(void) +{ + cleanup_fixture_worktree(&fixture); +} + +void test_worktree_refs__list(void) +{ + git_strarray refs, wtrefs; + unsigned i, j; + int error = 0; + + cl_git_pass(git_reference_list(&refs, fixture.repo)); + cl_git_pass(git_reference_list(&wtrefs, fixture.worktree)); + + if (refs.count != wtrefs.count) + { + error = GIT_ERROR; + goto exit; + } + + for (i = 0; i < refs.count; i++) + { + int found = 0; + + for (j = 0; j < wtrefs.count; j++) + { + if (!strcmp(refs.strings[i], wtrefs.strings[j])) + { + found = 1; + break; + } + } + + if (!found) + { + error = GIT_ERROR; + goto exit; + } + } + +exit: + git_strarray_free(&refs); + git_strarray_free(&wtrefs); + cl_git_pass(error); +} + +void test_worktree_refs__read_head(void) +{ + git_reference *head; + + cl_git_pass(git_repository_head(&head, fixture.worktree)); + + git_reference_free(head); +} + +void test_worktree_refs__set_head_fails_when_worktree_wants_linked_repos_HEAD(void) +{ + git_reference *head; + + cl_git_pass(git_repository_head(&head, fixture.repo)); + cl_git_fail(git_repository_set_head(fixture.worktree, git_reference_name(head))); + + git_reference_free(head); +} + +void test_worktree_refs__set_head_fails_when_main_repo_wants_worktree_head(void) +{ + git_reference *head; + + cl_git_pass(git_repository_head(&head, fixture.worktree)); + cl_git_fail(git_repository_set_head(fixture.repo, git_reference_name(head))); + + git_reference_free(head); +} + +void test_worktree_refs__set_head_works_for_current_HEAD(void) +{ + git_reference *head; + + cl_git_pass(git_repository_head(&head, fixture.repo)); + cl_git_pass(git_repository_set_head(fixture.repo, git_reference_name(head))); + + git_reference_free(head); +} + +void test_worktree_refs__set_head_fails_when_already_checked_out(void) +{ + cl_git_fail(git_repository_set_head(fixture.repo, "refs/heads/testrepo-worktree")); +} + +void test_worktree_refs__delete_fails_for_checked_out_branch(void) +{ + git_reference *branch; + + cl_git_pass(git_branch_lookup(&branch, fixture.repo, + "testrepo-worktree", GIT_BRANCH_LOCAL)); + cl_git_fail(git_branch_delete(branch)); + + git_reference_free(branch); +} + +void test_worktree_refs__delete_succeeds_after_pruning_worktree(void) +{ + git_worktree_prune_options opts = GIT_WORKTREE_PRUNE_OPTIONS_INIT; + git_reference *branch; + git_worktree *worktree; + + opts.flags = GIT_WORKTREE_PRUNE_VALID; + + cl_git_pass(git_worktree_lookup(&worktree, fixture.repo, fixture.worktreename)); + cl_git_pass(git_worktree_prune(worktree, &opts)); + git_worktree_free(worktree); + + cl_git_pass(git_branch_lookup(&branch, fixture.repo, + "testrepo-worktree", GIT_BRANCH_LOCAL)); + cl_git_pass(git_branch_delete(branch)); + git_reference_free(branch); +} + +void test_worktree_refs__renaming_reference_updates_worktree_heads(void) +{ + git_reference *head, *branch, *renamed; + + cl_git_pass(git_branch_lookup(&branch, fixture.repo, + "testrepo-worktree", GIT_BRANCH_LOCAL)); + cl_git_pass(git_reference_rename(&renamed, branch, "refs/heads/renamed", 0, NULL)); + cl_git_pass(git_repository_head(&head, fixture.worktree)); + + git_reference_free(head); + git_reference_free(branch); + git_reference_free(renamed); +} + +void test_worktree_refs__creating_refs_uses_commondir(void) +{ + git_reference *head, *branch, *lookup; + git_commit *commit; + git_buf refpath = GIT_BUF_INIT; + + cl_git_pass(git_buf_joinpath(&refpath, + git_repository_commondir(fixture.worktree), "refs/heads/testbranch")); + cl_assert(!git_path_exists(refpath.ptr)); + + cl_git_pass(git_repository_head(&head, fixture.worktree)); + cl_git_pass(git_commit_lookup(&commit, fixture.worktree, git_reference_target(head))); + cl_git_pass(git_branch_create(&branch, fixture.worktree, "testbranch", commit, 0)); + cl_git_pass(git_branch_lookup(&lookup, fixture.worktree, "testbranch", GIT_BRANCH_LOCAL)); + cl_assert(git_reference_cmp(branch, lookup) == 0); + cl_assert(git_path_exists(refpath.ptr)); + + git_reference_free(lookup); + git_reference_free(branch); + git_reference_free(head); + git_commit_free(commit); + git_buf_free(&refpath); +} diff --git a/tests/worktree/repository.c b/tests/worktree/repository.c new file mode 100644 index 000000000..5c7595c64 --- /dev/null +++ b/tests/worktree/repository.c @@ -0,0 +1,63 @@ +#include "clar_libgit2.h" +#include "worktree_helpers.h" +#include "submodule/submodule_helpers.h" + +#include "repository.h" + +#define COMMON_REPO "testrepo" +#define WORKTREE_REPO "testrepo-worktree" + +static worktree_fixture fixture = + WORKTREE_FIXTURE_INIT(COMMON_REPO, WORKTREE_REPO); + +void test_worktree_repository__initialize(void) +{ + setup_fixture_worktree(&fixture); +} + +void test_worktree_repository__cleanup(void) +{ + cleanup_fixture_worktree(&fixture); +} + +void test_worktree_repository__head(void) +{ + git_reference *ref, *head; + + cl_git_pass(git_reference_lookup(&ref, fixture.repo, "refs/heads/testrepo-worktree")); + cl_git_pass(git_repository_head_for_worktree(&head, fixture.repo, "testrepo-worktree")); + cl_assert(git_reference_cmp(ref, head) == 0); + + git_reference_free(ref); + git_reference_free(head); +} + +void test_worktree_repository__head_fails_for_invalid_worktree(void) +{ + git_reference *head = NULL; + + cl_git_fail(git_repository_head_for_worktree(&head, fixture.repo, "invalid")); + cl_assert(head == NULL); +} + +void test_worktree_repository__head_detached(void) +{ + git_reference *ref, *head; + + cl_git_pass(git_reference_lookup(&ref, fixture.repo, "refs/heads/testrepo-worktree")); + cl_git_pass(git_repository_set_head_detached(fixture.worktree, &ref->target.oid)); + + cl_assert(git_repository_head_detached(fixture.worktree)); + cl_assert(git_repository_head_detached_for_worktree(fixture.repo, "testrepo-worktree")); + cl_git_fail(git_repository_head_for_worktree(&head, fixture.repo, "testrepo-worktree")); + + git_reference_free(ref); +} + +void test_worktree_repository__head_detached_fails_for_invalid_worktree(void) +{ + git_reference *head = NULL; + + cl_git_fail(git_repository_head_detached_for_worktree(fixture.repo, "invalid")); + cl_assert(head == NULL); +} diff --git a/tests/worktree/submodule.c b/tests/worktree/submodule.c new file mode 100644 index 000000000..294385226 --- /dev/null +++ b/tests/worktree/submodule.c @@ -0,0 +1,92 @@ +#include "clar_libgit2.h" +#include "repository.h" +#include "worktree.h" +#include "worktree_helpers.h" + +#define WORKTREE_PARENT "submodules-worktree-parent" +#define WORKTREE_CHILD "submodules-worktree-child" + +static worktree_fixture parent + = WORKTREE_FIXTURE_INIT("submodules", WORKTREE_PARENT); +static worktree_fixture child + = WORKTREE_FIXTURE_INIT(NULL, WORKTREE_CHILD); + +void test_worktree_submodule__initialize(void) +{ + setup_fixture_worktree(&parent); + + cl_git_pass(p_rename( + "submodules/testrepo/.gitted", + "submodules/testrepo/.git")); + + setup_fixture_worktree(&child); +} + +void test_worktree_submodule__cleanup(void) +{ + cleanup_fixture_worktree(&child); + cleanup_fixture_worktree(&parent); +} + +void test_worktree_submodule__submodule_worktree_parent(void) +{ + cl_assert(git_repository_path(parent.worktree) != NULL); + cl_assert(git_repository_workdir(parent.worktree) != NULL); + + cl_assert(!parent.repo->is_worktree); + cl_assert(parent.worktree->is_worktree); +} + +void test_worktree_submodule__submodule_worktree_child(void) +{ + cl_assert(!parent.repo->is_worktree); + cl_assert(parent.worktree->is_worktree); + cl_assert(child.worktree->is_worktree); +} + +void test_worktree_submodule__open_discovered_submodule_worktree(void) +{ + git_buf path = GIT_BUF_INIT; + git_repository *repo; + + cl_git_pass(git_repository_discover(&path, + git_repository_workdir(child.worktree), false, NULL)); + cl_git_pass(git_repository_open(&repo, path.ptr)); + cl_assert_equal_s(git_repository_workdir(child.worktree), + git_repository_workdir(repo)); + + git_buf_free(&path); + git_repository_free(repo); +} + +void test_worktree_submodule__resolve_relative_url(void) +{ + git_buf wt_path = GIT_BUF_INIT; + git_buf sm_relative_path = GIT_BUF_INIT, wt_relative_path = GIT_BUF_INIT; + git_repository *repo; + git_worktree *wt; + + cl_git_pass(git_futils_mkdir("subdir", 0755, GIT_MKDIR_PATH)); + cl_git_pass(git_path_prettify_dir(&wt_path, "subdir", NULL)); + cl_git_pass(git_buf_joinpath(&wt_path, wt_path.ptr, "wt")); + + /* Open child repository, which is a submodule */ + cl_git_pass(git_repository_open(&child.repo, WORKTREE_CHILD)); + + /* Create worktree of submodule repository */ + cl_git_pass(git_worktree_add(&wt, child.repo, "subdir", wt_path.ptr, NULL)); + cl_git_pass(git_repository_open_from_worktree(&repo, wt)); + + cl_git_pass(git_submodule_resolve_url(&sm_relative_path, repo, + "../" WORKTREE_CHILD)); + cl_git_pass(git_submodule_resolve_url(&wt_relative_path, child.repo, + "../" WORKTREE_CHILD)); + + cl_assert_equal_s(sm_relative_path.ptr, wt_relative_path.ptr); + + git_worktree_free(wt); + git_repository_free(repo); + git_buf_free(&wt_path); + git_buf_free(&sm_relative_path); + git_buf_free(&wt_relative_path); +} diff --git a/tests/worktree/worktree.c b/tests/worktree/worktree.c new file mode 100644 index 000000000..4ac3b8bba --- /dev/null +++ b/tests/worktree/worktree.c @@ -0,0 +1,583 @@ +#include "clar_libgit2.h" +#include "worktree_helpers.h" +#include "submodule/submodule_helpers.h" + +#include "checkout.h" +#include "repository.h" +#include "worktree.h" + +#define COMMON_REPO "testrepo" +#define WORKTREE_REPO "testrepo-worktree" + +static worktree_fixture fixture = + WORKTREE_FIXTURE_INIT(COMMON_REPO, WORKTREE_REPO); + +void test_worktree_worktree__initialize(void) +{ + setup_fixture_worktree(&fixture); +} + +void test_worktree_worktree__cleanup(void) +{ + cleanup_fixture_worktree(&fixture); +} + +void test_worktree_worktree__list(void) +{ + git_strarray wts; + + cl_git_pass(git_worktree_list(&wts, fixture.repo)); + cl_assert_equal_i(wts.count, 1); + cl_assert_equal_s(wts.strings[0], "testrepo-worktree"); + + git_strarray_free(&wts); +} + +void test_worktree_worktree__list_with_invalid_worktree_dirs(void) +{ + const char *filesets[3][2] = { + { "gitdir", "commondir" }, + { "gitdir", "HEAD" }, + { "HEAD", "commondir" }, + }; + git_buf path = GIT_BUF_INIT; + git_strarray wts; + unsigned i, j, len; + + cl_git_pass(git_buf_printf(&path, "%s/worktrees/invalid", + fixture.repo->commondir)); + cl_git_pass(p_mkdir(path.ptr, 0755)); + + len = path.size; + + for (i = 0; i < ARRAY_SIZE(filesets); i++) { + + for (j = 0; j < ARRAY_SIZE(filesets[i]); j++) { + git_buf_truncate(&path, len); + cl_git_pass(git_buf_joinpath(&path, path.ptr, filesets[i][j])); + cl_git_pass(p_close(p_creat(path.ptr, 0644))); + } + + cl_git_pass(git_worktree_list(&wts, fixture.worktree)); + cl_assert_equal_i(wts.count, 1); + cl_assert_equal_s(wts.strings[0], "testrepo-worktree"); + git_strarray_free(&wts); + + for (j = 0; j < ARRAY_SIZE(filesets[i]); j++) { + git_buf_truncate(&path, len); + cl_git_pass(git_buf_joinpath(&path, path.ptr, filesets[i][j])); + p_unlink(path.ptr); + } + } + + git_buf_free(&path); +} + +void test_worktree_worktree__list_in_worktree_repo(void) +{ + git_strarray wts; + + cl_git_pass(git_worktree_list(&wts, fixture.worktree)); + cl_assert_equal_i(wts.count, 1); + cl_assert_equal_s(wts.strings[0], "testrepo-worktree"); + + git_strarray_free(&wts); +} + +void test_worktree_worktree__list_bare(void) +{ + git_repository *repo; + git_strarray wts; + + repo = cl_git_sandbox_init("testrepo.git"); + cl_git_pass(git_worktree_list(&wts, repo)); + cl_assert_equal_i(wts.count, 0); + + git_repository_free(repo); +} + +void test_worktree_worktree__list_without_worktrees(void) +{ + git_repository *repo; + git_strarray wts; + + repo = cl_git_sandbox_init("testrepo2"); + cl_git_pass(git_worktree_list(&wts, repo)); + cl_assert_equal_i(wts.count, 0); + + git_repository_free(repo); +} + +void test_worktree_worktree__lookup(void) +{ + git_worktree *wt; + git_buf gitdir_path = GIT_BUF_INIT; + + cl_git_pass(git_worktree_lookup(&wt, fixture.repo, "testrepo-worktree")); + + cl_git_pass(git_buf_joinpath(&gitdir_path, fixture.repo->commondir, "worktrees/testrepo-worktree/")); + + cl_assert_equal_s(wt->gitdir_path, gitdir_path.ptr); + cl_assert_equal_s(wt->parent_path, fixture.repo->workdir); + cl_assert_equal_s(wt->gitlink_path, fixture.worktree->gitlink); + cl_assert_equal_s(wt->commondir_path, fixture.repo->gitdir); + cl_assert_equal_s(wt->commondir_path, fixture.repo->commondir); + + git_buf_free(&gitdir_path); + git_worktree_free(wt); +} + +void test_worktree_worktree__lookup_nonexistent_worktree(void) +{ + git_worktree *wt; + + cl_git_fail(git_worktree_lookup(&wt, fixture.repo, "nonexistent")); + cl_assert_equal_p(wt, NULL); +} + +void test_worktree_worktree__open(void) +{ + git_worktree *wt; + git_repository *repo; + + cl_git_pass(git_worktree_lookup(&wt, fixture.repo, "testrepo-worktree")); + + cl_git_pass(git_repository_open_from_worktree(&repo, wt)); + cl_assert_equal_s(git_repository_workdir(repo), + git_repository_workdir(fixture.worktree)); + + git_repository_free(repo); + git_worktree_free(wt); +} + +void test_worktree_worktree__open_invalid_commondir(void) +{ + git_worktree *wt; + git_repository *repo; + git_buf buf = GIT_BUF_INIT, path = GIT_BUF_INIT; + + cl_git_pass(git_buf_sets(&buf, "/path/to/nonexistent/commondir")); + cl_git_pass(git_buf_printf(&path, + "%s/worktrees/testrepo-worktree/commondir", + fixture.repo->commondir)); + cl_git_pass(git_futils_writebuffer(&buf, path.ptr, O_RDWR, 0644)); + + cl_git_pass(git_worktree_lookup(&wt, fixture.repo, "testrepo-worktree")); + cl_git_fail(git_repository_open_from_worktree(&repo, wt)); + + git_buf_free(&buf); + git_buf_free(&path); + git_worktree_free(wt); +} + +void test_worktree_worktree__open_invalid_gitdir(void) +{ + git_worktree *wt; + git_repository *repo; + git_buf buf = GIT_BUF_INIT, path = GIT_BUF_INIT; + + cl_git_pass(git_buf_sets(&buf, "/path/to/nonexistent/gitdir")); + cl_git_pass(git_buf_printf(&path, + "%s/worktrees/testrepo-worktree/gitdir", + fixture.repo->commondir)); + cl_git_pass(git_futils_writebuffer(&buf, path.ptr, O_RDWR, 0644)); + + cl_git_pass(git_worktree_lookup(&wt, fixture.repo, "testrepo-worktree")); + cl_git_fail(git_repository_open_from_worktree(&repo, wt)); + + git_buf_free(&buf); + git_buf_free(&path); + git_worktree_free(wt); +} + +void test_worktree_worktree__open_invalid_parent(void) +{ + git_worktree *wt; + git_repository *repo; + git_buf buf = GIT_BUF_INIT; + + cl_git_pass(git_buf_sets(&buf, "/path/to/nonexistent/gitdir")); + cl_git_pass(git_futils_writebuffer(&buf, + fixture.worktree->gitlink, O_RDWR, 0644)); + + cl_git_pass(git_worktree_lookup(&wt, fixture.repo, "testrepo-worktree")); + cl_git_fail(git_repository_open_from_worktree(&repo, wt)); + + git_buf_free(&buf); + git_worktree_free(wt); +} + +void test_worktree_worktree__init(void) +{ + git_worktree *wt; + git_repository *repo; + git_reference *branch; + git_buf path = GIT_BUF_INIT; + + cl_git_pass(git_buf_joinpath(&path, fixture.repo->workdir, "../worktree-new")); + cl_git_pass(git_worktree_add(&wt, fixture.repo, "worktree-new", path.ptr, NULL)); + + /* Open and verify created repo */ + cl_git_pass(git_repository_open(&repo, path.ptr)); + cl_assert(git__suffixcmp(git_repository_workdir(repo), "worktree-new/") == 0); + cl_git_pass(git_branch_lookup(&branch, repo, "worktree-new", GIT_BRANCH_LOCAL)); + + git_buf_free(&path); + git_worktree_free(wt); + git_reference_free(branch); + git_repository_free(repo); +} + +void test_worktree_worktree__add_locked(void) +{ + git_worktree *wt; + git_repository *repo; + git_reference *branch; + git_buf path = GIT_BUF_INIT; + git_worktree_add_options opts = GIT_WORKTREE_ADD_OPTIONS_INIT; + + opts.lock = 1; + + cl_git_pass(git_buf_joinpath(&path, fixture.repo->workdir, "../worktree-locked")); + cl_git_pass(git_worktree_add(&wt, fixture.repo, "worktree-locked", path.ptr, &opts)); + + /* Open and verify created repo */ + cl_assert(git_worktree_is_locked(NULL, wt)); + cl_git_pass(git_repository_open(&repo, path.ptr)); + cl_assert(git__suffixcmp(git_repository_workdir(repo), "worktree-locked/") == 0); + cl_git_pass(git_branch_lookup(&branch, repo, "worktree-locked", GIT_BRANCH_LOCAL)); + + git_buf_free(&path); + git_worktree_free(wt); + git_reference_free(branch); + git_repository_free(repo); +} + +void test_worktree_worktree__init_existing_branch(void) +{ + git_reference *head, *branch; + git_commit *commit; + git_worktree *wt; + git_buf path = GIT_BUF_INIT; + + cl_git_pass(git_repository_head(&head, fixture.repo)); + cl_git_pass(git_commit_lookup(&commit, fixture.repo, &head->target.oid)); + cl_git_pass(git_branch_create(&branch, fixture.repo, "worktree-new", commit, false)); + + cl_git_pass(git_buf_joinpath(&path, fixture.repo->workdir, "../worktree-new")); + cl_git_fail(git_worktree_add(&wt, fixture.repo, "worktree-new", path.ptr, NULL)); + + git_buf_free(&path); + git_commit_free(commit); + git_reference_free(head); + git_reference_free(branch); +} + +void test_worktree_worktree__init_existing_worktree(void) +{ + git_worktree *wt; + git_buf path = GIT_BUF_INIT; + + cl_git_pass(git_buf_joinpath(&path, fixture.repo->workdir, "../worktree-new")); + cl_git_fail(git_worktree_add(&wt, fixture.repo, "testrepo-worktree", path.ptr, NULL)); + + cl_git_pass(git_worktree_lookup(&wt, fixture.repo, "testrepo-worktree")); + cl_assert_equal_s(wt->gitlink_path, fixture.worktree->gitlink); + + git_buf_free(&path); + git_worktree_free(wt); +} + +void test_worktree_worktree__init_existing_path(void) +{ + const char *wtfiles[] = { "HEAD", "commondir", "gitdir", "index" }; + git_worktree *wt; + git_buf path = GIT_BUF_INIT; + unsigned i; + + /* Delete files to verify they have not been created by + * the init call */ + for (i = 0; i < ARRAY_SIZE(wtfiles); i++) { + cl_git_pass(git_buf_joinpath(&path, + fixture.worktree->gitdir, wtfiles[i])); + cl_git_pass(p_unlink(path.ptr)); + } + + cl_git_pass(git_buf_joinpath(&path, fixture.repo->workdir, "../testrepo-worktree")); + cl_git_fail(git_worktree_add(&wt, fixture.repo, "worktree-new", path.ptr, NULL)); + + /* Verify files have not been re-created */ + for (i = 0; i < ARRAY_SIZE(wtfiles); i++) { + cl_git_pass(git_buf_joinpath(&path, + fixture.worktree->gitdir, wtfiles[i])); + cl_assert(!git_path_exists(path.ptr)); + } + + git_buf_free(&path); +} + +void test_worktree_worktree__init_submodule(void) +{ + git_repository *repo, *sm, *wt; + git_worktree *worktree; + git_buf path = GIT_BUF_INIT; + + cleanup_fixture_worktree(&fixture); + repo = setup_fixture_submod2(); + + cl_git_pass(git_buf_joinpath(&path, repo->workdir, "sm_unchanged")); + cl_git_pass(git_repository_open(&sm, path.ptr)); + cl_git_pass(git_buf_joinpath(&path, repo->workdir, "../worktree/")); + cl_git_pass(git_worktree_add(&worktree, sm, "repo-worktree", path.ptr, NULL)); + cl_git_pass(git_repository_open_from_worktree(&wt, worktree)); + + cl_git_pass(git_path_prettify_dir(&path, path.ptr, NULL)); + cl_assert_equal_s(path.ptr, wt->workdir); + cl_git_pass(git_path_prettify_dir(&path, sm->commondir, NULL)); + cl_assert_equal_s(sm->commondir, wt->commondir); + + cl_git_pass(git_buf_joinpath(&path, sm->gitdir, "worktrees/repo-worktree/")); + cl_assert_equal_s(path.ptr, wt->gitdir); + + git_buf_free(&path); + git_worktree_free(worktree); + git_repository_free(sm); + git_repository_free(wt); +} + +void test_worktree_worktree__validate(void) +{ + git_worktree *wt; + + cl_git_pass(git_worktree_lookup(&wt, fixture.repo, "testrepo-worktree")); + cl_git_pass(git_worktree_validate(wt)); + + git_worktree_free(wt); +} + +void test_worktree_worktree__validate_invalid_commondir(void) +{ + git_worktree *wt; + + cl_git_pass(git_worktree_lookup(&wt, fixture.repo, "testrepo-worktree")); + git__free(wt->commondir_path); + wt->commondir_path = "/path/to/invalid/commondir"; + + cl_git_fail(git_worktree_validate(wt)); + + wt->commondir_path = NULL; + git_worktree_free(wt); +} + +void test_worktree_worktree__validate_invalid_gitdir(void) +{ + git_worktree *wt; + + cl_git_pass(git_worktree_lookup(&wt, fixture.repo, "testrepo-worktree")); + git__free(wt->gitdir_path); + wt->gitdir_path = "/path/to/invalid/gitdir"; + cl_git_fail(git_worktree_validate(wt)); + + wt->gitdir_path = NULL; + git_worktree_free(wt); +} + +void test_worktree_worktree__validate_invalid_parent(void) +{ + git_worktree *wt; + + cl_git_pass(git_worktree_lookup(&wt, fixture.repo, "testrepo-worktree")); + git__free(wt->parent_path); + wt->parent_path = "/path/to/invalid/parent"; + cl_git_fail(git_worktree_validate(wt)); + + wt->parent_path = NULL; + git_worktree_free(wt); +} + +void test_worktree_worktree__lock_with_reason(void) +{ + git_worktree *wt; + git_buf reason = GIT_BUF_INIT; + + cl_git_pass(git_worktree_lookup(&wt, fixture.repo, "testrepo-worktree")); + + cl_assert(!git_worktree_is_locked(NULL, wt)); + cl_git_pass(git_worktree_lock(wt, "because")); + cl_assert(git_worktree_is_locked(&reason, wt) > 0); + cl_assert_equal_s(reason.ptr, "because"); + cl_assert(wt->locked); + + git_buf_free(&reason); + git_worktree_free(wt); +} + +void test_worktree_worktree__lock_without_reason(void) +{ + git_worktree *wt; + git_buf reason = GIT_BUF_INIT; + + cl_git_pass(git_worktree_lookup(&wt, fixture.repo, "testrepo-worktree")); + + cl_assert(!git_worktree_is_locked(NULL, wt)); + cl_git_pass(git_worktree_lock(wt, NULL)); + cl_assert(git_worktree_is_locked(&reason, wt) > 0); + cl_assert_equal_i(reason.size, 0); + cl_assert(wt->locked); + + git_buf_free(&reason); + git_worktree_free(wt); +} + +void test_worktree_worktree__unlock_unlocked_worktree(void) +{ + git_worktree *wt; + + cl_git_pass(git_worktree_lookup(&wt, fixture.repo, "testrepo-worktree")); + cl_assert(!git_worktree_is_locked(NULL, wt)); + cl_assert(git_worktree_unlock(wt) == 0); + cl_assert(!wt->locked); + + git_worktree_free(wt); +} + +void test_worktree_worktree__unlock_locked_worktree(void) +{ + git_worktree *wt; + + cl_git_pass(git_worktree_lookup(&wt, fixture.repo, "testrepo-worktree")); + cl_git_pass(git_worktree_lock(wt, NULL)); + cl_assert(git_worktree_is_locked(NULL, wt)); + cl_git_pass(git_worktree_unlock(wt)); + cl_assert(!wt->locked); + + git_worktree_free(wt); +} + +void test_worktree_worktree__prune_without_opts_fails(void) +{ + git_worktree *wt; + git_repository *repo; + + cl_git_pass(git_worktree_lookup(&wt, fixture.repo, "testrepo-worktree")); + cl_git_fail(git_worktree_prune(wt, NULL)); + + /* Assert the repository is still valid */ + cl_git_pass(git_repository_open_from_worktree(&repo, wt)); + + git_worktree_free(wt); + git_repository_free(repo); +} + +void test_worktree_worktree__prune_valid(void) +{ + git_worktree_prune_options opts = GIT_WORKTREE_PRUNE_OPTIONS_INIT; + git_worktree *wt; + git_repository *repo; + + opts.flags = GIT_WORKTREE_PRUNE_VALID; + + cl_git_pass(git_worktree_lookup(&wt, fixture.repo, "testrepo-worktree")); + cl_git_pass(git_worktree_prune(wt, &opts)); + + /* Assert the repository is not valid anymore */ + cl_git_fail(git_repository_open_from_worktree(&repo, wt)); + + git_worktree_free(wt); + git_repository_free(repo); +} + +void test_worktree_worktree__prune_locked(void) +{ + git_worktree_prune_options opts = GIT_WORKTREE_PRUNE_OPTIONS_INIT; + git_worktree *wt; + git_repository *repo; + + cl_git_pass(git_worktree_lookup(&wt, fixture.repo, "testrepo-worktree")); + cl_git_pass(git_worktree_lock(wt, NULL)); + + opts.flags = GIT_WORKTREE_PRUNE_VALID; + cl_git_fail(git_worktree_prune(wt, &opts)); + /* Assert the repository is still valid */ + cl_git_pass(git_repository_open_from_worktree(&repo, wt)); + + opts.flags = GIT_WORKTREE_PRUNE_VALID|GIT_WORKTREE_PRUNE_LOCKED; + cl_git_pass(git_worktree_prune(wt, &opts)); + + git_worktree_free(wt); + git_repository_free(repo); +} + +void test_worktree_worktree__prune_gitdir_only(void) +{ + git_worktree_prune_options opts = GIT_WORKTREE_PRUNE_OPTIONS_INIT; + git_worktree *wt; + + opts.flags = GIT_WORKTREE_PRUNE_VALID; + cl_git_pass(git_worktree_lookup(&wt, fixture.repo, "testrepo-worktree")); + cl_git_pass(git_worktree_prune(wt, &opts)); + + cl_assert(!git_path_exists(wt->gitdir_path)); + cl_assert(git_path_exists(wt->gitlink_path)); + + git_worktree_free(wt); +} + +void test_worktree_worktree__prune_worktree(void) +{ + git_worktree_prune_options opts = GIT_WORKTREE_PRUNE_OPTIONS_INIT; + git_worktree *wt; + + opts.flags = GIT_WORKTREE_PRUNE_VALID|GIT_WORKTREE_PRUNE_WORKING_TREE; + + cl_git_pass(git_worktree_lookup(&wt, fixture.repo, "testrepo-worktree")); + cl_git_pass(git_worktree_prune(wt, &opts)); + + cl_assert(!git_path_exists(wt->gitdir_path)); + cl_assert(!git_path_exists(wt->gitlink_path)); + + git_worktree_free(wt); +} + +static int read_head_ref(git_repository *repo, const char *path, void *payload) +{ + git_vector *refs = (git_vector *) payload; + git_reference *head; + + GIT_UNUSED(repo); + + cl_git_pass(git_reference__read_head(&head, repo, path)); + + git_vector_insert(refs, head); + + return 0; +} + +void test_worktree_worktree__foreach_head_gives_same_results_in_wt_and_repo(void) +{ + git_vector repo_refs = GIT_VECTOR_INIT, worktree_refs = GIT_VECTOR_INIT; + git_reference *heads[2]; + size_t i; + + cl_git_pass(git_reference_lookup(&heads[0], fixture.repo, GIT_HEAD_FILE)); + cl_git_pass(git_reference_lookup(&heads[1], fixture.worktree, GIT_HEAD_FILE)); + + cl_git_pass(git_repository_foreach_head(fixture.repo, read_head_ref, &repo_refs)); + cl_git_pass(git_repository_foreach_head(fixture.worktree, read_head_ref, &worktree_refs)); + + cl_assert_equal_i(repo_refs.length, ARRAY_SIZE(heads)); + cl_assert_equal_i(worktree_refs.length, ARRAY_SIZE(heads)); + + for (i = 0; i < ARRAY_SIZE(heads); i++) { + cl_assert_equal_s(heads[i]->name, ((git_reference *) repo_refs.contents[i])->name); + cl_assert_equal_s(heads[i]->name, ((git_reference *) repo_refs.contents[i])->name); + cl_assert_equal_s(heads[i]->name, ((git_reference *) worktree_refs.contents[i])->name); + + git_reference_free(heads[i]); + git_reference_free(repo_refs.contents[i]); + git_reference_free(worktree_refs.contents[i]); + } + + git_vector_free(&repo_refs); + git_vector_free(&worktree_refs); +} diff --git a/tests/worktree/worktree_helpers.c b/tests/worktree/worktree_helpers.c new file mode 100644 index 000000000..6d4cdbaeb --- /dev/null +++ b/tests/worktree/worktree_helpers.c @@ -0,0 +1,30 @@ +#include "clar_libgit2.h" +#include "worktree_helpers.h" + +void cleanup_fixture_worktree(worktree_fixture *fixture) +{ + if (!fixture) + return; + + if (fixture->repo) { + git_repository_free(fixture->repo); + fixture->repo = NULL; + } + if (fixture->worktree) { + git_repository_free(fixture->worktree); + fixture->worktree = NULL; + } + + if (fixture->reponame) + cl_fixture_cleanup(fixture->reponame); + if (fixture->worktreename) + cl_fixture_cleanup(fixture->worktreename); +} + +void setup_fixture_worktree(worktree_fixture *fixture) +{ + if (fixture->reponame) + fixture->repo = cl_git_sandbox_init(fixture->reponame); + if (fixture->worktreename) + fixture->worktree = cl_git_sandbox_init(fixture->worktreename); +} diff --git a/tests/worktree/worktree_helpers.h b/tests/worktree/worktree_helpers.h new file mode 100644 index 000000000..35ea9ed4c --- /dev/null +++ b/tests/worktree/worktree_helpers.h @@ -0,0 +1,11 @@ +typedef struct { + const char *reponame; + const char *worktreename; + git_repository *repo; + git_repository *worktree; +} worktree_fixture; + +#define WORKTREE_FIXTURE_INIT(repo, worktree) { (repo), (worktree), NULL, NULL } + +void cleanup_fixture_worktree(worktree_fixture *fixture); +void setup_fixture_worktree(worktree_fixture *fixture); |