2 * Copyright (c) 2006 Michael Bushkov <bushman@freebsd.org>
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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.
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
28 #include <sys/queue.h>
30 #define DECLARE_TEST_DATA(ent) \
31 struct ent##_entry { \
33 STAILQ_ENTRY(ent##_entry) entries; \
36 struct ent##_test_data { \
37 void (*clone_func)(struct ent *, struct ent const *); \
38 void (*free_func)(struct ent *); \
40 STAILQ_HEAD(ent_head, ent##_entry) snapshot_data; \
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 *); \
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 *, \
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 *);
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)
70 #define IMPLEMENT_TEST_DATA(ent) \
72 __##ent##_test_data_init(struct ent##_test_data *td, \
73 void (*clonef)(struct ent *, struct ent const *), \
74 void (*freef)(struct ent *)) \
77 assert(clonef != NULL); \
78 assert(freef != NULL); \
80 memset(td, 0, sizeof(*td)); \
81 td->clone_func = clonef; \
82 td->free_func = freef; \
83 STAILQ_INIT(&td->snapshot_data); \
87 __##ent##_test_data_destroy(struct ent##_test_data *td) \
89 __##ent##_test_data_clear(td); \
93 __##ent##_test_data_append(struct ent##_test_data *td, struct ent *app_data)\
95 struct ent##_entry *e; \
98 assert(app_data != NULL); \
100 e = (struct ent##_entry *)malloc(sizeof(struct ent##_entry)); \
102 memset(e, 0, sizeof(struct ent##_entry)); \
104 td->clone_func(&e->data, app_data); \
105 STAILQ_INSERT_TAIL(&td->snapshot_data, e, entries); \
109 __##ent##_test_data_foreach(struct ent##_test_data *td, \
110 int (*forf)(struct ent *, void *), void *mdata) \
112 struct ent##_entry *e; \
115 assert(td != NULL); \
116 assert(forf != NULL); \
119 STAILQ_FOREACH(e, &td->snapshot_data, entries) { \
120 rv = forf(&e->data, mdata); \
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)\
132 struct ent##_entry *e1, *e2; \
135 assert(td1 != NULL); \
136 assert(td2 != NULL); \
137 assert(cmp_func != NULL); \
139 e1 = STAILQ_FIRST(&td1->snapshot_data); \
140 e2 = STAILQ_FIRST(&td2->snapshot_data); \
144 if ((e1 == NULL) || (e2 == NULL)) { \
151 rv = cmp_func(&e1->data, &e2->data, mdata); \
152 e1 = STAILQ_NEXT(e1, entries); \
153 e2 = STAILQ_NEXT(e2, entries); \
160 __##ent##_test_data_find(struct ent##_test_data *td, struct ent *data, \
161 int (*cmp)(struct ent *, struct ent *, void *), void *mdata) \
163 struct ent##_entry *e; \
164 struct ent *result; \
166 assert(td != NULL); \
167 assert(cmp != NULL); \
170 STAILQ_FOREACH(e, &td->snapshot_data, entries) { \
171 if (cmp(&e->data, data, mdata) == 0) { \
182 __##ent##_test_data_clear(struct ent##_test_data *td) \
184 struct ent##_entry *e; \
185 assert(td != NULL); \
187 while (!STAILQ_EMPTY(&td->snapshot_data)) { \
188 e = STAILQ_FIRST(&td->snapshot_data); \
189 STAILQ_REMOVE_HEAD(&td->snapshot_data, entries); \
191 td->free_func(&e->data); \
197 #define DECLARE_TEST_FILE_SNAPSHOT(ent) \
198 struct ent##_snp_param { \
200 void (*sdump_func)(struct ent *, char *, size_t); \
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 *));
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)
214 #define IMPLEMENT_TEST_FILE_SNAPSHOT(ent) \
216 __##ent##_snapshot_write_func(struct ent *data, void *mdata) \
219 struct ent##_snp_param *param; \
221 assert(data != NULL); \
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); \
232 __##ent##_snapshot_write(char const *fname, struct ent##_test_data *td, \
233 void (*sdump_func)(struct ent *, char *, size_t)) \
235 struct ent##_snp_param param; \
237 assert(fname != NULL); \
238 assert(td != NULL); \
240 param.fp = fopen(fname, "w"); \
241 if (param.fp == NULL) \
244 param.sdump_func = sdump_func; \
245 __##ent##_test_data_foreach(td, __##ent##_snapshot_write_func, ¶m);\
252 __##ent##_snapshot_read(char const *fname, struct ent##_test_data *td, \
253 int (*read_func)(struct ent *, char *)) \
262 assert(fname != NULL); \
263 assert(td != NULL); \
265 fi = fopen(fname, "r"); \
270 memset(buffer, 0, sizeof(buffer)); \
271 while (!feof(fi)) { \
272 s = fgets(buffer, sizeof(buffer), fi); \
273 if (s != NULL && s[0] != '#') { \
277 if (buffer[len - 1] == '\n') \
278 buffer[len -1] = '\0'; \
280 rv = read_func(&data, s); \
282 __##ent##_test_data_append(td, &data); \
283 td->free_func(&data); \
294 #define DECLARE_1PASS_TEST(ent) \
295 int __##ent##_1pass_test(struct ent##_test_data *, \
296 int (*)(struct ent *, void *), \
299 #define DO_1PASS_TEST(ent, td, f, mdata) \
300 __##ent##_1pass_test(td, f, mdata)
302 #define IMPLEMENT_1PASS_TEST(ent) \
304 __##ent##_1pass_test(struct ent##_test_data *td, \
305 int (*tf)(struct ent *, void *), \
309 rv = __##ent##_test_data_foreach(td, tf, mdata); \
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 *);
319 #define DO_2PASS_TEST(ent, td1, td2, f, mdata) \
320 __##ent##_2pass_test(td1, td2, f, mdata)
322 #define IMPLEMENT_2PASS_TEST(ent) \
324 __##ent##_2pass_test(struct ent##_test_data *td1, \
325 struct ent##_test_data *td2, \
326 int (*cmp_func)(struct ent *, struct ent *, void *), \
331 rv = __##ent##_test_data_compare(td1, td2, cmp_func, cmp_mdata); \