/** * @file test_hashtable.c * @author rick * @date 27.07.22 * @brief Test for the HashTable implementation */ #include "waitui/hashtable_generic.h" #include "waitui/hashtable_generic_impl.h" #include "../../bdd-for-c-ext.h" typedef struct value { int count; int i; } value; static value *value_new(int i) { value *this = calloc(1, sizeof(*this)); if (!this) { return NULL; } this->i = i; return this; } static void value_destroy(value **this) { if (!this || !(*this)) { return; } free(*this); *this = NULL; } static int value_check_counter(value *this, int *count) { if (!this) { return 0; } return this->count == *count; } CREATE_HASHTABLE_TYPE(INTERFACE, value) CREATE_HASHTABLE_TYPE(IMPLEMENTATION, value) spec("hashtable") { context("use as a normal hashtable with no forced collisions") { static value_hashtable *hashtable = NULL; before_each() { hashtable = value_hashtable_new(42); check(hashtable != NULL, "hashtable should not be NULL"); } after_each() { value_hashtable_destroy(&hashtable); check(hashtable == NULL, "hashtable should be NULL"); } describe("value_hashtable_insert()") { for_it( "should add values to the end of the list and it should be there", params_format(2, "start: %d", "elements: %d"), format_args(test_param.start, test_param.count), { int start; int count; }, test_params( {0, 0}, {0, 1}, {1, 1}, {4, 20}, ) ) { for (int i = test_param.start; i < test_param.start + test_param.count; ++i) { str key = STR_NULL_INIT; value *value = NULL; STR_SNPRINTF(&key, "key-%d", i); check(key.s != NULL, "key.s should be not NULL"); check(value_hashtable_has(hashtable, key) == 0, "hashtable should not have the key already"); check(value_hashtable_insert(hashtable, key, value_new(i)) == 1); check(value_hashtable_has(hashtable, key) == 1, "hashtable should have the key"); value = value_hashtable_lookup(hashtable, key); check(value != NULL, "value should not be NULL"); check(value->i == i, "value should be %d but is %d", i, value->i); STR_FREE(&key); } for (int i = test_param.start + test_param.count - 1; i >= test_param.start; --i) { str key = STR_NULL_INIT; value *value = NULL; STR_SNPRINTF(&key, "key-%d", i); check(key.s != NULL, "key.s should be not NULL"); value = value_hashtable_lookup(hashtable, key); check(value != NULL, "value should not be NULL"); check(value->i == i, "value should be %d but is %d", i, value->i); STR_FREE(&key); } } for_it_end(); it("should work with the empty str") { str key = STR_STATIC_INIT(""); check(value_hashtable_has(hashtable, key) == 0, "hashtable should not have the key already"); check(value_hashtable_insert(hashtable, key, value_new(1337)) == 1); check(value_hashtable_has(hashtable, key) == 1, "hashtable should have the key"); } it("should not work with the str having NULL as string") { str key = STR_NULL_INIT; check(value_hashtable_insert(hashtable, key, value_new(1337)) == 0); } it("should return 0 with NULL as this param") { str key = STR_STATIC_INIT("leet"); check(value_hashtable_insert(NULL, key, value_new(1)) == 0, "return should be 0"); } it("should not allow double entry") { str key = STR_STATIC_INIT("42"); check(value_hashtable_has(hashtable, key) == 0, "hashtable should not have the key already"); check(value_hashtable_insert(hashtable, key, value_new(1337)) == 1); check(value_hashtable_has(hashtable, key) == 1, "hashtable should have the key"); check(value_hashtable_insert(hashtable, key, value_new(1337)) == 0); } } describe("value_hashtable_insertCheck()") { it("should allow a double insert when check test the value and returns true") { int counter; str key = STR_STATIC_INIT("foo"); value *value1 = value_new(1337); value1->count = 0; value *value2 = value_new(7331); value2->count = 1; value *resultValue = NULL; counter = 0; check(value_hashtable_insertCheck(hashtable, key, value1, (value_hashtable_value_check_fn) value_check_counter, &counter) == 1); check(value_hashtable_hasCheck(hashtable, key, (value_hashtable_value_check_fn) value_check_counter, &counter) == 1); check(value_hashtable_insertCheck(hashtable, key, value1, (value_hashtable_value_check_fn) value_check_counter, &counter) == 0); counter = 1; check(value_hashtable_insertCheck(hashtable, key, value2, (value_hashtable_value_check_fn) value_check_counter, &counter) == 1); check(value_hashtable_hasCheck(hashtable, key, (value_hashtable_value_check_fn) value_check_counter, &counter) == 1); check(value_hashtable_insertCheck(hashtable, key, value2, (value_hashtable_value_check_fn) value_check_counter, &counter) == 0); counter = 0; resultValue = value_hashtable_lookupCheck(hashtable, key, (value_hashtable_value_check_fn) value_check_counter, &counter); check(resultValue != NULL, "resultValue should not be NULL"); check(resultValue->i == 1337, "resultValue->i should be %d", 1337); check(resultValue->count == 0, "resultValue->count should be %d", 0); counter = 1; resultValue = value_hashtable_lookupCheck(hashtable, key, (value_hashtable_value_check_fn) value_check_counter, &counter); check(resultValue != NULL, "resultValue should not be NULL"); check(resultValue->i == 7331, "resultValue->i should be %d", 7331); check(resultValue->count == 1, "resultValue->count should be %d", 1); check(value_hashtable_markStolenCheck(hashtable, key, (value_hashtable_value_check_fn) value_check_counter, &counter) == 1); check(value_hashtable_isStolenCheck(hashtable, key, (value_hashtable_value_check_fn) value_check_counter, &counter) == 1); value_destroy(&resultValue); check(resultValue == NULL, "resultValue should be NULL"); } } describe("value_hashtable_destroy()") { it("should work with NULL as this param") { value_hashtable_destroy(NULL); } it("should work with a pointer to NULL as this param") { static value_hashtable *empty = NULL; value_hashtable_destroy(&empty); check(empty == NULL, "empty should be NULL"); } } describe("value_hashtable_lookup()") { it("should work with the empty str") { str key = STR_STATIC_INIT(""); value *value = value_hashtable_lookup(hashtable, key); check(value == NULL, "value should be NULL"); } it("should not work with the str having NULL as string") { str key = STR_NULL_INIT; value *value = value_hashtable_lookup(hashtable, key); check(value == NULL, "value should be NULL"); } it("should return NULL with NULL as this param") { str key = STR_STATIC_INIT("leet"); value *value = value_hashtable_lookup(NULL, key); check(value == NULL, "value should be NULL"); } } describe("value_hashtable_markStolen()") { it("should mark the value for the given key as stolen") { str key = STR_STATIC_INIT("leet"); check(value_hashtable_has(hashtable, key) == 0,"hashtable should not have the key already"); check(value_hashtable_insert(hashtable, key, value_new(1337)) == 1); check(value_hashtable_has(hashtable, key) == 1, "hashtable should have the key"); check(value_hashtable_markStolen(hashtable, key) == 1, "hashtable should mark the value for the key as stolen"); check(value_hashtable_isStolen(hashtable, key) == 1, "hashtable should have the value for the key marked as stolen"); } it("should return 0 the given key that is not existing") { str keyExists = STR_STATIC_INIT("other"); check(value_hashtable_insert(hashtable, keyExists, value_new(1337)) == 1); str key = STR_STATIC_INIT("leet"); check(value_hashtable_has(hashtable, key) == 0,"hashtable should not have the key already"); check(value_hashtable_markStolen(hashtable, key) == 0, "hashtable should mark the value for the key as stolen"); } it("should work with the empty str") { str key = STR_STATIC_INIT(""); check(value_hashtable_insert(hashtable, key, value_new(1337)) == 1); check(value_hashtable_markStolen(hashtable, key) == 1, "return should be 1"); } it("should not work with the str having NULL as string") { str key = STR_NULL_INIT; check(value_hashtable_markStolen(hashtable, key) == 0, "return should be 0"); } it("should return 0 with NULL as this param") { str key = STR_STATIC_INIT("leet"); check(value_hashtable_markStolen(NULL, key) == 0, "return should be 0"); } } describe("value_hashtable_has()") { it("should work with the empty str") { str key = STR_STATIC_INIT(""); check(value_hashtable_insert(hashtable, key, value_new(1337)) == 1); check(value_hashtable_has(hashtable, key) == 1, "return should be 1"); } it("should not work with the str having NULL as string") { str key = STR_NULL_INIT; check(value_hashtable_has(hashtable, key) == 0, "return should be 0"); } it("should return NULL with NULL as this param") { str key = STR_STATIC_INIT("leet"); check(value_hashtable_has(NULL, key) == 0, "return should be 0"); } } describe("value_hashtable_isStolen()") { it("should work with the empty str") { str key = STR_STATIC_INIT(""); check(value_hashtable_insert(hashtable, key, value_new(1337)) == 1); check(value_hashtable_isStolen(hashtable, key) == 0, "return should be 0"); } it("should not work with the str having NULL as string") { str key = STR_NULL_INIT; check(value_hashtable_isStolen(hashtable, key) == 0, "return should be 0"); } it("should return NULL with NULL as this param") { str key = STR_STATIC_INIT("leet"); check(value_hashtable_isStolen(NULL, key) == 0, "return should be 0"); } it("should return 0 with a not stolen value") { str key = STR_STATIC_INIT("test"); str otherKey1 = STR_STATIC_INIT("otherKey1"); check(value_hashtable_insert(hashtable, otherKey1, value_new(1337)) == 1); check(value_hashtable_isStolen(hashtable, key) == 0, "return should be 0"); } } } context("use as a normal hashtable with forced collisions") { static value_hashtable *hashtable = NULL; before_each() { hashtable = value_hashtable_new(2); check(hashtable != NULL, "hashtable should not be NULL"); } after_each() { value_hashtable_destroy(&hashtable); check(hashtable == NULL, "hashtable should be NULL"); } describe("value_hashtable_markStolen()") { it("should mark the value for the given key as stolen") { str key = STR_STATIC_INIT("leet"); str otherKey1 = STR_STATIC_INIT("otherKey1"); str otherKey2 = STR_STATIC_INIT("otherKey2"); str otherKey3 = STR_STATIC_INIT("otherKey3"); str otherKey4 = STR_STATIC_INIT("otherKey4"); check(value_hashtable_has(hashtable, key) == 0,"hashtable should not have the key already"); check(value_hashtable_insert(hashtable, key, value_new(1337)) == 1); check(value_hashtable_has(hashtable, key) == 1, "hashtable should have the key"); check(value_hashtable_insert(hashtable, otherKey1, value_new(1337)) == 1); check(value_hashtable_insert(hashtable, otherKey2, value_new(1337)) == 1); check(value_hashtable_insert(hashtable, otherKey3, value_new(1337)) == 1); check(value_hashtable_insert(hashtable, otherKey4, value_new(1337)) == 1); check(value_hashtable_markStolen(hashtable, key) == 1, "hashtable should mark the value for the key as stolen"); check(value_hashtable_isStolen(hashtable, key) == 1, "hashtable should have the value for the key marked as stolen"); } } } }