Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/lib/libc/tests/nss/testutil.h
39491 views
1
/*-
2
* Copyright (c) 2006 Michael Bushkov <[email protected]>
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
330