153a5a1b3Sopenharmony_ci#ifdef HAVE_CONFIG_H 253a5a1b3Sopenharmony_ci#include <config.h> 353a5a1b3Sopenharmony_ci#endif 453a5a1b3Sopenharmony_ci 553a5a1b3Sopenharmony_ci#include <check.h> 653a5a1b3Sopenharmony_ci#include <pulsecore/hashmap.h> 753a5a1b3Sopenharmony_ci 853a5a1b3Sopenharmony_cistruct int_entry { 953a5a1b3Sopenharmony_ci int key; 1053a5a1b3Sopenharmony_ci int value; 1153a5a1b3Sopenharmony_ci}; 1253a5a1b3Sopenharmony_ci 1353a5a1b3Sopenharmony_cistatic unsigned int_trivial_hash_func(const void* pa) { 1453a5a1b3Sopenharmony_ci int a = *((unsigned*) pa); 1553a5a1b3Sopenharmony_ci if (a < 0) { 1653a5a1b3Sopenharmony_ci return -a; 1753a5a1b3Sopenharmony_ci } 1853a5a1b3Sopenharmony_ci return a; 1953a5a1b3Sopenharmony_ci} 2053a5a1b3Sopenharmony_ci 2153a5a1b3Sopenharmony_cistatic int int_compare_func(const void* pa, const void* pb) { 2253a5a1b3Sopenharmony_ci int a, b; 2353a5a1b3Sopenharmony_ci a = *((int*) pa); 2453a5a1b3Sopenharmony_ci b = *((int*) pb); 2553a5a1b3Sopenharmony_ci if (a < b) { 2653a5a1b3Sopenharmony_ci return -1; 2753a5a1b3Sopenharmony_ci } 2853a5a1b3Sopenharmony_ci if (a == b) { 2953a5a1b3Sopenharmony_ci return 0; 3053a5a1b3Sopenharmony_ci } 3153a5a1b3Sopenharmony_ci return 1; 3253a5a1b3Sopenharmony_ci} 3353a5a1b3Sopenharmony_ci 3453a5a1b3Sopenharmony_ci/* single_key_test exercises basic hashmap functionality on a single key. */ 3553a5a1b3Sopenharmony_ciSTART_TEST(single_key_test) 3653a5a1b3Sopenharmony_ci { 3753a5a1b3Sopenharmony_ci pa_hashmap* map; 3853a5a1b3Sopenharmony_ci struct int_entry entry; 3953a5a1b3Sopenharmony_ci int lookup_key; 4053a5a1b3Sopenharmony_ci int put_ret; 4153a5a1b3Sopenharmony_ci void* get_ret; 4253a5a1b3Sopenharmony_ci unsigned size_ret; 4353a5a1b3Sopenharmony_ci 4453a5a1b3Sopenharmony_ci entry.key = 0; 4553a5a1b3Sopenharmony_ci entry.value = 0; 4653a5a1b3Sopenharmony_ci 4753a5a1b3Sopenharmony_ci lookup_key = 0; 4853a5a1b3Sopenharmony_ci 4953a5a1b3Sopenharmony_ci map = pa_hashmap_new(int_trivial_hash_func, int_compare_func); 5053a5a1b3Sopenharmony_ci 5153a5a1b3Sopenharmony_ci if ((put_ret = pa_hashmap_put(map, &entry.key, &entry)) != 0) { 5253a5a1b3Sopenharmony_ci ck_abort_msg("Hashmap rejected k=0/v=0; got %d, want %d", put_ret, 0); 5353a5a1b3Sopenharmony_ci } 5453a5a1b3Sopenharmony_ci 5553a5a1b3Sopenharmony_ci if ((size_ret = pa_hashmap_size(map)) != 1) { 5653a5a1b3Sopenharmony_ci ck_abort_msg("Hashmap reported wrong size; got %u, want 1", size_ret); 5753a5a1b3Sopenharmony_ci } 5853a5a1b3Sopenharmony_ci 5953a5a1b3Sopenharmony_ci if ((get_ret = pa_hashmap_get(map, &lookup_key)) != &entry) { 6053a5a1b3Sopenharmony_ci ck_abort_msg("Got wrong value from hashmap for k=0; got %p, want %p", get_ret, &entry); 6153a5a1b3Sopenharmony_ci } 6253a5a1b3Sopenharmony_ci 6353a5a1b3Sopenharmony_ci if ((put_ret = pa_hashmap_put(map, &entry.key, &entry)) == 0) { 6453a5a1b3Sopenharmony_ci ck_abort_msg("Hashmap allowed duplicate key for k=0; got %d, want non-zero", put_ret); 6553a5a1b3Sopenharmony_ci } 6653a5a1b3Sopenharmony_ci 6753a5a1b3Sopenharmony_ci if ((size_ret = pa_hashmap_size(map)) != 1) { 6853a5a1b3Sopenharmony_ci ck_abort_msg("Hashmap reported wrong size; got %u, want 1", size_ret); 6953a5a1b3Sopenharmony_ci } 7053a5a1b3Sopenharmony_ci 7153a5a1b3Sopenharmony_ci if ((get_ret = pa_hashmap_remove(map, &lookup_key)) != &entry) { 7253a5a1b3Sopenharmony_ci ck_abort_msg("Hashmap returned wrong value during free; got %p, want %p", get_ret, &entry); 7353a5a1b3Sopenharmony_ci } 7453a5a1b3Sopenharmony_ci 7553a5a1b3Sopenharmony_ci if ((size_ret = pa_hashmap_size(map)) != 0) { 7653a5a1b3Sopenharmony_ci ck_abort_msg("Hashmap reported wrong size; got %u, want 1", size_ret); 7753a5a1b3Sopenharmony_ci } 7853a5a1b3Sopenharmony_ci 7953a5a1b3Sopenharmony_ci pa_hashmap_free(map); 8053a5a1b3Sopenharmony_ci } 8153a5a1b3Sopenharmony_ciEND_TEST 8253a5a1b3Sopenharmony_ci 8353a5a1b3Sopenharmony_ci/* remove_all_test checks that pa_hashmap_remove_all really removes all entries 8453a5a1b3Sopenharmony_ci * from the map.*/ 8553a5a1b3Sopenharmony_ciSTART_TEST(remove_all_test) 8653a5a1b3Sopenharmony_ci { 8753a5a1b3Sopenharmony_ci pa_hashmap* map; 8853a5a1b3Sopenharmony_ci struct int_entry entries[1000]; 8953a5a1b3Sopenharmony_ci unsigned size; 9053a5a1b3Sopenharmony_ci 9153a5a1b3Sopenharmony_ci for (int i = 0; i < 1000; i++) { 9253a5a1b3Sopenharmony_ci entries[i].key = i; 9353a5a1b3Sopenharmony_ci entries[i].value = i; 9453a5a1b3Sopenharmony_ci } 9553a5a1b3Sopenharmony_ci 9653a5a1b3Sopenharmony_ci map = pa_hashmap_new(int_trivial_hash_func, int_compare_func); 9753a5a1b3Sopenharmony_ci 9853a5a1b3Sopenharmony_ci for (int i = 0; i < 1000; i++) { 9953a5a1b3Sopenharmony_ci pa_hashmap_put(map, &entries[i].key, &entries[i]); 10053a5a1b3Sopenharmony_ci } 10153a5a1b3Sopenharmony_ci 10253a5a1b3Sopenharmony_ci if ((size = pa_hashmap_size(map)) != 1000) { 10353a5a1b3Sopenharmony_ci ck_abort_msg("Hashmap has wrong size; got %u, want 1000", size); 10453a5a1b3Sopenharmony_ci } 10553a5a1b3Sopenharmony_ci 10653a5a1b3Sopenharmony_ci pa_hashmap_remove_all(map); 10753a5a1b3Sopenharmony_ci 10853a5a1b3Sopenharmony_ci if ((size = pa_hashmap_size(map)) != 0) { 10953a5a1b3Sopenharmony_ci ck_abort_msg("Hashmap has wrong size; got %u, want 0", size); 11053a5a1b3Sopenharmony_ci } 11153a5a1b3Sopenharmony_ci 11253a5a1b3Sopenharmony_ci pa_hashmap_free(map); 11353a5a1b3Sopenharmony_ci } 11453a5a1b3Sopenharmony_ciEND_TEST 11553a5a1b3Sopenharmony_ci 11653a5a1b3Sopenharmony_ci/* fill_all_buckets hits the hashmap with enough keys to exercise the bucket 11753a5a1b3Sopenharmony_ci * linked list for every bucket. */ 11853a5a1b3Sopenharmony_ciSTART_TEST(fill_all_buckets) 11953a5a1b3Sopenharmony_ci { 12053a5a1b3Sopenharmony_ci pa_hashmap* map; 12153a5a1b3Sopenharmony_ci struct int_entry entries[1000]; 12253a5a1b3Sopenharmony_ci int lookup_keys[1000]; /* Don't share addresses with insertion keys */ 12353a5a1b3Sopenharmony_ci 12453a5a1b3Sopenharmony_ci map = pa_hashmap_new(int_trivial_hash_func, int_compare_func); 12553a5a1b3Sopenharmony_ci 12653a5a1b3Sopenharmony_ci for (int i = 0; i < 1000; i++) { 12753a5a1b3Sopenharmony_ci entries[i].key = i; 12853a5a1b3Sopenharmony_ci lookup_keys[i] = i; 12953a5a1b3Sopenharmony_ci entries[i].value = i; 13053a5a1b3Sopenharmony_ci } 13153a5a1b3Sopenharmony_ci 13253a5a1b3Sopenharmony_ci for (int i = 0; i < 1000; i++) { 13353a5a1b3Sopenharmony_ci int put_ret; 13453a5a1b3Sopenharmony_ci unsigned size_ret; 13553a5a1b3Sopenharmony_ci 13653a5a1b3Sopenharmony_ci if ((put_ret = pa_hashmap_put(map, &entries[i].key, &entries[i])) != 0) { 13753a5a1b3Sopenharmony_ci ck_abort_msg("Unexpected failure putting k=%d v=%d into the map", entries[i].key, entries[i].value); 13853a5a1b3Sopenharmony_ci } 13953a5a1b3Sopenharmony_ci 14053a5a1b3Sopenharmony_ci if ((size_ret = pa_hashmap_size(map)) != i + 1) { 14153a5a1b3Sopenharmony_ci ck_abort_msg("Hashmap reported wrong size; got %u, want %d", size_ret, i); 14253a5a1b3Sopenharmony_ci } 14353a5a1b3Sopenharmony_ci } 14453a5a1b3Sopenharmony_ci 14553a5a1b3Sopenharmony_ci for (int i = 0; i < 1000; i++) { 14653a5a1b3Sopenharmony_ci unsigned size_ret; 14753a5a1b3Sopenharmony_ci int* k; 14853a5a1b3Sopenharmony_ci struct int_entry* v; 14953a5a1b3Sopenharmony_ci 15053a5a1b3Sopenharmony_ci k = lookup_keys + i; 15153a5a1b3Sopenharmony_ci 15253a5a1b3Sopenharmony_ci v = (struct int_entry*) pa_hashmap_remove(map, k); 15353a5a1b3Sopenharmony_ci if (v == NULL) { 15453a5a1b3Sopenharmony_ci ck_abort_msg("Hashmap returned NULL for k=%d; wanted nonnull", *k); 15553a5a1b3Sopenharmony_ci } 15653a5a1b3Sopenharmony_ci if ((*v).value != i) { 15753a5a1b3Sopenharmony_ci ck_abort_msg("Hashmap returned wrong value for k=%d; got %d, want %d", *k, (*v).value, i); 15853a5a1b3Sopenharmony_ci } 15953a5a1b3Sopenharmony_ci 16053a5a1b3Sopenharmony_ci if ((size_ret = pa_hashmap_size(map)) != 1000 - i - 1) { 16153a5a1b3Sopenharmony_ci ck_abort_msg("Hashmap reported wrong size; got %u, want %d", size_ret, 1000 - i); 16253a5a1b3Sopenharmony_ci } 16353a5a1b3Sopenharmony_ci } 16453a5a1b3Sopenharmony_ci 16553a5a1b3Sopenharmony_ci pa_hashmap_free(map); 16653a5a1b3Sopenharmony_ci } 16753a5a1b3Sopenharmony_ciEND_TEST 16853a5a1b3Sopenharmony_ci 16953a5a1b3Sopenharmony_ci/* iterate_test exercises the iteration list maintained by the hashtable. */ 17053a5a1b3Sopenharmony_ciSTART_TEST(iterate_test) 17153a5a1b3Sopenharmony_ci { 17253a5a1b3Sopenharmony_ci pa_hashmap* map; 17353a5a1b3Sopenharmony_ci struct int_entry entries[1000]; 17453a5a1b3Sopenharmony_ci void* state; 17553a5a1b3Sopenharmony_ci struct int_entry* v; 17653a5a1b3Sopenharmony_ci int expected; 17753a5a1b3Sopenharmony_ci 17853a5a1b3Sopenharmony_ci for (int i = 0; i < 1000; i++) { 17953a5a1b3Sopenharmony_ci entries[i].key = i; 18053a5a1b3Sopenharmony_ci entries[i].value = i; 18153a5a1b3Sopenharmony_ci } 18253a5a1b3Sopenharmony_ci 18353a5a1b3Sopenharmony_ci map = pa_hashmap_new(int_trivial_hash_func, int_compare_func); 18453a5a1b3Sopenharmony_ci 18553a5a1b3Sopenharmony_ci for (int i = 0; i < 1000; i++) { 18653a5a1b3Sopenharmony_ci if (pa_hashmap_put(map, &(entries[i].key), &(entries[i])) != 0) { 18753a5a1b3Sopenharmony_ci ck_abort_msg("Unexpected failure putting k=%d v=%d into the map", entries[i].key, entries[i].value); 18853a5a1b3Sopenharmony_ci } 18953a5a1b3Sopenharmony_ci } 19053a5a1b3Sopenharmony_ci 19153a5a1b3Sopenharmony_ci expected = 0; 19253a5a1b3Sopenharmony_ci PA_HASHMAP_FOREACH (v, map, state) { 19353a5a1b3Sopenharmony_ci if ((*v).value != expected) { 19453a5a1b3Sopenharmony_ci ck_abort_msg("Got bad order iterating over hashmap: got %d, want %d", v->value, expected); 19553a5a1b3Sopenharmony_ci } 19653a5a1b3Sopenharmony_ci expected++; 19753a5a1b3Sopenharmony_ci } 19853a5a1b3Sopenharmony_ci 19953a5a1b3Sopenharmony_ci expected = 999; 20053a5a1b3Sopenharmony_ci PA_HASHMAP_FOREACH_BACKWARDS (v, map, state) { 20153a5a1b3Sopenharmony_ci if ((*v).value != expected) { 20253a5a1b3Sopenharmony_ci ck_abort_msg("Got bad order iterating over hashmap: got %d, want %d", v->value, expected); 20353a5a1b3Sopenharmony_ci } 20453a5a1b3Sopenharmony_ci expected--; 20553a5a1b3Sopenharmony_ci } 20653a5a1b3Sopenharmony_ci 20753a5a1b3Sopenharmony_ci /* Now empty out the hashmap. The iteration list should be empty. */ 20853a5a1b3Sopenharmony_ci for(int i = 0; i < 1000; i++) { 20953a5a1b3Sopenharmony_ci pa_hashmap_remove(map, &(entries[i].key)); 21053a5a1b3Sopenharmony_ci } 21153a5a1b3Sopenharmony_ci 21253a5a1b3Sopenharmony_ci PA_HASHMAP_FOREACH(v, map, state) { 21353a5a1b3Sopenharmony_ci ck_abort_msg("Iteration over empty map returned entries"); 21453a5a1b3Sopenharmony_ci } 21553a5a1b3Sopenharmony_ci 21653a5a1b3Sopenharmony_ci /* Now add one element back. The iteration list should only contain this 21753a5a1b3Sopenharmony_ci * one element, even though the entry nodes are reused. */ 21853a5a1b3Sopenharmony_ci if(pa_hashmap_put(map, &(entries[0].key), &(entries[0])) != 0) { 21953a5a1b3Sopenharmony_ci ck_abort_msg("Unexpected failure putting k=%d v=%d into the map", entries[0].key, entries[0].value); 22053a5a1b3Sopenharmony_ci } 22153a5a1b3Sopenharmony_ci 22253a5a1b3Sopenharmony_ci expected = 0; 22353a5a1b3Sopenharmony_ci PA_HASHMAP_FOREACH(v, map, state) { 22453a5a1b3Sopenharmony_ci if ((*v).value != expected) { 22553a5a1b3Sopenharmony_ci ck_abort_msg("Got bad order iterating over hashmap: got %d, want %d", v->value, expected); 22653a5a1b3Sopenharmony_ci } 22753a5a1b3Sopenharmony_ci expected++; 22853a5a1b3Sopenharmony_ci } 22953a5a1b3Sopenharmony_ci if (expected != 1) { 23053a5a1b3Sopenharmony_ci ck_abort_msg("Got too many elements while iterating: got %d, want 1", expected); 23153a5a1b3Sopenharmony_ci } 23253a5a1b3Sopenharmony_ci 23353a5a1b3Sopenharmony_ci pa_hashmap_free(map); 23453a5a1b3Sopenharmony_ci } 23553a5a1b3Sopenharmony_ciEND_TEST 23653a5a1b3Sopenharmony_ci 23753a5a1b3Sopenharmony_ciint main(int argc, char** argv) { 23853a5a1b3Sopenharmony_ci int failed = 0; 23953a5a1b3Sopenharmony_ci Suite* s; 24053a5a1b3Sopenharmony_ci TCase* tc; 24153a5a1b3Sopenharmony_ci SRunner* sr; 24253a5a1b3Sopenharmony_ci 24353a5a1b3Sopenharmony_ci s = suite_create("HashMap"); 24453a5a1b3Sopenharmony_ci tc = tcase_create("hashmap"); 24553a5a1b3Sopenharmony_ci tcase_add_test(tc, single_key_test); 24653a5a1b3Sopenharmony_ci tcase_add_test(tc, remove_all_test); 24753a5a1b3Sopenharmony_ci tcase_add_test(tc, fill_all_buckets); 24853a5a1b3Sopenharmony_ci tcase_add_test(tc, iterate_test); 24953a5a1b3Sopenharmony_ci suite_add_tcase(s, tc); 25053a5a1b3Sopenharmony_ci 25153a5a1b3Sopenharmony_ci sr = srunner_create(s); 25253a5a1b3Sopenharmony_ci srunner_run_all(sr, CK_NORMAL); 25353a5a1b3Sopenharmony_ci failed = srunner_ntests_failed(sr); 25453a5a1b3Sopenharmony_ci srunner_free(sr); 25553a5a1b3Sopenharmony_ci 25653a5a1b3Sopenharmony_ci if (failed > 0) { 25753a5a1b3Sopenharmony_ci return EXIT_FAILURE; 25853a5a1b3Sopenharmony_ci } 25953a5a1b3Sopenharmony_ci return EXIT_SUCCESS; 26053a5a1b3Sopenharmony_ci} 261