xref: /openbsd-src/regress/lib/libcrypto/lhash/lhash_test.c (revision 080cd0facda91e23daed705d6597785ebeb20dbd)
1 /*	$OpenBSD: lhash_test.c,v 1.2 2024/05/08 15:13:23 jsing Exp $	*/
2 /*
3  * Copyright (c) 2024 Joel Sing <jsing@openbsd.org>
4  *
5  * Permission to use, copy, modify, and distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16  */
17 
18 #include <stdint.h>
19 #include <stdio.h>
20 #include <stdlib.h>
21 
22 #include <openssl/lhash.h>
23 
24 /*
25  * Need to add test coverage for:
26  *  - custom hash function
27  *  - custom comparison function
28  */
29 
30 static void
test_doall_count(void * arg1,void * arg2)31 test_doall_count(void *arg1, void *arg2)
32 {
33 	int *count = arg2;
34 
35 	(*count)++;
36 }
37 
38 static int
test_lhash(void)39 test_lhash(void)
40 {
41 	const char *a = "a", *b = "b", *c = "c", *d = "d";
42 	const char *a2 = "a", *b2 = "b";
43 	_LHASH *lh;
44 	int count;
45 	int failed = 1;
46 
47 	if ((lh = lh_new(NULL, NULL)) == NULL)
48 		goto failure;
49 
50 	/*
51 	 * Another amazing API... both a successful insert and a failure will
52 	 * return NULL. The only way you can tell the difference is to follow
53 	 * with a call to lh_error().
54 	 */
55 	if (lh_retrieve(lh, "a") != NULL || lh_error(lh) != 0) {
56 		fprintf(stderr, "FAIL: retrieved a before insert\n");
57 		goto failure;
58 	}
59 	if (lh_insert(lh, (void *)a) != NULL || lh_error(lh) != 0) {
60 		fprintf(stderr, "FAIL: insert a\n");
61 		goto failure;
62 	}
63 	if (lh_retrieve(lh, "a") != a) {
64 		fprintf(stderr, "FAIL: failed to retrieve a\n");
65 		goto failure;
66 	}
67 
68 	if (lh_retrieve(lh, "b") != NULL || lh_error(lh) != 0) {
69 		fprintf(stderr, "FAIL: retrieved b before insert\n");
70 		goto failure;
71 	}
72 	if (lh_insert(lh, (void *)b) != NULL || lh_error(lh) != 0) {
73 		fprintf(stderr, "FAIL: insert b\n");
74 		goto failure;
75 	}
76 	if (lh_retrieve(lh, "b") != b) {
77 		fprintf(stderr, "FAIL: failed to retrieve b\n");
78 		goto failure;
79 	}
80 
81 	if (lh_retrieve(lh, "c") != NULL || lh_error(lh) != 0) {
82 		fprintf(stderr, "FAIL: retrieved c before insert\n");
83 		goto failure;
84 	}
85 	if (lh_insert(lh, (void *)c) != NULL || lh_error(lh) != 0) {
86 		fprintf(stderr, "FAIL: insert c\n");
87 		goto failure;
88 	}
89 	if (lh_retrieve(lh, "c") != c) {
90 		fprintf(stderr, "FAIL: failed to retrieve c\n");
91 		goto failure;
92 	}
93 
94 	if (lh_retrieve(lh, "d") != NULL || lh_error(lh) != 0) {
95 		fprintf(stderr, "FAIL: retrieved d before insert\n");
96 		goto failure;
97 	}
98 	if (lh_insert(lh, (void *)d) != NULL || lh_error(lh) != 0) {
99 		fprintf(stderr, "FAIL: insert d\n");
100 		goto failure;
101 	}
102 	if (lh_retrieve(lh, "d") != d) {
103 		fprintf(stderr, "FAIL: failed to retrieve d\n");
104 		goto failure;
105 	}
106 
107 	if (lh_num_items(lh) != 4) {
108 		fprintf(stderr, "FAIL: lh_num_items() = %ld, want 4\n",
109 		    lh_num_items(lh));
110 		goto failure;
111 	}
112 
113 	/* Insert should replace. */
114 	if (lh_insert(lh, (void *)a2) != a || lh_error(lh) != 0) {
115 		fprintf(stderr, "FAIL: replace a\n");
116 		goto failure;
117 	}
118 	if (lh_retrieve(lh, "a") != a2) {
119 		fprintf(stderr, "FAIL: failed to retrieve a2\n");
120 		goto failure;
121 	}
122 	if (lh_insert(lh, (void *)b2) != b || lh_error(lh) != 0) {
123 		fprintf(stderr, "FAIL: replace b\n");
124 		goto failure;
125 	}
126 	if (lh_retrieve(lh, "b") != b2) {
127 		fprintf(stderr, "FAIL: failed to retrieve b2\n");
128 		goto failure;
129 	}
130 
131 	if (lh_num_items(lh) != 4) {
132 		fprintf(stderr, "FAIL: lh_num_items() = %ld, want 4\n",
133 		    lh_num_items(lh));
134 		goto failure;
135 	}
136 
137 	/* Do all. */
138 	count = 0;
139 	lh_doall_arg(lh, test_doall_count, &count);
140 	if (count != 4) {
141 		fprintf(stderr, "FAIL: lh_doall_arg failed (count = %d)\n",
142 		    count);
143 		goto failure;
144 	}
145 
146 	/* Delete. */
147 	if (lh_delete(lh, "z") != NULL || lh_error(lh) != 0) {
148 		fprintf(stderr, "FAIL: delete succeeded for z\n");
149 		goto failure;
150 	}
151 	if (lh_delete(lh, "a") != a2 || lh_error(lh) != 0) {
152 		fprintf(stderr, "FAIL: delete failed for a\n");
153 		goto failure;
154 	}
155 	if (lh_retrieve(lh, "a") != NULL || lh_error(lh) != 0) {
156 		fprintf(stderr, "FAIL: retrieved a after deletion\n");
157 		goto failure;
158 	}
159 	if (lh_delete(lh, "b") != b2 || lh_error(lh) != 0) {
160 		fprintf(stderr, "FAIL: delete failed for b\n");
161 		goto failure;
162 	}
163 	if (lh_retrieve(lh, "b") != NULL || lh_error(lh) != 0) {
164 		fprintf(stderr, "FAIL: retrieved b after deletion\n");
165 		goto failure;
166 	}
167 	if (lh_delete(lh, "c") != c || lh_error(lh) != 0) {
168 		fprintf(stderr, "FAIL: delete failed for c\n");
169 		goto failure;
170 	}
171 	if (lh_retrieve(lh, "c") != NULL || lh_error(lh) != 0) {
172 		fprintf(stderr, "FAIL: retrieved c after deletion\n");
173 		goto failure;
174 	}
175 	if (lh_delete(lh, "d") != d || lh_error(lh) != 0) {
176 		fprintf(stderr, "FAIL: delete failed for d\n");
177 		goto failure;
178 	}
179 	if (lh_retrieve(lh, "d") != NULL || lh_error(lh) != 0) {
180 		fprintf(stderr, "FAIL: retrieved d after deletion\n");
181 		goto failure;
182 	}
183 
184 	if (lh_num_items(lh) != 0) {
185 		fprintf(stderr, "FAIL: lh_num_items() = %ld, want 0\n",
186 		    lh_num_items(lh));
187 		goto failure;
188 	}
189 
190 	failed = 0;
191 
192  failure:
193 	lh_free(lh);
194 
195 	return failed;
196 }
197 
198 static void
test_doall_fn(void * arg1)199 test_doall_fn(void *arg1)
200 {
201 }
202 
203 static int
test_lhash_doall(void)204 test_lhash_doall(void)
205 {
206 	_LHASH *lh;
207 	int i;
208 	int failed = 1;
209 
210 	if ((lh = lh_new(NULL, NULL)) == NULL)
211 		goto failure;
212 
213 	/* Call doall multiple times while linked hash is empty. */
214 	for (i = 0; i < 100; i++)
215 		lh_doall(lh, test_doall_fn);
216 
217 	failed = 0;
218 
219  failure:
220 	lh_free(lh);
221 
222 	return failed;
223 }
224 
225 static void
test_doall_delete_some(void * arg1,void * arg2)226 test_doall_delete_some(void *arg1, void *arg2)
227 {
228 	void *data;
229 
230 	if (arc4random_uniform(32) != 0)
231 		return;
232 
233 	data = lh_delete(arg2, arg1);
234 	free(data);
235 }
236 
237 static void
test_doall_delete_all(void * arg1,void * arg2)238 test_doall_delete_all(void *arg1, void *arg2)
239 {
240 	void *data;
241 
242 	data = lh_delete(arg2, arg1);
243 	free(data);
244 }
245 
246 static int
test_lhash_load(void)247 test_lhash_load(void)
248 {
249 	uint8_t c3 = 1, c2 = 1, c1 = 1, c0 = 1;
250 	_LHASH *lh;
251 	char *data = NULL;
252 	int i, j;
253 	int failed = 1;
254 
255 	if ((lh = lh_new(NULL, NULL)) == NULL)
256 		goto failure;
257 
258 	for (i = 0; i < 1024; i++) {
259 		for (j = 0; j < 1024; j++) {
260 			if ((data = calloc(1, 128)) == NULL)
261 				goto failure;
262 
263 			data[0] = c0;
264 			data[1] = c1;
265 			data[2] = c2;
266 			data[3] = c3;
267 
268 			if (++c0 == 0) {
269 				c0++;
270 				c1++;
271 			}
272 			if (c1 == 0) {
273 				c1++;
274 				c2++;
275 			}
276 			if (c2 == 0) {
277 				c2++;
278 				c3++;
279 			}
280 
281 			if (lh_insert(lh, data) != NULL || lh_error(lh) != 0) {
282 				fprintf(stderr, "FAIL: lh_insert() failed\n");
283 				goto failure;
284 			}
285 			data = NULL;
286 		}
287 		lh_doall_arg(lh, test_doall_delete_some, lh);
288 	}
289 
290 	/* We should have ~31,713 entries. */
291 	if (lh_num_items(lh) < 31000 || lh_num_items(lh) > 33000) {
292 		fprintf(stderr, "FAIL: unexpected number of entries (%ld)\n",
293 		    lh_num_items(lh));
294 		goto failure;
295 	}
296 
297 	failed = 0;
298 
299  failure:
300 	if (lh != NULL)
301 		lh_doall_arg(lh, test_doall_delete_all, lh);
302 
303 	lh_free(lh);
304 	free(data);
305 
306 	return failed;
307 }
308 
309 int
main(int argc,char ** argv)310 main(int argc, char **argv)
311 {
312 	int failed = 0;
313 
314 	failed |= test_lhash();
315 	failed |= test_lhash_doall();
316 	failed |= test_lhash_load();
317 
318 	return failed;
319 }
320