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_SYNTH 4u /* register must not be assigned */
242 #define TVRF_ID 8u /* part of test identity */
243 union tvec_misc arg; /* extra detail for the type */
245 #define TVEC_ENDREGS { 0, 0, 0, 0, { 0 } }
247 /* @TVEC_GREG(vec, i, regsz)@
249 * If @vec@ is a data pointer which happens to contain the address of a
250 * vector of @struct tvec_reg@ objects, @i@ is an integer, and @regsz@ is the
251 * size of a @struct tvec_reg@, then this evaluates to the address of the
252 * @i@th element of the vector.
254 * This is the general tool you need for accessing register vectors when you
255 * don't have absolute knowledge of the size of a @union tvec_regval@.
256 * Usually you want to access one of the register vectors in a @struct
257 * tvec_state@, and @TVEC_REG@ will be more convenient.
259 #define TVEC_GREG(vec, i, regsz) \
260 ((struct tvec_reg *)((unsigned char *)(vec) + (i)*(regsz)))
262 /*----- Register types ----------------------------------------------------*/
264 struct tvec_state; /* forward declaration */
267 /* A register type. */
269 void (*init)(union tvec_regval */*rv*/, const struct tvec_regdef */*rd*/);
270 /* Initialize the value in @*rv@. This will be called before any other
271 * function acting on the value, including @release@. Following @init@,
272 * the register value must be valid to use for all other type entry
276 void (*release)(union tvec_regval */*rv*/,
277 const struct tvec_regdef */*rd*/);
278 /* Release any resources associated with the value in @*rv@. The
279 * register value may be left in an invalid state.
282 int (*eq)(const union tvec_regval */*rv0*/,
283 const union tvec_regval */*rv1*/,
284 const struct tvec_regdef */*rd*/);
285 /* Return nonzero if @*rv0@ and @*rv1@ are equal values. Asymmetric
286 * criteria are permitted: @tvec_checkregs@ calls @eq@ with the input
287 * register as @rv0@ and the output as @rv1@.
290 void (*copy)(union tvec_regval */*rvd*/,
291 const union tvec_regval */*rvs*/,
292 const struct tvec_regdef */*rd*/);
293 /* Copy the value from @rvs@ to @rvd@. */
295 int (*tobuf)(buf */*b*/, const union tvec_regval */*rv*/,
296 const struct tvec_regdef */*rd*/);
297 /* Serialize the value @*rv@, writing the result to @b@. Return zero on
298 * success, or %$-1$% on error.
301 int (*frombuf)(buf */*b*/, union tvec_regval */*rv*/,
302 const struct tvec_regdef */*rd*/);
303 /* Deserialize a value from @b@, storing it in @*rv@. Return zero on
304 * success, or %$-1$% on error.
307 int (*parse)(union tvec_regval */*rv*/, const struct tvec_regdef */*rd*/,
308 struct tvec_state */*tv*/);
309 /* Parse a value from @tv->fp@, storing it in @*rv@. Return zero on
310 * success, or %$-1$% on error, having reported one or more errors via
311 * @tvec_error@ or @tvec_syntax@. If @TVSF_NEXT@ is not set on exit,
312 * then the caller will advance to the start of the next non-continuation
313 * line, reporting an error it any non-whitespace non-comment material
314 * found following a successful return.
317 void (*dump)(const union tvec_regval */*rv*/,
318 const struct tvec_regdef */*rd*/,
320 const struct gprintf_ops */*gops*/, void */*go*/);
321 #define TVSF_COMPACT 1u
323 /* Write a human-readable representation of the value @*rv@ using
324 * @gprintf@ on @gops@ and @go@. The @style@ is a collection of flags:
325 * if @TVSF_COMPACT@ is set, then output should be minimal, and must fit
326 * on a single line; otherwise, output may consist of multiple lines and
327 * may contain redundant information if that is likely to be useful to a
328 * human reader. If @TVSF_RAW@ is set, then output should prefer
329 * machine-readability over human-readability.
333 /*----- Test descriptions -------------------------------------------------*/
337 typedef void tvec_testfn(const struct tvec_reg */*in*/,
338 struct tvec_reg */*out*/,
340 /* A test function. It should read inputs from @in@ and write outputs to
341 * @out@. The @TVRF_LIVE@ is set on inputs which are actually present, and
342 * on outputs which are wanted to test. A test function can set additional
343 * `gratuitous outputs' by setting @TVRF_LIVE@ on them; clearing
344 * @TVRF_LIVE@ on a wanted output causes a mismatch.
346 * A test function may be called zero or more times by the environment. In
347 * particular, it may be called multiple times, though usually by prior
348 * arrangement with the environment.
350 * The @ctx@ is supplied by the environment's @run@ function (see below).
351 * The default environment calls the test function once, with a null
352 * @ctx@. There is no expectation that the environment's context has
353 * anything to do with the test function's context.
356 typedef int tvec_setvarfn(struct tvec_state */*tv*/, const char */*var*/,
357 const union tvec_regval */*rv*/, void */*ctx*/);
358 /* Called after a variable is read. Return zero on success or %$-1$% on
359 * error. This function is never called if the test group is skipped.
363 size_t regsz; /* (minimum) register size */
364 tvec_setvarfn *setvar; /* function to set variable */
365 struct tvec_regdef def; /* register definition */
368 typedef void tvec_envsetupfn(struct tvec_state */*tv*/,
369 const struct tvec_env */*env*/,
370 void */*pctx*/, void */*ctx*/);
371 /* Initialize the context; called at the start of a test group; @pctx@ is
372 * null for environments called by the core, but may be non-null for
373 * subordinate environments. If setup fails, the function should call
374 * @tvec_skipgroup@ with a suitable excuse. The @set@, @after@, and
375 * @teardown@ entry points will still be called, but @before@ and @run@
379 typedef const struct tvec_vardef *tvec_envfindvarfn
380 (struct tvec_state */*tv*/, const char */*name*/,
381 void **/*ctx_out*/, void */*ctx*/);
382 /* Called when the parser finds a %|@var|%' special variable. If a
383 * suitable variable was found, set @*ctx_out@ to a suitable context and
384 * return the variable definition; the context will be passed to the
385 * variable definition's @setvar@ function. If no suitable variable was
386 * found, then return null.
389 typedef void tvec_envbeforefn(struct tvec_state */*tv*/, void */*ctx*/);
390 /* Called prior to running a test. This is the right place to act on any
391 * `%|@var|%' settings. If preparation fails, the function should call
392 * @tvec_skip@ with a suitable excuse. This function is never called if
393 * the test group is skipped. It %%\emph{is}%% called if the test will be
394 * skipped due to erroneous test data. It should check the @TVSF_ACTIVE@
398 typedef void tvec_envrunfn(struct tvec_state */*tv*/,
399 tvec_testfn */*fn*/, void */*ctx*/);
400 /* Run the test. It should either call @tvec_skip@, or run @fn@ one or
401 * more times. In the latter case, it is responsible for checking the
402 * outputs, and calling @tvec_fail@ as necessary; @tvec_checkregs@ will
403 * check the register values against the supplied test vector, while
404 * @tvec_check@ does pretty much everything necessary. This function is
405 * never called if the test group is skipped.
408 typedef void tvec_envafterfn(struct tvec_state */*tv*/, void */*ctx*/);
409 /* Called after running or skipping a test. Typical actions involve
410 * resetting whatever things were established by @set@. This function
411 * %%\emph{is}%% called if the test group is skipped or the test data is
412 * erroneous, so that the test environment can reset variables set by the
413 * @set@ entry point. It should check the @TVSF_SKIP@ flag if necessary.
416 typedef void tvec_envteardownfn(struct tvec_state */*tv*/, void */*ctx*/);
417 /* Tear down the environment: called at the end of a test group. */
420 /* A test environment sets things up for and arranges to run the test.
422 * The caller is responsible for allocating storage for the environment's
423 * context, based on the @ctxsz@ slot, and freeing it later; this space is
424 * passed in as the @ctx@ parameter to the remaining functions; if @ctxsz@
425 * is zero then @ctx@ is null.
428 size_t ctxsz; /* environment context size */
430 tvec_envsetupfn *setup; /* setup for group */
431 tvec_envfindvarfn *findvar; /* find variable */
432 tvec_envbeforefn *before; /* prepare for test */
433 tvec_envrunfn *run; /* run test function */
434 tvec_envafterfn *after; /* clean up after test */
435 tvec_envteardownfn *teardown; /* tear down after group */
439 /* A test description. */
441 const char *name; /* name of the test */
442 const struct tvec_regdef *regs; /* descriptions of the registers */
443 const struct tvec_env *env; /* environment to run test in */
444 tvec_testfn *fn; /* test function */
448 /* An overall test configuration. */
450 const struct tvec_test *const *tests; /* the tests to be performed */
451 unsigned nrout, nreg; /* number of output/total regs */
452 size_t regsz; /* size of a register */
455 /*----- Test state --------------------------------------------------------*/
460 /* Possible test outcomes. */
462 TVOUT_LOSE, /* test failed */
463 TVOUT_SKIP, /* test skipped */
464 TVOUT_XFAIL, /* test passed, but shouldn't have */
465 TVOUT_WIN, /* test passed */
466 TVOUT_LIMIT /* (number of possible outcomes) */
470 /* The primary state structure for the test vector machinery. */
472 /* Flags. Read-only for all callers. */
473 unsigned f; /* flags */
474 #define TVSF_SKIP 0x0001u /* skip this test group */
475 #define TVSF_OPEN 0x0002u /* test is open */
476 #define TVSF_ACTIVE 0x0004u /* test is active */
477 #define TVSF_ERROR 0x0008u /* an error occurred */
478 #define TVSF_OUTMASK 0x00f0u /* test outcome (@TVOUT_...@) */
479 #define TVSF_OUTSHIFT 4 /* shift applied to outcome */
480 #define TVSF_XFAIL 0x0100u /* test expected to fail */
481 #define TVSF_MUFFLE 0x0200u /* muffle errors */
482 #define TVSF_NEXT 0x0400u /* input at next definition */
484 /* Memory allocation. Read-only for all callers. */
487 /* Test configuration. Read-only for all callers. */
488 struct tvec_config cfg; /* test configuration */
490 /* Registers. Available to execution environments, which may modify the
491 * contents of the active registers, as defined by the current test group,
492 * but not the vector pointers themselves or inactive registers.
494 struct tvec_reg *in, *out; /* register vectors */
496 /* Test group state. Read-only for all callers. */
497 const struct tvec_test *test; /* current test */
499 /* Test scoreboard. Available to output formatters. */
500 unsigned curr[TVOUT_LIMIT], all[TVOUT_LIMIT], grps[TVOUT_LIMIT];
502 /* Output machinery. Read-only for environments. */
503 struct tvec_output *output; /* output formatter */
505 /* Input machinery. Available to type parsers. */
506 const char *infile; unsigned lno, test_lno; /* input file name, line */
507 FILE *fp; /* input file stream */
509 /* Adhoc testing state. Private. */
510 struct tvec_test adhoc_test;
511 const struct tvec_test *adhoc_tests[];
514 /* @TVEC_REG(tv, vec, i)@
516 * If @tv@ is a pointer to a @struct tvec_state@, @vec@ is either @in@ or
517 * @out@, and @i@ is an integer, then this evaluates to the address of the
518 * @i@th register in the selected vector.
520 #define TVEC_REG(tv, vec, i) TVEC_GREG((tv)->vec, (i), (tv)->cfg.regsz)
522 /*----- Session lifecycle -------------------------------------------------*/
524 /* --- @tvec_begin@ --- *
526 * Arguments: @struct tvec_state *tv_out@ = state structure to fill in
527 * @const struct tvec_config *config@ = test configuration
528 * @struct tvec_output *o@ = output driver
532 * Use: Initialize a state structure ready to do some testing. The
533 * test state takes ownership of the output driver: @tvec_end@
537 extern void tvec_begin(struct tvec_state */*tv_out*/,
538 const struct tvec_config */*config*/,
539 struct tvec_output */*o*/);
541 /* --- @tvec_end@ --- *
543 * Arguments: @struct tvec_state *tv@ = test-vector state
545 * Returns: A proposed exit code.
547 * Use: Conclude testing and suggests an exit code to be returned to
548 * the calling program. (The exit code comes from the output
549 * driver's @esession@ method.) The output driver, originally
550 * passed to @tvec_begin@ is destroyed.
553 extern int tvec_end(struct tvec_state */*tv*/);
555 /* --- @tvec_read@ --- *
557 * Arguments: @struct tvec_state *tv@ = test-vector state
558 * @const char *infile@ = the name of the input file
559 * @FILE *fp@ = stream to read from
561 * Returns: Zero on success, %$-1$% on error.
563 * Use: Read test vector data from @fp@ and exercise test functions.
564 * THe return code doesn't indicate test failures: it's only
565 * concerned with whether there were problems with the input
566 * file or with actually running the tests.
569 extern int tvec_read(struct tvec_state */*tv*/,
570 const char */*infile*/, FILE */*fp*/);
572 /*----- Command-line interface --------------------------------------------*/
574 /* --- @tvec_parseargs@ --- *
576 * Arguments: @int argc@ = number of command-line arguments
577 * @char *argv[]@ = vector of argument strings
578 * @struct tvec_state *tv_out@ = test vector state to initialize
579 * @int *argpos_out@ = where to leave unread argument index
580 * @const struct tvec_config *config@ = test vector
585 * Use: Parse arguments and set up the test vector state @*tv_out@.
586 * If errors occur, print messages to standard error and exit
590 extern void tvec_parseargs(int /*argc*/, char */*argv*/[],
591 struct tvec_state */*tv_out*/,
593 const struct tvec_config */*config*/);
595 /* --- @tvec_readstdin@, @tvec_readfile@, @tvec_readarg@ --- *
597 * Arguments: @struct tvec_state *tv@ = test vector state
598 * @const char *file@ = pathname of file to read
599 * @const char *arg@ = argument to interpret
601 * Returns: Zero on success, %$-1$% on error.
603 * Use: Read test vector data from stdin or a named file. The
604 * @tvec_readarg@ function reads from stdin if @arg@ is `%|-|%',
605 * and from the named file otherwise.
608 extern int tvec_readstdin(struct tvec_state */*tv*/);
609 extern int tvec_readfile(struct tvec_state */*tv*/, const char */*file*/);
610 extern int tvec_readarg(struct tvec_state */*tv*/, const char */*arg*/);
612 /* --- @tvec_readdflt@ --- *
614 * Arguments: @struct tvec_state *tv@ = test vector state
615 * @const char *dflt@ = defsault filename or null
617 * Returns: Zero on success, %$-1$% on error.
619 * Use: Reads from the default test vector data. If @file@ is null,
620 * then read from standard input, unless that's a terminal; if
621 * @file@ is not null, then read the named file, looking in the
622 * directory named by the `%|srcdir|%' environment variable if
623 * that's set, or otherwise in the current directory.
626 extern int tvec_readdflt(struct tvec_state */*tv*/, const char */*file*/);
628 /* --- @tvec_readargs@ --- *
630 * Arguments: @int argc@ = number of command-line arguments
631 * @char *argv[]@ = vector of argument strings
632 * @struct tvec_state *tv@ = test vector state
633 * @int *argpos_inout@ = current argument position (updated)
634 * @const char *dflt@ = default filename or null
636 * Returns: Zero on success, %$-1$% on error.
638 * Use: Reads from the sources indicated by the command-line
639 * arguments, in order, interpreting each as for @tvec_readarg@;
640 * if no arguments are given then read from @dflt@ as for
644 extern int tvec_readargs(int /*argc*/, char */*argv*/[],
645 struct tvec_state */*tv*/,
646 int */*argpos_inout*/, const char */*dflt*/);
648 /* --- @tvec_main@ --- *
650 * Arguments: @int argc@ = number of command-line arguments
651 * @char *argv[]@ = vector of argument strings
652 * @const struct tvec_config *config@ = test vector
654 * @const char *dflt@ = default filename or null
656 * Returns: Exit code.
658 * Use: All-in-one test vector front-end. Parse options from the
659 * command-line as for @tvec_parseargs@, and then process the
660 * remaining positional arguments as for @tvec_readargs@. The
661 * function constructs and disposes of a test vector state.
664 extern int tvec_main(int /*argc*/, char */*argv*/[],
665 const struct tvec_config */*config*/,
666 const char */*dflt*/);
668 /*----- Test processing ---------------------------------------------------*/
670 /* --- @tvec_skipgroup@, @tvec_skipgroup_v@ --- *
672 * Arguments: @struct tvec_state *tv@ = test-vector state
673 * @const char *excuse@, @va_list *ap@ = reason why skipped
677 * Use: Skip the current group. This should only be called from a
678 * test environment @setup@ function; a similar effect occurs if
679 * the @setup@ function fails.
682 extern PRINTF_LIKE(2, 3)
683 void tvec_skipgroup(struct tvec_state */*tv*/,
684 const char */*excuse*/, ...);
685 extern void tvec_skipgroup_v(struct tvec_state */*tv*/,
686 const char */*excuse*/, va_list */*ap*/);
688 /* --- @tvec_skip@, @tvec_skip_v@ --- *
690 * Arguments: @struct tvec_state *tv@ = test-vector state
691 * @const char *excuse@, @va_list *ap@ = reason why test skipped
695 * Use: Skip the current test. This should only be called from a
696 * test environment @run@ function; a similar effect occurs if
697 * the @before@ function fails.
700 extern PRINTF_LIKE(2, 3)
701 void tvec_skip(struct tvec_state */*tv*/, const char */*excuse*/, ...);
702 extern void tvec_skip_v(struct tvec_state */*tv*/,
703 const char */*excuse*/, va_list */*ap*/);
705 /* --- @tvec_fail@, @tvec_fail_v@ --- *
707 * Arguments: @struct tvec_state *tv@ = test-vector state
708 * @const char *detail@, @va_list *ap@ = description of test
712 * Use: Report the current test as a failure. This function can be
713 * called multiple times for a single test, e.g., if the test
714 * environment's @run@ function invokes the test function
715 * repeatedly; but a single test that fails repeatedly still
716 * only counts as a single failure in the statistics. The
717 * @detail@ string and its format parameters can be used to
718 * distinguish which of several invocations failed; it can
719 * safely be left null if the test function is run only once.
722 extern PRINTF_LIKE(2, 3)
723 void tvec_fail(struct tvec_state */*tv*/, const char */*detail*/, ...);
724 extern void tvec_fail_v(struct tvec_state */*tv*/,
725 const char */*detail*/, va_list */*ap*/);
727 /* --- @tvec_dumpreg@ --- *
729 * Arguments: @struct tvec_state *tv@ = test-vector state
730 * @unsigned disp@ = the register disposition (@TVRD_...@)
731 * @const union tvec_regval *tv@ = register value, or null
732 * @const struct tvec_regdef *rd@ = register definition
736 * Use: Dump a register value to the output. This is the lowest-
737 * level function for dumping registers, and calls the output
738 * formatter directly.
740 * Usually @tvec_mismatch@ is much more convenient. Low-level
741 * access is required for reporting `virtual' registers
742 * corresponding to test environment settings.
745 extern void tvec_dumpreg(struct tvec_state */*tv*/,
746 unsigned /*disp*/, const union tvec_regval */*rv*/,
747 const struct tvec_regdef */*rd*/);
749 /* --- @tvec_initregs@, @tvec_releaseregs@ --- *
751 * Arguments: @struct tvec_state *tv@ = test-vector state
755 * Use: Initialize or release, respectively, the registers required
756 * by the current test. All of the registers, both input and
757 * output, are effected. Initialized registers are not marked
761 extern void tvec_initregs(struct tvec_state */*tv*/);
762 extern void tvec_releaseregs(struct tvec_state */*tv*/);
764 /* --- @tvec_resetoutputs@ --- *
766 * Arguments: @struct tvec_state *tv@ = test-vector state
770 * Use: Reset (releases and reinitializes) the output registers in
771 * the test state. This is mostly of use to test environment
772 * @run@ functions, between invocations of the test function.
773 * Output registers are marked live if and only if the
774 * corresponding input register is live.
777 extern void tvec_resetoutputs(struct tvec_state */*tv*/);
779 /* --- @tvec_checkregs@ --- *
781 * Arguments: @struct tvec_state *tv@ = test-vector state
783 * Returns: Zero on success, %$-1$% on mismatch.
785 * Use: Compare the active output registers (according to the current
786 * test group definition) with the corresponding input register
787 * values. A mismatch occurs if the two values differ
788 * (according to the register type's @eq@ method), or if the
789 * input is live but the output is dead.
791 * This function only checks for a mismatch and returns the
792 * result; it takes no other action. In particular, it doesn't
793 * report a failure, or dump register values.
796 extern int tvec_checkregs(struct tvec_state */*tv*/);
798 /* --- @tvec_mismatch@ --- *
800 * Arguments: @struct tvec_state *tv@ = test-vector state
801 * @unsigned f@ = flags (@TVMF_...@)
805 * Use: Dumps registers suitably to report a mismatch. The flag bits
806 * @TVMF_IN@ and @TVF_OUT@ select input-only and output
807 * registers. If both are reset then nothing happens.
808 * Suppressing the output registers may be useful, e.g., if the
809 * test function crashed rather than returning outputs.
814 extern void tvec_mismatch(struct tvec_state */*tv*/, unsigned /*f*/);
816 /* --- @tvec_check@, @tvec_check_v@ --- *
818 * Arguments: @struct tvec_state *tv@ = test-vector state
819 * @const char *detail@, @va_list *ap@ = description of test
823 * Use: Check the register values, reporting a failure and dumping
824 * the registers in the event of a mismatch. This just wraps up
825 * @tvec_checkregs@, @tvec_fail@ and @tvec_mismatch@ in the
829 extern PRINTF_LIKE(2, 3)
830 void tvec_check(struct tvec_state */*tv*/, const char */*detail*/, ...);
831 extern void tvec_check_v(struct tvec_state */*tv*/,
832 const char */*detail*/, va_list */*ap*/);
834 /*----- Output functions --------------------------------------------------*/
836 /* --- @tvec_strlevel@ --- *
838 * Arguments: @unsigned level@ = level code
840 * Returns: A human-readable description.
842 * Use: Converts a level code into something that you can print in a
846 extern const char *tvec_strlevel(unsigned /*level*/);
848 /* --- @tvec_report@, @tvec_report_v@ --- *
850 * Arguments: @struct tvec_state *tv@ = test-vector state
851 * @const char *msg@, @va_list *ap@ = error message
855 * Use: Report an message with a given severity. Messages with level
856 * @TVLEV_ERR@ or higher force a nonzero exit code.
859 #define TVEC_LEVELS(_) \
861 _(NOTE, "notice", 4) \
864 #define TVEC_DEFLEVEL(tag, name, val) TVLEV_##tag = val,
865 TVEC_LEVELS(TVEC_DEFLEVEL)
870 extern PRINTF_LIKE(3, 4)
871 void tvec_report(struct tvec_state */*tv*/, unsigned /*level*/,
872 const char */*msg*/, ...);
873 extern void tvec_report_v(struct tvec_state */*tv*/, unsigned /*level*/,
874 const char */*msg*/, va_list */*ap*/);
876 /* --- @tvec_error@, @tvec_notice@, @tvec_info@ --- *
878 * Arguments: @struct tvec_state *tv@ = test-vector state
879 * @const char *msg@, @va_list *ap@ = error message
881 * Returns: The @tvec_error@ function returns %$-1$% as a trivial
882 * convenience; @tvec_notice@ does not return a value.
884 * Use: Report a message. Errors are distinct from test
885 * failures, and indicate that a problem was encountered which
886 * compromised the activity of testing. Notices are important
887 * information which doesn't fit into any other obvious
888 * category. Information is anything else, and is a reasonable
889 * fallback for writing unstructured information in the absence
890 * of dedicated support in an output driver.
892 * These functions are simple convenience wrappers around
893 * @tvec_report@. Use @tvec_report_v@ directly if you have a
894 * captured @va_list@ of arguments to format.
897 extern PRINTF_LIKE(2, 3)
898 int tvec_error(struct tvec_state */*tv*/, const char */*msg*/, ...);
899 extern PRINTF_LIKE(2, 3)
900 void tvec_notice(struct tvec_state */*tv*/, const char */*msg*/, ...);
901 extern PRINTF_LIKE(2, 3)
902 void tvec_info(struct tvec_state */*tv*/, const char */*msg*/, ...);
904 /* --- @tvec_unkregerr@, @tvec_dupregerr@, @tvec_synthregerr@ --- *
906 * Arguments: @struct tvec_state *tv@ = test-vector state
907 * @const char *name@ = register or pseudoregister name
911 * Use: Reports an error about a misused register: @tvec_unkregerr@
912 * reports that the register is unknown, @tvec_dupregerr@ that
913 * it is already assigned, and @tvec_synthregerr@ that it is
917 extern int tvec_unkregerr(struct tvec_state */*tv*/, const char */*name*/);
918 extern int tvec_dupregerr(struct tvec_state */*tv*/, const char */*name*/);
919 extern int tvec_synthregerr(struct tvec_state */*tv*/, const char */*name*/);
921 /*----- Built-in output drivers -------------------------------------------*/
923 /* --- @tvec_humanoutput@ --- *
925 * Arguments: @FILE *fp@ = output file to write on
926 * @unsigned f, m@ = flags and mask
928 * Returns: An output formatter.
930 * Use: Return an output formatter which writes on @fp@ with the
931 * expectation that a human will interpret the output.
933 * The flags @f@ and mask @m@ operate together. Flag bits not
934 * covered by the mask must be left clear, i.e., @f&~m$ must be
935 * zero; the semantics are that a set mask bit indicates that
936 * the corresponding bit of @f@ should control the indicated
937 * behaviour; a clear mask bit indicates that a suitable default
938 * should be chosen based on environmental conditions.
940 * If @TVHF_TTY@ is set, then the output shows a `scoreboard'
941 * indicating the outcome of each test case attempted, providing
942 * a visual indication of progress. If @TVHF_COLOUR@ is set,
943 * then the output uses control codes for colour and other
944 * highlighting. It is unusual to set @TVHF_COLOUR@ without
945 * @TVHF_TTY@, this is permitted anyway.
947 * The environment variables %|TVEC_TTY|% and %|TVEC_COLOUR|%
948 * provide default values for these settings. If they are not
949 * set, then @TVHF_TTY@ is set if @fp@ refers to a terminal, and
950 * @TVHF_COLOUR@ is set if @TVHF_TTY@ is set and, additionally,
951 * the %|TERM|% environment variable is set to a value other
955 #define TVHF_TTY 1u /* output to terminal */
956 #define TVHF_COLOUR 2u /* output in colour */
957 extern struct tvec_output *tvec_humanoutput(FILE */*fp*/,
958 unsigned /*f*/, unsigned /*m*/);
960 /* --- @tvec_machineoutput@ --- *
962 * Arguments: @FILE *fp@ = output file to write on
964 * Returns: An output formatter.
966 * Use: Return an output formatter which writes on @fp@ in a
967 * moderately simple machine-readable format.
970 struct tvec_output *tvec_machineoutput(FILE *fp);
972 /* --- @tvec_tapoutput@ --- *
974 * Arguments: @FILE *fp@ = output file to write on
975 * @unsigned style@ = output style (@TVSF_...@)
977 * Returns: An output formatter.
979 * Use: Return an output formatter which writes on @fp@ in `TAP'
980 * (`Test Anything Protocol') format.
982 * TAP comes from the Perl community, but has spread rather
983 * further. This driver currently produces TAP version 14, but
984 * pretends to be version 13. The driver produces a TAP `test
985 * point' -- i.e., a result reported as `ok' or `not ok' -- for
986 * each input test group. Failure reports and register dumps
987 * are produced as diagnostic messages before the final group
988 * result. (TAP permits structuerd YAML data after the
989 * test-point result, which could be used to report details, but
990 * (a) postponing the details until after the report is
991 * inconvenient, and (b) there is no standardization for the
992 * YAML anyway, so in practice it's no more useful than the
993 * unstructured diagnostics.
996 extern struct tvec_output *tvec_tapoutput(FILE */*fp*/);
998 /* --- @tvec_dfltoutput@ --- *
1000 * Arguments: @FILE *fp@ = output file to write on
1002 * Returns: An output formatter.
1004 * Use: Selects and instantiates an output formatter suitable for
1005 * writing on @fp@. The policy is subject to change, but
1006 * currently the `human' output format is selected if @fp@ is
1007 * interactive (i.e., if @isatty(fileno(fp))@ is true), and
1008 * otherwise the `machine' format is used.
1011 extern struct tvec_output *tvec_dfltoutput(FILE */*fp*/);
1013 /* --- @tvec_amoutput@ --- *
1015 * Arguments: @const struct tvec_amargs *a@ = arguments from Automake
1016 * command-line protocol
1018 * Returns: An output formatter.
1020 * Use: Returns an output formatter which writes on standard output
1021 * in human format, pretending that the output is to a terminal
1022 * (in order to cope with %%\manpage{make}{1}%%'s output-
1023 * buffering behaviour, writes to the log file @a->log@ in
1024 * machine-readable format, and writes an Automake rST-format
1025 * test result file to @a->trs@. The `test name' is currently
1026 * ignored, because the framework has its own means of
1027 * determining test names.
1030 struct tvec_amargs {
1031 unsigned f; /* flags */
1032 #define TVAF_COLOUR 1u /* produce colour output */
1033 const char *name; /* test name */
1034 FILE *log; /* `log' output file */
1035 FILE *trs; /* `trs' summary file */
1038 extern struct tvec_output *tvec_amoutput(const struct tvec_amargs */*a*/);
1040 /*------ Serialization utilities ------------------------------------------*/
1042 /* Serialization format.
1044 * The `candidate register definitions' are those entries @r@ in the @regs@
1045 * vector whose index @r.i@ is strictly less than @nr@ and where
1046 * @r.f&mask == want@* . The `selected register definitions' are those
1047 * candidate register definitions @r@ for which the indicated register
1048 * @rv[r.i]@ has the @TVRF_LIVE@ flag set. The serialized output begins with
1049 * a header bitmap: if there are %$n$% candidate register definitions then
1050 * the header bitmap consists of %$\lceil n/8 \rceil$% bytes. Bits are
1051 * ordered starting from the least significant bit of the first byte, end
1052 * ending at the most significant bit of the final byte. The bit
1053 * corresponding to a candidate register definition is set if and only if
1054 * that register defintion is selected. The header bitmap is then followed
1055 * by the serializations of the selected registers -- i.e., for each selected
1056 * register definition @r@, the serialized value of register @rv[r.i]@ --
1057 * simply concatenated together, with no padding or alignment.
1060 /* --- @tvec_serialize@ --- *
1062 * Arguments: @const struct tvec_reg *rv@ = vector of registers
1063 * @buf *b@ = buffer to write on
1064 * @const struct tvec_regdef *regs@ = vector of register
1065 * descriptions, terminated by an entry with a null
1067 * @unsigned mask, want@ = flag-based selection
1068 * @unsigned nr@ = number of entries in the @rv@ vector
1069 * @size_t regsz@ = true size of each element of @rv@
1071 * Returns: Zero on success, %$-1$% on failure.
1073 * Use: Serialize a collection of register values.
1075 * The serialized output is written to the buffer @b@. Failure
1076 * can be caused by running out of buffer space, or a failing
1080 extern int tvec_serialize(const struct tvec_reg */*rv*/, buf */*b*/,
1081 const struct tvec_regdef */*regs*/,
1082 unsigned /*mask*/, unsigned /*want*/,
1083 unsigned /*nr*/, size_t /*regsz*/);
1085 /* --- @tvec_deserialize@ --- *
1087 * Arguments: @struct tvec_reg *rv@ = vector of registers
1088 * @buf *b@ = buffer to write on
1089 * @const struct tvec_regdef *regs@ = vector of register
1090 * descriptions, terminated by an entry with a null
1092 * @unsigned mask, want@ = flag-based selection
1093 * @unsigned nr@ = number of entries in the @rv@ vector
1094 * @size_t regsz@ = true size of each element of @rv@
1096 * Returns: Zero on success, %$-1$% on failure.
1098 * Use: Deserialize a collection of register values.
1100 * The size of the register vector @nr@ and the register
1101 * definitions @regs@ must match those used when producing the
1102 * serialization. For each serialized register value,
1103 * deserialize and store the value into the appropriate register
1104 * slot, and set the @TVRF_LIVE@ flag on the register. See
1105 * @tvec_serialize@ for a description of the format.
1107 * Failure results only from an input too small for the initial
1108 * bitmap or a failing register type handler.
1111 extern int tvec_deserialize(struct tvec_reg */*rv*/, buf */*b*/,
1112 const struct tvec_regdef */*regs*/,
1113 unsigned /*mask*/, unsigned /*want*/,
1114 unsigned /*nr*/, size_t /*regsz*/);
1116 /*----- Input utilities ---------------------------------------------------*/
1118 /* These are provided by the core for the benefit of type @parse@ methods,
1119 * and test-environment @set@ functions, which get to read from the test
1120 * input file. The latter are usually best implemented by calling on the
1123 * The two main rules are as follows.
1125 * * Leave the file position at the beginning of the line following
1126 * whatever it was that you read.
1128 * * When you read and consume a newline (which you do at least once, by
1129 * the previous rule), then increment @tv->lno@ to keep track of the
1130 * current line number.
1133 /* --- @tvec_syntax@, @tvec_syntax_v@ --- *
1135 * Arguments: @struct tvec_state *tv@ = test-vector state
1136 * @int ch@ = the character found (in @fgetc@ format)
1137 * @const char *expect@, @va_list *ap@ = what was expected
1141 * Use: Report a syntax error quoting @ch@ and @expect@.
1143 * If @ch@ is a newline, or if @TVSF_NEXT@ is set, then unread
1144 * it so that it can be read again (e.g., by @tvec_nexttoken@).
1145 * The intent here is that you can safely read a character,
1146 * inspect it, and then complain about it with @tvec_syntax@
1147 * without having to worry too much about backing up. The
1148 * flipside of this is that you %%\emph{must}%% read a
1149 * character, even if you don't have one ready, e,g, if you
1150 * called @tvec_nexttoken@ and it said there wasn't one
1154 extern PRINTF_LIKE(3, 4)
1155 int tvec_syntax(struct tvec_state */*tv*/, int /*ch*/,
1156 const char */*expect*/, ...);
1157 extern int tvec_syntax_v(struct tvec_state */*tv*/, int /*ch*/,
1158 const char */*expect*/, va_list */*ap*/);
1160 /* --- @tvec_skipspc@ --- *
1162 * Arguments: @struct tvec_state *tv@ = test-vector state
1166 * Use: Advance over any whitespace characters other than newlines.
1167 * This will stop at `;', end-of-file, or any other kind of
1168 * non-whitespace; and it won't consume a newline.
1171 extern void tvec_skipspc(struct tvec_state */*tv*/);
1173 /* --- @tvec_nexttoken@ --- *
1175 * Arguments: @struct tvec_state *tv@ = test-vector state
1177 * Returns: Zero if there is a next token which can be read; %$-1$% if no
1178 * token is available.
1180 * Use: Advance to the next whitespace-separated token, which may be
1183 * Tokens are separated by non-newline whitespace, comments, and
1184 * newlines followed by whitespace; a newline /not/ followed by
1185 * whitespace instead begins the next assignment, and two
1186 * newlines separated only by whitespace terminate the data for
1189 * If this function returns zero, then the next character in the
1190 * file begins a suitable token which can be read and processed.
1191 * If it returns %$-1$% then there is no such token, @TVSF_NEXT@
1192 * is set, and the file position is left correctly. The line
1193 * number count is updated appropriately.
1196 extern int tvec_nexttoken(struct tvec_state */*tv*/);
1198 /* --- @tvec_readword@, @tvec_readword_v@ --- *
1200 * Arguments: @struct tvec_state *tv@ = test-vector state
1201 * @dstr *d@ = string to append the word to
1202 * @const char **p_inout@ = pointer into string, updated
1203 * @const char *delims@ = additional delimiters to stop at
1204 * @const char *expect@, @va_list *ap@ = what was expected
1206 * Returns: Zero on success, %$-1$% on failure.
1208 * Use: A `word' consists of characters other than whitespace, null
1209 * characters, and other than those listed in @delims@;
1210 * furthermore, a word does not begin with a `;'. (If you want
1211 * reading to stop at comments not preceded by whitespace, then
1212 * include `;' in @delims@. This is a common behaviour.)
1214 * The function advances past whitespace and comments, as for
1215 * @tvec_nexttoken@. If there is no word beginning after the
1216 * current file position, but before the start of the next
1217 * non-continuation line, then return %$-1$%; furthermore, if
1218 * @expect@ is not null, then report an appropriate error via
1221 * Otherwise, the word is accumulated in @d@ and zero is
1222 * returned; if @d@ was not empty at the start of the call, the
1223 * newly read word is separated from the existing material by a
1224 * single space character. Since null bytes are never valid
1225 * word constituents, a null terminator is written to @d@, and
1226 * it is safe to treat the string in @d@ as being null-
1229 * If @p_inout@ is not null, then @*p_inout@ must be a pointer
1230 * into @d->buf@, which will be adjusted so that it will
1231 * continue to point at the same position even if the buffer is
1232 * reallocated. As a subtle tweak, if @*p_inout@ initially
1233 * points at the end of the buffer, then it will be adjusted to
1234 * point at the beginning of the next word, rather than at the
1235 * additional intervening space.
1238 extern PRINTF_LIKE(5, 6)
1239 int tvec_readword(struct tvec_state */*tv*/, dstr */*d*/,
1240 const char **/*p_inout*/, const char */*delims*/,
1241 const char */*expect*/, ...);
1242 extern int tvec_readword_v(struct tvec_state */*tv*/, dstr */*d*/,
1243 const char **/*p_inout*/, const char */*delims*/,
1244 const char */*expect*/, va_list */*ap*/);
1246 /*----- That's all, folks -------------------------------------------------*/