libgit2/tests/odb/mixed.c
Vicent Marti 9a78665005 odb: Handle corner cases in git_odb_expand_ids
The old implementation had two issues:

1. OIDs that were too short as to be ambiguous were not being handled
properly.

2. If the last OID to expand in the array was missing from the ODB, we
would leak a `GIT_ENOTFOUND` error code from the function.
2016-03-09 11:00:27 +01:00

266 lines
7.6 KiB
C

#include "clar_libgit2.h"
#include "odb.h"
static git_odb *_odb;
void test_odb_mixed__initialize(void)
{
cl_git_pass(git_odb_open(&_odb, cl_fixture("duplicate.git/objects")));
}
void test_odb_mixed__cleanup(void)
{
git_odb_free(_odb);
_odb = NULL;
}
void test_odb_mixed__dup_oid(void) {
const char hex[] = "ce013625030ba8dba906f756967f9e9ca394464a";
const char short_hex[] = "ce01362";
git_oid oid;
git_odb_object *obj;
cl_git_pass(git_oid_fromstr(&oid, hex));
cl_git_pass(git_odb_read_prefix(&obj, _odb, &oid, GIT_OID_HEXSZ));
git_odb_object_free(obj);
cl_git_pass(git_odb_exists_prefix(NULL, _odb, &oid, GIT_OID_HEXSZ));
cl_git_pass(git_oid_fromstrn(&oid, short_hex, sizeof(short_hex) - 1));
cl_git_pass(git_odb_read_prefix(&obj, _odb, &oid, sizeof(short_hex) - 1));
git_odb_object_free(obj);
cl_git_pass(git_odb_exists_prefix(NULL, _odb, &oid, sizeof(short_hex) - 1));
}
/* some known sha collisions of file content:
* 'aabqhq' and 'aaazvc' with prefix 'dea509d0' (+ '9' and + 'b')
* 'aaeufo' and 'aaaohs' with prefix '81b5bff5' (+ 'f' and + 'b')
* 'aafewy' and 'aaepta' with prefix '739e3c4c'
* 'aahsyn' and 'aadrjg' with prefix '0ddeaded' (+ '9' and + 'e')
*/
void test_odb_mixed__dup_oid_prefix_0(void) {
char hex[10];
git_oid oid, found;
git_odb_object *obj;
/* ambiguous in the same pack file */
strncpy(hex, "dea509d0", sizeof(hex));
cl_git_pass(git_oid_fromstrn(&oid, hex, strlen(hex)));
cl_assert_equal_i(
GIT_EAMBIGUOUS, git_odb_read_prefix(&obj, _odb, &oid, strlen(hex)));
cl_assert_equal_i(
GIT_EAMBIGUOUS, git_odb_exists_prefix(&found, _odb, &oid, strlen(hex)));
strncpy(hex, "dea509d09", sizeof(hex));
cl_git_pass(git_oid_fromstrn(&oid, hex, strlen(hex)));
cl_git_pass(git_odb_read_prefix(&obj, _odb, &oid, strlen(hex)));
cl_git_pass(git_odb_exists_prefix(&found, _odb, &oid, strlen(hex)));
cl_assert_equal_oid(&found, git_odb_object_id(obj));
git_odb_object_free(obj);
strncpy(hex, "dea509d0b", sizeof(hex));
cl_git_pass(git_oid_fromstrn(&oid, hex, strlen(hex)));
cl_git_pass(git_odb_read_prefix(&obj, _odb, &oid, strlen(hex)));
git_odb_object_free(obj);
/* ambiguous in different pack files */
strncpy(hex, "81b5bff5", sizeof(hex));
cl_git_pass(git_oid_fromstrn(&oid, hex, strlen(hex)));
cl_assert_equal_i(
GIT_EAMBIGUOUS, git_odb_read_prefix(&obj, _odb, &oid, strlen(hex)));
cl_assert_equal_i(
GIT_EAMBIGUOUS, git_odb_exists_prefix(&found, _odb, &oid, strlen(hex)));
strncpy(hex, "81b5bff5b", sizeof(hex));
cl_git_pass(git_oid_fromstrn(&oid, hex, strlen(hex)));
cl_git_pass(git_odb_read_prefix(&obj, _odb, &oid, strlen(hex)));
cl_git_pass(git_odb_exists_prefix(&found, _odb, &oid, strlen(hex)));
cl_assert_equal_oid(&found, git_odb_object_id(obj));
git_odb_object_free(obj);
strncpy(hex, "81b5bff5f", sizeof(hex));
cl_git_pass(git_oid_fromstrn(&oid, hex, strlen(hex)));
cl_git_pass(git_odb_read_prefix(&obj, _odb, &oid, strlen(hex)));
git_odb_object_free(obj);
/* ambiguous in pack file and loose */
strncpy(hex, "0ddeaded", sizeof(hex));
cl_git_pass(git_oid_fromstrn(&oid, hex, strlen(hex)));
cl_assert_equal_i(
GIT_EAMBIGUOUS, git_odb_read_prefix(&obj, _odb, &oid, strlen(hex)));
cl_assert_equal_i(
GIT_EAMBIGUOUS, git_odb_exists_prefix(&found, _odb, &oid, strlen(hex)));
strncpy(hex, "0ddeaded9", sizeof(hex));
cl_git_pass(git_oid_fromstrn(&oid, hex, strlen(hex)));
cl_git_pass(git_odb_read_prefix(&obj, _odb, &oid, strlen(hex)));
cl_git_pass(git_odb_exists_prefix(&found, _odb, &oid, strlen(hex)));
cl_assert_equal_oid(&found, git_odb_object_id(obj));
git_odb_object_free(obj);
strncpy(hex, "0ddeadede", sizeof(hex));
cl_git_pass(git_oid_fromstrn(&oid, hex, strlen(hex)));
cl_git_pass(git_odb_read_prefix(&obj, _odb, &oid, strlen(hex)));
git_odb_object_free(obj);
}
struct expand_id_test_data {
char *lookup_id;
char *expected_id;
git_otype expected_type;
};
struct expand_id_test_data expand_id_test_data[] = {
/* some prefixes and their expected values */
{ "dea509d0", NULL, GIT_OBJ_ANY },
{ "00000000", NULL, GIT_OBJ_ANY },
{ "dea509d0", NULL, GIT_OBJ_ANY },
{ "dea509d09", "dea509d097ce692e167dfc6a48a7a280cc5e877e", GIT_OBJ_BLOB },
{ "dea509d0b", "dea509d0b3cb8ee0650f6ca210bc83f4678851ba", GIT_OBJ_BLOB },
{ "ce0136250", "ce013625030ba8dba906f756967f9e9ca394464a", GIT_OBJ_BLOB },
{ "0ddeaded", NULL, GIT_OBJ_ANY },
{ "4d5979b", "4d5979b468252190cb572ae758aca36928e8a91e", GIT_OBJ_TREE },
{ "0ddeaded", NULL, GIT_OBJ_ANY },
{ "0ddeadede", "0ddeadede9e6d6ccddce0ee1e5749eed0485e5ea", GIT_OBJ_BLOB },
{ "0ddeaded9", "0ddeaded9502971eefe1e41e34d0e536853ae20f", GIT_OBJ_BLOB },
{ "f00b4e", NULL, GIT_OBJ_ANY },
/* this OID is too short and should be ambiguous! */
{ "f00", NULL, GIT_OBJ_ANY },
/* some full-length object ids */
{ "0000000000000000000000000000000000000000", NULL, GIT_OBJ_ANY },
{
"dea509d097ce692e167dfc6a48a7a280cc5e877e",
"dea509d097ce692e167dfc6a48a7a280cc5e877e",
GIT_OBJ_BLOB
},
{ "f00f00f00f00f00f00f00f00f00f00f00f00f00f", NULL, GIT_OBJ_ANY },
{
"4d5979b468252190cb572ae758aca36928e8a91e",
"4d5979b468252190cb572ae758aca36928e8a91e",
GIT_OBJ_TREE
},
/*
* ensure we're not leaking the return error code for the
* last lookup if the last object is invalid
*/
{ "0ddeadedfff", NULL, GIT_OBJ_ANY },
};
static void setup_prefix_query(
git_odb_expand_id **out_ids,
size_t *out_num)
{
git_odb_expand_id *ids;
size_t num, i;
num = ARRAY_SIZE(expand_id_test_data);
cl_assert((ids = git__calloc(num, sizeof(git_odb_expand_id))));
for (i = 0; i < num; i++) {
git_odb_expand_id *id = &ids[i];
size_t len = strlen(expand_id_test_data[i].lookup_id);
git_oid_fromstrn(&id->id, expand_id_test_data[i].lookup_id, len);
id->length = (unsigned short)len;
id->type = expand_id_test_data[i].expected_type;
}
*out_ids = ids;
*out_num = num;
}
static void assert_found_objects(git_odb_expand_id *ids)
{
size_t num, i;
num = ARRAY_SIZE(expand_id_test_data);
for (i = 0; i < num; i++) {
git_oid expected_id = {{0}};
size_t expected_len = 0;
git_otype expected_type = 0;
if (expand_id_test_data[i].expected_id) {
git_oid_fromstr(&expected_id, expand_id_test_data[i].expected_id);
expected_len = GIT_OID_HEXSZ;
expected_type = expand_id_test_data[i].expected_type;
}
cl_assert_equal_oid(&expected_id, &ids[i].id);
cl_assert_equal_i(expected_len, ids[i].length);
cl_assert_equal_i(expected_type, ids[i].type);
}
}
static void assert_notfound_objects(git_odb_expand_id *ids)
{
git_oid expected_id = {{0}};
size_t num, i;
num = ARRAY_SIZE(expand_id_test_data);
for (i = 0; i < num; i++) {
cl_assert_equal_oid(&expected_id, &ids[i].id);
cl_assert_equal_i(0, ids[i].length);
cl_assert_equal_i(0, ids[i].type);
}
}
void test_odb_mixed__expand_ids(void)
{
git_odb_expand_id *ids;
size_t i, num;
/* test looking for the actual (correct) types */
setup_prefix_query(&ids, &num);
cl_git_pass(git_odb_expand_ids(_odb, ids, num));
assert_found_objects(ids);
git__free(ids);
/* test looking for an explicit `type == 0` */
setup_prefix_query(&ids, &num);
for (i = 0; i < num; i++)
ids[i].type = 0;
cl_git_pass(git_odb_expand_ids(_odb, ids, num));
assert_found_objects(ids);
git__free(ids);
/* test looking for an explicit GIT_OBJ_ANY */
setup_prefix_query(&ids, &num);
for (i = 0; i < num; i++)
ids[i].type = GIT_OBJ_ANY;
cl_git_pass(git_odb_expand_ids(_odb, ids, num));
assert_found_objects(ids);
git__free(ids);
/* test looking for the completely wrong type */
setup_prefix_query(&ids, &num);
for (i = 0; i < num; i++)
ids[i].type = (ids[i].type == GIT_OBJ_BLOB) ?
GIT_OBJ_TREE : GIT_OBJ_BLOB;
cl_git_pass(git_odb_expand_ids(_odb, ids, num));
assert_notfound_objects(ids);
git__free(ids);
}