+/*
+ * TSM - Hashtable Tests
+ *
+ * Copyright (c) 2012-2013 David Herrmann <dh.herrmann@gmail.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+
+#include "test_common.h"
+
+static struct shl_htable ht = SHL_HTABLE_INIT_STR(ht);
+static struct shl_htable uht = SHL_HTABLE_INIT_ULONG(uht);
+
+struct node {
+ char huge_padding[16384];
+ uint8_t v;
+ char paaaaaadding[16384];
+ char *key;
+ unsigned long ul;
+ char more_padding[32768];
+ size_t hash;
+};
+
+#define to_node(_key) shl_htable_offsetof((_key), struct node, key)
+#define ul_to_node(_key) shl_htable_offsetof((_key), struct node, ul)
+
+static struct node o[] = {
+ { .v = 0, .key = "o0", .ul = 0 },
+ { .v = 1, .key = "o1", .ul = 1 },
+ { .v = 2, .key = "o2", .ul = 2 },
+ { .v = 3, .key = "o3", .ul = 3 },
+ { .v = 4, .key = "o4", .ul = 4 },
+ { .v = 5, .key = "o5", .ul = 5 },
+ { .v = 6, .key = "o6", .ul = 6 },
+ { .v = 7, .key = "o7", .ul = 7 },
+};
+
+static void test_htable_str_cb(char **k, void *ctx)
+{
+ int *num = ctx;
+
+ ck_assert(to_node(k)->v == to_node(k)->ul);
+ ++*num;
+}
+
+START_TEST(test_htable_str)
+{
+ int r, i, num;
+ char **k;
+ bool b;
+
+ /* insert once, remove once, try removing again */
+
+ ck_assert(!o[0].hash);
+ r = shl_htable_insert_str(&ht, &o[0].key, &o[0].hash);
+ ck_assert(!r);
+ ck_assert(o[0].hash == shl_htable_rehash_str(&o[0].key, NULL));
+
+ b = shl_htable_remove_str(&ht, o[0].key, &o[0].hash, &k);
+ ck_assert(b);
+ ck_assert(k != NULL);
+ ck_assert(to_node(k)->v == 0);
+
+ k = NULL;
+ b = shl_htable_remove_str(&ht, o[0].key, &o[0].hash, &k);
+ ck_assert(!b);
+ ck_assert(k == NULL);
+
+ /* insert twice, remove twice, try removing again */
+
+ r = shl_htable_insert_str(&ht, &o[0].key, &o[0].hash);
+ ck_assert(!r);
+ ck_assert(o[0].hash == shl_htable_rehash_str(&o[0].key, NULL));
+
+ r = shl_htable_insert_str(&ht, &o[0].key, &o[0].hash);
+ ck_assert(!r);
+ ck_assert(o[0].hash == shl_htable_rehash_str(&o[0].key, NULL));
+
+ b = shl_htable_remove_str(&ht, o[0].key, &o[0].hash, &k);
+ ck_assert(b);
+ ck_assert(k != NULL);
+ ck_assert(to_node(k)->v == 0);
+
+ b = shl_htable_remove_str(&ht, o[0].key, &o[0].hash, &k);
+ ck_assert(b);
+ ck_assert(k != NULL);
+ ck_assert(to_node(k)->v == 0);
+
+ k = NULL;
+ b = shl_htable_remove_str(&ht, o[0].key, &o[0].hash, &k);
+ ck_assert(!b);
+ ck_assert(k == NULL);
+
+ /* same as before but without hash-cache */
+
+ r = shl_htable_insert_str(&ht, &o[0].key, NULL);
+ ck_assert(!r);
+
+ r = shl_htable_insert_str(&ht, &o[0].key, NULL);
+ ck_assert(!r);
+
+ b = shl_htable_remove_str(&ht, o[0].key, NULL, &k);
+ ck_assert(b);
+ ck_assert(k != NULL);
+ ck_assert(to_node(k)->v == 0);
+
+ b = shl_htable_remove_str(&ht, o[0].key, NULL, &k);
+ ck_assert(b);
+ ck_assert(k != NULL);
+ ck_assert(to_node(k)->v == 0);
+
+ k = NULL;
+ b = shl_htable_remove_str(&ht, o[0].key, NULL, &k);
+ ck_assert(!b);
+ ck_assert(k == NULL);
+
+ /* insert all elements and verify empty hash-caches */
+
+ o[0].hash = 0;
+ for (i = 0; i < 8; ++i) {
+ ck_assert(!o[i].hash);
+ r = shl_htable_insert_str(&ht, &o[i].key, &o[i].hash);
+ ck_assert(!r);
+ ck_assert(o[i].hash == shl_htable_rehash_str(&o[i].key, NULL));
+ }
+
+ /* verify */
+
+ for (i = 0; i < 8; ++i) {
+ k = NULL;
+ b = shl_htable_lookup_str(&ht, o[i].key, NULL, &k);
+ ck_assert(b);
+ ck_assert(k != NULL);
+ ck_assert(to_node(k)->v == i);
+ }
+
+ /* remove all elements again */
+
+ for (i = 0; i < 8; ++i) {
+ b = shl_htable_remove_str(&ht, o[i].key, NULL, &k);
+ ck_assert(b);
+ ck_assert(k != NULL);
+ ck_assert(to_node(k)->v == i);
+ }
+
+ /* verify they're gone */
+
+ for (i = 0; i < 8; ++i) {
+ k = NULL;
+ b = shl_htable_remove_str(&ht, o[i].key, NULL, &k);
+ ck_assert(!b);
+ ck_assert(k == NULL);
+ }
+
+ for (i = 0; i < 8; ++i) {
+ k = NULL;
+ b = shl_htable_lookup_str(&ht, o[i].key, NULL, &k);
+ ck_assert(!b);
+ ck_assert(k == NULL);
+ }
+
+ num = 0;
+ shl_htable_visit_str(&ht, test_htable_str_cb, &num);
+ ck_assert(num == 0);
+
+ num = 0;
+ shl_htable_clear_str(&ht, test_htable_str_cb, &num);
+ ck_assert(num == 0);
+
+ /* test shl_htable_clear_str() */
+
+ for (i = 0; i < 8; ++i) {
+ r = shl_htable_insert_str(&ht, &o[i].key, &o[i].hash);
+ ck_assert(!r);
+ }
+
+ num = 0;
+ shl_htable_visit_str(&ht, test_htable_str_cb, &num);
+ ck_assert(num == 8);
+
+ num = 0;
+ shl_htable_clear_str(&ht, test_htable_str_cb, &num);
+ ck_assert(num == 8);
+}
+END_TEST
+
+static void test_htable_ulong_cb(unsigned long *k, void *ctx)
+{
+ int *num = ctx;
+
+ ck_assert(ul_to_node(k)->v == ul_to_node(k)->ul);
+ ++*num;
+}
+
+START_TEST(test_htable_ulong)
+{
+ int r, i, num;
+ unsigned long *k;
+ bool b;
+
+ /* insert once, remove once, try removing again */
+
+ r = shl_htable_insert_ulong(&uht, &o[0].ul);
+ ck_assert(!r);
+ ck_assert(o[0].ul == shl_htable_rehash_ulong(&o[0].ul, NULL));
+
+ b = shl_htable_remove_ulong(&uht, o[0].ul, &k);
+ ck_assert(b);
+ ck_assert(k != NULL);
+ ck_assert(ul_to_node(k)->v == 0);
+
+ k = NULL;
+ b = shl_htable_remove_ulong(&uht, o[0].ul, &k);
+ ck_assert(!b);
+ ck_assert(k == NULL);
+
+ /* insert all */
+
+ for (i = 0; i < 8; ++i) {
+ r = shl_htable_insert_ulong(&uht, &o[i].ul);
+ ck_assert(!r);
+ }
+
+ /* verify */
+
+ for (i = 0; i < 8; ++i) {
+ k = NULL;
+ b = shl_htable_lookup_ulong(&uht, o[i].ul, &k);
+ ck_assert(b);
+ ck_assert(k != NULL);
+ }
+
+ /* remove all elements again */
+
+ for (i = 0; i < 8; ++i) {
+ b = shl_htable_remove_ulong(&uht, o[i].ul, &k);
+ ck_assert(b);
+ ck_assert(k != NULL);
+ ck_assert(ul_to_node(k)->v == i);
+ }
+
+ /* verify they're gone */
+
+ for (i = 0; i < 8; ++i) {
+ k = NULL;
+ b = shl_htable_remove_ulong(&uht, o[i].ul, &k);
+ ck_assert(!b);
+ ck_assert(k == NULL);
+ }
+
+ for (i = 0; i < 8; ++i) {
+ k = NULL;
+ b = shl_htable_lookup_ulong(&uht, o[i].ul, &k);
+ ck_assert(!b);
+ ck_assert(k == NULL);
+ }
+
+ num = 0;
+ shl_htable_visit_ulong(&uht, test_htable_ulong_cb, &num);
+ ck_assert(num == 0);
+
+ num = 0;
+ shl_htable_clear_ulong(&uht, test_htable_ulong_cb, &num);
+ ck_assert(num == 0);
+
+ /* test shl_htable_clear_ulong() */
+
+ for (i = 0; i < 8; ++i) {
+ r = shl_htable_insert_ulong(&uht, &o[i].ul);
+ ck_assert(!r);
+ }
+
+ num = 0;
+ shl_htable_visit_ulong(&uht, test_htable_ulong_cb, &num);
+ ck_assert(num == 8);
+
+ num = 0;
+ shl_htable_clear_ulong(&uht, test_htable_ulong_cb, &num);
+ ck_assert(num == 8);
+}
+END_TEST
+
+TEST_DEFINE_CASE(misc)
+ TEST(test_htable_str)
+ TEST(test_htable_ulong)
+TEST_END_CASE
+
+TEST_DEFINE(
+ TEST_SUITE(hashtable,
+ TEST_CASE(misc),
+ TEST_END
+ )
+)