t: port helper/test-hashmap.c to unit-tests/t-hashmap.c
helper/test-hashmap.c along with t0011-hashmap.sh test the hashmap.h
library. Migrate them to the unit testing framework for better
debugging, runtime performance and concise code.
Along with the migration, make 'add' tests from the shell script order
agnostic in unit tests, since they iterate over entries with the same
keys and we do not guarantee the order. This was already done for the
'iterate' tests[1].
The helper/test-hashmap.c is still not removed because it contains a
performance test meant to be run by the user directly (not used in
t/perf). And it makes sense for such a utility to be a helper.
[1]: e1e7a77141
(t: sort output of hashmap iteration, 2019-07-30)
Mentored-by: Christian Couder <chriscool@tuxfamily.org>
Mentored-by: Kaartic Sivaraam <kaartic.sivaraam@gmail.com>
Helped-by: Josh Steadmon <steadmon@google.com>
Helped-by: Junio C Hamano <gitster@pobox.com>
Helped-by: Phillip Wood <phillip.wood123@gmail.com>
Signed-off-by: Ghanshyam Thakkar <shyamthakkar001@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:

committed by
Junio C Hamano

parent
5c9be4c9d6
commit
3469a23659
@ -12,11 +12,6 @@ struct test_entry
|
||||
char key[FLEX_ARRAY];
|
||||
};
|
||||
|
||||
static const char *get_value(const struct test_entry *e)
|
||||
{
|
||||
return e->key + strlen(e->key) + 1;
|
||||
}
|
||||
|
||||
static int test_entry_cmp(const void *cmp_data,
|
||||
const struct hashmap_entry *eptr,
|
||||
const struct hashmap_entry *entry_or_key,
|
||||
@ -141,30 +136,16 @@ static void perf_hashmap(unsigned int method, unsigned int rounds)
|
||||
/*
|
||||
* Read stdin line by line and print result of commands to stdout:
|
||||
*
|
||||
* hash key -> strhash(key) memhash(key) strihash(key) memihash(key)
|
||||
* put key value -> NULL / old value
|
||||
* get key -> NULL / value
|
||||
* remove key -> NULL / old value
|
||||
* iterate -> key1 value1\nkey2 value2\n...
|
||||
* size -> tablesize numentries
|
||||
*
|
||||
* perfhashmap method rounds -> test hashmap.[ch] performance
|
||||
*/
|
||||
int cmd__hashmap(int argc, const char **argv)
|
||||
{
|
||||
struct string_list parts = STRING_LIST_INIT_NODUP;
|
||||
struct strbuf line = STRBUF_INIT;
|
||||
int icase;
|
||||
struct hashmap map = HASHMAP_INIT(test_entry_cmp, &icase);
|
||||
|
||||
/* init hash map */
|
||||
icase = argc > 1 && !strcmp("ignorecase", argv[1]);
|
||||
|
||||
/* process commands from stdin */
|
||||
while (strbuf_getline(&line, stdin) != EOF) {
|
||||
char *cmd, *p1, *p2;
|
||||
unsigned int hash = 0;
|
||||
struct test_entry *entry;
|
||||
|
||||
/* break line into command and up to two parameters */
|
||||
string_list_setlen(&parts, 0);
|
||||
@ -180,84 +161,8 @@ int cmd__hashmap(int argc, const char **argv)
|
||||
cmd = parts.items[0].string;
|
||||
p1 = parts.nr >= 1 ? parts.items[1].string : NULL;
|
||||
p2 = parts.nr >= 2 ? parts.items[2].string : NULL;
|
||||
if (p1)
|
||||
hash = icase ? strihash(p1) : strhash(p1);
|
||||
|
||||
if (!strcmp("add", cmd) && p1 && p2) {
|
||||
|
||||
/* create entry with key = p1, value = p2 */
|
||||
entry = alloc_test_entry(hash, p1, p2);
|
||||
|
||||
/* add to hashmap */
|
||||
hashmap_add(&map, &entry->ent);
|
||||
|
||||
} else if (!strcmp("put", cmd) && p1 && p2) {
|
||||
|
||||
/* create entry with key = p1, value = p2 */
|
||||
entry = alloc_test_entry(hash, p1, p2);
|
||||
|
||||
/* add / replace entry */
|
||||
entry = hashmap_put_entry(&map, entry, ent);
|
||||
|
||||
/* print and free replaced entry, if any */
|
||||
puts(entry ? get_value(entry) : "NULL");
|
||||
free(entry);
|
||||
|
||||
} else if (!strcmp("get", cmd) && p1) {
|
||||
/* lookup entry in hashmap */
|
||||
entry = hashmap_get_entry_from_hash(&map, hash, p1,
|
||||
struct test_entry, ent);
|
||||
|
||||
/* print result */
|
||||
if (!entry)
|
||||
puts("NULL");
|
||||
hashmap_for_each_entry_from(&map, entry, ent)
|
||||
puts(get_value(entry));
|
||||
|
||||
} else if (!strcmp("remove", cmd) && p1) {
|
||||
|
||||
/* setup static key */
|
||||
struct hashmap_entry key;
|
||||
struct hashmap_entry *rm;
|
||||
hashmap_entry_init(&key, hash);
|
||||
|
||||
/* remove entry from hashmap */
|
||||
rm = hashmap_remove(&map, &key, p1);
|
||||
entry = rm ? container_of(rm, struct test_entry, ent)
|
||||
: NULL;
|
||||
|
||||
/* print result and free entry*/
|
||||
puts(entry ? get_value(entry) : "NULL");
|
||||
free(entry);
|
||||
|
||||
} else if (!strcmp("iterate", cmd)) {
|
||||
struct hashmap_iter iter;
|
||||
|
||||
hashmap_for_each_entry(&map, &iter, entry,
|
||||
ent /* member name */)
|
||||
printf("%s %s\n", entry->key, get_value(entry));
|
||||
|
||||
} else if (!strcmp("size", cmd)) {
|
||||
|
||||
/* print table sizes */
|
||||
printf("%u %u\n", map.tablesize,
|
||||
hashmap_get_size(&map));
|
||||
|
||||
} else if (!strcmp("intern", cmd) && p1) {
|
||||
|
||||
/* test that strintern works */
|
||||
const char *i1 = strintern(p1);
|
||||
const char *i2 = strintern(p1);
|
||||
if (strcmp(i1, p1))
|
||||
printf("strintern(%s) returns %s\n", p1, i1);
|
||||
else if (i1 == p1)
|
||||
printf("strintern(%s) returns input pointer\n", p1);
|
||||
else if (i1 != i2)
|
||||
printf("strintern(%s) != strintern(%s)", i1, i2);
|
||||
else
|
||||
printf("%s\n", i1);
|
||||
|
||||
} else if (!strcmp("perfhashmap", cmd) && p1 && p2) {
|
||||
if (!strcmp("perfhashmap", cmd) && p1 && p2) {
|
||||
|
||||
perf_hashmap(atoi(p1), atoi(p2));
|
||||
|
||||
@ -270,6 +175,5 @@ int cmd__hashmap(int argc, const char **argv)
|
||||
|
||||
string_list_clear(&parts, 0);
|
||||
strbuf_release(&line);
|
||||
hashmap_clear_and_free(&map, struct test_entry, ent);
|
||||
return 0;
|
||||
}
|
||||
|
Reference in New Issue
Block a user