]> git.proxmox.com Git - libgit2.git/blob - tests/submodule/status.c
06595cc9aa2d86e227314a86b375974e72b54ce4
[libgit2.git] / tests / submodule / status.c
1 #include "clar_libgit2.h"
2 #include "posix.h"
3 #include "path.h"
4 #include "submodule_helpers.h"
5 #include "futils.h"
6 #include "iterator.h"
7
8 static git_repository *g_repo = NULL;
9
10 void test_submodule_status__initialize(void)
11 {
12 g_repo = setup_fixture_submod2();
13 }
14
15 void test_submodule_status__cleanup(void)
16 {
17 }
18
19 void test_submodule_status__unchanged(void)
20 {
21 unsigned int status = get_submodule_status(g_repo, "sm_unchanged");
22 unsigned int expected =
23 GIT_SUBMODULE_STATUS_IN_HEAD |
24 GIT_SUBMODULE_STATUS_IN_INDEX |
25 GIT_SUBMODULE_STATUS_IN_CONFIG |
26 GIT_SUBMODULE_STATUS_IN_WD;
27
28 cl_assert(GIT_SUBMODULE_STATUS_IS_UNMODIFIED(status));
29 cl_assert(expected == status);
30 }
31
32 static void rm_submodule(const char *name)
33 {
34 git_buf path = GIT_BUF_INIT;
35 cl_git_pass(git_buf_joinpath(&path, git_repository_workdir(g_repo), name));
36 cl_git_pass(git_futils_rmdir_r(path.ptr, NULL, GIT_RMDIR_REMOVE_FILES));
37 git_buf_dispose(&path);
38 }
39
40 static void add_submodule_to_index(const char *name)
41 {
42 git_submodule *sm;
43 cl_git_pass(git_submodule_lookup(&sm, g_repo, name));
44 cl_git_pass(git_submodule_add_to_index(sm, true));
45 git_submodule_free(sm);
46 }
47
48 static void rm_submodule_from_index(const char *name)
49 {
50 git_index *index;
51 size_t pos;
52
53 cl_git_pass(git_repository_index(&index, g_repo));
54 cl_assert(!git_index_find(&pos, index, name));
55 cl_git_pass(git_index_remove(index, name, 0));
56 cl_git_pass(git_index_write(index));
57 git_index_free(index);
58 }
59
60 /* 4 values of GIT_SUBMODULE_IGNORE to check */
61
62 void test_submodule_status__ignore_none(void)
63 {
64 unsigned int status;
65
66 rm_submodule("sm_unchanged");
67
68 refute_submodule_exists(g_repo, "just_a_dir", GIT_ENOTFOUND);
69 refute_submodule_exists(g_repo, "not-submodule", GIT_EEXISTS);
70 refute_submodule_exists(g_repo, "not", GIT_EEXISTS);
71
72 status = get_submodule_status(g_repo, "sm_changed_index");
73 cl_assert((status & GIT_SUBMODULE_STATUS_WD_INDEX_MODIFIED) != 0);
74
75 status = get_submodule_status(g_repo, "sm_changed_head");
76 cl_assert((status & GIT_SUBMODULE_STATUS_WD_MODIFIED) != 0);
77
78 status = get_submodule_status(g_repo, "sm_changed_file");
79 cl_assert((status & GIT_SUBMODULE_STATUS_WD_WD_MODIFIED) != 0);
80
81 status = get_submodule_status(g_repo, "sm_changed_untracked_file");
82 cl_assert((status & GIT_SUBMODULE_STATUS_WD_UNTRACKED) != 0);
83
84 status = get_submodule_status(g_repo, "sm_missing_commits");
85 cl_assert((status & GIT_SUBMODULE_STATUS_WD_MODIFIED) != 0);
86
87 status = get_submodule_status(g_repo, "sm_added_and_uncommited");
88 cl_assert((status & GIT_SUBMODULE_STATUS_INDEX_ADDED) != 0);
89
90 /* removed sm_unchanged for deleted workdir */
91 status = get_submodule_status(g_repo, "sm_unchanged");
92 cl_assert((status & GIT_SUBMODULE_STATUS_WD_DELETED) != 0);
93
94 /* now mkdir sm_unchanged to test uninitialized */
95 cl_git_pass(git_futils_mkdir_relative("sm_unchanged", "submod2", 0755, 0, NULL));
96 status = get_submodule_status(g_repo, "sm_unchanged");
97 cl_assert((status & GIT_SUBMODULE_STATUS_WD_UNINITIALIZED) != 0);
98
99 /* update sm_changed_head in index */
100 add_submodule_to_index("sm_changed_head");
101 status = get_submodule_status(g_repo, "sm_changed_head");
102 cl_assert((status & GIT_SUBMODULE_STATUS_INDEX_MODIFIED) != 0);
103
104 /* remove sm_changed_head from index */
105 rm_submodule_from_index("sm_changed_head");
106 status = get_submodule_status(g_repo, "sm_changed_head");
107 cl_assert((status & GIT_SUBMODULE_STATUS_INDEX_DELETED) != 0);
108 }
109
110 void test_submodule_status__ignore_untracked(void)
111 {
112 unsigned int status;
113 git_submodule_ignore_t ign = GIT_SUBMODULE_IGNORE_UNTRACKED;
114
115 rm_submodule("sm_unchanged");
116
117 refute_submodule_exists(g_repo, "just_a_dir", GIT_ENOTFOUND);
118 refute_submodule_exists(g_repo, "not-submodule", GIT_EEXISTS);
119 refute_submodule_exists(g_repo, "not", GIT_EEXISTS);
120
121 cl_git_pass(git_submodule_status(&status, g_repo,"sm_changed_index", ign));
122 cl_assert((status & GIT_SUBMODULE_STATUS_WD_INDEX_MODIFIED) != 0);
123
124 cl_git_pass(git_submodule_status(&status, g_repo,"sm_changed_head", ign));
125 cl_assert((status & GIT_SUBMODULE_STATUS_WD_MODIFIED) != 0);
126
127 cl_git_pass(git_submodule_status(&status, g_repo,"sm_changed_file", ign));
128 cl_assert((status & GIT_SUBMODULE_STATUS_WD_WD_MODIFIED) != 0);
129
130 cl_git_pass(git_submodule_status(&status, g_repo,"sm_changed_untracked_file", ign));
131 cl_assert(GIT_SUBMODULE_STATUS_IS_UNMODIFIED(status));
132
133 cl_git_pass(git_submodule_status(&status, g_repo,"sm_missing_commits", ign));
134 cl_assert((status & GIT_SUBMODULE_STATUS_WD_MODIFIED) != 0);
135
136 cl_git_pass(git_submodule_status(&status, g_repo,"sm_added_and_uncommited", ign));
137 cl_assert((status & GIT_SUBMODULE_STATUS_INDEX_ADDED) != 0);
138
139 /* removed sm_unchanged for deleted workdir */
140 cl_git_pass(git_submodule_status(&status, g_repo,"sm_unchanged", ign));
141 cl_assert((status & GIT_SUBMODULE_STATUS_WD_DELETED) != 0);
142
143 /* now mkdir sm_unchanged to test uninitialized */
144 cl_git_pass(git_futils_mkdir_relative("sm_unchanged", "submod2", 0755, 0, NULL));
145 cl_git_pass(git_submodule_status(&status, g_repo,"sm_unchanged", ign));
146 cl_assert((status & GIT_SUBMODULE_STATUS_WD_UNINITIALIZED) != 0);
147
148 /* update sm_changed_head in index */
149 add_submodule_to_index("sm_changed_head");
150 cl_git_pass(git_submodule_status(&status, g_repo,"sm_changed_head", ign));
151 cl_assert((status & GIT_SUBMODULE_STATUS_INDEX_MODIFIED) != 0);
152 }
153
154 void test_submodule_status__ignore_dirty(void)
155 {
156 unsigned int status;
157 git_submodule_ignore_t ign = GIT_SUBMODULE_IGNORE_DIRTY;
158
159 rm_submodule("sm_unchanged");
160
161 refute_submodule_exists(g_repo, "just_a_dir", GIT_ENOTFOUND);
162 refute_submodule_exists(g_repo, "not-submodule", GIT_EEXISTS);
163 refute_submodule_exists(g_repo, "not", GIT_EEXISTS);
164
165 cl_git_pass(git_submodule_status(&status, g_repo,"sm_changed_index", ign));
166 cl_assert(GIT_SUBMODULE_STATUS_IS_UNMODIFIED(status));
167
168 cl_git_pass(git_submodule_status(&status, g_repo,"sm_changed_head", ign));
169 cl_assert((status & GIT_SUBMODULE_STATUS_WD_MODIFIED) != 0);
170
171 cl_git_pass(git_submodule_status(&status, g_repo,"sm_changed_file", ign));
172 cl_assert(GIT_SUBMODULE_STATUS_IS_UNMODIFIED(status));
173
174 cl_git_pass(git_submodule_status(&status, g_repo,"sm_changed_untracked_file", ign));
175 cl_assert(GIT_SUBMODULE_STATUS_IS_UNMODIFIED(status));
176
177 cl_git_pass(git_submodule_status(&status, g_repo,"sm_missing_commits", ign));
178 cl_assert((status & GIT_SUBMODULE_STATUS_WD_MODIFIED) != 0);
179
180 cl_git_pass(git_submodule_status(&status, g_repo,"sm_added_and_uncommited", ign));
181 cl_assert((status & GIT_SUBMODULE_STATUS_INDEX_ADDED) != 0);
182
183 /* removed sm_unchanged for deleted workdir */
184 cl_git_pass(git_submodule_status(&status, g_repo,"sm_unchanged", ign));
185 cl_assert((status & GIT_SUBMODULE_STATUS_WD_DELETED) != 0);
186
187 /* now mkdir sm_unchanged to test uninitialized */
188 cl_git_pass(git_futils_mkdir_relative("sm_unchanged", "submod2", 0755, 0, NULL));
189 cl_git_pass(git_submodule_status(&status, g_repo,"sm_unchanged", ign));
190 cl_assert((status & GIT_SUBMODULE_STATUS_WD_UNINITIALIZED) != 0);
191
192 /* update sm_changed_head in index */
193 add_submodule_to_index("sm_changed_head");
194 cl_git_pass(git_submodule_status(&status, g_repo,"sm_changed_head", ign));
195 cl_assert((status & GIT_SUBMODULE_STATUS_INDEX_MODIFIED) != 0);
196 }
197
198 void test_submodule_status__ignore_all(void)
199 {
200 unsigned int status;
201 git_submodule_ignore_t ign = GIT_SUBMODULE_IGNORE_ALL;
202
203 rm_submodule("sm_unchanged");
204
205 refute_submodule_exists(g_repo, "just_a_dir", GIT_ENOTFOUND);
206 refute_submodule_exists(g_repo, "not-submodule", GIT_EEXISTS);
207 refute_submodule_exists(g_repo, "not", GIT_EEXISTS);
208
209 cl_git_pass(git_submodule_status(&status, g_repo,"sm_changed_index", ign));
210 cl_assert(GIT_SUBMODULE_STATUS_IS_UNMODIFIED(status));
211
212 cl_git_pass(git_submodule_status(&status, g_repo,"sm_changed_head", ign));
213 cl_assert(GIT_SUBMODULE_STATUS_IS_UNMODIFIED(status));
214
215 cl_git_pass(git_submodule_status(&status, g_repo,"sm_changed_file", ign));
216 cl_assert(GIT_SUBMODULE_STATUS_IS_UNMODIFIED(status));
217
218 cl_git_pass(git_submodule_status(&status, g_repo,"sm_changed_untracked_file", ign));
219 cl_assert(GIT_SUBMODULE_STATUS_IS_UNMODIFIED(status));
220
221 cl_git_pass(git_submodule_status(&status, g_repo,"sm_missing_commits", ign));
222 cl_assert(GIT_SUBMODULE_STATUS_IS_UNMODIFIED(status));
223
224 cl_git_pass(git_submodule_status(&status, g_repo,"sm_added_and_uncommited", ign));
225 cl_assert(GIT_SUBMODULE_STATUS_IS_UNMODIFIED(status));
226
227 /* removed sm_unchanged for deleted workdir */
228 cl_git_pass(git_submodule_status(&status, g_repo,"sm_unchanged", ign));
229 cl_assert(GIT_SUBMODULE_STATUS_IS_UNMODIFIED(status));
230
231 /* now mkdir sm_unchanged to test uninitialized */
232 cl_git_pass(git_futils_mkdir_relative("sm_unchanged", "submod2", 0755, 0, NULL));
233 cl_git_pass(git_submodule_status(&status, g_repo,"sm_unchanged", ign));
234 cl_assert(GIT_SUBMODULE_STATUS_IS_UNMODIFIED(status));
235
236 /* update sm_changed_head in index */
237 add_submodule_to_index("sm_changed_head");
238 cl_git_pass(git_submodule_status(&status, g_repo,"sm_changed_head", ign));
239 cl_assert(GIT_SUBMODULE_STATUS_IS_UNMODIFIED(status));
240 }
241
242 typedef struct {
243 size_t counter;
244 const char **paths;
245 int *statuses;
246 } submodule_expectations;
247
248 static int confirm_submodule_status(
249 const char *path, unsigned int status_flags, void *payload)
250 {
251 submodule_expectations *exp = payload;
252
253 while (exp->statuses[exp->counter] < 0)
254 exp->counter++;
255
256 cl_assert_equal_i(exp->statuses[exp->counter], (int)status_flags);
257 cl_assert_equal_s(exp->paths[exp->counter++], path);
258
259 GIT_UNUSED(status_flags);
260
261 return 0;
262 }
263
264 void test_submodule_status__iterator(void)
265 {
266 git_iterator *iter;
267 git_iterator_options iter_opts = GIT_ITERATOR_OPTIONS_INIT;
268 const git_index_entry *entry;
269 size_t i;
270 static const char *expected[] = {
271 ".gitmodules",
272 "just_a_dir/",
273 "just_a_dir/contents",
274 "just_a_file",
275 "not-submodule/",
276 "not-submodule/README.txt",
277 "not/",
278 "not/README.txt",
279 "README.txt",
280 "sm_added_and_uncommited",
281 "sm_changed_file",
282 "sm_changed_head",
283 "sm_changed_index",
284 "sm_changed_untracked_file",
285 "sm_missing_commits",
286 "sm_unchanged",
287 NULL
288 };
289 static int expected_flags[] = {
290 GIT_STATUS_INDEX_MODIFIED | GIT_STATUS_WT_MODIFIED, /* ".gitmodules" */
291 -1, /* "just_a_dir/" will be skipped */
292 GIT_STATUS_CURRENT, /* "just_a_dir/contents" */
293 GIT_STATUS_CURRENT, /* "just_a_file" */
294 GIT_STATUS_WT_NEW, /* "not-submodule/" untracked item */
295 -1, /* "not-submodule/README.txt" */
296 GIT_STATUS_WT_NEW, /* "not/" untracked item */
297 -1, /* "not/README.txt" */
298 GIT_STATUS_CURRENT, /* "README.txt */
299 GIT_STATUS_INDEX_NEW, /* "sm_added_and_uncommited" */
300 GIT_STATUS_WT_MODIFIED, /* "sm_changed_file" */
301 GIT_STATUS_WT_MODIFIED, /* "sm_changed_head" */
302 GIT_STATUS_WT_MODIFIED, /* "sm_changed_index" */
303 GIT_STATUS_WT_MODIFIED, /* "sm_changed_untracked_file" */
304 GIT_STATUS_WT_MODIFIED, /* "sm_missing_commits" */
305 GIT_STATUS_CURRENT, /* "sm_unchanged" */
306 0
307 };
308 submodule_expectations exp = { 0, expected, expected_flags };
309 git_status_options opts = GIT_STATUS_OPTIONS_INIT;
310 git_index *index;
311
312 iter_opts.flags = GIT_ITERATOR_IGNORE_CASE | GIT_ITERATOR_INCLUDE_TREES;
313
314 cl_git_pass(git_repository_index(&index, g_repo));
315 cl_git_pass(git_iterator_for_workdir(&iter, g_repo, index, NULL, &iter_opts));
316
317 for (i = 0; !git_iterator_advance(&entry, iter); ++i)
318 cl_assert_equal_s(expected[i], entry->path);
319
320 git_iterator_free(iter);
321 git_index_free(index);
322
323 opts.flags = GIT_STATUS_OPT_INCLUDE_UNTRACKED |
324 GIT_STATUS_OPT_INCLUDE_UNMODIFIED |
325 GIT_STATUS_OPT_INCLUDE_IGNORED |
326 GIT_STATUS_OPT_RECURSE_UNTRACKED_DIRS |
327 GIT_STATUS_OPT_SORT_CASE_INSENSITIVELY;
328
329 cl_git_pass(git_status_foreach_ext(
330 g_repo, &opts, confirm_submodule_status, &exp));
331 }
332
333 void test_submodule_status__untracked_dirs_containing_ignored_files(void)
334 {
335 unsigned int status, expected;
336
337 cl_git_append2file(
338 "submod2/.git/modules/sm_unchanged/info/exclude", "\n*.ignored\n");
339
340 cl_git_pass(
341 git_futils_mkdir_relative("sm_unchanged/directory", "submod2", 0755, 0, NULL));
342 cl_git_mkfile(
343 "submod2/sm_unchanged/directory/i_am.ignored",
344 "ignore this file, please\n");
345
346 status = get_submodule_status(g_repo, "sm_unchanged");
347 cl_assert(GIT_SUBMODULE_STATUS_IS_UNMODIFIED(status));
348
349 expected = GIT_SUBMODULE_STATUS_IN_HEAD |
350 GIT_SUBMODULE_STATUS_IN_INDEX |
351 GIT_SUBMODULE_STATUS_IN_CONFIG |
352 GIT_SUBMODULE_STATUS_IN_WD;
353 cl_assert(status == expected);
354 }