t: migrate helper/test-oidmap.c to unit-tests/t-oidmap.c

helper/test-oidmap.c along with t0016-oidmap.sh test the oidmap.h library which is built on top of hashmap.h. Migrate them to the unit testing framework for better performance, concise code and better debugging. Along with the migration also plug memory leaks and make the test logic independent for all the tests. The migration removes 'put' tests from t0016, because it is used as setup to all the other tests, so testing it separately does not yield any benefit. Mentored-by: Christian Couder <chriscool@tuxfamily.org> Mentored-by: Kaartic Sivaraam <kaartic.sivaraam@gmail.com> Reviewed-by: Josh Steadmon <steadmon@google.com> Helped-by: Phillip Wood <phillip.wood123@gmail.com> Helped-by: Junio C Hamano <gitster@pobox.com> Signed-off-by: Ghanshyam Thakkar <shyamthakkar001@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Ghanshyam Thakkar committed Jul 3, 2024 at 11:59 UTC 28c1c077001d5cf715eb6264d75bc2537aa8cfd2
6 files changed +182 -238
Makefile
+1 -1
@@ -809,7 +809,6 @@ TEST_BUILTINS_OBJS += test-match-trees.o
809 TEST_BUILTINS_OBJS += test-mergesort.o
810 TEST_BUILTINS_OBJS += test-mktemp.o
811 TEST_BUILTINS_OBJS += test-oid-array.o
812 -TEST_BUILTINS_OBJS += test-oidmap.o
812 TEST_BUILTINS_OBJS += test-online-cpus.o
813 TEST_BUILTINS_OBJS += test-pack-mtimes.o
814 TEST_BUILTINS_OBJS += test-parse-options.o
@@ -1337,6 +1336,7 @@ UNIT_TEST_PROGRAMS += t-ctype
1336 UNIT_TEST_PROGRAMS += t-example-decorate
1337 UNIT_TEST_PROGRAMS += t-hash
1338 UNIT_TEST_PROGRAMS += t-mem-pool
1339 +UNIT_TEST_PROGRAMS += t-oidmap
1340 UNIT_TEST_PROGRAMS += t-oidtree
1341 UNIT_TEST_PROGRAMS += t-prio-queue
1342 UNIT_TEST_PROGRAMS += t-reftable-basics
t/helper/test-oidmap.c deleted
-123
@@ -1,123 +0,0 @@
1 -#include "test-tool.h"
2 -#include "hex.h"
3 -#include "object-name.h"
4 -#include "oidmap.h"
5 -#include "repository.h"
6 -#include "setup.h"
7 -#include "strbuf.h"
8 -#include "string-list.h"
9 -
10 -/* key is an oid and value is a name (could be a refname for example) */
11 -struct test_entry {
12 - struct oidmap_entry entry;
13 - char name[FLEX_ARRAY];
14 -};
15 -
16 -#define DELIM " \t\r\n"
17 -
18 -/*
19 - * Read stdin line by line and print result of commands to stdout:
20 - *
21 - * hash oidkey -> sha1hash(oidkey)
22 - * put oidkey namevalue -> NULL / old namevalue
23 - * get oidkey -> NULL / namevalue
24 - * remove oidkey -> NULL / old namevalue
25 - * iterate -> oidkey1 namevalue1\noidkey2 namevalue2\n...
26 - *
27 - */
28 -int cmd__oidmap(int argc UNUSED, const char **argv UNUSED)
29 -{
30 - struct string_list parts = STRING_LIST_INIT_NODUP;
31 - struct strbuf line = STRBUF_INIT;
32 - struct oidmap map = OIDMAP_INIT;
33 -
34 - setup_git_directory();
35 -
36 - /* init oidmap */
37 - oidmap_init(&map, 0);
38 -
39 - /* process commands from stdin */
40 - while (strbuf_getline(&line, stdin) != EOF) {
41 - char *cmd, *p1, *p2;
42 - struct test_entry *entry;
43 - struct object_id oid;
44 -
45 - /* break line into command and up to two parameters */
46 - string_list_setlen(&parts, 0);
47 - string_list_split_in_place(&parts, line.buf, DELIM, 2);
48 - string_list_remove_empty_items(&parts, 0);
49 -
50 - /* ignore empty lines */
51 - if (!parts.nr)
52 - continue;
53 - if (!*parts.items[0].string || *parts.items[0].string == '#')
54 - continue;
55 -
56 - cmd = parts.items[0].string;
57 - p1 = parts.nr >= 1 ? parts.items[1].string : NULL;
58 - p2 = parts.nr >= 2 ? parts.items[2].string : NULL;
59 -
60 - if (!strcmp("put", cmd) && p1 && p2) {
61 -
62 - if (repo_get_oid(the_repository, p1, &oid)) {
63 - printf("Unknown oid: %s\n", p1);
64 - continue;
65 - }
66 -
67 - /* create entry with oid_key = p1, name_value = p2 */
68 - FLEX_ALLOC_STR(entry, name, p2);
69 - oidcpy(&entry->entry.oid, &oid);
70 -
71 - /* add / replace entry */
72 - entry = oidmap_put(&map, entry);
73 -
74 - /* print and free replaced entry, if any */
75 - puts(entry ? entry->name : "NULL");
76 - free(entry);
77 -
78 - } else if (!strcmp("get", cmd) && p1) {
79 -
80 - if (repo_get_oid(the_repository, p1, &oid)) {
81 - printf("Unknown oid: %s\n", p1);
82 - continue;
83 - }
84 -
85 - /* lookup entry in oidmap */
86 - entry = oidmap_get(&map, &oid);
87 -
88 - /* print result */
89 - puts(entry ? entry->name : "NULL");
90 -
91 - } else if (!strcmp("remove", cmd) && p1) {
92 -
93 - if (repo_get_oid(the_repository, p1, &oid)) {
94 - printf("Unknown oid: %s\n", p1);
95 - continue;
96 - }
97 -
98 - /* remove entry from oidmap */
99 - entry = oidmap_remove(&map, &oid);
100 -
101 - /* print result and free entry*/
102 - puts(entry ? entry->name : "NULL");
103 - free(entry);
104 -
105 - } else if (!strcmp("iterate", cmd)) {
106 -
107 - struct oidmap_iter iter;
108 - oidmap_iter_init(&map, &iter);
109 - while ((entry = oidmap_iter_next(&iter)))
110 - printf("%s %s\n", oid_to_hex(&entry->entry.oid), entry->name);
111 -
112 - } else {
113 -
114 - printf("Unknown command %s\n", cmd);
115 -
116 - }
117 - }
118 -
119 - string_list_clear(&parts, 0);
120 - strbuf_release(&line);
121 - oidmap_free(&map, 1);
122 - return 0;
123 -}
t/helper/test-tool.c
-1
@@ -44,7 +44,6 @@ static struct test_cmd cmds[] = {
44 { "mergesort", cmd__mergesort },
45 { "mktemp", cmd__mktemp },
46 { "oid-array", cmd__oid_array },
47 - { "oidmap", cmd__oidmap },
47 { "online-cpus", cmd__online_cpus },
48 { "pack-mtimes", cmd__pack_mtimes },
49 { "parse-options", cmd__parse_options },
t/helper/test-tool.h
-1
@@ -37,7 +37,6 @@ int cmd__lazy_init_name_hash(int argc, const char **argv);
37 int cmd__match_trees(int argc, const char **argv);
38 int cmd__mergesort(int argc, const char **argv);
39 int cmd__mktemp(int argc, const char **argv);
40 -int cmd__oidmap(int argc, const char **argv);
40 int cmd__online_cpus(int argc, const char **argv);
41 int cmd__pack_mtimes(int argc, const char **argv);
42 int cmd__parse_options(int argc, const char **argv);
t/t0016-oidmap.sh deleted
-112
@@ -1,112 +0,0 @@
1 -#!/bin/sh
2 -
3 -test_description='test oidmap'
4 -
5 -TEST_PASSES_SANITIZE_LEAK=true
6 -. ./test-lib.sh
7 -
8 -# This purposefully is very similar to t0011-hashmap.sh
9 -
10 -test_oidmap () {
11 - echo "$1" | test-tool oidmap $3 >actual &&
12 - echo "$2" >expect &&
13 - test_cmp expect actual
14 -}
15 -
16 -
17 -test_expect_success 'setup' '
18 -
19 - test_commit one &&
20 - test_commit two &&
21 - test_commit three &&
22 - test_commit four
23 -
24 -'
25 -
26 -test_expect_success 'put' '
27 -
28 -test_oidmap "put one 1
29 -put two 2
30 -put invalidOid 4
31 -put three 3" "NULL
32 -NULL
33 -Unknown oid: invalidOid
34 -NULL"
35 -
36 -'
37 -
38 -test_expect_success 'replace' '
39 -
40 -test_oidmap "put one 1
41 -put two 2
42 -put three 3
43 -put invalidOid 4
44 -put two deux
45 -put one un" "NULL
46 -NULL
47 -NULL
48 -Unknown oid: invalidOid
49 -2
50 -1"
51 -
52 -'
53 -
54 -test_expect_success 'get' '
55 -
56 -test_oidmap "put one 1
57 -put two 2
58 -put three 3
59 -get two
60 -get four
61 -get invalidOid
62 -get one" "NULL
63 -NULL
64 -NULL
65 -2
66 -NULL
67 -Unknown oid: invalidOid
68 -1"
69 -
70 -'
71 -
72 -test_expect_success 'remove' '
73 -
74 -test_oidmap "put one 1
75 -put two 2
76 -put three 3
77 -remove one
78 -remove two
79 -remove invalidOid
80 -remove four" "NULL
81 -NULL
82 -NULL
83 -1
84 -2
85 -Unknown oid: invalidOid
86 -NULL"
87 -
88 -'
89 -
90 -test_expect_success 'iterate' '
91 - test-tool oidmap >actual.raw <<-\EOF &&
92 - put one 1
93 - put two 2
94 - put three 3
95 - iterate
96 - EOF
97 -
98 - # sort "expect" too so we do not rely on the order of particular oids
99 - sort >expect <<-EOF &&
100 - NULL
101 - NULL
102 - NULL
103 - $(git rev-parse one) 1
104 - $(git rev-parse two) 2
105 - $(git rev-parse three) 3
106 - EOF
107 -
108 - sort <actual.raw >actual &&
109 - test_cmp expect actual
110 -'
111 -
112 -test_done
t/unit-tests/t-oidmap.c new
+181
@@ -0,0 +1,181 @@
1 +#include "test-lib.h"
2 +#include "lib-oid.h"
3 +#include "oidmap.h"
4 +#include "hash.h"
5 +#include "hex.h"
6 +
7 +/*
8 + * Elements we will put in oidmap structs are made of a key: the entry.oid
9 + * field, which is of type struct object_id, and a value: the name field (could
10 + * be a refname for example).
11 + */
12 +struct test_entry {
13 + struct oidmap_entry entry;
14 + char name[FLEX_ARRAY];
15 +};
16 +
17 +static const char *const key_val[][2] = { { "11", "one" },
18 + { "22", "two" },
19 + { "33", "three" } };
20 +
21 +static void setup(void (*f)(struct oidmap *map))
22 +{
23 + struct oidmap map = OIDMAP_INIT;
24 + int ret = 0;
25 +
26 + for (size_t i = 0; i < ARRAY_SIZE(key_val); i++){
27 + struct test_entry *entry;
28 +
29 + FLEX_ALLOC_STR(entry, name, key_val[i][1]);
30 + if ((ret = get_oid_arbitrary_hex(key_val[i][0], &entry->entry.oid))) {
31 + free(entry);
32 + break;
33 + }
34 + entry = oidmap_put(&map, entry);
35 + if (!check(entry == NULL))
36 + free(entry);
37 + }
38 +
39 + if (!ret)
40 + f(&map);
41 + oidmap_free(&map, 1);
42 +}
43 +
44 +static void t_replace(struct oidmap *map)
45 +{
46 + struct test_entry *entry, *prev;
47 +
48 + FLEX_ALLOC_STR(entry, name, "un");
49 + if (get_oid_arbitrary_hex("11", &entry->entry.oid))
50 + return;
51 + prev = oidmap_put(map, entry);
52 + if (!check(prev != NULL))
53 + return;
54 + check_str(prev->name, "one");
55 + free(prev);
56 +
57 + FLEX_ALLOC_STR(entry, name, "deux");
58 + if (get_oid_arbitrary_hex("22", &entry->entry.oid))
59 + return;
60 + prev = oidmap_put(map, entry);
61 + if (!check(prev != NULL))
62 + return;
63 + check_str(prev->name, "two");
64 + free(prev);
65 +}
66 +
67 +static void t_get(struct oidmap *map)
68 +{
69 + struct test_entry *entry;
70 + struct object_id oid;
71 +
72 + if (get_oid_arbitrary_hex("22", &oid))
73 + return;
74 + entry = oidmap_get(map, &oid);
75 + if (!check(entry != NULL))
76 + return;
77 + check_str(entry->name, "two");
78 +
79 + if (get_oid_arbitrary_hex("44", &oid))
80 + return;
81 + check(oidmap_get(map, &oid) == NULL);
82 +
83 + if (get_oid_arbitrary_hex("11", &oid))
84 + return;
85 + entry = oidmap_get(map, &oid);
86 + if (!check(entry != NULL))
87 + return;
88 + check_str(entry->name, "one");
89 +}
90 +
91 +static void t_remove(struct oidmap *map)
92 +{
93 + struct test_entry *entry;
94 + struct object_id oid;
95 +
96 + if (get_oid_arbitrary_hex("11", &oid))
97 + return;
98 + entry = oidmap_remove(map, &oid);
99 + if (!check(entry != NULL))
100 + return;
101 + check_str(entry->name, "one");
102 + check(oidmap_get(map, &oid) == NULL);
103 + free(entry);
104 +
105 + if (get_oid_arbitrary_hex("22", &oid))
106 + return;
107 + entry = oidmap_remove(map, &oid);
108 + if (!check(entry != NULL))
109 + return;
110 + check_str(entry->name, "two");
111 + check(oidmap_get(map, &oid) == NULL);
112 + free(entry);
113 +
114 + if (get_oid_arbitrary_hex("44", &oid))
115 + return;
116 + check(oidmap_remove(map, &oid) == NULL);
117 +}
118 +
119 +static int key_val_contains(struct test_entry *entry, char seen[])
120 +{
121 + for (size_t i = 0; i < ARRAY_SIZE(key_val); i++) {
122 + struct object_id oid;
123 +
124 + if (get_oid_arbitrary_hex(key_val[i][0], &oid))
125 + return -1;
126 +
127 + if (oideq(&entry->entry.oid, &oid)) {
128 + if (seen[i])
129 + return 2;
130 + seen[i] = 1;
131 + return 0;
132 + }
133 + }
134 + return 1;
135 +}
136 +
137 +static void t_iterate(struct oidmap *map)
138 +{
139 + struct oidmap_iter iter;
140 + struct test_entry *entry;
141 + char seen[ARRAY_SIZE(key_val)] = { 0 };
142 + int count = 0;
143 +
144 + oidmap_iter_init(map, &iter);
145 + while ((entry = oidmap_iter_next(&iter))) {
146 + int ret;
147 + if (!check_int((ret = key_val_contains(entry, seen)), ==, 0)) {
148 + switch (ret) {
149 + case -1:
150 + break; /* error message handled by get_oid_arbitrary_hex() */
151 + case 1:
152 + test_msg("obtained entry was not given in the input\n"
153 + " name: %s\n oid: %s\n",
154 + entry->name, oid_to_hex(&entry->entry.oid));
155 + break;
156 + case 2:
157 + test_msg("duplicate entry detected\n"
158 + " name: %s\n oid: %s\n",
159 + entry->name, oid_to_hex(&entry->entry.oid));
160 + break;
161 + default:
162 + test_msg("BUG: invalid return value (%d) from key_val_contains()",
163 + ret);
164 + break;
165 + }
166 + } else {
167 + count++;
168 + }
169 + }
170 + check_int(count, ==, ARRAY_SIZE(key_val));
171 + check_int(hashmap_get_size(&map->map), ==, ARRAY_SIZE(key_val));
172 +}
173 +
174 +int cmd_main(int argc UNUSED, const char **argv UNUSED)
175 +{
176 + TEST(setup(t_replace), "replace works");
177 + TEST(setup(t_get), "get works");
178 + TEST(setup(t_remove), "remove works");
179 + TEST(setup(t_iterate), "iterate works");
180 + return test_done();
181 +}