1 #include "clar_libgit2.h"
2 #include "git2/checkout.h"
7 static git_repository
*g_repo
= NULL
;
10 From the test repo used for this test:
11 --------------------------------------
13 This is a test repo for libgit2 where tree entries have type changes
15 The key types that could be found in tree entries are:
17 1 - GIT_FILEMODE_NEW = 0000000
18 2 - GIT_FILEMODE_TREE = 0040000
19 3 - GIT_FILEMODE_BLOB = 0100644
20 4 - GIT_FILEMODE_BLOB_EXECUTABLE = 0100755
21 5 - GIT_FILEMODE_LINK = 0120000
22 6 - GIT_FILEMODE_COMMIT = 0160000
24 I will try to have every type of transition somewhere in the history
29 Initial commit - a(1) b(1) c(1) d(1) e(1)
30 Create content - a(1->2) b(1->3) c(1->4) d(1->5) e(1->6)
31 Changes #1 - a(2->3) b(3->4) c(4->5) d(5->6) e(6->2)
32 Changes #2 - a(3->5) b(4->6) c(5->2) d(6->3) e(2->4)
33 Changes #3 - a(5->3) b(6->4) c(2->5) d(3->6) e(4->2)
34 Changes #4 - a(3->2) b(4->3) c(5->4) d(6->5) e(2->6)
35 Changes #5 - a(2->1) b(3->1) c(4->1) d(5->1) e(6->1)
39 static const char *g_typechange_oids
[] = {
40 "79b9f23e85f55ea36a472a902e875bc1121a94cb",
41 "9bdb75b73836a99e3dbeea640a81de81031fdc29",
42 "0e7ed140b514b8cae23254cb8656fe1674403aff",
43 "9d0235c7a7edc0889a18f97a42ee6db9fe688447",
44 "9b19edf33a03a0c59cdfc113bfa5c06179bf9b1a",
45 "1b63caae4a5ca96f78e8dfefc376c6a39a142475",
46 "6eae26c90e8ccc4d16208972119c40635489c6f0",
50 static bool g_typechange_empty
[] = {
51 true, false, false, false, false, false, true, true
54 static const int g_typechange_expected_conflicts
[] = {
58 static const int g_typechange_expected_untracked
[] = {
62 void test_checkout_typechange__initialize(void)
64 g_repo
= cl_git_sandbox_init("typechanges");
66 cl_fixture_sandbox("submod2_target");
67 p_rename("submod2_target/.gitted", "submod2_target/.git");
70 void test_checkout_typechange__cleanup(void)
72 cl_git_sandbox_cleanup();
73 cl_fixture_cleanup("submod2_target");
76 static void assert_file_exists(const char *path
)
78 cl_assert_(git_path_isfile(path
), path
);
81 static void assert_dir_exists(const char *path
)
83 cl_assert_(git_path_isdir(path
), path
);
86 static void assert_workdir_matches_tree(
87 git_repository
*repo
, const git_oid
*id
, const char *root
, bool recurse
)
92 git_buf path
= GIT_BUF_INIT
;
95 root
= git_repository_workdir(repo
);
98 cl_git_pass(git_object_lookup(&obj
, repo
, id
, GIT_OBJ_ANY
));
99 cl_git_pass(git_object_peel((git_object
**)&tree
, obj
, GIT_OBJ_TREE
));
100 git_object_free(obj
);
102 max_i
= git_tree_entrycount(tree
);
104 for (i
= 0; i
< max_i
; ++i
) {
105 const git_tree_entry
*te
= git_tree_entry_byindex(tree
, i
);
108 cl_git_pass(git_buf_joinpath(&path
, root
, git_tree_entry_name(te
)));
110 switch (git_tree_entry_type(te
)) {
112 assert_dir_exists(path
.ptr
);
115 assert_dir_exists(path
.ptr
);
117 assert_workdir_matches_tree(
118 repo
, git_tree_entry_id(te
), path
.ptr
, true);
121 switch (git_tree_entry_filemode(te
)) {
122 case GIT_FILEMODE_BLOB
:
123 case GIT_FILEMODE_BLOB_EXECUTABLE
:
124 assert_file_exists(path
.ptr
);
125 /* because of cross-platform, don't confirm exec bit yet */
127 case GIT_FILEMODE_LINK
:
128 cl_assert_(git_path_exists(path
.ptr
), path
.ptr
);
129 /* because of cross-platform, don't confirm link yet */
132 cl_assert(false); /* really?! */
136 cl_assert(false); /* really?!! */
144 void test_checkout_typechange__checkout_typechanges_safe(void)
148 git_checkout_options opts
= GIT_CHECKOUT_OPTIONS_INIT
;
150 for (i
= 0; g_typechange_oids
[i
] != NULL
; ++i
) {
151 cl_git_pass(git_revparse_single(&obj
, g_repo
, g_typechange_oids
[i
]));
153 opts
.checkout_strategy
= !i
? GIT_CHECKOUT_FORCE
: GIT_CHECKOUT_SAFE
;
155 cl_git_pass(git_checkout_tree(g_repo
, obj
, &opts
));
158 git_repository_set_head_detached(g_repo
, git_object_id(obj
)));
160 assert_workdir_matches_tree(g_repo
, git_object_id(obj
), NULL
, true);
162 git_object_free(obj
);
164 if (!g_typechange_empty
[i
]) {
165 cl_assert(git_path_isdir("typechanges"));
166 cl_assert(git_path_exists("typechanges/a"));
167 cl_assert(git_path_exists("typechanges/b"));
168 cl_assert(git_path_exists("typechanges/c"));
169 cl_assert(git_path_exists("typechanges/d"));
170 cl_assert(git_path_exists("typechanges/e"));
172 cl_assert(git_path_isdir("typechanges"));
173 cl_assert(!git_path_exists("typechanges/a"));
174 cl_assert(!git_path_exists("typechanges/b"));
175 cl_assert(!git_path_exists("typechanges/c"));
176 cl_assert(!git_path_exists("typechanges/d"));
177 cl_assert(!git_path_exists("typechanges/e"));
190 static int notify_counter(
191 git_checkout_notify_t why
,
193 const git_diff_file
*baseline
,
194 const git_diff_file
*target
,
195 const git_diff_file
*workdir
,
198 notify_counts
*cts
= payload
;
201 GIT_UNUSED(baseline
);
206 case GIT_CHECKOUT_NOTIFY_CONFLICT
: cts
->conflicts
++; break;
207 case GIT_CHECKOUT_NOTIFY_DIRTY
: cts
->dirty
++; break;
208 case GIT_CHECKOUT_NOTIFY_UPDATED
: cts
->updates
++; break;
209 case GIT_CHECKOUT_NOTIFY_UNTRACKED
: cts
->untracked
++; break;
210 case GIT_CHECKOUT_NOTIFY_IGNORED
: cts
->ignored
++; break;
217 static void force_create_file(const char *file
)
219 int error
= git_futils_rmdir_r(file
, NULL
,
220 GIT_RMDIR_REMOVE_FILES
| GIT_RMDIR_REMOVE_BLOCKERS
);
221 cl_assert(!error
|| error
== GIT_ENOTFOUND
);
222 cl_git_pass(git_futils_mkpath2file(file
, 0777));
223 cl_git_rewritefile(file
, "yowza!!");
226 static int make_submodule_dirty(git_submodule
*sm
, const char *name
, void *payload
)
228 git_buf submodulepath
= GIT_BUF_INIT
;
229 git_buf dirtypath
= GIT_BUF_INIT
;
230 git_repository
*submodule_repo
;
235 /* remove submodule directory in preparation for init and repo_init */
236 cl_git_pass(git_buf_joinpath(
238 git_repository_workdir(g_repo
),
239 git_submodule_path(sm
)
241 git_futils_rmdir_r(git_buf_cstr(&submodulepath
), NULL
, GIT_RMDIR_REMOVE_FILES
);
243 /* initialize submodule's repository */
244 cl_git_pass(git_submodule_repo_init(&submodule_repo
, sm
, 0));
246 /* create a file in the submodule workdir to make it dirty */
248 git_buf_joinpath(&dirtypath
, git_repository_workdir(submodule_repo
), "dirty"));
249 force_create_file(git_buf_cstr(&dirtypath
));
251 git_buf_free(&dirtypath
);
252 git_buf_free(&submodulepath
);
253 git_repository_free(submodule_repo
);
258 void test_checkout_typechange__checkout_with_conflicts(void)
262 git_checkout_options opts
= GIT_CHECKOUT_OPTIONS_INIT
;
263 notify_counts cts
= {0};
266 GIT_CHECKOUT_NOTIFY_CONFLICT
| GIT_CHECKOUT_NOTIFY_UNTRACKED
;
267 opts
.notify_cb
= notify_counter
;
268 opts
.notify_payload
= &cts
;
270 for (i
= 0; g_typechange_oids
[i
] != NULL
; ++i
) {
271 cl_git_pass(git_revparse_single(&obj
, g_repo
, g_typechange_oids
[i
]));
273 force_create_file("typechanges/a/blocker");
274 force_create_file("typechanges/b");
275 force_create_file("typechanges/c/sub/sub/file");
276 git_futils_rmdir_r("typechanges/d", NULL
, GIT_RMDIR_REMOVE_FILES
);
277 p_mkdir("typechanges/d", 0777); /* intentionally empty dir */
278 force_create_file("typechanges/untracked");
279 cl_git_pass(git_submodule_foreach(g_repo
, make_submodule_dirty
, NULL
));
281 opts
.checkout_strategy
= GIT_CHECKOUT_SAFE
;
282 memset(&cts
, 0, sizeof(cts
));
284 cl_git_fail(git_checkout_tree(g_repo
, obj
, &opts
));
285 cl_assert_equal_i(cts
.conflicts
, g_typechange_expected_conflicts
[i
]);
286 cl_assert_equal_i(cts
.untracked
, g_typechange_expected_untracked
[i
]);
287 cl_assert_equal_i(cts
.dirty
, 0);
288 cl_assert_equal_i(cts
.updates
, 0);
289 cl_assert_equal_i(cts
.ignored
, 0);
291 opts
.checkout_strategy
=
292 GIT_CHECKOUT_FORCE
| GIT_CHECKOUT_REMOVE_UNTRACKED
;
293 memset(&cts
, 0, sizeof(cts
));
295 cl_assert(git_path_exists("typechanges/untracked"));
297 cl_git_pass(git_checkout_tree(g_repo
, obj
, &opts
));
298 cl_assert_equal_i(0, cts
.conflicts
);
300 cl_assert(!git_path_exists("typechanges/untracked"));
303 git_repository_set_head_detached(g_repo
, git_object_id(obj
)));
305 assert_workdir_matches_tree(g_repo
, git_object_id(obj
), NULL
, true);
307 git_object_free(obj
);