]> git.proxmox.com Git - libgit2.git/blame - tests/t18-status.c
Merge pull request #384 from kiryl/warnings
[libgit2.git] / tests / t18-status.c
CommitLineData
205166d2
JP
1/*
2 * This file is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License, version 2,
4 * as published by the Free Software Foundation.
5 *
6 * In addition to the permissions in the GNU General Public License,
7 * the authors give you unlimited permission to link the compiled
8 * version of this file into combinations with other programs,
9 * and to distribute those combinations without any restriction
10 * coming from the use of this file. (The General Public License
11 * restrictions do apply in other respects; for example, they cover
12 * modification of the file, and distribution when not linked into
13 * a combined executable.)
14 *
15 * This file is distributed in the hope that it will be useful, but
16 * WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; see the file COPYING. If not, write to
22 * the Free Software Foundation, 51 Franklin Street, Fifth Floor,
23 * Boston, MA 02110-1301, USA.
24 */
d4760a42 25
205166d2
JP
26#include "test_lib.h"
27#include "test_helpers.h"
28#include "fileops.h"
29#include "git2/status.h"
30
3af6b34a 31static const char *test_blob_oid = "d4fa8600b4f37d7516bef4816ae2c64dbf029e3a";
205166d2 32
d4760a42 33#define STATUS_WORKDIR_FOLDER TEST_RESOURCES "/status/"
34#define STATUS_REPOSITORY_TEMP_FOLDER TEMP_REPO_FOLDER ".gitted/"
2b90cc26 35
d8b903da 36static int file_create(const char *filename, const char *content)
37{
38 int fd;
39
40 fd = p_creat(filename, 0644);
41 if (fd == 0)
42 return GIT_ERROR;
43 if (p_write(fd, content, strlen(content)) != 0)
44 return GIT_ERROR;
45 if (p_close(fd) != 0)
46 return GIT_ERROR;
47
48 return GIT_SUCCESS;
49}
50
bcba8460
VM
51BEGIN_TEST(file0, "test retrieving OID from a file apart from the ODB")
52 git_oid expected_id, actual_id;
53 char filename[] = "new_file";
54
55 must_pass(file_create(filename, "new_file\n\0"));
56
57 must_pass(git_odb_hashfile(&actual_id, filename, GIT_OBJ_BLOB));
58
59 must_pass(git_oid_fromstr(&expected_id, test_blob_oid));
60 must_be_true(git_oid_cmp(&expected_id, &actual_id) == 0);
61
62 must_pass(p_unlink(filename));
63END_TEST
64
d8b903da 65static const char *entry_paths0[] = {
3af6b34a
JP
66 "file_deleted",
67 "modified_file",
68 "new_file",
69 "staged_changes",
70 "staged_changes_file_deleted",
71 "staged_changes_modified_file",
72 "staged_delete_file_deleted",
73 "staged_delete_modified_file",
74 "staged_new_file",
75 "staged_new_file_deleted_file",
76 "staged_new_file_modified_file",
34dfea27 77
34dfea27
JP
78 "subdir/deleted_file",
79 "subdir/modified_file",
80 "subdir/new_file",
3af6b34a 81};
d8b903da 82
83static const unsigned int entry_statuses0[] = {
3af6b34a
JP
84 GIT_STATUS_WT_DELETED,
85 GIT_STATUS_WT_MODIFIED,
86 GIT_STATUS_WT_NEW,
87 GIT_STATUS_INDEX_MODIFIED,
88 GIT_STATUS_INDEX_MODIFIED | GIT_STATUS_WT_DELETED,
89 GIT_STATUS_INDEX_MODIFIED | GIT_STATUS_WT_MODIFIED,
90 GIT_STATUS_INDEX_DELETED,
91 GIT_STATUS_INDEX_DELETED | GIT_STATUS_WT_NEW,
92 GIT_STATUS_INDEX_NEW,
93 GIT_STATUS_INDEX_NEW | GIT_STATUS_WT_DELETED,
94 GIT_STATUS_INDEX_NEW | GIT_STATUS_WT_MODIFIED,
34dfea27 95
34dfea27
JP
96 GIT_STATUS_WT_DELETED,
97 GIT_STATUS_WT_MODIFIED,
98 GIT_STATUS_WT_NEW,
3af6b34a 99};
3af6b34a 100
d8b903da 101#define ENTRY_COUNT0 14
3af6b34a 102
bcba8460
VM
103struct status_entry_counts {
104 int wrong_status_flags_count;
105 int wrong_sorted_path;
106 int entry_count;
107 const unsigned int* expected_statuses;
108 const char** expected_paths;
109 int expected_entry_count;
110};
111
3af6b34a
JP
112static int status_cb(const char *path, unsigned int status_flags, void *payload)
113{
3af6b34a
JP
114 struct status_entry_counts *counts = (struct status_entry_counts *)payload;
115
8320001d 116 if (counts->entry_count >= counts->expected_entry_count) {
d8b903da 117 counts->wrong_status_flags_count++;
118 goto exit;
119 }
120
121 if (strcmp(path, counts->expected_paths[counts->entry_count])) {
122 counts->wrong_sorted_path++;
123 goto exit;
124 }
125
126 if (status_flags != counts->expected_statuses[counts->entry_count])
3af6b34a
JP
127 counts->wrong_status_flags_count++;
128
d8b903da 129exit:
130 counts->entry_count++;
3af6b34a
JP
131 return GIT_SUCCESS;
132}
133
134BEGIN_TEST(statuscb0, "test retrieving status for worktree of repository")
3af6b34a
JP
135 git_repository *repo;
136 struct status_entry_counts counts;
137
d4760a42 138 must_pass(copydir_recurs(STATUS_WORKDIR_FOLDER, TEMP_REPO_FOLDER));
139 must_pass(git_futils_mv_atomic(STATUS_REPOSITORY_TEMP_FOLDER, TEST_STD_REPO_FOLDER));
140 must_pass(git_repository_open(&repo, TEST_STD_REPO_FOLDER));
3af6b34a
JP
141
142 memset(&counts, 0x0, sizeof(struct status_entry_counts));
d8b903da 143 counts.expected_entry_count = ENTRY_COUNT0;
144 counts.expected_paths = entry_paths0;
145 counts.expected_statuses = entry_statuses0;
146
afdf8dcb 147 must_pass(git_status_foreach(repo, status_cb, &counts));
d8b903da 148 must_be_true(counts.entry_count == counts.expected_entry_count);
149 must_be_true(counts.wrong_status_flags_count == 0);
150 must_be_true(counts.wrong_sorted_path == 0);
151
152 git_repository_free(repo);
153
154 git_futils_rmdir_r(TEMP_REPO_FOLDER, 1);
155END_TEST
156
bcba8460
VM
157static int status_cb1(const char *path, unsigned int status_flags, void *payload)
158{
159 int *count = (int *)payload;;
160
161 GIT_UNUSED_ARG(path);
162 GIT_UNUSED_ARG(status_flags);
163
164 *count++;
165
166 return GIT_SUCCESS;
167}
168
d8b903da 169BEGIN_TEST(statuscb1, "test retrieving status for a worktree of an empty repository")
170 git_repository *repo;
171 int count = 0;
172
173 must_pass(copydir_recurs(EMPTY_REPOSITORY_FOLDER, TEST_STD_REPO_FOLDER));
174 must_pass(remove_placeholders(TEST_STD_REPO_FOLDER, "dummy-marker.txt"));
175 must_pass(git_repository_open(&repo, TEST_STD_REPO_FOLDER));
176
afdf8dcb 177 must_pass(git_status_foreach(repo, status_cb1, &count));
d8b903da 178 must_be_true(count == 0);
179
180 git_repository_free(repo);
181
182 git_futils_rmdir_r(TEMP_REPO_FOLDER, 1);
183END_TEST
184
185static const char *entry_paths2[] = {
186 "current_file",
187 "file_deleted",
188 "modified_file",
189 "staged_changes",
190 "staged_changes_file_deleted",
191 "staged_changes_modified_file",
192 "staged_delete_file_deleted",
193 "staged_delete_modified_file",
194 "staged_new_file",
195 "staged_new_file_deleted_file",
196 "staged_new_file_modified_file",
197 "subdir/current_file",
198 "subdir/deleted_file",
199 "subdir/modified_file",
200};
201
202static const unsigned int entry_statuses2[] = {
203 GIT_STATUS_WT_DELETED,
204 GIT_STATUS_WT_DELETED,
205 GIT_STATUS_WT_DELETED,
206 GIT_STATUS_WT_DELETED | GIT_STATUS_INDEX_MODIFIED,
207 GIT_STATUS_WT_DELETED | GIT_STATUS_INDEX_MODIFIED,
208 GIT_STATUS_WT_DELETED | GIT_STATUS_INDEX_MODIFIED,
209 GIT_STATUS_INDEX_DELETED,
210 GIT_STATUS_INDEX_DELETED,
211 GIT_STATUS_WT_DELETED | GIT_STATUS_INDEX_NEW,
212 GIT_STATUS_WT_DELETED | GIT_STATUS_INDEX_NEW,
213 GIT_STATUS_WT_DELETED | GIT_STATUS_INDEX_NEW,
214 GIT_STATUS_WT_DELETED,
215 GIT_STATUS_WT_DELETED,
216 GIT_STATUS_WT_DELETED,
217};
218
219#define ENTRY_COUNT2 14
220
221BEGIN_TEST(statuscb2, "test retrieving status for a purged worktree of an valid repository")
222 git_repository *repo;
223 struct status_entry_counts counts;
224
225 must_pass(copydir_recurs(STATUS_WORKDIR_FOLDER, TEMP_REPO_FOLDER));
226 must_pass(git_futils_mv_atomic(STATUS_REPOSITORY_TEMP_FOLDER, TEST_STD_REPO_FOLDER));
227 must_pass(git_repository_open(&repo, TEST_STD_REPO_FOLDER));
228
229 /* Purging the working */
230 must_pass(p_unlink(TEMP_REPO_FOLDER "current_file"));
231 must_pass(p_unlink(TEMP_REPO_FOLDER "modified_file"));
232 must_pass(p_unlink(TEMP_REPO_FOLDER "new_file"));
233 must_pass(p_unlink(TEMP_REPO_FOLDER "staged_changes"));
234 must_pass(p_unlink(TEMP_REPO_FOLDER "staged_changes_modified_file"));
235 must_pass(p_unlink(TEMP_REPO_FOLDER "staged_delete_modified_file"));
236 must_pass(p_unlink(TEMP_REPO_FOLDER "staged_new_file"));
237 must_pass(p_unlink(TEMP_REPO_FOLDER "staged_new_file_modified_file"));
238 must_pass(git_futils_rmdir_r(TEMP_REPO_FOLDER "subdir", 1));
239
240 memset(&counts, 0x0, sizeof(struct status_entry_counts));
241 counts.expected_entry_count = ENTRY_COUNT2;
242 counts.expected_paths = entry_paths2;
243 counts.expected_statuses = entry_statuses2;
244
afdf8dcb 245 must_pass(git_status_foreach(repo, status_cb, &counts));
d8b903da 246 must_be_true(counts.entry_count == counts.expected_entry_count);
247 must_be_true(counts.wrong_status_flags_count == 0);
248 must_be_true(counts.wrong_sorted_path == 0);
249
250 git_repository_free(repo);
251
252 git_futils_rmdir_r(TEMP_REPO_FOLDER, 1);
253END_TEST
254
255static const char *entry_paths3[] = {
256 ".HEADER",
257 "42-is-not-prime.sigh",
258 "README.md",
259 "current_file",
260 "current_file/current_file",
261 "current_file/modified_file",
262 "current_file/new_file",
263 "file_deleted",
264 "modified_file",
265 "new_file",
266 "staged_changes",
267 "staged_changes_file_deleted",
268 "staged_changes_modified_file",
269 "staged_delete_file_deleted",
270 "staged_delete_modified_file",
271 "staged_new_file",
272 "staged_new_file_deleted_file",
273 "staged_new_file_modified_file",
274 "subdir",
275 "subdir/current_file",
276 "subdir/deleted_file",
277 "subdir/modified_file",
278};
279
280static const unsigned int entry_statuses3[] = {
281 GIT_STATUS_WT_NEW,
282 GIT_STATUS_WT_NEW,
283 GIT_STATUS_WT_NEW,
284 GIT_STATUS_WT_DELETED,
285 GIT_STATUS_WT_NEW,
286 GIT_STATUS_WT_NEW,
287 GIT_STATUS_WT_NEW,
288 GIT_STATUS_WT_DELETED,
289 GIT_STATUS_WT_MODIFIED,
290 GIT_STATUS_WT_NEW,
291 GIT_STATUS_INDEX_MODIFIED,
292 GIT_STATUS_WT_DELETED | GIT_STATUS_INDEX_MODIFIED,
293 GIT_STATUS_WT_MODIFIED | GIT_STATUS_INDEX_MODIFIED,
294 GIT_STATUS_INDEX_DELETED,
295 GIT_STATUS_WT_NEW | GIT_STATUS_INDEX_DELETED,
296 GIT_STATUS_INDEX_NEW,
297 GIT_STATUS_WT_DELETED | GIT_STATUS_INDEX_NEW,
298 GIT_STATUS_WT_MODIFIED | GIT_STATUS_INDEX_NEW,
299 GIT_STATUS_WT_NEW,
300 GIT_STATUS_WT_DELETED,
301 GIT_STATUS_WT_DELETED,
302 GIT_STATUS_WT_DELETED,
303};
304
305#define ENTRY_COUNT3 22
306
307BEGIN_TEST(statuscb3, "test retrieving status for a worktree where a file and a subdir have been renamed and some files have been added")
308 git_repository *repo;
309 struct status_entry_counts counts;
310
311 must_pass(copydir_recurs(STATUS_WORKDIR_FOLDER, TEMP_REPO_FOLDER));
312 must_pass(git_futils_mv_atomic(STATUS_REPOSITORY_TEMP_FOLDER, TEST_STD_REPO_FOLDER));
313 must_pass(git_repository_open(&repo, TEST_STD_REPO_FOLDER));
314
315 must_pass(git_futils_mv_atomic(TEMP_REPO_FOLDER "current_file", TEMP_REPO_FOLDER "swap"));
316 must_pass(git_futils_mv_atomic(TEMP_REPO_FOLDER "subdir", TEMP_REPO_FOLDER "current_file"));
317 must_pass(git_futils_mv_atomic(TEMP_REPO_FOLDER "swap", TEMP_REPO_FOLDER "subdir"));
318
319 must_pass(file_create(TEMP_REPO_FOLDER ".HEADER", "dummy"));
320 must_pass(file_create(TEMP_REPO_FOLDER "42-is-not-prime.sigh", "dummy"));
321 must_pass(file_create(TEMP_REPO_FOLDER "README.md", "dummy"));
322
323 memset(&counts, 0x0, sizeof(struct status_entry_counts));
324 counts.expected_entry_count = ENTRY_COUNT3;
325 counts.expected_paths = entry_paths3;
326 counts.expected_statuses = entry_statuses3;
327
afdf8dcb 328 must_pass(git_status_foreach(repo, status_cb, &counts));
d8b903da 329 must_be_true(counts.entry_count == counts.expected_entry_count);
3af6b34a 330 must_be_true(counts.wrong_status_flags_count == 0);
d8b903da 331 must_be_true(counts.wrong_sorted_path == 0);
3af6b34a
JP
332
333 git_repository_free(repo);
334
d4760a42 335 git_futils_rmdir_r(TEMP_REPO_FOLDER, 1);
3af6b34a
JP
336END_TEST
337
20361b2f 338BEGIN_TEST(singlestatus0, "test retrieving status for single file")
20361b2f
JP
339 git_repository *repo;
340 unsigned int status_flags;
341 int i;
342
d4760a42 343 must_pass(copydir_recurs(STATUS_WORKDIR_FOLDER, TEMP_REPO_FOLDER));
344 must_pass(git_futils_mv_atomic(STATUS_REPOSITORY_TEMP_FOLDER, TEST_STD_REPO_FOLDER));
345 must_pass(git_repository_open(&repo, TEST_STD_REPO_FOLDER));
20361b2f 346
d8b903da 347 for (i = 0; i < ENTRY_COUNT0; ++i) {
348 must_pass(git_status_file(&status_flags, repo, entry_paths0[i]));
349 must_be_true(status_flags == entry_statuses0[i]);
20361b2f
JP
350 }
351
352 git_repository_free(repo);
353
d4760a42 354 git_futils_rmdir_r(TEMP_REPO_FOLDER, 1);
20361b2f
JP
355END_TEST
356
3b2a423c 357BEGIN_TEST(singlestatus1, "test retrieving status for nonexistent file")
3b2a423c
JP
358 git_repository *repo;
359 unsigned int status_flags;
360 int error;
361
d4760a42 362 must_pass(copydir_recurs(STATUS_WORKDIR_FOLDER, TEMP_REPO_FOLDER));
363 must_pass(git_futils_mv_atomic(STATUS_REPOSITORY_TEMP_FOLDER, TEST_STD_REPO_FOLDER));
364 must_pass(git_repository_open(&repo, TEST_STD_REPO_FOLDER));
3b2a423c
JP
365
366 // "nonexistent" does not exist in HEAD, Index or the worktree
367 error = git_status_file(&status_flags, repo, "nonexistent");
368 must_be_true(error == GIT_ENOTFOUND);
369
370 git_repository_free(repo);
371
d4760a42 372 git_futils_rmdir_r(TEMP_REPO_FOLDER, 1);
3b2a423c
JP
373END_TEST
374
56453d34 375BEGIN_TEST(singlestatus2, "test retrieving status for a non existent file in an empty repository")
376 git_repository *repo;
377 unsigned int status_flags;
378 int error;
379
380 must_pass(copydir_recurs(EMPTY_REPOSITORY_FOLDER, TEST_STD_REPO_FOLDER));
381 must_pass(remove_placeholders(TEST_STD_REPO_FOLDER, "dummy-marker.txt"));
382 must_pass(git_repository_open(&repo, TEST_STD_REPO_FOLDER));
383
384 error = git_status_file(&status_flags, repo, "nonexistent");
385 must_be_true(error == GIT_ENOTFOUND);
386
387 git_repository_free(repo);
388
389 git_futils_rmdir_r(TEMP_REPO_FOLDER, 1);
390END_TEST
391
392BEGIN_TEST(singlestatus3, "test retrieving status for a new file in an empty repository")
393 git_repository *repo;
394 unsigned int status_flags;
395 char file_path[GIT_PATH_MAX];
396 char filename[] = "new_file";
397 int fd;
398
399 must_pass(copydir_recurs(EMPTY_REPOSITORY_FOLDER, TEST_STD_REPO_FOLDER));
400 must_pass(remove_placeholders(TEST_STD_REPO_FOLDER, "dummy-marker.txt"));
401
402 git_path_join(file_path, TEMP_REPO_FOLDER, filename);
403 fd = p_creat(file_path, 0644);
404 must_pass(fd);
405 must_pass(p_write(fd, "new_file\n", 9));
406 must_pass(p_close(fd));
407
408 must_pass(git_repository_open(&repo, TEST_STD_REPO_FOLDER));
409
410 must_pass(git_status_file(&status_flags, repo, filename));
411 must_be_true(status_flags == GIT_STATUS_WT_NEW);
412
413 git_repository_free(repo);
414
415 git_futils_rmdir_r(TEMP_REPO_FOLDER, 1);
416END_TEST
417
418BEGIN_TEST(singlestatus4, "can't determine the status for a folder")
419 git_repository *repo;
420 unsigned int status_flags;
421 int error;
422
423 must_pass(copydir_recurs(STATUS_WORKDIR_FOLDER, TEMP_REPO_FOLDER));
424 must_pass(git_futils_mv_atomic(STATUS_REPOSITORY_TEMP_FOLDER, TEST_STD_REPO_FOLDER));
425 must_pass(git_repository_open(&repo, TEST_STD_REPO_FOLDER));
426
427 error = git_status_file(&status_flags, repo, "subdir");
428 must_be_true(error == GIT_EINVALIDPATH);
429
430 git_repository_free(repo);
431
432 git_futils_rmdir_r(TEMP_REPO_FOLDER, 1);
433END_TEST
434
205166d2
JP
435BEGIN_SUITE(status)
436 ADD_TEST(file0);
d4760a42 437
3af6b34a 438 ADD_TEST(statuscb0);
d8b903da 439 ADD_TEST(statuscb1);
440 ADD_TEST(statuscb2);
441 ADD_TEST(statuscb3);
d4760a42 442
20361b2f 443 ADD_TEST(singlestatus0);
3b2a423c 444 ADD_TEST(singlestatus1);
56453d34 445 ADD_TEST(singlestatus2);
446 ADD_TEST(singlestatus3);
447 ADD_TEST(singlestatus4);
bcba8460 448END_SUITE