1168754Sbushman/*-
2168754Sbushman * Copyright (c) 2006 Michael Bushkov <bushman@freebsd.org>
3168754Sbushman *
4168754Sbushman * Redistribution and use in source and binary forms, with or without
5168754Sbushman * modification, are permitted provided that the following conditions
6168754Sbushman * are met:
7168754Sbushman * 1. Redistributions of source code must retain the above copyright
8168754Sbushman *    notice, this list of conditions and the following disclaimer.
9168754Sbushman * 2. Redistributions in binary form must reproduce the above copyright
10168754Sbushman *    notice, this list of conditions and the following disclaimer in the
11168754Sbushman *    documentation and/or other materials provided with the distribution.
12168754Sbushman *
13168754Sbushman * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
14168754Sbushman * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15168754Sbushman * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16168754Sbushman * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
17168754Sbushman * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18168754Sbushman * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19168754Sbushman * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20168754Sbushman * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21168754Sbushman * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22168754Sbushman * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23168754Sbushman * SUCH DAMAGE.
24168754Sbushman *
25168754Sbushman * $FreeBSD$
26168754Sbushman */
27168754Sbushman
28168754Sbushman#include <sys/queue.h>
29168754Sbushman
30168754Sbushman#define DECLARE_TEST_DATA(ent)						\
31168754Sbushmanstruct ent##_entry {							\
32168754Sbushman	struct ent data;						\
33168754Sbushman	STAILQ_ENTRY(ent##_entry) entries;				\
34168754Sbushman};									\
35168754Sbushman									\
36168754Sbushmanstruct ent##_test_data {						\
37168754Sbushman	void (*clone_func)(struct ent *, struct ent const *);		\
38168754Sbushman	void (*free_func)(struct ent *);				\
39168754Sbushman									\
40168754Sbushman	STAILQ_HEAD(ent_head, ent##_entry) snapshot_data;		\
41168754Sbushman};									\
42168754Sbushman									\
43168754Sbushmanvoid __##ent##_test_data_init(struct ent##_test_data *, 		\
44168754Sbushman	void (*)(struct ent *, struct ent const *),			\
45168754Sbushman	void (*freef)(struct ent *));		 			\
46168754Sbushmanvoid __##ent##_test_data_destroy(struct ent##_test_data *);		\
47168754Sbushman									\
48168754Sbushmanvoid __##ent##_test_data_append(struct ent##_test_data *, struct ent *data);\
49168754Sbushmanint __##ent##_test_data_foreach(struct ent##_test_data *,		\
50168754Sbushman	int (*)(struct ent *, void *), void *);				\
51168754Sbushmanint __##ent##_test_data_compare(struct ent##_test_data *,		\
52168754Sbushman	struct ent##_test_data *, int (*)(struct ent *, struct ent *,	\
53168754Sbushman	void *), void *);						\
54168754Sbushmanstruct ent *__##ent##_test_data_find(struct ent##_test_data *, struct ent *,\
55168754Sbushman	int (*)(struct ent *, struct ent *, void *), void *);		\
56291363Sngievoid __##ent##_test_data_clear(struct ent##_test_data *);
57291363Sngie
58168754Sbushman#define TEST_DATA_INIT(ent, td, clonef, freef)\
59168754Sbushman	__##ent##_test_data_init(td, clonef, freef)
60168754Sbushman#define TEST_DATA_DESTROY(ent, td) __##ent##_test_data_destroy(td)
61168754Sbushman#define TEST_DATA_APPEND(ent, td, d) __##ent##_test_data_append(td, d)
62168754Sbushman#define TEST_DATA_FOREACH(ent, td, f, mdata)\
63168754Sbushman	__##ent##_test_data_foreach(td, f, mdata)
64168754Sbushman#define TEST_DATA_COMPARE(ent, td1, td2, fcmp, mdata)\
65168754Sbushman	__##ent##_test_data_compare(td1, td2, fcmp, mdata);
66168754Sbushman#define TEST_DATA_FIND(ent, td, d, fcmp, mdata)\
67168754Sbushman	__##ent##_test_data_find(td, d, fcmp, mdata)
68168754Sbushman#define TEST_DATA_CLEAR(ent, td) __##ent##_test_data_clear(td)
69168754Sbushman
70168754Sbushman#define IMPLEMENT_TEST_DATA(ent)					\
71168754Sbushmanvoid									\
72168754Sbushman__##ent##_test_data_init(struct ent##_test_data *td,			\
73168754Sbushman	void (*clonef)(struct ent *, struct ent const *),		\
74168754Sbushman	void (*freef)(struct ent *))					\
75168754Sbushman{									\
76292323Sngie	ATF_REQUIRE(td != NULL);					\
77292323Sngie	ATF_REQUIRE(clonef != NULL);					\
78292323Sngie	ATF_REQUIRE(freef != NULL);					\
79168754Sbushman									\
80168754Sbushman	memset(td, 0, sizeof(*td));					\
81168754Sbushman	td->clone_func = clonef;					\
82168754Sbushman	td->free_func = freef;						\
83168754Sbushman	STAILQ_INIT(&td->snapshot_data);				\
84168754Sbushman}									\
85168754Sbushman									\
86168754Sbushmanvoid 									\
87168754Sbushman__##ent##_test_data_destroy(struct ent##_test_data *td)			\
88168754Sbushman{									\
89168754Sbushman	__##ent##_test_data_clear(td);					\
90168754Sbushman}									\
91168754Sbushman									\
92168754Sbushmanvoid 									\
93168754Sbushman__##ent##_test_data_append(struct ent##_test_data *td, struct ent *app_data)\
94168754Sbushman{									\
95168754Sbushman	struct ent##_entry *e;						\
96168754Sbushman									\
97292323Sngie	ATF_REQUIRE(td != NULL);					\
98292323Sngie	ATF_REQUIRE(app_data != NULL);					\
99168754Sbushman									\
100168754Sbushman	e = (struct ent##_entry *)malloc(sizeof(struct ent##_entry));	\
101292323Sngie	ATF_REQUIRE(e != NULL);						\
102168754Sbushman	memset(e, 0, sizeof(struct ent##_entry));			\
103168754Sbushman									\
104168754Sbushman	td->clone_func(&e->data, app_data);				\
105168754Sbushman	STAILQ_INSERT_TAIL(&td->snapshot_data, e, entries);		\
106168754Sbushman}									\
107168754Sbushman									\
108168754Sbushmanint									\
109168754Sbushman__##ent##_test_data_foreach(struct ent##_test_data *td,			\
110168754Sbushman	int (*forf)(struct ent *, void *), void *mdata)			\
111168754Sbushman{									\
112168754Sbushman	struct ent##_entry *e;						\
113168754Sbushman	int rv;								\
114168754Sbushman									\
115292323Sngie	ATF_REQUIRE(td != NULL);					\
116292323Sngie	ATF_REQUIRE(forf != NULL);					\
117168754Sbushman									\
118168754Sbushman	rv = 0;								\
119168754Sbushman	STAILQ_FOREACH(e, &td->snapshot_data, entries) {		\
120168754Sbushman		rv = forf(&e->data, mdata);				\
121168754Sbushman		if (rv != 0)						\
122168754Sbushman			break;						\
123168754Sbushman	}								\
124168754Sbushman									\
125168754Sbushman	return (rv);							\
126168754Sbushman}									\
127168754Sbushman									\
128168754Sbushmanint									\
129168754Sbushman__##ent##_test_data_compare(struct ent##_test_data *td1, struct ent##_test_data *td2,\
130168754Sbushman	int (*cmp_func)(struct ent *, struct ent *, void *), void *mdata)\
131168754Sbushman{									\
132168754Sbushman	struct ent##_entry *e1, *e2;					\
133168754Sbushman	int rv;								\
134168754Sbushman									\
135292323Sngie	ATF_REQUIRE(td1 != NULL);					\
136292323Sngie	ATF_REQUIRE(td2 != NULL);					\
137292323Sngie	ATF_REQUIRE(cmp_func != NULL);					\
138168754Sbushman									\
139168754Sbushman	e1 = STAILQ_FIRST(&td1->snapshot_data);				\
140168754Sbushman	e2 = STAILQ_FIRST(&td2->snapshot_data);				\
141168754Sbushman									\
142168754Sbushman	rv = 0;								\
143168754Sbushman	do {								\
144168754Sbushman		if ((e1 == NULL) || (e2 == NULL)) {			\
145168754Sbushman			if (e1 == e2)					\
146168754Sbushman				return (0);				\
147168754Sbushman			else						\
148168754Sbushman				return (-1);				\
149168754Sbushman		}							\
150168754Sbushman									\
151168754Sbushman		rv = cmp_func(&e1->data, &e2->data, mdata);		\
152168754Sbushman		e1 = STAILQ_NEXT(e1, entries);				\
153168754Sbushman		e2 = STAILQ_NEXT(e2, entries);				\
154168754Sbushman	} while (rv == 0);						\
155168754Sbushman									\
156168754Sbushman	return (rv);							\
157168754Sbushman}									\
158168754Sbushman									\
159168754Sbushmanstruct ent *								\
160168754Sbushman__##ent##_test_data_find(struct ent##_test_data *td, struct ent *data,	\
161168754Sbushman	int (*cmp)(struct ent *, struct ent *, void *), void *mdata)	\
162168754Sbushman{									\
163168754Sbushman	struct ent##_entry *e;						\
164168754Sbushman	struct ent *result;						\
165168754Sbushman									\
166292323Sngie	ATF_REQUIRE(td != NULL);					\
167292323Sngie	ATF_REQUIRE(cmp != NULL);					\
168168754Sbushman									\
169168754Sbushman	result = NULL;							\
170168754Sbushman	STAILQ_FOREACH(e, &td->snapshot_data, entries) {		\
171168754Sbushman		if (cmp(&e->data, data, mdata) == 0) {			\
172168754Sbushman			result = &e->data;				\
173168754Sbushman			break;						\
174168754Sbushman		}							\
175168754Sbushman	}								\
176168754Sbushman									\
177168754Sbushman	return (result);						\
178168754Sbushman}									\
179168754Sbushman									\
180168754Sbushman									\
181168754Sbushmanvoid									\
182168754Sbushman__##ent##_test_data_clear(struct ent##_test_data *td)			\
183168754Sbushman{									\
184168754Sbushman	struct ent##_entry *e;						\
185292323Sngie	ATF_REQUIRE(td != NULL);					\
186168754Sbushman									\
187168754Sbushman	while (!STAILQ_EMPTY(&td->snapshot_data)) {			\
188168754Sbushman		e = STAILQ_FIRST(&td->snapshot_data);			\
189168754Sbushman		STAILQ_REMOVE_HEAD(&td->snapshot_data, entries);	\
190168754Sbushman									\
191168754Sbushman		td->free_func(&e->data);				\
192168754Sbushman		free(e);						\
193292323Sngie		e = NULL;						\
194168754Sbushman	}								\
195291363Sngie}
196168754Sbushman
197168754Sbushman#define DECLARE_TEST_FILE_SNAPSHOT(ent)					\
198168754Sbushmanstruct ent##_snp_param {						\
199168754Sbushman	FILE *fp;							\
200168754Sbushman	void (*sdump_func)(struct ent *, char *, size_t);		\
201168754Sbushman};									\
202168754Sbushman									\
203168754Sbushmanint __##ent##_snapshot_write_func(struct ent *, void *);		\
204168754Sbushmanint __##ent##_snapshot_write(char const *, struct ent##_test_data *,	\
205168754Sbushman	void (*)(struct ent *, char *, size_t));			\
206168754Sbushmanint __##ent##_snapshot_read(char const *, struct ent##_test_data *,	\
207291363Sngie	int (*)(struct ent *, char *));
208291363Sngie
209168754Sbushman#define TEST_SNAPSHOT_FILE_WRITE(ent, fname, td, f)			\
210168754Sbushman	__##ent##_snapshot_write(fname, td, f)
211168754Sbushman#define TEST_SNAPSHOT_FILE_READ(ent, fname, td, f)			\
212168754Sbushman	__##ent##_snapshot_read(fname, td, f)
213168754Sbushman
214168754Sbushman#define IMPLEMENT_TEST_FILE_SNAPSHOT(ent)				\
215168754Sbushmanint									\
216168754Sbushman__##ent##_snapshot_write_func(struct ent *data, void *mdata)		\
217168754Sbushman{									\
218168754Sbushman	char buffer[1024];						\
219168754Sbushman	struct ent##_snp_param *param;					\
220168754Sbushman									\
221292323Sngie	ATF_REQUIRE(data != NULL);					\
222168754Sbushman									\
223168754Sbushman	param = (struct ent##_snp_param *)mdata;			\
224168754Sbushman	param->sdump_func(data, buffer, sizeof(buffer));		\
225168754Sbushman	fputs(buffer, param->fp);					\
226168754Sbushman	fputc('\n', param->fp);						\
227168754Sbushman									\
228168754Sbushman	return (0);							\
229168754Sbushman}									\
230168754Sbushman									\
231168754Sbushmanint									\
232168754Sbushman__##ent##_snapshot_write(char const *fname, struct ent##_test_data *td,	\
233168754Sbushman	void (*sdump_func)(struct ent *, char *, size_t))		\
234168754Sbushman{									\
235168754Sbushman	struct ent##_snp_param	param;					\
236168754Sbushman									\
237292323Sngie	ATF_REQUIRE(fname != NULL);					\
238292323Sngie	ATF_REQUIRE(td != NULL);					\
239168754Sbushman									\
240168754Sbushman	param.fp = fopen(fname, "w");					\
241168754Sbushman	if (param.fp == NULL)						\
242168754Sbushman		return (-1);						\
243168754Sbushman									\
244168754Sbushman	param.sdump_func = sdump_func;					\
245168754Sbushman	__##ent##_test_data_foreach(td, __##ent##_snapshot_write_func, &param);\
246168754Sbushman	fclose(param.fp);						\
247168754Sbushman									\
248168754Sbushman	return (0);							\
249168754Sbushman}									\
250168754Sbushman									\
251168754Sbushmanint									\
252168754Sbushman__##ent##_snapshot_read(char const *fname, struct ent##_test_data *td,	\
253168754Sbushman	int (*read_func)(struct ent *, char *))				\
254168754Sbushman{									\
255168754Sbushman	struct ent data;						\
256168754Sbushman	FILE *fi;							\
257168754Sbushman	size_t len;							\
258168754Sbushman	int rv;								\
259168754Sbushman									\
260292323Sngie	ATF_REQUIRE(fname != NULL);					\
261292323Sngie	ATF_REQUIRE(td != NULL);					\
262168754Sbushman									\
263168754Sbushman	fi = fopen(fname, "r");						\
264168754Sbushman	if (fi == NULL)							\
265168754Sbushman		return (-1);						\
266168754Sbushman									\
267168754Sbushman	rv = 0;								\
268168754Sbushman	while (!feof(fi)) {						\
269299654Sngie		char *buf = fgetln(fi, &len);				\
270299654Sngie		if (buf == NULL || len <= 1)				\
271299654Sngie			continue;					\
272299654Sngie		if (buf[len - 1] == '\n')				\
273299654Sngie			buf[len - 1] = '\0';				\
274299654Sngie		else							\
275299654Sngie			buf[len] = '\0';				\
276299654Sngie		if (buf[0] == '#')					\
277299654Sngie			continue;					\
278299654Sngie		rv = read_func(&data, buf);				\
279299654Sngie		if (rv == 0) {						\
280299654Sngie			__##ent##_test_data_append(td, &data);		\
281299654Sngie			td->free_func(&data);				\
282299654Sngie		} else 							\
283299654Sngie			goto fin;					\
284168754Sbushman	}								\
285168754Sbushman									\
286168754Sbushmanfin:									\
287168754Sbushman	fclose(fi);							\
288168754Sbushman	return (rv);							\
289168754Sbushman}
290168754Sbushman
291168754Sbushman#define DECLARE_1PASS_TEST(ent)						\
292168754Sbushmanint __##ent##_1pass_test(struct ent##_test_data *, 			\
293168754Sbushman	int (*)(struct ent *, void *),					\
294291363Sngie	void *);
295291363Sngie
296168754Sbushman#define DO_1PASS_TEST(ent, td, f, mdata)				\
297168754Sbushman	__##ent##_1pass_test(td, f, mdata)
298168754Sbushman
299168754Sbushman#define IMPLEMENT_1PASS_TEST(ent)					\
300168754Sbushmanint									\
301168754Sbushman__##ent##_1pass_test(struct ent##_test_data *td, 			\
302168754Sbushman	int (*tf)(struct ent *, void *),				\
303168754Sbushman	void *mdata)							\
304168754Sbushman{									\
305168754Sbushman	int rv;								\
306168754Sbushman	rv = __##ent##_test_data_foreach(td, tf, mdata);		\
307168754Sbushman									\
308168754Sbushman	return (rv);							\
309168754Sbushman}
310168754Sbushman
311168754Sbushman#define DECLARE_2PASS_TEST(ent)						\
312168754Sbushmanint __##ent##_2pass_test(struct ent##_test_data *, 			\
313168754Sbushman	struct ent##_test_data *, 					\
314168754Sbushman	int (*)(struct ent *, struct ent *, void *), void *);
315168754Sbushman
316168754Sbushman#define DO_2PASS_TEST(ent, td1, td2, f, mdata)				\
317168754Sbushman	__##ent##_2pass_test(td1, td2, f, mdata)
318291363Sngie
319168754Sbushman#define IMPLEMENT_2PASS_TEST(ent)					\
320168754Sbushmanint									\
321168754Sbushman__##ent##_2pass_test(struct ent##_test_data *td1,			\
322168754Sbushman	struct ent##_test_data *td2,					\
323168754Sbushman	int (*cmp_func)(struct ent *, struct ent *, void *),		\
324168754Sbushman	void *cmp_mdata)						\
325168754Sbushman{									\
326168754Sbushman	int rv;								\
327168754Sbushman									\
328168754Sbushman	rv = __##ent##_test_data_compare(td1, td2, cmp_func, cmp_mdata);	\
329168754Sbushman	return (rv);							\
330168754Sbushman}
331