xref: /freebsd/contrib/netbsd-tests/lib/libc/stdlib/t_hsearch.c (revision ff0ba87247820afbdfdc1b307c803f7923d0e4d3)
1 /* $NetBSD: t_hsearch.c,v 1.4 2014/07/20 20:17:21 christos Exp $ */
2 
3 /*-
4  * Copyright (c) 2008 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
17  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
18  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
20  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26  * POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 /*
30  * Copyright (c) 2001 Christopher G. Demetriou
31  * All rights reserved.
32  *
33  * Redistribution and use in source and binary forms, with or without
34  * modification, are permitted provided that the following conditions
35  * are met:
36  * 1. Redistributions of source code must retain the above copyright
37  *    notice, this list of conditions and the following disclaimer.
38  * 2. Redistributions in binary form must reproduce the above copyright
39  *    notice, this list of conditions and the following disclaimer in the
40  *    documentation and/or other materials provided with the distribution.
41  * 3. All advertising materials mentioning features or use of this software
42  *    must display the following acknowledgement:
43  *          This product includes software developed for the
44  *          NetBSD Project.  See http://www.NetBSD.org/ for
45  *          information about NetBSD.
46  * 4. The name of the author may not be used to endorse or promote products
47  *    derived from this software without specific prior written permission.
48  *
49  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
50  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
51  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
52  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
53  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
54  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
55  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
56  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
57  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
58  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
59  *
60  * <<Id: LICENSE,v 1.2 2000/06/14 15:57:33 cgd Exp>>
61  */
62 
63 #include <sys/cdefs.h>
64 __COPYRIGHT("@(#) Copyright (c) 2008\
65  The NetBSD Foundation, inc. All rights reserved.");
66 __RCSID("$NetBSD: t_hsearch.c,v 1.4 2014/07/20 20:17:21 christos Exp $");
67 
68 #include <errno.h>
69 #include <search.h>
70 #include <string.h>
71 #include <stdio.h>
72 #include <stdlib.h>
73 
74 #include <atf-c.h>
75 
76 #define REQUIRE_ERRNO(x) ATF_REQUIRE_MSG(x, "%s", strerror(errno))
77 
78 #ifdef __NetBSD__
79 ATF_TC(hsearch_basic);
80 ATF_TC_HEAD(hsearch_basic, tc)
81 {
82 
83 	atf_tc_set_md_var(tc, "descr", "Checks basic insertions and searching");
84 }
85 
86 ATF_TC_BODY(hsearch_basic, tc)
87 {
88 	ENTRY e, *ep;
89 	char ch[2];
90 	int i;
91 
92 	REQUIRE_ERRNO(hcreate(16) != 0);
93 
94 	/* ch[1] should be constant from here on down. */
95 	ch[1] = '\0';
96 
97 	/* Basic insertions.  Check enough that there'll be collisions. */
98 	for (i = 0; i < 26; i++) {
99 		ch[0] = 'a' + i;
100 		e.key = strdup(ch);	/* ptr to provided key is kept! */
101 		ATF_REQUIRE(e.key != NULL);
102 		e.data = (void *)(intptr_t)i;
103 
104 		ep = hsearch(e, ENTER);
105 
106 		ATF_REQUIRE(ep != NULL);
107 		ATF_REQUIRE_STREQ(ep->key, ch);
108 		ATF_REQUIRE_EQ((intptr_t)ep->data, i);
109 	}
110 
111 	/* e.key should be constant from here on down. */
112 	e.key = ch;
113 
114 	/* Basic lookups. */
115 	for (i = 0; i < 26; i++) {
116 		ch[0] = 'a' + i;
117 
118 		ep = hsearch(e, FIND);
119 
120 		ATF_REQUIRE(ep != NULL);
121 		ATF_REQUIRE_STREQ(ep->key, ch);
122 		ATF_REQUIRE_EQ((intptr_t)ep->data, i);
123 	}
124 
125 	hdestroy1(free, NULL);
126 }
127 #endif
128 
129 ATF_TC(hsearch_duplicate);
130 ATF_TC_HEAD(hsearch_duplicate, tc)
131 {
132 
133 	atf_tc_set_md_var(tc, "descr", "Checks that inserting duplicate "
134 	    "doesn't overwrite existing data");
135 }
136 
137 ATF_TC_BODY(hsearch_duplicate, tc)
138 {
139 	ENTRY e, *ep;
140 
141 	REQUIRE_ERRNO(hcreate(16));
142 
143 	e.key = __UNCONST("a");
144 	e.data = (void *)(intptr_t) 0;
145 
146 	ep = hsearch(e, ENTER);
147 
148 	ATF_REQUIRE(ep != NULL);
149 	ATF_REQUIRE_STREQ(ep->key, "a");
150 	ATF_REQUIRE_EQ((intptr_t)ep->data, 0);
151 
152 	e.data = (void *)(intptr_t)12345;
153 
154 	ep = hsearch(e, ENTER);
155 	ep = hsearch(e, FIND);
156 
157 	ATF_REQUIRE(ep != NULL);
158 	ATF_REQUIRE_STREQ(ep->key, "a");
159 	ATF_REQUIRE_EQ((intptr_t)ep->data, 0);
160 
161 	hdestroy();
162 }
163 
164 ATF_TC(hsearch_nonexistent);
165 ATF_TC_HEAD(hsearch_nonexistent, tc)
166 {
167 
168 	atf_tc_set_md_var(tc, "descr",
169 	    "Checks searching for non-existent entry");
170 }
171 
172 ATF_TC_BODY(hsearch_nonexistent, tc)
173 {
174 	ENTRY e, *ep;
175 
176 	REQUIRE_ERRNO(hcreate(16));
177 
178 	e.key = __UNCONST("A");
179 	ep = hsearch(e, FIND);
180 	ATF_REQUIRE_EQ(ep, NULL);
181 
182 	hdestroy();
183 }
184 
185 ATF_TC(hsearch_two);
186 ATF_TC_HEAD(hsearch_two, tc)
187 {
188 
189 	atf_tc_set_md_var(tc, "descr",
190 	    "Checks that searching doesn't overwrite previous search results");
191 }
192 
193 ATF_TC_BODY(hsearch_two, tc)
194 {
195 	ENTRY e, *ep, *ep2;
196 
197 	REQUIRE_ERRNO(hcreate(16));
198 
199 	e.key = __UNCONST("a");
200 	e.data = (void*)(intptr_t)0;
201 
202 	ep = hsearch(e, ENTER);
203 
204 	ATF_REQUIRE(ep != NULL);
205 	ATF_REQUIRE_STREQ(ep->key, "a");
206 	ATF_REQUIRE_EQ((intptr_t)ep->data, 0);
207 
208 	e.key = __UNCONST("b");
209 	e.data = (void*)(intptr_t)1;
210 
211 	ep = hsearch(e, ENTER);
212 
213 	ATF_REQUIRE(ep != NULL);
214 	ATF_REQUIRE_STREQ(ep->key, "b");
215 	ATF_REQUIRE_EQ((intptr_t)ep->data, 1);
216 
217 	e.key = __UNCONST("a");
218 	ep = hsearch(e, FIND);
219 
220 	e.key = __UNCONST("b");
221 	ep2 = hsearch(e, FIND);
222 
223 	ATF_REQUIRE(ep != NULL);
224 	ATF_REQUIRE_STREQ(ep->key, "a");
225 	ATF_REQUIRE_EQ((intptr_t)ep->data, 0);
226 
227 	ATF_REQUIRE(ep2 != NULL);
228 	ATF_REQUIRE_STREQ(ep2->key, "b");
229 	ATF_REQUIRE_EQ((intptr_t)ep2->data, 1);
230 
231 	hdestroy();
232 }
233 
234 #ifdef __NetBSD__
235 ATF_TC(hsearch_r_basic);
236 ATF_TC_HEAD(hsearch_r_basic, tc)
237 {
238 
239 	atf_tc_set_md_var(tc, "descr", "Checks basic insertions and searching");
240 }
241 
242 ATF_TC_BODY(hsearch_r_basic, tc)
243 {
244 	ENTRY e, *ep;
245 	char ch[2];
246 	int i;
247 	struct hsearch_data t;
248 
249 	REQUIRE_ERRNO(hcreate_r(16, &t) != 0);
250 
251 	/* ch[1] should be constant from here on down. */
252 	ch[1] = '\0';
253 
254 	/* Basic insertions.  Check enough that there'll be collisions. */
255 	for (i = 0; i < 26; i++) {
256 		ch[0] = 'a' + i;
257 		e.key = strdup(ch);	/* ptr to provided key is kept! */
258 		ATF_REQUIRE(e.key != NULL);
259 		e.data = (void *)(intptr_t)i;
260 
261 		ATF_REQUIRE(hsearch_r(e, ENTER, &ep, &t) == 1);
262 		ATF_REQUIRE(ep != NULL);
263 		ATF_REQUIRE_STREQ(ep->key, ch);
264 		ATF_REQUIRE_EQ((intptr_t)ep->data, i);
265 	}
266 
267 	/* e.key should be constant from here on down. */
268 	e.key = ch;
269 
270 	/* Basic lookups. */
271 	for (i = 0; i < 26; i++) {
272 		ch[0] = 'a' + i;
273 
274 		ATF_REQUIRE(hsearch_r(e, FIND, &ep, &t) == 1);
275 		ATF_REQUIRE(ep != NULL);
276 		ATF_REQUIRE_STREQ(ep->key, ch);
277 		ATF_REQUIRE_EQ((intptr_t)ep->data, i);
278 	}
279 
280 	hdestroy1_r(&t, free, NULL);
281 }
282 #endif
283 
284 ATF_TC(hsearch_r_duplicate);
285 ATF_TC_HEAD(hsearch_r_duplicate, tc)
286 {
287 
288 	atf_tc_set_md_var(tc, "descr", "Checks that inserting duplicate "
289 	    "doesn't overwrite existing data");
290 }
291 
292 ATF_TC_BODY(hsearch_r_duplicate, tc)
293 {
294 	ENTRY e, *ep;
295 	struct hsearch_data t;
296 
297 	REQUIRE_ERRNO(hcreate_r(16, &t));
298 
299 	e.key = __UNCONST("a");
300 	e.data = (void *)(intptr_t) 0;
301 
302 	ATF_REQUIRE(hsearch_r(e, ENTER, &ep, &t) == 1);
303 	ATF_REQUIRE(ep != NULL);
304 	ATF_REQUIRE_STREQ(ep->key, "a");
305 	ATF_REQUIRE_EQ((intptr_t)ep->data, 0);
306 
307 	e.data = (void *)(intptr_t)12345;
308 
309 	ATF_REQUIRE(hsearch_r(e, ENTER, &ep, &t) == 1);
310 	ATF_REQUIRE(hsearch_r(e, FIND, &ep, &t) == 1);
311 
312 	ATF_REQUIRE(ep != NULL);
313 	ATF_REQUIRE_STREQ(ep->key, "a");
314 	ATF_REQUIRE_EQ((intptr_t)ep->data, 0);
315 
316 	hdestroy_r(&t);
317 }
318 
319 ATF_TC(hsearch_r_nonexistent);
320 ATF_TC_HEAD(hsearch_r_nonexistent, tc)
321 {
322 
323 	atf_tc_set_md_var(tc, "descr",
324 	    "Checks searching for non-existent entry");
325 }
326 
327 ATF_TC_BODY(hsearch_r_nonexistent, tc)
328 {
329 	ENTRY e, *ep;
330 	struct hsearch_data t;
331 
332 	REQUIRE_ERRNO(hcreate_r(16, &t));
333 
334 	e.key = __UNCONST("A");
335 	ATF_REQUIRE(hsearch_r(e, FIND, &ep, &t) == 1);
336 	ATF_REQUIRE_EQ(ep, NULL);
337 
338 	hdestroy_r(&t);
339 }
340 
341 ATF_TC(hsearch_r_two);
342 ATF_TC_HEAD(hsearch_r_two, tc)
343 {
344 
345 	atf_tc_set_md_var(tc, "descr",
346 	    "Checks that searching doesn't overwrite previous search results");
347 }
348 
349 ATF_TC_BODY(hsearch_r_two, tc)
350 {
351 	ENTRY e, *ep, *ep2;
352 	struct hsearch_data t;
353 
354 	REQUIRE_ERRNO(hcreate_r(16, &t));
355 
356 	e.key = __UNCONST("a");
357 	e.data = (void*)(intptr_t)0;
358 
359 	ATF_REQUIRE(hsearch_r(e, ENTER, &ep, &t) == 1);
360 	ATF_REQUIRE(ep != NULL);
361 	ATF_REQUIRE_STREQ(ep->key, "a");
362 	ATF_REQUIRE_EQ((intptr_t)ep->data, 0);
363 
364 	e.key = __UNCONST("b");
365 	e.data = (void*)(intptr_t)1;
366 
367 	ATF_REQUIRE(hsearch_r(e, ENTER, &ep, &t) == 1);
368 	ATF_REQUIRE(ep != NULL);
369 	ATF_REQUIRE_STREQ(ep->key, "b");
370 	ATF_REQUIRE_EQ((intptr_t)ep->data, 1);
371 
372 	e.key = __UNCONST("a");
373 	ATF_REQUIRE(hsearch_r(e, FIND, &ep, &t) == 1);
374 
375 	e.key = __UNCONST("b");
376 	ATF_REQUIRE(hsearch_r(e, FIND, &ep2, &t) == 1);
377 
378 	ATF_REQUIRE(ep != NULL);
379 	ATF_REQUIRE_STREQ(ep->key, "a");
380 	ATF_REQUIRE_EQ((intptr_t)ep->data, 0);
381 
382 	ATF_REQUIRE(ep2 != NULL);
383 	ATF_REQUIRE_STREQ(ep2->key, "b");
384 	ATF_REQUIRE_EQ((intptr_t)ep2->data, 1);
385 
386 	hdestroy_r(&t);
387 }
388 
389 ATF_TP_ADD_TCS(tp)
390 {
391 
392 #ifdef __NetBSD__
393 	ATF_TP_ADD_TC(tp, hsearch_basic);
394 #endif
395 	ATF_TP_ADD_TC(tp, hsearch_duplicate);
396 	ATF_TP_ADD_TC(tp, hsearch_nonexistent);
397 	ATF_TP_ADD_TC(tp, hsearch_two);
398 
399 #ifdef __NetBSD__
400 	ATF_TP_ADD_TC(tp, hsearch_r_basic);
401 #endif
402 	ATF_TP_ADD_TC(tp, hsearch_r_duplicate);
403 	ATF_TP_ADD_TC(tp, hsearch_r_nonexistent);
404 	ATF_TP_ADD_TC(tp, hsearch_r_two);
405 
406 	return atf_no_error();
407 }
408