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