blob: f19ff360a05c0b76f280deb8f9d03d1e37a0c874 [file] [log] [blame]
Michal Vaskof20ad112023-02-10 15:12:12 +01001/**
aPiecek023f83a2021-05-11 07:37:03 +02002 * @file test_hash_table.c
Radek Krejciaaf6d402018-09-20 15:14:47 +02003 * @author: Radek Krejci <rkrejci@cesnet.cz>
4 * @brief unit tests for functions from hash_table.c
5 *
6 * Copyright (c) 2018 CESNET, z.s.p.o.
7 *
8 * This source code is licensed under BSD 3-Clause License (the "License").
9 * You may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
11 *
12 * https://opensource.org/licenses/BSD-3-Clause
13 */
Radek Iša56ca9e42020-09-08 18:42:00 +020014#define _UTEST_MAIN_
15#include "utests.h"
Radek Krejci535ea9f2020-05-29 16:01:05 +020016
Radek Krejcica376bd2020-06-11 16:04:06 +020017#include <stdlib.h>
Radek Krejciaaf6d402018-09-20 15:14:47 +020018
Radek Krejci70593c12020-06-13 20:48:09 +020019#include "common.h"
20#include "hash_table.h"
Radek Krejci2d7a47b2019-05-16 13:34:10 +020021
Radek Krejciaaf6d402018-09-20 15:14:47 +020022static void
23test_invalid_arguments(void **state)
24{
Radek Krejci011e4aa2020-09-04 15:22:31 +020025 assert_int_equal(LY_EINVAL, lydict_insert(NULL, NULL, 0, NULL));
Radek Iša56ca9e42020-09-08 18:42:00 +020026 CHECK_LOG("Invalid argument ctx (lydict_insert()).", NULL);
Radek Krejciaaf6d402018-09-20 15:14:47 +020027
Radek Krejci011e4aa2020-09-04 15:22:31 +020028 assert_int_equal(LY_EINVAL, lydict_insert_zc(NULL, NULL, NULL));
Radek Iša56ca9e42020-09-08 18:42:00 +020029 CHECK_LOG("Invalid argument ctx (lydict_insert_zc()).", NULL);
30 assert_int_equal(LY_EINVAL, lydict_insert_zc(UTEST_LYCTX, NULL, NULL));
Michal Vaskobe27c912021-02-24 17:07:37 +010031 CHECK_LOG_CTX("Invalid argument str_p (lydict_insert_zc()).", NULL);
Radek Krejciaaf6d402018-09-20 15:14:47 +020032}
33
34static void
35test_dict_hit(void **state)
36{
Radek Krejci011e4aa2020-09-04 15:22:31 +020037 const char *str1, *str2, *str3;
Radek Krejciaaf6d402018-09-20 15:14:47 +020038
39 /* insert 2 strings, one of them repeatedly */
Radek Iša56ca9e42020-09-08 18:42:00 +020040 assert_int_equal(LY_SUCCESS, lydict_insert(UTEST_LYCTX, "test1", 0, &str1));
Radek Krejciaaf6d402018-09-20 15:14:47 +020041 assert_non_null(str1);
42 /* via zerocopy we have to get the same pointer as provided */
43 assert_non_null(str2 = strdup("test2"));
Radek Iša56ca9e42020-09-08 18:42:00 +020044 assert_int_equal(LY_SUCCESS, lydict_insert_zc(UTEST_LYCTX, (char *)str2, &str3));
Radek Krejci011e4aa2020-09-04 15:22:31 +020045 assert_ptr_equal(str2, str3);
Radek Krejciaaf6d402018-09-20 15:14:47 +020046 /* here we get the same pointer as in case the string was inserted first time */
Radek Iša56ca9e42020-09-08 18:42:00 +020047 assert_int_equal(LY_SUCCESS, lydict_insert(UTEST_LYCTX, "test1", 0, &str2));
Radek Krejciaaf6d402018-09-20 15:14:47 +020048 assert_non_null(str2);
49 assert_ptr_equal(str1, str2);
50
51 /* remove strings, but the repeatedly inserted only once */
Radek Iša56ca9e42020-09-08 18:42:00 +020052 lydict_remove(UTEST_LYCTX, "test1");
53 lydict_remove(UTEST_LYCTX, "test2");
Radek Krejciaaf6d402018-09-20 15:14:47 +020054
55 /* destroy dictionary - should raise warning about data presence */
Radek Krejci90ed21e2021-04-12 14:47:46 +020056 ly_ctx_destroy(UTEST_LYCTX);
Radek Iša56ca9e42020-09-08 18:42:00 +020057 UTEST_LYCTX = NULL;
58 CHECK_LOG("String \"test1\" not freed from the dictionary, refcount 1", NULL);
Radek Krejciaaf6d402018-09-20 15:14:47 +020059
60#ifndef NDEBUG
61 /* cleanup */
Radek Krejcib4ac5a92020-11-23 17:54:33 +010062 free((char *)str1);
Radek Krejciaaf6d402018-09-20 15:14:47 +020063#endif
64}
65
Radek Krejci1deb5be2020-08-26 16:43:36 +020066static uint8_t
67ht_equal_clb(void *val1, void *val2, uint8_t mod, void *cb_data)
Radek Krejci0ae092d2018-09-20 16:43:19 +020068{
69 int *v1, *v2;
Radek Krejcib4ac5a92020-11-23 17:54:33 +010070
Radek Krejci0ae092d2018-09-20 16:43:19 +020071 (void)mod;
72 (void)cb_data;
73
74 v1 = (int *)val1;
75 v2 = (int *)val2;
76
77 return *v1 == *v2;
78}
79
80static void
81test_ht_basic(void **state)
82{
Radek Krejci0ae092d2018-09-20 16:43:19 +020083 uint32_t i;
Michal Vasko8efac242023-03-30 08:24:56 +020084 struct ly_ht *ht;
Radek Krejci0ae092d2018-09-20 16:43:19 +020085
86 assert_non_null(ht = lyht_new(8, sizeof(int), ht_equal_clb, NULL, 0));
87
88 i = 2;
Michal Vaskoda859032020-07-14 12:20:14 +020089 assert_int_equal(LY_ENOTFOUND, lyht_find(ht, &i, i, NULL));
Radek Krejci0ae092d2018-09-20 16:43:19 +020090 assert_int_equal(LY_SUCCESS, lyht_insert(ht, &i, i, NULL));
Michal Vaskoda859032020-07-14 12:20:14 +020091 assert_int_equal(LY_SUCCESS, lyht_find(ht, &i, i, NULL));
Radek Krejci0ae092d2018-09-20 16:43:19 +020092 assert_int_equal(LY_SUCCESS, lyht_remove(ht, &i, i));
Michal Vaskoda859032020-07-14 12:20:14 +020093 assert_int_equal(LY_ENOTFOUND, lyht_find(ht, &i, i, NULL));
Michal Vasko4a4c7ed2020-07-17 09:30:12 +020094 assert_int_equal(LY_ENOTFOUND, lyht_remove(ht, &i, i));
Radek Iša56ca9e42020-09-08 18:42:00 +020095 CHECK_LOG("Invalid argument hash (lyht_remove_with_resize_cb()).", NULL);
Radek Krejci0ae092d2018-09-20 16:43:19 +020096
Michal Vasko77b7f90a2023-01-31 15:42:41 +010097 lyht_free(ht, NULL);
Radek Krejci0ae092d2018-09-20 16:43:19 +020098}
99
100static void
101test_ht_resize(void **state)
102{
Radek Krejci0ae092d2018-09-20 16:43:19 +0200103 uint32_t i;
Michal Vasko8efac242023-03-30 08:24:56 +0200104 struct ly_ht *ht;
Radek Krejci0ae092d2018-09-20 16:43:19 +0200105
106 assert_non_null(ht = lyht_new(8, sizeof(int), ht_equal_clb, NULL, 1));
107 assert_int_equal(8, ht->size);
108
109 /* insert records into indexes 2-7 */
110 for (i = 2; i < 8; ++i) {
111 assert_int_equal(LY_SUCCESS, lyht_insert(ht, &i, i, NULL));
112 }
113 /* check that table resized */
114 assert_int_equal(16, ht->size);
115
116 /* check expected content of the table */
117 for (i = 0; i < 16; ++i) {
Radek Krejcib4ac5a92020-11-23 17:54:33 +0100118 if ((i >= 2) && (i < 8)) {
Radek Krejci0ae092d2018-09-20 16:43:19 +0200119 /* inserted data on indexes 2-7 */
Olivier Matz6a669c12023-09-28 12:07:12 +0200120 assert_int_not_equal(UINT32_MAX, ht->hlists[i].first);
Olivier Matz75c00192023-09-21 14:35:12 +0200121 assert_int_equal(LY_SUCCESS, lyht_find(ht, &i, i, NULL));
Radek Krejci0ae092d2018-09-20 16:43:19 +0200122 } else {
123 /* nothing otherwise */
Olivier Matz6a669c12023-09-28 12:07:12 +0200124 assert_int_equal(UINT32_MAX, ht->hlists[i].first);
Olivier Matz75c00192023-09-21 14:35:12 +0200125 assert_int_equal(LY_ENOTFOUND, lyht_find(ht, &i, i, NULL));
Radek Krejci0ae092d2018-09-20 16:43:19 +0200126 }
127 }
128
129 /* removing not present data should fail */
130 for (i = 0; i < 2; ++i) {
Radek Iša56ca9e42020-09-08 18:42:00 +0200131 UTEST_LOG_CLEAN;
Michal Vasko4a4c7ed2020-07-17 09:30:12 +0200132 assert_int_equal(LY_ENOTFOUND, lyht_remove(ht, &i, i));
Radek Iša56ca9e42020-09-08 18:42:00 +0200133 CHECK_LOG("Invalid argument hash (lyht_remove_with_resize_cb()).", NULL);
Radek Krejci0ae092d2018-09-20 16:43:19 +0200134 }
135 /* removing present data, resize should happened
136 * when we are below 25% of the table filled, so with 3 records left */
Radek Krejcib4ac5a92020-11-23 17:54:33 +0100137 for ( ; i < 5; ++i) {
Radek Krejci0ae092d2018-09-20 16:43:19 +0200138 assert_int_equal(LY_SUCCESS, lyht_remove(ht, &i, i));
139 }
140 assert_int_equal(8, ht->size);
141
142 /* remove the rest */
Radek Krejcib4ac5a92020-11-23 17:54:33 +0100143 for ( ; i < 8; ++i) {
Radek Krejci0ae092d2018-09-20 16:43:19 +0200144 assert_int_equal(LY_SUCCESS, lyht_remove(ht, &i, i));
145 }
146
147 for (i = 0; i < 8; ++i) {
Michal Vaskoda859032020-07-14 12:20:14 +0200148 assert_int_equal(LY_ENOTFOUND, lyht_find(ht, &i, i, NULL));
Radek Krejci0ae092d2018-09-20 16:43:19 +0200149 }
150
151 /* cleanup */
Michal Vasko77b7f90a2023-01-31 15:42:41 +0100152 lyht_free(ht, NULL);
Radek Krejci0ae092d2018-09-20 16:43:19 +0200153}
154
Radek Krejci0ae092d2018-09-20 16:43:19 +0200155static void
Radek Iša56ca9e42020-09-08 18:42:00 +0200156test_ht_collisions(void **UNUSED(state))
Radek Krejci0ae092d2018-09-20 16:43:19 +0200157{
Radek Krejci0ae092d2018-09-20 16:43:19 +0200158#define GET_REC_INT(rec) (*((uint32_t *)&(rec)->val))
159
160 uint32_t i;
Michal Vasko8efac242023-03-30 08:24:56 +0200161 struct ly_ht_rec *rec;
162 struct ly_ht *ht;
Olivier Matz75c00192023-09-21 14:35:12 +0200163 uint32_t rec_idx;
164 int count;
Radek Krejci0ae092d2018-09-20 16:43:19 +0200165
166 assert_non_null(ht = lyht_new(8, sizeof(int), ht_equal_clb, NULL, 1));
167
168 for (i = 2; i < 6; ++i) {
169 assert_int_equal(lyht_insert(ht, &i, 2, NULL), 0);
170 }
171
172 /* check all records */
Olivier Matz75c00192023-09-21 14:35:12 +0200173 for (i = 0; i < 8; ++i) {
174 if (i == 2)
Olivier Matz6a669c12023-09-28 12:07:12 +0200175 assert_int_not_equal(UINT32_MAX, ht->hlists[i].first);
Olivier Matz75c00192023-09-21 14:35:12 +0200176 else
Olivier Matz6a669c12023-09-28 12:07:12 +0200177 assert_int_equal(UINT32_MAX, ht->hlists[i].first);
Radek Krejci0ae092d2018-09-20 16:43:19 +0200178 }
Olivier Matz75c00192023-09-21 14:35:12 +0200179 for (i = 0; i < 8; ++i) {
180 if (i >= 2 && i < 6)
181 assert_int_equal(LY_SUCCESS, lyht_find(ht, &i, 2, NULL));
182 else
183 assert_int_equal(LY_ENOTFOUND, lyht_find(ht, &i, 2, NULL));
Radek Krejci0ae092d2018-09-20 16:43:19 +0200184 }
Olivier Matz6a669c12023-09-28 12:07:12 +0200185 rec_idx = ht->hlists[2].first;
Olivier Matz75c00192023-09-21 14:35:12 +0200186 count = 0;
187 while (rec_idx != UINT32_MAX) {
188 rec = lyht_get_rec(ht->recs, ht->rec_size, rec_idx);
189 rec_idx = rec->next;
190 assert_int_equal(rec->hash, 2);
191 count++;
Radek Krejci0ae092d2018-09-20 16:43:19 +0200192 }
Olivier Matz75c00192023-09-21 14:35:12 +0200193 assert_int_equal(count, 4);
Radek Krejci0ae092d2018-09-20 16:43:19 +0200194
195 i = 4;
196 assert_int_equal(lyht_remove(ht, &i, 2), 0);
197
198 rec = lyht_get_rec(ht->recs, ht->rec_size, i);
Radek Krejci0ae092d2018-09-20 16:43:19 +0200199
200 i = 2;
201 assert_int_equal(lyht_remove(ht, &i, 2), 0);
202
203 /* check all records */
Olivier Matz75c00192023-09-21 14:35:12 +0200204 for (i = 0; i < 8; ++i) {
205 if (i == 2)
Olivier Matz6a669c12023-09-28 12:07:12 +0200206 assert_int_not_equal(UINT32_MAX, ht->hlists[i].first);
Olivier Matz75c00192023-09-21 14:35:12 +0200207 else
Olivier Matz6a669c12023-09-28 12:07:12 +0200208 assert_int_equal(UINT32_MAX, ht->hlists[i].first);
Radek Krejci0ae092d2018-09-20 16:43:19 +0200209 }
Olivier Matz75c00192023-09-21 14:35:12 +0200210 for (i = 0; i < 8; ++i) {
211 if (i == 3 || i == 5)
212 assert_int_equal(LY_SUCCESS, lyht_find(ht, &i, 2, NULL));
213 else
214 assert_int_equal(LY_ENOTFOUND, lyht_find(ht, &i, 2, NULL));
Radek Krejci0ae092d2018-09-20 16:43:19 +0200215 }
Olivier Matz6a669c12023-09-28 12:07:12 +0200216 rec_idx = ht->hlists[2].first;
Olivier Matz75c00192023-09-21 14:35:12 +0200217 count = 0;
218 while (rec_idx != UINT32_MAX) {
219 rec = lyht_get_rec(ht->recs, ht->rec_size, rec_idx);
220 rec_idx = rec->next;
221 assert_int_equal(rec->hash, 2);
222 count++;
Radek Krejci0ae092d2018-09-20 16:43:19 +0200223 }
Olivier Matz75c00192023-09-21 14:35:12 +0200224 assert_int_equal(count, 2);
Radek Krejci0ae092d2018-09-20 16:43:19 +0200225
Olivier Matz75c00192023-09-21 14:35:12 +0200226 for (i = 0; i < 8; ++i) {
227 if (i == 3 || i == 5)
228 assert_int_equal(lyht_find(ht, &i, 2, NULL), LY_SUCCESS);
229 else
230 assert_int_equal(lyht_find(ht, &i, 2, NULL), LY_ENOTFOUND);
Radek Krejci0ae092d2018-09-20 16:43:19 +0200231 }
232
233 i = 3;
234 assert_int_equal(lyht_remove(ht, &i, 2), 0);
235 i = 5;
236 assert_int_equal(lyht_remove(ht, &i, 2), 0);
237
238 /* check all records */
Olivier Matz75c00192023-09-21 14:35:12 +0200239 for (i = 0; i < 8; ++i) {
Olivier Matz6a669c12023-09-28 12:07:12 +0200240 assert_int_equal(UINT32_MAX, ht->hlists[i].first);
Radek Krejci0ae092d2018-09-20 16:43:19 +0200241 }
242
Michal Vasko77b7f90a2023-01-31 15:42:41 +0100243 lyht_free(ht, NULL);
Radek Krejci0ae092d2018-09-20 16:43:19 +0200244}
245
Radek Krejcib4ac5a92020-11-23 17:54:33 +0100246int
247main(void)
Radek Krejciaaf6d402018-09-20 15:14:47 +0200248{
249 const struct CMUnitTest tests[] = {
Radek Iša56ca9e42020-09-08 18:42:00 +0200250 UTEST(test_invalid_arguments),
251 UTEST(test_dict_hit),
252 UTEST(test_ht_basic),
253 UTEST(test_ht_resize),
254 UTEST(test_ht_collisions),
Radek Krejciaaf6d402018-09-20 15:14:47 +0200255 };
256
257 return cmocka_run_group_tests(tests, NULL, NULL);
258}