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.
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.)
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.
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.
27 #include "test_helpers.h"
29 #include "git2/status.h"
31 static const char *test_blob_oid
= "d4fa8600b4f37d7516bef4816ae2c64dbf029e3a";
33 #define STATUS_WORKDIR_FOLDER TEST_RESOURCES "/status/"
34 #define STATUS_REPOSITORY_TEMP_FOLDER TEMP_REPO_FOLDER ".gitted/"
36 static int file_create(const char *filename
, const char *content
)
40 fd
= p_creat(filename
, 0644);
43 if (p_write(fd
, content
, strlen(content
)) != 0)
51 BEGIN_TEST(file0
, "test retrieving OID from a file apart from the ODB")
52 git_oid expected_id
, actual_id
;
53 char filename
[] = "new_file";
55 must_pass(file_create(filename
, "new_file\n\0"));
57 must_pass(git_odb_hashfile(&actual_id
, filename
, GIT_OBJ_BLOB
));
59 must_pass(git_oid_fromstr(&expected_id
, test_blob_oid
));
60 must_be_true(git_oid_cmp(&expected_id
, &actual_id
) == 0);
62 must_pass(p_unlink(filename
));
65 static const char *entry_paths0
[] = {
70 "staged_changes_file_deleted",
71 "staged_changes_modified_file",
72 "staged_delete_file_deleted",
73 "staged_delete_modified_file",
75 "staged_new_file_deleted_file",
76 "staged_new_file_modified_file",
78 "subdir/deleted_file",
79 "subdir/modified_file",
83 static const unsigned int entry_statuses0
[] = {
84 GIT_STATUS_WT_DELETED
,
85 GIT_STATUS_WT_MODIFIED
,
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
,
93 GIT_STATUS_INDEX_NEW
| GIT_STATUS_WT_DELETED
,
94 GIT_STATUS_INDEX_NEW
| GIT_STATUS_WT_MODIFIED
,
96 GIT_STATUS_WT_DELETED
,
97 GIT_STATUS_WT_MODIFIED
,
101 #define ENTRY_COUNT0 14
103 struct status_entry_counts
{
104 int wrong_status_flags_count
;
105 int wrong_sorted_path
;
107 const unsigned int* expected_statuses
;
108 const char** expected_paths
;
109 int expected_entry_count
;
112 static int status_cb(const char *path
, unsigned int status_flags
, void *payload
)
114 struct status_entry_counts
*counts
= (struct status_entry_counts
*)payload
;
116 if (counts
->entry_count
>= counts
->expected_entry_count
) {
117 counts
->wrong_status_flags_count
++;
121 if (strcmp(path
, counts
->expected_paths
[counts
->entry_count
])) {
122 counts
->wrong_sorted_path
++;
126 if (status_flags
!= counts
->expected_statuses
[counts
->entry_count
])
127 counts
->wrong_status_flags_count
++;
130 counts
->entry_count
++;
134 BEGIN_TEST(statuscb0
, "test retrieving status for worktree of repository")
135 git_repository
*repo
;
136 struct status_entry_counts counts
;
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
));
142 memset(&counts
, 0x0, sizeof(struct status_entry_counts
));
143 counts
.expected_entry_count
= ENTRY_COUNT0
;
144 counts
.expected_paths
= entry_paths0
;
145 counts
.expected_statuses
= entry_statuses0
;
147 must_pass(git_status_foreach(repo
, status_cb
, &counts
));
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);
152 git_repository_free(repo
);
154 git_futils_rmdir_r(TEMP_REPO_FOLDER
, 1);
157 static int status_cb1(const char *path
, unsigned int status_flags
, void *payload
)
159 int *count
= (int *)payload
;;
161 GIT_UNUSED_ARG(path
);
162 GIT_UNUSED_ARG(status_flags
);
169 BEGIN_TEST(statuscb1
, "test retrieving status for a worktree of an empty repository")
170 git_repository
*repo
;
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
));
177 must_pass(git_status_foreach(repo
, status_cb1
, &count
));
178 must_be_true(count
== 0);
180 git_repository_free(repo
);
182 git_futils_rmdir_r(TEMP_REPO_FOLDER
, 1);
185 static const char *entry_paths2
[] = {
190 "staged_changes_file_deleted",
191 "staged_changes_modified_file",
192 "staged_delete_file_deleted",
193 "staged_delete_modified_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",
202 static 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
,
219 #define ENTRY_COUNT2 14
221 BEGIN_TEST(statuscb2
, "test retrieving status for a purged worktree of an valid repository")
222 git_repository
*repo
;
223 struct status_entry_counts counts
;
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
));
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));
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
;
245 must_pass(git_status_foreach(repo
, status_cb
, &counts
));
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);
250 git_repository_free(repo
);
252 git_futils_rmdir_r(TEMP_REPO_FOLDER
, 1);
255 static const char *entry_paths3
[] = {
257 "42-is-not-prime.sigh",
260 "current_file/current_file",
261 "current_file/modified_file",
262 "current_file/new_file",
267 "staged_changes_file_deleted",
268 "staged_changes_modified_file",
269 "staged_delete_file_deleted",
270 "staged_delete_modified_file",
272 "staged_new_file_deleted_file",
273 "staged_new_file_modified_file",
275 "subdir/current_file",
276 "subdir/deleted_file",
277 "subdir/modified_file",
280 static const unsigned int entry_statuses3
[] = {
284 GIT_STATUS_WT_DELETED
,
288 GIT_STATUS_WT_DELETED
,
289 GIT_STATUS_WT_MODIFIED
,
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
,
300 GIT_STATUS_WT_DELETED
,
301 GIT_STATUS_WT_DELETED
,
302 GIT_STATUS_WT_DELETED
,
305 #define ENTRY_COUNT3 22
307 BEGIN_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
;
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
));
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"));
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"));
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
;
328 must_pass(git_status_foreach(repo
, status_cb
, &counts
));
329 must_be_true(counts
.entry_count
== counts
.expected_entry_count
);
330 must_be_true(counts
.wrong_status_flags_count
== 0);
331 must_be_true(counts
.wrong_sorted_path
== 0);
333 git_repository_free(repo
);
335 git_futils_rmdir_r(TEMP_REPO_FOLDER
, 1);
338 BEGIN_TEST(singlestatus0
, "test retrieving status for single file")
339 git_repository
*repo
;
340 unsigned int status_flags
;
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
));
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
]);
352 git_repository_free(repo
);
354 git_futils_rmdir_r(TEMP_REPO_FOLDER
, 1);
357 BEGIN_TEST(singlestatus1
, "test retrieving status for nonexistent file")
358 git_repository
*repo
;
359 unsigned int status_flags
;
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
));
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
);
370 git_repository_free(repo
);
372 git_futils_rmdir_r(TEMP_REPO_FOLDER
, 1);
375 BEGIN_TEST(singlestatus2
, "test retrieving status for a non existent file in an empty repository")
376 git_repository
*repo
;
377 unsigned int status_flags
;
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
));
384 error
= git_status_file(&status_flags
, repo
, "nonexistent");
385 must_be_true(error
== GIT_ENOTFOUND
);
387 git_repository_free(repo
);
389 git_futils_rmdir_r(TEMP_REPO_FOLDER
, 1);
392 BEGIN_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";
399 must_pass(copydir_recurs(EMPTY_REPOSITORY_FOLDER
, TEST_STD_REPO_FOLDER
));
400 must_pass(remove_placeholders(TEST_STD_REPO_FOLDER
, "dummy-marker.txt"));
402 git_path_join(file_path
, TEMP_REPO_FOLDER
, filename
);
403 fd
= p_creat(file_path
, 0644);
405 must_pass(p_write(fd
, "new_file\n", 9));
406 must_pass(p_close(fd
));
408 must_pass(git_repository_open(&repo
, TEST_STD_REPO_FOLDER
));
410 must_pass(git_status_file(&status_flags
, repo
, filename
));
411 must_be_true(status_flags
== GIT_STATUS_WT_NEW
);
413 git_repository_free(repo
);
415 git_futils_rmdir_r(TEMP_REPO_FOLDER
, 1);
418 BEGIN_TEST(singlestatus4
, "can't determine the status for a folder")
419 git_repository
*repo
;
420 unsigned int status_flags
;
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
));
427 error
= git_status_file(&status_flags
, repo
, "subdir");
428 must_be_true(error
== GIT_EINVALIDPATH
);
430 git_repository_free(repo
);
432 git_futils_rmdir_r(TEMP_REPO_FOLDER
, 1);
443 ADD_TEST(singlestatus0
);
444 ADD_TEST(singlestatus1
);
445 ADD_TEST(singlestatus2
);
446 ADD_TEST(singlestatus3
);
447 ADD_TEST(singlestatus4
);