1
0
mirror of https://github.com/rtbrick/bngblaster.git synced 2024-05-06 15:54:57 +00:00
Files
rtbrick-bngblaster/code/libdict/unit_tests.c
2023-12-21 11:03:22 +00:00

817 lines
25 KiB
C

/* unit_tests.c
* Copyright (C) 2012 Farooq Mela. All rights reserved. */
#include <assert.h>
#include <float.h>
#include <limits.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <CUnit/CUnit.h>
#include <CUnit/Basic.h>
#include "dict.h"
#include "util.h"
#include "src/hashtable_common.h" /* For dict_prime_geq() */
#define TEST_FUNC(func) { (char *)#func, func }
struct key_info {
char *key, *value, *alt;
};
struct closest_lookup_info {
const char *key;
const char *le_key, *le_val;
const char *lt_key, *lt_val;
const char *ge_key, *ge_val;
const char *gt_key, *gt_val;
};
void test_basic(dict *dct, const struct key_info *keys, const unsigned nkeys, bool keys_sorted);
void test_basic_hashtable_1bucket(void);
void test_basic_hashtable2_1bucket(void);
void test_basic_hashtable_nbuckets(void);
void test_basic_hashtable2_nbuckets(void);
void test_basic_height_balanced_tree(void);
void test_basic_path_reduction_tree(void);
void test_basic_red_black_tree(void);
void test_basic_skiplist(void);
void test_basic_splay_tree(void);
void test_basic_treap(void);
void test_basic_weight_balanced_tree(void);
void test_search(dict *dct, dict_itor *itor, const char *key, const char *value);
void test_closest_lookup(dict *dct, unsigned nkeys, bool keys_sorted);
void test_primes_geq(void);
void test_version_string(void);
static CU_TestInfo basic_tests[] = {
TEST_FUNC(test_basic_hashtable_1bucket),
TEST_FUNC(test_basic_hashtable2_1bucket),
TEST_FUNC(test_basic_hashtable_nbuckets),
TEST_FUNC(test_basic_hashtable2_nbuckets),
TEST_FUNC(test_basic_height_balanced_tree),
TEST_FUNC(test_basic_path_reduction_tree),
TEST_FUNC(test_basic_red_black_tree),
TEST_FUNC(test_basic_skiplist),
TEST_FUNC(test_basic_splay_tree),
TEST_FUNC(test_basic_treap),
TEST_FUNC(test_basic_weight_balanced_tree),
TEST_FUNC(test_primes_geq),
TEST_FUNC(test_version_string),
CU_TEST_INFO_NULL
};
#define TEST_SUITE(suite) { .pName = (char *)#suite, .pTests = suite }
static CU_SuiteInfo test_suites[] = {
TEST_SUITE(basic_tests),
CU_SUITE_INFO_NULL
};
static size_t bytes_malloced = 0;
static void*
custom_malloc(size_t n)
{
size_t* p = malloc(sizeof(size_t) + n);
assert(p);
bytes_malloced += n;
p[0] = n;
return &p[1];
}
static void
custom_free(void* p)
{
assert(p);
size_t* sp = p;
bytes_malloced -= sp[-1];
free(sp - 1);
}
int
main()
{
dict_malloc_func = custom_malloc;
dict_free_func = custom_free;
if (CU_initialize_registry() != CUE_SUCCESS ||
CU_register_suites(test_suites) != CUE_SUCCESS) {
fprintf(stderr, "Failed to initialize tests!\n");
exit(EXIT_FAILURE);
}
CU_basic_set_mode(CU_BRM_SILENT);
if (CU_basic_run_tests() != CUE_SUCCESS) {
fprintf(stderr, "Failed to run tests!\n");
exit(EXIT_FAILURE);
}
unsigned failures = 0;
for (const CU_FailureRecord *f = CU_get_failure_list(); f; f = f->pNext) {
fprintf(stderr, "%u: %s (%s:%u): %s\n",
++failures, f->pTest->pName, f->strFileName, f->uiLineNumber, f->strCondition);
}
CU_cleanup_registry();
return failures ? EXIT_FAILURE : EXIT_SUCCESS;
}
static const struct key_info unsorted_keys[] = {
{ "d", "D", "d" },
{ "b", "B", "b" },
{ "a", "A", "a" },
{ "c", "C", "c" },
{ "g", "G", "g" },
{ "f", "F", "f" },
{ "h", "H", "h" },
{ "y", "Y", "y" },
{ "z", "Z", "z" },
{ "x", "X", "x" },
{ "j", "J", "j" },
{ "r", "R", "r" },
{ "q", "Q", "q" },
{ "p", "P", "p" },
{ "l", "L", "l" },
{ "m", "M", "m" },
{ "s", "S", "s" },
{ "t", "T", "t" },
{ "u", "U", "u" },
{ "da", "DA", "da" },
{ "ba", "BA", "ba" },
{ "aa", "AA", "aa" },
{ "ca", "CA", "ca" },
{ "ga", "GA", "ga" },
{ "fa", "FA", "fa" },
{ "ha", "HA", "ha" },
{ "ya", "YA", "ya" },
{ "za", "ZA", "za" },
{ "xa", "XA", "xa" },
{ "ja", "JA", "ja" },
{ "ra", "RA", "ra" },
{ "qa", "QA", "qa" },
{ "pa", "PA", "pa" },
{ "la", "LA", "la" },
{ "ma", "MA", "ma" },
{ "sa", "SA", "sa" },
{ "ta", "TA", "ta" },
{ "ua", "UA", "ua" },
};
#define NUM_UNSORTED_KEYS (sizeof(unsorted_keys) / sizeof(unsorted_keys[0]))
static const struct key_info sorted_keys[] = {
{ "a", "A", "a" },
{ "aa", "AA", "aa" },
{ "b", "B", "b" },
{ "ba", "BA", "ba" },
{ "c", "C", "c" },
{ "ca", "CA", "ca" },
{ "d", "D", "d" },
{ "da", "DA", "da" },
{ "f", "F", "f" },
{ "fa", "FA", "fa" },
{ "g", "G", "g" },
{ "ga", "GA", "ga" },
{ "h", "H", "h" },
{ "ha", "HA", "ha" },
{ "j", "J", "j" },
{ "ja", "JA", "ja" },
{ "l", "L", "l" },
{ "la", "LA", "la" },
{ "m", "M", "m" },
{ "ma", "MA", "ma" },
{ "p", "P", "p" },
{ "pa", "PA", "pa" },
{ "q", "Q", "q" },
{ "qa", "QA", "qa" },
{ "r", "R", "r" },
{ "ra", "RA", "ra" },
{ "s", "S", "s" },
{ "sa", "SA", "sa" },
{ "t", "T", "t" },
{ "ta", "TA", "ta" },
{ "u", "U", "u" },
{ "ua", "UA", "ua" },
{ "x", "X", "x" },
{ "xa", "XA", "xa" },
{ "y", "Y", "y" },
{ "ya", "YA", "ya" },
{ "z", "Z", "z" },
{ "za", "ZA", "za" },
};
#define NUM_SORTED_KEYS (sizeof(sorted_keys) / sizeof(sorted_keys[0]))
static_assert(NUM_SORTED_KEYS == NUM_UNSORTED_KEYS, "sorted keys and unsorted keys count mismatch");
static const struct closest_lookup_info closest_lookup_infos[] = {
{.key = "_",
.ge_key = "a", .ge_val = "A",
.gt_key = "a", .gt_val = "A"},
{.key = "a",
.le_key = "a", .le_val = "A",
.ge_key = "a", .ge_val = "A",
.gt_key = "aa", .gt_val = "AA"},
{.key = "aa",
.le_key = "aa", .le_val = "AA",
.lt_key = "a", .lt_val = "A",
.ge_key = "aa", .ge_val = "AA",
.gt_key = "b", .gt_val = "B"},
{.key = "ab",
.le_key = "aa", .le_val = "AA",
.lt_key = "aa", .lt_val = "AA",
.ge_key = "b", .ge_val = "B",
.gt_key = "b", .gt_val = "B"},
{.key = "m",
.le_key = "m", .le_val = "M",
.lt_key = "la", .lt_val = "LA",
.ge_key = "m", .ge_val = "M",
.gt_key = "ma", .gt_val = "MA"},
{.key = "n",
.le_key = "ma", .le_val = "MA",
.lt_key = "ma", .lt_val = "MA",
.ge_key = "p", .ge_val = "P",
.gt_key = "p", .gt_val = "P"},
{.key = "za",
.le_key = "za", .le_val = "ZA",
.lt_key = "z", .lt_val = "Z",
.ge_key = "za", .ge_val = "ZA"},
{.key = "zb",
.le_key = "za", .le_val = "ZA",
.lt_key = "za", .lt_val = "ZA"},
};
#define NUM_CLOSEST_LOOKUP_INFOS (sizeof(closest_lookup_infos) / sizeof(closest_lookup_infos[0]))
void
test_search(dict *dct, dict_itor *itor, const char *key, const char *value)
{
void **search = dict_search(dct, key);
if (value == NULL) {
CU_ASSERT_PTR_NULL(search);
} else {
CU_ASSERT_PTR_NOT_NULL(search);
CU_ASSERT_EQUAL(*search, value);
}
if (itor != NULL) {
if (value == NULL) {
CU_ASSERT_FALSE(dict_itor_search(itor, key));
CU_ASSERT_FALSE(dict_itor_valid(itor));
} else {
CU_ASSERT_TRUE(dict_itor_search(itor, key));
CU_ASSERT_TRUE(dict_itor_valid(itor));
CU_ASSERT_EQUAL(dict_itor_key(itor), key);
CU_ASSERT_PTR_NOT_NULL(dict_itor_datum(itor));
CU_ASSERT_EQUAL(*dict_itor_datum(itor), value);
}
}
}
void
test_closest_lookup(dict *dct, unsigned nkeys, bool keys_sorted)
{
if (dict_is_sorted(dct) && keys_sorted) {
for (unsigned i = 0; i < nkeys; ++i) {
const void* key = NULL;
void* datum = NULL;
if (dct->_vtable->select) {
CU_ASSERT_TRUE(dict_select(dct, i, &key, &datum));
CU_ASSERT_EQUAL(key, sorted_keys[i].key);
CU_ASSERT_EQUAL(datum, sorted_keys[i].value);
}
}
const void* key = NULL;
void* datum = NULL;
CU_ASSERT_FALSE(dict_select(dct, nkeys, &key, &datum));
CU_ASSERT_EQUAL(key, (const void*)NULL);
CU_ASSERT_PTR_NULL(datum);
}
dict_itor* itor = dict_itor_new(dct);
for (unsigned i = 0; i < NUM_CLOSEST_LOOKUP_INFOS; i++) {
const struct closest_lookup_info* const info = &closest_lookup_infos[i];
if (!dict_is_sorted(dct)) {
CU_ASSERT_PTR_NULL(dct->_vtable->search_le);
CU_ASSERT_PTR_NULL(dct->_vtable->search_lt);
CU_ASSERT_PTR_NULL(dct->_vtable->search_ge);
CU_ASSERT_PTR_NULL(dct->_vtable->search_gt);
CU_ASSERT_PTR_NULL(itor->_vtable->search_le);
CU_ASSERT_PTR_NULL(itor->_vtable->search_lt);
CU_ASSERT_PTR_NULL(itor->_vtable->search_ge);
CU_ASSERT_PTR_NULL(itor->_vtable->search_gt);
const void* key = NULL;
void* datum = NULL;
CU_ASSERT_FALSE(dict_select(dct, i, &key, &datum));
CU_ASSERT_EQUAL(key, (const void*)NULL);
CU_ASSERT_PTR_NULL(datum);
CU_ASSERT_PTR_NULL(dict_search_le(dct, info->key));
CU_ASSERT_PTR_NULL(dict_search_lt(dct, info->key));
CU_ASSERT_PTR_NULL(dict_search_ge(dct, info->key));
CU_ASSERT_PTR_NULL(dict_search_gt(dct, info->key));
continue;
}
if (nkeys < NUM_SORTED_KEYS)
continue;
if (info->le_key) {
if (dct->_vtable->search_le) {
CU_ASSERT_PTR_NOT_NULL(dict_search_le(dct, info->key));
void **datum = dict_search_le(dct, info->key);
CU_ASSERT_TRUE(datum != NULL && *datum != NULL && strcmp(*datum, info->le_val) == 0);
}
if (itor->_vtable->search_le) {
CU_ASSERT_TRUE(dict_itor_search_le(itor, info->key));
CU_ASSERT_TRUE(dict_itor_valid(itor));
CU_ASSERT_STRING_EQUAL(dict_itor_key(itor), info->le_key);
void **datum = dict_itor_datum(itor);
CU_ASSERT_TRUE(datum != NULL && *datum != NULL && strcmp(*datum, info->le_val) == 0);
}
} else {
CU_ASSERT_PTR_NULL(dict_search_le(dct, info->key));
CU_ASSERT_FALSE(dict_itor_search_le(itor, info->key));
CU_ASSERT_FALSE(dict_itor_valid(itor));
CU_ASSERT_PTR_NULL(dict_itor_key(itor));
CU_ASSERT_PTR_NULL(dict_itor_datum(itor));
}
if (info->lt_key) {
if (dct->_vtable->search_lt) {
CU_ASSERT_PTR_NOT_NULL(dict_search_lt(dct, info->key));
void** datum = dict_search_lt(dct, info->key);
CU_ASSERT_TRUE(datum != NULL && *datum != NULL && strcmp(*datum, info->lt_val) == 0);
}
if (itor->_vtable->search_lt) {
CU_ASSERT_TRUE(dict_itor_search_lt(itor, info->key));
CU_ASSERT_TRUE(dict_itor_valid(itor));
CU_ASSERT_STRING_EQUAL(dict_itor_key(itor), info->lt_key);
void** datum = dict_itor_datum(itor);
CU_ASSERT_TRUE(datum != NULL && *datum != NULL && strcmp(*datum, info->lt_val) == 0);
}
} else {
CU_ASSERT_PTR_NULL(dict_search_lt(dct, info->key));
CU_ASSERT_FALSE(dict_itor_search_lt(itor, info->key));
CU_ASSERT_FALSE(dict_itor_valid(itor));
CU_ASSERT_PTR_NULL(dict_itor_key(itor));
CU_ASSERT_PTR_NULL(dict_itor_datum(itor));
}
if (info->ge_key) {
if (dct->_vtable->search_ge) {
CU_ASSERT_PTR_NOT_NULL(dict_search_ge(dct, info->key));
void** datum = dict_search_ge(dct, info->key);
CU_ASSERT_TRUE(datum != NULL && *datum != NULL && strcmp(*datum, info->ge_val) == 0);
}
if (itor->_vtable->search_ge) {
CU_ASSERT_TRUE(dict_itor_search_ge(itor, info->key));
CU_ASSERT_TRUE(dict_itor_valid(itor));
CU_ASSERT_STRING_EQUAL(dict_itor_key(itor), info->ge_key);
void** datum = dict_itor_datum(itor);
CU_ASSERT_TRUE(datum != NULL && *datum != NULL && strcmp(*datum, info->ge_val) == 0);
}
} else {
CU_ASSERT_PTR_NULL(dict_search_ge(dct, info->key));
CU_ASSERT_FALSE(dict_itor_search_ge(itor, info->key));
CU_ASSERT_FALSE(dict_itor_valid(itor));
CU_ASSERT_PTR_NULL(dict_itor_key(itor));
CU_ASSERT_PTR_NULL(dict_itor_datum(itor));
}
if (info->gt_key) {
if (dct->_vtable->search_gt) {
CU_ASSERT_PTR_NOT_NULL(dict_search_gt(dct, info->key));
void** datum = dict_search_gt(dct, info->key);
CU_ASSERT_TRUE(datum != NULL && *datum != NULL && strcmp(*datum, info->gt_val) == 0);
}
if (itor->_vtable->search_gt) {
CU_ASSERT_TRUE(dict_itor_search_gt(itor, info->key));
CU_ASSERT_TRUE(dict_itor_valid(itor));
CU_ASSERT_STRING_EQUAL(dict_itor_key(itor), info->gt_key);
void** datum = dict_itor_datum(itor);
CU_ASSERT_TRUE(datum != NULL && *datum != NULL && strcmp(*datum, info->gt_val) == 0);
}
} else {
CU_ASSERT_PTR_NULL(dict_search_gt(dct, info->key));
CU_ASSERT_FALSE(dict_itor_search_gt(itor, info->key));
CU_ASSERT_FALSE(dict_itor_valid(itor));
CU_ASSERT_PTR_NULL(dict_itor_key(itor));
CU_ASSERT_PTR_NULL(dict_itor_datum(itor));
}
}
dict_itor_free(itor);
}
void test_basic(dict *dct, const struct key_info *keys, const unsigned nkeys, bool keys_sorted)
{
CU_ASSERT_TRUE(dict_verify(dct));
dict_itor *itor = dict_itor_new(dct);
CU_ASSERT_PTR_NOT_NULL(itor);
CU_ASSERT_FALSE(dict_itor_valid(itor));
CU_ASSERT_FALSE(dict_itor_next(itor));
CU_ASSERT_FALSE(dict_itor_valid(itor));
CU_ASSERT_FALSE(dict_itor_prev(itor));
CU_ASSERT_FALSE(dict_itor_valid(itor));
for (unsigned i = 0; i < nkeys; ++i) {
dict_insert_result result = dict_insert(dct, keys[i].key);
CU_ASSERT_TRUE(result.inserted);
CU_ASSERT_PTR_NOT_NULL(result.datum_ptr);
CU_ASSERT_PTR_NULL(*result.datum_ptr);
*result.datum_ptr = keys[i].value;
CU_ASSERT_TRUE(dict_verify(dct));
for (unsigned j = 0; j <= i; ++j)
test_search(dct, itor, keys[j].key, keys[j].value);
for (unsigned j = i + 1; j < nkeys; ++j)
test_search(dct, itor, keys[j].key, NULL);
}
CU_ASSERT_EQUAL(dict_count(dct), nkeys);
if (dct->_vtable->insert == (dict_insert_func)hashtable_insert ||
dct->_vtable->insert == (dict_insert_func)hashtable2_insert) {
/* Verify that hashtable_resize works as expected. */
if (dct->_vtable->insert == (dict_insert_func)hashtable_insert) {
CU_ASSERT_TRUE(hashtable_resize(dict_private(dct), 3));
} else {
CU_ASSERT_TRUE(hashtable2_resize(dict_private(dct),
dict_prime_geq(nkeys * 5)));
}
CU_ASSERT_TRUE(dict_verify(dct));
CU_ASSERT_EQUAL(dict_count(dct), nkeys);
for (unsigned j = 0; j < nkeys; ++j)
test_search(dct, NULL, keys[j].key, keys[j].value);
}
for (unsigned i = 0; i < nkeys; ++i)
test_search(dct, itor, keys[i].key, keys[i].value);
for (unsigned i = 0; i < nkeys; ++i) {
dict_insert_result result = dict_insert(dct, keys[i].key);
CU_ASSERT_FALSE(result.inserted);
CU_ASSERT_PTR_NOT_NULL(result.datum_ptr);
CU_ASSERT_EQUAL(*result.datum_ptr, keys[i].value);
CU_ASSERT_TRUE(dict_verify(dct));
}
CU_ASSERT_EQUAL(dict_count(dct), nkeys);
dict_itor *first = dict_itor_new(dct);
CU_ASSERT_PTR_NOT_NULL(first);
CU_ASSERT_FALSE(dict_itor_valid(first));
if (nkeys > 0) {
CU_ASSERT_TRUE(dict_itor_first(first));
CU_ASSERT_TRUE(dict_itor_valid(first));
} else {
CU_ASSERT_FALSE(dict_itor_first(first));
CU_ASSERT_FALSE(dict_itor_valid(first));
}
dict_itor *last = dict_itor_new(dct);
CU_ASSERT_PTR_NOT_NULL(last);
CU_ASSERT_FALSE(dict_itor_valid(last));
if (nkeys > 0) {
CU_ASSERT_TRUE(dict_itor_last(last));
CU_ASSERT_TRUE(dict_itor_valid(last));
} else {
CU_ASSERT_FALSE(dict_itor_last(last));
CU_ASSERT_FALSE(dict_itor_valid(last));
}
if (dict_is_sorted(dct)) {
if (nkeys <= 1) {
CU_ASSERT_TRUE(dict_itor_compare(first, last) == 0);
CU_ASSERT_TRUE(dict_itor_compare(last, first) == 0);
} else {
CU_ASSERT_TRUE(dict_itor_compare(first, last) < 0);
CU_ASSERT_TRUE(dict_itor_compare(last, first) > 0);
}
}
char *last_key = NULL;
unsigned n = 0;
for (dict_itor_first(itor); dict_itor_valid(itor); dict_itor_next(itor)) {
CU_ASSERT_PTR_NOT_NULL(dict_itor_key(itor));
CU_ASSERT_PTR_NOT_NULL(dict_itor_datum(itor));
CU_ASSERT_PTR_NOT_NULL(*dict_itor_datum(itor));
if (dict_is_sorted(dct)) {
CU_ASSERT_TRUE(dict_itor_compare(itor, itor) == 0);
if (n == 0) {
CU_ASSERT_TRUE(dict_itor_compare(itor, first) == 0);
CU_ASSERT_TRUE(dict_itor_compare(first, itor) == 0);
} else {
CU_ASSERT_TRUE(dict_itor_compare(itor, first) > 0);
CU_ASSERT_TRUE(dict_itor_compare(first, itor) < 0);
}
if (n == nkeys - 1) {
CU_ASSERT_TRUE(dict_itor_compare(itor, last) == 0);
CU_ASSERT_TRUE(dict_itor_compare(last, itor) == 0);
} else {
CU_ASSERT_TRUE(dict_itor_compare(itor, last) < 0);
CU_ASSERT_TRUE(dict_itor_compare(last, itor) > 0);
}
if (keys_sorted) {
CU_ASSERT_EQUAL(dict_itor_key(itor), keys[n].key);
CU_ASSERT_EQUAL(*dict_itor_datum(itor), keys[n].value);
}
}
unsigned keys_matched = 0;
for (unsigned i = 0; i < nkeys; ++i) {
if (dict_itor_key(itor) == keys[i].key) {
CU_ASSERT_EQUAL(*dict_itor_datum(itor), keys[i].value);
keys_matched++;
} else {
CU_ASSERT_NOT_EQUAL(*dict_itor_datum(itor), keys[i].value);
}
}
CU_ASSERT_EQUAL(keys_matched, 1);
if (dict_is_sorted(dct)) {
if (last_key) {
CU_ASSERT_TRUE(strcmp(last_key, dict_itor_key(itor)) < 0);
}
last_key = dict_itor_key(itor);
}
++n;
}
CU_ASSERT_EQUAL(n, nkeys);
last_key = NULL;
n = 0;
for (dict_itor_last(itor); dict_itor_valid(itor); dict_itor_prev(itor)) {
CU_ASSERT_PTR_NOT_NULL(dict_itor_key(itor));
CU_ASSERT_PTR_NOT_NULL(dict_itor_datum(itor));
CU_ASSERT_PTR_NOT_NULL(*dict_itor_datum(itor));
if (dict_is_sorted(dct) && keys_sorted) {
CU_ASSERT_EQUAL(dict_itor_key(itor), keys[nkeys - 1 - n].key);
CU_ASSERT_EQUAL(*dict_itor_datum(itor), keys[nkeys - 1 - n].value);
}
unsigned keys_matched = 0;
for (unsigned i = 0; i < nkeys; ++i) {
if (dict_itor_key(itor) == keys[i].key) {
CU_ASSERT_EQUAL(*dict_itor_datum(itor), keys[i].value);
keys_matched++;
} else {
CU_ASSERT_NOT_EQUAL(*dict_itor_datum(itor), keys[i].value);
}
}
CU_ASSERT_EQUAL(keys_matched, 1);
if (dict_is_sorted(dct)) {
if (last_key) {
CU_ASSERT_TRUE(strcmp(last_key, dict_itor_key(itor)) > 0);
}
last_key = dict_itor_key(itor);
}
++n;
}
CU_ASSERT_EQUAL(n, nkeys);
for (unsigned i = 0; i < nkeys; ++i) {
dict_insert_result result = dict_insert(dct, keys[i].key);
CU_ASSERT_FALSE(result.inserted);
CU_ASSERT_PTR_NOT_NULL(result.datum_ptr);
CU_ASSERT_PTR_NOT_NULL(*result.datum_ptr);
*result.datum_ptr = keys[i].alt;
CU_ASSERT_TRUE(dict_verify(dct));
}
CU_ASSERT_EQUAL(dict_count(dct), nkeys);
for (unsigned i = 0; i < nkeys; ++i)
test_search(dct, itor, keys[i].key, keys[i].alt);
for (unsigned i = 0; i < nkeys; ++i) {
test_search(dct, itor, keys[i].key, keys[i].alt);
dict_remove_result result = dict_remove(dct, keys[i].key);
CU_ASSERT_TRUE(result.removed);
CU_ASSERT_EQUAL(result.key, keys[i].key);
CU_ASSERT_EQUAL(result.datum, keys[i].alt);
CU_ASSERT_TRUE(dict_verify(dct));
result = dict_remove(dct, keys[i].key);
CU_ASSERT_FALSE(result.removed);
CU_ASSERT_PTR_NULL(result.key);
CU_ASSERT_PTR_NULL(result.datum);
for (unsigned j = 0; j <= i; ++j) {
test_search(dct, itor, keys[j].key, NULL);
}
for (unsigned j = i + 1; j < nkeys; ++j) {
test_search(dct, itor, keys[j].key, keys[j].alt);
}
}
for (unsigned i = 0; i < nkeys; ++i) {
dict_insert_result result = dict_insert(dct, keys[i].key);
CU_ASSERT_TRUE(result.inserted);
CU_ASSERT_PTR_NOT_NULL(result.datum_ptr);
CU_ASSERT_PTR_NULL(*result.datum_ptr);
*result.datum_ptr = keys[i].value;
CU_ASSERT_TRUE(dict_verify(dct));
}
CU_ASSERT_EQUAL(dict_count(dct), nkeys);
CU_ASSERT_EQUAL(dict_clear(dct, NULL), nkeys);
CU_ASSERT_TRUE(dict_verify(dct));
CU_ASSERT_EQUAL(dict_count(dct), 0);
for (unsigned i = 0; i < nkeys; ++i) {
test_search(dct, itor, keys[i].key, NULL);
dict_insert_result result = dict_insert(dct, keys[i].key);
CU_ASSERT_TRUE(result.inserted);
CU_ASSERT_PTR_NOT_NULL(result.datum_ptr);
CU_ASSERT_PTR_NULL(*result.datum_ptr);
*result.datum_ptr = keys[i].value;
CU_ASSERT_TRUE(dict_verify(dct));
}
CU_ASSERT_EQUAL(dict_count(dct), nkeys);
test_closest_lookup(dct, nkeys, keys_sorted);
for (unsigned i = 0; i < nkeys; ++i) {
CU_ASSERT_TRUE(dict_itor_search(itor, keys[i].key));
CU_ASSERT_TRUE(dict_itor_valid(itor));
CU_ASSERT_EQUAL(dict_itor_key(itor), keys[i].key);
CU_ASSERT_PTR_NOT_NULL(dict_itor_datum(itor));
CU_ASSERT_EQUAL(*dict_itor_datum(itor), keys[i].value);
CU_ASSERT_TRUE(dict_itor_remove(itor));
CU_ASSERT_FALSE(dict_itor_valid(itor));
CU_ASSERT_FALSE(dict_itor_search(itor, keys[i].key));
CU_ASSERT_FALSE(dict_itor_valid(itor));
}
CU_ASSERT_EQUAL(dict_count(dct), 0);
for (unsigned i = 0; i < nkeys; ++i) {
test_search(dct, itor, keys[i].key, NULL);
dict_insert_result result = dict_insert(dct, keys[i].key);
CU_ASSERT_TRUE(result.inserted);
CU_ASSERT_PTR_NOT_NULL(result.datum_ptr);
CU_ASSERT_PTR_NULL(*result.datum_ptr);
*result.datum_ptr = keys[i].value;
CU_ASSERT_TRUE(dict_verify(dct));
}
CU_ASSERT_EQUAL(dict_count(dct), nkeys);
dict_itor_free(itor);
dict_itor_free(first);
dict_itor_free(last);
CU_ASSERT_EQUAL(dict_count(dct), nkeys);
CU_ASSERT_EQUAL(dict_free(dct, NULL), nkeys);
}
void test_basic_hashtable_1bucket()
{
for (unsigned n = 0; n <= NUM_SORTED_KEYS; ++n) {
CU_ASSERT_EQUAL(bytes_malloced, 0);
test_basic(hashtable_dict_new(dict_str_cmp, dict_str_hash, 1), unsorted_keys, n, false);
CU_ASSERT_EQUAL(bytes_malloced, 0);
test_basic(hashtable_dict_new(dict_str_cmp, dict_str_hash, 1), sorted_keys, n, true);
CU_ASSERT_EQUAL(bytes_malloced, 0);
}
}
void test_basic_hashtable2_1bucket()
{
for (unsigned n = 0; n <= NUM_SORTED_KEYS; ++n) {
CU_ASSERT_EQUAL(bytes_malloced, 0);
test_basic(hashtable2_dict_new(dict_str_cmp, dict_str_hash, 1), unsorted_keys, n, false);
CU_ASSERT_EQUAL(bytes_malloced, 0);
test_basic(hashtable2_dict_new(dict_str_cmp, dict_str_hash, 1), sorted_keys, n, true);
CU_ASSERT_EQUAL(bytes_malloced, 0);
}
}
void test_basic_hashtable_nbuckets()
{
for (unsigned n = 0; n <= NUM_SORTED_KEYS; ++n) {
CU_ASSERT_EQUAL(bytes_malloced, 0);
test_basic(hashtable_dict_new(dict_str_cmp, dict_str_hash, 7), unsorted_keys, n, false);
CU_ASSERT_EQUAL(bytes_malloced, 0);
test_basic(hashtable_dict_new(dict_str_cmp, dict_str_hash, 7), sorted_keys, n, true);
CU_ASSERT_EQUAL(bytes_malloced, 0);
}
}
void test_basic_hashtable2_nbuckets()
{
for (unsigned n = 0; n <= NUM_SORTED_KEYS; ++n) {
CU_ASSERT_EQUAL(bytes_malloced, 0);
test_basic(hashtable2_dict_new(dict_str_cmp, dict_str_hash, 7), unsorted_keys, n, false);
CU_ASSERT_EQUAL(bytes_malloced, 0);
test_basic(hashtable2_dict_new(dict_str_cmp, dict_str_hash, 7), sorted_keys, n, true);
CU_ASSERT_EQUAL(bytes_malloced, 0);
}
}
void test_basic_height_balanced_tree()
{
for (unsigned n = 0; n <= NUM_SORTED_KEYS; ++n) {
CU_ASSERT_EQUAL(bytes_malloced, 0);
test_basic(hb_dict_new(dict_str_cmp), unsorted_keys, n, false);
CU_ASSERT_EQUAL(bytes_malloced, 0);
test_basic(hb_dict_new(dict_str_cmp), sorted_keys, n, true);
CU_ASSERT_EQUAL(bytes_malloced, 0);
}
}
void test_basic_path_reduction_tree()
{
for (unsigned n = 0; n <= NUM_SORTED_KEYS; ++n) {
CU_ASSERT_EQUAL(bytes_malloced, 0);
test_basic(pr_dict_new(dict_str_cmp), unsorted_keys, n, false);
CU_ASSERT_EQUAL(bytes_malloced, 0);
test_basic(pr_dict_new(dict_str_cmp), sorted_keys, n, true);
CU_ASSERT_EQUAL(bytes_malloced, 0);
}
}
void test_basic_red_black_tree()
{
for (unsigned n = 0; n <= NUM_SORTED_KEYS; ++n) {
CU_ASSERT_EQUAL(bytes_malloced, 0);
test_basic(rb_dict_new(dict_str_cmp), unsorted_keys, n, false);
CU_ASSERT_EQUAL(bytes_malloced, 0);
test_basic(rb_dict_new(dict_str_cmp), sorted_keys, n, true);
CU_ASSERT_EQUAL(bytes_malloced, 0);
}
}
void test_basic_skiplist()
{
for (unsigned n = 0; n <= NUM_SORTED_KEYS; ++n) {
CU_ASSERT_EQUAL(bytes_malloced, 0);
test_basic(skiplist_dict_new(dict_str_cmp, 13), unsorted_keys, n, false);
CU_ASSERT_EQUAL(bytes_malloced, 0);
test_basic(skiplist_dict_new(dict_str_cmp, 13), sorted_keys, n, true);
CU_ASSERT_EQUAL(bytes_malloced, 0);
}
}
void test_basic_splay_tree()
{
for (unsigned n = 0; n <= NUM_SORTED_KEYS; ++n) {
CU_ASSERT_EQUAL(bytes_malloced, 0);
test_basic(sp_dict_new(dict_str_cmp), unsorted_keys, n, false);
CU_ASSERT_EQUAL(bytes_malloced, 0);
test_basic(sp_dict_new(dict_str_cmp), sorted_keys, n, true);
CU_ASSERT_EQUAL(bytes_malloced, 0);
}
}
void test_basic_treap()
{
for (unsigned n = 0; n <= NUM_SORTED_KEYS; ++n) {
CU_ASSERT_EQUAL(bytes_malloced, 0);
test_basic(tr_dict_new(dict_str_cmp, NULL), unsorted_keys, n, false);
CU_ASSERT_EQUAL(bytes_malloced, 0);
test_basic(tr_dict_new(dict_str_cmp, NULL), sorted_keys, n, true);
CU_ASSERT_EQUAL(bytes_malloced, 0);
}
}
void test_basic_weight_balanced_tree()
{
for (unsigned n = 0; n <= NUM_SORTED_KEYS; ++n) {
CU_ASSERT_EQUAL(bytes_malloced, 0);
test_basic(wb_dict_new(dict_str_cmp), unsorted_keys, n, false);
CU_ASSERT_EQUAL(bytes_malloced, 0);
test_basic(wb_dict_new(dict_str_cmp), sorted_keys, n, true);
CU_ASSERT_EQUAL(bytes_malloced, 0);
}
}
void test_primes_geq()
{
CU_ASSERT_TRUE(is_prime(2));
CU_ASSERT_TRUE(is_prime(3));
CU_ASSERT_FALSE(is_prime(4));
CU_ASSERT_TRUE(is_prime(5));
CU_ASSERT_FALSE(is_prime(6));
CU_ASSERT_TRUE(is_prime(7));
unsigned value = 0;
do {
const unsigned prime_geq_value = dict_prime_geq(value+1);
CU_ASSERT_TRUE(prime_geq_value >= value+1);
CU_ASSERT_TRUE(is_prime(prime_geq_value));
CU_ASSERT_TRUE(dict_prime_geq(prime_geq_value) == prime_geq_value);
value = prime_geq_value;
} while (value != 4294967291U);
}
void test_version_string()
{
char version_string[32];
snprintf(version_string, sizeof(version_string), "%d.%d.%d",
DICT_VERSION_MAJOR, DICT_VERSION_MINOR, DICT_VERSION_PATCH);
CU_ASSERT_STRING_EQUAL(kDictVersionString, version_string);
}