Initial commit

This commit is contained in:
jiapengyu
2026-07-27 13:37:48 +08:00
commit ecba71e2a5
39123 changed files with 5989154 additions and 0 deletions
+118
View File
@@ -0,0 +1,118 @@
#include "clar_libgit2.h"
#include "tree.h"
static git_repository *repo;
static const char *blob_oid = "3d0970ec547fc41ef8a5882dde99c6adce65b021";
static const char *tree_oid = "1b05fdaa881ee45b48cbaa5e9b037d667a47745e";
void test_object_tree_attributes__initialize(void)
{
repo = cl_git_sandbox_init("deprecated-mode.git");
}
void test_object_tree_attributes__cleanup(void)
{
cl_git_sandbox_cleanup();
}
void test_object_tree_attributes__ensure_correctness_of_attributes_on_insertion(void)
{
git_treebuilder *builder;
git_oid oid;
cl_git_pass(git_oid_fromstr(&oid, blob_oid));
cl_git_pass(git_treebuilder_new(&builder, repo, NULL));
cl_git_fail(git_treebuilder_insert(NULL, builder, "one.txt", &oid, (git_filemode_t)0777777));
cl_git_fail(git_treebuilder_insert(NULL, builder, "one.txt", &oid, (git_filemode_t)0100666));
cl_git_fail(git_treebuilder_insert(NULL, builder, "one.txt", &oid, (git_filemode_t)0000001));
git_treebuilder_free(builder);
}
void test_object_tree_attributes__group_writable_tree_entries_created_with_an_antique_git_version_can_still_be_accessed(void)
{
git_oid tid;
git_tree *tree;
const git_tree_entry *entry;
cl_git_pass(git_oid_fromstr(&tid, tree_oid));
cl_git_pass(git_tree_lookup(&tree, repo, &tid));
entry = git_tree_entry_byname(tree, "old_mode.txt");
cl_assert_equal_i(
GIT_FILEMODE_BLOB,
git_tree_entry_filemode(entry));
git_tree_free(tree);
}
void test_object_tree_attributes__treebuilder_reject_invalid_filemode(void)
{
git_treebuilder *builder;
git_oid bid;
const git_tree_entry *entry;
cl_git_pass(git_oid_fromstr(&bid, blob_oid));
cl_git_pass(git_treebuilder_new(&builder, repo, NULL));
cl_git_fail(git_treebuilder_insert(
&entry,
builder,
"normalized.txt",
&bid,
GIT_FILEMODE_BLOB_GROUP_WRITABLE));
git_treebuilder_free(builder);
}
void test_object_tree_attributes__normalize_attributes_when_creating_a_tree_from_an_existing_one(void)
{
git_treebuilder *builder;
git_oid tid, tid2;
git_tree *tree;
const git_tree_entry *entry;
cl_git_pass(git_oid_fromstr(&tid, tree_oid));
cl_git_pass(git_tree_lookup(&tree, repo, &tid));
cl_git_pass(git_treebuilder_new(&builder, repo, tree));
entry = git_treebuilder_get(builder, "old_mode.txt");
cl_assert(entry != NULL);
cl_assert_equal_i(
GIT_FILEMODE_BLOB,
git_tree_entry_filemode(entry));
cl_git_pass(git_treebuilder_write(&tid2, builder));
git_treebuilder_free(builder);
git_tree_free(tree);
cl_git_pass(git_tree_lookup(&tree, repo, &tid2));
entry = git_tree_entry_byname(tree, "old_mode.txt");
cl_assert(entry != NULL);
cl_assert_equal_i(
GIT_FILEMODE_BLOB,
git_tree_entry_filemode(entry));
git_tree_free(tree);
}
void test_object_tree_attributes__normalize_600(void)
{
git_oid id;
git_tree *tree;
const git_tree_entry *entry;
git_oid_fromstr(&id, "0810fb7818088ff5ac41ee49199b51473b1bd6c7");
cl_git_pass(git_tree_lookup(&tree, repo, &id));
entry = git_tree_entry_byname(tree, "ListaTeste.xml");
cl_assert_equal_i(git_tree_entry_filemode(entry), GIT_FILEMODE_BLOB);
cl_assert_equal_i(git_tree_entry_filemode_raw(entry), 0100600);
git_tree_free(tree);
}
@@ -0,0 +1,157 @@
#include "clar_libgit2.h"
#include "tree.h"
static git_repository *_repo;
void test_object_tree_duplicateentries__initialize(void) {
_repo = cl_git_sandbox_init("testrepo");
}
void test_object_tree_duplicateentries__cleanup(void) {
cl_git_sandbox_cleanup();
}
/*
* $ git show --format=raw refs/heads/dir
* commit 144344043ba4d4a405da03de3844aa829ae8be0e
* tree d52a8fe84ceedf260afe4f0287bbfca04a117e83
* parent cf80f8de9f1185bf3a05f993f6121880dd0cfbc9
* author Ben Straub <bstraub@github.com> 1343755506 -0700
* committer Ben Straub <bstraub@github.com> 1343755506 -0700
*
* Change a file mode
*
* diff --git a/a/b.txt b/a/b.txt
* old mode 100644
* new mode 100755
*
* $ git ls-tree d52a8fe84ceedf260afe4f0287bbfca04a117e83
* 100644 blob a8233120f6ad708f843d861ce2b7228ec4e3dec6 README
* 040000 tree 4e0883eeeeebc1fb1735161cea82f7cb5fab7e63 a
* 100644 blob 45b983be36b73c0788dc9cbcb76cbb80fc7bb057 branch_file.txt
* 100644 blob a71586c1dfe8a71c6cbf6c129f404c5642ff31bd new.txt
*/
static void tree_checker(
git_oid *tid,
const char *expected_sha,
git_filemode_t expected_filemode)
{
git_tree *tree;
const git_tree_entry *entry;
git_oid oid;
cl_git_pass(git_tree_lookup(&tree, _repo, tid));
cl_assert_equal_i(1, (int)git_tree_entrycount(tree));
entry = git_tree_entry_byindex(tree, 0);
cl_git_pass(git_oid_fromstr(&oid, expected_sha));
cl_assert_equal_i(0, git_oid_cmp(&oid, git_tree_entry_id(entry)));
cl_assert_equal_i(expected_filemode, git_tree_entry_filemode(entry));
git_tree_free(tree);
}
static void tree_creator(git_oid *out, void (*fn)(git_treebuilder *))
{
git_treebuilder *builder;
cl_git_pass(git_treebuilder_new(&builder, _repo, NULL));
fn(builder);
cl_git_pass(git_treebuilder_write(out, builder));
git_treebuilder_free(builder);
}
static void two_blobs(git_treebuilder *bld)
{
git_oid oid;
const git_tree_entry *entry;
cl_git_pass(git_oid_fromstr(&oid,
"a8233120f6ad708f843d861ce2b7228ec4e3dec6")); /* blob oid (README) */
cl_git_pass(git_treebuilder_insert(
&entry, bld, "duplicate", &oid,
GIT_FILEMODE_BLOB));
cl_git_pass(git_oid_fromstr(&oid,
"a71586c1dfe8a71c6cbf6c129f404c5642ff31bd")); /* blob oid (new.txt) */
cl_git_pass(git_treebuilder_insert(
&entry, bld, "duplicate", &oid,
GIT_FILEMODE_BLOB));
}
static void one_blob_and_one_tree(git_treebuilder *bld)
{
git_oid oid;
const git_tree_entry *entry;
cl_git_pass(git_oid_fromstr(&oid,
"a8233120f6ad708f843d861ce2b7228ec4e3dec6")); /* blob oid (README) */
cl_git_pass(git_treebuilder_insert(
&entry, bld, "duplicate", &oid,
GIT_FILEMODE_BLOB));
cl_git_pass(git_oid_fromstr(&oid,
"4e0883eeeeebc1fb1735161cea82f7cb5fab7e63")); /* tree oid (a) */
cl_git_pass(git_treebuilder_insert(
&entry, bld, "duplicate", &oid,
GIT_FILEMODE_TREE));
}
void test_object_tree_duplicateentries__cannot_create_a_duplicate_entry_through_the_treebuilder(void)
{
git_oid tid;
tree_creator(&tid, two_blobs);
tree_checker(&tid, "a71586c1dfe8a71c6cbf6c129f404c5642ff31bd", GIT_FILEMODE_BLOB);
tree_creator(&tid, one_blob_and_one_tree);
tree_checker(&tid, "4e0883eeeeebc1fb1735161cea82f7cb5fab7e63", GIT_FILEMODE_TREE);
}
static void add_fake_conflicts(git_index *index)
{
git_index_entry ancestor_entry, our_entry, their_entry;
memset(&ancestor_entry, 0x0, sizeof(git_index_entry));
memset(&our_entry, 0x0, sizeof(git_index_entry));
memset(&their_entry, 0x0, sizeof(git_index_entry));
ancestor_entry.path = "duplicate";
ancestor_entry.mode = GIT_FILEMODE_BLOB;
GIT_INDEX_ENTRY_STAGE_SET(&ancestor_entry, 1);
git_oid_fromstr(&ancestor_entry.id, "a8233120f6ad708f843d861ce2b7228ec4e3dec6");
our_entry.path = "duplicate";
our_entry.mode = GIT_FILEMODE_BLOB;
GIT_INDEX_ENTRY_STAGE_SET(&our_entry, 2);
git_oid_fromstr(&our_entry.id, "45b983be36b73c0788dc9cbcb76cbb80fc7bb057");
their_entry.path = "duplicate";
their_entry.mode = GIT_FILEMODE_BLOB;
GIT_INDEX_ENTRY_STAGE_SET(&their_entry, 3);
git_oid_fromstr(&their_entry.id, "a71586c1dfe8a71c6cbf6c129f404c5642ff31bd");
cl_git_pass(git_index_conflict_add(index, &ancestor_entry, &our_entry, &their_entry));
}
void test_object_tree_duplicateentries__cannot_create_a_duplicate_entry_building_a_tree_from_a_index_with_conflicts(void)
{
git_index *index;
git_oid tid;
cl_git_pass(git_repository_index(&index, _repo));
add_fake_conflicts(index);
cl_assert_equal_i(GIT_EUNMERGED, git_index_write_tree(&tid, index));
git_index_free(index);
}
+68
View File
@@ -0,0 +1,68 @@
#include "clar_libgit2.h"
static git_repository *repo;
static git_tree *tree;
void test_object_tree_frompath__initialize(void)
{
git_oid id;
const char *tree_with_subtrees_oid = "ae90f12eea699729ed24555e40b9fd669da12a12";
cl_git_pass(git_repository_open(&repo, cl_fixture("testrepo.git")));
cl_assert(repo != NULL);
cl_git_pass(git_oid_fromstr(&id, tree_with_subtrees_oid));
cl_git_pass(git_tree_lookup(&tree, repo, &id));
cl_assert(tree != NULL);
}
void test_object_tree_frompath__cleanup(void)
{
git_tree_free(tree);
tree = NULL;
git_repository_free(repo);
repo = NULL;
}
static void assert_tree_from_path(
git_tree *root,
const char *path,
const char *expected_entry_name)
{
git_tree_entry *entry;
cl_git_pass(git_tree_entry_bypath(&entry, root, path));
cl_assert_equal_s(git_tree_entry_name(entry), expected_entry_name);
git_tree_entry_free(entry);
}
void test_object_tree_frompath__retrieve_tree_from_path_to_treeentry(void)
{
git_tree_entry *e;
assert_tree_from_path(tree, "README", "README");
assert_tree_from_path(tree, "ab/de/fgh/1.txt", "1.txt");
assert_tree_from_path(tree, "ab/de/fgh", "fgh");
assert_tree_from_path(tree, "ab/de/fgh/", "fgh");
assert_tree_from_path(tree, "ab/de", "de");
assert_tree_from_path(tree, "ab/", "ab");
assert_tree_from_path(tree, "ab/de/", "de");
cl_assert_equal_i(GIT_ENOTFOUND, git_tree_entry_bypath(&e, tree, "i-do-not-exist.txt"));
cl_assert_equal_i(GIT_ENOTFOUND, git_tree_entry_bypath(&e, tree, "README/"));
cl_assert_equal_i(GIT_ENOTFOUND, git_tree_entry_bypath(&e, tree, "ab/de/fgh/i-do-not-exist.txt"));
cl_assert_equal_i(GIT_ENOTFOUND, git_tree_entry_bypath(&e, tree, "nope/de/fgh/1.txt"));
cl_assert_equal_i(GIT_ENOTFOUND, git_tree_entry_bypath(&e, tree, "ab/me-neither/fgh/2.txt"));
cl_assert_equal_i(GIT_ENOTFOUND, git_tree_entry_bypath(&e, tree, "ab/me-neither/fgh/2.txt/"));
}
void test_object_tree_frompath__fail_when_processing_an_invalid_path(void)
{
git_tree_entry *e;
cl_must_fail(git_tree_entry_bypath(&e, tree, "/"));
cl_must_fail(git_tree_entry_bypath(&e, tree, "/ab"));
cl_must_fail(git_tree_entry_bypath(&e, tree, "/ab/de"));
cl_must_fail(git_tree_entry_bypath(&e, tree, "ab//de"));
}
+164
View File
@@ -0,0 +1,164 @@
#include "clar_libgit2.h"
#include "tree.h"
#include "object.h"
#define OID1_HEX \
"\xae\x90\xf1\x2e\xea\x69\x97\x29\xed\x24" \
"\x55\x5e\x40\xb9\xfd\x66\x9d\xa1\x2a\x12"
#define OID1_STR "ae90f12eea699729ed24555e40b9fd669da12a12"
#define OID2_HEX \
"\xe8\xbf\xe5\xaf\x39\x57\x9a\x7e\x48\x98" \
"\xbb\x23\xf3\xa7\x6a\x72\xc3\x68\xce\xe6"
#define OID2_STR "e8bfe5af39579a7e4898bb23f3a76a72c368cee6"
typedef struct {
const char *filename;
uint16_t attr;
const char *oid;
} expected_entry;
static void assert_tree_parses(const char *data, size_t datalen,
expected_entry *expected_entries, size_t expected_nentries)
{
git_tree *tree;
size_t n;
if (!datalen)
datalen = strlen(data);
cl_git_pass(git_object__from_raw((git_object **) &tree, data, datalen, GIT_OBJECT_TREE));
cl_assert_equal_i(git_tree_entrycount(tree), expected_nentries);
for (n = 0; n < expected_nentries; n++) {
expected_entry *expected = expected_entries + n;
const git_tree_entry *entry;
git_oid oid;
cl_git_pass(git_oid_fromstr(&oid, expected->oid));
cl_assert(entry = git_tree_entry_byname(tree, expected->filename));
cl_assert_equal_s(expected->filename, entry->filename);
cl_assert_equal_i(expected->attr, entry->attr);
cl_assert_equal_oid(&oid, entry->oid);
}
git_object_free(&tree->object);
}
static void assert_tree_fails(const char *data, size_t datalen)
{
git_object *object;
if (!datalen)
datalen = strlen(data);
cl_git_fail(git_object__from_raw(&object, data, datalen, GIT_OBJECT_TREE));
}
void test_object_tree_parse__single_blob_parses(void)
{
expected_entry entries[] = {
{ "foo", 0100644, OID1_STR },
};
const char data[] = "100644 foo\x00" OID1_HEX;
assert_tree_parses(data, ARRAY_SIZE(data) - 1, entries, ARRAY_SIZE(entries));
}
void test_object_tree_parse__single_tree_parses(void)
{
expected_entry entries[] = {
{ "foo", 040000, OID1_STR },
};
const char data[] = "040000 foo\x00" OID1_HEX;
assert_tree_parses(data, ARRAY_SIZE(data) - 1, entries, ARRAY_SIZE(entries));
}
void test_object_tree_parse__leading_filename_spaces_parse(void)
{
expected_entry entries[] = {
{ " bar", 0100644, OID1_STR },
};
const char data[] = "100644 bar\x00" OID1_HEX;
assert_tree_parses(data, ARRAY_SIZE(data) - 1, entries, ARRAY_SIZE(entries));
}
void test_object_tree_parse__multiple_entries_parse(void)
{
expected_entry entries[] = {
{ "bar", 0100644, OID1_STR },
{ "foo", 040000, OID2_STR },
};
const char data[] =
"100644 bar\x00" OID1_HEX
"040000 foo\x00" OID2_HEX;
assert_tree_parses(data, ARRAY_SIZE(data) - 1, entries, ARRAY_SIZE(entries));
}
void test_object_tree_parse__invalid_mode_fails(void)
{
const char data[] = "10x644 bar\x00" OID1_HEX;
assert_tree_fails(data, ARRAY_SIZE(data) - 1);
}
void test_object_tree_parse__missing_mode_fails(void)
{
const char data[] = " bar\x00" OID1_HEX;
assert_tree_fails(data, ARRAY_SIZE(data) - 1);
}
void test_object_tree_parse__mode_doesnt_cause_oob_read(void)
{
const char data[] = "100644 bar\x00" OID1_HEX;
assert_tree_fails(data, 2);
/*
* An oob-read would correctly parse the filename and
* later fail to parse the OID with a different error
* message
*/
cl_assert_equal_s(git_error_last()->message, "failed to parse tree: missing space after filemode");
}
void test_object_tree_parse__unreasonably_large_mode_fails(void)
{
const char data[] = "10000000000000000000000000 bar\x00" OID1_HEX;
assert_tree_fails(data, ARRAY_SIZE(data) - 1);
}
void test_object_tree_parse__missing_filename_separator_fails(void)
{
const char data[] = "100644bar\x00" OID1_HEX;
assert_tree_fails(data, ARRAY_SIZE(data) - 1);
}
void test_object_tree_parse__missing_filename_terminator_fails(void)
{
const char data[] = "100644 bar" OID1_HEX;
assert_tree_fails(data, ARRAY_SIZE(data) - 1);
}
void test_object_tree_parse__empty_filename_fails(void)
{
const char data[] = "100644 \x00" OID1_HEX;
assert_tree_fails(data, ARRAY_SIZE(data) - 1);
}
void test_object_tree_parse__trailing_garbage_fails(void)
{
const char data[] = "100644 bar\x00" OID1_HEX "x";
assert_tree_fails(data, ARRAY_SIZE(data) - 1);
}
void test_object_tree_parse__leading_space_fails(void)
{
const char data[] = " 100644 bar\x00" OID1_HEX;
assert_tree_fails(data, ARRAY_SIZE(data) - 1);
}
void test_object_tree_parse__truncated_oid_fails(void)
{
const char data[] = " 100644 bar\x00" OID1_HEX;
assert_tree_fails(data, ARRAY_SIZE(data) - 2);
}
+119
View File
@@ -0,0 +1,119 @@
#include "clar_libgit2.h"
#include "tree.h"
static const char *tree_oid = "1810dff58d8a660512d4832e740f692884338ccd";
static git_repository *g_repo;
/* Fixture setup and teardown */
void test_object_tree_read__initialize(void)
{
g_repo = cl_git_sandbox_init("testrepo");
}
void test_object_tree_read__cleanup(void)
{
cl_git_sandbox_cleanup();
}
void test_object_tree_read__loaded(void)
{
/* acces randomly the entries on a loaded tree */
git_oid id;
git_tree *tree;
git_oid_fromstr(&id, tree_oid);
cl_git_pass(git_tree_lookup(&tree, g_repo, &id));
cl_assert(git_tree_entry_byname(tree, "README") != NULL);
cl_assert(git_tree_entry_byname(tree, "NOTEXISTS") == NULL);
cl_assert(git_tree_entry_byname(tree, "") == NULL);
cl_assert(git_tree_entry_byindex(tree, 0) != NULL);
cl_assert(git_tree_entry_byindex(tree, 2) != NULL);
cl_assert(git_tree_entry_byindex(tree, 3) == NULL);
cl_assert(git_tree_entry_byindex(tree, (unsigned int)-1) == NULL);
git_tree_free(tree);
}
void test_object_tree_read__two(void)
{
/* read a tree from the repository */
git_oid id;
git_tree *tree;
const git_tree_entry *entry;
git_object *obj;
git_oid_fromstr(&id, tree_oid);
cl_git_pass(git_tree_lookup(&tree, g_repo, &id));
cl_assert(git_tree_entrycount(tree) == 3);
/* GH-86: git_object_lookup() should also check the type if the object comes from the cache */
cl_assert(git_object_lookup(&obj, g_repo, &id, GIT_OBJECT_TREE) == 0);
cl_assert(obj != NULL);
git_object_free(obj);
obj = NULL;
cl_git_fail(git_object_lookup(&obj, g_repo, &id, GIT_OBJECT_BLOB));
cl_assert(obj == NULL);
entry = git_tree_entry_byname(tree, "README");
cl_assert(entry != NULL);
cl_assert_equal_s(git_tree_entry_name(entry), "README");
cl_git_pass(git_tree_entry_to_object(&obj, g_repo, entry));
cl_assert(obj != NULL);
git_object_free(obj);
git_tree_free(tree);
}
#define BIGFILE "bigfile"
#ifdef GIT_ARCH_64
#define BIGFILE_SIZE (off_t)4294967296
#else
# define BIGFILE_SIZE SIZE_MAX
#endif
void test_object_tree_read__largefile(void)
{
const git_tree_entry *entry;
git_index_entry ie;
git_commit *commit;
git_object *object;
git_index *index;
git_tree *tree;
git_oid oid;
char *buf;
if (!cl_is_env_set("GITTEST_INVASIVE_FS_SIZE"))
cl_skip();
cl_assert(buf = git__calloc(1, BIGFILE_SIZE));
memset(&ie, 0, sizeof(ie));
ie.mode = GIT_FILEMODE_BLOB;
ie.path = BIGFILE;
cl_git_pass(git_repository_index(&index, g_repo));
cl_git_pass(git_index_add_from_buffer(index, &ie, buf, BIGFILE_SIZE));
cl_repo_commit_from_index(&oid, g_repo, NULL, 0, BIGFILE);
cl_git_pass(git_commit_lookup(&commit, g_repo, &oid));
cl_git_pass(git_commit_tree(&tree, commit));
cl_assert(entry = git_tree_entry_byname(tree, BIGFILE));
cl_git_pass(git_tree_entry_to_object(&object, g_repo, entry));
git_object_free(object);
git_tree_free(tree);
git_index_free(index);
git_commit_free(commit);
git__free(buf);
}
+302
View File
@@ -0,0 +1,302 @@
#include "clar_libgit2.h"
#include "tree.h"
static git_repository *g_repo;
void test_object_tree_update__initialize(void)
{
g_repo = cl_git_sandbox_init("testrepo2");
}
void test_object_tree_update__cleanup(void)
{
cl_git_sandbox_cleanup();
}
void test_object_tree_update__remove_blob(void)
{
git_oid tree_index_id, tree_updater_id, base_id;
git_tree *base_tree;
git_index *idx;
const char *path = "README";
git_tree_update updates[] = {
{ GIT_TREE_UPDATE_REMOVE, {{0}}, GIT_FILEMODE_BLOB /* ignored */, path},
};
cl_git_pass(git_oid_fromstr(&base_id, "c4dc1555e4d4fa0e0c9c3fc46734c7c35b3ce90b"));
cl_git_pass(git_tree_lookup(&base_tree, g_repo, &base_id));
/* Create it with an index */
cl_git_pass(git_index_new(&idx));
cl_git_pass(git_index_read_tree(idx, base_tree));
cl_git_pass(git_index_remove(idx, path, 0));
cl_git_pass(git_index_write_tree_to(&tree_index_id, idx, g_repo));
git_index_free(idx);
/* Perform the same operation via the tree updater */
cl_git_pass(git_tree_create_updated(&tree_updater_id, g_repo, base_tree, 1, updates));
cl_assert_equal_oid(&tree_index_id, &tree_updater_id);
git_tree_free(base_tree);
}
void test_object_tree_update__remove_blob_deeper(void)
{
git_oid tree_index_id, tree_updater_id, base_id;
git_tree *base_tree;
git_index *idx;
const char *path = "subdir/README";
git_tree_update updates[] = {
{ GIT_TREE_UPDATE_REMOVE, {{0}}, GIT_FILEMODE_BLOB /* ignored */, path},
};
cl_git_pass(git_oid_fromstr(&base_id, "c4dc1555e4d4fa0e0c9c3fc46734c7c35b3ce90b"));
cl_git_pass(git_tree_lookup(&base_tree, g_repo, &base_id));
/* Create it with an index */
cl_git_pass(git_index_new(&idx));
cl_git_pass(git_index_read_tree(idx, base_tree));
cl_git_pass(git_index_remove(idx, path, 0));
cl_git_pass(git_index_write_tree_to(&tree_index_id, idx, g_repo));
git_index_free(idx);
/* Perform the same operation via the tree updater */
cl_git_pass(git_tree_create_updated(&tree_updater_id, g_repo, base_tree, 1, updates));
cl_assert_equal_oid(&tree_index_id, &tree_updater_id);
git_tree_free(base_tree);
}
void test_object_tree_update__remove_all_entries(void)
{
git_oid tree_index_id, tree_updater_id, base_id;
git_tree *base_tree;
git_index *idx;
const char *path1 = "subdir/subdir2/README";
const char *path2 = "subdir/subdir2/new.txt";
git_tree_update updates[] = {
{ GIT_TREE_UPDATE_REMOVE, {{0}}, GIT_FILEMODE_BLOB /* ignored */, path1},
{ GIT_TREE_UPDATE_REMOVE, {{0}}, GIT_FILEMODE_BLOB /* ignored */, path2},
};
cl_git_pass(git_oid_fromstr(&base_id, "c4dc1555e4d4fa0e0c9c3fc46734c7c35b3ce90b"));
cl_git_pass(git_tree_lookup(&base_tree, g_repo, &base_id));
/* Create it with an index */
cl_git_pass(git_index_new(&idx));
cl_git_pass(git_index_read_tree(idx, base_tree));
cl_git_pass(git_index_remove(idx, path1, 0));
cl_git_pass(git_index_remove(idx, path2, 0));
cl_git_pass(git_index_write_tree_to(&tree_index_id, idx, g_repo));
git_index_free(idx);
/* Perform the same operation via the tree updater */
cl_git_pass(git_tree_create_updated(&tree_updater_id, g_repo, base_tree, 2, updates));
cl_assert_equal_oid(&tree_index_id, &tree_updater_id);
git_tree_free(base_tree);
}
void test_object_tree_update__replace_blob(void)
{
git_oid tree_index_id, tree_updater_id, base_id;
git_tree *base_tree;
git_index *idx;
const char *path = "README";
git_index_entry entry = { {0} };
git_tree_update updates[] = {
{ GIT_TREE_UPDATE_UPSERT, {{0}}, GIT_FILEMODE_BLOB, path},
};
cl_git_pass(git_oid_fromstr(&base_id, "c4dc1555e4d4fa0e0c9c3fc46734c7c35b3ce90b"));
cl_git_pass(git_tree_lookup(&base_tree, g_repo, &base_id));
/* Create it with an index */
cl_git_pass(git_index_new(&idx));
cl_git_pass(git_index_read_tree(idx, base_tree));
entry.path = path;
cl_git_pass(git_oid_fromstr(&entry.id, "fa49b077972391ad58037050f2a75f74e3671e92"));
entry.mode = GIT_FILEMODE_BLOB;
cl_git_pass(git_index_add(idx, &entry));
cl_git_pass(git_index_write_tree_to(&tree_index_id, idx, g_repo));
git_index_free(idx);
/* Perform the same operation via the tree updater */
cl_git_pass(git_oid_fromstr(&updates[0].id, "fa49b077972391ad58037050f2a75f74e3671e92"));
cl_git_pass(git_tree_create_updated(&tree_updater_id, g_repo, base_tree, 1, updates));
cl_assert_equal_oid(&tree_index_id, &tree_updater_id);
git_tree_free(base_tree);
}
void test_object_tree_update__add_blobs(void)
{
git_oid tree_index_id, tree_updater_id, base_id;
git_tree *base_tree;
git_index *idx;
git_index_entry entry = { {0} };
int i;
const char *paths[] = {
"some/deep/path",
"some/other/path",
"a/path/elsewhere",
};
git_tree_update updates[] = {
{ GIT_TREE_UPDATE_UPSERT, {{0}}, GIT_FILEMODE_BLOB, paths[0]},
{ GIT_TREE_UPDATE_UPSERT, {{0}}, GIT_FILEMODE_BLOB, paths[1]},
{ GIT_TREE_UPDATE_UPSERT, {{0}}, GIT_FILEMODE_BLOB, paths[2]},
};
cl_git_pass(git_oid_fromstr(&base_id, "c4dc1555e4d4fa0e0c9c3fc46734c7c35b3ce90b"));
entry.mode = GIT_FILEMODE_BLOB;
cl_git_pass(git_oid_fromstr(&entry.id, "fa49b077972391ad58037050f2a75f74e3671e92"));
for (i = 0; i < 3; i++) {
cl_git_pass(git_oid_fromstr(&updates[i].id, "fa49b077972391ad58037050f2a75f74e3671e92"));
}
for (i = 0; i < 2; i++) {
int j;
/* Create it with an index */
cl_git_pass(git_index_new(&idx));
base_tree = NULL;
if (i == 1) {
cl_git_pass(git_tree_lookup(&base_tree, g_repo, &base_id));
cl_git_pass(git_index_read_tree(idx, base_tree));
}
for (j = 0; j < 3; j++) {
entry.path = paths[j];
cl_git_pass(git_index_add(idx, &entry));
}
cl_git_pass(git_index_write_tree_to(&tree_index_id, idx, g_repo));
git_index_free(idx);
/* Perform the same operations via the tree updater */
cl_git_pass(git_tree_create_updated(&tree_updater_id, g_repo, base_tree, 3, updates));
cl_assert_equal_oid(&tree_index_id, &tree_updater_id);
}
git_tree_free(base_tree);
}
void test_object_tree_update__add_blobs_unsorted(void)
{
git_oid tree_index_id, tree_updater_id, base_id;
git_tree *base_tree;
git_index *idx;
git_index_entry entry = { {0} };
int i;
const char *paths[] = {
"some/deep/path",
"a/path/elsewhere",
"some/other/path",
};
git_tree_update updates[] = {
{ GIT_TREE_UPDATE_UPSERT, {{0}}, GIT_FILEMODE_BLOB, paths[0]},
{ GIT_TREE_UPDATE_UPSERT, {{0}}, GIT_FILEMODE_BLOB, paths[1]},
{ GIT_TREE_UPDATE_UPSERT, {{0}}, GIT_FILEMODE_BLOB, paths[2]},
};
cl_git_pass(git_oid_fromstr(&base_id, "c4dc1555e4d4fa0e0c9c3fc46734c7c35b3ce90b"));
entry.mode = GIT_FILEMODE_BLOB;
cl_git_pass(git_oid_fromstr(&entry.id, "fa49b077972391ad58037050f2a75f74e3671e92"));
for (i = 0; i < 3; i++) {
cl_git_pass(git_oid_fromstr(&updates[i].id, "fa49b077972391ad58037050f2a75f74e3671e92"));
}
for (i = 0; i < 2; i++) {
int j;
/* Create it with an index */
cl_git_pass(git_index_new(&idx));
base_tree = NULL;
if (i == 1) {
cl_git_pass(git_tree_lookup(&base_tree, g_repo, &base_id));
cl_git_pass(git_index_read_tree(idx, base_tree));
}
for (j = 0; j < 3; j++) {
entry.path = paths[j];
cl_git_pass(git_index_add(idx, &entry));
}
cl_git_pass(git_index_write_tree_to(&tree_index_id, idx, g_repo));
git_index_free(idx);
/* Perform the same operations via the tree updater */
cl_git_pass(git_tree_create_updated(&tree_updater_id, g_repo, base_tree, 3, updates));
cl_assert_equal_oid(&tree_index_id, &tree_updater_id);
}
git_tree_free(base_tree);
}
void test_object_tree_update__add_conflict(void)
{
int i;
git_oid tree_updater_id;
git_tree_update updates[] = {
{ GIT_TREE_UPDATE_UPSERT, {{0}}, GIT_FILEMODE_BLOB, "a/dir/blob"},
{ GIT_TREE_UPDATE_UPSERT, {{0}}, GIT_FILEMODE_BLOB, "a/dir"},
};
for (i = 0; i < 2; i++) {
cl_git_pass(git_oid_fromstr(&updates[i].id, "a71586c1dfe8a71c6cbf6c129f404c5642ff31bd"));
}
cl_git_fail(git_tree_create_updated(&tree_updater_id, g_repo, NULL, 2, updates));
}
void test_object_tree_update__add_conflict2(void)
{
int i;
git_oid tree_updater_id;
git_tree_update updates[] = {
{ GIT_TREE_UPDATE_UPSERT, {{0}}, GIT_FILEMODE_BLOB, "a/dir/blob"},
{ GIT_TREE_UPDATE_UPSERT, {{0}}, GIT_FILEMODE_TREE, "a/dir/blob"},
};
for (i = 0; i < 2; i++) {
cl_git_pass(git_oid_fromstr(&updates[i].id, "a71586c1dfe8a71c6cbf6c129f404c5642ff31bd"));
}
cl_git_fail(git_tree_create_updated(&tree_updater_id, g_repo, NULL, 2, updates));
}
void test_object_tree_update__remove_invalid_submodule(void)
{
git_tree *baseline;
git_oid updated_tree_id, baseline_id;
git_tree_update updates[] = {
{GIT_TREE_UPDATE_REMOVE, {{0}}, GIT_FILEMODE_BLOB, "submodule"},
};
/* This tree contains a submodule with an all-zero commit for a submodule named 'submodule' */
cl_git_pass(git_oid_fromstr(&baseline_id, "396c7f1adb7925f51ba13a75f48252f44c5a14a2"));
cl_git_pass(git_tree_lookup(&baseline, g_repo, &baseline_id));
cl_git_pass(git_tree_create_updated(&updated_tree_id, g_repo, baseline, 1, updates));
git_tree_free(baseline);
}
+177
View File
@@ -0,0 +1,177 @@
#include "clar_libgit2.h"
#include "tree.h"
static const char *tree_oid = "1810dff58d8a660512d4832e740f692884338ccd";
static git_repository *g_repo;
void test_object_tree_walk__initialize(void)
{
g_repo = cl_git_sandbox_init("testrepo");
}
void test_object_tree_walk__cleanup(void)
{
cl_git_sandbox_cleanup();
}
static int treewalk_count_cb(
const char *root, const git_tree_entry *entry, void *payload)
{
int *count = payload;
GIT_UNUSED(root);
GIT_UNUSED(entry);
(*count) += 1;
return 0;
}
void test_object_tree_walk__0(void)
{
git_oid id;
git_tree *tree;
int ct;
git_oid_fromstr(&id, tree_oid);
cl_git_pass(git_tree_lookup(&tree, g_repo, &id));
ct = 0;
cl_git_pass(git_tree_walk(tree, GIT_TREEWALK_PRE, treewalk_count_cb, &ct));
cl_assert_equal_i(3, ct);
ct = 0;
cl_git_pass(git_tree_walk(tree, GIT_TREEWALK_POST, treewalk_count_cb, &ct));
cl_assert_equal_i(3, ct);
git_tree_free(tree);
}
static int treewalk_stop_cb(
const char *root, const git_tree_entry *entry, void *payload)
{
int *count = payload;
GIT_UNUSED(root);
GIT_UNUSED(entry);
(*count) += 1;
return (*count == 2) ? -123 : 0;
}
static int treewalk_stop_immediately_cb(
const char *root, const git_tree_entry *entry, void *payload)
{
GIT_UNUSED(root);
GIT_UNUSED(entry);
GIT_UNUSED(payload);
return -100;
}
void test_object_tree_walk__1(void)
{
git_oid id;
git_tree *tree;
int ct;
git_oid_fromstr(&id, tree_oid);
cl_git_pass(git_tree_lookup(&tree, g_repo, &id));
ct = 0;
cl_assert_equal_i(
-123, git_tree_walk(tree, GIT_TREEWALK_PRE, treewalk_stop_cb, &ct));
cl_assert_equal_i(2, ct);
ct = 0;
cl_assert_equal_i(
-123, git_tree_walk(tree, GIT_TREEWALK_POST, treewalk_stop_cb, &ct));
cl_assert_equal_i(2, ct);
cl_assert_equal_i(
-100, git_tree_walk(
tree, GIT_TREEWALK_PRE, treewalk_stop_immediately_cb, NULL));
cl_assert_equal_i(
-100, git_tree_walk(
tree, GIT_TREEWALK_POST, treewalk_stop_immediately_cb, NULL));
git_tree_free(tree);
}
struct treewalk_skip_data {
int files;
int dirs;
const char *skip;
const char *stop;
};
static int treewalk_skip_de_cb(
const char *root, const git_tree_entry *entry, void *payload)
{
struct treewalk_skip_data *data = payload;
const char *name = git_tree_entry_name(entry);
GIT_UNUSED(root);
if (git_tree_entry_type(entry) == GIT_OBJECT_TREE)
data->dirs++;
else
data->files++;
if (data->skip && !strcmp(name, data->skip))
return 1;
else if (data->stop && !strcmp(name, data->stop))
return -1;
else
return 0;
}
void test_object_tree_walk__2(void)
{
git_oid id;
git_tree *tree;
struct treewalk_skip_data data;
/* look up a deep tree */
git_oid_fromstr(&id, "ae90f12eea699729ed24555e40b9fd669da12a12");
cl_git_pass(git_tree_lookup(&tree, g_repo, &id));
memset(&data, 0, sizeof(data));
data.skip = "de";
cl_assert_equal_i(0, git_tree_walk(
tree, GIT_TREEWALK_PRE, treewalk_skip_de_cb, &data));
cl_assert_equal_i(5, data.files);
cl_assert_equal_i(3, data.dirs);
memset(&data, 0, sizeof(data));
data.stop = "3.txt";
cl_assert_equal_i(-1, git_tree_walk(
tree, GIT_TREEWALK_PRE, treewalk_skip_de_cb, &data));
cl_assert_equal_i(3, data.files);
cl_assert_equal_i(2, data.dirs);
memset(&data, 0, sizeof(data));
data.skip = "new.txt";
cl_assert_equal_i(0, git_tree_walk(
tree, GIT_TREEWALK_PRE, treewalk_skip_de_cb, &data));
cl_assert_equal_i(7, data.files);
cl_assert_equal_i(4, data.dirs);
memset(&data, 0, sizeof(data));
data.stop = "new.txt";
cl_assert_equal_i(-1, git_tree_walk(
tree, GIT_TREEWALK_PRE, treewalk_skip_de_cb, &data));
cl_assert_equal_i(7, data.files);
cl_assert_equal_i(4, data.dirs);
git_tree_free(tree);
}
+525
View File
@@ -0,0 +1,525 @@
#include "clar_libgit2.h"
#include "tree.h"
static const char *blob_oid = "fa49b077972391ad58037050f2a75f74e3671e92";
static const char *first_tree = "181037049a54a1eb5fab404658a3a250b44335d7";
static const char *second_tree = "f60079018b664e4e79329a7ef9559c8d9e0378d1";
static const char *third_tree = "eb86d8b81d6adbd5290a935d6c9976882de98488";
static git_repository *g_repo;
/* Fixture setup and teardown */
void test_object_tree_write__initialize(void)
{
g_repo = cl_git_sandbox_init("testrepo");
}
void test_object_tree_write__cleanup(void)
{
cl_git_sandbox_cleanup();
cl_git_pass(git_libgit2_opts(GIT_OPT_ENABLE_STRICT_OBJECT_CREATION, 1));
}
void test_object_tree_write__from_memory(void)
{
/* write a tree from a memory */
git_treebuilder *builder;
git_tree *tree;
git_oid id, bid, rid, id2;
git_oid_fromstr(&id, first_tree);
git_oid_fromstr(&id2, second_tree);
git_oid_fromstr(&bid, blob_oid);
/* create a second tree from first tree using `git_treebuilder_insert`
* on REPOSITORY_FOLDER.
*/
cl_git_pass(git_tree_lookup(&tree, g_repo, &id));
cl_git_pass(git_treebuilder_new(&builder, g_repo, tree));
cl_git_fail(git_treebuilder_insert(NULL, builder, "",
&bid, GIT_FILEMODE_BLOB));
cl_git_fail(git_treebuilder_insert(NULL, builder, "/",
&bid, GIT_FILEMODE_BLOB));
cl_git_fail(git_treebuilder_insert(NULL, builder, ".git",
&bid, GIT_FILEMODE_BLOB));
cl_git_fail(git_treebuilder_insert(NULL, builder, "..",
&bid, GIT_FILEMODE_BLOB));
cl_git_fail(git_treebuilder_insert(NULL, builder, ".",
&bid, GIT_FILEMODE_BLOB));
cl_git_fail(git_treebuilder_insert(NULL, builder, "folder/new.txt",
&bid, GIT_FILEMODE_BLOB));
cl_git_pass(git_treebuilder_insert(
NULL, builder, "new.txt", &bid, GIT_FILEMODE_BLOB));
cl_git_pass(git_treebuilder_write(&rid, builder));
cl_assert(git_oid_cmp(&rid, &id2) == 0);
git_treebuilder_free(builder);
git_tree_free(tree);
}
void test_object_tree_write__subtree(void)
{
/* write a hierarchical tree from a memory */
git_treebuilder *builder;
git_tree *tree;
git_oid id, bid, subtree_id, id2, id3;
git_oid id_hiearar;
git_oid_fromstr(&id, first_tree);
git_oid_fromstr(&id2, second_tree);
git_oid_fromstr(&id3, third_tree);
git_oid_fromstr(&bid, blob_oid);
/* create subtree */
cl_git_pass(git_treebuilder_new(&builder, g_repo, NULL));
cl_git_pass(git_treebuilder_insert(
NULL, builder, "new.txt", &bid, GIT_FILEMODE_BLOB)); /* -V536 */
cl_git_pass(git_treebuilder_write(&subtree_id, builder));
git_treebuilder_free(builder);
/* create parent tree */
cl_git_pass(git_tree_lookup(&tree, g_repo, &id));
cl_git_pass(git_treebuilder_new(&builder, g_repo, tree));
cl_git_pass(git_treebuilder_insert(
NULL, builder, "new", &subtree_id, GIT_FILEMODE_TREE)); /* -V536 */
cl_git_pass(git_treebuilder_write(&id_hiearar, builder));
git_treebuilder_free(builder);
git_tree_free(tree);
cl_assert(git_oid_cmp(&id_hiearar, &id3) == 0);
/* check data is correct */
cl_git_pass(git_tree_lookup(&tree, g_repo, &id_hiearar));
cl_assert(2 == git_tree_entrycount(tree));
git_tree_free(tree);
}
/*
* And the Lord said: Is this tree properly sorted?
*/
void test_object_tree_write__sorted_subtrees(void)
{
git_treebuilder *builder;
git_tree *tree;
unsigned int i;
int position_c = -1, position_cake = -1, position_config = -1;
struct {
unsigned int attr;
const char *filename;
} entries[] = {
{ GIT_FILEMODE_BLOB, ".gitattributes" },
{ GIT_FILEMODE_BLOB, ".gitignore" },
{ GIT_FILEMODE_BLOB, ".htaccess" },
{ GIT_FILEMODE_BLOB, "Capfile" },
{ GIT_FILEMODE_BLOB, "Makefile"},
{ GIT_FILEMODE_BLOB, "README"},
{ GIT_FILEMODE_TREE, "app"},
{ GIT_FILEMODE_TREE, "cake"},
{ GIT_FILEMODE_TREE, "config"},
{ GIT_FILEMODE_BLOB, "c"},
{ GIT_FILEMODE_BLOB, "git_test.txt"},
{ GIT_FILEMODE_BLOB, "htaccess.htaccess"},
{ GIT_FILEMODE_BLOB, "index.php"},
{ GIT_FILEMODE_TREE, "plugins"},
{ GIT_FILEMODE_TREE, "schemas"},
{ GIT_FILEMODE_TREE, "ssl-certs"},
{ GIT_FILEMODE_TREE, "vendors"}
};
git_oid bid, tid, tree_oid;
cl_git_pass(git_oid_fromstr(&bid, blob_oid));
cl_git_pass(git_oid_fromstr(&tid, first_tree));
cl_git_pass(git_treebuilder_new(&builder, g_repo, NULL));
for (i = 0; i < ARRAY_SIZE(entries); ++i) {
git_oid *id = entries[i].attr == GIT_FILEMODE_TREE ? &tid : &bid;
cl_git_pass(git_treebuilder_insert(NULL,
builder, entries[i].filename, id, entries[i].attr));
}
cl_git_pass(git_treebuilder_write(&tree_oid, builder));
cl_git_pass(git_tree_lookup(&tree, g_repo, &tree_oid));
for (i = 0; i < git_tree_entrycount(tree); i++) {
const git_tree_entry *entry = git_tree_entry_byindex(tree, i);
if (strcmp(entry->filename, "c") == 0)
position_c = i;
if (strcmp(entry->filename, "cake") == 0)
position_cake = i;
if (strcmp(entry->filename, "config") == 0)
position_config = i;
}
git_tree_free(tree);
cl_assert(position_c != -1);
cl_assert(position_cake != -1);
cl_assert(position_config != -1);
cl_assert(position_c < position_cake);
cl_assert(position_cake < position_config);
git_treebuilder_free(builder);
}
static struct {
unsigned int attr;
const char *filename;
} _entries[] = {
{ GIT_FILEMODE_BLOB, "aardvark" },
{ GIT_FILEMODE_BLOB, ".first" },
{ GIT_FILEMODE_BLOB, "apple" },
{ GIT_FILEMODE_BLOB, "last"},
{ GIT_FILEMODE_BLOB, "apple_after"},
{ GIT_FILEMODE_BLOB, "after_aardvark"},
{ 0, NULL },
};
void test_object_tree_write__removing_and_re_adding_in_treebuilder(void)
{
git_treebuilder *builder;
int i, aardvark_i, apple_i, apple_after_i, apple_extra_i, last_i;
git_oid entry_oid, tree_oid;
git_tree *tree;
cl_git_pass(git_oid_fromstr(&entry_oid, blob_oid));
cl_git_pass(git_treebuilder_new(&builder, g_repo, NULL));
cl_assert_equal_i(0, (int)git_treebuilder_entrycount(builder));
for (i = 0; _entries[i].filename; ++i)
cl_git_pass(git_treebuilder_insert(NULL,
builder, _entries[i].filename, &entry_oid, _entries[i].attr));
cl_assert_equal_i(6, (int)git_treebuilder_entrycount(builder));
cl_git_pass(git_treebuilder_remove(builder, "apple"));
cl_assert_equal_i(5, (int)git_treebuilder_entrycount(builder));
cl_git_pass(git_treebuilder_remove(builder, "apple_after"));
cl_assert_equal_i(4, (int)git_treebuilder_entrycount(builder));
cl_git_pass(git_treebuilder_insert(
NULL, builder, "before_last", &entry_oid, GIT_FILEMODE_BLOB));
cl_assert_equal_i(5, (int)git_treebuilder_entrycount(builder));
/* reinsert apple_after */
cl_git_pass(git_treebuilder_insert(
NULL, builder, "apple_after", &entry_oid, GIT_FILEMODE_BLOB));
cl_assert_equal_i(6, (int)git_treebuilder_entrycount(builder));
cl_git_pass(git_treebuilder_remove(builder, "last"));
cl_assert_equal_i(5, (int)git_treebuilder_entrycount(builder));
/* reinsert last */
cl_git_pass(git_treebuilder_insert(
NULL, builder, "last", &entry_oid, GIT_FILEMODE_BLOB));
cl_assert_equal_i(6, (int)git_treebuilder_entrycount(builder));
cl_git_pass(git_treebuilder_insert(
NULL, builder, "apple_extra", &entry_oid, GIT_FILEMODE_BLOB));
cl_assert_equal_i(7, (int)git_treebuilder_entrycount(builder));
cl_git_pass(git_treebuilder_write(&tree_oid, builder));
git_treebuilder_free(builder);
cl_git_pass(git_tree_lookup(&tree, g_repo, &tree_oid));
cl_assert_equal_i(7, (int)git_tree_entrycount(tree));
cl_assert(git_tree_entry_byname(tree, ".first") != NULL);
cl_assert(git_tree_entry_byname(tree, "apple") == NULL);
cl_assert(git_tree_entry_byname(tree, "apple_after") != NULL);
cl_assert(git_tree_entry_byname(tree, "apple_extra") != NULL);
cl_assert(git_tree_entry_byname(tree, "last") != NULL);
aardvark_i = apple_i = apple_after_i = apple_extra_i = last_i = -1;
for (i = 0; i < 7; ++i) {
const git_tree_entry *entry = git_tree_entry_byindex(tree, i);
if (!strcmp(entry->filename, "aardvark"))
aardvark_i = i;
else if (!strcmp(entry->filename, "apple"))
apple_i = i;
else if (!strcmp(entry->filename, "apple_after"))
apple_after_i = i;
else if (!strcmp(entry->filename, "apple_extra"))
apple_extra_i = i;
else if (!strcmp(entry->filename, "last"))
last_i = i;
}
cl_assert_equal_i(-1, apple_i);
cl_assert_equal_i(6, last_i);
cl_assert(aardvark_i < apple_after_i);
cl_assert(apple_after_i < apple_extra_i);
git_tree_free(tree);
}
static int treebuilder_filter_prefixed(
const git_tree_entry *entry, void *payload)
{
return !git__prefixcmp(git_tree_entry_name(entry), payload);
}
void test_object_tree_write__filtering(void)
{
git_treebuilder *builder;
int i;
git_oid entry_oid, tree_oid;
git_tree *tree;
git_oid_fromstr(&entry_oid, blob_oid);
cl_git_pass(git_treebuilder_new(&builder, g_repo, NULL));
for (i = 0; _entries[i].filename; ++i)
cl_git_pass(git_treebuilder_insert(NULL,
builder, _entries[i].filename, &entry_oid, _entries[i].attr));
cl_assert_equal_i(6, (int)git_treebuilder_entrycount(builder));
cl_assert(git_treebuilder_get(builder, "apple") != NULL);
cl_assert(git_treebuilder_get(builder, "aardvark") != NULL);
cl_assert(git_treebuilder_get(builder, "last") != NULL);
git_treebuilder_filter(builder, treebuilder_filter_prefixed, "apple");
cl_assert_equal_i(4, (int)git_treebuilder_entrycount(builder));
cl_assert(git_treebuilder_get(builder, "apple") == NULL);
cl_assert(git_treebuilder_get(builder, "aardvark") != NULL);
cl_assert(git_treebuilder_get(builder, "last") != NULL);
git_treebuilder_filter(builder, treebuilder_filter_prefixed, "a");
cl_assert_equal_i(2, (int)git_treebuilder_entrycount(builder));
cl_assert(git_treebuilder_get(builder, "aardvark") == NULL);
cl_assert(git_treebuilder_get(builder, "last") != NULL);
cl_git_pass(git_treebuilder_write(&tree_oid, builder));
git_treebuilder_free(builder);
cl_git_pass(git_tree_lookup(&tree, g_repo, &tree_oid));
cl_assert_equal_i(2, (int)git_tree_entrycount(tree));
git_tree_free(tree);
}
void test_object_tree_write__cruel_paths(void)
{
static const char *the_paths[] = {
"C:\\",
" : * ? \" \n < > |",
"a\\b",
"\\\\b\a",
":\\",
"COM1",
"foo.aux",
REP1024("1234"), /* 4096 char string */
REP1024("12345678"), /* 8192 char string */
"\xC5\xAA\x6E\xC4\xAD\x63\xC5\x8D\x64\x65\xCC\xBD", /* Ūnĭcōde̽ */
NULL
};
git_treebuilder *builder;
git_tree *tree;
git_oid id, bid, subid;
const char **scan;
int count = 0, i, j;
git_tree_entry *te;
git_oid_fromstr(&bid, blob_oid);
/* create tree */
cl_git_pass(git_treebuilder_new(&builder, g_repo, NULL));
for (scan = the_paths; *scan; ++scan) {
cl_git_pass(git_treebuilder_insert(
NULL, builder, *scan, &bid, GIT_FILEMODE_BLOB));
count++;
}
cl_git_pass(git_treebuilder_write(&id, builder));
git_treebuilder_free(builder);
/* check data is correct */
cl_git_pass(git_tree_lookup(&tree, g_repo, &id));
cl_assert_equal_i(count, git_tree_entrycount(tree));
for (scan = the_paths; *scan; ++scan) {
const git_tree_entry *cte = git_tree_entry_byname(tree, *scan);
cl_assert(cte != NULL);
cl_assert_equal_s(*scan, git_tree_entry_name(cte));
}
for (scan = the_paths; *scan; ++scan) {
cl_git_pass(git_tree_entry_bypath(&te, tree, *scan));
cl_assert_equal_s(*scan, git_tree_entry_name(te));
git_tree_entry_free(te);
}
git_tree_free(tree);
/* let's try longer paths */
cl_git_pass(git_treebuilder_new(&builder, g_repo, NULL));
for (scan = the_paths; *scan; ++scan) {
cl_git_pass(git_treebuilder_insert(
NULL, builder, *scan, &id, GIT_FILEMODE_TREE));
}
cl_git_pass(git_treebuilder_write(&subid, builder));
git_treebuilder_free(builder);
/* check data is correct */
cl_git_pass(git_tree_lookup(&tree, g_repo, &subid));
cl_assert_equal_i(count, git_tree_entrycount(tree));
for (i = 0; i < count; ++i) {
for (j = 0; j < count; ++j) {
git_buf b = GIT_BUF_INIT;
cl_git_pass(git_buf_joinpath(&b, the_paths[i], the_paths[j]));
cl_git_pass(git_tree_entry_bypath(&te, tree, b.ptr));
cl_assert_equal_s(the_paths[j], git_tree_entry_name(te));
git_tree_entry_free(te);
git_buf_dispose(&b);
}
}
git_tree_free(tree);
}
void test_object_tree_write__protect_filesystems(void)
{
git_treebuilder *builder;
git_oid bid;
cl_git_pass(git_oid_fromstr(&bid, "fa49b077972391ad58037050f2a75f74e3671e92"));
/* Ensure that (by default) we can write objects with funny names on
* platforms that are not affected.
*/
cl_git_pass(git_treebuilder_new(&builder, g_repo, NULL));
cl_git_fail(git_treebuilder_insert(NULL, builder, ".git.", &bid, GIT_FILEMODE_BLOB));
cl_git_fail(git_treebuilder_insert(NULL, builder, "git~1", &bid, GIT_FILEMODE_BLOB));
#ifndef __APPLE__
cl_git_pass(git_treebuilder_insert(NULL, builder, ".git\xef\xbb\xbf", &bid, GIT_FILEMODE_BLOB));
cl_git_pass(git_treebuilder_insert(NULL, builder, ".git\xe2\x80\xad", &bid, GIT_FILEMODE_BLOB));
#endif
git_treebuilder_free(builder);
/* Now turn on core.protectHFS and core.protectNTFS and validate that these
* paths are rejected.
*/
cl_repo_set_bool(g_repo, "core.protectHFS", true);
cl_repo_set_bool(g_repo, "core.protectNTFS", true);
cl_git_pass(git_treebuilder_new(&builder, g_repo, NULL));
cl_git_fail(git_treebuilder_insert(NULL, builder, ".git.", &bid, GIT_FILEMODE_BLOB));
cl_git_fail(git_treebuilder_insert(NULL, builder, "git~1", &bid, GIT_FILEMODE_BLOB));
cl_git_fail(git_treebuilder_insert(NULL, builder, ".git\xef\xbb\xbf", &bid, GIT_FILEMODE_BLOB));
cl_git_fail(git_treebuilder_insert(NULL, builder, ".git\xe2\x80\xad", &bid, GIT_FILEMODE_BLOB));
cl_git_fail(git_treebuilder_insert(NULL, builder, ".git::$INDEX_ALLOCATION/dummy-file", &bid, GIT_FILEMODE_BLOB));
git_treebuilder_free(builder);
}
static void test_invalid_objects(bool should_allow_invalid)
{
git_treebuilder *builder;
git_oid valid_blob_id, invalid_blob_id, valid_tree_id, invalid_tree_id;
#define assert_allowed(expr) \
clar__assert(!(expr) == should_allow_invalid, __FILE__, __LINE__, \
(should_allow_invalid ? \
"Expected function call to succeed: " #expr : \
"Expected function call to fail: " #expr), \
NULL, 1)
cl_git_pass(git_oid_fromstr(&valid_blob_id, blob_oid));
cl_git_pass(git_oid_fromstr(&invalid_blob_id,
"1234567890123456789012345678901234567890"));
cl_git_pass(git_oid_fromstr(&valid_tree_id, first_tree));
cl_git_pass(git_oid_fromstr(&invalid_tree_id,
"0000000000111111111122222222223333333333"));
cl_git_pass(git_treebuilder_new(&builder, g_repo, NULL));
/* test valid blobs and trees (these should always pass) */
cl_git_pass(git_treebuilder_insert(NULL, builder, "file.txt", &valid_blob_id, GIT_FILEMODE_BLOB));
cl_git_pass(git_treebuilder_insert(NULL, builder, "folder", &valid_tree_id, GIT_FILEMODE_TREE));
/* replace valid files and folders with invalid ones */
assert_allowed(git_treebuilder_insert(NULL, builder, "file.txt", &invalid_blob_id, GIT_FILEMODE_BLOB));
assert_allowed(git_treebuilder_insert(NULL, builder, "folder", &invalid_blob_id, GIT_FILEMODE_BLOB));
/* insert new invalid files and folders */
assert_allowed(git_treebuilder_insert(NULL, builder, "invalid_file.txt", &invalid_blob_id, GIT_FILEMODE_BLOB));
assert_allowed(git_treebuilder_insert(NULL, builder, "invalid_folder", &invalid_blob_id, GIT_FILEMODE_BLOB));
/* insert valid blobs as trees and trees as blobs */
assert_allowed(git_treebuilder_insert(NULL, builder, "file_as_folder", &valid_blob_id, GIT_FILEMODE_TREE));
assert_allowed(git_treebuilder_insert(NULL, builder, "folder_as_file.txt", &valid_tree_id, GIT_FILEMODE_BLOB));
#undef assert_allowed
git_treebuilder_free(builder);
}
static void test_inserting_submodule(void)
{
git_treebuilder *bld;
git_oid sm_id;
cl_git_pass(git_oid_fromstr(&sm_id, "da39a3ee5e6b4b0d3255bfef95601890afd80709"));
cl_git_pass(git_treebuilder_new(&bld, g_repo, NULL));
cl_git_pass(git_treebuilder_insert(NULL, bld, "sm", &sm_id, GIT_FILEMODE_COMMIT));
git_treebuilder_free(bld);
}
void test_object_tree_write__object_validity(void)
{
/* Ensure that we cannot add invalid objects by default */
test_invalid_objects(false);
test_inserting_submodule();
/* Ensure that we can turn off validation */
cl_git_pass(git_libgit2_opts(GIT_OPT_ENABLE_STRICT_OBJECT_CREATION, 0));
test_invalid_objects(true);
test_inserting_submodule();
}
void test_object_tree_write__invalid_null_oid(void)
{
git_treebuilder *bld;
git_oid null_oid = {{0}};
cl_git_pass(git_treebuilder_new(&bld, g_repo, NULL));
cl_git_fail(git_treebuilder_insert(NULL, bld, "null_oid_file", &null_oid, GIT_FILEMODE_BLOB));
cl_assert(git_error_last() && strstr(git_error_last()->message, "null OID") != NULL);
git_treebuilder_free(bld);
}