]> git.proxmox.com Git - libgit2.git/blame - tests/checkout/typechange.c
push: remove reflog message override
[libgit2.git] / tests / checkout / typechange.c
CommitLineData
0d64bef9
RB
1#include "clar_libgit2.h"
2#include "git2/checkout.h"
3#include "path.h"
4#include "posix.h"
c50c58de 5#include "fileops.h"
0d64bef9
RB
6
7static git_repository *g_repo = NULL;
8
9static const char *g_typechange_oids[] = {
10 "79b9f23e85f55ea36a472a902e875bc1121a94cb",
11 "9bdb75b73836a99e3dbeea640a81de81031fdc29",
12 "0e7ed140b514b8cae23254cb8656fe1674403aff",
13 "9d0235c7a7edc0889a18f97a42ee6db9fe688447",
14 "9b19edf33a03a0c59cdfc113bfa5c06179bf9b1a",
15 "1b63caae4a5ca96f78e8dfefc376c6a39a142475",
16 "6eae26c90e8ccc4d16208972119c40635489c6f0",
17 NULL
18};
19
20static bool g_typechange_empty[] = {
21 true, false, false, false, false, false, true, true
22};
23
24void test_checkout_typechange__initialize(void)
25{
26 g_repo = cl_git_sandbox_init("typechanges");
27
28 cl_fixture_sandbox("submod2_target");
29 p_rename("submod2_target/.gitted", "submod2_target/.git");
30}
31
32void test_checkout_typechange__cleanup(void)
33{
34 cl_git_sandbox_cleanup();
35 cl_fixture_cleanup("submod2_target");
36}
37
c50c58de
RB
38static void assert_file_exists(const char *path)
39{
40 cl_assert_(git_path_isfile(path), path);
41}
42
43static void assert_dir_exists(const char *path)
44{
45 cl_assert_(git_path_isdir(path), path);
46}
47
48static void assert_workdir_matches_tree(
49 git_repository *repo, const git_oid *id, const char *root, bool recurse)
50{
51 git_object *obj;
52 git_tree *tree;
53 size_t i, max_i;
54 git_buf path = GIT_BUF_INIT;
55
56 if (!root)
57 root = git_repository_workdir(repo);
58 cl_assert(root);
59
60 cl_git_pass(git_object_lookup(&obj, repo, id, GIT_OBJ_ANY));
61 cl_git_pass(git_object_peel((git_object **)&tree, obj, GIT_OBJ_TREE));
62 git_object_free(obj);
63
64 max_i = git_tree_entrycount(tree);
65
66 for (i = 0; i < max_i; ++i) {
67 const git_tree_entry *te = git_tree_entry_byindex(tree, i);
68 cl_assert(te);
69
70 cl_git_pass(git_buf_joinpath(&path, root, git_tree_entry_name(te)));
71
72 switch (git_tree_entry_type(te)) {
73 case GIT_OBJ_COMMIT:
74 assert_dir_exists(path.ptr);
75 break;
76 case GIT_OBJ_TREE:
77 assert_dir_exists(path.ptr);
78 if (recurse)
79 assert_workdir_matches_tree(
80 repo, git_tree_entry_id(te), path.ptr, true);
81 break;
82 case GIT_OBJ_BLOB:
83 switch (git_tree_entry_filemode(te)) {
84 case GIT_FILEMODE_BLOB:
85 case GIT_FILEMODE_BLOB_EXECUTABLE:
86 assert_file_exists(path.ptr);
87 /* because of cross-platform, don't confirm exec bit yet */
88 break;
89 case GIT_FILEMODE_LINK:
90 cl_assert_(git_path_exists(path.ptr), path.ptr);
91 /* because of cross-platform, don't confirm link yet */
92 break;
93 default:
94 cl_assert(false); /* really?! */
95 }
96 break;
97 default:
98 cl_assert(false); /* really?!! */
99 }
100 }
101
102 git_tree_free(tree);
103 git_buf_free(&path);
104}
105
106void test_checkout_typechange__checkout_typechanges_safe(void)
0d64bef9
RB
107{
108 int i;
109 git_object *obj;
6affd71f 110 git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT;
0d64bef9 111
0d64bef9
RB
112 for (i = 0; g_typechange_oids[i] != NULL; ++i) {
113 cl_git_pass(git_revparse_single(&obj, g_repo, g_typechange_oids[i]));
7e5c8a5b 114
c50c58de
RB
115 opts.checkout_strategy = GIT_CHECKOUT_FORCE;
116
117 /* There are bugs in some submodule->tree changes that prevent
118 * SAFE from passing here, even though the following should work:
119 */
120 /* !i ? GIT_CHECKOUT_FORCE : GIT_CHECKOUT_SAFE; */
0d64bef9 121
30a46ab1 122 cl_git_pass(git_checkout_tree(g_repo, obj, &opts));
0d64bef9 123
ad9a921b 124 cl_git_pass(
659cf202 125 git_repository_set_head_detached(g_repo, git_object_id(obj), NULL));
ad9a921b 126
c50c58de
RB
127 assert_workdir_matches_tree(g_repo, git_object_id(obj), NULL, true);
128
0d64bef9
RB
129 git_object_free(obj);
130
131 if (!g_typechange_empty[i]) {
132 cl_assert(git_path_isdir("typechanges"));
133 cl_assert(git_path_exists("typechanges/a"));
134 cl_assert(git_path_exists("typechanges/b"));
135 cl_assert(git_path_exists("typechanges/c"));
136 cl_assert(git_path_exists("typechanges/d"));
137 cl_assert(git_path_exists("typechanges/e"));
138 } else {
139 cl_assert(git_path_isdir("typechanges"));
140 cl_assert(!git_path_exists("typechanges/a"));
141 cl_assert(!git_path_exists("typechanges/b"));
142 cl_assert(!git_path_exists("typechanges/c"));
143 cl_assert(!git_path_exists("typechanges/d"));
144 cl_assert(!git_path_exists("typechanges/e"));
145 }
146 }
147}
c50c58de
RB
148
149typedef struct {
150 int conflicts;
151 int dirty;
152 int updates;
153 int untracked;
154 int ignored;
155} notify_counts;
156
157static int notify_counter(
158 git_checkout_notify_t why,
159 const char *path,
160 const git_diff_file *baseline,
161 const git_diff_file *target,
162 const git_diff_file *workdir,
163 void *payload)
164{
165 notify_counts *cts = payload;
166
167 GIT_UNUSED(path);
168 GIT_UNUSED(baseline);
169 GIT_UNUSED(target);
170 GIT_UNUSED(workdir);
171
172 switch (why) {
173 case GIT_CHECKOUT_NOTIFY_CONFLICT: cts->conflicts++; break;
174 case GIT_CHECKOUT_NOTIFY_DIRTY: cts->dirty++; break;
175 case GIT_CHECKOUT_NOTIFY_UPDATED: cts->updates++; break;
176 case GIT_CHECKOUT_NOTIFY_UNTRACKED: cts->untracked++; break;
177 case GIT_CHECKOUT_NOTIFY_IGNORED: cts->ignored++; break;
178 default: break;
179 }
180
181 return 0;
182}
183
184static void force_create_file(const char *file)
185{
186 int error = git_futils_rmdir_r(file, NULL,
187 GIT_RMDIR_REMOVE_FILES | GIT_RMDIR_REMOVE_BLOCKERS);
188 cl_assert(!error || error == GIT_ENOTFOUND);
189 cl_git_pass(git_futils_mkpath2file(file, 0777));
8023b83a 190 cl_git_rewritefile(file, "yowza!!");
c50c58de
RB
191}
192
193void test_checkout_typechange__checkout_with_conflicts(void)
194{
195 int i;
196 git_object *obj;
6affd71f 197 git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT;
c50c58de
RB
198 notify_counts cts = {0};
199
200 opts.notify_flags =
201 GIT_CHECKOUT_NOTIFY_CONFLICT | GIT_CHECKOUT_NOTIFY_UNTRACKED;
202 opts.notify_cb = notify_counter;
203 opts.notify_payload = &cts;
204
205 for (i = 0; g_typechange_oids[i] != NULL; ++i) {
206 cl_git_pass(git_revparse_single(&obj, g_repo, g_typechange_oids[i]));
207
208 force_create_file("typechanges/a/blocker");
209 force_create_file("typechanges/b");
210 force_create_file("typechanges/c/sub/sub/file");
211 git_futils_rmdir_r("typechanges/d", NULL, GIT_RMDIR_REMOVE_FILES);
212 p_mkdir("typechanges/d", 0777); /* intentionally empty dir */
213 force_create_file("typechanges/untracked");
214
496b76d4 215 opts.checkout_strategy = GIT_CHECKOUT_SAFE;
c50c58de
RB
216 memset(&cts, 0, sizeof(cts));
217
218 cl_git_fail(git_checkout_tree(g_repo, obj, &opts));
219 cl_assert(cts.conflicts > 0);
220 cl_assert(cts.untracked > 0);
221
222 opts.checkout_strategy =
223 GIT_CHECKOUT_FORCE | GIT_CHECKOUT_REMOVE_UNTRACKED;
224 memset(&cts, 0, sizeof(cts));
225
226 cl_assert(git_path_exists("typechanges/untracked"));
227
228 cl_git_pass(git_checkout_tree(g_repo, obj, &opts));
229 cl_assert_equal_i(0, cts.conflicts);
230
231 cl_assert(!git_path_exists("typechanges/untracked"));
232
233 cl_git_pass(
659cf202 234 git_repository_set_head_detached(g_repo, git_object_id(obj), NULL));
c50c58de
RB
235
236 assert_workdir_matches_tree(g_repo, git_object_id(obj), NULL, true);
237
238 git_object_free(obj);
239 }
240}