blob: aa794721bb317667d7cd85479b28fb70ddd9f3a9 [file] [log] [blame] [raw]
#ifndef H_LIST_HASH_TESTS_H
#define H_LIST_HASH_TESTS_H
#include "fio_dict.h"
#include "fio_hash_table.h"
#include <errno.h>
#include <stdio.h>
#include <string.h>
struct ht_dict_test_s {
uint64_t len;
fio_ht_node_s node;
char data[];
};
static void test_dict_store(fio_ht_s *dict, char *name, char *data) {
uint64_t data_len = strlen(data);
struct ht_dict_test_s *entry = malloc(sizeof(*entry) + data_len + 1);
if (!entry)
perror("WTF? can't allocate dictionary entry"), exit(errno);
memcpy(entry->data, data, data_len + 1);
entry->len = data_len;
entry = (void *)fio_ht_add(dict, &entry->node, fio_ht_hash_cstr(name));
if (entry) {
entry = fio_ht_object(struct ht_dict_test_s, node, (void *)(entry));
fprintf(stderr, "collision node: %p -> %p\n", (void *)entry,
(void *)(&entry->node));
fprintf(
stderr,
"ERROR: Collision detected for %s with data (len: %llu =? %llu):\n%s\n",
name, data_len, entry->len, entry->data);
free(entry);
}
}
static void test_dict_remove(fio_ht_s *dict, char *name) {
uint64_t name_len = strlen(name);
struct ht_dict_test_s *entry =
(void *)fio_ht_pop(dict, fio_ht_hash(name, name_len));
if (!entry) {
fprintf(stderr, "ERROR: Can't find entry for removal: %s\n", name);
return;
}
entry = fio_ht_object(struct ht_dict_test_s, node, (void *)(entry));
free(entry);
}
static void test_fio_hash_table(void) {
const size_t TEST_CYCLES = 2000000UL;
fio_list_s list = FIO_LIST_INIT(list);
fio_ht_s dict = FIO_HASH_TABLE_INIT(dict);
fprintf(stderr, "Dictionary test %p\n", (void *)&dict);
{
uint64_t result = fio_ht_hash(
"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e", 15);
fprintf(stderr, "* fio_ht_hash simple SipHash test %s\n",
(result == 0xa129ca6149be45e5ULL) ? "passed" : "FAILED");
fprintf(stderr, "* fio_ht_hash and fio_ht_hash_cstr %s\n",
(fio_ht_hash("testing if they match", 21) ==
fio_ht_hash_cstr("testing if they match"))
? "match"
: "FAILED to match!");
}
struct ht_dict_test_s *item;
char tmp[20] = {0};
for (size_t i = 0; i < 8; i++) {
memcpy(tmp, "item ", 5);
tmp[5] = '1' + i;
tmp[6] = 0;
test_dict_store(&dict, tmp, tmp);
}
if (dict.count != 8)
fprintf(stderr, "ERROR: Hash table missing objects!\n");
fio_ht_for_each(struct ht_dict_test_s, node, item, dict)
fprintf(stderr, "* %s\n", item->data);
for (size_t i = 0; i < 8; i++) {
memcpy(tmp, "item ", 5);
tmp[5] = '1' + i;
tmp[6] = 0;
test_dict_remove(&dict, tmp);
}
if (dict.count)
fprintf(stderr, "ERROR: Hash table should be empty!\n");
memcpy(tmp, "item ", 5);
size_t i_tmp, pos;
for (size_t i = 0; i < TEST_CYCLES; i++) {
i_tmp = i;
pos = 5;
while (i_tmp) {
tmp[pos] = '0' + (i_tmp & 0xf);
pos++;
i_tmp >>= 4;
}
tmp[pos] = 0;
test_dict_store(&dict, tmp, tmp);
}
if (!dict.bins)
fprintf(stderr, "ERROR: Hash table should have bins allocated by now!\n");
if (dict.count != TEST_CYCLES)
fprintf(stderr,
"ERROR: Hash table should have more elements, %llu != %lu!\n",
dict.count, TEST_CYCLES);
struct ht_dict_test_s *itm;
fio_ht_for_each(struct ht_dict_test_s, node, itm, dict) {
fio_ht_remove(&itm->node);
free(itm);
}
if (dict.count)
fprintf(stderr, "ERROR: Hash table should be empty!\n");
fio_ht_rehash(&dict, 0);
}
struct dict_test {
fio_dict_s node;
char *value;
};
static void test_fio_dict_task(fio_dict_s *node, void *arg) {
char *key = fio_node2obj(struct dict_test, node, node)->value;
fprintf(stderr, "*Dictionary test: task for (%p) %s\n", (void *)node, key);
fio_dict_remove(node);
node = fio_dict_get(arg, key, 9);
if (node)
fprintf(stderr,
"ERROR (dict): (%p) \"%s\" "
"should have been removed\n",
(void *)node, fio_node2obj(struct dict_test, node, node)->value);
}
static void test_fio_dict_small_task(fio_dict_s *node, void *arg) {
char *key = fio_node2obj(struct dict_test, node, node)->value;
fprintf(stderr, "*Dictionary test: slice (%p) %s %s\n", (void *)node, key,
arg ? arg : "");
}
static void test_fio_dict(void) {
fio_dict_s dict = FIO_DICT_INIT;
fio_dict_s *tmp;
struct dict_test items[5] = {
{.value = "channel 1"}, {.value = "channel 2"}, {.value = "Ahannel A"},
{.value = "channel 3"}, {.value = "channel 4"},
};
for (size_t i = 0; i < 5; i++) {
tmp = fio_dict_set(&dict, items[i].value, 9, &items[i].node);
if (tmp)
fprintf(stderr, "* ERROR (dict): an item %p (%s) shouldn't exist\n",
(void *)tmp, fio_node2obj(struct dict_test, node, tmp)->value);
}
fio_dict_each(fio_dict_prefix(&dict, (void *)"chan", 4),
test_fio_dict_small_task, NULL);
fprintf(stderr, "* Next 7 slices test glob matching.\n");
fio_dict_each_match_glob(&dict, "Ahannel A", 9, test_fio_dict_small_task,
"(exact match)");
fio_dict_each_match_glob(&dict, "A*A", 3, test_fio_dict_small_task, "(A*A)");
fio_dict_each_match_glob(&dict, "Ahannel ?", 9, test_fio_dict_small_task,
"(Ahannel ?)");
fio_dict_each_match_glob(&dict, "Ahannel[ ]A", 11, test_fio_dict_small_task,
"(Ahannel[ ]A)");
fio_dict_each_match_glob(&dict, "Ahannel [A]", 11, test_fio_dict_small_task,
"(Ahannel [A])");
fio_dict_each_match_glob(&dict, "Ahannel[^a-z]A", 14,
test_fio_dict_small_task, "(Ahannel[^a-z]A)");
fio_dict_each_match_glob(&dict, "Ahannel [A-Z]", 13, test_fio_dict_small_task,
"(Ahannel [A-Z])");
fio_dict_each_match_glob(&dict, "A?a*A", 5, test_fio_dict_small_task,
"(A?n*A)");
fio_dict_each_match_glob(&dict, "A?a* A", 6, test_fio_dict_small_task,
"(A?n* A)");
fio_dict_each_match_glob(&dict, "A?a*[^a-z]A", 11, test_fio_dict_small_task,
"(everything)");
fprintf(stderr, "* Next slices test glob matching for: *[0-9].\n");
fio_dict_each_match_glob(&dict, "*[1-9]", 6, test_fio_dict_small_task,
"(everything)");
fprintf(stderr, "* Match and clear at the same time.\n");
fio_dict_each(&dict, test_fio_dict_task, &dict);
if (!fio_dict_isempty(&dict))
fprintf(
stderr,
"ERROR (dict): Dictionary should be empty, but nodes still exist!\n");
if (fio_glob_match((uint8_t *)"A String To Match", 17, (uint8_t *)"[A-Z]*",
6))
fprintf(stderr, "* Simple glob: [A-Z]*\n");
if (fio_glob_match((uint8_t *)"A String To Match", 17, (uint8_t *)"A String*",
9))
fprintf(stderr, "* Simple glob: A String*\n");
if (fio_glob_match((uint8_t *)"A String To Match", 17,
(uint8_t *)"? Str?ng To Matc?", 17))
fprintf(stderr, "* Simple glob: ? Str?ng To Matc?\n");
if (fio_glob_match((uint8_t *)"A String To Match", 17,
(uint8_t *)"*ch", 3))
fprintf(stderr, "* Simple glob: *ch\n");
if (fio_glob_match((uint8_t *)"A String To Match", 17,
(uint8_t *)"[A-Z] String*ch", 15))
fprintf(stderr, "* Simple glob matching might be working.\n");
else
fprintf(stderr, "* Simple glob matching is broken.\n");
}
static void test_fio_types(void) {
test_fio_hash_table();
test_fio_dict();
}
#endif