summaryrefslogtreecommitdiff
path: root/t/unit-tests
diff options
context:
space:
mode:
Diffstat (limited to 't/unit-tests')
-rw-r--r--t/unit-tests/lib-oid.c32
-rw-r--r--t/unit-tests/lib-oid.h9
-rw-r--r--t/unit-tests/t-example-decorate.c74
-rw-r--r--t/unit-tests/t-oid-array.c126
-rw-r--r--t/unit-tests/t-oidmap.c181
-rw-r--r--t/unit-tests/t-oidtree.c122
-rw-r--r--t/unit-tests/t-reftable-stack.c54
-rw-r--r--t/unit-tests/t-strbuf.c122
-rw-r--r--t/unit-tests/t-strcmp-offset.c35
-rw-r--r--t/unit-tests/u-example-decorate.c64
-rw-r--r--t/unit-tests/u-hashmap.c (renamed from t/unit-tests/t-hashmap.c)226
-rw-r--r--t/unit-tests/u-oid-array.c129
-rw-r--r--t/unit-tests/u-oidmap.c136
-rw-r--r--t/unit-tests/u-oidtree.c107
-rw-r--r--t/unit-tests/u-strbuf.c119
-rw-r--r--t/unit-tests/u-strcmp-offset.c45
-rw-r--r--t/unit-tests/unit-test.c2
17 files changed, 782 insertions, 801 deletions
diff --git a/t/unit-tests/lib-oid.c b/t/unit-tests/lib-oid.c
index 8f0ccac532..e0b3180f23 100644
--- a/t/unit-tests/lib-oid.c
+++ b/t/unit-tests/lib-oid.c
@@ -1,9 +1,9 @@
-#include "test-lib.h"
+#include "unit-test.h"
#include "lib-oid.h"
#include "strbuf.h"
#include "hex.h"
-int init_hash_algo(void)
+int cl_setup_hash_algo(void)
{
static int algo = -1;
@@ -11,42 +11,32 @@ int init_hash_algo(void)
const char *algo_name = getenv("GIT_TEST_DEFAULT_HASH");
algo = algo_name ? hash_algo_by_name(algo_name) : GIT_HASH_SHA1;
- if (!check(algo != GIT_HASH_UNKNOWN))
- test_msg("BUG: invalid GIT_TEST_DEFAULT_HASH value ('%s')",
- algo_name);
+ cl_assert(algo != GIT_HASH_UNKNOWN);
}
return algo;
}
-static int get_oid_arbitrary_hex_algop(const char *hex, struct object_id *oid,
+static void cl_parse_oid(const char *hex, struct object_id *oid,
const struct git_hash_algo *algop)
{
- int ret;
size_t sz = strlen(hex);
struct strbuf buf = STRBUF_INIT;
- if (!check(sz <= algop->hexsz)) {
- test_msg("BUG: hex string (%s) bigger than maximum allowed (%lu)",
- hex, (unsigned long)algop->hexsz);
- return -1;
- }
+ cl_assert(sz <= algop->hexsz);
strbuf_add(&buf, hex, sz);
strbuf_addchars(&buf, '0', algop->hexsz - sz);
- ret = get_oid_hex_algop(buf.buf, oid, algop);
- if (!check_int(ret, ==, 0))
- test_msg("BUG: invalid hex input (%s) provided", hex);
+ cl_assert_equal_i(get_oid_hex_algop(buf.buf, oid, algop), 0);
strbuf_release(&buf);
- return ret;
}
-int get_oid_arbitrary_hex(const char *hex, struct object_id *oid)
+
+void cl_parse_any_oid(const char *hex, struct object_id *oid)
{
- int hash_algo = init_hash_algo();
+ int hash_algo = cl_setup_hash_algo();
- if (!check_int(hash_algo, !=, GIT_HASH_UNKNOWN))
- return -1;
- return get_oid_arbitrary_hex_algop(hex, oid, &hash_algos[hash_algo]);
+ cl_assert(hash_algo != GIT_HASH_UNKNOWN);
+ cl_parse_oid(hex, oid, &hash_algos[hash_algo]);
}
diff --git a/t/unit-tests/lib-oid.h b/t/unit-tests/lib-oid.h
index 4e77c04bd2..4031775104 100644
--- a/t/unit-tests/lib-oid.h
+++ b/t/unit-tests/lib-oid.h
@@ -5,6 +5,7 @@
/*
* Convert arbitrary hex string to object_id.
+ *
* For example, passing "abc12" will generate
* "abc1200000000000000000000000000000000000" hex of length 40 for SHA-1 and
* create object_id with that.
@@ -12,14 +13,16 @@
* algo is not allowed. The hash algo is decided based on GIT_TEST_DEFAULT_HASH
* environment variable.
*/
-int get_oid_arbitrary_hex(const char *s, struct object_id *oid);
+
+void cl_parse_any_oid (const char *s, struct object_id *oid);
/*
* Returns one of GIT_HASH_{SHA1, SHA256, UNKNOWN} based on the value of
* GIT_TEST_DEFAULT_HASH environment variable. The fallback value in the
* absence of GIT_TEST_DEFAULT_HASH is GIT_HASH_SHA1. It also uses
- * check(algo != GIT_HASH_UNKNOWN) before returning to verify if the
+ * cl_assert(algo != GIT_HASH_UNKNOWN) before returning to verify if the
* GIT_TEST_DEFAULT_HASH's value is valid or not.
*/
-int init_hash_algo(void);
+
+int cl_setup_hash_algo(void);
#endif /* LIB_OID_H */
diff --git a/t/unit-tests/t-example-decorate.c b/t/unit-tests/t-example-decorate.c
deleted file mode 100644
index bfc776e223..0000000000
--- a/t/unit-tests/t-example-decorate.c
+++ /dev/null
@@ -1,74 +0,0 @@
-#define USE_THE_REPOSITORY_VARIABLE
-
-#include "test-lib.h"
-#include "object.h"
-#include "decorate.h"
-#include "repository.h"
-
-struct test_vars {
- struct object *one, *two, *three;
- struct decoration n;
- int decoration_a, decoration_b;
-};
-
-static void t_add(struct test_vars *vars)
-{
- void *ret = add_decoration(&vars->n, vars->one, &vars->decoration_a);
-
- check(ret == NULL);
- ret = add_decoration(&vars->n, vars->two, NULL);
- check(ret == NULL);
-}
-
-static void t_readd(struct test_vars *vars)
-{
- void *ret = add_decoration(&vars->n, vars->one, NULL);
-
- check(ret == &vars->decoration_a);
- ret = add_decoration(&vars->n, vars->two, &vars->decoration_b);
- check(ret == NULL);
-}
-
-static void t_lookup(struct test_vars *vars)
-{
- void *ret = lookup_decoration(&vars->n, vars->one);
-
- check(ret == NULL);
- ret = lookup_decoration(&vars->n, vars->two);
- check(ret == &vars->decoration_b);
- ret = lookup_decoration(&vars->n, vars->three);
- check(ret == NULL);
-}
-
-static void t_loop(struct test_vars *vars)
-{
- int objects_noticed = 0;
-
- for (size_t i = 0; i < vars->n.size; i++) {
- if (vars->n.entries[i].base)
- objects_noticed++;
- }
- check_int(objects_noticed, ==, 2);
-}
-
-int cmd_main(int argc UNUSED, const char **argv UNUSED)
-{
- struct object_id one_oid = { { 1 } }, two_oid = { { 2 } }, three_oid = { { 3 } };
- struct test_vars vars = { 0 };
-
- vars.one = lookup_unknown_object(the_repository, &one_oid);
- vars.two = lookup_unknown_object(the_repository, &two_oid);
- vars.three = lookup_unknown_object(the_repository, &three_oid);
-
- TEST(t_add(&vars),
- "Add 2 objects, one with a non-NULL decoration and one with a NULL decoration.");
- TEST(t_readd(&vars),
- "When re-adding an already existing object, the old decoration is returned.");
- TEST(t_lookup(&vars),
- "Lookup returns the added declarations, or NULL if the object was never added.");
- TEST(t_loop(&vars), "The user can also loop through all entries.");
-
- clear_decoration(&vars.n, NULL);
-
- return test_done();
-}
diff --git a/t/unit-tests/t-oid-array.c b/t/unit-tests/t-oid-array.c
deleted file mode 100644
index 45b59a2a51..0000000000
--- a/t/unit-tests/t-oid-array.c
+++ /dev/null
@@ -1,126 +0,0 @@
-#define USE_THE_REPOSITORY_VARIABLE
-
-#include "test-lib.h"
-#include "lib-oid.h"
-#include "oid-array.h"
-#include "hex.h"
-
-static int fill_array(struct oid_array *array, const char *hexes[], size_t n)
-{
- for (size_t i = 0; i < n; i++) {
- struct object_id oid;
-
- if (!check_int(get_oid_arbitrary_hex(hexes[i], &oid), ==, 0))
- return -1;
- oid_array_append(array, &oid);
- }
- if (!check_uint(array->nr, ==, n))
- return -1;
- return 0;
-}
-
-static int add_to_oid_array(const struct object_id *oid, void *data)
-{
- struct oid_array *array = data;
-
- oid_array_append(array, oid);
- return 0;
-}
-
-static void t_enumeration(const char **input_args, size_t input_sz,
- const char **expect_args, size_t expect_sz)
-{
- struct oid_array input = OID_ARRAY_INIT, expect = OID_ARRAY_INIT,
- actual = OID_ARRAY_INIT;
- size_t i;
-
- if (fill_array(&input, input_args, input_sz))
- return;
- if (fill_array(&expect, expect_args, expect_sz))
- return;
-
- oid_array_for_each_unique(&input, add_to_oid_array, &actual);
- if (!check_uint(actual.nr, ==, expect.nr))
- return;
-
- for (i = 0; i < actual.nr; i++) {
- if (!check(oideq(&actual.oid[i], &expect.oid[i])))
- test_msg("expected: %s\n got: %s\n index: %" PRIuMAX,
- oid_to_hex(&expect.oid[i]), oid_to_hex(&actual.oid[i]),
- (uintmax_t)i);
- }
-
- oid_array_clear(&actual);
- oid_array_clear(&input);
- oid_array_clear(&expect);
-}
-
-#define TEST_ENUMERATION(input, expect, desc) \
- TEST(t_enumeration(input, ARRAY_SIZE(input), expect, ARRAY_SIZE(expect)), \
- desc " works")
-
-static void t_lookup(const char **input_hexes, size_t n, const char *query_hex,
- int lower_bound, int upper_bound)
-{
- struct oid_array array = OID_ARRAY_INIT;
- struct object_id oid_query;
- int ret;
-
- if (!check_int(get_oid_arbitrary_hex(query_hex, &oid_query), ==, 0))
- return;
- if (fill_array(&array, input_hexes, n))
- return;
- ret = oid_array_lookup(&array, &oid_query);
-
- if (!check_int(ret, <=, upper_bound) ||
- !check_int(ret, >=, lower_bound))
- test_msg("oid query for lookup: %s", oid_to_hex(&oid_query));
-
- oid_array_clear(&array);
-}
-
-#define TEST_LOOKUP(input_hexes, query, lower_bound, upper_bound, desc) \
- TEST(t_lookup(input_hexes, ARRAY_SIZE(input_hexes), query, \
- lower_bound, upper_bound), \
- desc " works")
-
-static void setup(void)
-{
- /* The hash algo is used by oid_array_lookup() internally */
- int algo = init_hash_algo();
- if (check_int(algo, !=, GIT_HASH_UNKNOWN))
- repo_set_hash_algo(the_repository, algo);
-}
-
-int cmd_main(int argc UNUSED, const char **argv UNUSED)
-{
- const char *arr_input[] = { "88", "44", "aa", "55" };
- const char *arr_input_dup[] = { "88", "44", "aa", "55",
- "88", "44", "aa", "55",
- "88", "44", "aa", "55" };
- const char *res_sorted[] = { "44", "55", "88", "aa" };
- const char *nearly_55;
-
- if (!TEST(setup(), "setup"))
- test_skip_all("hash algo initialization failed");
-
- TEST_ENUMERATION(arr_input, res_sorted, "ordered enumeration");
- TEST_ENUMERATION(arr_input_dup, res_sorted,
- "ordered enumeration with duplicate suppression");
-
- TEST_LOOKUP(arr_input, "55", 1, 1, "lookup");
- TEST_LOOKUP(arr_input, "33", INT_MIN, -1, "lookup non-existent entry");
- TEST_LOOKUP(arr_input_dup, "55", 3, 5, "lookup with duplicates");
- TEST_LOOKUP(arr_input_dup, "66", INT_MIN, -1,
- "lookup non-existent entry with duplicates");
-
- nearly_55 = init_hash_algo() == GIT_HASH_SHA1 ?
- "5500000000000000000000000000000000000001" :
- "5500000000000000000000000000000000000000000000000000000000000001";
- TEST_LOOKUP(((const char *[]){ "55", nearly_55 }), "55", 0, 0,
- "lookup with almost duplicate values");
- TEST_LOOKUP(((const char *[]){ "55", "55" }), "55", 0, 1,
- "lookup with single duplicate value");
-
- return test_done();
-}
diff --git a/t/unit-tests/t-oidmap.c b/t/unit-tests/t-oidmap.c
deleted file mode 100644
index b22e52d08b..0000000000
--- a/t/unit-tests/t-oidmap.c
+++ /dev/null
@@ -1,181 +0,0 @@
-#include "test-lib.h"
-#include "lib-oid.h"
-#include "oidmap.h"
-#include "hash.h"
-#include "hex.h"
-
-/*
- * Elements we will put in oidmap structs are made of a key: the entry.oid
- * field, which is of type struct object_id, and a value: the name field (could
- * be a refname for example).
- */
-struct test_entry {
- struct oidmap_entry entry;
- char name[FLEX_ARRAY];
-};
-
-static const char *const key_val[][2] = { { "11", "one" },
- { "22", "two" },
- { "33", "three" } };
-
-static void setup(void (*f)(struct oidmap *map))
-{
- struct oidmap map = OIDMAP_INIT;
- int ret = 0;
-
- for (size_t i = 0; i < ARRAY_SIZE(key_val); i++){
- struct test_entry *entry;
-
- FLEX_ALLOC_STR(entry, name, key_val[i][1]);
- if ((ret = get_oid_arbitrary_hex(key_val[i][0], &entry->entry.oid))) {
- free(entry);
- break;
- }
- entry = oidmap_put(&map, entry);
- if (!check(entry == NULL))
- free(entry);
- }
-
- if (!ret)
- f(&map);
- oidmap_free(&map, 1);
-}
-
-static void t_replace(struct oidmap *map)
-{
- struct test_entry *entry, *prev;
-
- FLEX_ALLOC_STR(entry, name, "un");
- if (get_oid_arbitrary_hex("11", &entry->entry.oid))
- return;
- prev = oidmap_put(map, entry);
- if (!check(prev != NULL))
- return;
- check_str(prev->name, "one");
- free(prev);
-
- FLEX_ALLOC_STR(entry, name, "deux");
- if (get_oid_arbitrary_hex("22", &entry->entry.oid))
- return;
- prev = oidmap_put(map, entry);
- if (!check(prev != NULL))
- return;
- check_str(prev->name, "two");
- free(prev);
-}
-
-static void t_get(struct oidmap *map)
-{
- struct test_entry *entry;
- struct object_id oid;
-
- if (get_oid_arbitrary_hex("22", &oid))
- return;
- entry = oidmap_get(map, &oid);
- if (!check(entry != NULL))
- return;
- check_str(entry->name, "two");
-
- if (get_oid_arbitrary_hex("44", &oid))
- return;
- check(oidmap_get(map, &oid) == NULL);
-
- if (get_oid_arbitrary_hex("11", &oid))
- return;
- entry = oidmap_get(map, &oid);
- if (!check(entry != NULL))
- return;
- check_str(entry->name, "one");
-}
-
-static void t_remove(struct oidmap *map)
-{
- struct test_entry *entry;
- struct object_id oid;
-
- if (get_oid_arbitrary_hex("11", &oid))
- return;
- entry = oidmap_remove(map, &oid);
- if (!check(entry != NULL))
- return;
- check_str(entry->name, "one");
- check(oidmap_get(map, &oid) == NULL);
- free(entry);
-
- if (get_oid_arbitrary_hex("22", &oid))
- return;
- entry = oidmap_remove(map, &oid);
- if (!check(entry != NULL))
- return;
- check_str(entry->name, "two");
- check(oidmap_get(map, &oid) == NULL);
- free(entry);
-
- if (get_oid_arbitrary_hex("44", &oid))
- return;
- check(oidmap_remove(map, &oid) == NULL);
-}
-
-static int key_val_contains(struct test_entry *entry, char seen[])
-{
- for (size_t i = 0; i < ARRAY_SIZE(key_val); i++) {
- struct object_id oid;
-
- if (get_oid_arbitrary_hex(key_val[i][0], &oid))
- return -1;
-
- if (oideq(&entry->entry.oid, &oid)) {
- if (seen[i])
- return 2;
- seen[i] = 1;
- return 0;
- }
- }
- return 1;
-}
-
-static void t_iterate(struct oidmap *map)
-{
- struct oidmap_iter iter;
- struct test_entry *entry;
- char seen[ARRAY_SIZE(key_val)] = { 0 };
- int count = 0;
-
- oidmap_iter_init(map, &iter);
- while ((entry = oidmap_iter_next(&iter))) {
- int ret;
- if (!check_int((ret = key_val_contains(entry, seen)), ==, 0)) {
- switch (ret) {
- case -1:
- break; /* error message handled by get_oid_arbitrary_hex() */
- case 1:
- test_msg("obtained entry was not given in the input\n"
- " name: %s\n oid: %s\n",
- entry->name, oid_to_hex(&entry->entry.oid));
- break;
- case 2:
- test_msg("duplicate entry detected\n"
- " name: %s\n oid: %s\n",
- entry->name, oid_to_hex(&entry->entry.oid));
- break;
- default:
- test_msg("BUG: invalid return value (%d) from key_val_contains()",
- ret);
- break;
- }
- } else {
- count++;
- }
- }
- check_int(count, ==, ARRAY_SIZE(key_val));
- check_int(hashmap_get_size(&map->map), ==, ARRAY_SIZE(key_val));
-}
-
-int cmd_main(int argc UNUSED, const char **argv UNUSED)
-{
- TEST(setup(t_replace), "replace works");
- TEST(setup(t_get), "get works");
- TEST(setup(t_remove), "remove works");
- TEST(setup(t_iterate), "iterate works");
- return test_done();
-}
diff --git a/t/unit-tests/t-oidtree.c b/t/unit-tests/t-oidtree.c
deleted file mode 100644
index a38754b066..0000000000
--- a/t/unit-tests/t-oidtree.c
+++ /dev/null
@@ -1,122 +0,0 @@
-#include "test-lib.h"
-#include "lib-oid.h"
-#include "oidtree.h"
-#include "hash.h"
-#include "hex.h"
-#include "strvec.h"
-
-#define FILL_TREE(tree, ...) \
- do { \
- const char *hexes[] = { __VA_ARGS__ }; \
- if (fill_tree_loc(tree, hexes, ARRAY_SIZE(hexes))) \
- return; \
- } while (0)
-
-static int fill_tree_loc(struct oidtree *ot, const char *hexes[], size_t n)
-{
- for (size_t i = 0; i < n; i++) {
- struct object_id oid;
- if (!check_int(get_oid_arbitrary_hex(hexes[i], &oid), ==, 0))
- return -1;
- oidtree_insert(ot, &oid);
- }
- return 0;
-}
-
-static void check_contains(struct oidtree *ot, const char *hex, int expected)
-{
- struct object_id oid;
-
- if (!check_int(get_oid_arbitrary_hex(hex, &oid), ==, 0))
- return;
- if (!check_int(oidtree_contains(ot, &oid), ==, expected))
- test_msg("oid: %s", oid_to_hex(&oid));
-}
-
-struct expected_hex_iter {
- size_t i;
- struct strvec expected_hexes;
- const char *query;
-};
-
-static enum cb_next check_each_cb(const struct object_id *oid, void *data)
-{
- struct expected_hex_iter *hex_iter = data;
- struct object_id expected;
-
- if (!check_int(hex_iter->i, <, hex_iter->expected_hexes.nr)) {
- test_msg("error: extraneous callback for query: ('%s'), object_id: ('%s')",
- hex_iter->query, oid_to_hex(oid));
- return CB_BREAK;
- }
-
- if (!check_int(get_oid_arbitrary_hex(hex_iter->expected_hexes.v[hex_iter->i],
- &expected), ==, 0))
- ; /* the data is bogus and cannot be used */
- else if (!check(oideq(oid, &expected)))
- test_msg("expected: %s\n got: %s\n query: %s",
- oid_to_hex(&expected), oid_to_hex(oid), hex_iter->query);
-
- hex_iter->i += 1;
- return CB_CONTINUE;
-}
-
-LAST_ARG_MUST_BE_NULL
-static void check_each(struct oidtree *ot, const char *query, ...)
-{
- struct object_id oid;
- struct expected_hex_iter hex_iter = { .expected_hexes = STRVEC_INIT,
- .query = query };
- const char *arg;
- va_list hex_args;
-
- va_start(hex_args, query);
- while ((arg = va_arg(hex_args, const char *)))
- strvec_push(&hex_iter.expected_hexes, arg);
- va_end(hex_args);
-
- if (!check_int(get_oid_arbitrary_hex(query, &oid), ==, 0))
- return;
- oidtree_each(ot, &oid, strlen(query), check_each_cb, &hex_iter);
-
- if (!check_int(hex_iter.i, ==, hex_iter.expected_hexes.nr))
- test_msg("error: could not find some 'object_id's for query ('%s')", query);
- strvec_clear(&hex_iter.expected_hexes);
-}
-
-static void setup(void (*f)(struct oidtree *ot))
-{
- struct oidtree ot;
-
- oidtree_init(&ot);
- f(&ot);
- oidtree_clear(&ot);
-}
-
-static void t_contains(struct oidtree *ot)
-{
- FILL_TREE(ot, "444", "1", "2", "3", "4", "5", "a", "b", "c", "d", "e");
- check_contains(ot, "44", 0);
- check_contains(ot, "441", 0);
- check_contains(ot, "440", 0);
- check_contains(ot, "444", 1);
- check_contains(ot, "4440", 1);
- check_contains(ot, "4444", 0);
-}
-
-static void t_each(struct oidtree *ot)
-{
- FILL_TREE(ot, "f", "9", "8", "123", "321", "320", "a", "b", "c", "d", "e");
- check_each(ot, "12300", "123", NULL);
- check_each(ot, "3211", NULL); /* should not reach callback */
- check_each(ot, "3210", "321", NULL);
- check_each(ot, "32100", "321", NULL);
- check_each(ot, "32", "320", "321", NULL);
-}
-
-int cmd_main(int argc UNUSED, const char **argv UNUSED)
-{
- TEST(setup(t_contains), "oidtree insert and contains works");
- TEST(setup(t_each), "oidtree each works");
- return test_done();
-}
diff --git a/t/unit-tests/t-reftable-stack.c b/t/unit-tests/t-reftable-stack.c
index aeec195b2b..c3f0059c34 100644
--- a/t/unit-tests/t-reftable-stack.c
+++ b/t/unit-tests/t-reftable-stack.c
@@ -103,7 +103,8 @@ static void t_read_file(void)
static int write_test_ref(struct reftable_writer *wr, void *arg)
{
struct reftable_ref_record *ref = arg;
- reftable_writer_set_limits(wr, ref->update_index, ref->update_index);
+ check(!reftable_writer_set_limits(wr, ref->update_index,
+ ref->update_index));
return reftable_writer_add_ref(wr, ref);
}
@@ -143,7 +144,8 @@ static int write_test_log(struct reftable_writer *wr, void *arg)
{
struct write_log_arg *wla = arg;
- reftable_writer_set_limits(wr, wla->update_index, wla->update_index);
+ check(!reftable_writer_set_limits(wr, wla->update_index,
+ wla->update_index));
return reftable_writer_add_log(wr, wla->log);
}
@@ -961,7 +963,7 @@ static void t_reflog_expire(void)
static int write_nothing(struct reftable_writer *wr, void *arg UNUSED)
{
- reftable_writer_set_limits(wr, 1, 1);
+ check(!reftable_writer_set_limits(wr, 1, 1));
return 0;
}
@@ -1369,11 +1371,57 @@ static void t_reftable_stack_reload_with_missing_table(void)
clear_dir(dir);
}
+static int write_limits_after_ref(struct reftable_writer *wr, void *arg)
+{
+ struct reftable_ref_record *ref = arg;
+ check(!reftable_writer_set_limits(wr, ref->update_index, ref->update_index));
+ check(!reftable_writer_add_ref(wr, ref));
+ return reftable_writer_set_limits(wr, ref->update_index, ref->update_index);
+}
+
+static void t_reftable_invalid_limit_updates(void)
+{
+ struct reftable_ref_record ref = {
+ .refname = (char *) "HEAD",
+ .update_index = 1,
+ .value_type = REFTABLE_REF_SYMREF,
+ .value.symref = (char *) "master",
+ };
+ struct reftable_write_options opts = {
+ .default_permissions = 0660,
+ };
+ struct reftable_addition *add = NULL;
+ char *dir = get_tmp_dir(__LINE__);
+ struct reftable_stack *st = NULL;
+ int err;
+
+ err = reftable_new_stack(&st, dir, &opts);
+ check(!err);
+
+ reftable_addition_destroy(add);
+
+ err = reftable_stack_new_addition(&add, st, 0);
+ check(!err);
+
+ /*
+ * write_limits_after_ref also updates the update indexes after adding
+ * the record. This should cause an err to be returned, since the limits
+ * must be set at the start.
+ */
+ err = reftable_addition_add(add, write_limits_after_ref, &ref);
+ check_int(err, ==, REFTABLE_API_ERROR);
+
+ reftable_addition_destroy(add);
+ reftable_stack_destroy(st);
+ clear_dir(dir);
+}
+
int cmd_main(int argc UNUSED, const char *argv[] UNUSED)
{
TEST(t_empty_add(), "empty addition to stack");
TEST(t_read_file(), "read_lines works");
TEST(t_reflog_expire(), "expire reflog entries");
+ TEST(t_reftable_invalid_limit_updates(), "prevent limit updates after adding records");
TEST(t_reftable_stack_add(), "add multiple refs and logs to stack");
TEST(t_reftable_stack_add_one(), "add a single ref record to stack");
TEST(t_reftable_stack_add_performs_auto_compaction(), "addition to stack triggers auto-compaction");
diff --git a/t/unit-tests/t-strbuf.c b/t/unit-tests/t-strbuf.c
deleted file mode 100644
index 3f4044d697..0000000000
--- a/t/unit-tests/t-strbuf.c
+++ /dev/null
@@ -1,122 +0,0 @@
-#include "test-lib.h"
-#include "strbuf.h"
-
-/* wrapper that supplies tests with an empty, initialized strbuf */
-static void setup(void (*f)(struct strbuf*, const void*),
- const void *data)
-{
- struct strbuf buf = STRBUF_INIT;
-
- f(&buf, data);
- strbuf_release(&buf);
- check_uint(buf.len, ==, 0);
- check_uint(buf.alloc, ==, 0);
-}
-
-/* wrapper that supplies tests with a populated, initialized strbuf */
-static void setup_populated(void (*f)(struct strbuf*, const void*),
- const char *init_str, const void *data)
-{
- struct strbuf buf = STRBUF_INIT;
-
- strbuf_addstr(&buf, init_str);
- check_uint(buf.len, ==, strlen(init_str));
- f(&buf, data);
- strbuf_release(&buf);
- check_uint(buf.len, ==, 0);
- check_uint(buf.alloc, ==, 0);
-}
-
-static int assert_sane_strbuf(struct strbuf *buf)
-{
- /* Initialized strbufs should always have a non-NULL buffer */
- if (!check(!!buf->buf))
- return 0;
- /* Buffers should always be NUL-terminated */
- if (!check_char(buf->buf[buf->len], ==, '\0'))
- return 0;
- /*
- * Freshly-initialized strbufs may not have a dynamically allocated
- * buffer
- */
- if (buf->len == 0 && buf->alloc == 0)
- return 1;
- /* alloc must be at least one byte larger than len */
- return check_uint(buf->len, <, buf->alloc);
-}
-
-static void t_static_init(void)
-{
- struct strbuf buf = STRBUF_INIT;
-
- check_uint(buf.len, ==, 0);
- check_uint(buf.alloc, ==, 0);
- check_char(buf.buf[0], ==, '\0');
-}
-
-static void t_dynamic_init(void)
-{
- struct strbuf buf;
-
- strbuf_init(&buf, 1024);
- check(assert_sane_strbuf(&buf));
- check_uint(buf.len, ==, 0);
- check_uint(buf.alloc, >=, 1024);
- check_char(buf.buf[0], ==, '\0');
- strbuf_release(&buf);
-}
-
-static void t_addch(struct strbuf *buf, const void *data)
-{
- const char *p_ch = data;
- const char ch = *p_ch;
- size_t orig_alloc = buf->alloc;
- size_t orig_len = buf->len;
-
- if (!check(assert_sane_strbuf(buf)))
- return;
- strbuf_addch(buf, ch);
- if (!check(assert_sane_strbuf(buf)))
- return;
- if (!(check_uint(buf->len, ==, orig_len + 1) &&
- check_uint(buf->alloc, >=, orig_alloc)))
- return; /* avoid de-referencing buf->buf */
- check_char(buf->buf[buf->len - 1], ==, ch);
- check_char(buf->buf[buf->len], ==, '\0');
-}
-
-static void t_addstr(struct strbuf *buf, const void *data)
-{
- const char *text = data;
- size_t len = strlen(text);
- size_t orig_alloc = buf->alloc;
- size_t orig_len = buf->len;
-
- if (!check(assert_sane_strbuf(buf)))
- return;
- strbuf_addstr(buf, text);
- if (!check(assert_sane_strbuf(buf)))
- return;
- if (!(check_uint(buf->len, ==, orig_len + len) &&
- check_uint(buf->alloc, >=, orig_alloc) &&
- check_uint(buf->alloc, >, orig_len + len) &&
- check_char(buf->buf[orig_len + len], ==, '\0')))
- return;
- check_str(buf->buf + orig_len, text);
-}
-
-int cmd_main(int argc UNUSED, const char **argv UNUSED)
-{
- if (!TEST(t_static_init(), "static initialization works"))
- test_skip_all("STRBUF_INIT is broken");
- TEST(t_dynamic_init(), "dynamic initialization works");
- TEST(setup(t_addch, "a"), "strbuf_addch adds char");
- TEST(setup(t_addch, ""), "strbuf_addch adds NUL char");
- TEST(setup_populated(t_addch, "initial value", "a"),
- "strbuf_addch appends to initial value");
- TEST(setup(t_addstr, "hello there"), "strbuf_addstr adds string");
- TEST(setup_populated(t_addstr, "initial value", "hello there"),
- "strbuf_addstr appends string to initial value");
-
- return test_done();
-}
diff --git a/t/unit-tests/t-strcmp-offset.c b/t/unit-tests/t-strcmp-offset.c
deleted file mode 100644
index 6880f21161..0000000000
--- a/t/unit-tests/t-strcmp-offset.c
+++ /dev/null
@@ -1,35 +0,0 @@
-#include "test-lib.h"
-#include "read-cache-ll.h"
-
-static void check_strcmp_offset(const char *string1, const char *string2,
- int expect_result, uintmax_t expect_offset)
-{
- size_t offset;
- int result = strcmp_offset(string1, string2, &offset);
-
- /*
- * Because different CRTs behave differently, only rely on signs of the
- * result values.
- */
- result = (result < 0 ? -1 :
- result > 0 ? 1 :
- 0);
-
- check_int(result, ==, expect_result);
- check_uint((uintmax_t)offset, ==, expect_offset);
-}
-
-#define TEST_STRCMP_OFFSET(string1, string2, expect_result, expect_offset) \
- TEST(check_strcmp_offset(string1, string2, expect_result, \
- expect_offset), \
- "strcmp_offset(%s, %s) works", #string1, #string2)
-
-int cmd_main(int argc UNUSED, const char **argv UNUSED)
-{
- TEST_STRCMP_OFFSET("abc", "abc", 0, 3);
- TEST_STRCMP_OFFSET("abc", "def", -1, 0);
- TEST_STRCMP_OFFSET("abc", "abz", -1, 2);
- TEST_STRCMP_OFFSET("abc", "abcdef", -1, 3);
-
- return test_done();
-}
diff --git a/t/unit-tests/u-example-decorate.c b/t/unit-tests/u-example-decorate.c
new file mode 100644
index 0000000000..9b1d1ce753
--- /dev/null
+++ b/t/unit-tests/u-example-decorate.c
@@ -0,0 +1,64 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
+#include "unit-test.h"
+#include "object.h"
+#include "decorate.h"
+#include "repository.h"
+
+struct test_vars {
+ struct object *one, *two, *three;
+ struct decoration n;
+ int decoration_a, decoration_b;
+};
+
+static struct test_vars vars;
+
+void test_example_decorate__initialize(void)
+{
+ struct object_id one_oid = { { 1 } }, two_oid = { { 2 } }, three_oid = { { 3 } };
+
+ vars.one = lookup_unknown_object(the_repository, &one_oid);
+ vars.two = lookup_unknown_object(the_repository, &two_oid);
+ vars.three = lookup_unknown_object(the_repository, &three_oid);
+}
+
+void test_example_decorate__cleanup(void)
+{
+ clear_decoration(&vars.n, NULL);
+}
+
+void test_example_decorate__add(void)
+{
+ cl_assert_equal_p(add_decoration(&vars.n, vars.one, &vars.decoration_a), NULL);
+ cl_assert_equal_p(add_decoration(&vars.n, vars.two, NULL), NULL);
+}
+
+void test_example_decorate__readd(void)
+{
+ cl_assert_equal_p(add_decoration(&vars.n, vars.one, &vars.decoration_a), NULL);
+ cl_assert_equal_p(add_decoration(&vars.n, vars.two, NULL), NULL);
+ cl_assert_equal_p(add_decoration(&vars.n, vars.one, NULL), &vars.decoration_a);
+ cl_assert_equal_p(add_decoration(&vars.n, vars.two, &vars.decoration_b), NULL);
+}
+
+void test_example_decorate__lookup(void)
+{
+ cl_assert_equal_p(add_decoration(&vars.n, vars.two, &vars.decoration_b), NULL);
+ cl_assert_equal_p(add_decoration(&vars.n, vars.one, NULL), NULL);
+ cl_assert_equal_p(lookup_decoration(&vars.n, vars.two), &vars.decoration_b);
+ cl_assert_equal_p(lookup_decoration(&vars.n, vars.one), NULL);
+}
+
+void test_example_decorate__loop(void)
+{
+ int objects_noticed = 0;
+
+ cl_assert_equal_p(add_decoration(&vars.n, vars.one, &vars.decoration_a), NULL);
+ cl_assert_equal_p(add_decoration(&vars.n, vars.two, &vars.decoration_b), NULL);
+
+ for (size_t i = 0; i < vars.n.size; i++)
+ if (vars.n.entries[i].base)
+ objects_noticed++;
+
+ cl_assert_equal_i(objects_noticed, 2);
+}
diff --git a/t/unit-tests/t-hashmap.c b/t/unit-tests/u-hashmap.c
index 83b79dff39..eb80aa1348 100644
--- a/t/unit-tests/t-hashmap.c
+++ b/t/unit-tests/u-hashmap.c
@@ -1,4 +1,4 @@
-#include "test-lib.h"
+#include "unit-test.h"
#include "hashmap.h"
#include "strbuf.h"
@@ -83,23 +83,23 @@ static void t_replace(struct hashmap *map, unsigned int ignore_case)
struct test_entry *entry;
entry = alloc_test_entry("key1", "value1", ignore_case);
- check_pointer_eq(hashmap_put_entry(map, entry, ent), NULL);
+ cl_assert_equal_p(hashmap_put_entry(map, entry, ent), NULL);
entry = alloc_test_entry(ignore_case ? "Key1" : "key1", "value2",
ignore_case);
entry = hashmap_put_entry(map, entry, ent);
- if (check(entry != NULL))
- check_str(get_value(entry), "value1");
+ cl_assert(entry != NULL);
+ cl_assert_equal_s(get_value(entry), "value1");
free(entry);
entry = alloc_test_entry("fooBarFrotz", "value3", ignore_case);
- check_pointer_eq(hashmap_put_entry(map, entry, ent), NULL);
+ cl_assert_equal_p(hashmap_put_entry(map, entry, ent), NULL);
entry = alloc_test_entry(ignore_case ? "FOObarFrotz" : "fooBarFrotz",
"value4", ignore_case);
entry = hashmap_put_entry(map, entry, ent);
- if (check(entry != NULL))
- check_str(get_value(entry), "value3");
+ cl_assert(entry != NULL);
+ cl_assert_equal_s(get_value(entry), "value3");
free(entry);
}
@@ -122,20 +122,18 @@ static void t_get(struct hashmap *map, unsigned int ignore_case)
for (size_t i = 0; i < ARRAY_SIZE(key_val); i++) {
entry = alloc_test_entry(key_val[i][0], key_val[i][1],
ignore_case);
- check_pointer_eq(hashmap_put_entry(map, entry, ent), NULL);
+ cl_assert_equal_p(hashmap_put_entry(map, entry, ent), NULL);
}
for (size_t i = 0; i < ARRAY_SIZE(query); i++) {
entry = get_test_entry(map, query[i][0], ignore_case);
- if (check(entry != NULL))
- check_str(get_value(entry), query[i][1]);
- else
- test_msg("query key: %s", query[i][0]);
+ cl_assert(entry != NULL);
+ cl_assert_equal_s(get_value(entry), query[i][1]);
}
- check_pointer_eq(get_test_entry(map, "notInMap", ignore_case), NULL);
- check_int(map->tablesize, ==, 64);
- check_int(hashmap_get_size(map), ==, ARRAY_SIZE(key_val));
+ cl_assert_equal_p(get_test_entry(map, "notInMap", ignore_case), NULL);
+ cl_assert_equal_i(map->tablesize, 64);
+ cl_assert_equal_i(hashmap_get_size(map), ARRAY_SIZE(key_val));
}
static void t_add(struct hashmap *map, unsigned int ignore_case)
@@ -165,39 +163,19 @@ static void t_add(struct hashmap *map, unsigned int ignore_case)
hashmap_for_each_entry_from(map, entry, ent)
{
- int ret;
- if (!check_int((ret = key_val_contains(
- key_val, seen,
- ARRAY_SIZE(key_val), entry)),
- ==, 0)) {
- switch (ret) {
- case 1:
- test_msg("found entry was not given in the input\n"
- " key: %s\n value: %s",
- entry->key, get_value(entry));
- break;
- case 2:
- test_msg("duplicate entry detected\n"
- " key: %s\n value: %s",
- entry->key, get_value(entry));
- break;
- }
- } else {
- count++;
- }
+ int ret = key_val_contains(key_val, seen,
+ ARRAY_SIZE(key_val), entry);
+ cl_assert_equal_i(ret, 0);
+ count++;
}
- check_int(count, ==, 2);
+ cl_assert_equal_i(count, 2);
}
- for (size_t i = 0; i < ARRAY_SIZE(seen); i++) {
- if (!check_int(seen[i], ==, 1))
- test_msg("following key-val pair was not iterated over:\n"
- " key: %s\n value: %s",
- key_val[i][0], key_val[i][1]);
- }
+ for (size_t i = 0; i < ARRAY_SIZE(seen); i++)
+ cl_assert_equal_i(seen[i], 1);
- check_int(hashmap_get_size(map), ==, ARRAY_SIZE(key_val));
- check_pointer_eq(get_test_entry(map, "notInMap", ignore_case), NULL);
+ cl_assert_equal_i(hashmap_get_size(map), ARRAY_SIZE(key_val));
+ cl_assert_equal_p(get_test_entry(map, "notInMap", ignore_case), NULL);
}
static void t_remove(struct hashmap *map, unsigned int ignore_case)
@@ -211,24 +189,25 @@ static void t_remove(struct hashmap *map, unsigned int ignore_case)
for (size_t i = 0; i < ARRAY_SIZE(key_val); i++) {
entry = alloc_test_entry(key_val[i][0], key_val[i][1], ignore_case);
- check_pointer_eq(hashmap_put_entry(map, entry, ent), NULL);
+ cl_assert_equal_p(hashmap_put_entry(map, entry, ent), NULL);
}
for (size_t i = 0; i < ARRAY_SIZE(remove); i++) {
entry = alloc_test_entry(remove[i][0], "", ignore_case);
removed = hashmap_remove_entry(map, entry, ent, remove[i][0]);
- if (check(removed != NULL))
- check_str(get_value(removed), remove[i][1]);
+ cl_assert(removed != NULL);
+ cl_assert_equal_s(get_value(removed), remove[i][1]);
free(entry);
free(removed);
}
entry = alloc_test_entry("notInMap", "", ignore_case);
- check_pointer_eq(hashmap_remove_entry(map, entry, ent, "notInMap"), NULL);
+ cl_assert_equal_p(hashmap_remove_entry(map, entry, ent, "notInMap"), NULL);
free(entry);
- check_int(map->tablesize, ==, 64);
- check_int(hashmap_get_size(map), ==, ARRAY_SIZE(key_val) - ARRAY_SIZE(remove));
+ cl_assert_equal_i(map->tablesize, 64);
+ cl_assert_equal_i(hashmap_get_size(map),
+ ARRAY_SIZE(key_val) - ARRAY_SIZE(remove));
}
static void t_iterate(struct hashmap *map, unsigned int ignore_case)
@@ -242,38 +221,21 @@ static void t_iterate(struct hashmap *map, unsigned int ignore_case)
for (size_t i = 0; i < ARRAY_SIZE(key_val); i++) {
entry = alloc_test_entry(key_val[i][0], key_val[i][1], ignore_case);
- check_pointer_eq(hashmap_put_entry(map, entry, ent), NULL);
+ cl_assert_equal_p(hashmap_put_entry(map, entry, ent), NULL);
}
hashmap_for_each_entry(map, &iter, entry, ent /* member name */)
{
- int ret;
- if (!check_int((ret = key_val_contains(key_val, seen,
- ARRAY_SIZE(key_val),
- entry)), ==, 0)) {
- switch (ret) {
- case 1:
- test_msg("found entry was not given in the input\n"
- " key: %s\n value: %s",
- entry->key, get_value(entry));
- break;
- case 2:
- test_msg("duplicate entry detected\n"
- " key: %s\n value: %s",
- entry->key, get_value(entry));
- break;
- }
- }
+ int ret = key_val_contains(key_val, seen,
+ ARRAY_SIZE(key_val),
+ entry);
+ cl_assert(ret == 0);
}
- for (size_t i = 0; i < ARRAY_SIZE(seen); i++) {
- if (!check_int(seen[i], ==, 1))
- test_msg("following key-val pair was not iterated over:\n"
- " key: %s\n value: %s",
- key_val[i][0], key_val[i][1]);
- }
+ for (size_t i = 0; i < ARRAY_SIZE(seen); i++)
+ cl_assert_equal_i(seen[i], 1);
- check_int(hashmap_get_size(map), ==, ARRAY_SIZE(key_val));
+ cl_assert_equal_i(hashmap_get_size(map), ARRAY_SIZE(key_val));
}
static void t_alloc(struct hashmap *map, unsigned int ignore_case)
@@ -284,17 +246,17 @@ static void t_alloc(struct hashmap *map, unsigned int ignore_case)
char *key = xstrfmt("key%d", i);
char *value = xstrfmt("value%d", i);
entry = alloc_test_entry(key, value, ignore_case);
- check_pointer_eq(hashmap_put_entry(map, entry, ent), NULL);
+ cl_assert_equal_p(hashmap_put_entry(map, entry, ent), NULL);
free(key);
free(value);
}
- check_int(map->tablesize, ==, 64);
- check_int(hashmap_get_size(map), ==, 51);
+ cl_assert_equal_i(map->tablesize, 64);
+ cl_assert_equal_i(hashmap_get_size(map), 51);
entry = alloc_test_entry("key52", "value52", ignore_case);
- check_pointer_eq(hashmap_put_entry(map, entry, ent), NULL);
- check_int(map->tablesize, ==, 256);
- check_int(hashmap_get_size(map), ==, 52);
+ cl_assert_equal_p(hashmap_put_entry(map, entry, ent), NULL);
+ cl_assert_equal_i(map->tablesize, 256);
+ cl_assert_equal_i(hashmap_get_size(map), 52);
for (int i = 1; i <= 12; i++) {
char *key = xstrfmt("key%d", i);
@@ -302,27 +264,27 @@ static void t_alloc(struct hashmap *map, unsigned int ignore_case)
entry = alloc_test_entry(key, "", ignore_case);
removed = hashmap_remove_entry(map, entry, ent, key);
- if (check(removed != NULL))
- check_str(value, get_value(removed));
+ cl_assert(removed != NULL);
+ cl_assert_equal_s(value, get_value(removed));
free(key);
free(value);
free(entry);
free(removed);
}
- check_int(map->tablesize, ==, 256);
- check_int(hashmap_get_size(map), ==, 40);
+ cl_assert_equal_i(map->tablesize, 256);
+ cl_assert_equal_i(hashmap_get_size(map), 40);
entry = alloc_test_entry("key40", "", ignore_case);
removed = hashmap_remove_entry(map, entry, ent, "key40");
- if (check(removed != NULL))
- check_str("value40", get_value(removed));
- check_int(map->tablesize, ==, 64);
- check_int(hashmap_get_size(map), ==, 39);
+ cl_assert(removed != NULL);
+ cl_assert_equal_s("value40", get_value(removed));
+ cl_assert_equal_i(map->tablesize, 64);
+ cl_assert_equal_i(hashmap_get_size(map), 39);
free(entry);
free(removed);
}
-static void t_intern(void)
+void test_hashmap__intern(void)
{
const char *values[] = { "value1", "Value1", "value2", "value2" };
@@ -330,32 +292,68 @@ static void t_intern(void)
const char *i1 = strintern(values[i]);
const char *i2 = strintern(values[i]);
- if (!check(!strcmp(i1, values[i])))
- test_msg("strintern(%s) returns %s\n", values[i], i1);
- else if (!check(i1 != values[i]))
- test_msg("strintern(%s) returns input pointer\n",
- values[i]);
- else if (!check_pointer_eq(i1, i2))
- test_msg("address('%s') != address('%s'), so strintern('%s') != strintern('%s')",
- i1, i2, values[i], values[i]);
- else
- check_str(i1, values[i]);
+ cl_assert_equal_s(i1, values[i]);
+ cl_assert(i1 != values[i]);
+ cl_assert_equal_p(i1, i2);
}
}
-int cmd_main(int argc UNUSED, const char **argv UNUSED)
+void test_hashmap__replace_case_sensitive(void)
+{
+ setup(t_replace, 0);
+}
+
+void test_hashmap__replace_case_insensitive(void)
+{
+ setup(t_replace, 1);
+}
+
+void test_hashmap__get_case_sensitive(void)
+{
+ setup(t_get, 0);
+}
+
+void test_hashmap__get_case_insensitive(void)
+{
+ setup(t_get, 1);
+}
+
+void test_hashmap__add_case_sensitive(void)
+{
+ setup(t_add, 0);
+}
+
+void test_hashmap__add_case_insensitive(void)
+{
+ setup(t_add, 1);
+}
+
+void test_hashmap__remove_case_sensitive(void)
+{
+ setup(t_remove, 0);
+}
+
+void test_hashmap__remove_case_insensitive(void)
+{
+ setup(t_remove, 1);
+}
+
+void test_hashmap__iterate_case_sensitive(void)
+{
+ setup(t_iterate, 0);
+}
+
+void test_hashmap__iterate_case_insensitive(void)
+{
+ setup(t_iterate, 1);
+}
+
+void test_hashmap__alloc_case_sensitive(void)
+{
+ setup(t_alloc, 0);
+}
+
+void test_hashmap__alloc_case_insensitive(void)
{
- TEST(setup(t_replace, 0), "replace works");
- TEST(setup(t_replace, 1), "replace (case insensitive) works");
- TEST(setup(t_get, 0), "get works");
- TEST(setup(t_get, 1), "get (case insensitive) works");
- TEST(setup(t_add, 0), "add works");
- TEST(setup(t_add, 1), "add (case insensitive) works");
- TEST(setup(t_remove, 0), "remove works");
- TEST(setup(t_remove, 1), "remove (case insensitive) works");
- TEST(setup(t_iterate, 0), "iterate works");
- TEST(setup(t_iterate, 1), "iterate (case insensitive) works");
- TEST(setup(t_alloc, 0), "grow / shrink works");
- TEST(t_intern(), "string interning works");
- return test_done();
+ setup(t_alloc, 1);
}
diff --git a/t/unit-tests/u-oid-array.c b/t/unit-tests/u-oid-array.c
new file mode 100644
index 0000000000..e48a433f21
--- /dev/null
+++ b/t/unit-tests/u-oid-array.c
@@ -0,0 +1,129 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
+#include "unit-test.h"
+#include "lib-oid.h"
+#include "oid-array.h"
+#include "hex.h"
+
+static void fill_array(struct oid_array *array, const char *hexes[], size_t n)
+{
+ for (size_t i = 0; i < n; i++) {
+ struct object_id oid;
+
+ cl_parse_any_oid(hexes[i], &oid);
+ oid_array_append(array, &oid);
+ }
+ cl_assert_equal_i(array->nr, n);
+}
+
+static int add_to_oid_array(const struct object_id *oid, void *data)
+{
+ struct oid_array *array = data;
+
+ oid_array_append(array, oid);
+ return 0;
+}
+
+static void t_enumeration(const char **input_args, size_t input_sz,
+ const char **expect_args, size_t expect_sz)
+{
+ struct oid_array input = OID_ARRAY_INIT, expect = OID_ARRAY_INIT,
+ actual = OID_ARRAY_INIT;
+ size_t i;
+
+ fill_array(&input, input_args, input_sz);
+ fill_array(&expect, expect_args, expect_sz);
+
+ oid_array_for_each_unique(&input, add_to_oid_array, &actual);
+ cl_assert_equal_i(actual.nr, expect.nr);
+
+ for (i = 0; i < actual.nr; i++)
+ cl_assert(oideq(&actual.oid[i], &expect.oid[i]));
+
+ oid_array_clear(&actual);
+ oid_array_clear(&input);
+ oid_array_clear(&expect);
+}
+
+#define TEST_ENUMERATION(input, expect) \
+ t_enumeration(input, ARRAY_SIZE(input), expect, ARRAY_SIZE(expect));
+
+static void t_lookup(const char **input_hexes, size_t n, const char *query_hex,
+ int lower_bound, int upper_bound)
+{
+ struct oid_array array = OID_ARRAY_INIT;
+ struct object_id oid_query;
+ int ret;
+
+ cl_parse_any_oid(query_hex, &oid_query);
+ fill_array(&array, input_hexes, n);
+ ret = oid_array_lookup(&array, &oid_query);
+
+ cl_assert(ret <= upper_bound);
+ cl_assert(ret >= lower_bound);
+
+ oid_array_clear(&array);
+}
+
+#define TEST_LOOKUP(input_hexes, query, lower_bound, upper_bound) \
+ t_lookup(input_hexes, ARRAY_SIZE(input_hexes), query, \
+ lower_bound, upper_bound);
+
+void test_oid_array__initialize(void)
+{
+ /* The hash algo is used by oid_array_lookup() internally */
+ int algo = cl_setup_hash_algo();
+ repo_set_hash_algo(the_repository, algo);
+}
+
+static const char *arr_input[] = { "88", "44", "aa", "55" };
+static const char *arr_input_dup[] = { "88", "44", "aa", "55",
+ "88", "44", "aa", "55",
+ "88", "44", "aa", "55" };
+static const char *res_sorted[] = { "44", "55", "88", "aa" };
+
+void test_oid_array__enumerate_unique(void)
+{
+ TEST_ENUMERATION(arr_input, res_sorted);
+}
+
+void test_oid_array__enumerate_duplicate(void)
+{
+ TEST_ENUMERATION(arr_input_dup, res_sorted);
+}
+
+void test_oid_array__lookup(void)
+{
+ TEST_LOOKUP(arr_input, "55", 1, 1);
+}
+
+void test_oid_array__lookup_non_existent(void)
+{
+ TEST_LOOKUP(arr_input, "33", INT_MIN, -1);
+}
+
+void test_oid_array__lookup_duplicates(void)
+{
+ TEST_LOOKUP(arr_input_dup, "55", 3, 5);
+}
+
+void test_oid_array__lookup_non_existent_dup(void)
+{
+ TEST_LOOKUP(arr_input_dup, "66", INT_MIN, -1);
+}
+
+void test_oid_array__lookup_almost_dup(void)
+{
+ const char *nearly_55;
+
+ nearly_55 = cl_setup_hash_algo() == GIT_HASH_SHA1 ?
+ "5500000000000000000000000000000000000001" :
+ "5500000000000000000000000000000000000000000000000000000000000001";
+
+ TEST_LOOKUP(((const char *[]){ "55", nearly_55 }), "55", 0, 0);
+}
+
+void test_oid_array__lookup_single_dup(void)
+{
+ TEST_LOOKUP(((const char *[]){ "55", "55" }), "55", 0, 1);
+}
diff --git a/t/unit-tests/u-oidmap.c b/t/unit-tests/u-oidmap.c
new file mode 100644
index 0000000000..dc805b7e3c
--- /dev/null
+++ b/t/unit-tests/u-oidmap.c
@@ -0,0 +1,136 @@
+#include "unit-test.h"
+#include "lib-oid.h"
+#include "oidmap.h"
+#include "hash.h"
+#include "hex.h"
+
+/*
+ * Elements we will put in oidmap structs are made of a key: the entry.oid
+ * field, which is of type struct object_id, and a value: the name field (could
+ * be a refname for example).
+ */
+struct test_entry {
+ struct oidmap_entry entry;
+ char name[FLEX_ARRAY];
+};
+
+static const char *const key_val[][2] = { { "11", "one" },
+ { "22", "two" },
+ { "33", "three" } };
+
+static struct oidmap map;
+
+void test_oidmap__initialize(void)
+{
+ oidmap_init(&map, 0);
+
+ for (size_t i = 0; i < ARRAY_SIZE(key_val); i++){
+ struct test_entry *entry;
+
+ FLEX_ALLOC_STR(entry, name, key_val[i][1]);
+ cl_parse_any_oid(key_val[i][0], &entry->entry.oid);
+ cl_assert(oidmap_put(&map, entry) == NULL);
+ }
+}
+
+void test_oidmap__cleanup(void)
+{
+ oidmap_free(&map, 1);
+}
+
+void test_oidmap__replace(void)
+{
+ struct test_entry *entry, *prev;
+
+ FLEX_ALLOC_STR(entry, name, "un");
+ cl_parse_any_oid("11", &entry->entry.oid);
+ prev = oidmap_put(&map, entry);
+ cl_assert(prev != NULL);
+ cl_assert_equal_s(prev->name, "one");
+ free(prev);
+
+ FLEX_ALLOC_STR(entry, name, "deux");
+ cl_parse_any_oid("22", &entry->entry.oid);
+ prev = oidmap_put(&map, entry);
+ cl_assert(prev != NULL);
+ cl_assert_equal_s(prev->name, "two");
+ free(prev);
+}
+
+void test_oidmap__get(void)
+{
+ struct test_entry *entry;
+ struct object_id oid;
+
+ cl_parse_any_oid("22", &oid);
+ entry = oidmap_get(&map, &oid);
+ cl_assert(entry != NULL);
+ cl_assert_equal_s(entry->name, "two");
+
+ cl_parse_any_oid("44", &oid);
+ cl_assert(oidmap_get(&map, &oid) == NULL);
+
+ cl_parse_any_oid("11", &oid);
+ entry = oidmap_get(&map, &oid);
+ cl_assert(entry != NULL);
+ cl_assert_equal_s(entry->name, "one");
+}
+
+void test_oidmap__remove(void)
+{
+ struct test_entry *entry;
+ struct object_id oid;
+
+ cl_parse_any_oid("11", &oid);
+ entry = oidmap_remove(&map, &oid);
+ cl_assert(entry != NULL);
+ cl_assert_equal_s(entry->name, "one");
+ cl_assert(oidmap_get(&map, &oid) == NULL);
+ free(entry);
+
+ cl_parse_any_oid("22", &oid);
+ entry = oidmap_remove(&map, &oid);
+ cl_assert(entry != NULL);
+ cl_assert_equal_s(entry->name, "two");
+ cl_assert(oidmap_get(&map, &oid) == NULL);
+ free(entry);
+
+ cl_parse_any_oid("44", &oid);
+ cl_assert(oidmap_remove(&map, &oid) == NULL);
+}
+
+static int key_val_contains(struct test_entry *entry, char seen[])
+{
+ for (size_t i = 0; i < ARRAY_SIZE(key_val); i++) {
+ struct object_id oid;
+
+ cl_parse_any_oid(key_val[i][0], &oid);
+
+ if (oideq(&entry->entry.oid, &oid)) {
+ if (seen[i])
+ return 2;
+ seen[i] = 1;
+ return 0;
+ }
+ }
+ return 1;
+}
+
+void test_oidmap__iterate(void)
+{
+ struct oidmap_iter iter;
+ struct test_entry *entry;
+ char seen[ARRAY_SIZE(key_val)] = { 0 };
+ int count = 0;
+
+ oidmap_iter_init(&map, &iter);
+ while ((entry = oidmap_iter_next(&iter))) {
+ if (key_val_contains(entry, seen) != 0) {
+ cl_failf("Unexpected entry: name = %s, oid = %s",
+ entry->name, oid_to_hex(&entry->entry.oid));
+ }
+ count++;
+ }
+ cl_assert_equal_i(count, ARRAY_SIZE(key_val));
+ cl_assert_equal_i(hashmap_get_size(&map.map), ARRAY_SIZE(key_val));
+}
diff --git a/t/unit-tests/u-oidtree.c b/t/unit-tests/u-oidtree.c
new file mode 100644
index 0000000000..e6eede2740
--- /dev/null
+++ b/t/unit-tests/u-oidtree.c
@@ -0,0 +1,107 @@
+#include "unit-test.h"
+#include "lib-oid.h"
+#include "oidtree.h"
+#include "hash.h"
+#include "hex.h"
+#include "strvec.h"
+
+static struct oidtree ot;
+
+#define FILL_TREE(tree, ...) \
+ do { \
+ const char *hexes[] = { __VA_ARGS__ }; \
+ if (fill_tree_loc(tree, hexes, ARRAY_SIZE(hexes))) \
+ return; \
+ } while (0)
+
+static int fill_tree_loc(struct oidtree *ot, const char *hexes[], size_t n)
+{
+ for (size_t i = 0; i < n; i++) {
+ struct object_id oid;
+ cl_parse_any_oid(hexes[i], &oid);
+ oidtree_insert(ot, &oid);
+ }
+ return 0;
+}
+
+static void check_contains(struct oidtree *ot, const char *hex, int expected)
+{
+ struct object_id oid;
+
+ cl_parse_any_oid(hex, &oid);
+ cl_assert_equal_i(oidtree_contains(ot, &oid), expected);
+}
+
+struct expected_hex_iter {
+ size_t i;
+ struct strvec expected_hexes;
+ const char *query;
+};
+
+static enum cb_next check_each_cb(const struct object_id *oid, void *data)
+{
+ struct expected_hex_iter *hex_iter = data;
+ struct object_id expected;
+
+ cl_assert(hex_iter->i < hex_iter->expected_hexes.nr);
+
+ cl_parse_any_oid(hex_iter->expected_hexes.v[hex_iter->i],
+ &expected);
+ cl_assert_equal_s(oid_to_hex(oid), oid_to_hex(&expected));
+ hex_iter->i += 1;
+ return CB_CONTINUE;
+}
+
+LAST_ARG_MUST_BE_NULL
+static void check_each(struct oidtree *ot, const char *query, ...)
+{
+ struct object_id oid;
+ struct expected_hex_iter hex_iter = { .expected_hexes = STRVEC_INIT,
+ .query = query };
+ const char *arg;
+ va_list hex_args;
+
+ va_start(hex_args, query);
+ while ((arg = va_arg(hex_args, const char *)))
+ strvec_push(&hex_iter.expected_hexes, arg);
+ va_end(hex_args);
+
+ cl_parse_any_oid(query, &oid);
+ oidtree_each(ot, &oid, strlen(query), check_each_cb, &hex_iter);
+
+ if (hex_iter.i != hex_iter.expected_hexes.nr)
+ cl_failf("error: could not find some 'object_id's for query ('%s')", query);
+
+ strvec_clear(&hex_iter.expected_hexes);
+}
+
+void test_oidtree__initialize(void)
+{
+ oidtree_init(&ot);
+}
+
+void test_oidtree__cleanup(void)
+{
+ oidtree_clear(&ot);
+}
+
+void test_oidtree__contains(void)
+{
+ FILL_TREE(&ot, "444", "1", "2", "3", "4", "5", "a", "b", "c", "d", "e");
+ check_contains(&ot, "44", 0);
+ check_contains(&ot, "441", 0);
+ check_contains(&ot, "440", 0);
+ check_contains(&ot, "444", 1);
+ check_contains(&ot, "4440", 1);
+ check_contains(&ot, "4444", 0);
+}
+
+void test_oidtree__each(void)
+{
+ FILL_TREE(&ot, "f", "9", "8", "123", "321", "320", "a", "b", "c", "d", "e");
+ check_each(&ot, "12300", "123", NULL);
+ check_each(&ot, "3211", NULL); /* should not reach callback */
+ check_each(&ot, "3210", "321", NULL);
+ check_each(&ot, "32100", "321", NULL);
+ check_each(&ot, "32", "320", "321", NULL);
+}
diff --git a/t/unit-tests/u-strbuf.c b/t/unit-tests/u-strbuf.c
new file mode 100644
index 0000000000..caa5d78aa3
--- /dev/null
+++ b/t/unit-tests/u-strbuf.c
@@ -0,0 +1,119 @@
+#include "unit-test.h"
+#include "strbuf.h"
+
+/* wrapper that supplies tests with an empty, initialized strbuf */
+static void setup(void (*f)(struct strbuf*, const void*),
+ const void *data)
+{
+ struct strbuf buf = STRBUF_INIT;
+
+ f(&buf, data);
+ strbuf_release(&buf);
+ cl_assert_equal_i(buf.len, 0);
+ cl_assert_equal_i(buf.alloc, 0);
+}
+
+/* wrapper that supplies tests with a populated, initialized strbuf */
+static void setup_populated(void (*f)(struct strbuf*, const void*),
+ const char *init_str, const void *data)
+{
+ struct strbuf buf = STRBUF_INIT;
+
+ strbuf_addstr(&buf, init_str);
+ cl_assert_equal_i(buf.len, strlen(init_str));
+ f(&buf, data);
+ strbuf_release(&buf);
+ cl_assert_equal_i(buf.len, 0);
+ cl_assert_equal_i(buf.alloc, 0);
+}
+
+static void assert_sane_strbuf(struct strbuf *buf)
+{
+ /* Initialized strbufs should always have a non-NULL buffer */
+ cl_assert(buf->buf != NULL);
+ /* Buffers should always be NUL-terminated */
+ cl_assert(buf->buf[buf->len] == '\0');
+ /*
+ * In case the buffer contains anything, `alloc` must alloc must
+ * be at least one byte larger than `len`.
+ */
+ if (buf->len)
+ cl_assert(buf->len < buf->alloc);
+}
+
+void test_strbuf__static_init(void)
+{
+ struct strbuf buf = STRBUF_INIT;
+
+ cl_assert_equal_i(buf.len, 0);
+ cl_assert_equal_i(buf.alloc, 0);
+ cl_assert(buf.buf[0] == '\0');
+}
+
+void test_strbuf__dynamic_init(void)
+{
+ struct strbuf buf;
+
+ strbuf_init(&buf, 1024);
+ assert_sane_strbuf(&buf);
+ cl_assert_equal_i(buf.len, 0);
+ cl_assert(buf.alloc >= 1024);
+ cl_assert(buf.buf[0] == '\0');
+ strbuf_release(&buf);
+}
+
+static void t_addch(struct strbuf *buf, const void *data)
+{
+ const char *p_ch = data;
+ const char ch = *p_ch;
+ size_t orig_alloc = buf->alloc;
+ size_t orig_len = buf->len;
+
+ assert_sane_strbuf(buf);
+ strbuf_addch(buf, ch);
+ assert_sane_strbuf(buf);
+ cl_assert_equal_i(buf->len, orig_len + 1);
+ cl_assert(buf->alloc >= orig_alloc);
+ cl_assert(buf->buf[buf->len] == '\0');
+}
+
+static void t_addstr(struct strbuf *buf, const void *data)
+{
+ const char *text = data;
+ size_t len = strlen(text);
+ size_t orig_alloc = buf->alloc;
+ size_t orig_len = buf->len;
+
+ assert_sane_strbuf(buf);
+ strbuf_addstr(buf, text);
+ assert_sane_strbuf(buf);
+ cl_assert_equal_i(buf->len, orig_len + len);
+ cl_assert(buf->alloc >= orig_alloc);
+ cl_assert(buf->buf[buf->len] == '\0');
+ cl_assert_equal_s(buf->buf + orig_len, text);
+}
+
+void test_strbuf__add_single_char(void)
+{
+ setup(t_addch, "a");
+}
+
+void test_strbuf__add_empty_char(void)
+{
+ setup(t_addch, "");
+}
+
+void test_strbuf__add_append_char(void)
+{
+ setup_populated(t_addch, "initial value", "a");
+}
+
+void test_strbuf__add_single_str(void)
+{
+ setup(t_addstr, "hello there");
+}
+
+void test_strbuf__add_append_str(void)
+{
+ setup_populated(t_addstr, "initial value", "hello there");
+}
diff --git a/t/unit-tests/u-strcmp-offset.c b/t/unit-tests/u-strcmp-offset.c
new file mode 100644
index 0000000000..7e8e9acf3c
--- /dev/null
+++ b/t/unit-tests/u-strcmp-offset.c
@@ -0,0 +1,45 @@
+#include "unit-test.h"
+#include "read-cache-ll.h"
+
+static void check_strcmp_offset(const char *string1, const char *string2,
+ int expect_result, uintmax_t expect_offset)
+{
+ size_t offset;
+ int result = strcmp_offset(string1, string2, &offset);
+
+ /*
+ * Because different CRTs behave differently, only rely on signs of the
+ * result values.
+ */
+ result = (result < 0 ? -1 :
+ result > 0 ? 1 :
+ 0);
+
+ cl_assert_equal_i(result, expect_result);
+ cl_assert_equal_i((uintmax_t)offset, expect_offset);
+}
+
+void test_strcmp_offset__empty(void)
+{
+ check_strcmp_offset("", "", 0, 0);
+}
+
+void test_strcmp_offset__equal(void)
+{
+ check_strcmp_offset("abc", "abc", 0, 3);
+}
+
+void test_strcmp_offset__different(void)
+{
+ check_strcmp_offset("abc", "def", -1, 0);
+}
+
+void test_strcmp_offset__mismatch(void)
+{
+ check_strcmp_offset("abc", "abz", -1, 2);
+}
+
+void test_strcmp_offset__different_length(void)
+{
+ check_strcmp_offset("abc", "abcdef", -1, 3);
+}
diff --git a/t/unit-tests/unit-test.c b/t/unit-tests/unit-test.c
index fa8818842a..5af645048a 100644
--- a/t/unit-tests/unit-test.c
+++ b/t/unit-tests/unit-test.c
@@ -1,5 +1,7 @@
#include "unit-test.h"
+#include "hex.h"
#include "parse-options.h"
+#include "strbuf.h"
#include "string-list.h"
#include "strvec.h"