xref: /freebsd/lib/libc/tests/nss/testutil.h (revision 42249ef2)
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 	struct ent data;						\
256 	FILE *fi;							\
257 	size_t len;							\
258 	int rv;								\
259 									\
260 	ATF_REQUIRE(fname != NULL);					\
261 	ATF_REQUIRE(td != NULL);					\
262 									\
263 	fi = fopen(fname, "r");						\
264 	if (fi == NULL)							\
265 		return (-1);						\
266 									\
267 	rv = 0;								\
268 	while (!feof(fi)) {						\
269 		char *buf = fgetln(fi, &len);				\
270 		if (buf == NULL || len <= 1)				\
271 			continue;					\
272 		if (buf[len - 1] == '\n')				\
273 			buf[len - 1] = '\0';				\
274 		else							\
275 			buf[len] = '\0';				\
276 		if (buf[0] == '#')					\
277 			continue;					\
278 		rv = read_func(&data, buf);				\
279 		if (rv == 0) {						\
280 			__##ent##_test_data_append(td, &data);		\
281 			td->free_func(&data);				\
282 		} else 							\
283 			goto fin;					\
284 	}								\
285 									\
286 fin:									\
287 	fclose(fi);							\
288 	return (rv);							\
289 }
290 
291 #define DECLARE_1PASS_TEST(ent)						\
292 int __##ent##_1pass_test(struct ent##_test_data *, 			\
293 	int (*)(struct ent *, void *),					\
294 	void *);
295 
296 #define DO_1PASS_TEST(ent, td, f, mdata)				\
297 	__##ent##_1pass_test(td, f, mdata)
298 
299 #define IMPLEMENT_1PASS_TEST(ent)					\
300 int									\
301 __##ent##_1pass_test(struct ent##_test_data *td, 			\
302 	int (*tf)(struct ent *, void *),				\
303 	void *mdata)							\
304 {									\
305 	int rv;								\
306 	rv = __##ent##_test_data_foreach(td, tf, mdata);		\
307 									\
308 	return (rv);							\
309 }
310 
311 #define DECLARE_2PASS_TEST(ent)						\
312 int __##ent##_2pass_test(struct ent##_test_data *, 			\
313 	struct ent##_test_data *, 					\
314 	int (*)(struct ent *, struct ent *, void *), void *);
315 
316 #define DO_2PASS_TEST(ent, td1, td2, f, mdata)				\
317 	__##ent##_2pass_test(td1, td2, f, mdata)
318 
319 #define IMPLEMENT_2PASS_TEST(ent)					\
320 int									\
321 __##ent##_2pass_test(struct ent##_test_data *td1,			\
322 	struct ent##_test_data *td2,					\
323 	int (*cmp_func)(struct ent *, struct ent *, void *),		\
324 	void *cmp_mdata)						\
325 {									\
326 	int rv;								\
327 									\
328 	rv = __##ent##_test_data_compare(td1, td2, cmp_func, cmp_mdata);	\
329 	return (rv);							\
330 }
331