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 #if defined(__FreeBSD__) && 1100027 <= __FreeBSD_version
235 #ifdef __NetBSD__
236 ATF_TC(hsearch_r_basic);
237 ATF_TC_HEAD(hsearch_r_basic, tc)
238 {
239 
240 	atf_tc_set_md_var(tc, "descr", "Checks basic insertions and searching");
241 }
242 
243 ATF_TC_BODY(hsearch_r_basic, tc)
244 {
245 	ENTRY e, *ep;
246 	char ch[2];
247 	int i;
248 	struct hsearch_data t;
249 
250 	REQUIRE_ERRNO(hcreate_r(16, &t) != 0);
251 
252 	/* ch[1] should be constant from here on down. */
253 	ch[1] = '\0';
254 
255 	/* Basic insertions.  Check enough that there'll be collisions. */
256 	for (i = 0; i < 26; i++) {
257 		ch[0] = 'a' + i;
258 		e.key = strdup(ch);	/* ptr to provided key is kept! */
259 		ATF_REQUIRE(e.key != NULL);
260 		e.data = (void *)(intptr_t)i;
261 
262 		ATF_REQUIRE(hsearch_r(e, ENTER, &ep, &t) == 1);
263 		ATF_REQUIRE(ep != NULL);
264 		ATF_REQUIRE_STREQ(ep->key, ch);
265 		ATF_REQUIRE_EQ((intptr_t)ep->data, i);
266 	}
267 
268 	/* e.key should be constant from here on down. */
269 	e.key = ch;
270 
271 	/* Basic lookups. */
272 	for (i = 0; i < 26; i++) {
273 		ch[0] = 'a' + i;
274 
275 		ATF_REQUIRE(hsearch_r(e, FIND, &ep, &t) == 1);
276 		ATF_REQUIRE(ep != NULL);
277 		ATF_REQUIRE_STREQ(ep->key, ch);
278 		ATF_REQUIRE_EQ((intptr_t)ep->data, i);
279 	}
280 
281 	hdestroy1_r(&t, free, NULL);
282 }
283 #endif
284 
285 ATF_TC(hsearch_r_duplicate);
286 ATF_TC_HEAD(hsearch_r_duplicate, tc)
287 {
288 
289 	atf_tc_set_md_var(tc, "descr", "Checks that inserting duplicate "
290 	    "doesn't overwrite existing data");
291 }
292 
293 ATF_TC_BODY(hsearch_r_duplicate, tc)
294 {
295 	ENTRY e, *ep;
296 	struct hsearch_data t;
297 
298 	REQUIRE_ERRNO(hcreate_r(16, &t));
299 
300 	e.key = __UNCONST("a");
301 	e.data = (void *)(intptr_t) 0;
302 
303 	ATF_REQUIRE(hsearch_r(e, ENTER, &ep, &t) == 1);
304 	ATF_REQUIRE(ep != NULL);
305 	ATF_REQUIRE_STREQ(ep->key, "a");
306 	ATF_REQUIRE_EQ((intptr_t)ep->data, 0);
307 
308 	e.data = (void *)(intptr_t)12345;
309 
310 	ATF_REQUIRE(hsearch_r(e, ENTER, &ep, &t) == 1);
311 	ATF_REQUIRE(hsearch_r(e, FIND, &ep, &t) == 1);
312 
313 	ATF_REQUIRE(ep != NULL);
314 	ATF_REQUIRE_STREQ(ep->key, "a");
315 	ATF_REQUIRE_EQ((intptr_t)ep->data, 0);
316 
317 	hdestroy_r(&t);
318 }
319 
320 ATF_TC(hsearch_r_nonexistent);
321 ATF_TC_HEAD(hsearch_r_nonexistent, tc)
322 {
323 
324 	atf_tc_set_md_var(tc, "descr",
325 	    "Checks searching for non-existent entry");
326 }
327 
328 ATF_TC_BODY(hsearch_r_nonexistent, tc)
329 {
330 	ENTRY e, *ep;
331 	struct hsearch_data t;
332 
333 	REQUIRE_ERRNO(hcreate_r(16, &t));
334 
335 	e.key = __UNCONST("A");
336 	ATF_REQUIRE(hsearch_r(e, FIND, &ep, &t) == 1);
337 	ATF_REQUIRE_EQ(ep, NULL);
338 
339 	hdestroy_r(&t);
340 }
341 
342 ATF_TC(hsearch_r_two);
343 ATF_TC_HEAD(hsearch_r_two, tc)
344 {
345 
346 	atf_tc_set_md_var(tc, "descr",
347 	    "Checks that searching doesn't overwrite previous search results");
348 }
349 
350 ATF_TC_BODY(hsearch_r_two, tc)
351 {
352 	ENTRY e, *ep, *ep2;
353 	struct hsearch_data t;
354 
355 	REQUIRE_ERRNO(hcreate_r(16, &t));
356 
357 	e.key = __UNCONST("a");
358 	e.data = (void*)(intptr_t)0;
359 
360 	ATF_REQUIRE(hsearch_r(e, ENTER, &ep, &t) == 1);
361 	ATF_REQUIRE(ep != NULL);
362 	ATF_REQUIRE_STREQ(ep->key, "a");
363 	ATF_REQUIRE_EQ((intptr_t)ep->data, 0);
364 
365 	e.key = __UNCONST("b");
366 	e.data = (void*)(intptr_t)1;
367 
368 	ATF_REQUIRE(hsearch_r(e, ENTER, &ep, &t) == 1);
369 	ATF_REQUIRE(ep != NULL);
370 	ATF_REQUIRE_STREQ(ep->key, "b");
371 	ATF_REQUIRE_EQ((intptr_t)ep->data, 1);
372 
373 	e.key = __UNCONST("a");
374 	ATF_REQUIRE(hsearch_r(e, FIND, &ep, &t) == 1);
375 
376 	e.key = __UNCONST("b");
377 	ATF_REQUIRE(hsearch_r(e, FIND, &ep2, &t) == 1);
378 
379 	ATF_REQUIRE(ep != NULL);
380 	ATF_REQUIRE_STREQ(ep->key, "a");
381 	ATF_REQUIRE_EQ((intptr_t)ep->data, 0);
382 
383 	ATF_REQUIRE(ep2 != NULL);
384 	ATF_REQUIRE_STREQ(ep2->key, "b");
385 	ATF_REQUIRE_EQ((intptr_t)ep2->data, 1);
386 
387 	hdestroy_r(&t);
388 }
389 #endif
390 
391 ATF_TP_ADD_TCS(tp)
392 {
393 
394 #ifdef __NetBSD__
395 	ATF_TP_ADD_TC(tp, hsearch_basic);
396 #endif
397 	ATF_TP_ADD_TC(tp, hsearch_duplicate);
398 	ATF_TP_ADD_TC(tp, hsearch_nonexistent);
399 	ATF_TP_ADD_TC(tp, hsearch_two);
400 
401 #if defined(__FreeBSD__) && 1100027 <= __FreeBSD_version
402 #ifdef __NetBSD__
403 	ATF_TP_ADD_TC(tp, hsearch_r_basic);
404 #endif
405 	ATF_TP_ADD_TC(tp, hsearch_r_duplicate);
406 	ATF_TP_ADD_TC(tp, hsearch_r_nonexistent);
407 	ATF_TP_ADD_TC(tp, hsearch_r_two);
408 #endif
409 
410 	return atf_no_error();
411 }
412