/* SPDX-License-Identifier: BSD-3-Clause */ /* * Copyright © 2010, Zed A. Shaw. * Copyright © 2020 rsiddharth */ #include "minunit.h" #include #include #include Hashmap *map = NULL; Hashmap *map_alt = NULL; static int traverse_called = 0; static int traverse_duplicates = 0; struct tagbstring test0 = bsStatic("test data 0"); struct tagbstring test1 = bsStatic("test data 1"); struct tagbstring test2 = bsStatic("test data 2"); struct tagbstring test3 = bsStatic("xest data 3"); struct tagbstring expect0 = bsStatic("THE VALUE 0"); struct tagbstring expect1 = bsStatic("THE VALUE 1"); struct tagbstring expect2 = bsStatic("THE VALUE 2"); struct tagbstring expect3 = bsStatic("THE VALUE 3"); static int traverse_good_cb(HashmapNode *node) { debug("KEY: %s", bdata((bstring) node->key)); traverse_called++; return 0; } static int traverse_fail_cb(HashmapNode *node) { debug("KEY %s", bdata((bstring) node->key)); traverse_called++; if (traverse_called == 2) { return 1; } else { return 0; } } static int traverse_duplicates_cb(HashmapNode *node) { if ((bstring) node->data == &expect1) { ++traverse_duplicates; } return 0; } int non_empty_buckets(Hashmap *map) { int i = 0, non_empty = 0; for (i = 0; i < DArray_count(map->buckets); i++) { DArray *bucket = DArray_get(map->buckets, i); if (bucket) { non_empty += 1; } } return non_empty; } char *test_create() { map = Hashmap_create(NULL, NULL); mu_assert(map != NULL, "Failed to create map."); map_alt = Hashmap_create(NULL, (Hashmap_hash) fnv_hash); mu_assert(map != NULL, "Failde to create map_alt."); return NULL; } char *test_destroy() { Hashmap_destroy(map); Hashmap_destroy(map_alt); return NULL; } char *test_get_test() { int rc = Hashmap_set(map, &test1, &expect1); mu_assert(rc == 0, "Failed to set &test1"); bstring result = Hashmap_get(map, &test1); mu_assert(result == &expect1, "Wron value for test1."); rc = Hashmap_set(map, &test2, &expect2); mu_assert(rc == 0, "Failed to test test2"); result = Hashmap_get(map, &test2); mu_assert(result == &expect2, "Wrong value for test2."); rc = Hashmap_set(map, &test3, &expect3); mu_assert(rc == 0, "Failed to set test3"); result = Hashmap_get(map, &test3); mu_assert(result == &expect3, "Wrong value for test3"); return NULL; } char *test_traverse() { int rc = Hashmap_traverse(map, traverse_good_cb); mu_assert(rc == 0, "Failed to traverse"); mu_assert(traverse_called == 3, "Wrong count traverse"); traverse_called = 0; rc = Hashmap_traverse(map, traverse_fail_cb); mu_assert(rc == 1, "Failed to traverse."); mu_assert(traverse_called == 2, "Wrong count traverse for fail."); return NULL; } char *test_keys() { DArray *keys = Hashmap_keys(map); mu_assert(keys != NULL, "Unable to get hashmap's keys"); mu_assert(DArray_count(keys) == 3, "Expected three keys"); for (int i = 0; i < DArray_count(keys); i++) { char *k = bdata((bstring) DArray_get(keys, i)); debug("KEY: %s", k); } // clean up. DArray_destroy(keys); return NULL; } char *test_delete() { bstring deleted = (bstring) Hashmap_delete(map, &test1); mu_assert(deleted != NULL, "Got NULL on delete"); mu_assert(deleted == &expect1, "Should get test1"); bstring result = Hashmap_get(map, &test1); mu_assert(result == NULL, "Should delete"); deleted = (bstring) Hashmap_delete(map, &test2); mu_assert(deleted != NULL, "Got NULL on delete"); mu_assert(deleted == &expect2, "Should get test2"); result = Hashmap_get(map, &test2); mu_assert(result == NULL, "Should delete"); deleted = (bstring) Hashmap_delete(map, &test3); mu_assert(deleted != NULL, "Got NULL on delete."); mu_assert(deleted == &expect3, "Should get test3"); result = Hashmap_get(map, &test3); mu_assert(result == NULL, "Should delete."); return NULL; } char *test_bucket_destruction() { int rc = 0, non_empty = 0; bstring deleted = NULL; // Insert some elements. rc = Hashmap_set(map, &test1, &expect1); mu_assert(rc == 0, "Failed to set &test1 0"); rc = Hashmap_set(map, &test2, &expect2); mu_assert(rc == 0, "Failed to test test2"); // Non-empty buckets test. non_empty = non_empty_buckets(map); mu_assert(non_empty == 2, "Expected two non-empty buckets"); // Remove test1 deleted = Hashmap_delete(map, &test1); mu_assert(deleted != NULL, "Error deleting test1"); // Non-empty buckets test. non_empty = non_empty_buckets(map); mu_assert(non_empty == 1, "Expected one non-empty buckets"); // Remove test2 deleted = Hashmap_delete(map, &test2); mu_assert(deleted != NULL, "Error deleting test2"); // Non-empty buckets test. non_empty = non_empty_buckets(map); mu_assert(non_empty == 0, "Expected one non-empty buckets"); return NULL; } char *test_set_duplicates() { int rc = 0; // Insert test1 two times. rc = Hashmap_set(map, &test1, &expect1); mu_assert(rc == 0, "Failed to set &test1 0"); rc = Hashmap_set(map, &test1, &expect1); mu_assert(rc == 0, "Failed to set &test1 1"); // Insert test2 one time. rc = Hashmap_set(map, &test2, &expect2); mu_assert(rc == 0, "Failed to test test2"); // Insert test3 one time. rc = Hashmap_set(map, &test3, &expect3); mu_assert(rc == 0, "Failed to set test3"); // Test there are two test1 nodes. traverse_duplicates = 0; rc = Hashmap_traverse(map, traverse_duplicates_cb); mu_assert(traverse_duplicates == 2, "traverse_duplicates must be 2"); // Cleanup bstring deleted = NULL; deleted = Hashmap_delete(map, &test1); mu_assert(deleted != NULL, "Error deleting test1 0"); deleted = Hashmap_delete(map, &test1); mu_assert(deleted != NULL, "Error deleting test1 1"); deleted = Hashmap_delete(map, &test2); mu_assert(deleted != NULL, "Error deleting test2"); deleted = Hashmap_delete(map, &test3); mu_assert(deleted != NULL, "Error deleting test3"); return NULL; } char *test_set_fucked() { int rc = 0; // Insert test1 three times. rc = Hashmap_set_fucked(map, &test1, &expect1); mu_assert(rc == 1, "Failed to set fuck &test1 0"); rc = Hashmap_set_fucked(map, &test1, &expect1); mu_assert(rc == 0, "Failed to set fuck &test1 1"); rc = Hashmap_set_fucked(map, &test1, &expect1); mu_assert(rc == 0, "Failed to set fuck &test1 2"); // Insert test2 one time. rc = Hashmap_set_fucked(map, &test2, &expect2); mu_assert(rc == 1, "Failed to test test2"); // Insert test3 one time. rc = Hashmap_set_fucked(map, &test3, &expect3); mu_assert(rc == 1, "Failed to set test3"); // Test there are two test1 nodes. traverse_duplicates = 0; rc = Hashmap_traverse(map, traverse_duplicates_cb); mu_assert(traverse_duplicates == 1, "traverse_duplicates must be 1"); // Cleanup bstring deleted = NULL; deleted = Hashmap_delete(map, &test1); mu_assert(deleted != NULL, "Error deleting test1"); deleted = Hashmap_delete(map, &test1); mu_assert(deleted == NULL, "Error test1 must be already deleted"); deleted = Hashmap_delete(map, &test2); mu_assert(deleted != NULL, "Error deleting test2"); deleted = Hashmap_delete(map, &test3); mu_assert(deleted != NULL, "Error deleting test3"); return NULL; } char *test_fnv_hash() { uint32_t hash[3]; hash[0] = fnv_hash(&test0); mu_assert(hash[0] > 0, "hash not set correctly for key test0"); hash[1] = fnv_hash(&test1); mu_assert(hash[1] > 0, "hash not set correctly for key test1"); hash[2] = fnv_hash(&test2); mu_assert(hash[2] > 0, "hash not set correctly for key test2"); // Check all three hashes are different. mu_assert(hash[0] != hash[1], "hash for test0 = hash for test1"); mu_assert(hash[0] != hash[2], "hash for test0 = hash for test2"); mu_assert(hash[1] != hash[2], "hash for test1 = hash for test2"); return NULL; } char *all_tests() { mu_suite_start(); mu_run_test(test_create); mu_run_test(test_get_test); mu_run_test(test_traverse); mu_run_test(test_keys); mu_run_test(test_delete); mu_run_test(test_bucket_destruction); mu_run_test(test_set_duplicates); mu_run_test(test_set_fucked); mu_run_test(test_fnv_hash); mu_run_test(test_destroy); return NULL; } RUN_TESTS(all_tests);