xref: /freebsd/lib/libc/tests/nss/testutil.h (revision b3e76948)
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 
26 #include <sys/queue.h>
27 
28 #define DECLARE_TEST_DATA(ent)						\
29 struct ent##_entry {							\
30 	struct ent data;						\
31 	STAILQ_ENTRY(ent##_entry) entries;				\
32 };									\
33 									\
34 struct ent##_test_data {						\
35 	void (*clone_func)(struct ent *, struct ent const *);		\
36 	void (*free_func)(struct ent *);				\
37 									\
38 	STAILQ_HEAD(ent_head, ent##_entry) snapshot_data;		\
39 };									\
40 									\
41 void __##ent##_test_data_init(struct ent##_test_data *, 		\
42 	void (*)(struct ent *, struct ent const *),			\
43 	void (*freef)(struct ent *));		 			\
44 void __##ent##_test_data_destroy(struct ent##_test_data *);		\
45 									\
46 void __##ent##_test_data_append(struct ent##_test_data *, struct ent *data);\
47 int __##ent##_test_data_foreach(struct ent##_test_data *,		\
48 	int (*)(struct ent *, void *), void *);				\
49 int __##ent##_test_data_compare(struct ent##_test_data *,		\
50 	struct ent##_test_data *, int (*)(struct ent *, struct ent *,	\
51 	void *), void *);						\
52 struct ent *__##ent##_test_data_find(struct ent##_test_data *, struct ent *,\
53 	int (*)(struct ent *, struct ent *, void *), void *);		\
54 void __##ent##_test_data_clear(struct ent##_test_data *);
55 
56 #define TEST_DATA_INIT(ent, td, clonef, freef)\
57 	__##ent##_test_data_init(td, clonef, freef)
58 #define TEST_DATA_DESTROY(ent, td) __##ent##_test_data_destroy(td)
59 #define TEST_DATA_APPEND(ent, td, d) __##ent##_test_data_append(td, d)
60 #define TEST_DATA_FOREACH(ent, td, f, mdata)\
61 	__##ent##_test_data_foreach(td, f, mdata)
62 #define TEST_DATA_COMPARE(ent, td1, td2, fcmp, mdata)\
63 	__##ent##_test_data_compare(td1, td2, fcmp, mdata);
64 #define TEST_DATA_FIND(ent, td, d, fcmp, mdata)\
65 	__##ent##_test_data_find(td, d, fcmp, mdata)
66 #define TEST_DATA_CLEAR(ent, td) __##ent##_test_data_clear(td)
67 
68 #define IMPLEMENT_TEST_DATA(ent)					\
69 void									\
70 __##ent##_test_data_init(struct ent##_test_data *td,			\
71 	void (*clonef)(struct ent *, struct ent const *),		\
72 	void (*freef)(struct ent *))					\
73 {									\
74 	ATF_REQUIRE(td != NULL);					\
75 	ATF_REQUIRE(clonef != NULL);					\
76 	ATF_REQUIRE(freef != NULL);					\
77 									\
78 	memset(td, 0, sizeof(*td));					\
79 	td->clone_func = clonef;					\
80 	td->free_func = freef;						\
81 	STAILQ_INIT(&td->snapshot_data);				\
82 }									\
83 									\
84 void 									\
85 __##ent##_test_data_destroy(struct ent##_test_data *td)			\
86 {									\
87 	__##ent##_test_data_clear(td);					\
88 }									\
89 									\
90 void 									\
91 __##ent##_test_data_append(struct ent##_test_data *td, struct ent *app_data)\
92 {									\
93 	struct ent##_entry *e;						\
94 									\
95 	ATF_REQUIRE(td != NULL);					\
96 	ATF_REQUIRE(app_data != NULL);					\
97 									\
98 	e = (struct ent##_entry *)malloc(sizeof(struct ent##_entry));	\
99 	ATF_REQUIRE(e != NULL);						\
100 	memset(e, 0, sizeof(struct ent##_entry));			\
101 									\
102 	td->clone_func(&e->data, app_data);				\
103 	STAILQ_INSERT_TAIL(&td->snapshot_data, e, entries);		\
104 }									\
105 									\
106 int									\
107 __##ent##_test_data_foreach(struct ent##_test_data *td,			\
108 	int (*forf)(struct ent *, void *), void *mdata)			\
109 {									\
110 	struct ent##_entry *e;						\
111 	int rv;								\
112 									\
113 	ATF_REQUIRE(td != NULL);					\
114 	ATF_REQUIRE(forf != NULL);					\
115 									\
116 	rv = 0;								\
117 	STAILQ_FOREACH(e, &td->snapshot_data, entries) {		\
118 		rv = forf(&e->data, mdata);				\
119 		if (rv != 0)						\
120 			break;						\
121 	}								\
122 									\
123 	return (rv);							\
124 }									\
125 									\
126 int									\
127 __##ent##_test_data_compare(struct ent##_test_data *td1, struct ent##_test_data *td2,\
128 	int (*cmp_func)(struct ent *, struct ent *, void *), void *mdata)\
129 {									\
130 	struct ent##_entry *e1, *e2;					\
131 	int rv;								\
132 									\
133 	ATF_REQUIRE(td1 != NULL);					\
134 	ATF_REQUIRE(td2 != NULL);					\
135 	ATF_REQUIRE(cmp_func != NULL);					\
136 									\
137 	e1 = STAILQ_FIRST(&td1->snapshot_data);				\
138 	e2 = STAILQ_FIRST(&td2->snapshot_data);				\
139 									\
140 	rv = 0;								\
141 	do {								\
142 		if ((e1 == NULL) || (e2 == NULL)) {			\
143 			if (e1 == e2)					\
144 				return (0);				\
145 			else						\
146 				return (-1);				\
147 		}							\
148 									\
149 		rv = cmp_func(&e1->data, &e2->data, mdata);		\
150 		e1 = STAILQ_NEXT(e1, entries);				\
151 		e2 = STAILQ_NEXT(e2, entries);				\
152 	} while (rv == 0);						\
153 									\
154 	return (rv);							\
155 }									\
156 									\
157 struct ent *								\
158 __##ent##_test_data_find(struct ent##_test_data *td, struct ent *data,	\
159 	int (*cmp)(struct ent *, struct ent *, void *), void *mdata)	\
160 {									\
161 	struct ent##_entry *e;						\
162 	struct ent *result;						\
163 									\
164 	ATF_REQUIRE(td != NULL);					\
165 	ATF_REQUIRE(cmp != NULL);					\
166 									\
167 	result = NULL;							\
168 	STAILQ_FOREACH(e, &td->snapshot_data, entries) {		\
169 		if (cmp(&e->data, data, mdata) == 0) {			\
170 			result = &e->data;				\
171 			break;						\
172 		}							\
173 	}								\
174 									\
175 	return (result);						\
176 }									\
177 									\
178 									\
179 void									\
180 __##ent##_test_data_clear(struct ent##_test_data *td)			\
181 {									\
182 	struct ent##_entry *e;						\
183 	ATF_REQUIRE(td != NULL);					\
184 									\
185 	while (!STAILQ_EMPTY(&td->snapshot_data)) {			\
186 		e = STAILQ_FIRST(&td->snapshot_data);			\
187 		STAILQ_REMOVE_HEAD(&td->snapshot_data, entries);	\
188 									\
189 		td->free_func(&e->data);				\
190 		free(e);						\
191 		e = NULL;						\
192 	}								\
193 }
194 
195 #define DECLARE_TEST_FILE_SNAPSHOT(ent)					\
196 struct ent##_snp_param {						\
197 	FILE *fp;							\
198 	void (*sdump_func)(struct ent *, char *, size_t);		\
199 };									\
200 									\
201 int __##ent##_snapshot_write_func(struct ent *, void *);		\
202 int __##ent##_snapshot_write(char const *, struct ent##_test_data *,	\
203 	void (*)(struct ent *, char *, size_t));			\
204 int __##ent##_snapshot_read(char const *, struct ent##_test_data *,	\
205 	int (*)(struct ent *, char *));
206 
207 #define TEST_SNAPSHOT_FILE_WRITE(ent, fname, td, f)			\
208 	__##ent##_snapshot_write(fname, td, f)
209 #define TEST_SNAPSHOT_FILE_READ(ent, fname, td, f)			\
210 	__##ent##_snapshot_read(fname, td, f)
211 
212 #define IMPLEMENT_TEST_FILE_SNAPSHOT(ent)				\
213 int									\
214 __##ent##_snapshot_write_func(struct ent *data, void *mdata)		\
215 {									\
216 	char buffer[1024];						\
217 	struct ent##_snp_param *param;					\
218 									\
219 	ATF_REQUIRE(data != NULL);					\
220 									\
221 	param = (struct ent##_snp_param *)mdata;			\
222 	param->sdump_func(data, buffer, sizeof(buffer));		\
223 	fputs(buffer, param->fp);					\
224 	fputc('\n', param->fp);						\
225 									\
226 	return (0);							\
227 }									\
228 									\
229 int									\
230 __##ent##_snapshot_write(char const *fname, struct ent##_test_data *td,	\
231 	void (*sdump_func)(struct ent *, char *, size_t))		\
232 {									\
233 	struct ent##_snp_param	param;					\
234 									\
235 	ATF_REQUIRE(fname != NULL);					\
236 	ATF_REQUIRE(td != NULL);					\
237 									\
238 	param.fp = fopen(fname, "w");					\
239 	if (param.fp == NULL)						\
240 		return (-1);						\
241 									\
242 	param.sdump_func = sdump_func;					\
243 	__##ent##_test_data_foreach(td, __##ent##_snapshot_write_func, &param);\
244 	fclose(param.fp);						\
245 									\
246 	return (0);							\
247 }									\
248 									\
249 int									\
250 __##ent##_snapshot_read(char const *fname, struct ent##_test_data *td,	\
251 	int (*read_func)(struct ent *, char *))				\
252 {									\
253 	struct ent data;						\
254 	FILE *fi;							\
255 	size_t len;							\
256 	int rv;								\
257 									\
258 	ATF_REQUIRE(fname != NULL);					\
259 	ATF_REQUIRE(td != NULL);					\
260 									\
261 	fi = fopen(fname, "r");						\
262 	if (fi == NULL)							\
263 		return (-1);						\
264 									\
265 	rv = 0;								\
266 	while (!feof(fi)) {						\
267 		char *buf = fgetln(fi, &len);				\
268 		if (buf == NULL || len <= 1)				\
269 			continue;					\
270 		if (buf[len - 1] == '\n')				\
271 			buf[len - 1] = '\0';				\
272 		else							\
273 			buf[len] = '\0';				\
274 		if (buf[0] == '#')					\
275 			continue;					\
276 		rv = read_func(&data, buf);				\
277 		if (rv == 0) {						\
278 			__##ent##_test_data_append(td, &data);		\
279 			td->free_func(&data);				\
280 		} else 							\
281 			goto fin;					\
282 	}								\
283 									\
284 fin:									\
285 	fclose(fi);							\
286 	return (rv);							\
287 }
288 
289 #define DECLARE_1PASS_TEST(ent)						\
290 int __##ent##_1pass_test(struct ent##_test_data *, 			\
291 	int (*)(struct ent *, void *),					\
292 	void *);
293 
294 #define DO_1PASS_TEST(ent, td, f, mdata)				\
295 	__##ent##_1pass_test(td, f, mdata)
296 
297 #define IMPLEMENT_1PASS_TEST(ent)					\
298 int									\
299 __##ent##_1pass_test(struct ent##_test_data *td, 			\
300 	int (*tf)(struct ent *, void *),				\
301 	void *mdata)							\
302 {									\
303 	int rv;								\
304 	rv = __##ent##_test_data_foreach(td, tf, mdata);		\
305 									\
306 	return (rv);							\
307 }
308 
309 #define DECLARE_2PASS_TEST(ent)						\
310 int __##ent##_2pass_test(struct ent##_test_data *, 			\
311 	struct ent##_test_data *, 					\
312 	int (*)(struct ent *, struct ent *, void *), void *);
313 
314 #define DO_2PASS_TEST(ent, td1, td2, f, mdata)				\
315 	__##ent##_2pass_test(td1, td2, f, mdata)
316 
317 #define IMPLEMENT_2PASS_TEST(ent)					\
318 int									\
319 __##ent##_2pass_test(struct ent##_test_data *td1,			\
320 	struct ent##_test_data *td2,					\
321 	int (*cmp_func)(struct ent *, struct ent *, void *),		\
322 	void *cmp_mdata)						\
323 {									\
324 	int rv;								\
325 									\
326 	rv = __##ent##_test_data_compare(td1, td2, cmp_func, cmp_mdata);\
327 	return (rv);							\
328 }
329