]> git.proxmox.com Git - libgit2.git/blame - tests/submodule/status.c
Merge pull request #2201 from ethomson/gitbuf_test_fix
[libgit2.git] / tests / submodule / status.c
CommitLineData
aa13bf05
RB
1#include "clar_libgit2.h"
2#include "posix.h"
3#include "path.h"
4#include "submodule_helpers.h"
5f4a61ae 5#include "fileops.h"
65025cb8 6#include "iterator.h"
aa13bf05
RB
7
8static git_repository *g_repo = NULL;
9
10void test_submodule_status__initialize(void)
11{
125655fe 12 g_repo = setup_fixture_submod2();
aa13bf05
RB
13}
14
15void test_submodule_status__cleanup(void)
16{
aa13bf05
RB
17}
18
19void test_submodule_status__unchanged(void)
20{
5f4a61ae
RB
21 unsigned int status, expected;
22 git_submodule *sm;
23
24 cl_git_pass(git_submodule_lookup(&sm, g_repo, "sm_unchanged"));
25 cl_git_pass(git_submodule_status(&status, sm));
26 cl_assert(GIT_SUBMODULE_STATUS_IS_UNMODIFIED(status));
27
28 expected = GIT_SUBMODULE_STATUS_IN_HEAD |
29 GIT_SUBMODULE_STATUS_IN_INDEX |
30 GIT_SUBMODULE_STATUS_IN_CONFIG |
31 GIT_SUBMODULE_STATUS_IN_WD;
32
33 cl_assert(status == expected);
aa13bf05
RB
34}
35
5f4a61ae
RB
36/* 4 values of GIT_SUBMODULE_IGNORE to check */
37
38void test_submodule_status__ignore_none(void)
aa13bf05 39{
5f4a61ae
RB
40 unsigned int status;
41 git_submodule *sm;
42 git_buf path = GIT_BUF_INIT;
43
44 cl_git_pass(git_buf_joinpath(&path, git_repository_workdir(g_repo), "sm_unchanged"));
331e7de9 45 cl_git_pass(git_futils_rmdir_r(git_buf_cstr(&path), NULL, GIT_RMDIR_REMOVE_FILES));
5f4a61ae 46
65025cb8
RB
47 cl_assert_equal_i(GIT_ENOTFOUND,
48 git_submodule_lookup(&sm, g_repo, "just_a_dir"));
49 cl_assert_equal_i(GIT_EEXISTS,
50 git_submodule_lookup(&sm, g_repo, "not-submodule"));
51 cl_assert_equal_i(GIT_EEXISTS,
52 git_submodule_lookup(&sm, g_repo, "not"));
5f4a61ae
RB
53
54 cl_git_pass(git_submodule_lookup(&sm, g_repo, "sm_changed_index"));
55 cl_git_pass(git_submodule_status(&status, sm));
56 cl_assert((status & GIT_SUBMODULE_STATUS_WD_INDEX_MODIFIED) != 0);
57
58 cl_git_pass(git_submodule_lookup(&sm, g_repo, "sm_changed_head"));
59 cl_git_pass(git_submodule_status(&status, sm));
60 cl_assert((status & GIT_SUBMODULE_STATUS_WD_MODIFIED) != 0);
61
62 cl_git_pass(git_submodule_lookup(&sm, g_repo, "sm_changed_file"));
63 cl_git_pass(git_submodule_status(&status, sm));
64 cl_assert((status & GIT_SUBMODULE_STATUS_WD_WD_MODIFIED) != 0);
65
66 cl_git_pass(git_submodule_lookup(&sm, g_repo, "sm_changed_untracked_file"));
67 cl_git_pass(git_submodule_status(&status, sm));
68 cl_assert((status & GIT_SUBMODULE_STATUS_WD_UNTRACKED) != 0);
69
70 cl_git_pass(git_submodule_lookup(&sm, g_repo, "sm_missing_commits"));
71 cl_git_pass(git_submodule_status(&status, sm));
72 cl_assert((status & GIT_SUBMODULE_STATUS_WD_MODIFIED) != 0);
73
74 cl_git_pass(git_submodule_lookup(&sm, g_repo, "sm_added_and_uncommited"));
75 cl_git_pass(git_submodule_status(&status, sm));
76 cl_assert((status & GIT_SUBMODULE_STATUS_INDEX_ADDED) != 0);
77
78 /* removed sm_unchanged for deleted workdir */
79 cl_git_pass(git_submodule_lookup(&sm, g_repo, "sm_unchanged"));
80 cl_git_pass(git_submodule_status(&status, sm));
81 cl_assert((status & GIT_SUBMODULE_STATUS_WD_DELETED) != 0);
82
83 /* now mkdir sm_unchanged to test uninitialized */
84 cl_git_pass(git_futils_mkdir(git_buf_cstr(&path), NULL, 0755, 0));
85 cl_git_pass(git_submodule_lookup(&sm, g_repo, "sm_unchanged"));
86 cl_git_pass(git_submodule_reload(sm));
87 cl_git_pass(git_submodule_status(&status, sm));
88 cl_assert((status & GIT_SUBMODULE_STATUS_WD_UNINITIALIZED) != 0);
89
90 /* update sm_changed_head in index */
91 cl_git_pass(git_submodule_lookup(&sm, g_repo, "sm_changed_head"));
92 cl_git_pass(git_submodule_add_to_index(sm, true));
93 /* reload is not needed because add_to_index updates the submodule data */
94 cl_git_pass(git_submodule_status(&status, sm));
95 cl_assert((status & GIT_SUBMODULE_STATUS_INDEX_MODIFIED) != 0);
96
97 /* remove sm_changed_head from index */
98 {
99 git_index *index;
11d9f6b3 100 size_t pos;
5f4a61ae
RB
101
102 cl_git_pass(git_repository_index(&index, g_repo));
11d9f6b3 103 cl_assert(!git_index_find(&pos, index, "sm_changed_head"));
f45ec1a0 104 cl_git_pass(git_index_remove(index, "sm_changed_head", 0));
5f4a61ae
RB
105 cl_git_pass(git_index_write(index));
106
107 git_index_free(index);
108 }
aa13bf05 109
5f4a61ae
RB
110 cl_git_pass(git_submodule_lookup(&sm, g_repo, "sm_changed_head"));
111 cl_git_pass(git_submodule_reload(sm));
112 cl_git_pass(git_submodule_status(&status, sm));
113 cl_assert((status & GIT_SUBMODULE_STATUS_INDEX_DELETED) != 0);
114
115 git_buf_free(&path);
aa13bf05
RB
116}
117
5f4a61ae
RB
118static int set_sm_ignore(git_submodule *sm, const char *name, void *payload)
119{
120 git_submodule_ignore_t ignore = *(git_submodule_ignore_t *)payload;
121 GIT_UNUSED(name);
122 git_submodule_set_ignore(sm, ignore);
123 return 0;
124}
125
126void test_submodule_status__ignore_untracked(void)
127{
128 unsigned int status;
129 git_submodule *sm;
130 git_buf path = GIT_BUF_INIT;
131 git_submodule_ignore_t ign = GIT_SUBMODULE_IGNORE_UNTRACKED;
132
133 cl_git_pass(git_buf_joinpath(&path, git_repository_workdir(g_repo), "sm_unchanged"));
331e7de9 134 cl_git_pass(git_futils_rmdir_r(git_buf_cstr(&path), NULL, GIT_RMDIR_REMOVE_FILES));
5f4a61ae
RB
135
136 cl_git_pass(git_submodule_foreach(g_repo, set_sm_ignore, &ign));
137
65025cb8 138 cl_git_fail(git_submodule_lookup(&sm, g_repo, "not-submodule"));
5f4a61ae
RB
139
140 cl_git_pass(git_submodule_lookup(&sm, g_repo, "sm_changed_index"));
141 cl_git_pass(git_submodule_status(&status, sm));
142 cl_assert((status & GIT_SUBMODULE_STATUS_WD_INDEX_MODIFIED) != 0);
143
144 cl_git_pass(git_submodule_lookup(&sm, g_repo, "sm_changed_head"));
145 cl_git_pass(git_submodule_status(&status, sm));
146 cl_assert((status & GIT_SUBMODULE_STATUS_WD_MODIFIED) != 0);
147
148 cl_git_pass(git_submodule_lookup(&sm, g_repo, "sm_changed_file"));
149 cl_git_pass(git_submodule_status(&status, sm));
150 cl_assert((status & GIT_SUBMODULE_STATUS_WD_WD_MODIFIED) != 0);
151
152 cl_git_pass(git_submodule_lookup(&sm, g_repo, "sm_changed_untracked_file"));
153 cl_git_pass(git_submodule_status(&status, sm));
154 cl_assert(GIT_SUBMODULE_STATUS_IS_UNMODIFIED(status));
155
156 cl_git_pass(git_submodule_lookup(&sm, g_repo, "sm_missing_commits"));
157 cl_git_pass(git_submodule_status(&status, sm));
158 cl_assert((status & GIT_SUBMODULE_STATUS_WD_MODIFIED) != 0);
159
160 cl_git_pass(git_submodule_lookup(&sm, g_repo, "sm_added_and_uncommited"));
161 cl_git_pass(git_submodule_status(&status, sm));
162 cl_assert((status & GIT_SUBMODULE_STATUS_INDEX_ADDED) != 0);
163
164 /* removed sm_unchanged for deleted workdir */
165 cl_git_pass(git_submodule_lookup(&sm, g_repo, "sm_unchanged"));
166 cl_git_pass(git_submodule_status(&status, sm));
167 cl_assert((status & GIT_SUBMODULE_STATUS_WD_DELETED) != 0);
168
169 /* now mkdir sm_unchanged to test uninitialized */
170 cl_git_pass(git_futils_mkdir(git_buf_cstr(&path), NULL, 0755, 0));
171 cl_git_pass(git_submodule_lookup(&sm, g_repo, "sm_unchanged"));
172 cl_git_pass(git_submodule_reload(sm));
173 cl_git_pass(git_submodule_status(&status, sm));
174 cl_assert((status & GIT_SUBMODULE_STATUS_WD_UNINITIALIZED) != 0);
175
176 /* update sm_changed_head in index */
177 cl_git_pass(git_submodule_lookup(&sm, g_repo, "sm_changed_head"));
178 cl_git_pass(git_submodule_add_to_index(sm, true));
179 /* reload is not needed because add_to_index updates the submodule data */
180 cl_git_pass(git_submodule_status(&status, sm));
181 cl_assert((status & GIT_SUBMODULE_STATUS_INDEX_MODIFIED) != 0);
182
183 git_buf_free(&path);
184}
185
186void test_submodule_status__ignore_dirty(void)
187{
188 unsigned int status;
189 git_submodule *sm;
190 git_buf path = GIT_BUF_INIT;
191 git_submodule_ignore_t ign = GIT_SUBMODULE_IGNORE_DIRTY;
192
193 cl_git_pass(git_buf_joinpath(&path, git_repository_workdir(g_repo), "sm_unchanged"));
331e7de9 194 cl_git_pass(git_futils_rmdir_r(git_buf_cstr(&path), NULL, GIT_RMDIR_REMOVE_FILES));
5f4a61ae
RB
195
196 cl_git_pass(git_submodule_foreach(g_repo, set_sm_ignore, &ign));
197
65025cb8
RB
198 cl_assert_equal_i(GIT_ENOTFOUND,
199 git_submodule_lookup(&sm, g_repo, "just_a_dir"));
200 cl_assert_equal_i(GIT_EEXISTS,
201 git_submodule_lookup(&sm, g_repo, "not-submodule"));
202 cl_assert_equal_i(GIT_EEXISTS,
203 git_submodule_lookup(&sm, g_repo, "not"));
5f4a61ae
RB
204
205 cl_git_pass(git_submodule_lookup(&sm, g_repo, "sm_changed_index"));
206 cl_git_pass(git_submodule_status(&status, sm));
207 cl_assert(GIT_SUBMODULE_STATUS_IS_UNMODIFIED(status));
208
209 cl_git_pass(git_submodule_lookup(&sm, g_repo, "sm_changed_head"));
210 cl_git_pass(git_submodule_status(&status, sm));
211 cl_assert((status & GIT_SUBMODULE_STATUS_WD_MODIFIED) != 0);
212
213 cl_git_pass(git_submodule_lookup(&sm, g_repo, "sm_changed_file"));
214 cl_git_pass(git_submodule_status(&status, sm));
215 cl_assert(GIT_SUBMODULE_STATUS_IS_UNMODIFIED(status));
216
217 cl_git_pass(git_submodule_lookup(&sm, g_repo, "sm_changed_untracked_file"));
218 cl_git_pass(git_submodule_status(&status, sm));
219 cl_assert(GIT_SUBMODULE_STATUS_IS_UNMODIFIED(status));
220
221 cl_git_pass(git_submodule_lookup(&sm, g_repo, "sm_missing_commits"));
222 cl_git_pass(git_submodule_status(&status, sm));
223 cl_assert((status & GIT_SUBMODULE_STATUS_WD_MODIFIED) != 0);
224
225 cl_git_pass(git_submodule_lookup(&sm, g_repo, "sm_added_and_uncommited"));
226 cl_git_pass(git_submodule_status(&status, sm));
227 cl_assert((status & GIT_SUBMODULE_STATUS_INDEX_ADDED) != 0);
228
229 /* removed sm_unchanged for deleted workdir */
230 cl_git_pass(git_submodule_lookup(&sm, g_repo, "sm_unchanged"));
231 cl_git_pass(git_submodule_status(&status, sm));
232 cl_assert((status & GIT_SUBMODULE_STATUS_WD_DELETED) != 0);
233
234 /* now mkdir sm_unchanged to test uninitialized */
235 cl_git_pass(git_futils_mkdir(git_buf_cstr(&path), NULL, 0755, 0));
236 cl_git_pass(git_submodule_lookup(&sm, g_repo, "sm_unchanged"));
237 cl_git_pass(git_submodule_reload(sm));
238 cl_git_pass(git_submodule_status(&status, sm));
239 cl_assert((status & GIT_SUBMODULE_STATUS_WD_UNINITIALIZED) != 0);
240
241 /* update sm_changed_head in index */
242 cl_git_pass(git_submodule_lookup(&sm, g_repo, "sm_changed_head"));
243 cl_git_pass(git_submodule_add_to_index(sm, true));
244 /* reload is not needed because add_to_index updates the submodule data */
245 cl_git_pass(git_submodule_status(&status, sm));
246 cl_assert((status & GIT_SUBMODULE_STATUS_INDEX_MODIFIED) != 0);
247
248 git_buf_free(&path);
249}
250
251void test_submodule_status__ignore_all(void)
252{
253 unsigned int status;
254 git_submodule *sm;
255 git_buf path = GIT_BUF_INIT;
256 git_submodule_ignore_t ign = GIT_SUBMODULE_IGNORE_ALL;
257
258 cl_git_pass(git_buf_joinpath(&path, git_repository_workdir(g_repo), "sm_unchanged"));
331e7de9 259 cl_git_pass(git_futils_rmdir_r(git_buf_cstr(&path), NULL, GIT_RMDIR_REMOVE_FILES));
5f4a61ae
RB
260
261 cl_git_pass(git_submodule_foreach(g_repo, set_sm_ignore, &ign));
262
65025cb8
RB
263 cl_assert_equal_i(GIT_ENOTFOUND,
264 git_submodule_lookup(&sm, g_repo, "just_a_dir"));
265 cl_assert_equal_i(GIT_EEXISTS,
266 git_submodule_lookup(&sm, g_repo, "not-submodule"));
267 cl_assert_equal_i(GIT_EEXISTS,
268 git_submodule_lookup(&sm, g_repo, "not"));
5f4a61ae
RB
269
270 cl_git_pass(git_submodule_lookup(&sm, g_repo, "sm_changed_index"));
271 cl_git_pass(git_submodule_status(&status, sm));
272 cl_assert(GIT_SUBMODULE_STATUS_IS_UNMODIFIED(status));
273
274 cl_git_pass(git_submodule_lookup(&sm, g_repo, "sm_changed_head"));
275 cl_git_pass(git_submodule_status(&status, sm));
276 cl_assert(GIT_SUBMODULE_STATUS_IS_UNMODIFIED(status));
277
278 cl_git_pass(git_submodule_lookup(&sm, g_repo, "sm_changed_file"));
279 cl_git_pass(git_submodule_status(&status, sm));
280 cl_assert(GIT_SUBMODULE_STATUS_IS_UNMODIFIED(status));
281
282 cl_git_pass(git_submodule_lookup(&sm, g_repo, "sm_changed_untracked_file"));
283 cl_git_pass(git_submodule_status(&status, sm));
284 cl_assert(GIT_SUBMODULE_STATUS_IS_UNMODIFIED(status));
285
286 cl_git_pass(git_submodule_lookup(&sm, g_repo, "sm_missing_commits"));
287 cl_git_pass(git_submodule_status(&status, sm));
288 cl_assert(GIT_SUBMODULE_STATUS_IS_UNMODIFIED(status));
289
290 cl_git_pass(git_submodule_lookup(&sm, g_repo, "sm_added_and_uncommited"));
291 cl_git_pass(git_submodule_status(&status, sm));
292 cl_assert(GIT_SUBMODULE_STATUS_IS_UNMODIFIED(status));
293
294 /* removed sm_unchanged for deleted workdir */
295 cl_git_pass(git_submodule_lookup(&sm, g_repo, "sm_unchanged"));
296 cl_git_pass(git_submodule_status(&status, sm));
297 cl_assert(GIT_SUBMODULE_STATUS_IS_UNMODIFIED(status));
298
299 /* now mkdir sm_unchanged to test uninitialized */
300 cl_git_pass(git_futils_mkdir(git_buf_cstr(&path), NULL, 0755, 0));
301 cl_git_pass(git_submodule_lookup(&sm, g_repo, "sm_unchanged"));
302 cl_git_pass(git_submodule_reload(sm));
303 cl_git_pass(git_submodule_status(&status, sm));
304 cl_assert(GIT_SUBMODULE_STATUS_IS_UNMODIFIED(status));
305
306 /* update sm_changed_head in index */
307 cl_git_pass(git_submodule_lookup(&sm, g_repo, "sm_changed_head"));
308 cl_git_pass(git_submodule_add_to_index(sm, true));
309 /* reload is not needed because add_to_index updates the submodule data */
310 cl_git_pass(git_submodule_status(&status, sm));
311 cl_assert(GIT_SUBMODULE_STATUS_IS_UNMODIFIED(status));
312
313 git_buf_free(&path);
314}
65025cb8
RB
315
316typedef struct {
317 size_t counter;
318 const char **paths;
125655fe 319 int *statuses;
65025cb8
RB
320} submodule_expectations;
321
322static int confirm_submodule_status(
323 const char *path, unsigned int status_flags, void *payload)
324{
325 submodule_expectations *exp = payload;
326
327 while (git__suffixcmp(exp->paths[exp->counter], "/") == 0)
328 exp->counter++;
329
125655fe 330 cl_assert_equal_i(exp->statuses[exp->counter], (int)status_flags);
65025cb8
RB
331 cl_assert_equal_s(exp->paths[exp->counter++], path);
332
333 GIT_UNUSED(status_flags);
334
335 return 0;
336}
337
338void test_submodule_status__iterator(void)
339{
340 git_iterator *iter;
341 const git_index_entry *entry;
342 size_t i;
343 static const char *expected[] = {
344 ".gitmodules",
345 "just_a_dir/",
346 "just_a_dir/contents",
347 "just_a_file",
348 "not",
349 "not-submodule",
350 "README.txt",
351 "sm_added_and_uncommited",
352 "sm_changed_file",
353 "sm_changed_head",
354 "sm_changed_index",
355 "sm_changed_untracked_file",
356 "sm_missing_commits",
357 "sm_unchanged",
358 NULL
359 };
125655fe
RB
360 static int expected_flags[] = {
361 GIT_STATUS_INDEX_MODIFIED | GIT_STATUS_WT_MODIFIED, /* ".gitmodules" */
362 0, /* "just_a_dir/" will be skipped */
363 GIT_STATUS_CURRENT, /* "just_a_dir/contents" */
364 GIT_STATUS_CURRENT, /* "just_a_file" */
365 GIT_STATUS_IGNORED, /* "not" (contains .git) */
366 GIT_STATUS_IGNORED, /* "not-submodule" (contains .git) */
367 GIT_STATUS_CURRENT, /* "README.txt */
368 GIT_STATUS_INDEX_NEW, /* "sm_added_and_uncommited" */
369 GIT_STATUS_WT_MODIFIED, /* "sm_changed_file" */
370 GIT_STATUS_WT_MODIFIED, /* "sm_changed_head" */
371 GIT_STATUS_WT_MODIFIED, /* "sm_changed_index" */
372 GIT_STATUS_WT_MODIFIED, /* "sm_changed_untracked_file" */
373 GIT_STATUS_WT_MODIFIED, /* "sm_missing_commits" */
374 GIT_STATUS_CURRENT, /* "sm_unchanged" */
375 0
376 };
377 submodule_expectations exp = { 0, expected, expected_flags };
65025cb8
RB
378 git_status_options opts = GIT_STATUS_OPTIONS_INIT;
379
380 cl_git_pass(git_iterator_for_workdir(&iter, g_repo,
381 GIT_ITERATOR_IGNORE_CASE | GIT_ITERATOR_INCLUDE_TREES, NULL, NULL));
65025cb8 382
cee695ae 383 for (i = 0; !git_iterator_advance(&entry, iter); ++i)
65025cb8 384 cl_assert_equal_s(expected[i], entry->path);
65025cb8
RB
385
386 git_iterator_free(iter);
387
351888cf
RB
388 opts.flags = GIT_STATUS_OPT_INCLUDE_UNTRACKED |
389 GIT_STATUS_OPT_INCLUDE_UNMODIFIED |
125655fe 390 GIT_STATUS_OPT_INCLUDE_IGNORED |
d5e83627
RB
391 GIT_STATUS_OPT_RECURSE_UNTRACKED_DIRS |
392 GIT_STATUS_OPT_SORT_CASE_INSENSITIVELY;
65025cb8 393
351888cf
RB
394 cl_git_pass(git_status_foreach_ext(
395 g_repo, &opts, confirm_submodule_status, &exp));
65025cb8 396}
e26b14c0
RB
397
398void test_submodule_status__untracked_dirs_containing_ignored_files(void)
399{
400 git_buf path = GIT_BUF_INIT;
401 unsigned int status, expected;
402 git_submodule *sm;
403
404 cl_git_pass(git_buf_joinpath(&path, git_repository_path(g_repo), "modules/sm_unchanged/info/exclude"));
405 cl_git_append2file(git_buf_cstr(&path), "\n*.ignored\n");
406
407 cl_git_pass(git_buf_joinpath(&path, git_repository_workdir(g_repo), "sm_unchanged/directory"));
408 cl_git_pass(git_futils_mkdir(git_buf_cstr(&path), NULL, 0755, 0));
409 cl_git_pass(git_buf_joinpath(&path, git_buf_cstr(&path), "i_am.ignored"));
410 cl_git_mkfile(git_buf_cstr(&path), "ignored this file, please\n");
411
412 cl_git_pass(git_submodule_lookup(&sm, g_repo, "sm_unchanged"));
413 cl_git_pass(git_submodule_status(&status, sm));
414
415 cl_assert(GIT_SUBMODULE_STATUS_IS_UNMODIFIED(status));
416
417 expected = GIT_SUBMODULE_STATUS_IN_HEAD |
418 GIT_SUBMODULE_STATUS_IN_INDEX |
419 GIT_SUBMODULE_STATUS_IN_CONFIG |
420 GIT_SUBMODULE_STATUS_IN_WD;
421
422 cl_assert(status == expected);
d8041638
ET
423
424 git_buf_free(&path);
e26b14c0 425}