3 * Test the test-vector framework
5 * (c) 2023 Straylight/Edgeware
8 /*----- Licensing notice --------------------------------------------------*
10 * This file is part of the mLib utilities library.
12 * mLib is free software: you can redistribute it and/or modify it under
13 * the terms of the GNU Library General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or (at
15 * your option) any later version.
17 * mLib is distributed in the hope that it will be useful, but WITHOUT
18 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
19 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
20 * License for more details.
22 * You should have received a copy of the GNU Library General Public
23 * License along with mLib. If not, write to the Free Software
24 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
28 /*----- Header files ------------------------------------------------------*/
32 /*----- Register definitions ----------------------------------------------*/
35 /* Standard outputs. */
36 RRC, /* return code from deserialize */
38 /* Output registers, one for each register type. */
39 RI, RU, RIE, RUE, RPE, RF, RSTR, RBY, RBUF,
41 /* Additional diagnostic outputs. */
42 RSER, /* serialized data */
46 /* Some additional inputs. */
47 RSAB = NROUT, /* which register to sabotage */
51 /* Single register for copy tests. */
55 static const struct tvec_iassoc ienum_assocs[] = {
62 static const struct tvec_uassoc uenum_assocs[] = {
69 static const struct tvec_passoc penum_assocs[] = {
70 { "alice", &uenum_assocs[0] },
71 { "bob", &uenum_assocs[1] },
72 { "carol", &uenum_assocs[2] },
76 #if __STDC_VERSION__ >= 199901
82 static DSGINIT(const) struct tvec_enuminfo
83 ienum_info = { "order", TVMISC_INT,
84 DSGINIT({ .i = { ienum_assocs COMMA &tvrange_i16 } }) },
85 uenum_info = { "fruit", TVMISC_UINT,
86 DSGINIT({ .u = { uenum_assocs COMMA &tvrange_u16 } }) },
87 penum_info = { "player", TVMISC_PTR,
88 DSGINIT({ .p = { penum_assocs } }) };
90 static const struct tvec_flag attr_flags[] = {
91 { "black-fg", 0x07, 0x00 },
92 { "blue-fg", 0x07, 0x01 },
93 { "red-fg", 0x07, 0x02 },
94 { "magenta-fg", 0x07, 0x03 },
95 { "green-fg", 0x07, 0x04 },
96 { "cyan-fg", 0x07, 0x05 },
97 { "yellow-fg", 0x07, 0x06 },
98 { "white-fg", 0x07, 0x07 },
100 { "black-bg", 0x38, 0x00 },
101 { "blue-bg", 0x38, 0x08 },
102 { "red-bg", 0x38, 0x10 },
103 { "magenta-bg", 0x38, 0x18 },
104 { "green-bg", 0x38, 0x20 },
105 { "cyan-bg", 0x38, 0x28 },
106 { "yellow-bg", 0x38, 0x30 },
107 { "white-bg", 0x38, 0x38 },
109 { "normal", 0xc0, 0x00 },
110 { "bright", 0x40, 0x40 },
111 { "flash", 0x80, 0x80 },
116 static const struct tvec_flaginfo attr_info =
117 { "attr", attr_flags, &tvrange_u16 };
119 static const struct tvec_urange range_32 = { 0, 31 };
121 #define TYPEREGS(_) \
122 _(int, RI, int, p, &tvrange_i16) \
123 _(uint, RU, uint, p, &tvrange_u16) \
124 _(ienum, RIE, enum, p, &ienum_info) \
125 _(uenum, RUE, enum, p, &uenum_info) \
126 _(penum, RPE, enum, p, &penum_info) \
127 _(flags, RF, flags, p, &attr_info) \
128 _(string, RSTR, string, p, &range_32) \
129 _(bytes, RBY, bytes, p, &tvrange_byte) \
130 _(buffer, RBUF, buffer, p, &tvrange_u16)
132 /*----- Serialization test ------------------------------------------------*/
134 struct test_context {
135 struct tvec_state *tv;
138 static int capture_state_and_run(struct tvec_state *tv)
140 struct test_context tctx;
142 tctx.tv = tv; tv->test->fn(tv->in, tv->out, &tctx);
143 if (!(tv->in[RRC].f&TVRF_LIVE)) {
145 tv->in[RRC].f |= TVRF_LIVE; tv->out[RRC].f |= TVRF_LIVE;
151 static void test_serialization
152 (const struct tvec_reg *in, struct tvec_reg *out, void *ctx)
154 struct test_context *tctx = ctx;
155 struct tvec_state *tv = tctx->tv;
156 const struct tvec_regdef *rd;
157 union tvec_regval *rv;
160 if (tvec_serialize(tv->in, tv->test->regs,
161 NROUT, sizeof(struct tvec_reg), &p, &sz))
162 { out[RRC].v.i = -1; return; }
163 out[RSER].f |= TVRF_LIVE;
164 out[RSER].v.bytes.p = p; out[RSER].v.bytes.sz = sz;
166 if (tvec_deserialize(tv->out, tv->test->regs,
167 NROUT, sizeof(struct tvec_reg), p, sz))
168 { out[RRC].v.i = -1; return; }
170 if (in[RSAB].f&TVRF_LIVE) {
171 for (rd = tv->test->regs; rd->name; rd++)
172 if (STRCMP(in[RSAB].v.str.p, ==, rd->name)) {
174 if (rd->ty == &tvty_int ||
175 (rd->ty == &tvty_enum &&
176 ((struct tvec_enuminfo *)rd->arg.p)->mv == TVMISC_INT))
178 else if (rd->ty == &tvty_uint || rd->ty == &tvty_flags ||
179 (rd->ty == &tvty_enum &&
180 ((struct tvec_enuminfo *)rd->arg.p)->mv == TVMISC_INT))
182 else if (rd->ty == &tvty_string)
183 { if (rv->str.sz) rv->str.p[0] ^= 1; }
184 else if (rd->ty == &tvty_bytes)
185 { if (rv->bytes.sz) rv->bytes.p[0] ^= 1; }
192 DSGINIT(static) const struct tvec_regdef test_regs[] = {
193 #define DEFREG(name, i, ty, argslot, argval) \
194 { #name, i, &tvty_##ty, TVRF_OPT, \
195 DSGINIT({ .argslot = argval }) },
198 { "rc", RRC, &tvty_int, TVRF_OPT, { &tvrange_int } },
199 { "serialized", RSER, &tvty_bytes, TVRF_OPT },
200 { "sabotage", RSAB, &tvty_string, TVRF_OPT, { &tvrange_byte } },
205 /*----- Single-type copy tests --------------------------------------------*/
207 static void test_copy_simple
208 (const struct tvec_reg *in, struct tvec_reg *out, void *ctx)
211 static void test_copy_string
212 (const struct tvec_reg *in, struct tvec_reg *out, void *ctx)
214 tvec_allocstring(&out->v, in->v.str.sz);
215 memcpy(out->v.str.p, in->v.str.p, in->v.str.sz);
218 static void test_copy_bytes
219 (const struct tvec_reg *in, struct tvec_reg *out, void *ctx)
221 tvec_allocstring(&out->v, in->v.str.sz);
222 memcpy(out->v.str.p, in->v.str.p, in->v.str.sz);
225 #define test_copy_int test_copy_simple
226 #define test_copy_uint test_copy_simple
227 #define test_copy_ienum test_copy_simple
228 #define test_copy_uenum test_copy_simple
229 #define test_copy_penum test_copy_simple
230 #define test_copy_flags test_copy_simple
231 #define test_copy_buffer test_copy_bytes
233 #define SINGLEREG(name, i, ty, argslot, argval) \
234 DSGINIT(const) struct tvec_regdef name##_regs[] = { \
235 { #name, RV, &tvty_##ty, 0, DSGINIT({ .argslot = argval }) }, \
241 /*----- Front end ---------------------------------------------------------*/
243 static const struct tvec_test tests[] = {
244 { "types", test_regs, 0, capture_state_and_run,
245 test_serialization },
247 #define DEFCOPY(name, i, ty, argslot, argval) \
248 { #name, name##_regs, 0, tvec_runtest, test_copy_##name },
255 static const struct tvec_info testinfo = {
257 NROUT, NREG, sizeof(struct tvec_reg)
260 int main(int argc, char *argv[])
262 #if __STDC_VERSION__ < 199901
263 # define POKE(tag, ty, slot) \
264 slot##enum_info.u.slot.av = slot##enum_assocs; \
267 # define POKE(name, i, ty, argslot, argval) \
268 name##_regs->arg.argslot = argval;
272 return (tvec_main(argc, argv, &testinfo, 0));
275 /*----- That's all, folks -------------------------------------------------*/