summaryrefslogtreecommitdiff
path: root/tests/libgit2/index/filemodes.c
diff options
context:
space:
mode:
Diffstat (limited to 'tests/libgit2/index/filemodes.c')
-rw-r--r--tests/libgit2/index/filemodes.c319
1 files changed, 319 insertions, 0 deletions
diff --git a/tests/libgit2/index/filemodes.c b/tests/libgit2/index/filemodes.c
new file mode 100644
index 000000000..1ab8a9a7f
--- /dev/null
+++ b/tests/libgit2/index/filemodes.c
@@ -0,0 +1,319 @@
+#include "clar_libgit2.h"
+#include "posix.h"
+#include "index.h"
+
+static git_repository *g_repo = NULL;
+
+void test_index_filemodes__initialize(void)
+{
+ g_repo = cl_git_sandbox_init("filemodes");
+}
+
+void test_index_filemodes__cleanup(void)
+{
+ cl_git_sandbox_cleanup();
+}
+
+void test_index_filemodes__read(void)
+{
+ git_index *index;
+ unsigned int i;
+ static bool expected[6] = { 0, 1, 0, 1, 0, 1 };
+
+ cl_git_pass(git_repository_index(&index, g_repo));
+ cl_assert_equal_i(6, (int)git_index_entrycount(index));
+
+ for (i = 0; i < 6; ++i) {
+ const git_index_entry *entry = git_index_get_byindex(index, i);
+ cl_assert(entry != NULL);
+ cl_assert(((entry->mode & 0100) ? 1 : 0) == expected[i]);
+ }
+
+ git_index_free(index);
+}
+
+static void replace_file_with_mode(
+ const char *filename, const char *backup, unsigned int create_mode)
+{
+ git_str path = GIT_STR_INIT, content = GIT_STR_INIT;
+
+ cl_git_pass(git_str_joinpath(&path, "filemodes", filename));
+ cl_git_pass(git_str_printf(&content, "%s as %08u (%d)",
+ filename, create_mode, rand()));
+
+ cl_git_pass(p_rename(path.ptr, backup));
+ cl_git_write2file(
+ path.ptr, content.ptr, content.size,
+ O_WRONLY|O_CREAT|O_TRUNC, create_mode);
+
+ git_str_dispose(&path);
+ git_str_dispose(&content);
+}
+
+#define add_and_check_mode(I,F,X) add_and_check_mode_(I,F,X,__FILE__,__func__,__LINE__)
+
+static void add_and_check_mode_(
+ git_index *index, const char *filename, unsigned int expect_mode,
+ const char *file, const char *func, int line)
+{
+ size_t pos;
+ const git_index_entry *entry;
+
+ cl_git_pass(git_index_add_bypath(index, filename));
+
+ clar__assert(!git_index_find(&pos, index, filename),
+ file, func, line, "Cannot find index entry", NULL, 1);
+
+ entry = git_index_get_byindex(index, pos);
+
+ clar__assert_equal(file, func, line, "Expected mode does not match index",
+ 1, "%07o", (unsigned int)entry->mode, (unsigned int)expect_mode);
+}
+
+void test_index_filemodes__untrusted(void)
+{
+ git_index *index;
+
+ cl_repo_set_bool(g_repo, "core.filemode", false);
+
+ cl_git_pass(git_repository_index(&index, g_repo));
+ cl_assert((git_index_caps(index) & GIT_INDEX_CAPABILITY_NO_FILEMODE) != 0);
+
+ /* 1 - add 0644 over existing 0644 -> expect 0644 */
+ replace_file_with_mode("exec_off", "filemodes/exec_off.0", 0644);
+ add_and_check_mode(index, "exec_off", GIT_FILEMODE_BLOB);
+
+ /* 2 - add 0644 over existing 0755 -> expect 0755 */
+ replace_file_with_mode("exec_on", "filemodes/exec_on.0", 0644);
+ add_and_check_mode(index, "exec_on", GIT_FILEMODE_BLOB_EXECUTABLE);
+
+ /* 3 - add 0755 over existing 0644 -> expect 0644 */
+ replace_file_with_mode("exec_off", "filemodes/exec_off.1", 0755);
+ add_and_check_mode(index, "exec_off", GIT_FILEMODE_BLOB);
+
+ /* 4 - add 0755 over existing 0755 -> expect 0755 */
+ replace_file_with_mode("exec_on", "filemodes/exec_on.1", 0755);
+ add_and_check_mode(index, "exec_on", GIT_FILEMODE_BLOB_EXECUTABLE);
+
+ /* 5 - add new 0644 -> expect 0644 */
+ cl_git_write2file("filemodes/new_off", "blah", 0,
+ O_WRONLY | O_CREAT | O_TRUNC, 0644);
+ add_and_check_mode(index, "new_off", GIT_FILEMODE_BLOB);
+
+ /* 6 - add new 0755 -> expect 0644 if core.filemode == false */
+ cl_git_write2file("filemodes/new_on", "blah", 0,
+ O_WRONLY | O_CREAT | O_TRUNC, 0755);
+ add_and_check_mode(index, "new_on", GIT_FILEMODE_BLOB);
+
+ git_index_free(index);
+}
+
+void test_index_filemodes__trusted(void)
+{
+ git_index *index;
+
+ /* Only run these tests on platforms where I can actually
+ * chmod a file and get the stat results I expect!
+ */
+ if (!cl_is_chmod_supported())
+ return;
+
+ cl_repo_set_bool(g_repo, "core.filemode", true);
+
+ cl_git_pass(git_repository_index(&index, g_repo));
+ cl_assert((git_index_caps(index) & GIT_INDEX_CAPABILITY_NO_FILEMODE) == 0);
+
+ /* 1 - add 0644 over existing 0644 -> expect 0644 */
+ replace_file_with_mode("exec_off", "filemodes/exec_off.0", 0644);
+ add_and_check_mode(index, "exec_off", GIT_FILEMODE_BLOB);
+
+ /* 2 - add 0644 over existing 0755 -> expect 0644 */
+ replace_file_with_mode("exec_on", "filemodes/exec_on.0", 0644);
+ add_and_check_mode(index, "exec_on", GIT_FILEMODE_BLOB);
+
+ /* 3 - add 0755 over existing 0644 -> expect 0755 */
+ replace_file_with_mode("exec_off", "filemodes/exec_off.1", 0755);
+ add_and_check_mode(index, "exec_off", GIT_FILEMODE_BLOB_EXECUTABLE);
+
+ /* 4 - add 0755 over existing 0755 -> expect 0755 */
+ replace_file_with_mode("exec_on", "filemodes/exec_on.1", 0755);
+ add_and_check_mode(index, "exec_on", GIT_FILEMODE_BLOB_EXECUTABLE);
+
+ /* 5 - add new 0644 -> expect 0644 */
+ cl_git_write2file("filemodes/new_off", "blah", 0,
+ O_WRONLY | O_CREAT | O_TRUNC, 0644);
+ add_and_check_mode(index, "new_off", GIT_FILEMODE_BLOB);
+
+ /* 6 - add 0755 -> expect 0755 */
+ cl_git_write2file("filemodes/new_on", "blah", 0,
+ O_WRONLY | O_CREAT | O_TRUNC, 0755);
+ add_and_check_mode(index, "new_on", GIT_FILEMODE_BLOB_EXECUTABLE);
+
+ git_index_free(index);
+}
+
+#define add_entry_and_check_mode(I,FF,X) add_entry_and_check_mode_(I,FF,X,__FILE__,__func__,__LINE__)
+
+static void add_entry_and_check_mode_(
+ git_index *index, bool from_file, git_filemode_t mode,
+ const char *file, const char *func, int line)
+{
+ size_t pos;
+ const git_index_entry* entry;
+ git_index_entry new_entry;
+
+ /* If old_filename exists, we copy that to the new file, and test
+ * git_index_add(), otherwise create a new entry testing git_index_add_from_buffer
+ */
+ if (from_file)
+ {
+ clar__assert(!git_index_find(&pos, index, "exec_off"),
+ file, func, line, "Cannot find original index entry", NULL, 1);
+
+ entry = git_index_get_byindex(index, pos);
+
+ memcpy(&new_entry, entry, sizeof(new_entry));
+ }
+ else
+ memset(&new_entry, 0x0, sizeof(git_index_entry));
+
+ new_entry.path = "filemodes/explicit_test";
+ new_entry.mode = mode;
+
+ if (from_file)
+ {
+ clar__assert(!git_index_add(index, &new_entry),
+ file, func, line, "Cannot add index entry", NULL, 1);
+ }
+ else
+ {
+ const char *content = "hey there\n";
+ clar__assert(!git_index_add_from_buffer(index, &new_entry, content, strlen(content)),
+ file, func, line, "Cannot add index entry from buffer", NULL, 1);
+ }
+
+ clar__assert(!git_index_find(&pos, index, "filemodes/explicit_test"),
+ file, func, line, "Cannot find new index entry", NULL, 1);
+
+ entry = git_index_get_byindex(index, pos);
+
+ clar__assert_equal(file, func, line, "Expected mode does not match index",
+ 1, "%07o", (unsigned int)entry->mode, (unsigned int)mode);
+}
+
+void test_index_filemodes__explicit(void)
+{
+ git_index *index;
+
+ /* These tests should run and work everywhere, as the filemode is
+ * given explicitly to git_index_add or git_index_add_from_buffer
+ */
+ cl_repo_set_bool(g_repo, "core.filemode", false);
+
+ cl_git_pass(git_repository_index(&index, g_repo));
+
+ /* Each of these tests keeps overwriting the same file in the index. */
+ /* 1 - add new 0644 entry */
+ add_entry_and_check_mode(index, true, GIT_FILEMODE_BLOB);
+
+ /* 2 - add 0755 entry over existing 0644 */
+ add_entry_and_check_mode(index, true, GIT_FILEMODE_BLOB_EXECUTABLE);
+
+ /* 3 - add 0644 entry over existing 0755 */
+ add_entry_and_check_mode(index, true, GIT_FILEMODE_BLOB);
+
+ /* 4 - add 0755 buffer entry over existing 0644 */
+ add_entry_and_check_mode(index, false, GIT_FILEMODE_BLOB_EXECUTABLE);
+
+ /* 5 - add 0644 buffer entry over existing 0755 */
+ add_entry_and_check_mode(index, false, GIT_FILEMODE_BLOB);
+
+ git_index_free(index);
+}
+
+void test_index_filemodes__invalid(void)
+{
+ git_index *index;
+ git_index_entry entry;
+ const git_index_entry *dummy;
+
+ cl_git_pass(git_repository_index(&index, g_repo));
+
+ /* add a dummy file so that we have a valid id */
+ cl_git_mkfile("./filemodes/dummy-file.txt", "new-file\n");
+ cl_git_pass(git_index_add_bypath(index, "dummy-file.txt"));
+ cl_assert((dummy = git_index_get_bypath(index, "dummy-file.txt", 0)));
+
+ GIT_INDEX_ENTRY_STAGE_SET(&entry, 0);
+ entry.path = "foo";
+ entry.mode = GIT_OBJECT_BLOB;
+ git_oid_cpy(&entry.id, &dummy->id);
+ cl_git_fail(git_index_add(index, &entry));
+
+ entry.mode = GIT_FILEMODE_BLOB;
+ cl_git_pass(git_index_add(index, &entry));
+
+ git_index_free(index);
+}
+
+void test_index_filemodes__frombuffer_requires_files(void)
+{
+ git_index *index;
+ git_index_entry new_entry;
+ const git_index_entry *ret_entry;
+ const char *content = "hey there\n";
+
+ memset(&new_entry, 0, sizeof(new_entry));
+ cl_git_pass(git_repository_index(&index, g_repo));
+
+ /* regular blob */
+ new_entry.path = "dummy-file.txt";
+ new_entry.mode = GIT_FILEMODE_BLOB;
+
+ cl_git_pass(git_index_add_from_buffer(index,
+ &new_entry, content, strlen(content)));
+
+ cl_assert((ret_entry = git_index_get_bypath(index, "dummy-file.txt", 0)));
+ cl_assert_equal_s("dummy-file.txt", ret_entry->path);
+ cl_assert_equal_i(GIT_FILEMODE_BLOB, ret_entry->mode);
+
+ /* executable blob */
+ new_entry.path = "dummy-file.txt";
+ new_entry.mode = GIT_FILEMODE_BLOB_EXECUTABLE;
+
+ cl_git_pass(git_index_add_from_buffer(index,
+ &new_entry, content, strlen(content)));
+
+ cl_assert((ret_entry = git_index_get_bypath(index, "dummy-file.txt", 0)));
+ cl_assert_equal_s("dummy-file.txt", ret_entry->path);
+ cl_assert_equal_i(GIT_FILEMODE_BLOB_EXECUTABLE, ret_entry->mode);
+
+ /* links are also acceptable */
+ new_entry.path = "dummy-link.txt";
+ new_entry.mode = GIT_FILEMODE_LINK;
+
+ cl_git_pass(git_index_add_from_buffer(index,
+ &new_entry, content, strlen(content)));
+
+ cl_assert((ret_entry = git_index_get_bypath(index, "dummy-link.txt", 0)));
+ cl_assert_equal_s("dummy-link.txt", ret_entry->path);
+ cl_assert_equal_i(GIT_FILEMODE_LINK, ret_entry->mode);
+
+ /* trees are rejected */
+ new_entry.path = "invalid_mode.txt";
+ new_entry.mode = GIT_FILEMODE_TREE;
+
+ cl_git_fail(git_index_add_from_buffer(index,
+ &new_entry, content, strlen(content)));
+ cl_assert_equal_p(NULL, git_index_get_bypath(index, "invalid_mode.txt", 0));
+
+ /* submodules are rejected */
+ new_entry.path = "invalid_mode.txt";
+ new_entry.mode = GIT_FILEMODE_COMMIT;
+
+ cl_git_fail(git_index_add_from_buffer(index,
+ &new_entry, content, strlen(content)));
+ cl_assert_equal_p(NULL, git_index_get_bypath(index, "invalid_mode.txt", 0));
+
+ git_index_free(index);
+}