blob: 2ea34faab6289fbb406c3315dcfcd7b081610aa9 [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));
Michal Vasko7a266772024-01-23 11:02:38 +010026 CHECK_LOG_LASTMSG("Invalid argument ctx (lydict_insert()).");
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));
Michal Vasko7a266772024-01-23 11:02:38 +010029 CHECK_LOG_LASTMSG("Invalid argument ctx (lydict_insert_zc()).");
Radek Iša56ca9e42020-09-08 18:42:00 +020030 assert_int_equal(LY_EINVAL, lydict_insert_zc(UTEST_LYCTX, NULL, NULL));
Michal Vasko7a266772024-01-23 11:02:38 +010031 CHECK_LOG_CTX("Invalid argument str_p (lydict_insert_zc()).", NULL, 0);
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 Vasko7a266772024-01-23 11:02:38 +010058 CHECK_LOG_LASTMSG("String \"test1\" not freed from the dictionary, refcount 1.");
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
Michal Vasko7a266772024-01-23 11:02:38 +010081test_ht_basic(void **UNUSED(state))
Radek Krejci0ae092d2018-09-20 16:43:19 +020082{
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));
Michal Vasko7a266772024-01-23 11:02:38 +010095 CHECK_LOG_LASTMSG("Invalid argument hash (lyht_remove_with_resize_cb()).");
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
Michal Vasko7a266772024-01-23 11:02:38 +0100101test_ht_resize(void **UNUSED(state))
Radek Krejci0ae092d2018-09-20 16:43:19 +0200102{
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) {
Michal Vasko4a4c7ed2020-07-17 09:30:12 +0200131 assert_int_equal(LY_ENOTFOUND, lyht_remove(ht, &i, i));
Michal Vasko7a266772024-01-23 11:02:38 +0100132 CHECK_LOG_LASTMSG("Invalid argument hash (lyht_remove_with_resize_cb()).");
Radek Krejci0ae092d2018-09-20 16:43:19 +0200133 }
134 /* removing present data, resize should happened
135 * when we are below 25% of the table filled, so with 3 records left */
Radek Krejcib4ac5a92020-11-23 17:54:33 +0100136 for ( ; i < 5; ++i) {
Radek Krejci0ae092d2018-09-20 16:43:19 +0200137 assert_int_equal(LY_SUCCESS, lyht_remove(ht, &i, i));
138 }
139 assert_int_equal(8, ht->size);
140
141 /* remove the rest */
Radek Krejcib4ac5a92020-11-23 17:54:33 +0100142 for ( ; i < 8; ++i) {
Radek Krejci0ae092d2018-09-20 16:43:19 +0200143 assert_int_equal(LY_SUCCESS, lyht_remove(ht, &i, i));
144 }
145
146 for (i = 0; i < 8; ++i) {
Michal Vaskoda859032020-07-14 12:20:14 +0200147 assert_int_equal(LY_ENOTFOUND, lyht_find(ht, &i, i, NULL));
Radek Krejci0ae092d2018-09-20 16:43:19 +0200148 }
149
150 /* cleanup */
Michal Vasko77b7f90a2023-01-31 15:42:41 +0100151 lyht_free(ht, NULL);
Radek Krejci0ae092d2018-09-20 16:43:19 +0200152}
153
Radek Krejci0ae092d2018-09-20 16:43:19 +0200154static void
Radek Iša56ca9e42020-09-08 18:42:00 +0200155test_ht_collisions(void **UNUSED(state))
Radek Krejci0ae092d2018-09-20 16:43:19 +0200156{
Radek Krejci0ae092d2018-09-20 16:43:19 +0200157#define GET_REC_INT(rec) (*((uint32_t *)&(rec)->val))
158
159 uint32_t i;
Michal Vasko8efac242023-03-30 08:24:56 +0200160 struct ly_ht_rec *rec;
161 struct ly_ht *ht;
Olivier Matz75c00192023-09-21 14:35:12 +0200162 uint32_t rec_idx;
163 int count;
Radek Krejci0ae092d2018-09-20 16:43:19 +0200164
165 assert_non_null(ht = lyht_new(8, sizeof(int), ht_equal_clb, NULL, 1));
166
167 for (i = 2; i < 6; ++i) {
168 assert_int_equal(lyht_insert(ht, &i, 2, NULL), 0);
169 }
170
171 /* check all records */
Olivier Matz75c00192023-09-21 14:35:12 +0200172 for (i = 0; i < 8; ++i) {
Olivier Matzc0feb682023-09-21 08:53:59 +0200173 if (i == 2) {
Olivier Matz6a669c12023-09-28 12:07:12 +0200174 assert_int_not_equal(UINT32_MAX, ht->hlists[i].first);
Olivier Matzc0feb682023-09-21 08:53:59 +0200175 } else {
Olivier Matz6a669c12023-09-28 12:07:12 +0200176 assert_int_equal(UINT32_MAX, ht->hlists[i].first);
Olivier Matzc0feb682023-09-21 08:53:59 +0200177 }
Radek Krejci0ae092d2018-09-20 16:43:19 +0200178 }
Olivier Matz75c00192023-09-21 14:35:12 +0200179 for (i = 0; i < 8; ++i) {
Olivier Matzc0feb682023-09-21 08:53:59 +0200180 if ((i >= 2) && (i < 6)) {
Olivier Matz75c00192023-09-21 14:35:12 +0200181 assert_int_equal(LY_SUCCESS, lyht_find(ht, &i, 2, NULL));
Olivier Matzc0feb682023-09-21 08:53:59 +0200182 } else {
Olivier Matz75c00192023-09-21 14:35:12 +0200183 assert_int_equal(LY_ENOTFOUND, lyht_find(ht, &i, 2, NULL));
Olivier Matzc0feb682023-09-21 08:53:59 +0200184 }
Radek Krejci0ae092d2018-09-20 16:43:19 +0200185 }
Olivier Matz6a669c12023-09-28 12:07:12 +0200186 rec_idx = ht->hlists[2].first;
Olivier Matz75c00192023-09-21 14:35:12 +0200187 count = 0;
188 while (rec_idx != UINT32_MAX) {
189 rec = lyht_get_rec(ht->recs, ht->rec_size, rec_idx);
190 rec_idx = rec->next;
191 assert_int_equal(rec->hash, 2);
192 count++;
Radek Krejci0ae092d2018-09-20 16:43:19 +0200193 }
Olivier Matz75c00192023-09-21 14:35:12 +0200194 assert_int_equal(count, 4);
Radek Krejci0ae092d2018-09-20 16:43:19 +0200195
196 i = 4;
197 assert_int_equal(lyht_remove(ht, &i, 2), 0);
198
199 rec = lyht_get_rec(ht->recs, ht->rec_size, i);
Radek Krejci0ae092d2018-09-20 16:43:19 +0200200
201 i = 2;
202 assert_int_equal(lyht_remove(ht, &i, 2), 0);
203
204 /* check all records */
Olivier Matz75c00192023-09-21 14:35:12 +0200205 for (i = 0; i < 8; ++i) {
Olivier Matzc0feb682023-09-21 08:53:59 +0200206 if (i == 2) {
Olivier Matz6a669c12023-09-28 12:07:12 +0200207 assert_int_not_equal(UINT32_MAX, ht->hlists[i].first);
Olivier Matzc0feb682023-09-21 08:53:59 +0200208 } else {
Olivier Matz6a669c12023-09-28 12:07:12 +0200209 assert_int_equal(UINT32_MAX, ht->hlists[i].first);
Olivier Matzc0feb682023-09-21 08:53:59 +0200210 }
Radek Krejci0ae092d2018-09-20 16:43:19 +0200211 }
Olivier Matz75c00192023-09-21 14:35:12 +0200212 for (i = 0; i < 8; ++i) {
Olivier Matzc0feb682023-09-21 08:53:59 +0200213 if ((i == 3) || (i == 5)) {
Olivier Matz75c00192023-09-21 14:35:12 +0200214 assert_int_equal(LY_SUCCESS, lyht_find(ht, &i, 2, NULL));
Olivier Matzc0feb682023-09-21 08:53:59 +0200215 } else {
Olivier Matz75c00192023-09-21 14:35:12 +0200216 assert_int_equal(LY_ENOTFOUND, lyht_find(ht, &i, 2, NULL));
Olivier Matzc0feb682023-09-21 08:53:59 +0200217 }
Radek Krejci0ae092d2018-09-20 16:43:19 +0200218 }
Olivier Matz6a669c12023-09-28 12:07:12 +0200219 rec_idx = ht->hlists[2].first;
Olivier Matz75c00192023-09-21 14:35:12 +0200220 count = 0;
221 while (rec_idx != UINT32_MAX) {
222 rec = lyht_get_rec(ht->recs, ht->rec_size, rec_idx);
223 rec_idx = rec->next;
224 assert_int_equal(rec->hash, 2);
225 count++;
Radek Krejci0ae092d2018-09-20 16:43:19 +0200226 }
Olivier Matz75c00192023-09-21 14:35:12 +0200227 assert_int_equal(count, 2);
Radek Krejci0ae092d2018-09-20 16:43:19 +0200228
Olivier Matz75c00192023-09-21 14:35:12 +0200229 for (i = 0; i < 8; ++i) {
Olivier Matzc0feb682023-09-21 08:53:59 +0200230 if ((i == 3) || (i == 5)) {
Olivier Matz75c00192023-09-21 14:35:12 +0200231 assert_int_equal(lyht_find(ht, &i, 2, NULL), LY_SUCCESS);
Olivier Matzc0feb682023-09-21 08:53:59 +0200232 } else {
Olivier Matz75c00192023-09-21 14:35:12 +0200233 assert_int_equal(lyht_find(ht, &i, 2, NULL), LY_ENOTFOUND);
Olivier Matzc0feb682023-09-21 08:53:59 +0200234 }
Radek Krejci0ae092d2018-09-20 16:43:19 +0200235 }
236
237 i = 3;
238 assert_int_equal(lyht_remove(ht, &i, 2), 0);
239 i = 5;
240 assert_int_equal(lyht_remove(ht, &i, 2), 0);
241
242 /* check all records */
Olivier Matz75c00192023-09-21 14:35:12 +0200243 for (i = 0; i < 8; ++i) {
Olivier Matz6a669c12023-09-28 12:07:12 +0200244 assert_int_equal(UINT32_MAX, ht->hlists[i].first);
Radek Krejci0ae092d2018-09-20 16:43:19 +0200245 }
246
Michal Vasko77b7f90a2023-01-31 15:42:41 +0100247 lyht_free(ht, NULL);
Radek Krejci0ae092d2018-09-20 16:43:19 +0200248}
249
Radek Krejcib4ac5a92020-11-23 17:54:33 +0100250int
251main(void)
Radek Krejciaaf6d402018-09-20 15:14:47 +0200252{
253 const struct CMUnitTest tests[] = {
Radek Iša56ca9e42020-09-08 18:42:00 +0200254 UTEST(test_invalid_arguments),
255 UTEST(test_dict_hit),
256 UTEST(test_ht_basic),
257 UTEST(test_ht_resize),
258 UTEST(test_ht_collisions),
Radek Krejciaaf6d402018-09-20 15:14:47 +0200259 };
260
261 return cmocka_run_group_tests(tests, NULL, NULL);
262}