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