blob: cebea4fb8e727dbece8b0c4246df61c697060f76 [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 "hash_table.h"
Michal Vasko8f702ee2024-02-20 15:44:24 +010020#include "ly_common.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;
Michal Vasko7ebd6072024-02-20 15:50:13 +010058 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) {
Olivier Matzc0feb682023-09-21 08:53:59 +0200174 if (i == 2) {
Olivier Matz6a669c12023-09-28 12:07:12 +0200175 assert_int_not_equal(UINT32_MAX, ht->hlists[i].first);
Olivier Matzc0feb682023-09-21 08:53:59 +0200176 } else {
Olivier Matz6a669c12023-09-28 12:07:12 +0200177 assert_int_equal(UINT32_MAX, ht->hlists[i].first);
Olivier Matzc0feb682023-09-21 08:53:59 +0200178 }
Radek Krejci0ae092d2018-09-20 16:43:19 +0200179 }
Olivier Matz75c00192023-09-21 14:35:12 +0200180 for (i = 0; i < 8; ++i) {
Olivier Matzc0feb682023-09-21 08:53:59 +0200181 if ((i >= 2) && (i < 6)) {
Olivier Matz75c00192023-09-21 14:35:12 +0200182 assert_int_equal(LY_SUCCESS, lyht_find(ht, &i, 2, NULL));
Olivier Matzc0feb682023-09-21 08:53:59 +0200183 } else {
Olivier Matz75c00192023-09-21 14:35:12 +0200184 assert_int_equal(LY_ENOTFOUND, lyht_find(ht, &i, 2, NULL));
Olivier Matzc0feb682023-09-21 08:53:59 +0200185 }
Radek Krejci0ae092d2018-09-20 16:43:19 +0200186 }
Olivier Matz6a669c12023-09-28 12:07:12 +0200187 rec_idx = ht->hlists[2].first;
Olivier Matz75c00192023-09-21 14:35:12 +0200188 count = 0;
189 while (rec_idx != UINT32_MAX) {
190 rec = lyht_get_rec(ht->recs, ht->rec_size, rec_idx);
191 rec_idx = rec->next;
192 assert_int_equal(rec->hash, 2);
193 count++;
Radek Krejci0ae092d2018-09-20 16:43:19 +0200194 }
Olivier Matz75c00192023-09-21 14:35:12 +0200195 assert_int_equal(count, 4);
Radek Krejci0ae092d2018-09-20 16:43:19 +0200196
197 i = 4;
198 assert_int_equal(lyht_remove(ht, &i, 2), 0);
199
200 rec = lyht_get_rec(ht->recs, ht->rec_size, i);
Radek Krejci0ae092d2018-09-20 16:43:19 +0200201
202 i = 2;
203 assert_int_equal(lyht_remove(ht, &i, 2), 0);
204
205 /* check all records */
Olivier Matz75c00192023-09-21 14:35:12 +0200206 for (i = 0; i < 8; ++i) {
Olivier Matzc0feb682023-09-21 08:53:59 +0200207 if (i == 2) {
Olivier Matz6a669c12023-09-28 12:07:12 +0200208 assert_int_not_equal(UINT32_MAX, ht->hlists[i].first);
Olivier Matzc0feb682023-09-21 08:53:59 +0200209 } else {
Olivier Matz6a669c12023-09-28 12:07:12 +0200210 assert_int_equal(UINT32_MAX, ht->hlists[i].first);
Olivier Matzc0feb682023-09-21 08:53:59 +0200211 }
Radek Krejci0ae092d2018-09-20 16:43:19 +0200212 }
Olivier Matz75c00192023-09-21 14:35:12 +0200213 for (i = 0; i < 8; ++i) {
Olivier Matzc0feb682023-09-21 08:53:59 +0200214 if ((i == 3) || (i == 5)) {
Olivier Matz75c00192023-09-21 14:35:12 +0200215 assert_int_equal(LY_SUCCESS, lyht_find(ht, &i, 2, NULL));
Olivier Matzc0feb682023-09-21 08:53:59 +0200216 } else {
Olivier Matz75c00192023-09-21 14:35:12 +0200217 assert_int_equal(LY_ENOTFOUND, lyht_find(ht, &i, 2, NULL));
Olivier Matzc0feb682023-09-21 08:53:59 +0200218 }
Radek Krejci0ae092d2018-09-20 16:43:19 +0200219 }
Olivier Matz6a669c12023-09-28 12:07:12 +0200220 rec_idx = ht->hlists[2].first;
Olivier Matz75c00192023-09-21 14:35:12 +0200221 count = 0;
222 while (rec_idx != UINT32_MAX) {
223 rec = lyht_get_rec(ht->recs, ht->rec_size, rec_idx);
224 rec_idx = rec->next;
225 assert_int_equal(rec->hash, 2);
226 count++;
Radek Krejci0ae092d2018-09-20 16:43:19 +0200227 }
Olivier Matz75c00192023-09-21 14:35:12 +0200228 assert_int_equal(count, 2);
Radek Krejci0ae092d2018-09-20 16:43:19 +0200229
Olivier Matz75c00192023-09-21 14:35:12 +0200230 for (i = 0; i < 8; ++i) {
Olivier Matzc0feb682023-09-21 08:53:59 +0200231 if ((i == 3) || (i == 5)) {
Olivier Matz75c00192023-09-21 14:35:12 +0200232 assert_int_equal(lyht_find(ht, &i, 2, NULL), LY_SUCCESS);
Olivier Matzc0feb682023-09-21 08:53:59 +0200233 } else {
Olivier Matz75c00192023-09-21 14:35:12 +0200234 assert_int_equal(lyht_find(ht, &i, 2, NULL), LY_ENOTFOUND);
Olivier Matzc0feb682023-09-21 08:53:59 +0200235 }
Radek Krejci0ae092d2018-09-20 16:43:19 +0200236 }
237
238 i = 3;
239 assert_int_equal(lyht_remove(ht, &i, 2), 0);
240 i = 5;
241 assert_int_equal(lyht_remove(ht, &i, 2), 0);
242
243 /* check all records */
Olivier Matz75c00192023-09-21 14:35:12 +0200244 for (i = 0; i < 8; ++i) {
Olivier Matz6a669c12023-09-28 12:07:12 +0200245 assert_int_equal(UINT32_MAX, ht->hlists[i].first);
Radek Krejci0ae092d2018-09-20 16:43:19 +0200246 }
247
Michal Vasko77b7f90a2023-01-31 15:42:41 +0100248 lyht_free(ht, NULL);
Radek Krejci0ae092d2018-09-20 16:43:19 +0200249}
250
Radek Krejcib4ac5a92020-11-23 17:54:33 +0100251int
252main(void)
Radek Krejciaaf6d402018-09-20 15:14:47 +0200253{
254 const struct CMUnitTest tests[] = {
Radek Iša56ca9e42020-09-08 18:42:00 +0200255 UTEST(test_invalid_arguments),
256 UTEST(test_dict_hit),
257 UTEST(test_ht_basic),
258 UTEST(test_ht_resize),
259 UTEST(test_ht_collisions),
Radek Krejciaaf6d402018-09-20 15:14:47 +0200260 };
261
262 return cmocka_run_group_tests(tests, NULL, NULL);
263}