@@@ fltfmt mess
[mLib] / test / tvec.h
1 /* -*-c-*-
2 *
3 * Test vector processing 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 #ifndef MLIB_TVEC_H
29 #define MLIB_TVEC_H
30
31 #ifdef __cplusplus
32 extern "C" {
33 #endif
34
35 /* Here's the overall flow for a testing session.
36 *
37 * @tvec_begin@
38 * -> output @bsession@
39 * @tvec_read@
40 * -> output @bgroup@
41 * -> env @setup@
42 * one or more tests
43 * -> type @init@ (input and output)
44 * -> type @parse@ (input)
45 * -> output @btest@
46 * -> env @before@
47 * -> @tvec_skipgroup@
48 * -> output @skipgroup@
49 * -> env @run@
50 * -> @tvec_skip@
51 * -> output @skip@
52 * -> test @fn@
53 * -> @tvec_checkregs@
54 * -> type @eq@
55 * -> @tvec_fail@
56 * -> output @fail@
57 * -> @tvec_mismatch@
58 * -> output @dumpreg@
59 * -> type @dump@
60 * -> output @etest@
61 * -> env @after@
62 * finally
63 * -> output @egroup@
64 * -> env @teardown@
65 *
66 * @tvec_adhoc@
67 * @tvec_begingroup@
68 * -> output @bgroup@
69 * -> env @setup@
70 * @tvec_begintest@
71 * -> output @btest@
72 * @tvec_skip@
73 * -> output @skip@
74 * @tvec_claimeq@
75 * -> @tvec_fail@
76 * -> output @fail@
77 * -> @tvec_mismatch@
78 * -> output @dumpreg@
79 * -> type @dump@
80 * @tvec_endtest@
81 * -> output @etest@
82 * or @tvec_skipgroup@
83 * -> output @skipgroup@
84 * @tvec_endgroup@
85 * -> output @egroup@
86 *
87 * @tvec_end@
88 * -> output @esession@
89 * -> output @destroy@
90 *
91 * @tvec_benchrun@
92 * -> type @dump@ (compact style)
93 * -> output @bbench@
94 * -> subenv @run@
95 * -> test @fn@
96 * -> output @ebench@
97 * -> @tvec_benchreport@
98 *
99 * The output functions @error@ and @notice@ can be called at arbitrary
100 * times.
101 */
102
103 /*----- Header files ------------------------------------------------------*/
104
105 #include <stdarg.h>
106 #include <stddef.h>
107 #include <stdio.h>
108 #include <string.h>
109
110 #ifndef MLIB_ARENA_H
111 # include "arena.h"
112 #endif
113
114 #ifndef MLIB_BUF_H
115 # include "buf.h"
116 #endif
117
118 #ifndef MLIB_DSTR_H
119 # include "dstr.h"
120 #endif
121
122 #ifndef MLIB_GPRINTF_H
123 # include "gprintf.h"
124 #endif
125
126 #ifndef MLIB_MACROS_H
127 # include "macros.h"
128 #endif
129
130 /*----- Miscellaneous values ----------------------------------------------*/
131
132 /* These are attached to structures which represent extension points, as a
133 * way to pass an opaque parameter to whatever things are hooked onto them.
134 */
135
136 #define TVEC_MISCSLOTS(_) \
137 _(PTR, const void *, p) /* arbitrary pointer */ \
138 _(INT, long, i) /* signed integer */ \
139 _(UINT, unsigned long, u) /* signed integer */ \
140 _(FLT, double, f) /* floating point */
141
142 union tvec_misc {
143 #define TVEC_DEFSLOT(tag, ty, slot) ty slot;
144 TVEC_MISCSLOTS(TVEC_DEFSLOT)
145 #undef TVEC_DEFSLOT
146 };
147 enum {
148 #define TVEC_DEFCONST(tag, ty, slot) TVMISC_##tag,
149 TVEC_MISCSLOTS(TVEC_DEFCONST)
150 TVMISC_LIMIT
151 };
152
153 /*----- Register values ---------------------------------------------------*/
154
155 /* The framework doesn't have a preconceived idea about what's in a register
156 * value: it just allocates them and accesses them through the register type
157 * functions. It doesn't even have a baked-in idea of how big a register
158 * value is: instead, it gets that via the `regsz' slot in `struct
159 * tvec_testinfo'. So, as far as the framework is concerned, it's safe to
160 * add new slots to this union, even if they make the overall union larger.
161 * This can be done by defining the preprocessor macro `TVEC_REGSLOTS' to be
162 * a `union' fragment defining any additional union members.
163 *
164 * This creates a distinction between code which does and doesn't know the
165 * size of a register value. Code which does, which typically means the test
166 * functions, benchmarking setup and teardown functions, and tightly-bound
167 * runner functions, is free to index the register vectors directly. Code
168 * which doesn't, which means the framework core itself and output formatting
169 * machinery, must use the `TVEC_REG' macro (or its more general `TVEC_GREG'
170 * companion) for indexing register vectors. (In principle, register type
171 * handlers also fit into this category, but they have no business peering
172 * into register values other than the one's they're given.)
173 */
174
175 union tvec_regval {
176 /* The actual register value. This is what the type handler sees.
177 * Additional members can be added by setting `TVEC_REGSLOTS' before
178 * including this file.
179 *
180 * A register value can be /initialized/, which simply means that its
181 * contents represent a valid value according to its type -- the register
182 * can be compared, dumped, serialized, parsed into, etc. You can't do
183 * anything safely to an uninitialized register value other than initialize
184 * it.
185 */
186
187 long i; /* signed integer */
188 unsigned long u; /* unsigned integer */
189 void *p; /* pointer */
190 double f; /* floating point */
191 struct { char *p; size_t sz; } text; /* text string */
192 struct { unsigned char *p; size_t sz; } bytes; /* binary string of bytes */
193 struct { /* buffer */
194 unsigned char *p; size_t sz; /* binary string */
195 size_t a, m; /* residue and modulus */
196 size_t off; /* offset into full buffer */
197 } buf;
198 #ifdef TVEC_REGSLOTS
199 TVEC_REGSLOTS
200 #endif
201 };
202
203 struct tvec_reg {
204 /* A register.
205 *
206 * Note that all of the registers listed as being used by a particular test
207 * group are initialized at all times[1] while that test group is being
208 * processed. (The other register slots don't even have types associated
209 * with them, so there's nothing useful we could do with them.)
210 *
211 * The `TVRF_LIVE' flag indicates that the register was assigned a value by
212 * the test vector file: it's the right thing to use to check whether an
213 * optional register is actually present. Even `dead' registers are still
214 * initialized, though.
215 *
216 * [1] This isn't quite true. Between individual tests, the registers are
217 * released and reinitialized in order to reset them to known values
218 * ready for the next test. But you won't see them at this point.
219 */
220
221 unsigned f; /* flags */
222 #define TVRF_SEEN 1u /* assignment seen in file */
223 #define TVRF_LIVE 2u /* used in current test */
224 union tvec_regval v; /* register value */
225 };
226
227 struct tvec_regdef {
228 /* A register definition. Register definitions list the registers which
229 * are used by a particular test group (see `struct tvec_test' below).
230 *
231 * A vector of register definitions is terminated by a definition whose
232 * `name' slot is null.
233 */
234
235 const char *name; /* register name (for input files) */
236 const struct tvec_regty *ty; /* register type descriptor */
237 unsigned i; /* register index */
238 unsigned f; /* flags */
239 #define TVRF_UNSET 1u /* register may be marked unset */
240 #define TVRF_OPT 2u /* register need not be assigned */
241 #define TVRF_ID 4u /* part of test identity */
242 union tvec_misc arg; /* extra detail for the type */
243 };
244 #define TVEC_ENDREGS { 0, 0, 0, 0, { 0 } }
245
246 /* @TVEC_GREG(vec, i, regsz)@
247 *
248 * If @vec@ is a data pointer which happens to contain the address of a
249 * vector of @struct tvec_reg@ objects, @i@ is an integer, and @regsz@ is the
250 * size of a @struct tvec_reg@, then this evaluates to the address of the
251 * @i@th element of the vector.
252 *
253 * This is the general tool you need for accessing register vectors when you
254 * don't have absolute knowledge of the size of a @union tvec_regval@.
255 * Usually you want to access one of the register vectors in a @struct
256 * tvec_state@, and @TVEC_REG@ will be more convenient.
257 */
258 #define TVEC_GREG(vec, i, regsz) \
259 ((struct tvec_reg *)((unsigned char *)(vec) + (i)*(regsz)))
260
261 /*----- Register types ----------------------------------------------------*/
262
263 struct tvec_state; /* forward declaration */
264
265 struct tvec_regty {
266 /* A register type. */
267
268 void (*init)(union tvec_regval */*rv*/, const struct tvec_regdef */*rd*/);
269 /* Initialize the value in @*rv@. This will be called before any other
270 * function acting on the value, including @release@. Following @init@,
271 * the register value must be valid to use for all other type entry
272 * points.
273 */
274
275 void (*release)(union tvec_regval */*rv*/,
276 const struct tvec_regdef */*rd*/);
277 /* Release any resources associated with the value in @*rv@. The
278 * register value may be left in an invalid state.
279 */
280
281 int (*eq)(const union tvec_regval */*rv0*/,
282 const union tvec_regval */*rv1*/,
283 const struct tvec_regdef */*rd*/);
284 /* Return nonzero if @*rv0@ and @*rv1@ are equal values. Asymmetric
285 * criteria are permitted: @tvec_checkregs@ calls @eq@ with the input
286 * register as @rv0@ and the output as @rv1@.
287 */
288
289 int (*tobuf)(buf */*b*/, const union tvec_regval */*rv*/,
290 const struct tvec_regdef */*rd*/);
291 /* Serialize the value @*rv@, writing the result to @b@. Return zero on
292 * success, or %$-1$% on error.
293 */
294
295 int (*frombuf)(buf */*b*/, union tvec_regval */*rv*/,
296 const struct tvec_regdef */*rd*/);
297 /* Deserialize a value from @b@, storing it in @*rv@. Return zero on
298 * success, or %$-1$% on error.
299 */
300
301 int (*parse)(union tvec_regval */*rv*/, const struct tvec_regdef */*rd*/,
302 struct tvec_state */*tv*/);
303 /* Parse a value from @tv->fp@, storing it in @*rv@. Return zero on
304 * success, or %$-1$% on error, having reported one or more errors via
305 * @tvec_error@ or @tvec_syntax@. A successful return should leave the
306 * input position at the start of the next line; the caller will flush
307 * the remainder of the line itself.
308 */
309
310 void (*dump)(const union tvec_regval */*rv*/,
311 const struct tvec_regdef */*rd*/,
312 unsigned /*style*/,
313 const struct gprintf_ops */*gops*/, void */*go*/);
314 #define TVSF_COMPACT 1u
315 #define TVSF_RAW 2u
316 /* Write a human-readable representation of the value @*rv@ using
317 * @gprintf@ on @gops@ and @go@. The @style@ is a collection of flags:
318 * if @TVSF_COMPACT@ is set, then output should be minimal, and must fit
319 * on a single line; otherwise, output may consist of multiple lines and
320 * may contain redundant information if that is likely to be useful to a
321 * human reader. If @TVSF_RAW@ is set, then output should prefer
322 * machine-readability over human-readability.
323 */
324 };
325
326 /*----- Test descriptions -------------------------------------------------*/
327
328 struct tvec_env;
329
330 typedef void tvec_testfn(const struct tvec_reg */*in*/,
331 struct tvec_reg */*out*/,
332 void */*ctx*/);
333 /* A test function. It should read inputs from @in@ and write outputs to
334 * @out@. The @TVRF_LIVE@ is set on inputs which are actually present, and
335 * on outputs which are wanted to test. A test function can set additional
336 * `gratuitous outputs' by setting @TVRF_LIVE@ on them; clearing
337 * @TVRF_LIVE@ on a wanted output causes a mismatch.
338 *
339 * A test function may be called zero or more times by the environment. In
340 * particular, it may be called multiple times, though usually by prior
341 * arrangement with the environment.
342 *
343 * The @ctx@ is supplied by the environment's @run@ function (see below).
344 * The default environment calls the test function once, with a null
345 * @ctx@. There is no expectation that the environment's context has
346 * anything to do with the test function's context.
347 */
348
349 typedef int tvec_setvarfn(struct tvec_state */*tv*/, const char */*var*/,
350 const union tvec_regval */*rv*/, void */*ctx*/);
351 /* Called after a variable is read. Return zero on success or %$-1$% on
352 * error. This function is never called if the test group is skipped.
353 */
354
355 struct tvec_vardef {
356 size_t regsz; /* (minimum) register size */
357 tvec_setvarfn *setvar; /* function to set variable */
358 struct tvec_regdef def; /* register definition */
359 };
360
361 typedef void tvec_envsetupfn(struct tvec_state */*tv*/,
362 const struct tvec_env */*env*/,
363 void */*pctx*/, void */*ctx*/);
364 /* Initialize the context; called at the start of a test group; @pctx@ is
365 * null for environments called by the core, but may be non-null for
366 * subordinate environments. If setup fails, the function should call
367 * @tvec_skipgroup@ with a suitable excuse. The @set@, @after@, and
368 * @teardown@ entry points will still be called, but @before@ and @run@
369 * will not.
370 */
371
372 typedef const struct tvec_vardef *tvec_envfindvarfn
373 (struct tvec_state */*tv*/, const char */*name*/,
374 void **/*ctx_out*/, void */*ctx*/);
375 /* Called when the parser finds a %|@var|%' special variable. If a
376 * suitable variable was found, set @*ctx_out@ to a suitable context and
377 * return the variable definition; the context will be passed to the
378 * variable definition's @setvar@ function. If no suitable variable was
379 * found, then return null.
380 */
381
382 typedef void tvec_envbeforefn(struct tvec_state */*tv*/, void */*ctx*/);
383 /* Called prior to running a test. This is the right place to act on any
384 * `%|@var|%' settings. If preparation fails, the function should call
385 * @tvec_skip@ with a suitable excuse. This function is never called if
386 * the test group is skipped. It %%\emph{is}%% called if the test will be
387 * skipped due to erroneous test data. It should check the @TVSF_ACTIVE@
388 * flag if necessary.
389 */
390
391 typedef void tvec_envrunfn(struct tvec_state */*tv*/,
392 tvec_testfn */*fn*/, void */*ctx*/);
393 /* Run the test. It should either call @tvec_skip@, or run @fn@ one or
394 * more times. In the latter case, it is responsible for checking the
395 * outputs, and calling @tvec_fail@ as necessary; @tvec_checkregs@ will
396 * check the register values against the supplied test vector, while
397 * @tvec_check@ does pretty much everything necessary. This function is
398 * never called if the test group is skipped.
399 */
400
401 typedef void tvec_envafterfn(struct tvec_state */*tv*/, void */*ctx*/);
402 /* Called after running or skipping a test. Typical actions involve
403 * resetting whatever things were established by @set@. This function
404 * %%\emph{is}%% called if the test group is skipped or the test data is
405 * erroneous, so that the test environment can reset variables set by the
406 * @set@ entry point. It should check the @TVSF_SKIP@ flag if necessary.
407 */
408
409 typedef void tvec_envteardownfn(struct tvec_state */*tv*/, void */*ctx*/);
410 /* Tear down the environment: called at the end of a test group. */
411
412
413 struct tvec_env {
414 /* A test environment sets things up for and arranges to run the test.
415 *
416 * The caller is responsible for allocating storage for the environment's
417 * context, based on the @ctxsz@ slot, and freeing it later; this space is
418 * passed in as the @ctx@ parameter to the remaining functions; if @ctxsz@
419 * is zero then @ctx@ is null.
420 */
421
422 size_t ctxsz; /* environment context size */
423
424 tvec_envsetupfn *setup; /* setup for group */
425 tvec_envfindvarfn *findvar; /* find variable */
426 tvec_envbeforefn *before; /* prepare for test */
427 tvec_envrunfn *run; /* run test function */
428 tvec_envafterfn *after; /* clean up after test */
429 tvec_envteardownfn *teardown; /* tear down after group */
430 };
431
432 struct tvec_test {
433 /* A test description. */
434
435 const char *name; /* name of the test */
436 const struct tvec_regdef *regs; /* descriptions of the registers */
437 const struct tvec_env *env; /* environment to run test in */
438 tvec_testfn *fn; /* test function */
439 };
440
441 /*----- Test state --------------------------------------------------------*/
442
443 struct tvec_output;
444
445 enum {
446 /* Possible test outcomes. */
447
448 TVOUT_LOSE, /* test failed */
449 TVOUT_SKIP, /* test skipped */
450 TVOUT_XFAIL, /* test passed, but shouldn't have */
451 TVOUT_WIN, /* test passed */
452 TVOUT_LIMIT /* (number of possible outcomes) */
453 };
454
455 struct tvec_config {
456 /* An overall test configuration. */
457
458 const struct tvec_test *const *tests; /* the tests to be performed */
459 unsigned nrout, nreg; /* number of output/total regs */
460 size_t regsz; /* size of a register */
461 };
462
463 struct tvec_state {
464 /* The primary state structure for the test vector machinery. */
465
466 /* Flags. Read-only for all callers. */
467 unsigned f; /* flags */
468 #define TVSF_SKIP 0x0001u /* skip this test group */
469 #define TVSF_OPEN 0x0002u /* test is open */
470 #define TVSF_ACTIVE 0x0004u /* test is active */
471 #define TVSF_ERROR 0x0008u /* an error occurred */
472 #define TVSF_OUTMASK 0x00f0u /* test outcome (@TVOUT_...@) */
473 #define TVSF_OUTSHIFT 4 /* shift applied to outcome */
474 #define TVSF_XFAIL 0x0100u /* test expected to fail */
475 #define TVSF_MUFFLE 0x0200u /* muffle errors */
476
477 /* Memory allocation. Read-only for all callers. */
478 arena *a;
479
480 /* Test configuration. Read-only for all callers. */
481 struct tvec_config cfg; /* test configuration */
482
483 /* Registers. Available to execution environments, which may modify the
484 * contents of the active registers, as defined by the current test group,
485 * but not the vector pointers themselves or inactive registers.
486 */
487 struct tvec_reg *in, *out; /* register vectors */
488
489 /* Test group state. Read-only for all callers. */
490 const struct tvec_test *test; /* current test */
491
492 /* Test scoreboard. Available to output formatters. */
493 unsigned curr[TVOUT_LIMIT], all[TVOUT_LIMIT], grps[TVOUT_LIMIT];
494
495 /* Output machinery. Read-only for environments. */
496 struct tvec_output *output; /* output formatter */
497
498 /* Input machinery. Available to type parsers. */
499 const char *infile; unsigned lno, test_lno; /* input file name, line */
500 FILE *fp; /* input file stream */
501
502 /* Adhoc testing state. Private. */
503 struct tvec_test adhoc_test;
504 const struct tvec_test *adhoc_tests[];
505 };
506
507 /* @TVEC_REG(tv, vec, i)@
508 *
509 * If @tv@ is a pointer to a @struct tvec_state@, @vec@ is either @in@ or
510 * @out@, and @i@ is an integer, then this evaluates to the address of the
511 * @i@th register in the selected vector.
512 */
513 #define TVEC_REG(tv, vec, i) TVEC_GREG((tv)->vec, (i), (tv)->cfg.regsz)
514
515 /*----- Session lifecycle -------------------------------------------------*/
516
517 /* --- @tvec_begin@ --- *
518 *
519 * Arguments: @struct tvec_state *tv_out@ = state structure to fill in
520 * @const struct tvec_config *config@ = test configuration
521 * @struct tvec_output *o@ = output driver
522 *
523 * Returns: ---
524 *
525 * Use: Initialize a state structure ready to do some testing.
526 */
527
528 extern void tvec_begin(struct tvec_state */*tv_out*/,
529 const struct tvec_config */*config*/,
530 struct tvec_output */*o*/);
531
532 /* --- @tvec_end@ --- *
533 *
534 * Arguments: @struct tvec_state *tv@ = test-vector state
535 *
536 * Returns: A proposed exit code.
537 *
538 * Use: Conclude testing and suggests an exit code to be returned to
539 * the calling program. (The exit code comes from the output
540 * driver's @esession@ method.)
541 */
542
543 extern int tvec_end(struct tvec_state */*tv*/);
544
545 /* --- @tvec_read@ --- *
546 *
547 * Arguments: @struct tvec_state *tv@ = test-vector state
548 * @const char *infile@ = the name of the input file
549 * @FILE *fp@ = stream to read from
550 *
551 * Returns: Zero on success, %$-1$% on error.
552 *
553 * Use: Read test vector data from @fp@ and exercise test functions.
554 * THe return code doesn't indicate test failures: it's only
555 * concerned with whether there were problems with the input
556 * file or with actually running the tests.
557 */
558
559 extern int tvec_read(struct tvec_state */*tv*/,
560 const char */*infile*/, FILE */*fp*/);
561
562 /*----- Command-line interface --------------------------------------------*/
563
564 /* --- @tvec_parseargs@ --- *
565 *
566 * Arguments: @int argc@ = number of command-line arguments
567 * @char *argv[]@ = vector of argument strings
568 * @struct tvec_state *tv_out@ = test vector state to initialize
569 * @int *argpos_out@ = where to leave unread argument index
570 * @const struct tvec_config *cofig@ = test vector configuration
571 *
572 * Returns: ---
573 *
574 * Use: Parse arguments and set up the test vector state @*tv_out@.
575 * If errors occur, print messages to standard error and exit
576 * with status 2.
577 */
578
579 extern void tvec_parseargs(int /*argc*/, char */*argv*/[],
580 struct tvec_state */*tv_out*/,
581 int */*argpos_out*/,
582 const struct tvec_config */*config*/);
583
584 /* --- @tvec_readstdin@, @tvec_readfile@, @tvec_readarg@ --- *
585 *
586 * Arguments: @struct tvec_state *tv@ = test vector state
587 * @const char *file@ = pathname of file to read
588 * @const char *arg@ = argument to interpret
589 *
590 * Returns: Zero on success, %$-1$% on error.
591 *
592 * Use: Read test vector data from stdin or a named file. The
593 * @tvec_readarg@ function reads from stdin if @arg@ is `%|-|%',
594 * and from the named file otherwise.
595 */
596
597 extern int tvec_readstdin(struct tvec_state */*tv*/);
598 extern int tvec_readfile(struct tvec_state */*tv*/, const char */*file*/);
599 extern int tvec_readarg(struct tvec_state */*tv*/, const char */*arg*/);
600
601 /* --- @tvec_readdflt@ --- *
602 *
603 * Arguments: @struct tvec_state *tv@ = test vector state
604 * @const char *dflt@ = defsault filename or null
605 *
606 * Returns: Zero on success, %$-1$% on error.
607 *
608 * Use: Reads from the default test vector data. If @file@ is null,
609 * then read from standard input, unless that's a terminal; if
610 * @file@ is not null, then read the named file, looking in the
611 * directory named by the `%|srcdir|%' environment variable if
612 * that's set, or otherwise in the current directory.
613 */
614
615 extern int tvec_readdflt(struct tvec_state */*tv*/, const char */*file*/);
616
617 /* --- @tvec_readargs@ --- *
618 *
619 * Arguments: @int argc@ = number of command-line arguments
620 * @char *argv[]@ = vector of argument strings
621 * @struct tvec_state *tv@ = test vector state
622 * @int *argpos_inout@ = current argument position (updated)
623 * @const char *dflt@ = default filename or null
624 *
625 * Returns: Zero on success, %$-1$% on error.
626 *
627 * Use: Reads from the sources indicated by the command-line
628 * arguments, in order, interpreting each as for @tvec_readarg@;
629 * if no arguments are given then read from @dflt@ as for
630 * @tvec_readdflt@.
631 */
632
633 extern int tvec_readargs(int /*argc*/, char */*argv*/[],
634 struct tvec_state */*tv*/,
635 int */*argpos_inout*/, const char */*dflt*/);
636
637 /* --- @tvec_main@ --- *
638 *
639 * Arguments: @int argc@ = number of command-line arguments
640 * @char *argv[]@ = vector of argument strings
641 * @const struct tvec_config *cofig@ = test vector configuration
642 * @const char *dflt@ = default filename or null
643 *
644 * Returns: Exit code.
645 *
646 * Use: All-in-one test vector front-end. Parse options from the
647 * command-line as for @tvec_parseargs@, and then process the
648 * remaining positional arguments as for @tvec_readargs@. The
649 * function constructs and disposes of a test vector state.
650 */
651
652 extern int tvec_main(int /*argc*/, char */*argv*/[],
653 const struct tvec_config */*config*/,
654 const char */*dflt*/);
655
656 /*----- Test processing ---------------------------------------------------*/
657
658 /* --- @tvec_skipgroup@, @tvec_skipgroup_v@ --- *
659 *
660 * Arguments: @struct tvec_state *tv@ = test-vector state
661 * @const char *excuse@, @va_list *ap@ = reason why skipped
662 *
663 * Returns: ---
664 *
665 * Use: Skip the current group. This should only be called from a
666 * test environment @setup@ function; a similar effect occurs if
667 * the @setup@ function fails.
668 */
669
670 extern PRINTF_LIKE(2, 3)
671 void tvec_skipgroup(struct tvec_state */*tv*/,
672 const char */*excuse*/, ...);
673 extern void tvec_skipgroup_v(struct tvec_state */*tv*/,
674 const char */*excuse*/, va_list */*ap*/);
675
676 /* --- @tvec_skip@, @tvec_skip_v@ --- *
677 *
678 * Arguments: @struct tvec_state *tv@ = test-vector state
679 * @const char *excuse@, @va_list *ap@ = reason why test skipped
680 *
681 * Returns: ---
682 *
683 * Use: Skip the current test. This should only be called from a
684 * test environment @run@ function; a similar effect occurs if
685 * the @before@ function fails.
686 */
687
688 extern PRINTF_LIKE(2, 3)
689 void tvec_skip(struct tvec_state */*tv*/, const char */*excuse*/, ...);
690 extern void tvec_skip_v(struct tvec_state */*tv*/,
691 const char */*excuse*/, va_list */*ap*/);
692
693 /* --- @tvec_fail@, @tvec_fail_v@ --- *
694 *
695 * Arguments: @struct tvec_state *tv@ = test-vector state
696 * @const char *detail@, @va_list *ap@ = description of test
697 *
698 * Returns: ---
699 *
700 * Use: Report the current test as a failure. This function can be
701 * called multiple times for a single test, e.g., if the test
702 * environment's @run@ function invokes the test function
703 * repeatedly; but a single test that fails repeatedly still
704 * only counts as a single failure in the statistics. The
705 * @detail@ string and its format parameters can be used to
706 * distinguish which of several invocations failed; it can
707 * safely be left null if the test function is run only once.
708 */
709
710 extern PRINTF_LIKE(2, 3)
711 void tvec_fail(struct tvec_state */*tv*/, const char */*detail*/, ...);
712 extern void tvec_fail_v(struct tvec_state */*tv*/,
713 const char */*detail*/, va_list */*ap*/);
714
715 /* --- @tvec_dumpreg@ --- *
716 *
717 * Arguments: @struct tvec_state *tv@ = test-vector state
718 * @unsigned disp@ = the register disposition (@TVRD_...@)
719 * @const union tvec_regval *tv@ = register value, or null
720 * @const struct tvec_regdef *rd@ = register definition
721 *
722 * Returns: ---
723 *
724 * Use: Dump a register value to the output. This is the lowest-
725 * level function for dumping registers, and calls the output
726 * formatter directly.
727 *
728 * Usually @tvec_mismatch@ is much more convenient. Low-level
729 * access is required for reporting `virtual' registers
730 * corresponding to test environment settings.
731 */
732
733 extern void tvec_dumpreg(struct tvec_state */*tv*/,
734 unsigned /*disp*/, const union tvec_regval */*rv*/,
735 const struct tvec_regdef */*rd*/);
736
737 /* --- @tvec_initregs@, @tvec_releaseregs@ --- *
738 *
739 * Arguments: @struct tvec_state *tv@ = test-vector state
740 *
741 * Returns: ---
742 *
743 * Use: Initialize or release, respectively, the registers required
744 * by the current test. All of the registers, both input and
745 * output, are effected. Initialized registers are not marked
746 * live.
747 */
748
749 extern void tvec_initregs(struct tvec_state */*tv*/);
750 extern void tvec_releaseregs(struct tvec_state */*tv*/);
751
752 /* --- @tvec_resetoutputs@ --- *
753 *
754 * Arguments: @struct tvec_state *tv@ = test-vector state
755 *
756 * Returns: ---
757 *
758 * Use: Reset (releases and reinitializes) the output registers in
759 * the test state. This is mostly of use to test environment
760 * @run@ functions, between invocations of the test function.
761 * Output registers are marked live if and only if the
762 * corresponding input register is live.
763 */
764
765 extern void tvec_resetoutputs(struct tvec_state */*tv*/);
766
767 /* --- @tvec_checkregs@ --- *
768 *
769 * Arguments: @struct tvec_state *tv@ = test-vector state
770 *
771 * Returns: Zero on success, %$-1$% on mismatch.
772 *
773 * Use: Compare the active output registers (according to the current
774 * test group definition) with the corresponding input register
775 * values. A mismatch occurs if the two values differ
776 * (according to the register type's @eq@ method), or if the
777 * input is live but the output is dead.
778 *
779 * This function only checks for a mismatch and returns the
780 * result; it takes no other action. In particular, it doesn't
781 * report a failure, or dump register values.
782 */
783
784 extern int tvec_checkregs(struct tvec_state */*tv*/);
785
786 /* --- @tvec_mismatch@ --- *
787 *
788 * Arguments: @struct tvec_state *tv@ = test-vector state
789 * @unsigned f@ = flags (@TVMF_...@)
790 *
791 * Returns: ---
792 *
793 * Use: Dumps registers suitably to report a mismatch. The flag bits
794 * @TVMF_IN@ and @TVF_OUT@ select input-only and output
795 * registers. If both are reset then nothing happens.
796 * Suppressing the output registers may be useful, e.g., if the
797 * test function crashed rather than returning outputs.
798 */
799
800 #define TVMF_IN 1u
801 #define TVMF_OUT 2u
802 extern void tvec_mismatch(struct tvec_state */*tv*/, unsigned /*f*/);
803
804 /* --- @tvec_check@, @tvec_check_v@ --- *
805 *
806 * Arguments: @struct tvec_state *tv@ = test-vector state
807 * @const char *detail@, @va_list *ap@ = description of test
808 *
809 * Returns: ---
810 *
811 * Use: Check the register values, reporting a failure and dumping
812 * the registers in the event of a mismatch. This just wraps up
813 * @tvec_checkregs@, @tvec_fail@ and @tvec_mismatch@ in the
814 * obvious way.
815 */
816
817 extern PRINTF_LIKE(2, 3)
818 void tvec_check(struct tvec_state */*tv*/, const char */*detail*/, ...);
819 extern void tvec_check_v(struct tvec_state */*tv*/,
820 const char */*detail*/, va_list */*ap*/);
821
822 /*----- Output functions --------------------------------------------------*/
823
824 /* --- @tvec_strlevel@ --- *
825 *
826 * Arguments: @unsigned level@ = level code
827 *
828 * Returns: A human-readable description.
829 *
830 * Use: Converts a level code into something that you can print in a
831 * message.
832 */
833
834 extern const char *tvec_strlevel(unsigned /*level*/);
835
836 /* --- @tvec_report@, @tvec_report_v@ --- *
837 *
838 * Arguments: @struct tvec_state *tv@ = test-vector state
839 * @const char *msg@, @va_list ap@ = error message
840 *
841 * Returns: ---
842 *
843 * Use: Report an message with a given severity. Messages with level
844 * @TVLEV_ERR@ or higher force a nonzero exit code.
845 */
846
847 #define TVEC_LEVELS(_) \
848 _(INFO, "info", 3) \
849 _(NOTE, "notice", 4) \
850 _(ERR, "ERROR", 8)
851 enum {
852 #define TVEC_DEFLEVEL(tag, name, val) TVLEV_##tag = val,
853 TVEC_LEVELS(TVEC_DEFLEVEL)
854 #undef TVEC_DEFLEVEL
855 TVLEV_LIMIT
856 };
857
858 extern PRINTF_LIKE(3, 4)
859 void tvec_report(struct tvec_state */*tv*/, unsigned /*level*/,
860 const char */*msg*/, ...);
861 extern void tvec_report_v(struct tvec_state */*tv*/, unsigned /*level*/,
862 const char */*msg*/, va_list */*ap*/);
863
864 /* --- @tvec_error@, @tvec_notice@, @tvec_info@ --- *
865 *
866 * Arguments: @struct tvec_state *tv@ = test-vector state
867 * @const char *msg@, @va_list ap@ = error message
868 *
869 * Returns: The @tvec_error@ function returns %$-1$% as a trivial
870 * convenience; @tvec_notice@ does not return a value.
871 *
872 * Use: Report a message. Errors are distinct from test
873 * failures, and indicate that a problem was encountered which
874 * compromised the activity of testing. Notices are important
875 * information which doesn't fit into any other obvious
876 * category. Information is anything else, and is a reasonable
877 * fallback for writing unstructured information in the absence
878 * of dedicated support in an output driver.
879 *
880 * These functions are simple convenience wrappers around
881 * @tvec_report@. Use @tvec_report_v@ directly if you have a
882 * captured @va_list@ of arguments to format.
883 */
884
885 extern PRINTF_LIKE(2, 3)
886 int tvec_error(struct tvec_state */*tv*/, const char */*msg*/, ...);
887 extern PRINTF_LIKE(2, 3)
888 void tvec_notice(struct tvec_state */*tv*/, const char */*msg*/, ...);
889 extern PRINTF_LIKE(2, 3)
890 void tvec_info(struct tvec_state */*tv*/, const char */*msg*/, ...);
891
892 /* --- @tvec_unkregerr@ --- *
893 *
894 * Arguments: @struct tvec_state *tv@ = test-vector state
895 * @const char *name@ = register or pseudoregister name
896 *
897 * Returns: %$-1$%.
898 *
899 * Use: Reports an error that the register or pseudoregister is
900 * unrecognized.
901 */
902
903 extern int tvec_unkregerr(struct tvec_state */*tv*/, const char */*name*/);
904
905 /* --- @tvec_dupregerr@ --- *
906 *
907 * Arguments: @struct tvec_state *tv@ = test-vector state
908 * @const char *name@ = register or pseudoregister name
909 *
910 * Returns: %$-1$%.
911 *
912 * Use: Reports an error that the register or pseudoregister has been
913 * assigned already in the current test.
914 */
915
916 extern int tvec_dupregerr(struct tvec_state */*tv*/, const char */*name*/);
917
918 /* --- @tvec_humanoutput@ --- *
919 *
920 * Arguments: @FILE *fp@ = output file to write on
921 * @unsigned style@ = output style (@TVSF_...@)
922 *
923 * Returns: An output formatter.
924 *
925 * Use: Return an output formatter which writes on @fp@ with the
926 * expectation that a human will be watching and interpreting
927 * the output. If @fp@ denotes a terminal, the display shows a
928 * `scoreboard' indicating the outcome of each test case
929 * attempted, and may in addition use colour and other
930 * highlighting.
931 */
932
933 extern struct tvec_output *tvec_humanoutput(FILE */*fp*/);
934
935 /* --- @tvec_machineoutput@ --- *
936 *
937 * Arguments: @FILE *fp@ = output file to write on
938 *
939 * Returns: An output formatter.
940 *
941 * Use: Return an output formatter which writes on @fp@ in a
942 * moderately simple machine-readable format.
943 */
944
945 struct tvec_output *tvec_machineoutput(FILE *fp);
946
947 /* --- @tvec_tapoutput@ --- *
948 *
949 * Arguments: @FILE *fp@ = output file to write on
950 * @unsigned style@ = output style (@TVSF_...@)
951 *
952 * Returns: An output formatter.
953 *
954 * Use: Return an output formatter which writes on @fp@ in `TAP'
955 * (`Test Anything Protocol') format.
956 *
957 * TAP comes from the Perl community, but has spread rather
958 * further. This driver currently produces TAP version 14, but
959 * pretends to be version 13. The driver produces a TAP `test
960 * point' -- i.e., a result reported as `ok' or `not ok' -- for
961 * each input test group. Failure reports and register dumps
962 * are produced as diagnostic messages before the final group
963 * result. (TAP permits structuerd YAML data after the
964 * test-point result, which could be used to report details, but
965 * (a) postponing the details until after the report is
966 * inconvenient, and (b) there is no standardization for the
967 * YAML anyway, so in practice it's no more useful than the
968 * unstructured diagnostics.
969 */
970
971 extern struct tvec_output *tvec_tapoutput(FILE */*fp*/);
972
973 /* --- @tvec_dfltoutput@ --- *
974 *
975 * Arguments: @FILE *fp@ = output file to write on
976 *
977 * Returns: An output formatter.
978 *
979 * Use: Selects and instantiates an output formatter suitable for
980 * writing on @fp@. The policy is subject to change, but
981 * currently the `human' output format is selected if @fp@ is
982 * interactive (i.e., if @isatty(fileno(fp))@ is true), and
983 * otherwise the `machine' format is used.
984 */
985
986 extern struct tvec_output *tvec_dfltout(FILE */*fp*/);
987
988 /*------ Serialization utilities ------------------------------------------*/
989
990 /* Serialization format.
991 *
992 * The `candidate register definitions' are those entries @r@ in the @regs@
993 * vector whose index @r.i@ is strictly less than @nr@ and where
994 * @r.f&mask == want@* . The `selected register definitions' are those
995 * candidate register definitions @r@ for which the indicated register
996 * @rv[r.i]@ has the @TVRF_LIVE@ flag set. The serialized output begins with
997 * a header bitmap: if there are %$n$% candidate register definitions then
998 * the header bitmap consists of %$\lceil n/8 \rceil$% bytes. Bits are
999 * ordered starting from the least significant bit of the first byte, end
1000 * ending at the most significant bit of the final byte. The bit
1001 * corresponding to a candidate register definition is set if and only if
1002 * that register defintion is selected. The header bitmap is then followed
1003 * by the serializations of the selected registers -- i.e., for each selected
1004 * register definition @r@, the serialized value of register @rv[r.i]@ --
1005 * simply concatenated together, with no padding or alignment.
1006 */
1007
1008 /* --- @tvec_serialize@ --- *
1009 *
1010 * Arguments: @const struct tvec_reg *rv@ = vector of registers
1011 * @buf *b@ = buffer to write on
1012 * @const struct tvec_regdef *regs@ = vector of register
1013 * descriptions, terminated by an entry with a null
1014 * @name@ slot
1015 * @unsigned mask, want@ = flag-based selection
1016 * @unsigned nr@ = number of entries in the @rv@ vector
1017 * @size_t regsz@ = true size of each element of @rv@
1018 *
1019 * Returns: Zero on success, %$-1$% on failure.
1020 *
1021 * Use: Serialize a collection of register values.
1022 *
1023 * The serialized output is written to the buffer @b@. Failure
1024 * can be caused by running out of buffer space, or a failing
1025 * type handler.
1026 */
1027
1028 extern int tvec_serialize(const struct tvec_reg */*rv*/, buf */*b*/,
1029 const struct tvec_regdef */*regs*/,
1030 unsigned /*mask*/, unsigned /*want*/,
1031 unsigned /*nr*/, size_t /*regsz*/);
1032
1033 /* --- @tvec_deserialize@ --- *
1034 *
1035 * Arguments: @struct tvec_reg *rv@ = vector of registers
1036 * @buf *b@ = buffer to write on
1037 * @const struct tvec_regdef *regs@ = vector of register
1038 * descriptions, terminated by an entry with a null
1039 * @name@ slot
1040 * @unsigned mask, want@ = flag-based selection
1041 * @unsigned nr@ = number of entries in the @rv@ vector
1042 * @size_t regsz@ = true size of each element of @rv@
1043 *
1044 * Returns: Zero on success, %$-1$% on failure.
1045 *
1046 * Use: Deserialize a collection of register values.
1047 *
1048 * The size of the register vector @nr@ and the register
1049 * definitions @regs@ must match those used when producing the
1050 * serialization. For each serialized register value,
1051 * deserialize and store the value into the appropriate register
1052 * slot, and set the @TVRF_LIVE@ flag on the register. See
1053 * @tvec_serialize@ for a description of the format.
1054 *
1055 * Failure results only from an input too small for the initial
1056 * bitmap or a failing register type handler.
1057 */
1058
1059 extern int tvec_deserialize(struct tvec_reg */*rv*/, buf */*b*/,
1060 const struct tvec_regdef */*regs*/,
1061 unsigned /*mask*/, unsigned /*want*/,
1062 unsigned /*nr*/, size_t /*regsz*/);
1063
1064 /*----- Input utilities ---------------------------------------------------*/
1065
1066 /* These are provided by the core for the benefit of type @parse@ methods,
1067 * and test-environment @set@ functions, which get to read from the test
1068 * input file. The latter are usually best implemented by calling on the
1069 * former.
1070 *
1071 * The two main rules are as follows.
1072 *
1073 * * Leave the file position at the beginning of the line following
1074 * whatever it was that you read.
1075 *
1076 * * When you read and consume a newline (which you do at least once, by
1077 * the previous rule), then increment @tv->lno@ to keep track of the
1078 * current line number.
1079 */
1080
1081 /* --- @tvec_syntax@, @tvec_syntax_v@ --- *
1082 *
1083 * Arguments: @struct tvec_state *tv@ = test-vector state
1084 * @int ch@ = the character found (in @fgetc@ format)
1085 * @const char *expect@, @va_list ap@ = what was expected
1086 *
1087 * Returns: %$-1$%.
1088 *
1089 * Use: Report a syntax error quoting @ch@ and @expect@. If @ch@ is
1090 * a newline, then back up so that it can be read again (e.g.,
1091 * by @tvec_flushtoeol@ or @tvec_nexttoken@, which will also
1092 * advance the line number).
1093 */
1094
1095 extern PRINTF_LIKE(3, 4)
1096 int tvec_syntax(struct tvec_state */*tv*/, int /*ch*/,
1097 const char */*expect*/, ...);
1098 extern int tvec_syntax_v(struct tvec_state */*tv*/, int /*ch*/,
1099 const char */*expect*/, va_list */*ap*/);
1100
1101 /* --- @tvec_skipspc@ --- *
1102 *
1103 * Arguments: @struct tvec_state *tv@ = test-vector state
1104 *
1105 * Returns: ---
1106 *
1107 * Use: Advance over any whitespace characters other than newlines.
1108 * This will stop at `;', end-of-file, or any other kind of
1109 * non-whitespace; and it won't consume a newline.
1110 */
1111
1112 extern void tvec_skipspc(struct tvec_state */*tv*/);
1113
1114 /* --- @tvec_flushtoeol@ --- *
1115 *
1116 * Arguments: @struct tvec_state *tv@ = test-vector state
1117 * @unsigned f@ = flags (@TVFF_...@)
1118 *
1119 * Returns: Zero on success, %$-1$% on error.
1120 *
1121 * Use: Advance to the start of the next line, consuming the
1122 * preceding newline.
1123 *
1124 * A syntax error is reported if no newline character is found,
1125 * i.e., the file ends in mid-line. A syntax error is also
1126 * reported if material other than whitespace or a comment is
1127 * found before the end of the line end, and @TVFF_ALLOWANY@ is
1128 * not set in @f@. The line number count is updated
1129 * appropriately.
1130 */
1131
1132 #define TVFF_ALLOWANY 1u
1133 extern int tvec_flushtoeol(struct tvec_state */*tv*/, unsigned /*f*/);
1134
1135 /* --- @tvec_nexttoken@ --- *
1136 *
1137 * Arguments: @struct tvec_state *tv@ = test-vector state
1138 *
1139 * Returns: Zero if there is a next token which can be read; %$-1$% if no
1140 * token is available.
1141 *
1142 * Use: Advance to the next whitespace-separated token, which may be
1143 * on the next line.
1144 *
1145 * Tokens are separated by non-newline whitespace, comments, and
1146 * newlines followed by whitespace; a newline /not/ followed by
1147 * whitespace instead begins the next assignment, and two
1148 * newlines separated only by whitespace terminate the data for
1149 * a test.
1150 *
1151 * If this function returns zero, then the next character in the
1152 * file begins a suitable token which can be read and
1153 * processed. If it returns %$-1$% then there is no such token,
1154 * and the file position is left correctly. The line number
1155 * count is updated appropriately.
1156 */
1157
1158 extern int tvec_nexttoken(struct tvec_state */*tv*/);
1159
1160 /* --- @tvec_readword@, @tvec_readword_v@ --- *
1161 *
1162 * Arguments: @struct tvec_state *tv@ = test-vector state
1163 * @dstr *d@ = string to append the word to
1164 * @const char **p_inout@ = pointer into string, updated
1165 * @const char *delims@ = additional delimiters to stop at
1166 * @const char *expect@, @va_list ap@ = what was expected
1167 *
1168 * Returns: Zero on success, %$-1$% on failure.
1169 *
1170 * Use: A `word' consists of characters other than whitespace, null
1171 * characters, and other than those listed in @delims@;
1172 * furthermore, a word does not begin with a `;'. (If you want
1173 * reading to stop at comments not preceded by whitespace, then
1174 * include `;' in @delims@. This is a common behaviour.)
1175 *
1176 * If there is no word beginning at the current file position,
1177 * then return %$-1$%; furthermore, if @expect@ is not null,
1178 * then report an appropriate error via @tvec_syntax@.
1179 *
1180 * Otherwise, the word is accumulated in @d@ and zero is
1181 * returned; if @d@ was not empty at the start of the call, the
1182 * newly read word is separated from the existing material by a
1183 * single space character. Since null bytes are never valid
1184 * word constituents, a null terminator is written to @d@, and
1185 * it is safe to treat the string in @d@ as being null-
1186 * terminated.
1187 *
1188 * If @p_inout@ is not null, then @*p_inout@ must be a pointer
1189 * into @d->buf@, which will be adjusted so that it will
1190 * continue to point at the same position even if the buffer is
1191 * reallocated. As a subtle tweak, if @*p_inout@ initially
1192 * points at the end of the buffer, then it will be adjusted to
1193 * point at the beginning of the next word, rather than at the
1194 * additional intervening space.
1195 */
1196
1197 extern PRINTF_LIKE(5, 6)
1198 int tvec_readword(struct tvec_state */*tv*/, dstr */*d*/,
1199 const char **/*p_inout*/, const char */*delims*/,
1200 const char */*expect*/, ...);
1201 extern int tvec_readword_v(struct tvec_state */*tv*/, dstr */*d*/,
1202 const char **/*p_inout*/, const char */*delims*/,
1203 const char */*expect*/, va_list */*ap*/);
1204
1205 /*----- That's all, folks -------------------------------------------------*/
1206
1207 #ifdef __cplusplus
1208 }
1209 #endif
1210
1211 #endif