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 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, ¶m);\ 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