xref: /freebsd-src/lib/libc/tests/nss/testutil.h (revision b3e7694832e81d7a904a10f525f8797b753bf0d3)
108ca345cSEnji Cooper /*-
208ca345cSEnji Cooper  * Copyright (c) 2006 Michael Bushkov <bushman@freebsd.org>
308ca345cSEnji Cooper  *
408ca345cSEnji Cooper  * Redistribution and use in source and binary forms, with or without
508ca345cSEnji Cooper  * modification, are permitted provided that the following conditions
608ca345cSEnji Cooper  * are met:
708ca345cSEnji Cooper  * 1. Redistributions of source code must retain the above copyright
808ca345cSEnji Cooper  *    notice, this list of conditions and the following disclaimer.
908ca345cSEnji Cooper  * 2. Redistributions in binary form must reproduce the above copyright
1008ca345cSEnji Cooper  *    notice, this list of conditions and the following disclaimer in the
1108ca345cSEnji Cooper  *    documentation and/or other materials provided with the distribution.
1208ca345cSEnji Cooper  *
1308ca345cSEnji Cooper  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1408ca345cSEnji Cooper  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1508ca345cSEnji Cooper  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1608ca345cSEnji Cooper  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1708ca345cSEnji Cooper  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1808ca345cSEnji Cooper  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
1908ca345cSEnji Cooper  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2008ca345cSEnji Cooper  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2108ca345cSEnji Cooper  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2208ca345cSEnji Cooper  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2308ca345cSEnji Cooper  * SUCH DAMAGE.
2408ca345cSEnji Cooper  */
2508ca345cSEnji Cooper 
2608ca345cSEnji Cooper #include <sys/queue.h>
2708ca345cSEnji Cooper 
2808ca345cSEnji Cooper #define DECLARE_TEST_DATA(ent)						\
2908ca345cSEnji Cooper struct ent##_entry {							\
3008ca345cSEnji Cooper 	struct ent data;						\
3108ca345cSEnji Cooper 	STAILQ_ENTRY(ent##_entry) entries;				\
3208ca345cSEnji Cooper };									\
3308ca345cSEnji Cooper 									\
3408ca345cSEnji Cooper struct ent##_test_data {						\
3508ca345cSEnji Cooper 	void (*clone_func)(struct ent *, struct ent const *);		\
3608ca345cSEnji Cooper 	void (*free_func)(struct ent *);				\
3708ca345cSEnji Cooper 									\
3808ca345cSEnji Cooper 	STAILQ_HEAD(ent_head, ent##_entry) snapshot_data;		\
3908ca345cSEnji Cooper };									\
4008ca345cSEnji Cooper 									\
4108ca345cSEnji Cooper void __##ent##_test_data_init(struct ent##_test_data *, 		\
4208ca345cSEnji Cooper 	void (*)(struct ent *, struct ent const *),			\
4308ca345cSEnji Cooper 	void (*freef)(struct ent *));		 			\
4408ca345cSEnji Cooper void __##ent##_test_data_destroy(struct ent##_test_data *);		\
4508ca345cSEnji Cooper 									\
4608ca345cSEnji Cooper void __##ent##_test_data_append(struct ent##_test_data *, struct ent *data);\
4708ca345cSEnji Cooper int __##ent##_test_data_foreach(struct ent##_test_data *,		\
4808ca345cSEnji Cooper 	int (*)(struct ent *, void *), void *);				\
4908ca345cSEnji Cooper int __##ent##_test_data_compare(struct ent##_test_data *,		\
5008ca345cSEnji Cooper 	struct ent##_test_data *, int (*)(struct ent *, struct ent *,	\
5108ca345cSEnji Cooper 	void *), void *);						\
5208ca345cSEnji Cooper struct ent *__##ent##_test_data_find(struct ent##_test_data *, struct ent *,\
5308ca345cSEnji Cooper 	int (*)(struct ent *, struct ent *, void *), void *);		\
5408ca345cSEnji Cooper void __##ent##_test_data_clear(struct ent##_test_data *);
5508ca345cSEnji Cooper 
5608ca345cSEnji Cooper #define TEST_DATA_INIT(ent, td, clonef, freef)\
5708ca345cSEnji Cooper 	__##ent##_test_data_init(td, clonef, freef)
5808ca345cSEnji Cooper #define TEST_DATA_DESTROY(ent, td) __##ent##_test_data_destroy(td)
5908ca345cSEnji Cooper #define TEST_DATA_APPEND(ent, td, d) __##ent##_test_data_append(td, d)
6008ca345cSEnji Cooper #define TEST_DATA_FOREACH(ent, td, f, mdata)\
6108ca345cSEnji Cooper 	__##ent##_test_data_foreach(td, f, mdata)
6208ca345cSEnji Cooper #define TEST_DATA_COMPARE(ent, td1, td2, fcmp, mdata)\
6308ca345cSEnji Cooper 	__##ent##_test_data_compare(td1, td2, fcmp, mdata);
6408ca345cSEnji Cooper #define TEST_DATA_FIND(ent, td, d, fcmp, mdata)\
6508ca345cSEnji Cooper 	__##ent##_test_data_find(td, d, fcmp, mdata)
6608ca345cSEnji Cooper #define TEST_DATA_CLEAR(ent, td) __##ent##_test_data_clear(td)
6708ca345cSEnji Cooper 
6808ca345cSEnji Cooper #define IMPLEMENT_TEST_DATA(ent)					\
6908ca345cSEnji Cooper void									\
7008ca345cSEnji Cooper __##ent##_test_data_init(struct ent##_test_data *td,			\
7108ca345cSEnji Cooper 	void (*clonef)(struct ent *, struct ent const *),		\
7208ca345cSEnji Cooper 	void (*freef)(struct ent *))					\
7308ca345cSEnji Cooper {									\
7408ca345cSEnji Cooper 	ATF_REQUIRE(td != NULL);					\
7508ca345cSEnji Cooper 	ATF_REQUIRE(clonef != NULL);					\
7608ca345cSEnji Cooper 	ATF_REQUIRE(freef != NULL);					\
7708ca345cSEnji Cooper 									\
7808ca345cSEnji Cooper 	memset(td, 0, sizeof(*td));					\
7908ca345cSEnji Cooper 	td->clone_func = clonef;					\
8008ca345cSEnji Cooper 	td->free_func = freef;						\
8108ca345cSEnji Cooper 	STAILQ_INIT(&td->snapshot_data);				\
8208ca345cSEnji Cooper }									\
8308ca345cSEnji Cooper 									\
8408ca345cSEnji Cooper void 									\
8508ca345cSEnji Cooper __##ent##_test_data_destroy(struct ent##_test_data *td)			\
8608ca345cSEnji Cooper {									\
8708ca345cSEnji Cooper 	__##ent##_test_data_clear(td);					\
8808ca345cSEnji Cooper }									\
8908ca345cSEnji Cooper 									\
9008ca345cSEnji Cooper void 									\
9108ca345cSEnji Cooper __##ent##_test_data_append(struct ent##_test_data *td, struct ent *app_data)\
9208ca345cSEnji Cooper {									\
9308ca345cSEnji Cooper 	struct ent##_entry *e;						\
9408ca345cSEnji Cooper 									\
9508ca345cSEnji Cooper 	ATF_REQUIRE(td != NULL);					\
9608ca345cSEnji Cooper 	ATF_REQUIRE(app_data != NULL);					\
9708ca345cSEnji Cooper 									\
9808ca345cSEnji Cooper 	e = (struct ent##_entry *)malloc(sizeof(struct ent##_entry));	\
9908ca345cSEnji Cooper 	ATF_REQUIRE(e != NULL);						\
10008ca345cSEnji Cooper 	memset(e, 0, sizeof(struct ent##_entry));			\
10108ca345cSEnji Cooper 									\
10208ca345cSEnji Cooper 	td->clone_func(&e->data, app_data);				\
10308ca345cSEnji Cooper 	STAILQ_INSERT_TAIL(&td->snapshot_data, e, entries);		\
10408ca345cSEnji Cooper }									\
10508ca345cSEnji Cooper 									\
10608ca345cSEnji Cooper int									\
10708ca345cSEnji Cooper __##ent##_test_data_foreach(struct ent##_test_data *td,			\
10808ca345cSEnji Cooper 	int (*forf)(struct ent *, void *), void *mdata)			\
10908ca345cSEnji Cooper {									\
11008ca345cSEnji Cooper 	struct ent##_entry *e;						\
11108ca345cSEnji Cooper 	int rv;								\
11208ca345cSEnji Cooper 									\
11308ca345cSEnji Cooper 	ATF_REQUIRE(td != NULL);					\
11408ca345cSEnji Cooper 	ATF_REQUIRE(forf != NULL);					\
11508ca345cSEnji Cooper 									\
11608ca345cSEnji Cooper 	rv = 0;								\
11708ca345cSEnji Cooper 	STAILQ_FOREACH(e, &td->snapshot_data, entries) {		\
11808ca345cSEnji Cooper 		rv = forf(&e->data, mdata);				\
11908ca345cSEnji Cooper 		if (rv != 0)						\
12008ca345cSEnji Cooper 			break;						\
12108ca345cSEnji Cooper 	}								\
12208ca345cSEnji Cooper 									\
12308ca345cSEnji Cooper 	return (rv);							\
12408ca345cSEnji Cooper }									\
12508ca345cSEnji Cooper 									\
12608ca345cSEnji Cooper int									\
12708ca345cSEnji Cooper __##ent##_test_data_compare(struct ent##_test_data *td1, struct ent##_test_data *td2,\
12808ca345cSEnji Cooper 	int (*cmp_func)(struct ent *, struct ent *, void *), void *mdata)\
12908ca345cSEnji Cooper {									\
13008ca345cSEnji Cooper 	struct ent##_entry *e1, *e2;					\
13108ca345cSEnji Cooper 	int rv;								\
13208ca345cSEnji Cooper 									\
13308ca345cSEnji Cooper 	ATF_REQUIRE(td1 != NULL);					\
13408ca345cSEnji Cooper 	ATF_REQUIRE(td2 != NULL);					\
13508ca345cSEnji Cooper 	ATF_REQUIRE(cmp_func != NULL);					\
13608ca345cSEnji Cooper 									\
13708ca345cSEnji Cooper 	e1 = STAILQ_FIRST(&td1->snapshot_data);				\
13808ca345cSEnji Cooper 	e2 = STAILQ_FIRST(&td2->snapshot_data);				\
13908ca345cSEnji Cooper 									\
14008ca345cSEnji Cooper 	rv = 0;								\
14108ca345cSEnji Cooper 	do {								\
14208ca345cSEnji Cooper 		if ((e1 == NULL) || (e2 == NULL)) {			\
14308ca345cSEnji Cooper 			if (e1 == e2)					\
14408ca345cSEnji Cooper 				return (0);				\
14508ca345cSEnji Cooper 			else						\
14608ca345cSEnji Cooper 				return (-1);				\
14708ca345cSEnji Cooper 		}							\
14808ca345cSEnji Cooper 									\
14908ca345cSEnji Cooper 		rv = cmp_func(&e1->data, &e2->data, mdata);		\
15008ca345cSEnji Cooper 		e1 = STAILQ_NEXT(e1, entries);				\
15108ca345cSEnji Cooper 		e2 = STAILQ_NEXT(e2, entries);				\
15208ca345cSEnji Cooper 	} while (rv == 0);						\
15308ca345cSEnji Cooper 									\
15408ca345cSEnji Cooper 	return (rv);							\
15508ca345cSEnji Cooper }									\
15608ca345cSEnji Cooper 									\
15708ca345cSEnji Cooper struct ent *								\
15808ca345cSEnji Cooper __##ent##_test_data_find(struct ent##_test_data *td, struct ent *data,	\
15908ca345cSEnji Cooper 	int (*cmp)(struct ent *, struct ent *, void *), void *mdata)	\
16008ca345cSEnji Cooper {									\
16108ca345cSEnji Cooper 	struct ent##_entry *e;						\
16208ca345cSEnji Cooper 	struct ent *result;						\
16308ca345cSEnji Cooper 									\
16408ca345cSEnji Cooper 	ATF_REQUIRE(td != NULL);					\
16508ca345cSEnji Cooper 	ATF_REQUIRE(cmp != NULL);					\
16608ca345cSEnji Cooper 									\
16708ca345cSEnji Cooper 	result = NULL;							\
16808ca345cSEnji Cooper 	STAILQ_FOREACH(e, &td->snapshot_data, entries) {		\
16908ca345cSEnji Cooper 		if (cmp(&e->data, data, mdata) == 0) {			\
17008ca345cSEnji Cooper 			result = &e->data;				\
17108ca345cSEnji Cooper 			break;						\
17208ca345cSEnji Cooper 		}							\
17308ca345cSEnji Cooper 	}								\
17408ca345cSEnji Cooper 									\
17508ca345cSEnji Cooper 	return (result);						\
17608ca345cSEnji Cooper }									\
17708ca345cSEnji Cooper 									\
17808ca345cSEnji Cooper 									\
17908ca345cSEnji Cooper void									\
18008ca345cSEnji Cooper __##ent##_test_data_clear(struct ent##_test_data *td)			\
18108ca345cSEnji Cooper {									\
18208ca345cSEnji Cooper 	struct ent##_entry *e;						\
18308ca345cSEnji Cooper 	ATF_REQUIRE(td != NULL);					\
18408ca345cSEnji Cooper 									\
18508ca345cSEnji Cooper 	while (!STAILQ_EMPTY(&td->snapshot_data)) {			\
18608ca345cSEnji Cooper 		e = STAILQ_FIRST(&td->snapshot_data);			\
18708ca345cSEnji Cooper 		STAILQ_REMOVE_HEAD(&td->snapshot_data, entries);	\
18808ca345cSEnji Cooper 									\
18908ca345cSEnji Cooper 		td->free_func(&e->data);				\
19008ca345cSEnji Cooper 		free(e);						\
19108ca345cSEnji Cooper 		e = NULL;						\
19208ca345cSEnji Cooper 	}								\
19308ca345cSEnji Cooper }
19408ca345cSEnji Cooper 
19508ca345cSEnji Cooper #define DECLARE_TEST_FILE_SNAPSHOT(ent)					\
19608ca345cSEnji Cooper struct ent##_snp_param {						\
19708ca345cSEnji Cooper 	FILE *fp;							\
19808ca345cSEnji Cooper 	void (*sdump_func)(struct ent *, char *, size_t);		\
19908ca345cSEnji Cooper };									\
20008ca345cSEnji Cooper 									\
20108ca345cSEnji Cooper int __##ent##_snapshot_write_func(struct ent *, void *);		\
20208ca345cSEnji Cooper int __##ent##_snapshot_write(char const *, struct ent##_test_data *,	\
20308ca345cSEnji Cooper 	void (*)(struct ent *, char *, size_t));			\
20408ca345cSEnji Cooper int __##ent##_snapshot_read(char const *, struct ent##_test_data *,	\
20508ca345cSEnji Cooper 	int (*)(struct ent *, char *));
20608ca345cSEnji Cooper 
20708ca345cSEnji Cooper #define TEST_SNAPSHOT_FILE_WRITE(ent, fname, td, f)			\
20808ca345cSEnji Cooper 	__##ent##_snapshot_write(fname, td, f)
20908ca345cSEnji Cooper #define TEST_SNAPSHOT_FILE_READ(ent, fname, td, f)			\
21008ca345cSEnji Cooper 	__##ent##_snapshot_read(fname, td, f)
21108ca345cSEnji Cooper 
21208ca345cSEnji Cooper #define IMPLEMENT_TEST_FILE_SNAPSHOT(ent)				\
21308ca345cSEnji Cooper int									\
21408ca345cSEnji Cooper __##ent##_snapshot_write_func(struct ent *data, void *mdata)		\
21508ca345cSEnji Cooper {									\
21608ca345cSEnji Cooper 	char buffer[1024];						\
21708ca345cSEnji Cooper 	struct ent##_snp_param *param;					\
21808ca345cSEnji Cooper 									\
21908ca345cSEnji Cooper 	ATF_REQUIRE(data != NULL);					\
22008ca345cSEnji Cooper 									\
22108ca345cSEnji Cooper 	param = (struct ent##_snp_param *)mdata;			\
22208ca345cSEnji Cooper 	param->sdump_func(data, buffer, sizeof(buffer));		\
22308ca345cSEnji Cooper 	fputs(buffer, param->fp);					\
22408ca345cSEnji Cooper 	fputc('\n', param->fp);						\
22508ca345cSEnji Cooper 									\
22608ca345cSEnji Cooper 	return (0);							\
22708ca345cSEnji Cooper }									\
22808ca345cSEnji Cooper 									\
22908ca345cSEnji Cooper int									\
23008ca345cSEnji Cooper __##ent##_snapshot_write(char const *fname, struct ent##_test_data *td,	\
23108ca345cSEnji Cooper 	void (*sdump_func)(struct ent *, char *, size_t))		\
23208ca345cSEnji Cooper {									\
23308ca345cSEnji Cooper 	struct ent##_snp_param	param;					\
23408ca345cSEnji Cooper 									\
23508ca345cSEnji Cooper 	ATF_REQUIRE(fname != NULL);					\
23608ca345cSEnji Cooper 	ATF_REQUIRE(td != NULL);					\
23708ca345cSEnji Cooper 									\
23808ca345cSEnji Cooper 	param.fp = fopen(fname, "w");					\
23908ca345cSEnji Cooper 	if (param.fp == NULL)						\
24008ca345cSEnji Cooper 		return (-1);						\
24108ca345cSEnji Cooper 									\
24208ca345cSEnji Cooper 	param.sdump_func = sdump_func;					\
24308ca345cSEnji Cooper 	__##ent##_test_data_foreach(td, __##ent##_snapshot_write_func, &param);\
24408ca345cSEnji Cooper 	fclose(param.fp);						\
24508ca345cSEnji Cooper 									\
24608ca345cSEnji Cooper 	return (0);							\
24708ca345cSEnji Cooper }									\
24808ca345cSEnji Cooper 									\
24908ca345cSEnji Cooper int									\
25008ca345cSEnji Cooper __##ent##_snapshot_read(char const *fname, struct ent##_test_data *td,	\
25108ca345cSEnji Cooper 	int (*read_func)(struct ent *, char *))				\
25208ca345cSEnji Cooper {									\
25308ca345cSEnji Cooper 	struct ent data;						\
25408ca345cSEnji Cooper 	FILE *fi;							\
25508ca345cSEnji Cooper 	size_t len;							\
25608ca345cSEnji Cooper 	int rv;								\
25708ca345cSEnji Cooper 									\
25808ca345cSEnji Cooper 	ATF_REQUIRE(fname != NULL);					\
25908ca345cSEnji Cooper 	ATF_REQUIRE(td != NULL);					\
26008ca345cSEnji Cooper 									\
26108ca345cSEnji Cooper 	fi = fopen(fname, "r");						\
26208ca345cSEnji Cooper 	if (fi == NULL)							\
26308ca345cSEnji Cooper 		return (-1);						\
26408ca345cSEnji Cooper 									\
26508ca345cSEnji Cooper 	rv = 0;								\
26608ca345cSEnji Cooper 	while (!feof(fi)) {						\
267*32855711SEnji Cooper 		char *buf = fgetln(fi, &len);				\
268*32855711SEnji Cooper 		if (buf == NULL || len <= 1)				\
26908ca345cSEnji Cooper 			continue;					\
270*32855711SEnji Cooper 		if (buf[len - 1] == '\n')				\
271*32855711SEnji Cooper 			buf[len - 1] = '\0';				\
272*32855711SEnji Cooper 		else							\
273*32855711SEnji Cooper 			buf[len] = '\0';				\
274*32855711SEnji Cooper 		if (buf[0] == '#')					\
275*32855711SEnji Cooper 			continue;					\
276*32855711SEnji Cooper 		rv = read_func(&data, buf);				\
27708ca345cSEnji Cooper 		if (rv == 0) {						\
27808ca345cSEnji Cooper 			__##ent##_test_data_append(td, &data);		\
27908ca345cSEnji Cooper 			td->free_func(&data);				\
28008ca345cSEnji Cooper 		} else 							\
28108ca345cSEnji Cooper 			goto fin;					\
28208ca345cSEnji Cooper 	}								\
28308ca345cSEnji Cooper 									\
28408ca345cSEnji Cooper fin:									\
28508ca345cSEnji Cooper 	fclose(fi);							\
28608ca345cSEnji Cooper 	return (rv);							\
28708ca345cSEnji Cooper }
28808ca345cSEnji Cooper 
28908ca345cSEnji Cooper #define DECLARE_1PASS_TEST(ent)						\
29008ca345cSEnji Cooper int __##ent##_1pass_test(struct ent##_test_data *, 			\
29108ca345cSEnji Cooper 	int (*)(struct ent *, void *),					\
29208ca345cSEnji Cooper 	void *);
29308ca345cSEnji Cooper 
29408ca345cSEnji Cooper #define DO_1PASS_TEST(ent, td, f, mdata)				\
29508ca345cSEnji Cooper 	__##ent##_1pass_test(td, f, mdata)
29608ca345cSEnji Cooper 
29708ca345cSEnji Cooper #define IMPLEMENT_1PASS_TEST(ent)					\
29808ca345cSEnji Cooper int									\
29908ca345cSEnji Cooper __##ent##_1pass_test(struct ent##_test_data *td, 			\
30008ca345cSEnji Cooper 	int (*tf)(struct ent *, void *),				\
30108ca345cSEnji Cooper 	void *mdata)							\
30208ca345cSEnji Cooper {									\
30308ca345cSEnji Cooper 	int rv;								\
30408ca345cSEnji Cooper 	rv = __##ent##_test_data_foreach(td, tf, mdata);		\
30508ca345cSEnji Cooper 									\
30608ca345cSEnji Cooper 	return (rv);							\
30708ca345cSEnji Cooper }
30808ca345cSEnji Cooper 
30908ca345cSEnji Cooper #define DECLARE_2PASS_TEST(ent)						\
31008ca345cSEnji Cooper int __##ent##_2pass_test(struct ent##_test_data *, 			\
31108ca345cSEnji Cooper 	struct ent##_test_data *, 					\
31208ca345cSEnji Cooper 	int (*)(struct ent *, struct ent *, void *), void *);
31308ca345cSEnji Cooper 
31408ca345cSEnji Cooper #define DO_2PASS_TEST(ent, td1, td2, f, mdata)				\
31508ca345cSEnji Cooper 	__##ent##_2pass_test(td1, td2, f, mdata)
31608ca345cSEnji Cooper 
31708ca345cSEnji Cooper #define IMPLEMENT_2PASS_TEST(ent)					\
31808ca345cSEnji Cooper int									\
31908ca345cSEnji Cooper __##ent##_2pass_test(struct ent##_test_data *td1,			\
32008ca345cSEnji Cooper 	struct ent##_test_data *td2,					\
32108ca345cSEnji Cooper 	int (*cmp_func)(struct ent *, struct ent *, void *),		\
32208ca345cSEnji Cooper 	void *cmp_mdata)						\
32308ca345cSEnji Cooper {									\
32408ca345cSEnji Cooper 	int rv;								\
32508ca345cSEnji Cooper 									\
32608ca345cSEnji Cooper 	rv = __##ent##_test_data_compare(td1, td2, cmp_func, cmp_mdata);\
32708ca345cSEnji Cooper 	return (rv);							\
32808ca345cSEnji Cooper }
329