3 * Test vector processing 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,
35 /* Here's the overall flow for a testing session.
38 * -> output @bsession@
43 * -> type @init@ (input and output)
44 * -> type @parse@ (input)
48 * -> output @skipgroup@
83 * -> output @skipgroup@
88 * -> output @esession@
92 * -> type @dump@ (compact style)
97 * -> @tvec_benchreport@
99 * The output functions @error@ and @notice@ can be called at arbitrary
103 /*----- Header files ------------------------------------------------------*/
122 #ifndef MLIB_GPRINTF_H
123 # include "gprintf.h"
126 #ifndef MLIB_MACROS_H
130 /*----- Miscellaneous values ----------------------------------------------*/
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.
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 */
143 #define TVEC_DEFSLOT(tag, ty, slot) ty slot;
144 TVEC_MISCSLOTS(TVEC_DEFSLOT)
148 #define TVEC_DEFCONST(tag, ty, slot) TVMISC_##tag,
149 TVEC_MISCSLOTS(TVEC_DEFCONST)
153 /*----- Register values ---------------------------------------------------*/
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.
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.)
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.
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
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 */
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.)
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.
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.
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 */
228 /* A register definition. Register definitions list the registers which
229 * are used by a particular test group (see `struct tvec_test' below).
231 * A vector of register definitions is terminated by a definition whose
232 * `name' slot is null.
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 */
244 #define TVEC_ENDREGS { 0, 0, 0, 0, { 0 } }
246 /* @TVEC_GREG(vec, i, regsz)@
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.
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.
258 #define TVEC_GREG(vec, i, regsz) \
259 ((struct tvec_reg *)((unsigned char *)(vec) + (i)*(regsz)))
261 /*----- Register types ----------------------------------------------------*/
263 struct tvec_state; /* forward declaration */
266 /* A register type. */
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
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.
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@.
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.
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.
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@. If @TVSF_NEXT@ is not set on exit,
306 * then the caller will advance to the start of the next non-continuation
307 * line, reporting an error it any non-whitespace non-comment material
308 * found following a successful return.
311 void (*dump)(const union tvec_regval */*rv*/,
312 const struct tvec_regdef */*rd*/,
314 const struct gprintf_ops */*gops*/, void */*go*/);
315 #define TVSF_COMPACT 1u
317 /* Write a human-readable representation of the value @*rv@ using
318 * @gprintf@ on @gops@ and @go@. The @style@ is a collection of flags:
319 * if @TVSF_COMPACT@ is set, then output should be minimal, and must fit
320 * on a single line; otherwise, output may consist of multiple lines and
321 * may contain redundant information if that is likely to be useful to a
322 * human reader. If @TVSF_RAW@ is set, then output should prefer
323 * machine-readability over human-readability.
327 /*----- Test descriptions -------------------------------------------------*/
331 typedef void tvec_testfn(const struct tvec_reg */*in*/,
332 struct tvec_reg */*out*/,
334 /* A test function. It should read inputs from @in@ and write outputs to
335 * @out@. The @TVRF_LIVE@ is set on inputs which are actually present, and
336 * on outputs which are wanted to test. A test function can set additional
337 * `gratuitous outputs' by setting @TVRF_LIVE@ on them; clearing
338 * @TVRF_LIVE@ on a wanted output causes a mismatch.
340 * A test function may be called zero or more times by the environment. In
341 * particular, it may be called multiple times, though usually by prior
342 * arrangement with the environment.
344 * The @ctx@ is supplied by the environment's @run@ function (see below).
345 * The default environment calls the test function once, with a null
346 * @ctx@. There is no expectation that the environment's context has
347 * anything to do with the test function's context.
350 typedef int tvec_setvarfn(struct tvec_state */*tv*/, const char */*var*/,
351 const union tvec_regval */*rv*/, void */*ctx*/);
352 /* Called after a variable is read. Return zero on success or %$-1$% on
353 * error. This function is never called if the test group is skipped.
357 size_t regsz; /* (minimum) register size */
358 tvec_setvarfn *setvar; /* function to set variable */
359 struct tvec_regdef def; /* register definition */
362 typedef void tvec_envsetupfn(struct tvec_state */*tv*/,
363 const struct tvec_env */*env*/,
364 void */*pctx*/, void */*ctx*/);
365 /* Initialize the context; called at the start of a test group; @pctx@ is
366 * null for environments called by the core, but may be non-null for
367 * subordinate environments. If setup fails, the function should call
368 * @tvec_skipgroup@ with a suitable excuse. The @set@, @after@, and
369 * @teardown@ entry points will still be called, but @before@ and @run@
373 typedef const struct tvec_vardef *tvec_envfindvarfn
374 (struct tvec_state */*tv*/, const char */*name*/,
375 void **/*ctx_out*/, void */*ctx*/);
376 /* Called when the parser finds a %|@var|%' special variable. If a
377 * suitable variable was found, set @*ctx_out@ to a suitable context and
378 * return the variable definition; the context will be passed to the
379 * variable definition's @setvar@ function. If no suitable variable was
380 * found, then return null.
383 typedef void tvec_envbeforefn(struct tvec_state */*tv*/, void */*ctx*/);
384 /* Called prior to running a test. This is the right place to act on any
385 * `%|@var|%' settings. If preparation fails, the function should call
386 * @tvec_skip@ with a suitable excuse. This function is never called if
387 * the test group is skipped. It %%\emph{is}%% called if the test will be
388 * skipped due to erroneous test data. It should check the @TVSF_ACTIVE@
392 typedef void tvec_envrunfn(struct tvec_state */*tv*/,
393 tvec_testfn */*fn*/, void */*ctx*/);
394 /* Run the test. It should either call @tvec_skip@, or run @fn@ one or
395 * more times. In the latter case, it is responsible for checking the
396 * outputs, and calling @tvec_fail@ as necessary; @tvec_checkregs@ will
397 * check the register values against the supplied test vector, while
398 * @tvec_check@ does pretty much everything necessary. This function is
399 * never called if the test group is skipped.
402 typedef void tvec_envafterfn(struct tvec_state */*tv*/, void */*ctx*/);
403 /* Called after running or skipping a test. Typical actions involve
404 * resetting whatever things were established by @set@. This function
405 * %%\emph{is}%% called if the test group is skipped or the test data is
406 * erroneous, so that the test environment can reset variables set by the
407 * @set@ entry point. It should check the @TVSF_SKIP@ flag if necessary.
410 typedef void tvec_envteardownfn(struct tvec_state */*tv*/, void */*ctx*/);
411 /* Tear down the environment: called at the end of a test group. */
414 /* A test environment sets things up for and arranges to run the test.
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.
422 size_t ctxsz; /* environment context size */
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 */
433 /* A test description. */
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 */
442 /* An overall test configuration. */
444 const struct tvec_test *const *tests; /* the tests to be performed */
445 unsigned nrout, nreg; /* number of output/total regs */
446 size_t regsz; /* size of a register */
449 /*----- Test state --------------------------------------------------------*/
454 /* Possible test outcomes. */
456 TVOUT_LOSE, /* test failed */
457 TVOUT_SKIP, /* test skipped */
458 TVOUT_XFAIL, /* test passed, but shouldn't have */
459 TVOUT_WIN, /* test passed */
460 TVOUT_LIMIT /* (number of possible outcomes) */
464 /* The primary state structure for the test vector machinery. */
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 #define TVSF_NEXT 0x0400u /* input at next definition */
478 /* Memory allocation. Read-only for all callers. */
481 /* Test configuration. Read-only for all callers. */
482 struct tvec_config cfg; /* test configuration */
484 /* Registers. Available to execution environments, which may modify the
485 * contents of the active registers, as defined by the current test group,
486 * but not the vector pointers themselves or inactive registers.
488 struct tvec_reg *in, *out; /* register vectors */
490 /* Test group state. Read-only for all callers. */
491 const struct tvec_test *test; /* current test */
493 /* Test scoreboard. Available to output formatters. */
494 unsigned curr[TVOUT_LIMIT], all[TVOUT_LIMIT], grps[TVOUT_LIMIT];
496 /* Output machinery. Read-only for environments. */
497 struct tvec_output *output; /* output formatter */
499 /* Input machinery. Available to type parsers. */
500 const char *infile; unsigned lno, test_lno; /* input file name, line */
501 FILE *fp; /* input file stream */
503 /* Adhoc testing state. Private. */
504 struct tvec_test adhoc_test;
505 const struct tvec_test *adhoc_tests[];
508 /* @TVEC_REG(tv, vec, i)@
510 * If @tv@ is a pointer to a @struct tvec_state@, @vec@ is either @in@ or
511 * @out@, and @i@ is an integer, then this evaluates to the address of the
512 * @i@th register in the selected vector.
514 #define TVEC_REG(tv, vec, i) TVEC_GREG((tv)->vec, (i), (tv)->cfg.regsz)
516 /*----- Session lifecycle -------------------------------------------------*/
518 /* --- @tvec_begin@ --- *
520 * Arguments: @struct tvec_state *tv_out@ = state structure to fill in
521 * @const struct tvec_config *config@ = test configuration
522 * @struct tvec_output *o@ = output driver
526 * Use: Initialize a state structure ready to do some testing. The
527 * test state takes ownership of the output driver: @tvec_end@
531 extern void tvec_begin(struct tvec_state */*tv_out*/,
532 const struct tvec_config */*config*/,
533 struct tvec_output */*o*/);
535 /* --- @tvec_end@ --- *
537 * Arguments: @struct tvec_state *tv@ = test-vector state
539 * Returns: A proposed exit code.
541 * Use: Conclude testing and suggests an exit code to be returned to
542 * the calling program. (The exit code comes from the output
543 * driver's @esession@ method.) The output driver, originally
544 * passed to @tvec_begin@ is destroyed.
547 extern int tvec_end(struct tvec_state */*tv*/);
549 /* --- @tvec_read@ --- *
551 * Arguments: @struct tvec_state *tv@ = test-vector state
552 * @const char *infile@ = the name of the input file
553 * @FILE *fp@ = stream to read from
555 * Returns: Zero on success, %$-1$% on error.
557 * Use: Read test vector data from @fp@ and exercise test functions.
558 * THe return code doesn't indicate test failures: it's only
559 * concerned with whether there were problems with the input
560 * file or with actually running the tests.
563 extern int tvec_read(struct tvec_state */*tv*/,
564 const char */*infile*/, FILE */*fp*/);
566 /*----- Command-line interface --------------------------------------------*/
568 /* --- @tvec_parseargs@ --- *
570 * Arguments: @int argc@ = number of command-line arguments
571 * @char *argv[]@ = vector of argument strings
572 * @struct tvec_state *tv_out@ = test vector state to initialize
573 * @int *argpos_out@ = where to leave unread argument index
574 * @const struct tvec_config *config@ = test vector
579 * Use: Parse arguments and set up the test vector state @*tv_out@.
580 * If errors occur, print messages to standard error and exit
584 extern void tvec_parseargs(int /*argc*/, char */*argv*/[],
585 struct tvec_state */*tv_out*/,
587 const struct tvec_config */*config*/);
589 /* --- @tvec_readstdin@, @tvec_readfile@, @tvec_readarg@ --- *
591 * Arguments: @struct tvec_state *tv@ = test vector state
592 * @const char *file@ = pathname of file to read
593 * @const char *arg@ = argument to interpret
595 * Returns: Zero on success, %$-1$% on error.
597 * Use: Read test vector data from stdin or a named file. The
598 * @tvec_readarg@ function reads from stdin if @arg@ is `%|-|%',
599 * and from the named file otherwise.
602 extern int tvec_readstdin(struct tvec_state */*tv*/);
603 extern int tvec_readfile(struct tvec_state */*tv*/, const char */*file*/);
604 extern int tvec_readarg(struct tvec_state */*tv*/, const char */*arg*/);
606 /* --- @tvec_readdflt@ --- *
608 * Arguments: @struct tvec_state *tv@ = test vector state
609 * @const char *dflt@ = defsault filename or null
611 * Returns: Zero on success, %$-1$% on error.
613 * Use: Reads from the default test vector data. If @file@ is null,
614 * then read from standard input, unless that's a terminal; if
615 * @file@ is not null, then read the named file, looking in the
616 * directory named by the `%|srcdir|%' environment variable if
617 * that's set, or otherwise in the current directory.
620 extern int tvec_readdflt(struct tvec_state */*tv*/, const char */*file*/);
622 /* --- @tvec_readargs@ --- *
624 * Arguments: @int argc@ = number of command-line arguments
625 * @char *argv[]@ = vector of argument strings
626 * @struct tvec_state *tv@ = test vector state
627 * @int *argpos_inout@ = current argument position (updated)
628 * @const char *dflt@ = default filename or null
630 * Returns: Zero on success, %$-1$% on error.
632 * Use: Reads from the sources indicated by the command-line
633 * arguments, in order, interpreting each as for @tvec_readarg@;
634 * if no arguments are given then read from @dflt@ as for
638 extern int tvec_readargs(int /*argc*/, char */*argv*/[],
639 struct tvec_state */*tv*/,
640 int */*argpos_inout*/, const char */*dflt*/);
642 /* --- @tvec_main@ --- *
644 * Arguments: @int argc@ = number of command-line arguments
645 * @char *argv[]@ = vector of argument strings
646 * @const struct tvec_config *config@ = test vector
648 * @const char *dflt@ = default filename or null
650 * Returns: Exit code.
652 * Use: All-in-one test vector front-end. Parse options from the
653 * command-line as for @tvec_parseargs@, and then process the
654 * remaining positional arguments as for @tvec_readargs@. The
655 * function constructs and disposes of a test vector state.
658 extern int tvec_main(int /*argc*/, char */*argv*/[],
659 const struct tvec_config */*config*/,
660 const char */*dflt*/);
662 /*----- Test processing ---------------------------------------------------*/
664 /* --- @tvec_skipgroup@, @tvec_skipgroup_v@ --- *
666 * Arguments: @struct tvec_state *tv@ = test-vector state
667 * @const char *excuse@, @va_list *ap@ = reason why skipped
671 * Use: Skip the current group. This should only be called from a
672 * test environment @setup@ function; a similar effect occurs if
673 * the @setup@ function fails.
676 extern PRINTF_LIKE(2, 3)
677 void tvec_skipgroup(struct tvec_state */*tv*/,
678 const char */*excuse*/, ...);
679 extern void tvec_skipgroup_v(struct tvec_state */*tv*/,
680 const char */*excuse*/, va_list */*ap*/);
682 /* --- @tvec_skip@, @tvec_skip_v@ --- *
684 * Arguments: @struct tvec_state *tv@ = test-vector state
685 * @const char *excuse@, @va_list *ap@ = reason why test skipped
689 * Use: Skip the current test. This should only be called from a
690 * test environment @run@ function; a similar effect occurs if
691 * the @before@ function fails.
694 extern PRINTF_LIKE(2, 3)
695 void tvec_skip(struct tvec_state */*tv*/, const char */*excuse*/, ...);
696 extern void tvec_skip_v(struct tvec_state */*tv*/,
697 const char */*excuse*/, va_list */*ap*/);
699 /* --- @tvec_fail@, @tvec_fail_v@ --- *
701 * Arguments: @struct tvec_state *tv@ = test-vector state
702 * @const char *detail@, @va_list *ap@ = description of test
706 * Use: Report the current test as a failure. This function can be
707 * called multiple times for a single test, e.g., if the test
708 * environment's @run@ function invokes the test function
709 * repeatedly; but a single test that fails repeatedly still
710 * only counts as a single failure in the statistics. The
711 * @detail@ string and its format parameters can be used to
712 * distinguish which of several invocations failed; it can
713 * safely be left null if the test function is run only once.
716 extern PRINTF_LIKE(2, 3)
717 void tvec_fail(struct tvec_state */*tv*/, const char */*detail*/, ...);
718 extern void tvec_fail_v(struct tvec_state */*tv*/,
719 const char */*detail*/, va_list */*ap*/);
721 /* --- @tvec_dumpreg@ --- *
723 * Arguments: @struct tvec_state *tv@ = test-vector state
724 * @unsigned disp@ = the register disposition (@TVRD_...@)
725 * @const union tvec_regval *tv@ = register value, or null
726 * @const struct tvec_regdef *rd@ = register definition
730 * Use: Dump a register value to the output. This is the lowest-
731 * level function for dumping registers, and calls the output
732 * formatter directly.
734 * Usually @tvec_mismatch@ is much more convenient. Low-level
735 * access is required for reporting `virtual' registers
736 * corresponding to test environment settings.
739 extern void tvec_dumpreg(struct tvec_state */*tv*/,
740 unsigned /*disp*/, const union tvec_regval */*rv*/,
741 const struct tvec_regdef */*rd*/);
743 /* --- @tvec_initregs@, @tvec_releaseregs@ --- *
745 * Arguments: @struct tvec_state *tv@ = test-vector state
749 * Use: Initialize or release, respectively, the registers required
750 * by the current test. All of the registers, both input and
751 * output, are effected. Initialized registers are not marked
755 extern void tvec_initregs(struct tvec_state */*tv*/);
756 extern void tvec_releaseregs(struct tvec_state */*tv*/);
758 /* --- @tvec_resetoutputs@ --- *
760 * Arguments: @struct tvec_state *tv@ = test-vector state
764 * Use: Reset (releases and reinitializes) the output registers in
765 * the test state. This is mostly of use to test environment
766 * @run@ functions, between invocations of the test function.
767 * Output registers are marked live if and only if the
768 * corresponding input register is live.
771 extern void tvec_resetoutputs(struct tvec_state */*tv*/);
773 /* --- @tvec_checkregs@ --- *
775 * Arguments: @struct tvec_state *tv@ = test-vector state
777 * Returns: Zero on success, %$-1$% on mismatch.
779 * Use: Compare the active output registers (according to the current
780 * test group definition) with the corresponding input register
781 * values. A mismatch occurs if the two values differ
782 * (according to the register type's @eq@ method), or if the
783 * input is live but the output is dead.
785 * This function only checks for a mismatch and returns the
786 * result; it takes no other action. In particular, it doesn't
787 * report a failure, or dump register values.
790 extern int tvec_checkregs(struct tvec_state */*tv*/);
792 /* --- @tvec_mismatch@ --- *
794 * Arguments: @struct tvec_state *tv@ = test-vector state
795 * @unsigned f@ = flags (@TVMF_...@)
799 * Use: Dumps registers suitably to report a mismatch. The flag bits
800 * @TVMF_IN@ and @TVF_OUT@ select input-only and output
801 * registers. If both are reset then nothing happens.
802 * Suppressing the output registers may be useful, e.g., if the
803 * test function crashed rather than returning outputs.
808 extern void tvec_mismatch(struct tvec_state */*tv*/, unsigned /*f*/);
810 /* --- @tvec_check@, @tvec_check_v@ --- *
812 * Arguments: @struct tvec_state *tv@ = test-vector state
813 * @const char *detail@, @va_list *ap@ = description of test
817 * Use: Check the register values, reporting a failure and dumping
818 * the registers in the event of a mismatch. This just wraps up
819 * @tvec_checkregs@, @tvec_fail@ and @tvec_mismatch@ in the
823 extern PRINTF_LIKE(2, 3)
824 void tvec_check(struct tvec_state */*tv*/, const char */*detail*/, ...);
825 extern void tvec_check_v(struct tvec_state */*tv*/,
826 const char */*detail*/, va_list */*ap*/);
828 /*----- Output functions --------------------------------------------------*/
830 /* --- @tvec_strlevel@ --- *
832 * Arguments: @unsigned level@ = level code
834 * Returns: A human-readable description.
836 * Use: Converts a level code into something that you can print in a
840 extern const char *tvec_strlevel(unsigned /*level*/);
842 /* --- @tvec_report@, @tvec_report_v@ --- *
844 * Arguments: @struct tvec_state *tv@ = test-vector state
845 * @const char *msg@, @va_list *ap@ = error message
849 * Use: Report an message with a given severity. Messages with level
850 * @TVLEV_ERR@ or higher force a nonzero exit code.
853 #define TVEC_LEVELS(_) \
855 _(NOTE, "notice", 4) \
858 #define TVEC_DEFLEVEL(tag, name, val) TVLEV_##tag = val,
859 TVEC_LEVELS(TVEC_DEFLEVEL)
864 extern PRINTF_LIKE(3, 4)
865 void tvec_report(struct tvec_state */*tv*/, unsigned /*level*/,
866 const char */*msg*/, ...);
867 extern void tvec_report_v(struct tvec_state */*tv*/, unsigned /*level*/,
868 const char */*msg*/, va_list */*ap*/);
870 /* --- @tvec_error@, @tvec_notice@, @tvec_info@ --- *
872 * Arguments: @struct tvec_state *tv@ = test-vector state
873 * @const char *msg@, @va_list *ap@ = error message
875 * Returns: The @tvec_error@ function returns %$-1$% as a trivial
876 * convenience; @tvec_notice@ does not return a value.
878 * Use: Report a message. Errors are distinct from test
879 * failures, and indicate that a problem was encountered which
880 * compromised the activity of testing. Notices are important
881 * information which doesn't fit into any other obvious
882 * category. Information is anything else, and is a reasonable
883 * fallback for writing unstructured information in the absence
884 * of dedicated support in an output driver.
886 * These functions are simple convenience wrappers around
887 * @tvec_report@. Use @tvec_report_v@ directly if you have a
888 * captured @va_list@ of arguments to format.
891 extern PRINTF_LIKE(2, 3)
892 int tvec_error(struct tvec_state */*tv*/, const char */*msg*/, ...);
893 extern PRINTF_LIKE(2, 3)
894 void tvec_notice(struct tvec_state */*tv*/, const char */*msg*/, ...);
895 extern PRINTF_LIKE(2, 3)
896 void tvec_info(struct tvec_state */*tv*/, const char */*msg*/, ...);
898 /* --- @tvec_unkregerr@ --- *
900 * Arguments: @struct tvec_state *tv@ = test-vector state
901 * @const char *name@ = register or pseudoregister name
905 * Use: Reports an error that the register or pseudoregister is
909 extern int tvec_unkregerr(struct tvec_state */*tv*/, const char */*name*/);
911 /* --- @tvec_dupregerr@ --- *
913 * Arguments: @struct tvec_state *tv@ = test-vector state
914 * @const char *name@ = register or pseudoregister name
918 * Use: Reports an error that the register or pseudoregister has been
919 * assigned already in the current test.
922 extern int tvec_dupregerr(struct tvec_state */*tv*/, const char */*name*/);
924 /*----- Built-in output drivers -------------------------------------------*/
926 /* --- @tvec_humanoutput@ --- *
928 * Arguments: @FILE *fp@ = output file to write on
929 * @unsigned f, m@ = flags and mask
931 * Returns: An output formatter.
933 * Use: Return an output formatter which writes on @fp@ with the
934 * expectation that a human will interpret the output.
936 * The flags @f@ and mask @m@ operate together. Flag bits not
937 * covered by the mask must be left clear, i.e., @f&~m$ must be
938 * zero; the semantics are that a set mask bit indicates that
939 * the corresponding bit of @f@ should control the indicated
940 * behaviour; a clear mask bit indicates that a suitable default
941 * should be chosen based on environmental conditions.
943 * If @TVHF_TTY@ is set, then the output shows a `scoreboard'
944 * indicating the outcome of each test case attempted, providing
945 * a visual indication of progress. If @TVHF_COLOUR@ is set,
946 * then the output uses control codes for colour and other
947 * highlighting. It is unusual to set @TVHF_COLOUR@ without
948 * @TVHF_TTY@, this is permitted anyway.
950 * The environment variables %|TVEC_TTY|% and %|TVEC_COLOUR|%
951 * provide default values for these settings. If they are not
952 * set, then @TVHF_TTY@ is set if @fp@ refers to a terminal, and
953 * @TVHF_COLOUR@ is set if @TVHF_TTY@ is set and, additionally,
954 * the %|TERM|% environment variable is set to a value other
958 #define TVHF_TTY 1u /* output to terminal */
959 #define TVHF_COLOUR 2u /* output in colour */
960 extern struct tvec_output *tvec_humanoutput(FILE */*fp*/,
961 unsigned /*f*/, unsigned /*m*/);
963 /* --- @tvec_machineoutput@ --- *
965 * Arguments: @FILE *fp@ = output file to write on
967 * Returns: An output formatter.
969 * Use: Return an output formatter which writes on @fp@ in a
970 * moderately simple machine-readable format.
973 struct tvec_output *tvec_machineoutput(FILE *fp);
975 /* --- @tvec_tapoutput@ --- *
977 * Arguments: @FILE *fp@ = output file to write on
978 * @unsigned style@ = output style (@TVSF_...@)
980 * Returns: An output formatter.
982 * Use: Return an output formatter which writes on @fp@ in `TAP'
983 * (`Test Anything Protocol') format.
985 * TAP comes from the Perl community, but has spread rather
986 * further. This driver currently produces TAP version 14, but
987 * pretends to be version 13. The driver produces a TAP `test
988 * point' -- i.e., a result reported as `ok' or `not ok' -- for
989 * each input test group. Failure reports and register dumps
990 * are produced as diagnostic messages before the final group
991 * result. (TAP permits structuerd YAML data after the
992 * test-point result, which could be used to report details, but
993 * (a) postponing the details until after the report is
994 * inconvenient, and (b) there is no standardization for the
995 * YAML anyway, so in practice it's no more useful than the
996 * unstructured diagnostics.
999 extern struct tvec_output *tvec_tapoutput(FILE */*fp*/);
1001 /* --- @tvec_dfltoutput@ --- *
1003 * Arguments: @FILE *fp@ = output file to write on
1005 * Returns: An output formatter.
1007 * Use: Selects and instantiates an output formatter suitable for
1008 * writing on @fp@. The policy is subject to change, but
1009 * currently the `human' output format is selected if @fp@ is
1010 * interactive (i.e., if @isatty(fileno(fp))@ is true), and
1011 * otherwise the `machine' format is used.
1014 extern struct tvec_output *tvec_dfltoutput(FILE */*fp*/);
1016 /* --- @tvec_amoutput@ --- *
1018 * Arguments: @const struct tvec_amargs *a@ = arguments from Automake
1019 * command-line protocol
1021 * Returns: An output formatter.
1023 * Use: Returns an output formatter which writes on standard output
1024 * in human format, pretending that the output is to a terminal
1025 * (in order to cope with %%\manpage{make}{1}%%'s output-
1026 * buffering behaviour, writes to the log file @a->log@ in
1027 * machine-readable format, and writes an Automake rST-format
1028 * test result file to @a->trs@. The `test name' is currently
1029 * ignored, because the framework has its own means of
1030 * determining test names.
1033 struct tvec_amargs {
1034 unsigned f; /* flags */
1035 #define TVAF_COLOUR 1u /* produce colour output */
1036 const char *name; /* test name */
1037 FILE *log; /* `log' output file */
1038 FILE *trs; /* `trs' summary file */
1041 extern struct tvec_output *tvec_amoutput(const struct tvec_amargs */*a*/);
1043 /*------ Serialization utilities ------------------------------------------*/
1045 /* Serialization format.
1047 * The `candidate register definitions' are those entries @r@ in the @regs@
1048 * vector whose index @r.i@ is strictly less than @nr@ and where
1049 * @r.f&mask == want@* . The `selected register definitions' are those
1050 * candidate register definitions @r@ for which the indicated register
1051 * @rv[r.i]@ has the @TVRF_LIVE@ flag set. The serialized output begins with
1052 * a header bitmap: if there are %$n$% candidate register definitions then
1053 * the header bitmap consists of %$\lceil n/8 \rceil$% bytes. Bits are
1054 * ordered starting from the least significant bit of the first byte, end
1055 * ending at the most significant bit of the final byte. The bit
1056 * corresponding to a candidate register definition is set if and only if
1057 * that register defintion is selected. The header bitmap is then followed
1058 * by the serializations of the selected registers -- i.e., for each selected
1059 * register definition @r@, the serialized value of register @rv[r.i]@ --
1060 * simply concatenated together, with no padding or alignment.
1063 /* --- @tvec_serialize@ --- *
1065 * Arguments: @const struct tvec_reg *rv@ = vector of registers
1066 * @buf *b@ = buffer to write on
1067 * @const struct tvec_regdef *regs@ = vector of register
1068 * descriptions, terminated by an entry with a null
1070 * @unsigned mask, want@ = flag-based selection
1071 * @unsigned nr@ = number of entries in the @rv@ vector
1072 * @size_t regsz@ = true size of each element of @rv@
1074 * Returns: Zero on success, %$-1$% on failure.
1076 * Use: Serialize a collection of register values.
1078 * The serialized output is written to the buffer @b@. Failure
1079 * can be caused by running out of buffer space, or a failing
1083 extern int tvec_serialize(const struct tvec_reg */*rv*/, buf */*b*/,
1084 const struct tvec_regdef */*regs*/,
1085 unsigned /*mask*/, unsigned /*want*/,
1086 unsigned /*nr*/, size_t /*regsz*/);
1088 /* --- @tvec_deserialize@ --- *
1090 * Arguments: @struct tvec_reg *rv@ = vector of registers
1091 * @buf *b@ = buffer to write on
1092 * @const struct tvec_regdef *regs@ = vector of register
1093 * descriptions, terminated by an entry with a null
1095 * @unsigned mask, want@ = flag-based selection
1096 * @unsigned nr@ = number of entries in the @rv@ vector
1097 * @size_t regsz@ = true size of each element of @rv@
1099 * Returns: Zero on success, %$-1$% on failure.
1101 * Use: Deserialize a collection of register values.
1103 * The size of the register vector @nr@ and the register
1104 * definitions @regs@ must match those used when producing the
1105 * serialization. For each serialized register value,
1106 * deserialize and store the value into the appropriate register
1107 * slot, and set the @TVRF_LIVE@ flag on the register. See
1108 * @tvec_serialize@ for a description of the format.
1110 * Failure results only from an input too small for the initial
1111 * bitmap or a failing register type handler.
1114 extern int tvec_deserialize(struct tvec_reg */*rv*/, buf */*b*/,
1115 const struct tvec_regdef */*regs*/,
1116 unsigned /*mask*/, unsigned /*want*/,
1117 unsigned /*nr*/, size_t /*regsz*/);
1119 /*----- Input utilities ---------------------------------------------------*/
1121 /* These are provided by the core for the benefit of type @parse@ methods,
1122 * and test-environment @set@ functions, which get to read from the test
1123 * input file. The latter are usually best implemented by calling on the
1126 * The two main rules are as follows.
1128 * * Leave the file position at the beginning of the line following
1129 * whatever it was that you read.
1131 * * When you read and consume a newline (which you do at least once, by
1132 * the previous rule), then increment @tv->lno@ to keep track of the
1133 * current line number.
1136 /* --- @tvec_syntax@, @tvec_syntax_v@ --- *
1138 * Arguments: @struct tvec_state *tv@ = test-vector state
1139 * @int ch@ = the character found (in @fgetc@ format)
1140 * @const char *expect@, @va_list *ap@ = what was expected
1144 * Use: Report a syntax error quoting @ch@ and @expect@.
1146 * If @ch@ is a newline, or if @TVSF_NEXT@ is set, then unread
1147 * it so that it can be read again (e.g., by @tvec_nexttoken@).
1148 * The intent here is that you can safely read a character,
1149 * inspect it, and then complain about it with @tvec_syntax@
1150 * without having to worry too much about backing up. The
1151 * flipside of this is that you %%\emph{must}%% read a
1152 * character, even if you don't have one ready, e,g, if you
1153 * called @tvec_nexttoken@ and it said there wasn't one
1157 extern PRINTF_LIKE(3, 4)
1158 int tvec_syntax(struct tvec_state */*tv*/, int /*ch*/,
1159 const char */*expect*/, ...);
1160 extern int tvec_syntax_v(struct tvec_state */*tv*/, int /*ch*/,
1161 const char */*expect*/, va_list */*ap*/);
1163 /* --- @tvec_skipspc@ --- *
1165 * Arguments: @struct tvec_state *tv@ = test-vector state
1169 * Use: Advance over any whitespace characters other than newlines.
1170 * This will stop at `;', end-of-file, or any other kind of
1171 * non-whitespace; and it won't consume a newline.
1174 extern void tvec_skipspc(struct tvec_state */*tv*/);
1176 /* --- @tvec_nexttoken@ --- *
1178 * Arguments: @struct tvec_state *tv@ = test-vector state
1180 * Returns: Zero if there is a next token which can be read; %$-1$% if no
1181 * token is available.
1183 * Use: Advance to the next whitespace-separated token, which may be
1186 * Tokens are separated by non-newline whitespace, comments, and
1187 * newlines followed by whitespace; a newline /not/ followed by
1188 * whitespace instead begins the next assignment, and two
1189 * newlines separated only by whitespace terminate the data for
1192 * If this function returns zero, then the next character in the
1193 * file begins a suitable token which can be read and processed.
1194 * If it returns %$-1$% then there is no such token, @TVSF_NEXT@
1195 * is set, and the file position is left correctly. The line
1196 * number count is updated appropriately.
1199 extern int tvec_nexttoken(struct tvec_state */*tv*/);
1201 /* --- @tvec_readword@, @tvec_readword_v@ --- *
1203 * Arguments: @struct tvec_state *tv@ = test-vector state
1204 * @dstr *d@ = string to append the word to
1205 * @const char **p_inout@ = pointer into string, updated
1206 * @const char *delims@ = additional delimiters to stop at
1207 * @const char *expect@, @va_list *ap@ = what was expected
1209 * Returns: Zero on success, %$-1$% on failure.
1211 * Use: A `word' consists of characters other than whitespace, null
1212 * characters, and other than those listed in @delims@;
1213 * furthermore, a word does not begin with a `;'. (If you want
1214 * reading to stop at comments not preceded by whitespace, then
1215 * include `;' in @delims@. This is a common behaviour.)
1217 * The function advances past whitespace and comments, as for
1218 * @tvec_nexttoken@. If there is no word beginning after the
1219 * current file position, but before the start of the next
1220 * non-continuation line, then return %$-1$%; furthermore, if
1221 * @expect@ is not null, then report an appropriate error via
1224 * Otherwise, the word is accumulated in @d@ and zero is
1225 * returned; if @d@ was not empty at the start of the call, the
1226 * newly read word is separated from the existing material by a
1227 * single space character. Since null bytes are never valid
1228 * word constituents, a null terminator is written to @d@, and
1229 * it is safe to treat the string in @d@ as being null-
1232 * If @p_inout@ is not null, then @*p_inout@ must be a pointer
1233 * into @d->buf@, which will be adjusted so that it will
1234 * continue to point at the same position even if the buffer is
1235 * reallocated. As a subtle tweak, if @*p_inout@ initially
1236 * points at the end of the buffer, then it will be adjusted to
1237 * point at the beginning of the next word, rather than at the
1238 * additional intervening space.
1241 extern PRINTF_LIKE(5, 6)
1242 int tvec_readword(struct tvec_state */*tv*/, dstr */*d*/,
1243 const char **/*p_inout*/, const char */*delims*/,
1244 const char */*expect*/, ...);
1245 extern int tvec_readword_v(struct tvec_state */*tv*/, dstr */*d*/,
1246 const char **/*p_inout*/, const char */*delims*/,
1247 const char */*expect*/, va_list */*ap*/);
1249 /*----- That's all, folks -------------------------------------------------*/