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