xref: /freebsd/lib/libc/tests/nss/testutil.h (revision 1f4bcc459a76b7aa664f3fd557684cd0ba6da352)
1 /*-
2  * Copyright (c) 2006 Michael Bushkov <bushman@freebsd.org>
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
14  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
17  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23  * SUCH DAMAGE.
24  *
25  * $FreeBSD$
26  */
27 
28 #include <sys/queue.h>
29 
30 #define DECLARE_TEST_DATA(ent)						\
31 struct ent##_entry {							\
32 	struct ent data;						\
33 	STAILQ_ENTRY(ent##_entry) entries;				\
34 };									\
35 									\
36 struct ent##_test_data {						\
37 	void (*clone_func)(struct ent *, struct ent const *);		\
38 	void (*free_func)(struct ent *);				\
39 									\
40 	STAILQ_HEAD(ent_head, ent##_entry) snapshot_data;		\
41 };									\
42 									\
43 void __##ent##_test_data_init(struct ent##_test_data *, 		\
44 	void (*)(struct ent *, struct ent const *),			\
45 	void (*freef)(struct ent *));		 			\
46 void __##ent##_test_data_destroy(struct ent##_test_data *);		\
47 									\
48 void __##ent##_test_data_append(struct ent##_test_data *, struct ent *data);\
49 int __##ent##_test_data_foreach(struct ent##_test_data *,		\
50 	int (*)(struct ent *, void *), void *);				\
51 int __##ent##_test_data_compare(struct ent##_test_data *,		\
52 	struct ent##_test_data *, int (*)(struct ent *, struct ent *,	\
53 	void *), void *);						\
54 struct ent *__##ent##_test_data_find(struct ent##_test_data *, struct ent *,\
55 	int (*)(struct ent *, struct ent *, void *), void *);		\
56 void __##ent##_test_data_clear(struct ent##_test_data *);
57 
58 #define TEST_DATA_INIT(ent, td, clonef, freef)\
59 	__##ent##_test_data_init(td, clonef, freef)
60 #define TEST_DATA_DESTROY(ent, td) __##ent##_test_data_destroy(td)
61 #define TEST_DATA_APPEND(ent, td, d) __##ent##_test_data_append(td, d)
62 #define TEST_DATA_FOREACH(ent, td, f, mdata)\
63 	__##ent##_test_data_foreach(td, f, mdata)
64 #define TEST_DATA_COMPARE(ent, td1, td2, fcmp, mdata)\
65 	__##ent##_test_data_compare(td1, td2, fcmp, mdata);
66 #define TEST_DATA_FIND(ent, td, d, fcmp, mdata)\
67 	__##ent##_test_data_find(td, d, fcmp, mdata)
68 #define TEST_DATA_CLEAR(ent, td) __##ent##_test_data_clear(td)
69 
70 #define IMPLEMENT_TEST_DATA(ent)					\
71 void									\
72 __##ent##_test_data_init(struct ent##_test_data *td,			\
73 	void (*clonef)(struct ent *, struct ent const *),		\
74 	void (*freef)(struct ent *))					\
75 {									\
76 	ATF_REQUIRE(td != NULL);					\
77 	ATF_REQUIRE(clonef != NULL);					\
78 	ATF_REQUIRE(freef != NULL);					\
79 									\
80 	memset(td, 0, sizeof(*td));					\
81 	td->clone_func = clonef;					\
82 	td->free_func = freef;						\
83 	STAILQ_INIT(&td->snapshot_data);				\
84 }									\
85 									\
86 void 									\
87 __##ent##_test_data_destroy(struct ent##_test_data *td)			\
88 {									\
89 	__##ent##_test_data_clear(td);					\
90 }									\
91 									\
92 void 									\
93 __##ent##_test_data_append(struct ent##_test_data *td, struct ent *app_data)\
94 {									\
95 	struct ent##_entry *e;						\
96 									\
97 	ATF_REQUIRE(td != NULL);					\
98 	ATF_REQUIRE(app_data != NULL);					\
99 									\
100 	e = (struct ent##_entry *)malloc(sizeof(struct ent##_entry));	\
101 	ATF_REQUIRE(e != NULL);						\
102 	memset(e, 0, sizeof(struct ent##_entry));			\
103 									\
104 	td->clone_func(&e->data, app_data);				\
105 	STAILQ_INSERT_TAIL(&td->snapshot_data, e, entries);		\
106 }									\
107 									\
108 int									\
109 __##ent##_test_data_foreach(struct ent##_test_data *td,			\
110 	int (*forf)(struct ent *, void *), void *mdata)			\
111 {									\
112 	struct ent##_entry *e;						\
113 	int rv;								\
114 									\
115 	ATF_REQUIRE(td != NULL);					\
116 	ATF_REQUIRE(forf != NULL);					\
117 									\
118 	rv = 0;								\
119 	STAILQ_FOREACH(e, &td->snapshot_data, entries) {		\
120 		rv = forf(&e->data, mdata);				\
121 		if (rv != 0)						\
122 			break;						\
123 	}								\
124 									\
125 	return (rv);							\
126 }									\
127 									\
128 int									\
129 __##ent##_test_data_compare(struct ent##_test_data *td1, struct ent##_test_data *td2,\
130 	int (*cmp_func)(struct ent *, struct ent *, void *), void *mdata)\
131 {									\
132 	struct ent##_entry *e1, *e2;					\
133 	int rv;								\
134 									\
135 	ATF_REQUIRE(td1 != NULL);					\
136 	ATF_REQUIRE(td2 != NULL);					\
137 	ATF_REQUIRE(cmp_func != NULL);					\
138 									\
139 	e1 = STAILQ_FIRST(&td1->snapshot_data);				\
140 	e2 = STAILQ_FIRST(&td2->snapshot_data);				\
141 									\
142 	rv = 0;								\
143 	do {								\
144 		if ((e1 == NULL) || (e2 == NULL)) {			\
145 			if (e1 == e2)					\
146 				return (0);				\
147 			else						\
148 				return (-1);				\
149 		}							\
150 									\
151 		rv = cmp_func(&e1->data, &e2->data, mdata);		\
152 		e1 = STAILQ_NEXT(e1, entries);				\
153 		e2 = STAILQ_NEXT(e2, entries);				\
154 	} while (rv == 0);						\
155 									\
156 	return (rv);							\
157 }									\
158 									\
159 struct ent *								\
160 __##ent##_test_data_find(struct ent##_test_data *td, struct ent *data,	\
161 	int (*cmp)(struct ent *, struct ent *, void *), void *mdata)	\
162 {									\
163 	struct ent##_entry *e;						\
164 	struct ent *result;						\
165 									\
166 	ATF_REQUIRE(td != NULL);					\
167 	ATF_REQUIRE(cmp != NULL);					\
168 									\
169 	result = NULL;							\
170 	STAILQ_FOREACH(e, &td->snapshot_data, entries) {		\
171 		if (cmp(&e->data, data, mdata) == 0) {			\
172 			result = &e->data;				\
173 			break;						\
174 		}							\
175 	}								\
176 									\
177 	return (result);						\
178 }									\
179 									\
180 									\
181 void									\
182 __##ent##_test_data_clear(struct ent##_test_data *td)			\
183 {									\
184 	struct ent##_entry *e;						\
185 	ATF_REQUIRE(td != NULL);					\
186 									\
187 	while (!STAILQ_EMPTY(&td->snapshot_data)) {			\
188 		e = STAILQ_FIRST(&td->snapshot_data);			\
189 		STAILQ_REMOVE_HEAD(&td->snapshot_data, entries);	\
190 									\
191 		td->free_func(&e->data);				\
192 		free(e);						\
193 		e = NULL;						\
194 	}								\
195 }
196 
197 #define DECLARE_TEST_FILE_SNAPSHOT(ent)					\
198 struct ent##_snp_param {						\
199 	FILE *fp;							\
200 	void (*sdump_func)(struct ent *, char *, size_t);		\
201 };									\
202 									\
203 int __##ent##_snapshot_write_func(struct ent *, void *);		\
204 int __##ent##_snapshot_write(char const *, struct ent##_test_data *,	\
205 	void (*)(struct ent *, char *, size_t));			\
206 int __##ent##_snapshot_read(char const *, struct ent##_test_data *,	\
207 	int (*)(struct ent *, char *));
208 
209 #define TEST_SNAPSHOT_FILE_WRITE(ent, fname, td, f)			\
210 	__##ent##_snapshot_write(fname, td, f)
211 #define TEST_SNAPSHOT_FILE_READ(ent, fname, td, f)			\
212 	__##ent##_snapshot_read(fname, td, f)
213 
214 #define IMPLEMENT_TEST_FILE_SNAPSHOT(ent)				\
215 int									\
216 __##ent##_snapshot_write_func(struct ent *data, void *mdata)		\
217 {									\
218 	char buffer[1024];						\
219 	struct ent##_snp_param *param;					\
220 									\
221 	ATF_REQUIRE(data != NULL);					\
222 									\
223 	param = (struct ent##_snp_param *)mdata;			\
224 	param->sdump_func(data, buffer, sizeof(buffer));		\
225 	fputs(buffer, param->fp);					\
226 	fputc('\n', param->fp);						\
227 									\
228 	return (0);							\
229 }									\
230 									\
231 int									\
232 __##ent##_snapshot_write(char const *fname, struct ent##_test_data *td,	\
233 	void (*sdump_func)(struct ent *, char *, size_t))		\
234 {									\
235 	struct ent##_snp_param	param;					\
236 									\
237 	ATF_REQUIRE(fname != NULL);					\
238 	ATF_REQUIRE(td != NULL);					\
239 									\
240 	param.fp = fopen(fname, "w");					\
241 	if (param.fp == NULL)						\
242 		return (-1);						\
243 									\
244 	param.sdump_func = sdump_func;					\
245 	__##ent##_test_data_foreach(td, __##ent##_snapshot_write_func, &param);\
246 	fclose(param.fp);						\
247 									\
248 	return (0);							\
249 }									\
250 									\
251 int									\
252 __##ent##_snapshot_read(char const *fname, struct ent##_test_data *td,	\
253 	int (*read_func)(struct ent *, char *))				\
254 {									\
255 	char buffer[1024];						\
256 	struct ent data;						\
257 	char *s;							\
258 	FILE *fi;							\
259 	size_t len;							\
260 	int rv;								\
261 									\
262 	ATF_REQUIRE(fname != NULL);					\
263 	ATF_REQUIRE(td != NULL);					\
264 									\
265 	fi = fopen(fname, "r");						\
266 	if (fi == NULL)							\
267 		return (-1);						\
268 									\
269 	rv = 0;								\
270 	memset(buffer, 0, sizeof(buffer));				\
271 	while (!feof(fi)) {						\
272 		s = fgets(buffer, sizeof(buffer), fi);			\
273 		if (s != NULL && s[0] != '#') {				\
274 			len = strlen(s);				\
275 			if (len == 0)					\
276 				continue;				\
277 			if (buffer[len - 1] == '\n')			\
278 				buffer[len -1] = '\0';			\
279 									\
280 			rv = read_func(&data, s);			\
281 			if (rv == 0) {					\
282 				__##ent##_test_data_append(td, &data);	\
283 				td->free_func(&data);			\
284 			} else 						\
285 				goto fin;				\
286 		}							\
287 	}								\
288 									\
289 fin:									\
290 	fclose(fi);							\
291 	return (rv);							\
292 }
293 
294 #define DECLARE_1PASS_TEST(ent)						\
295 int __##ent##_1pass_test(struct ent##_test_data *, 			\
296 	int (*)(struct ent *, void *),					\
297 	void *);
298 
299 #define DO_1PASS_TEST(ent, td, f, mdata)				\
300 	__##ent##_1pass_test(td, f, mdata)
301 
302 #define IMPLEMENT_1PASS_TEST(ent)					\
303 int									\
304 __##ent##_1pass_test(struct ent##_test_data *td, 			\
305 	int (*tf)(struct ent *, void *),				\
306 	void *mdata)							\
307 {									\
308 	int rv;								\
309 	rv = __##ent##_test_data_foreach(td, tf, mdata);		\
310 									\
311 	return (rv);							\
312 }
313 
314 #define DECLARE_2PASS_TEST(ent)						\
315 int __##ent##_2pass_test(struct ent##_test_data *, 			\
316 	struct ent##_test_data *, 					\
317 	int (*)(struct ent *, struct ent *, void *), void *);
318 
319 #define DO_2PASS_TEST(ent, td1, td2, f, mdata)				\
320 	__##ent##_2pass_test(td1, td2, f, mdata)
321 
322 #define IMPLEMENT_2PASS_TEST(ent)					\
323 int									\
324 __##ent##_2pass_test(struct ent##_test_data *td1,			\
325 	struct ent##_test_data *td2,					\
326 	int (*cmp_func)(struct ent *, struct ent *, void *),		\
327 	void *cmp_mdata)						\
328 {									\
329 	int rv;								\
330 									\
331 	rv = __##ent##_test_data_compare(td1, td2, cmp_func, cmp_mdata);	\
332 	return (rv);							\
333 }
334