195 lines
4.8 KiB
C
195 lines
4.8 KiB
C
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include "dkhash.c"
|
|
#include "t-utils.h"
|
|
|
|
static struct {
|
|
char *k1, *k2;
|
|
} keys[] = {
|
|
{ "nisse", "banan" },
|
|
{ "foo", "bar" },
|
|
{ "kalle", "penslar" },
|
|
{ "hello", "world" },
|
|
{ "test", "fnurg" },
|
|
{ "barsk", "nitfol" },
|
|
{ "andreas", "regerar" },
|
|
{ "Nagios", "rules" },
|
|
};
|
|
|
|
static int removed;
|
|
static struct test_data {
|
|
int x, i, j;
|
|
} del;
|
|
|
|
unsigned int dkhash_count_entries(dkhash_table *table)
|
|
{
|
|
unsigned int i, count = 0;
|
|
|
|
for (i = 0; i < table->num_buckets; i++) {
|
|
dkhash_bucket *bkt;
|
|
for (bkt = table->buckets[i]; bkt; bkt = bkt->next)
|
|
count++;
|
|
}
|
|
|
|
return count;
|
|
}
|
|
|
|
int dkhash_check_table(dkhash_table *t)
|
|
{
|
|
return t ? t->entries - dkhash_count_entries(t) : 0;
|
|
}
|
|
|
|
void dkhash_debug_print_table(dkhash_table *t, const char *name, int force)
|
|
{
|
|
int delta = dkhash_check_table(t);
|
|
unsigned int count;
|
|
if (!delta && !force)
|
|
return;
|
|
|
|
count = dkhash_count_entries(t);
|
|
printf("debug data for dkhash table '%s'\n", name);
|
|
printf(" entries: %u; counted: %u; delta: %d\n",
|
|
t->entries, count, delta);
|
|
printf(" added: %u; removed: %u; delta: %d\n",
|
|
t->added, t->removed, t->added - t->removed);
|
|
}
|
|
#define dkhash_debug_table(t, force) dkhash_debug_print_table(t, #t, force)
|
|
|
|
static struct test_data *ddup(int x, int i, int j)
|
|
{
|
|
struct test_data *d;
|
|
|
|
d = malloc(sizeof(*d));
|
|
d->x = x;
|
|
d->i = i;
|
|
d->j = j;
|
|
return d;
|
|
}
|
|
|
|
struct dkhash_check {
|
|
uint entries, count, max, added, removed;
|
|
int ent_delta, addrm_delta;
|
|
};
|
|
|
|
static int del_matching(void *data)
|
|
{
|
|
struct test_data *d = (struct test_data *)data;
|
|
|
|
if (!memcmp(d, &del, sizeof(del))) {
|
|
removed++;
|
|
return DKHASH_WALK_REMOVE;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int main(int argc, char **argv)
|
|
{
|
|
dkhash_table *tx, *t;
|
|
unsigned int x;
|
|
int ret, r2;
|
|
struct test_data s;
|
|
char *p1, *p2;
|
|
char *strs[10];
|
|
char tmp[32];
|
|
|
|
t_set_colors(0);
|
|
t_start("dkhash basic test");
|
|
t = dkhash_create(512);
|
|
|
|
p1 = strdup("a not-so secret value");
|
|
dkhash_insert(t, "nisse", NULL, p1);
|
|
ok_int(dkhash_num_entries_max(t), 1, "Added one entry, so that's max");
|
|
ok_int(dkhash_num_entries_added(t), 1, "Added one entry, so one added");
|
|
ok_int(dkhash_table_size(t), 1024, "Table must be sized properly");
|
|
ok_int(dkhash_collisions(t), 0, "One entry, so zero collisions");
|
|
p2 = dkhash_get(t, "nisse", NULL);
|
|
test(p1 == p2, "get should get what insert set");
|
|
dkhash_insert(t, "kalle", "bananas", p1);
|
|
p2 = dkhash_get(t, "kalle", "bezinga");
|
|
test(p1 != p2, "we should never get the wrong key");
|
|
ok_int(2, dkhash_num_entries(t), "should be 2 entries after 2 inserts");
|
|
p2 = dkhash_remove(t, "kalle", "bezinga");
|
|
ok_int(2, dkhash_num_entries(t), "should be 2 entries after 2 inserts and 1 failed remove");
|
|
ok_int(0, dkhash_num_entries_removed(t), "should be 0 removed entries after failed remove");
|
|
p2 = dkhash_remove(t, "kalle", "bananas");
|
|
test(p1 == p2, "dkhash_remove() should return removed data");
|
|
ok_int(dkhash_num_entries(t), 1, "should be 1 entries after 2 inserts and 1 successful remove");
|
|
p2 = dkhash_remove(t, "nisse", NULL);
|
|
test(p1 == p2, "dkhash_remove() should return removed data");
|
|
ret = t_end();
|
|
|
|
t_reset();
|
|
/* lots of tests below, so we shut up while they're running */
|
|
t_verbose = 0;
|
|
|
|
t_start("dkhash_walk_data() test");
|
|
memset(&s, 0, sizeof(s));
|
|
/* first we set up the dkhash-tables */
|
|
tx = dkhash_create(16);
|
|
for (x = 0; x < ARRAY_SIZE(keys); x++) {
|
|
dkhash_insert(tx, keys[x].k1, NULL, ddup(x, 0, 0));
|
|
dkhash_insert(tx, keys[x].k2, NULL, ddup(x, 0, 0));
|
|
dkhash_insert(tx, keys[x].k1, keys[x].k2, ddup(x, 0, 0));
|
|
s.x += 3;
|
|
ok_int(s.x, dkhash_num_entries(tx), "x table adding");
|
|
}
|
|
|
|
ok_int(s.x, dkhash_num_entries(tx), "x table done adding");
|
|
|
|
for (x = 0; x < ARRAY_SIZE(keys); x++) {
|
|
del.x = x;
|
|
del.i = del.j = 0;
|
|
|
|
ok_int(s.x, dkhash_num_entries(tx), "x table pre-delete");
|
|
s.x -= 3;
|
|
dkhash_walk_data(tx, del_matching);
|
|
ok_int(s.x, dkhash_num_entries(tx), "x table post-delete");
|
|
}
|
|
|
|
test(0 == dkhash_num_entries(tx), "x table post all ops");
|
|
test(0 == dkhash_check_table(tx), "x table consistency post all ops");
|
|
dkhash_debug_table(tx, 0);
|
|
r2 = t_end();
|
|
ret = r2 ? r2 : ret;
|
|
|
|
t_reset();
|
|
for(x = 0; x < 10; x++) {
|
|
sprintf(tmp, "string %d", x);
|
|
strs[x] = strdup(tmp);
|
|
}
|
|
|
|
t_start("dkhash single bucket add remove forward");
|
|
|
|
t = dkhash_create(1);
|
|
for(x = 0; x < 10; x++) {
|
|
dkhash_insert(t, strs[x], NULL, strs[x]);
|
|
}
|
|
for(x = 0; x < 10; x++) {
|
|
p1 = strs[x];
|
|
p2 = dkhash_remove(t, p1, NULL);
|
|
test(p1 == p2, "remove should return a value");
|
|
}
|
|
r2 = t_end();
|
|
ret = r2 ? r2 : ret;
|
|
t_reset();
|
|
|
|
t_start("dkhash single bucket add remove backward");
|
|
|
|
t = dkhash_create(1);
|
|
for(x = 0; x < 10; x++) {
|
|
dkhash_insert(t, strs[x], NULL, strs[x]);
|
|
}
|
|
for(x = 9; x; x--) {
|
|
p1 = strs[x];
|
|
p2 = dkhash_remove(t, p1, NULL);
|
|
test(p1 == p2, "remove should return a value");
|
|
}
|
|
|
|
dkhash_destroy(t);
|
|
|
|
r2 = t_end();
|
|
return r2 ? r2 : ret;
|
|
}
|