379 lines
11 KiB
C++
379 lines
11 KiB
C++
/*
|
|
* test-core-hashtable.cpp - test hashtable functions
|
|
*
|
|
* Copyright (C) 2014-2019 Sébastien Helleu <flashcode@flashtux.org>
|
|
*
|
|
* This file is part of WeeChat, the extensible chat client.
|
|
*
|
|
* WeeChat is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* WeeChat is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with WeeChat. If not, see <https://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include "CppUTest/TestHarness.h"
|
|
|
|
extern "C"
|
|
{
|
|
#include <string.h>
|
|
#include "src/core/wee-hashtable.h"
|
|
#include "src/plugins/plugin.h"
|
|
}
|
|
|
|
#define HASHTABLE_TEST_KEY "test"
|
|
#define HASHTABLE_TEST_KEY_HASH 5849825121ULL
|
|
#define HASHTABLE_TEST_VALUE "this is a value"
|
|
|
|
TEST_GROUP(CoreHashtable)
|
|
{
|
|
};
|
|
|
|
/*
|
|
* Tests functions:
|
|
* hashtable_hash_key_djb2
|
|
*/
|
|
|
|
TEST(CoreHashtable, HashDbj2)
|
|
{
|
|
unsigned long long hash;
|
|
|
|
hash = hashtable_hash_key_djb2 (HASHTABLE_TEST_KEY);
|
|
CHECK(hash == HASHTABLE_TEST_KEY_HASH);
|
|
}
|
|
|
|
/*
|
|
* Test callback hashing a key.
|
|
*
|
|
* It returns the djb2 hash + 1.
|
|
*/
|
|
|
|
unsigned long long
|
|
test_hashtable_hash_key_cb (struct t_hashtable *hashtable, const void *key)
|
|
{
|
|
/* make C++ compiler happy */
|
|
(void) hashtable;
|
|
|
|
return hashtable_hash_key_djb2 ((const char *)key) + 1;
|
|
}
|
|
|
|
/*
|
|
* Test callback comparing two keys.
|
|
*
|
|
* It just makes a string comparison (strcmp) between both keys.
|
|
*/
|
|
|
|
int
|
|
test_hashtable_keycmp_cb (struct t_hashtable *hashtable,
|
|
const void *key1, const void *key2)
|
|
{
|
|
/* make C++ compiler happy */
|
|
(void) hashtable;
|
|
|
|
return strcmp ((const char *)key1, (const char *)key2);
|
|
}
|
|
|
|
/*
|
|
* Tests functions:
|
|
* hashtable_new
|
|
*/
|
|
|
|
TEST(CoreHashtable, New)
|
|
{
|
|
struct t_hashtable *hashtable;
|
|
|
|
hashtable = hashtable_new (-1, NULL, NULL, NULL, NULL);
|
|
POINTERS_EQUAL(NULL, hashtable);
|
|
|
|
/* test invalid size */
|
|
POINTERS_EQUAL(NULL,
|
|
hashtable_new (-1,
|
|
WEECHAT_HASHTABLE_STRING,
|
|
WEECHAT_HASHTABLE_STRING,
|
|
NULL, NULL));
|
|
|
|
/* test invalid type for keys/values */
|
|
POINTERS_EQUAL(NULL,
|
|
hashtable_new (32,
|
|
"xxxxx", /* invalid */
|
|
"yyyyy", /* invalid */
|
|
NULL, NULL));
|
|
|
|
/* valid hashtable */
|
|
hashtable = hashtable_new (32,
|
|
WEECHAT_HASHTABLE_STRING,
|
|
WEECHAT_HASHTABLE_INTEGER,
|
|
&test_hashtable_hash_key_cb,
|
|
&test_hashtable_keycmp_cb);
|
|
CHECK(hashtable);
|
|
LONGS_EQUAL(32, hashtable->size);
|
|
CHECK(hashtable->htable);
|
|
LONGS_EQUAL(0, hashtable->items_count);
|
|
LONGS_EQUAL(HASHTABLE_STRING, hashtable->type_keys);
|
|
LONGS_EQUAL(HASHTABLE_INTEGER, hashtable->type_values);
|
|
POINTERS_EQUAL(&test_hashtable_hash_key_cb, hashtable->callback_hash_key);
|
|
POINTERS_EQUAL(&test_hashtable_keycmp_cb, hashtable->callback_keycmp);
|
|
POINTERS_EQUAL(NULL, hashtable->callback_free_key);
|
|
POINTERS_EQUAL(NULL, hashtable->callback_free_value);
|
|
hashtable_free (hashtable);
|
|
}
|
|
|
|
/*
|
|
* Tests functions:
|
|
* hashtable_set_with_size
|
|
* hashtable_set
|
|
* hashtable_get_item
|
|
* hashtable_get
|
|
* hashtable_has_key
|
|
* hashtable_dup
|
|
* hashtable_remove
|
|
* hashtable_remove_all
|
|
* hashtable_free
|
|
*/
|
|
|
|
TEST(CoreHashtable, SetGetRemove)
|
|
{
|
|
struct t_hashtable *hashtable, *hashtable2;
|
|
struct t_hashtable_item *item, *ptr_item, *ptr_item2;
|
|
const char *str_key = HASHTABLE_TEST_KEY;
|
|
const char *str_value = HASHTABLE_TEST_VALUE;
|
|
const char *ptr_value;
|
|
unsigned long long hash;
|
|
int i;
|
|
|
|
hashtable = hashtable_new (32,
|
|
WEECHAT_HASHTABLE_STRING,
|
|
WEECHAT_HASHTABLE_STRING,
|
|
&test_hashtable_hash_key_cb,
|
|
&test_hashtable_keycmp_cb);
|
|
LONGS_EQUAL(32, hashtable->size);
|
|
LONGS_EQUAL(0, hashtable->items_count);
|
|
|
|
/* invalid set of items */
|
|
POINTERS_EQUAL(NULL, hashtable_set_with_size (NULL, NULL, -1, NULL, -1));
|
|
POINTERS_EQUAL(NULL, hashtable_set_with_size (NULL, NULL, -1, NULL, -1));
|
|
|
|
/* add an item in hashtable with NULL value */
|
|
item = hashtable_set (hashtable, str_key, NULL);
|
|
CHECK(item);
|
|
LONGS_EQUAL(1, hashtable->items_count);
|
|
STRCMP_EQUAL(str_key, (const char *)item->key);
|
|
LONGS_EQUAL(strlen (str_key) + 1, item->key_size);
|
|
POINTERS_EQUAL(NULL, item->value);
|
|
LONGS_EQUAL(0, item->value_size);
|
|
POINTERS_EQUAL(NULL, item->prev_item);
|
|
POINTERS_EQUAL(NULL, item->next_item);
|
|
|
|
/* set a string value for the same key */
|
|
item = hashtable_set (hashtable, str_key, str_value);
|
|
CHECK(item);
|
|
LONGS_EQUAL(1, hashtable->items_count);
|
|
STRCMP_EQUAL(str_key, (const char *)item->key);
|
|
LONGS_EQUAL(strlen (str_key) + 1, item->key_size);
|
|
STRCMP_EQUAL(str_value, (const char *)item->value);
|
|
LONGS_EQUAL(strlen (str_value) + 1, item->value_size);
|
|
POINTERS_EQUAL(NULL, item->prev_item);
|
|
POINTERS_EQUAL(NULL, item->next_item);
|
|
|
|
/* get item */
|
|
item = hashtable_get_item (hashtable, str_key, &hash);
|
|
CHECK(item);
|
|
STRCMP_EQUAL(str_key, (const char *)item->key);
|
|
STRCMP_EQUAL(str_value, (const char *)item->value);
|
|
LONGS_EQUAL(2, hash);
|
|
|
|
/* get value */
|
|
ptr_value = (const char *)hashtable_get (hashtable, str_key);
|
|
CHECK(ptr_value);
|
|
STRCMP_EQUAL(ptr_value, str_value);
|
|
|
|
/* check if key is in hashtable */
|
|
LONGS_EQUAL(0, hashtable_has_key (hashtable, NULL));
|
|
LONGS_EQUAL(0, hashtable_has_key (hashtable, ""));
|
|
LONGS_EQUAL(0, hashtable_has_key (hashtable, "xxx"));
|
|
LONGS_EQUAL(1, hashtable_has_key (hashtable, str_key));
|
|
|
|
/* delete an item */
|
|
hashtable_remove (hashtable, str_key);
|
|
LONGS_EQUAL(0, hashtable->items_count);
|
|
|
|
/* add an item with size in hashtable */
|
|
item = hashtable_set_with_size (hashtable,
|
|
str_key, strlen (str_key) + 1,
|
|
str_value, strlen (str_value) + 1);
|
|
CHECK(item);
|
|
LONGS_EQUAL(1, hashtable->items_count);
|
|
STRCMP_EQUAL(str_key, (const char *)item->key);
|
|
LONGS_EQUAL(strlen (str_key) + 1, item->key_size);
|
|
STRCMP_EQUAL(str_value, (const char *)item->value);
|
|
LONGS_EQUAL(strlen (str_value) + 1, item->value_size);
|
|
|
|
/* add another item */
|
|
hashtable_set (hashtable, "xxx", "zzz");
|
|
LONGS_EQUAL(2, hashtable->items_count);
|
|
|
|
/*
|
|
* test duplication of hashtable and check that duplicated content is
|
|
* exactly the same as initial hashtable
|
|
*/
|
|
hashtable2 = hashtable_dup (hashtable);
|
|
CHECK(hashtable2);
|
|
LONGS_EQUAL(hashtable->size, hashtable2->size);
|
|
LONGS_EQUAL(hashtable->items_count, hashtable2->items_count);
|
|
for (i = 0; i < hashtable->size; i++)
|
|
{
|
|
if (hashtable->htable[i])
|
|
{
|
|
ptr_item = hashtable->htable[i];
|
|
ptr_item2 = hashtable2->htable[i];
|
|
while (ptr_item && ptr_item2)
|
|
{
|
|
LONGS_EQUAL(ptr_item->key_size, ptr_item2->key_size);
|
|
LONGS_EQUAL(ptr_item->value_size, ptr_item2->value_size);
|
|
if (ptr_item->key)
|
|
{
|
|
STRCMP_EQUAL((const char *)ptr_item->key,
|
|
(const char *)ptr_item2->key);
|
|
}
|
|
else
|
|
{
|
|
POINTERS_EQUAL(ptr_item->key, ptr_item2->key);
|
|
}
|
|
if (ptr_item->value)
|
|
{
|
|
STRCMP_EQUAL((const char *)ptr_item->value,
|
|
(const char *)ptr_item2->value);
|
|
}
|
|
else
|
|
{
|
|
POINTERS_EQUAL(ptr_item->value, ptr_item2->value);
|
|
}
|
|
ptr_item = ptr_item->next_item;
|
|
ptr_item2 = ptr_item2->next_item;
|
|
CHECK((ptr_item && ptr_item2) || (!ptr_item && !ptr_item2));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
POINTERS_EQUAL(hashtable->htable[i], hashtable2->htable[i]);
|
|
}
|
|
}
|
|
|
|
/* remove all items */
|
|
hashtable_remove_all (hashtable);
|
|
LONGS_EQUAL(0, hashtable->items_count);
|
|
|
|
/* free hashtables */
|
|
hashtable_free (hashtable);
|
|
hashtable_free (hashtable2);
|
|
|
|
/*
|
|
* create a hashtable with size 8, and add 6 items,
|
|
* to check if many items with same hashed key work fine,
|
|
* the expected htable inside hashtable is:
|
|
* +-----+
|
|
* | 0 |
|
|
* +-----+
|
|
* | 1 |
|
|
* +-----+
|
|
* | 2 | --> "extensible"
|
|
* +-----+
|
|
* | 3 | --> "fast" --> "light"
|
|
* +-----+
|
|
* | 4 |
|
|
* +-----+
|
|
* | 5 | --> "chat"
|
|
* +-----+
|
|
* | 6 | --> "client"
|
|
* +-----+
|
|
* | 7 | --> "weechat"
|
|
* +-----+
|
|
*/
|
|
hashtable = hashtable_new (8,
|
|
WEECHAT_HASHTABLE_STRING,
|
|
WEECHAT_HASHTABLE_STRING,
|
|
NULL,
|
|
NULL);
|
|
LONGS_EQUAL(8, hashtable->size);
|
|
LONGS_EQUAL(0, hashtable->items_count);
|
|
|
|
item = hashtable_set (hashtable, "weechat", NULL);
|
|
CHECK(item);
|
|
POINTERS_EQUAL(item, hashtable->htable[7]);
|
|
|
|
item = hashtable_set (hashtable, "fast", NULL);
|
|
CHECK(item);
|
|
POINTERS_EQUAL(item, hashtable->htable[3]);
|
|
|
|
item = hashtable_set (hashtable, "light", NULL);
|
|
CHECK(item);
|
|
POINTERS_EQUAL(item, hashtable->htable[3]->next_item);
|
|
|
|
item = hashtable_set (hashtable, "extensible", NULL);
|
|
CHECK(item);
|
|
POINTERS_EQUAL(item, hashtable->htable[2]);
|
|
|
|
item = hashtable_set (hashtable, "chat", NULL);
|
|
CHECK(item);
|
|
POINTERS_EQUAL(item, hashtable->htable[5]);
|
|
|
|
item = hashtable_set (hashtable, "client", NULL);
|
|
CHECK(item);
|
|
POINTERS_EQUAL(item, hashtable->htable[6]);
|
|
|
|
/* free hashtable */
|
|
hashtable_free (hashtable);
|
|
}
|
|
|
|
/*
|
|
* Tests functions:
|
|
* hashtable_map
|
|
* hashtable_map_string
|
|
*/
|
|
|
|
TEST(CoreHashtable, Map)
|
|
{
|
|
/* TODO: write tests */
|
|
}
|
|
|
|
/*
|
|
* Tests functions:
|
|
* hashtable_get_list_keys
|
|
* hashtable_get_integer
|
|
* hashtable_get_string
|
|
* hashtable_set_pointer
|
|
*/
|
|
|
|
TEST(CoreHashtable, Properties)
|
|
{
|
|
/* TODO: write tests */
|
|
}
|
|
|
|
/*
|
|
* Tests functions:
|
|
* hashtable_add_to_infolist
|
|
* hashtable_add_from_infolist
|
|
*/
|
|
|
|
TEST(CoreHashtable, Infolist)
|
|
{
|
|
/* TODO: write tests */
|
|
}
|
|
|
|
/*
|
|
* Tests functions:
|
|
* hashtable_print_log
|
|
*/
|
|
|
|
TEST(CoreHashtable, PrintLog)
|
|
{
|
|
/* TODO: write tests */
|
|
}
|