@@@ wip type definitions in manpage synopses
[mLib] / test / t / tvec-test.c
CommitLineData
b64eb60f
MW
1/* -*-c-*-
2 *
3 * Test the test-vector framework
4 *
5 * (c) 2023 Straylight/Edgeware
6 */
7
8/*----- Licensing notice --------------------------------------------------*
9 *
10 * This file is part of the mLib utilities library.
11 *
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.
16 *
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.
21 *
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,
25 * USA.
26 */
27
28/*----- Header files ------------------------------------------------------*/
29
30#include "tvec.h"
31
32/*----- Register definitions ----------------------------------------------*/
33
34enum {
35 /* Standard outputs. */
36 RRC, /* return code from deserialize */
37
38 /* Output registers, one for each register type. */
39 RI, RU, RIE, RUE, RPE, RF, RSTR, RBY, RBUF,
40
41 /* Additional diagnostic outputs. */
42 RSER, /* serialized data */
43
44 NROUT,
45
46 /* Some additional inputs. */
47 RSAB = NROUT, /* which register to sabotage */
48
49 NREG,
50
51 /* Single register for copy tests. */
52 RV = 0
53};
54
55static const struct tvec_iassoc ienum_assocs[] = {
56 { "less", -1 },
57 { "equal", 0 },
58 { "greater", +1 },
59 { 0 }
60};
61
62static const struct tvec_uassoc uenum_assocs[] = {
63 { "apple", 0 },
64 { "banana", 1 },
65 { "clementine", 2 },
66 { 0 }
67};
68
69static const struct tvec_passoc penum_assocs[] = {
70 { "alice", &uenum_assocs[0] },
71 { "bob", &uenum_assocs[1] },
72 { "carol", &uenum_assocs[2] },
73 { 0 }
74};
75
76#if __STDC_VERSION__ >= 199901
77# define DSGINIT(x) x
78#else
79# define DSGINIT(x)
80#endif
81
82static 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 } }) };
89
90static 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 },
99
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 },
108
109 { "normal", 0xc0, 0x00 },
110 { "bright", 0x40, 0x40 },
111 { "flash", 0x80, 0x80 },
112
113 { 0 }
114};
115
116static const struct tvec_flaginfo attr_info =
117 { "attr", attr_flags, &tvrange_u16 };
118
119static const struct tvec_urange range_32 = { 0, 31 };
120
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)
131
132/*----- Serialization test ------------------------------------------------*/
133
134struct test_context {
135 struct tvec_state *tv;
136};
137
138static void capture_state_and_run(struct tvec_state *tv)
139{
140 struct test_context tctx;
141
142 tctx.tv = tv; tv->test->fn(tv->in, tv->out, &tctx);
143 if (!(tv->in[RRC].f&TVRF_LIVE)) {
144 tv->in[RRC].v.i = 0;
145 tv->in[RRC].f |= TVRF_LIVE; tv->out[RRC].f |= TVRF_LIVE;
146 }
147 tvec_check(tv, 0);
148}
149
150static void test_serialization
151 (const struct tvec_reg *in, struct tvec_reg *out, void *ctx)
152{
153 struct test_context *tctx = ctx;
154 struct tvec_state *tv = tctx->tv;
155 const struct tvec_regdef *rd;
156 union tvec_regval *rv;
157 void *p; size_t sz;
158
159 if (tvec_serialize(tv->in, tv->test->regs,
160 NROUT, sizeof(struct tvec_reg), &p, &sz))
161 { out[RRC].v.i = -1; return; }
162 out[RSER].f |= TVRF_LIVE;
163 out[RSER].v.bytes.p = p; out[RSER].v.bytes.sz = sz;
164
165 if (tvec_deserialize(tv->out, tv->test->regs,
166 NROUT, sizeof(struct tvec_reg), p, sz))
167 { out[RRC].v.i = -1; return; }
168
169 if (in[RSAB].f&TVRF_LIVE) {
170 for (rd = tv->test->regs; rd->name; rd++)
171 if (STRCMP(in[RSAB].v.str.p, ==, rd->name)) {
172 rv = &out[rd->i].v;
173 if (rd->ty == &tvty_int ||
174 (rd->ty == &tvty_enum &&
175 ((struct tvec_enuminfo *)rd->arg.p)->mv == TVMISC_INT))
176 rv->i ^= 1;
177 else if (rd->ty == &tvty_uint || rd->ty == &tvty_flags ||
178 (rd->ty == &tvty_enum &&
179 ((struct tvec_enuminfo *)rd->arg.p)->mv == TVMISC_INT))
180 rv->u ^= 1;
181 else if (rd->ty == &tvty_string)
182 { if (rv->str.sz) rv->str.p[0] ^= 1; }
183 else if (rd->ty == &tvty_bytes)
184 { if (rv->bytes.sz) rv->bytes.p[0] ^= 1; }
185 }
186 }
187
188 out[RRC].v.i = 0;
189}
190
191DSGINIT(static) const struct tvec_regdef test_regs[] = {
192#define DEFREG(name, i, ty, argslot, argval) \
193 { #name, i, &tvty_##ty, TVRF_OPT, \
194 DSGINIT({ .argslot = argval }) },
195 TYPEREGS(DEFREG)
196#undef DEFREG
197 { "rc", RRC, &tvty_int, TVRF_OPT, { &tvrange_int } },
198 { "serialized", RSER, &tvty_bytes, TVRF_OPT },
199 { "sabotage", RSAB, &tvty_string, TVRF_OPT, { &tvrange_byte } },
200
201 { 0 }
202};
203
204/*----- Single-type copy tests --------------------------------------------*/
205
206static void test_copy_simple
207 (const struct tvec_reg *in, struct tvec_reg *out, void *ctx)
208 { out->v = in->v; }
209
210static void test_copy_string
211 (const struct tvec_reg *in, struct tvec_reg *out, void *ctx)
212{
213 tvec_allocstring(&out->v, in->v.str.sz);
214 memcpy(out->v.str.p, in->v.str.p, in->v.str.sz);
215}
216
217static void test_copy_bytes
218 (const struct tvec_reg *in, struct tvec_reg *out, void *ctx)
219{
220 tvec_allocstring(&out->v, in->v.str.sz);
221 memcpy(out->v.str.p, in->v.str.p, in->v.str.sz);
222}
223
224#define test_copy_int test_copy_simple
225#define test_copy_uint test_copy_simple
226#define test_copy_ienum test_copy_simple
227#define test_copy_uenum test_copy_simple
228#define test_copy_penum test_copy_simple
229#define test_copy_flags test_copy_simple
230#define test_copy_buffer test_copy_bytes
231
232#define SINGLEREG(name, i, ty, argslot, argval) \
233 DSGINIT(const) struct tvec_regdef name##_regs[] = { \
234 { #name, RV, &tvty_##ty, 0, DSGINIT({ .argslot = argval }) }, \
235 { 0 } \
236 };
237TYPEREGS(SINGLEREG)
238#undef SINGLEREG
239
240/*----- Front end ---------------------------------------------------------*/
241
242static const struct tvec_test tests[] = {
243 { "types", test_regs, 0, capture_state_and_run,
244 test_serialization },
245
246#define DEFCOPY(name, i, ty, argslot, argval) \
247 { #name, name##_regs, 0, tvec_runtest, test_copy_##name },
248 TYPEREGS(DEFCOPY)
249#undef DEFCOPY
250
251 { 0 }
252};
253
254static const struct tvec_info testinfo = {
255 tests,
256 NROUT, NREG, sizeof(struct tvec_reg)
257};
258
259int main(int argc, char *argv[])
260{
261#if __STDC_VERSION__ < 199901
262# define POKE(tag, ty, slot) \
263 slot##enum_info.u.slot.av = slot##enum_assocs; \
264 TVEC_MISCSLOTS(POKE)
265# undef POKE
266# define POKE(name, i, ty, argslot, argval) \
267 name##_regs->arg.argslot = argval;
268 TYPEREGS(POKE)
269# undef POKE
270#endif
271 return (tvec_main(argc, argv, &testinfo, 0));
272}
273
274/*----- That's all, folks -------------------------------------------------*/