summaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
Diffstat (limited to 'tests')
-rw-r--r--tests/CMakeLists.txt63
-rw-r--r--tests/attr/ignore.c59
-rw-r--r--tests/checkout/head.c78
-rw-r--r--tests/checkout/tree.c35
-rw-r--r--tests/clar_libgit2.c14
-rw-r--r--tests/clar_libgit2.h67
-rw-r--r--tests/clone/local.c2
-rw-r--r--tests/config/include.c103
-rw-r--r--tests/config/readonly.c65
-rw-r--r--tests/core/encoding.c3
-rw-r--r--tests/core/env.c21
-rw-r--r--tests/core/features.c2
-rw-r--r--tests/core/filebuf.c29
-rw-r--r--tests/core/init.c40
-rw-r--r--tests/core/oidmap.c30
-rw-r--r--tests/core/path.c4
-rw-r--r--tests/core/posix.c54
-rw-r--r--tests/core/pqueue.c22
-rw-r--r--tests/core/sha1.c64
-rw-r--r--tests/core/strmap.c4
-rw-r--r--tests/core/structinit.c15
-rw-r--r--tests/core/vector.c31
-rw-r--r--tests/diff/format_email.c4
-rw-r--r--tests/diff/parse.c71
-rw-r--r--tests/diff/patchid.c60
-rw-r--r--tests/diff/stats.c36
-rw-r--r--tests/fetchhead/nonetwork.c4
-rw-r--r--tests/filter/custom.c21
-rw-r--r--tests/filter/custom_helpers.c33
-rw-r--r--tests/filter/custom_helpers.h1
-rw-r--r--tests/generate.py38
-rw-r--r--tests/index/tests.c6
-rw-r--r--tests/index/version.c126
-rw-r--r--tests/iterator/workdir.c4
-rw-r--r--tests/merge/trees/renames.c24
-rw-r--r--tests/network/remote/local.c17
-rw-r--r--tests/object/lookup.c63
-rw-r--r--tests/object/tree/update.c57
-rw-r--r--tests/odb/backend/backend_helpers.c159
-rw-r--r--tests/odb/backend/backend_helpers.h22
-rw-r--r--tests/odb/backend/multiple.c121
-rw-r--r--tests/odb/backend/nobackend.c2
-rw-r--r--tests/odb/backend/nonrefreshing.c177
-rw-r--r--tests/odb/backend/simple.c232
-rw-r--r--tests/odb/foreach.c8
-rw-r--r--tests/odb/freshen.c122
-rw-r--r--tests/odb/loose.c55
-rw-r--r--tests/online/badssl.c38
-rw-r--r--tests/online/clone.c2
-rw-r--r--tests/online/fetchhead.c2
-rw-r--r--tests/online/remotes.c82
-rw-r--r--tests/pack/indexer.c45
-rw-r--r--tests/pack/packbuilder.c45
-rw-r--r--tests/patch/patch_common.h61
-rw-r--r--tests/precompiled.c1
-rw-r--r--tests/precompiled.h4
-rw-r--r--tests/rebase/merge.c54
-rw-r--r--tests/rebase/submodule.c94
-rw-r--r--tests/refs/branches/create.c26
-rw-r--r--tests/refs/branches/upstream.c2
-rw-r--r--tests/refs/crashes.c4
-rw-r--r--tests/refs/create.c127
-rw-r--r--tests/refs/list.c4
-rw-r--r--tests/refs/namespaces.c36
-rw-r--r--tests/refs/reflog/reflog.c46
-rw-r--r--tests/refs/revparse.c35
-rw-r--r--tests/repo/discover.c171
-rw-r--r--tests/repo/env.c12
-rw-r--r--tests/repo/head.c12
-rw-r--r--tests/repo/init.c11
-rw-r--r--tests/repo/open.c3
-rw-r--r--tests/resources/diff_format_email/.gitted/indexbin289 -> 289 bytes
-rw-r--r--tests/resources/diff_format_email/.gitted/objects/06/b7b69a62cbd1e53c6c4e0c3f16473dcfdb4af6bin0 -> 159 bytes
-rw-r--r--tests/resources/diff_format_email/.gitted/objects/52/19b9784f9a92d7bd7cb567a6d6a21bfb86697ebin0 -> 160 bytes
-rw-r--r--tests/resources/diff_format_email/.gitted/objects/53/525d4cc3ef3ba4a5cbf69492fdffb4e4a74558bin0 -> 121 bytes
-rw-r--r--tests/resources/diff_format_email/.gitted/objects/a7/a65f98355b5a7567bcc395f6f7936c9252cf57bin0 -> 28 bytes
-rw-r--r--tests/resources/diff_format_email/.gitted/objects/c7/1a05d36025c806496a74d46d7d596eb23295c4bin0 -> 28 bytes
-rw-r--r--tests/resources/diff_format_email/.gitted/objects/d3/b6b38486f620b5b532a8cc6e0198ab7c3f52e4bin0 -> 121 bytes
-rw-r--r--tests/resources/diff_format_email/.gitted/refs/heads/master2
-rw-r--r--tests/resources/diff_format_email/file3.txt1
-rw-r--r--tests/resources/indexv4/.gitted/HEAD1
-rw-r--r--tests/resources/indexv4/.gitted/config5
-rw-r--r--tests/resources/indexv4/.gitted/indexbin0 -> 572 bytes
-rw-r--r--tests/resources/indexv4/.gitted/objects/4c/9109b3e671d851eec87e0e72f6305b582e7e99bin0 -> 70 bytes
-rw-r--r--tests/resources/indexv4/.gitted/objects/b0/952dbb50bed5f01e03e31b296184cb183e54a7bin0 -> 154 bytes
-rw-r--r--tests/resources/indexv4/.gitted/objects/e6/9de29bb2d1d6434b8b29ae775ad8c2e48c5391bin0 -> 15 bytes
-rw-r--r--tests/resources/indexv4/.gitted/refs/heads/master1
-rw-r--r--tests/resources/indexv4/file.tx0
-rw-r--r--tests/resources/indexv4/file.txt0
-rw-r--r--tests/resources/indexv4/file.txz0
-rw-r--r--tests/resources/indexv4/foo0
-rw-r--r--tests/resources/indexv4/zzz0
-rw-r--r--tests/resources/merge-resolve/.gitted/objects/2a/f2d9bcbc73723ac988bb202d4397f72a6ca7a0bin0 -> 105 bytes
-rw-r--r--tests/resources/merge-resolve/.gitted/objects/37/f53a5a14f64e91089a39ea58e71c87d81df7651
-rw-r--r--tests/resources/merge-resolve/.gitted/objects/4d/d1ef7569b18d92d93c0a35bb6b93049137b355bin0 -> 30 bytes
-rw-r--r--tests/resources/merge-resolve/.gitted/objects/63/ec604d491161ddafdae4179843c26d54bd999abin0 -> 30 bytes
-rw-r--r--tests/resources/merge-resolve/.gitted/objects/68/f7c02064019d89e40e51d7776b6f67914420a2bin0 -> 105 bytes
-rw-r--r--tests/resources/merge-resolve/.gitted/objects/94/29c05dd6f6f39fc567b4ce923b16df5d3d7a7abin0 -> 94 bytes
-rw-r--r--tests/resources/merge-resolve/.gitted/objects/a1/07e18a58f38c46086c8f8f1dcd54c40154eeb63
-rw-r--r--tests/resources/merge-resolve/.gitted/objects/a2/d8d1824c68541cca94ffb90f79291eba495921bin0 -> 30 bytes
-rw-r--r--tests/resources/merge-resolve/.gitted/objects/bc/85d1aad435ff3705a8c30ace85f7542c5736cbbin0 -> 104 bytes
-rw-r--r--tests/resources/merge-resolve/.gitted/objects/c8/26ef8b17b5cd2c4a0023f265f3a423b3aa0388bin0 -> 157 bytes
-rw-r--r--tests/resources/merge-resolve/.gitted/objects/cd/3e8d4aa06bdc781f264171030bc28f2b370feebin0 -> 94 bytes
-rw-r--r--tests/resources/merge-resolve/.gitted/objects/e2/6b8888956137218d8589368a3e606cf50fbb56bin0 -> 105 bytes
-rw-r--r--tests/resources/merge-resolve/.gitted/objects/e6/9de29bb2d1d6434b8b29ae775ad8c2e48c5391bin0 -> 15 bytes
-rw-r--r--tests/resources/merge-resolve/.gitted/objects/f9/7da95f156121bea8f978623628f4cbdbf30b361
-rw-r--r--tests/resources/merge-resolve/.gitted/refs/heads/submodule_rename11
-rw-r--r--tests/resources/merge-resolve/.gitted/refs/heads/submodule_rename21
-rw-r--r--tests/resources/rebase-submodule/.gitted/HEAD1
-rw-r--r--tests/resources/rebase-submodule/.gitted/ORIG_HEAD1
-rw-r--r--tests/resources/rebase-submodule/.gitted/config9
-rw-r--r--tests/resources/rebase-submodule/.gitted/description1
-rw-r--r--tests/resources/rebase-submodule/.gitted/indexbin0 -> 681 bytes
-rw-r--r--tests/resources/rebase-submodule/.gitted/info/exclude6
-rw-r--r--tests/resources/rebase-submodule/.gitted/info/refs4
-rw-r--r--tests/resources/rebase-submodule/.gitted/objects/01/971e2453a407e4b9f6c865e2c37f4db21da2941
-rw-r--r--tests/resources/rebase-submodule/.gitted/objects/17/f8ae8ebdd08a4bb272f61b897b308ad42b1b121
-rw-r--r--tests/resources/rebase-submodule/.gitted/objects/42/cdad903aef3e7b614675e6584a8be417941911bin0 -> 208 bytes
-rw-r--r--tests/resources/rebase-submodule/.gitted/objects/4b/7c5650008b2e747fe1809eeb5a1dde0e80850abin0 -> 615 bytes
-rw-r--r--tests/resources/rebase-submodule/.gitted/objects/5b/1e8bccf7787e942aecf61912f94a2c274f85a5bin0 -> 368 bytes
-rw-r--r--tests/resources/rebase-submodule/.gitted/objects/68/af1fc7407fd9addf1701a87eb1c95c7494c598bin0 -> 443 bytes
-rw-r--r--tests/resources/rebase-submodule/.gitted/objects/68/f6182f4c85d39e1309d97c7e456156dc9c0096bin0 -> 755 bytes
-rw-r--r--tests/resources/rebase-submodule/.gitted/objects/7c/71f7606bd3bfb25d063c970804e7fc00b9605bbin0 -> 279 bytes
-rw-r--r--tests/resources/rebase-submodule/.gitted/objects/7c/7bf85e978f1d18c0566f702d2cb7766b9c8d4f1
-rw-r--r--tests/resources/rebase-submodule/.gitted/objects/a7/b066537e6be7109abfe4ff97b675d4e077da20bin0 -> 621 bytes
-rw-r--r--tests/resources/rebase-submodule/.gitted/objects/ab/6cf22b4c67a274aa8d31b5877d92341e8c2a9cbin0 -> 279 bytes
-rw-r--r--tests/resources/rebase-submodule/.gitted/objects/c4/e6cca3ec6ae0148ed231f97257df8c311e015f1
-rw-r--r--tests/resources/rebase-submodule/.gitted/objects/f3/6de77de6f53dddafeb024ecaf375e45c3d9dddbin0 -> 58 bytes
-rw-r--r--tests/resources/rebase-submodule/.gitted/objects/ff/b36e513f5fdf8a6ba850a20142676a2ac4807dbin0 -> 355 bytes
-rw-r--r--tests/resources/rebase-submodule/.gitted/packed-refs2
-rw-r--r--tests/resources/rebase-submodule/.gitted/refs/heads/asparagus1
-rw-r--r--tests/resources/rebase-submodule/.gitted/refs/heads/master1
-rw-r--r--tests/resources/rebase-submodule/asparagus.txt10
-rw-r--r--tests/resources/rebase-submodule/beef.txt22
-rw-r--r--tests/resources/rebase-submodule/bouilli.txt18
-rw-r--r--tests/resources/rebase-submodule/gitmodules3
-rw-r--r--tests/resources/rebase-submodule/gravy.txt8
-rw-r--r--tests/resources/rebase-submodule/oyster.txt13
-rw-r--r--tests/resources/rebase-submodule/veal.txt18
-rw-r--r--tests/resources/sha1/hello_c6
-rw-r--r--tests/resources/sha1/shattered-1.pdfbin0 -> 422435 bytes
-rw-r--r--tests/resources/submodules-worktree-child/.gitted1
-rw-r--r--tests/resources/submodules-worktree-child/README1
-rw-r--r--tests/resources/submodules-worktree-child/branch_file.txt2
-rw-r--r--tests/resources/submodules-worktree-child/new.txt1
-rw-r--r--tests/resources/submodules-worktree-parent/.gitmodules3
-rw-r--r--tests/resources/submodules-worktree-parent/.gitted1
-rw-r--r--tests/resources/submodules-worktree-parent/deleted1
-rw-r--r--tests/resources/submodules-worktree-parent/modified1
-rw-r--r--tests/resources/submodules-worktree-parent/unmodified1
-rw-r--r--tests/resources/submodules.git/HEAD1
-rw-r--r--tests/resources/submodules.git/config4
-rw-r--r--tests/resources/submodules.git/objects/26/a3b32a9b7d97486c5557f5902e8ac94638145e2
-rw-r--r--tests/resources/submodules.git/objects/78/308c9251cf4eee8b25a76c7d2790c73d797357bin0 -> 97 bytes
-rw-r--r--tests/resources/submodules.git/objects/97/896810b3210244a62a82458b8e0819ecfc68503
-rw-r--r--tests/resources/submodules.git/objects/b6/0fd986699ba4e9e68bea07cf8e793f323ef888bin0 -> 138 bytes
-rw-r--r--tests/resources/submodules.git/objects/d5/f7fc3f74f7dec08280f370a975b112e8f60818bin0 -> 21 bytes
-rw-r--r--tests/resources/submodules.git/objects/e3/50052cc767cd1fcb37e84e9a89e701925be4aebin0 -> 120 bytes
-rw-r--r--tests/resources/submodules.git/objects/info/packs2
-rw-r--r--tests/resources/submodules.git/objects/pack/pack-b69d04bb39ac274669e2184e45bd90015d02ef5b.idxbin0 -> 1156 bytes
-rw-r--r--tests/resources/submodules.git/objects/pack/pack-b69d04bb39ac274669e2184e45bd90015d02ef5b.packbin0 -> 228 bytes
-rw-r--r--tests/resources/submodules.git/refs/heads/master1
-rw-r--r--tests/resources/submodules/.gitted/logs/refs/heads/submodules-worktree-parent1
-rw-r--r--tests/resources/submodules/.gitted/refs/heads/submodules-worktree-parent1
-rw-r--r--tests/resources/submodules/.gitted/worktrees/submodules-worktree-parent/HEAD1
-rw-r--r--tests/resources/submodules/.gitted/worktrees/submodules-worktree-parent/ORIG_HEAD1
-rw-r--r--tests/resources/submodules/.gitted/worktrees/submodules-worktree-parent/commondir1
-rw-r--r--tests/resources/submodules/.gitted/worktrees/submodules-worktree-parent/gitdir1
-rw-r--r--tests/resources/submodules/.gitted/worktrees/submodules-worktree-parent/indexbin0 -> 441 bytes
-rw-r--r--tests/resources/submodules/testrepo/.gitted/config3
-rw-r--r--tests/resources/submodules/testrepo/.gitted/logs/refs/heads/submodules-worktree-child1
-rw-r--r--tests/resources/submodules/testrepo/.gitted/refs/heads/submodules-worktree-child1
-rw-r--r--tests/resources/submodules/testrepo/.gitted/worktrees/submodules-worktree-child/HEAD1
-rw-r--r--tests/resources/submodules/testrepo/.gitted/worktrees/submodules-worktree-child/ORIG_HEAD1
-rw-r--r--tests/resources/submodules/testrepo/.gitted/worktrees/submodules-worktree-child/commondir1
-rw-r--r--tests/resources/submodules/testrepo/.gitted/worktrees/submodules-worktree-child/gitdir1
-rw-r--r--tests/resources/submodules/testrepo/.gitted/worktrees/submodules-worktree-child/indexbin0 -> 289 bytes
-rw-r--r--tests/resources/testrepo-worktree/.gitted1
-rw-r--r--tests/resources/testrepo-worktree/README1
-rw-r--r--tests/resources/testrepo-worktree/branch_file.txt2
l---------tests/resources/testrepo-worktree/link_to_new.txt1
-rw-r--r--tests/resources/testrepo-worktree/new.txt1
-rw-r--r--tests/resources/testrepo.git/objects/43/da5ec3274dd061df152ff5e69853d562b018422
-rw-r--r--tests/resources/testrepo.git/objects/43/e968a905a821532069bb413801d35b200631cf4
-rw-r--r--tests/resources/testrepo.git/objects/5d/0f8f7891e872d284beef38254882dc879b2602bin0 -> 149 bytes
-rw-r--r--tests/resources/testrepo.git/objects/5f/34cd6e3285089647165983482cf90873d50940bin0 -> 37 bytes
-rw-r--r--tests/resources/testrepo.git/objects/8e/73b769e97678d684b809b163bebdae2911720f2
-rw-r--r--tests/resources/testrepo.git/objects/b2/04707bbc546a1a770ef6ced37c7089cc3bfe6b2
-rw-r--r--tests/resources/testrepo.git/objects/b2/35959d89084af8d3544fbdf675e47944f86524bin0 -> 77 bytes
-rw-r--r--tests/resources/testrepo.git/objects/b9/1e763008b10db366442469339f90a2b8400d0abin0 -> 206 bytes
-rw-r--r--tests/resources/testrepo.git/objects/bd/758010071961f28336333bc41e9c64c9a64866bin0 -> 162 bytes
-rw-r--r--tests/resources/testrepo.git/objects/db/4df74a2fc340a0d0cb0cafc0db471fdfff10482
-rw-r--r--tests/resources/testrepo.git/objects/db/793a00a5615eca1aac97e42b3a68b1acfa8bfdbin0 -> 193 bytes
-rw-r--r--tests/resources/testrepo.git/objects/db/c0be625bed24b5d8f5d9a927484f2065d321afbin0 -> 175 bytes
-rw-r--r--tests/resources/testrepo.git/objects/f0/a2a10243ca64f935dbe3dccb89ec8bf16bdacebin0 -> 38 bytes
-rw-r--r--tests/resources/testrepo/.gitted/logs/refs/heads/testrepo-worktree1
-rw-r--r--tests/resources/testrepo/.gitted/objects/9b/1719f5cf069568785080a0bbabbe7c377e22aebin0 -> 24 bytes
-rw-r--r--tests/resources/testrepo/.gitted/objects/a3/8d028f71eaa590febb7d716b1ca32350cf70dabin0 -> 155 bytes
-rw-r--r--tests/resources/testrepo/.gitted/objects/ad/edac69457183c8265c8a9614c1c4fed31d1ff3bin0 -> 119 bytes
-rw-r--r--tests/resources/testrepo/.gitted/refs/heads/merge-conflict1
-rw-r--r--tests/resources/testrepo/.gitted/refs/heads/testrepo-worktree1
-rw-r--r--tests/resources/testrepo/.gitted/worktrees/testrepo-worktree/HEAD1
-rw-r--r--tests/resources/testrepo/.gitted/worktrees/testrepo-worktree/commondir1
-rw-r--r--tests/resources/testrepo/.gitted/worktrees/testrepo-worktree/gitdir1
-rw-r--r--tests/resources/testrepo/.gitted/worktrees/testrepo-worktree/indexbin0 -> 369 bytes
-rw-r--r--tests/resources/testrepo/.gitted/worktrees/testrepo-worktree/logs/HEAD1
-rw-r--r--tests/revwalk/basic.c92
-rw-r--r--tests/revwalk/hidecb.c2
-rw-r--r--tests/revwalk/simplify.c1
-rw-r--r--tests/status/ignore.c109
-rw-r--r--tests/submodule/lookup.c57
-rw-r--r--tests/submodule/open.c90
-rw-r--r--tests/submodule/submodule_helpers.c2
-rw-r--r--tests/threads/basic.c27
-rw-r--r--tests/threads/diff.c15
-rw-r--r--tests/threads/refdb.c175
-rw-r--r--tests/worktree/config.c45
-rw-r--r--tests/worktree/merge.c121
-rw-r--r--tests/worktree/open.c143
-rw-r--r--tests/worktree/reflog.c65
-rw-r--r--tests/worktree/refs.c173
-rw-r--r--tests/worktree/repository.c63
-rw-r--r--tests/worktree/submodule.c92
-rw-r--r--tests/worktree/worktree.c583
-rw-r--r--tests/worktree/worktree_helpers.c30
-rw-r--r--tests/worktree/worktree_helpers.h11
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(&current_oid, obj->oid);
+
+ if (git_oid_ncmp(&current_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
index d94f87de8..092a888e7 100644
--- a/tests/resources/diff_format_email/.gitted/index
+++ b/tests/resources/diff_format_email/.gitted/index
Binary files differ
diff --git a/tests/resources/diff_format_email/.gitted/objects/06/b7b69a62cbd1e53c6c4e0c3f16473dcfdb4af6 b/tests/resources/diff_format_email/.gitted/objects/06/b7b69a62cbd1e53c6c4e0c3f16473dcfdb4af6
new file mode 100644
index 000000000..37588f169
--- /dev/null
+++ b/tests/resources/diff_format_email/.gitted/objects/06/b7b69a62cbd1e53c6c4e0c3f16473dcfdb4af6
Binary files differ
diff --git a/tests/resources/diff_format_email/.gitted/objects/52/19b9784f9a92d7bd7cb567a6d6a21bfb86697e b/tests/resources/diff_format_email/.gitted/objects/52/19b9784f9a92d7bd7cb567a6d6a21bfb86697e
new file mode 100644
index 000000000..534e3b07d
--- /dev/null
+++ b/tests/resources/diff_format_email/.gitted/objects/52/19b9784f9a92d7bd7cb567a6d6a21bfb86697e
Binary files differ
diff --git a/tests/resources/diff_format_email/.gitted/objects/53/525d4cc3ef3ba4a5cbf69492fdffb4e4a74558 b/tests/resources/diff_format_email/.gitted/objects/53/525d4cc3ef3ba4a5cbf69492fdffb4e4a74558
new file mode 100644
index 000000000..b74d31f4f
--- /dev/null
+++ b/tests/resources/diff_format_email/.gitted/objects/53/525d4cc3ef3ba4a5cbf69492fdffb4e4a74558
Binary files differ
diff --git a/tests/resources/diff_format_email/.gitted/objects/a7/a65f98355b5a7567bcc395f6f7936c9252cf57 b/tests/resources/diff_format_email/.gitted/objects/a7/a65f98355b5a7567bcc395f6f7936c9252cf57
new file mode 100644
index 000000000..36a4b7be6
--- /dev/null
+++ b/tests/resources/diff_format_email/.gitted/objects/a7/a65f98355b5a7567bcc395f6f7936c9252cf57
Binary files differ
diff --git a/tests/resources/diff_format_email/.gitted/objects/c7/1a05d36025c806496a74d46d7d596eb23295c4 b/tests/resources/diff_format_email/.gitted/objects/c7/1a05d36025c806496a74d46d7d596eb23295c4
new file mode 100644
index 000000000..2822fe3e4
--- /dev/null
+++ b/tests/resources/diff_format_email/.gitted/objects/c7/1a05d36025c806496a74d46d7d596eb23295c4
Binary files differ
diff --git a/tests/resources/diff_format_email/.gitted/objects/d3/b6b38486f620b5b532a8cc6e0198ab7c3f52e4 b/tests/resources/diff_format_email/.gitted/objects/d3/b6b38486f620b5b532a8cc6e0198ab7c3f52e4
new file mode 100644
index 000000000..5b2e664f4
--- /dev/null
+++ b/tests/resources/diff_format_email/.gitted/objects/d3/b6b38486f620b5b532a8cc6e0198ab7c3f52e4
Binary files differ
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
new file mode 100644
index 000000000..e8fc61736
--- /dev/null
+++ b/tests/resources/indexv4/.gitted/index
Binary files differ
diff --git a/tests/resources/indexv4/.gitted/objects/4c/9109b3e671d851eec87e0e72f6305b582e7e99 b/tests/resources/indexv4/.gitted/objects/4c/9109b3e671d851eec87e0e72f6305b582e7e99
new file mode 100644
index 000000000..cedd594b0
--- /dev/null
+++ b/tests/resources/indexv4/.gitted/objects/4c/9109b3e671d851eec87e0e72f6305b582e7e99
Binary files differ
diff --git a/tests/resources/indexv4/.gitted/objects/b0/952dbb50bed5f01e03e31b296184cb183e54a7 b/tests/resources/indexv4/.gitted/objects/b0/952dbb50bed5f01e03e31b296184cb183e54a7
new file mode 100644
index 000000000..0ddc1d1a9
--- /dev/null
+++ b/tests/resources/indexv4/.gitted/objects/b0/952dbb50bed5f01e03e31b296184cb183e54a7
Binary files differ
diff --git a/tests/resources/indexv4/.gitted/objects/e6/9de29bb2d1d6434b8b29ae775ad8c2e48c5391 b/tests/resources/indexv4/.gitted/objects/e6/9de29bb2d1d6434b8b29ae775ad8c2e48c5391
new file mode 100644
index 000000000..711223894
--- /dev/null
+++ b/tests/resources/indexv4/.gitted/objects/e6/9de29bb2d1d6434b8b29ae775ad8c2e48c5391
Binary files differ
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
new file mode 100644
index 000000000..0d658237b
--- /dev/null
+++ b/tests/resources/merge-resolve/.gitted/objects/2a/f2d9bcbc73723ac988bb202d4397f72a6ca7a0
Binary files differ
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•ŽAjC1 D»ö)´Ù‘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
new file mode 100644
index 000000000..86a21ad50
--- /dev/null
+++ b/tests/resources/merge-resolve/.gitted/objects/4d/d1ef7569b18d92d93c0a35bb6b93049137b355
Binary files differ
diff --git a/tests/resources/merge-resolve/.gitted/objects/63/ec604d491161ddafdae4179843c26d54bd999a b/tests/resources/merge-resolve/.gitted/objects/63/ec604d491161ddafdae4179843c26d54bd999a
new file mode 100644
index 000000000..bc74da5ba
--- /dev/null
+++ b/tests/resources/merge-resolve/.gitted/objects/63/ec604d491161ddafdae4179843c26d54bd999a
Binary files differ
diff --git a/tests/resources/merge-resolve/.gitted/objects/68/f7c02064019d89e40e51d7776b6f67914420a2 b/tests/resources/merge-resolve/.gitted/objects/68/f7c02064019d89e40e51d7776b6f67914420a2
new file mode 100644
index 000000000..809a5b38b
--- /dev/null
+++ b/tests/resources/merge-resolve/.gitted/objects/68/f7c02064019d89e40e51d7776b6f67914420a2
Binary files differ
diff --git a/tests/resources/merge-resolve/.gitted/objects/94/29c05dd6f6f39fc567b4ce923b16df5d3d7a7a b/tests/resources/merge-resolve/.gitted/objects/94/29c05dd6f6f39fc567b4ce923b16df5d3d7a7a
new file mode 100644
index 000000000..d4d93f508
--- /dev/null
+++ b/tests/resources/merge-resolve/.gitted/objects/94/29c05dd6f6f39fc567b4ce923b16df5d3d7a7a
Binary files differ
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ñƒ-Âc­y«æ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
new file mode 100644
index 000000000..2d3d94718
--- /dev/null
+++ b/tests/resources/merge-resolve/.gitted/objects/a2/d8d1824c68541cca94ffb90f79291eba495921
Binary files differ
diff --git a/tests/resources/merge-resolve/.gitted/objects/bc/85d1aad435ff3705a8c30ace85f7542c5736cb b/tests/resources/merge-resolve/.gitted/objects/bc/85d1aad435ff3705a8c30ace85f7542c5736cb
new file mode 100644
index 000000000..ae529fe87
--- /dev/null
+++ b/tests/resources/merge-resolve/.gitted/objects/bc/85d1aad435ff3705a8c30ace85f7542c5736cb
Binary files differ
diff --git a/tests/resources/merge-resolve/.gitted/objects/c8/26ef8b17b5cd2c4a0023f265f3a423b3aa0388 b/tests/resources/merge-resolve/.gitted/objects/c8/26ef8b17b5cd2c4a0023f265f3a423b3aa0388
new file mode 100644
index 000000000..b655d7c40
--- /dev/null
+++ b/tests/resources/merge-resolve/.gitted/objects/c8/26ef8b17b5cd2c4a0023f265f3a423b3aa0388
Binary files differ
diff --git a/tests/resources/merge-resolve/.gitted/objects/cd/3e8d4aa06bdc781f264171030bc28f2b370fee b/tests/resources/merge-resolve/.gitted/objects/cd/3e8d4aa06bdc781f264171030bc28f2b370fee
new file mode 100644
index 000000000..144225df1
--- /dev/null
+++ b/tests/resources/merge-resolve/.gitted/objects/cd/3e8d4aa06bdc781f264171030bc28f2b370fee
Binary files differ
diff --git a/tests/resources/merge-resolve/.gitted/objects/e2/6b8888956137218d8589368a3e606cf50fbb56 b/tests/resources/merge-resolve/.gitted/objects/e2/6b8888956137218d8589368a3e606cf50fbb56
new file mode 100644
index 000000000..d4ec2b972
--- /dev/null
+++ b/tests/resources/merge-resolve/.gitted/objects/e2/6b8888956137218d8589368a3e606cf50fbb56
Binary files differ
diff --git a/tests/resources/merge-resolve/.gitted/objects/e6/9de29bb2d1d6434b8b29ae775ad8c2e48c5391 b/tests/resources/merge-resolve/.gitted/objects/e6/9de29bb2d1d6434b8b29ae775ad8c2e48c5391
new file mode 100644
index 000000000..711223894
--- /dev/null
+++ b/tests/resources/merge-resolve/.gitted/objects/e6/9de29bb2d1d6434b8b29ae775ad8c2e48c5391
Binary files differ
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!E­9½‰…)Œ±±´óÃ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
new file mode 100644
index 000000000..b63efabdb
--- /dev/null
+++ b/tests/resources/rebase-submodule/.gitted/index
Binary files differ
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Ã0 D»Ö)xMý€ È¢Yv× P'j«åôú•‹¬ÈâqÈX—¥t@=½õ–3p0qF e´ÄìÒ¤‚vÖ&©ì"²â‡[^;Hå­ÊHzb’6Sð³‰ÎèŒq²3¥€*1z¼÷GmpK¿Ü|=ê²Õ.y¸GwÍÿƒ—:Ǻ¼ƒ"© *CN’¤ÃÇöÜàƒŸelÙÛ:Äe­Oþ.Ûõ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
new file mode 100644
index 000000000..99b5e6d2c
--- /dev/null
+++ b/tests/resources/rebase-submodule/.gitted/objects/42/cdad903aef3e7b614675e6584a8be417941911
Binary files differ
diff --git a/tests/resources/rebase-submodule/.gitted/objects/4b/7c5650008b2e747fe1809eeb5a1dde0e80850a b/tests/resources/rebase-submodule/.gitted/objects/4b/7c5650008b2e747fe1809eeb5a1dde0e80850a
new file mode 100644
index 000000000..016398531
--- /dev/null
+++ b/tests/resources/rebase-submodule/.gitted/objects/4b/7c5650008b2e747fe1809eeb5a1dde0e80850a
Binary files differ
diff --git a/tests/resources/rebase-submodule/.gitted/objects/5b/1e8bccf7787e942aecf61912f94a2c274f85a5 b/tests/resources/rebase-submodule/.gitted/objects/5b/1e8bccf7787e942aecf61912f94a2c274f85a5
new file mode 100644
index 000000000..d4776d883
--- /dev/null
+++ b/tests/resources/rebase-submodule/.gitted/objects/5b/1e8bccf7787e942aecf61912f94a2c274f85a5
Binary files differ
diff --git a/tests/resources/rebase-submodule/.gitted/objects/68/af1fc7407fd9addf1701a87eb1c95c7494c598 b/tests/resources/rebase-submodule/.gitted/objects/68/af1fc7407fd9addf1701a87eb1c95c7494c598
new file mode 100644
index 000000000..6aaf79fcb
--- /dev/null
+++ b/tests/resources/rebase-submodule/.gitted/objects/68/af1fc7407fd9addf1701a87eb1c95c7494c598
Binary files differ
diff --git a/tests/resources/rebase-submodule/.gitted/objects/68/f6182f4c85d39e1309d97c7e456156dc9c0096 b/tests/resources/rebase-submodule/.gitted/objects/68/f6182f4c85d39e1309d97c7e456156dc9c0096
new file mode 100644
index 000000000..ed1de3ada
--- /dev/null
+++ b/tests/resources/rebase-submodule/.gitted/objects/68/f6182f4c85d39e1309d97c7e456156dc9c0096
Binary files differ
diff --git a/tests/resources/rebase-submodule/.gitted/objects/7c/71f7606bd3bfb25d063c970804e7fc00b9605b b/tests/resources/rebase-submodule/.gitted/objects/7c/71f7606bd3bfb25d063c970804e7fc00b9605b
new file mode 100644
index 000000000..ef923e714
--- /dev/null
+++ b/tests/resources/rebase-submodule/.gitted/objects/7c/71f7606bd3bfb25d063c970804e7fc00b9605b
Binary files differ
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
new file mode 100644
index 000000000..54f9b6617
--- /dev/null
+++ b/tests/resources/rebase-submodule/.gitted/objects/a7/b066537e6be7109abfe4ff97b675d4e077da20
Binary files differ
diff --git a/tests/resources/rebase-submodule/.gitted/objects/ab/6cf22b4c67a274aa8d31b5877d92341e8c2a9c b/tests/resources/rebase-submodule/.gitted/objects/ab/6cf22b4c67a274aa8d31b5877d92341e8c2a9c
new file mode 100644
index 000000000..5acdf362e
--- /dev/null
+++ b/tests/resources/rebase-submodule/.gitted/objects/ab/6cf22b4c67a274aa8d31b5877d92341e8c2a9c
Binary files differ
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
new file mode 100644
index 000000000..cd330a71f
--- /dev/null
+++ b/tests/resources/rebase-submodule/.gitted/objects/f3/6de77de6f53dddafeb024ecaf375e45c3d9ddd
Binary files differ
diff --git a/tests/resources/rebase-submodule/.gitted/objects/ff/b36e513f5fdf8a6ba850a20142676a2ac4807d b/tests/resources/rebase-submodule/.gitted/objects/ff/b36e513f5fdf8a6ba850a20142676a2ac4807d
new file mode 100644
index 000000000..f655d12ea
--- /dev/null
+++ b/tests/resources/rebase-submodule/.gitted/objects/ff/b36e513f5fdf8a6ba850a20142676a2ac4807d
Binary files differ
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
new file mode 100644
index 000000000..ba9aaa145
--- /dev/null
+++ b/tests/resources/sha1/shattered-1.pdf
Binary files differ
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%‰=
+€0 F]í)Š0à"ÃIŒ*•|Éý-t{?œ2ÇilV8¿ùô$±«Øm¡ýv»ãk­k*F DAÊ=(=|=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
new file mode 100644
index 000000000..c85fb5512
--- /dev/null
+++ b/tests/resources/submodules.git/objects/78/308c9251cf4eee8b25a76c7d2790c73d797357
Binary files differ
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
new file mode 100644
index 000000000..3d78bd6be
--- /dev/null
+++ b/tests/resources/submodules.git/objects/b6/0fd986699ba4e9e68bea07cf8e793f323ef888
Binary files differ
diff --git a/tests/resources/submodules.git/objects/d5/f7fc3f74f7dec08280f370a975b112e8f60818 b/tests/resources/submodules.git/objects/d5/f7fc3f74f7dec08280f370a975b112e8f60818
new file mode 100644
index 000000000..6e0b49e86
--- /dev/null
+++ b/tests/resources/submodules.git/objects/d5/f7fc3f74f7dec08280f370a975b112e8f60818
Binary files differ
diff --git a/tests/resources/submodules.git/objects/e3/50052cc767cd1fcb37e84e9a89e701925be4ae b/tests/resources/submodules.git/objects/e3/50052cc767cd1fcb37e84e9a89e701925be4ae
new file mode 100644
index 000000000..082a58941
--- /dev/null
+++ b/tests/resources/submodules.git/objects/e3/50052cc767cd1fcb37e84e9a89e701925be4ae
Binary files differ
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
new file mode 100644
index 000000000..810fc3181
--- /dev/null
+++ b/tests/resources/submodules.git/objects/pack/pack-b69d04bb39ac274669e2184e45bd90015d02ef5b.idx
Binary files differ
diff --git a/tests/resources/submodules.git/objects/pack/pack-b69d04bb39ac274669e2184e45bd90015d02ef5b.pack b/tests/resources/submodules.git/objects/pack/pack-b69d04bb39ac274669e2184e45bd90015d02ef5b.pack
new file mode 100644
index 000000000..c25c4a73f
--- /dev/null
+++ b/tests/resources/submodules.git/objects/pack/pack-b69d04bb39ac274669e2184e45bd90015d02ef5b.pack
Binary files differ
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
new file mode 100644
index 000000000..5b68f18a4
--- /dev/null
+++ b/tests/resources/submodules/.gitted/worktrees/submodules-worktree-parent/index
Binary files differ
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
new file mode 100644
index 000000000..52a42f966
--- /dev/null
+++ b/tests/resources/submodules/testrepo/.gitted/worktrees/submodules-worktree-child/index
Binary files differ
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
new file mode 100644
index 000000000..7a22451ed
--- /dev/null
+++ b/tests/resources/testrepo.git/objects/5d/0f8f7891e872d284beef38254882dc879b2602
Binary files differ
diff --git a/tests/resources/testrepo.git/objects/5f/34cd6e3285089647165983482cf90873d50940 b/tests/resources/testrepo.git/objects/5f/34cd6e3285089647165983482cf90873d50940
new file mode 100644
index 000000000..b1df3bdd5
--- /dev/null
+++ b/tests/resources/testrepo.git/objects/5f/34cd6e3285089647165983482cf90873d50940
Binary files differ
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.þQ J),{‚öŽ-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
new file mode 100644
index 000000000..7d563dbd3
--- /dev/null
+++ b/tests/resources/testrepo.git/objects/b2/35959d89084af8d3544fbdf675e47944f86524
Binary files differ
diff --git a/tests/resources/testrepo.git/objects/b9/1e763008b10db366442469339f90a2b8400d0a b/tests/resources/testrepo.git/objects/b9/1e763008b10db366442469339f90a2b8400d0a
new file mode 100644
index 000000000..7bab59be8
--- /dev/null
+++ b/tests/resources/testrepo.git/objects/b9/1e763008b10db366442469339f90a2b8400d0a
Binary files differ
diff --git a/tests/resources/testrepo.git/objects/bd/758010071961f28336333bc41e9c64c9a64866 b/tests/resources/testrepo.git/objects/bd/758010071961f28336333bc41e9c64c9a64866
new file mode 100644
index 000000000..c5e3b87ad
--- /dev/null
+++ b/tests/resources/testrepo.git/objects/bd/758010071961f28336333bc41e9c64c9a64866
Binary files differ
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
new file mode 100644
index 000000000..ae82880de
--- /dev/null
+++ b/tests/resources/testrepo.git/objects/db/793a00a5615eca1aac97e42b3a68b1acfa8bfd
Binary files differ
diff --git a/tests/resources/testrepo.git/objects/db/c0be625bed24b5d8f5d9a927484f2065d321af b/tests/resources/testrepo.git/objects/db/c0be625bed24b5d8f5d9a927484f2065d321af
new file mode 100644
index 000000000..b966b0b2f
--- /dev/null
+++ b/tests/resources/testrepo.git/objects/db/c0be625bed24b5d8f5d9a927484f2065d321af
Binary files differ
diff --git a/tests/resources/testrepo.git/objects/f0/a2a10243ca64f935dbe3dccb89ec8bf16bdace b/tests/resources/testrepo.git/objects/f0/a2a10243ca64f935dbe3dccb89ec8bf16bdace
new file mode 100644
index 000000000..1b299dc25
--- /dev/null
+++ b/tests/resources/testrepo.git/objects/f0/a2a10243ca64f935dbe3dccb89ec8bf16bdace
Binary files differ
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
new file mode 100644
index 000000000..13e3f581a
--- /dev/null
+++ b/tests/resources/testrepo/.gitted/objects/9b/1719f5cf069568785080a0bbabbe7c377e22ae
Binary files differ
diff --git a/tests/resources/testrepo/.gitted/objects/a3/8d028f71eaa590febb7d716b1ca32350cf70da b/tests/resources/testrepo/.gitted/objects/a3/8d028f71eaa590febb7d716b1ca32350cf70da
new file mode 100644
index 000000000..4df22ec17
--- /dev/null
+++ b/tests/resources/testrepo/.gitted/objects/a3/8d028f71eaa590febb7d716b1ca32350cf70da
Binary files differ
diff --git a/tests/resources/testrepo/.gitted/objects/ad/edac69457183c8265c8a9614c1c4fed31d1ff3 b/tests/resources/testrepo/.gitted/objects/ad/edac69457183c8265c8a9614c1c4fed31d1ff3
new file mode 100644
index 000000000..c054fc0c4
--- /dev/null
+++ b/tests/resources/testrepo/.gitted/objects/ad/edac69457183c8265c8a9614c1c4fed31d1ff3
Binary files differ
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
new file mode 100644
index 000000000..41141906e
--- /dev/null
+++ b/tests/resources/testrepo/.gitted/worktrees/testrepo-worktree/index
Binary files differ
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);