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
134 /*----- Miscellaneous values ----------------------------------------------*/
136 /* These are attached to structures which represent extension points, as a
137 * way to pass an opaque parameter to whatever things are hooked onto them.
140 #define TVEC_MISCSLOTS(_) \
141 _(PTR, const void *, p) /* arbitrary pointer */ \
142 _(INT, long, i) /* signed integer */ \
143 _(UINT, unsigned long, u) /* signed integer */ \
144 _(FLT, double, f) /* floating point */
147 #define TVEC_DEFSLOT(tag, ty, slot) ty slot;
148 TVEC_MISCSLOTS(TVEC_DEFSLOT)
152 #define TVEC_DEFCONST(tag, ty, slot) TVMISC_##tag,
153 TVEC_MISCSLOTS(TVEC_DEFCONST)
157 /*----- Register values ---------------------------------------------------*/
159 /* The framework doesn't have a preconceived idea about what's in a register
160 * value: it just allocates them and accesses them through the register type
161 * functions. It doesn't even have a baked-in idea of how big a register
162 * value is: instead, it gets that via the `regsz' slot in `struct
163 * tvec_testinfo'. So, as far as the framework is concerned, it's safe to
164 * add new slots to this union, even if they make the overall union larger.
165 * This can be done by defining the preprocessor macro `TVEC_REGSLOTS' to be
166 * a `union' fragment defining any additional union members.
168 * This creates a distinction between code which does and doesn't know the
169 * size of a register value. Code which does, which typically means the test
170 * functions, benchmarking setup and teardown functions, and tightly-bound
171 * runner functions, is free to index the register vectors directly. Code
172 * which doesn't, which means the framework core itself and output formatting
173 * machinery, must use the `TVEC_REG' macro (or its more general `TVEC_GREG'
174 * companion) for indexing register vectors. (In principle, register type
175 * handlers also fit into this category, but they have no business peering
176 * into register values other than the one's they're given.)
180 /* The actual register value. This is what the type handler sees.
181 * Additional members can be added by setting `TVEC_REGSLOTS' before
182 * including this file.
184 * A register value can be /initialized/, which simply means that its
185 * contents represent a valid value according to its type -- the register
186 * can be compared, dumped, serialized, parsed into, etc. You can't do
187 * anything safely to an uninitialized register value other than initialize
191 long i; /* signed integer */
192 unsigned long u; /* unsigned integer */
193 void *p; /* pointer */
194 double f; /* floating point */
195 struct { char *p; size_t sz; } text; /* text string */
196 struct { unsigned char *p; size_t sz; } bytes; /* binary string of bytes */
197 struct { /* buffer */
198 unsigned char *p; size_t sz; /* binary string */
199 size_t a, m; /* residue and modulus */
200 size_t off; /* offset into full buffer */
210 * Note that all of the registers listed as being used by a particular test
211 * group are initialized at all times[1] while that test group is being
212 * processed. (The other register slots don't even have types associated
213 * with them, so there's nothing useful we could do with them.)
215 * The `TVRF_LIVE' flag indicates that the register was assigned a value by
216 * the test vector file: it's the right thing to use to check whether an
217 * optional register is actually present. Even `dead' registers are still
218 * initialized, though.
220 * [1] This isn't quite true. Between individual tests, the registers are
221 * released and reinitialized in order to reset them to known values
222 * ready for the next test. But you won't see them at this point.
225 unsigned f; /* flags */
226 #define TVRF_SEEN 1u /* assignment seen in file */
227 #define TVRF_LIVE 2u /* used in current test */
228 union tvec_regval v; /* register value */
232 /* A register definition. Register definitions list the registers which
233 * are used by a particular test group (see `struct tvec_test' below).
235 * A vector of register definitions is terminated by a definition whose
236 * `name' slot is null.
239 const char *name; /* register name (for input files) */
240 const struct tvec_regty *ty; /* register type descriptor */
241 unsigned i; /* register index */
242 unsigned f; /* flags */
243 #define TVRF_UNSET 1u /* register may be marked unset */
244 #define TVRF_OPT 2u /* register need not be assigned */
245 #define TVRF_SYNTH 4u /* register must not be assigned */
246 #define TVRF_ID 8u /* part of test identity */
247 union tvec_misc arg; /* extra detail for the type */
249 #define TVEC_ENDREGS { 0, 0, 0, 0, { 0 } }
251 /* @TVEC_GREG(vec, i, regsz)@
253 * If @vec@ is a data pointer which happens to contain the address of a
254 * vector of @struct tvec_reg@ objects, @i@ is an integer, and @regsz@ is the
255 * size of a @struct tvec_reg@, then this evaluates to the address of the
256 * @i@th element of the vector.
258 * This is the general tool you need for accessing register vectors when you
259 * don't have absolute knowledge of the size of a @union tvec_regval@.
260 * Usually you want to access one of the register vectors in a @struct
261 * tvec_state@, and @TVEC_REG@ will be more convenient.
263 #define TVEC_GREG(vec, i, regsz) \
264 ((struct tvec_reg *)((unsigned char *)(vec) + (i)*(regsz)))
266 /*----- Register types ----------------------------------------------------*/
268 struct tvec_state; /* forward declaration */
271 /* A register type. */
273 void (*init)(union tvec_regval */*rv*/, const struct tvec_regdef */*rd*/);
274 /* Initialize the value in @*rv@. This will be called before any other
275 * function acting on the value, including @release@. Following @init@,
276 * the register value must be valid to use for all other type entry
280 void (*release)(union tvec_regval */*rv*/,
281 const struct tvec_regdef */*rd*/);
282 /* Release any resources associated with the value in @*rv@. The
283 * register value may be left in an invalid state.
286 int (*eq)(const union tvec_regval */*rv0*/,
287 const union tvec_regval */*rv1*/,
288 const struct tvec_regdef */*rd*/);
289 /* Return nonzero if @*rv0@ and @*rv1@ are equal values. Asymmetric
290 * criteria are permitted: @tvec_checkregs@ calls @eq@ with the input
291 * register as @rv0@ and the output as @rv1@.
294 void (*copy)(union tvec_regval */*rvd*/,
295 const union tvec_regval */*rvs*/,
296 const struct tvec_regdef */*rd*/);
297 /* Copy the value from @rvs@ to @rvd@. */
299 int (*tobuf)(buf */*b*/, const union tvec_regval */*rv*/,
300 const struct tvec_regdef */*rd*/);
301 /* Serialize the value @*rv@, writing the result to @b@. Return zero on
302 * success, or %$-1$% on error.
305 int (*frombuf)(buf */*b*/, union tvec_regval */*rv*/,
306 const struct tvec_regdef */*rd*/);
307 /* Deserialize a value from @b@, storing it in @*rv@. Return zero on
308 * success, or %$-1$% on error.
311 int (*parse)(union tvec_regval */*rv*/, const struct tvec_regdef */*rd*/,
312 struct tvec_state */*tv*/);
313 /* Parse a value from @tv->fp@, storing it in @*rv@. Return zero on
314 * success, or %$-1$% on error, having reported one or more errors via
315 * @tvec_error@ or @tvec_syntax@. If @TVSF_NEXT@ is not set on exit,
316 * then the caller will advance to the start of the next non-continuation
317 * line, reporting an error it any non-whitespace non-comment material
318 * found following a successful return.
321 void (*dump)(const union tvec_regval */*rv*/,
322 const struct tvec_regdef */*rd*/,
324 const struct gprintf_ops */*gops*/, void */*go*/);
325 #define TVSF_COMPACT 1u
327 /* Write a human-readable representation of the value @*rv@ using
328 * @gprintf@ on @gops@ and @go@. The @style@ is a collection of flags:
329 * if @TVSF_COMPACT@ is set, then output should be minimal, and must fit
330 * on a single line; otherwise, output may consist of multiple lines and
331 * may contain redundant information if that is likely to be useful to a
332 * human reader. If @TVSF_RAW@ is set, then output should prefer
333 * machine-readability over human-readability.
337 /*----- Test descriptions -------------------------------------------------*/
341 typedef void tvec_testfn(const struct tvec_reg */*in*/,
342 struct tvec_reg */*out*/,
344 /* A test function. It should read inputs from @in@ and write outputs to
345 * @out@. The @TVRF_LIVE@ is set on inputs which are actually present, and
346 * on outputs which are wanted to test. A test function can set additional
347 * `gratuitous outputs' by setting @TVRF_LIVE@ on them; clearing
348 * @TVRF_LIVE@ on a wanted output causes a mismatch.
350 * A test function may be called zero or more times by the environment. In
351 * particular, it may be called multiple times, though usually by prior
352 * arrangement with the environment.
354 * The @ctx@ is supplied by the environment's @run@ function (see below).
355 * The default environment calls the test function once, with a null
356 * @ctx@. There is no expectation that the environment's context has
357 * anything to do with the test function's context.
360 typedef int tvec_setvarfn(struct tvec_state */*tv*/, const char */*var*/,
361 const union tvec_regval */*rv*/, void */*ctx*/);
362 /* Called after a variable is read. Return zero on success or %$-1$% on
363 * error. This function is never called if the test group is skipped.
367 size_t regsz; /* (minimum) register size */
368 tvec_setvarfn *setvar; /* function to set variable */
369 struct tvec_regdef def; /* register definition */
372 typedef void tvec_envsetupfn(struct tvec_state */*tv*/,
373 const struct tvec_env */*env*/,
374 void */*pctx*/, void */*ctx*/);
375 /* Initialize the context; called at the start of a test group; @pctx@ is
376 * null for environments called by the core, but may be non-null for
377 * subordinate environments. If setup fails, the function should call
378 * @tvec_skipgroup@ with a suitable excuse. The @set@, @after@, and
379 * @teardown@ entry points will still be called, but @before@ and @run@
383 typedef const struct tvec_vardef *tvec_envfindvarfn
384 (struct tvec_state */*tv*/, const char */*name*/,
385 void **/*ctx_out*/, void */*ctx*/);
386 /* Called when the parser finds a %|@var|%' special variable. If a
387 * suitable variable was found, set @*ctx_out@ to a suitable context and
388 * return the variable definition; the context will be passed to the
389 * variable definition's @setvar@ function. If no suitable variable was
390 * found, then return null.
393 typedef void tvec_envbeforefn(struct tvec_state */*tv*/, void */*ctx*/);
394 /* Called prior to running a test. This is the right place to act on any
395 * `%|@var|%' settings. If preparation fails, the function should call
396 * @tvec_skip@ with a suitable excuse. This function is never called if
397 * the test group is skipped. It %%\emph{is}%% called if the test will be
398 * skipped due to erroneous test data. It should check the @TVSF_ACTIVE@
402 typedef void tvec_envrunfn(struct tvec_state */*tv*/,
403 tvec_testfn */*fn*/, void */*ctx*/);
404 /* Run the test. It should either call @tvec_skip@, or run @fn@ one or
405 * more times. In the latter case, it is responsible for checking the
406 * outputs, and calling @tvec_fail@ as necessary; @tvec_checkregs@ will
407 * check the register values against the supplied test vector, while
408 * @tvec_check@ does pretty much everything necessary. This function is
409 * never called if the test group is skipped.
412 typedef void tvec_envafterfn(struct tvec_state */*tv*/, void */*ctx*/);
413 /* Called after running or skipping a test. Typical actions involve
414 * resetting whatever things were established by @set@. This function
415 * %%\emph{is}%% called if the test group is skipped or the test data is
416 * erroneous, so that the test environment can reset variables set by the
417 * @set@ entry point. It should check the @TVSF_SKIP@ flag if necessary.
420 typedef void tvec_envteardownfn(struct tvec_state */*tv*/, void */*ctx*/);
421 /* Tear down the environment: called at the end of a test group. */
424 /* A test environment sets things up for and arranges to run the test.
426 * The caller is responsible for allocating storage for the environment's
427 * context, based on the @ctxsz@ slot, and freeing it later; this space is
428 * passed in as the @ctx@ parameter to the remaining functions; if @ctxsz@
429 * is zero then @ctx@ is null.
432 size_t ctxsz; /* environment context size */
434 tvec_envsetupfn *setup; /* setup for group */
435 tvec_envfindvarfn *findvar; /* find variable */
436 tvec_envbeforefn *before; /* prepare for test */
437 tvec_envrunfn *run; /* run test function */
438 tvec_envafterfn *after; /* clean up after test */
439 tvec_envteardownfn *teardown; /* tear down after group */
443 /* A test description. */
445 const char *name; /* name of the test */
446 const struct tvec_regdef *regs; /* descriptions of the registers */
447 const struct tvec_env *env; /* environment to run test in */
448 tvec_testfn *fn; /* test function */
452 /* An overall test configuration. */
454 const struct tvec_test *const *tests; /* the tests to be performed */
455 unsigned nrout, nreg; /* number of output/total regs */
456 size_t regsz; /* size of a register */
459 /*----- Test state --------------------------------------------------------*/
464 /* Possible test outcomes. */
466 TVOUT_LOSE, /* test failed */
467 TVOUT_SKIP, /* test skipped */
468 TVOUT_XFAIL, /* test passed, but shouldn't have */
469 TVOUT_WIN, /* test passed */
470 TVOUT_LIMIT /* (number of possible outcomes) */
474 /* The primary state structure for the test vector machinery. */
476 /* Flags. Read-only for all callers. */
477 unsigned f; /* flags */
478 #define TVSF_SKIP 0x0001u /* skip this test group */
479 #define TVSF_OPEN 0x0002u /* test is open */
480 #define TVSF_ACTIVE 0x0004u /* test is active */
481 #define TVSF_ERROR 0x0008u /* an error occurred */
482 #define TVSF_OUTMASK 0x00f0u /* test outcome (@TVOUT_...@) */
483 #define TVSF_OUTSHIFT 4 /* shift applied to outcome */
484 #define TVSF_XFAIL 0x0100u /* test expected to fail */
485 #define TVSF_MUFFLE 0x0200u /* muffle errors */
486 #define TVSF_NEXT 0x0400u /* input at next definition */
488 /* Memory allocation. Read-only for all callers. */
490 pool *p_session, *p_group, *p_test; /* allocation pools */
492 /* Test configuration. Read-only for all callers. */
493 struct tvec_config cfg; /* test configuration */
495 /* Registers. Available to execution environments, which may modify the
496 * contents of the active registers, as defined by the current test group,
497 * but not the vector pointers themselves or inactive registers.
499 struct tvec_reg *in, *out; /* register vectors */
501 /* Test group state. Read-only for all callers. */
502 const struct tvec_test *test; /* current test */
504 /* Test scoreboard. Available to output formatters. */
505 unsigned curr[TVOUT_LIMIT], all[TVOUT_LIMIT], grps[TVOUT_LIMIT];
507 /* Output machinery. Read-only for environments. */
508 struct tvec_output *output; /* output formatter */
510 /* Input machinery. Available to type parsers. */
511 const char *infile; unsigned lno, test_lno; /* input file name, line */
512 FILE *fp; /* input file stream */
514 /* Adhoc testing state. Private. */
515 struct tvec_test adhoc_test;
516 const struct tvec_test *adhoc_tests[2];
519 /* @TVEC_REG(tv, vec, i)@
521 * If @tv@ is a pointer to a @struct tvec_state@, @vec@ is either @in@ or
522 * @out@, and @i@ is an integer, then this evaluates to the address of the
523 * @i@th register in the selected vector.
525 #define TVEC_REG(tv, vec, i) TVEC_GREG((tv)->vec, (i), (tv)->cfg.regsz)
527 /*----- Session lifecycle -------------------------------------------------*/
529 /* --- @tvec_begin@ --- *
531 * Arguments: @struct tvec_state *tv_out@ = state structure to fill in
532 * @const struct tvec_config *config@ = test configuration
533 * @struct tvec_output *o@ = output driver
537 * Use: Initialize a state structure ready to do some testing. The
538 * test state takes ownership of the output driver: @tvec_end@
542 extern void tvec_begin(struct tvec_state */*tv_out*/,
543 const struct tvec_config */*config*/,
544 struct tvec_output */*o*/);
546 /* --- @tvec_end@ --- *
548 * Arguments: @struct tvec_state *tv@ = test-vector state
550 * Returns: A proposed exit code.
552 * Use: Conclude testing and suggests an exit code to be returned to
553 * the calling program. (The exit code comes from the output
554 * driver's @esession@ method.) The output driver, originally
555 * passed to @tvec_begin@ is destroyed.
558 extern int tvec_end(struct tvec_state */*tv*/);
560 /* --- @tvec_read@ --- *
562 * Arguments: @struct tvec_state *tv@ = test-vector state
563 * @const char *infile@ = the name of the input file
564 * @FILE *fp@ = stream to read from
566 * Returns: Zero on success, %$-1$% on error.
568 * Use: Read test vector data from @fp@ and exercise test functions.
569 * THe return code doesn't indicate test failures: it's only
570 * concerned with whether there were problems with the input
571 * file or with actually running the tests.
574 extern int tvec_read(struct tvec_state */*tv*/,
575 const char */*infile*/, FILE */*fp*/);
577 /*----- Command-line interface --------------------------------------------*/
579 /* --- @tvec_parseargs@ --- *
581 * Arguments: @int argc@ = number of command-line arguments
582 * @char *argv[]@ = vector of argument strings
583 * @struct tvec_state *tv_out@ = test vector state to initialize
584 * @int *argpos_out@ = where to leave unread argument index
585 * @const struct tvec_config *config@ = test vector
590 * Use: Parse arguments and set up the test vector state @*tv_out@.
591 * If errors occur, print messages to standard error and exit
595 extern void tvec_parseargs(int /*argc*/, char */*argv*/[],
596 struct tvec_state */*tv_out*/,
598 const struct tvec_config */*config*/);
600 /* --- @tvec_readstdin@, @tvec_readfile@, @tvec_readarg@ --- *
602 * Arguments: @struct tvec_state *tv@ = test vector state
603 * @const char *file@ = pathname of file to read
604 * @const char *arg@ = argument to interpret
606 * Returns: Zero on success, %$-1$% on error.
608 * Use: Read test vector data from stdin or a named file. The
609 * @tvec_readarg@ function reads from stdin if @arg@ is `%|-|%',
610 * and from the named file otherwise.
613 extern int tvec_readstdin(struct tvec_state */*tv*/);
614 extern int tvec_readfile(struct tvec_state */*tv*/, const char */*file*/);
615 extern int tvec_readarg(struct tvec_state */*tv*/, const char */*arg*/);
617 /* --- @tvec_readdflt@ --- *
619 * Arguments: @struct tvec_state *tv@ = test vector state
620 * @const char *dflt@ = defsault filename or null
622 * Returns: Zero on success, %$-1$% on error.
624 * Use: Reads from the default test vector data. If @file@ is null,
625 * then read from standard input, unless that's a terminal; if
626 * @file@ is not null, then read the named file, looking in the
627 * directory named by the `%|srcdir|%' environment variable if
628 * that's set, or otherwise in the current directory.
631 extern int tvec_readdflt(struct tvec_state */*tv*/, const char */*file*/);
633 /* --- @tvec_readargs@ --- *
635 * Arguments: @int argc@ = number of command-line arguments
636 * @char *argv[]@ = vector of argument strings
637 * @struct tvec_state *tv@ = test vector state
638 * @int *argpos_inout@ = current argument position (updated)
639 * @const char *dflt@ = default filename or null
641 * Returns: Zero on success, %$-1$% on error.
643 * Use: Reads from the sources indicated by the command-line
644 * arguments, in order, interpreting each as for @tvec_readarg@;
645 * if no arguments are given then read from @dflt@ as for
649 extern int tvec_readargs(int /*argc*/, char */*argv*/[],
650 struct tvec_state */*tv*/,
651 int */*argpos_inout*/, const char */*dflt*/);
653 /* --- @tvec_main@ --- *
655 * Arguments: @int argc@ = number of command-line arguments
656 * @char *argv[]@ = vector of argument strings
657 * @const struct tvec_config *config@ = test vector
659 * @const char *dflt@ = default filename or null
661 * Returns: Exit code.
663 * Use: All-in-one test vector front-end. Parse options from the
664 * command-line as for @tvec_parseargs@, and then process the
665 * remaining positional arguments as for @tvec_readargs@. The
666 * function constructs and disposes of a test vector state.
669 extern int tvec_main(int /*argc*/, char */*argv*/[],
670 const struct tvec_config */*config*/,
671 const char */*dflt*/);
673 /*----- Test processing ---------------------------------------------------*/
675 /* --- @tvec_skipgroup@, @tvec_skipgroup_v@ --- *
677 * Arguments: @struct tvec_state *tv@ = test-vector state
678 * @const char *excuse@, @va_list *ap@ = reason why skipped
682 * Use: Skip the current group. This should only be called from a
683 * test environment @setup@ function; a similar effect occurs if
684 * the @setup@ function fails.
687 extern PRINTF_LIKE(2, 3)
688 void tvec_skipgroup(struct tvec_state */*tv*/,
689 const char */*excuse*/, ...);
690 extern void tvec_skipgroup_v(struct tvec_state */*tv*/,
691 const char */*excuse*/, va_list */*ap*/);
693 /* --- @tvec_skip@, @tvec_skip_v@ --- *
695 * Arguments: @struct tvec_state *tv@ = test-vector state
696 * @const char *excuse@, @va_list *ap@ = reason why test skipped
700 * Use: Skip the current test. This should only be called from a
701 * test environment @run@ function; a similar effect occurs if
702 * the @before@ function fails.
705 extern PRINTF_LIKE(2, 3)
706 void tvec_skip(struct tvec_state */*tv*/, const char */*excuse*/, ...);
707 extern void tvec_skip_v(struct tvec_state */*tv*/,
708 const char */*excuse*/, va_list */*ap*/);
710 /* --- @tvec_fail@, @tvec_fail_v@ --- *
712 * Arguments: @struct tvec_state *tv@ = test-vector state
713 * @const char *detail@, @va_list *ap@ = description of test
717 * Use: Report the current test as a failure. This function can be
718 * called multiple times for a single test, e.g., if the test
719 * environment's @run@ function invokes the test function
720 * repeatedly; but a single test that fails repeatedly still
721 * only counts as a single failure in the statistics. The
722 * @detail@ string and its format parameters can be used to
723 * distinguish which of several invocations failed; it can
724 * safely be left null if the test function is run only once.
727 extern PRINTF_LIKE(2, 3)
728 void tvec_fail(struct tvec_state */*tv*/, const char */*detail*/, ...);
729 extern void tvec_fail_v(struct tvec_state */*tv*/,
730 const char */*detail*/, va_list */*ap*/);
732 /* --- @tvec_dumpreg@ --- *
734 * Arguments: @struct tvec_state *tv@ = test-vector state
735 * @unsigned disp@ = the register disposition (@TVRD_...@)
736 * @const union tvec_regval *tv@ = register value, or null
737 * @const struct tvec_regdef *rd@ = register definition
741 * Use: Dump a register value to the output. This is the lowest-
742 * level function for dumping registers, and calls the output
743 * formatter directly.
745 * Usually @tvec_mismatch@ is much more convenient. Low-level
746 * access is required for reporting `virtual' registers
747 * corresponding to test environment settings.
750 extern void tvec_dumpreg(struct tvec_state */*tv*/,
751 unsigned /*disp*/, const union tvec_regval */*rv*/,
752 const struct tvec_regdef */*rd*/);
754 /* --- @tvec_initregs@, @tvec_releaseregs@ --- *
756 * Arguments: @struct tvec_state *tv@ = test-vector state
760 * Use: Initialize or release, respectively, the registers required
761 * by the current test. All of the registers, both input and
762 * output, are effected. Initialized registers are not marked
766 extern void tvec_initregs(struct tvec_state */*tv*/);
767 extern void tvec_releaseregs(struct tvec_state */*tv*/);
769 /* --- @tvec_resetoutputs@ --- *
771 * Arguments: @struct tvec_state *tv@ = test-vector state
775 * Use: Reset (releases and reinitializes) the output registers in
776 * the test state. This is mostly of use to test environment
777 * @run@ functions, between invocations of the test function.
778 * Output registers are marked live if and only if the
779 * corresponding input register is live.
782 extern void tvec_resetoutputs(struct tvec_state */*tv*/);
784 /* --- @tvec_checkregs@ --- *
786 * Arguments: @struct tvec_state *tv@ = test-vector state
788 * Returns: Zero on success, %$-1$% on mismatch.
790 * Use: Compare the active output registers (according to the current
791 * test group definition) with the corresponding input register
792 * values. A mismatch occurs if the two values differ
793 * (according to the register type's @eq@ method), or if the
794 * input is live but the output is dead.
796 * This function only checks for a mismatch and returns the
797 * result; it takes no other action. In particular, it doesn't
798 * report a failure, or dump register values.
801 extern int tvec_checkregs(struct tvec_state */*tv*/);
803 /* --- @tvec_mismatch@ --- *
805 * Arguments: @struct tvec_state *tv@ = test-vector state
806 * @unsigned f@ = flags (@TVMF_...@)
810 * Use: Dumps registers suitably to report a mismatch. The flag bits
811 * @TVMF_IN@ and @TVF_OUT@ select input-only and output
812 * registers. If both are reset then nothing happens.
813 * Suppressing the output registers may be useful, e.g., if the
814 * test function crashed rather than returning outputs.
819 extern void tvec_mismatch(struct tvec_state */*tv*/, unsigned /*f*/);
821 /* --- @tvec_check@, @tvec_check_v@ --- *
823 * Arguments: @struct tvec_state *tv@ = test-vector state
824 * @const char *detail@, @va_list *ap@ = description of test
828 * Use: Check the register values, reporting a failure and dumping
829 * the registers in the event of a mismatch. This just wraps up
830 * @tvec_checkregs@, @tvec_fail@ and @tvec_mismatch@ in the
834 extern PRINTF_LIKE(2, 3)
835 void tvec_check(struct tvec_state */*tv*/, const char */*detail*/, ...);
836 extern void tvec_check_v(struct tvec_state */*tv*/,
837 const char */*detail*/, va_list */*ap*/);
839 /*----- Output functions --------------------------------------------------*/
841 /* --- @tvec_strlevel@ --- *
843 * Arguments: @unsigned level@ = level code
845 * Returns: A human-readable description.
847 * Use: Converts a level code into something that you can print in a
851 extern const char *tvec_strlevel(unsigned /*level*/);
853 /* --- @tvec_report@, @tvec_report_v@ --- *
855 * Arguments: @struct tvec_state *tv@ = test-vector state
856 * @const char *msg@, @va_list *ap@ = error message
860 * Use: Report an message with a given severity. Messages with level
861 * @TVLV_ERR@ or higher force a nonzero exit code.
864 #define TVEC_LEVELS(_) \
866 _(NOTE, "notice", 4) \
869 #define TVEC_DEFLEVEL(tag, name, val) TVLV_##tag = val,
870 TVEC_LEVELS(TVEC_DEFLEVEL)
875 extern PRINTF_LIKE(3, 4)
876 void tvec_report(struct tvec_state */*tv*/, unsigned /*level*/,
877 const char */*msg*/, ...);
878 extern void tvec_report_v(struct tvec_state */*tv*/, unsigned /*level*/,
879 const char */*msg*/, va_list */*ap*/);
881 /* --- @tvec_error@, @tvec_notice@, @tvec_info@ --- *
883 * Arguments: @struct tvec_state *tv@ = test-vector state
884 * @const char *msg@, @va_list *ap@ = error message
886 * Returns: The @tvec_error@ function returns %$-1$% as a trivial
887 * convenience; @tvec_notice@ does not return a value.
889 * Use: Report a message. Errors are distinct from test
890 * failures, and indicate that a problem was encountered which
891 * compromised the activity of testing. Notices are important
892 * information which doesn't fit into any other obvious
893 * category. Information is anything else, and is a reasonable
894 * fallback for writing unstructured information in the absence
895 * of dedicated support in an output driver.
897 * These functions are simple convenience wrappers around
898 * @tvec_report@. Use @tvec_report_v@ directly if you have a
899 * captured @va_list@ of arguments to format.
902 extern PRINTF_LIKE(2, 3)
903 int tvec_error(struct tvec_state */*tv*/, const char */*msg*/, ...);
904 extern PRINTF_LIKE(2, 3)
905 void tvec_notice(struct tvec_state */*tv*/, const char */*msg*/, ...);
906 extern PRINTF_LIKE(2, 3)
907 void tvec_info(struct tvec_state */*tv*/, const char */*msg*/, ...);
909 /* --- @tvec_unkregerr@, @tvec_dupregerr@, @tvec_synthregerr@ --- *
911 * Arguments: @struct tvec_state *tv@ = test-vector state
912 * @const char *name@ = register or pseudoregister name
916 * Use: Reports an error about a misused register: @tvec_unkregerr@
917 * reports that the register is unknown, @tvec_dupregerr@ that
918 * it is already assigned, and @tvec_synthregerr@ that it is
922 extern int tvec_unkregerr(struct tvec_state */*tv*/, const char */*name*/);
923 extern int tvec_dupregerr(struct tvec_state */*tv*/, const char */*name*/);
924 extern int tvec_synthregerr(struct tvec_state */*tv*/, const char */*name*/);
926 /*----- Built-in output drivers -------------------------------------------*/
928 /* --- @tvec_humanoutput@ --- *
930 * Arguments: @FILE *fp@ = output file to write on
931 * @unsigned f, m@ = flags and mask
933 * Returns: An output formatter.
935 * Use: Return an output formatter which writes on @fp@ with the
936 * expectation that a human will interpret the output.
938 * The flags @f@ and mask @m@ operate together. Flag bits not
939 * covered by the mask must be left clear, i.e., @f&~m$ must be
940 * zero; the semantics are that a set mask bit indicates that
941 * the corresponding bit of @f@ should control the indicated
942 * behaviour; a clear mask bit indicates that a suitable default
943 * should be chosen based on environmental conditions.
945 * If @TVHF_TTY@ is set, then the output shows a `scoreboard'
946 * indicating the outcome of each test case attempted, providing
947 * a visual indication of progress. If @TVHF_COLOUR@ is set,
948 * then the output uses control codes for colour and other
949 * highlighting. It is unusual to set @TVHF_COLOUR@ without
950 * @TVHF_TTY@, this is permitted anyway.
952 * The environment variables %|TVEC_TTY|% and %|TVEC_COLOUR|%
953 * provide default values for these settings. If they are not
954 * set, then @TVHF_TTY@ is set if @fp@ refers to a terminal, and
955 * @TVHF_COLOUR@ is set if @TVHF_TTY@ is set and, additionally,
956 * the %|TERM|% environment variable is set to a value other
960 #define TVHF_TTY 1u /* output to terminal */
961 #define TVHF_COLOUR 2u /* output in colour */
962 extern struct tvec_output *tvec_humanoutput(FILE */*fp*/,
963 unsigned /*f*/, unsigned /*m*/);
965 /* --- @tvec_machineoutput@ --- *
967 * Arguments: @FILE *fp@ = output file to write on
969 * Returns: An output formatter.
971 * Use: Return an output formatter which writes on @fp@ in a
972 * moderately simple machine-readable format.
975 struct tvec_output *tvec_machineoutput(FILE *fp);
977 /* --- @tvec_tapoutput@ --- *
979 * Arguments: @FILE *fp@ = output file to write on
980 * @unsigned style@ = output style (@TVSF_...@)
982 * Returns: An output formatter.
984 * Use: Return an output formatter which writes on @fp@ in `TAP'
985 * (`Test Anything Protocol') format.
987 * TAP comes from the Perl community, but has spread rather
988 * further. This driver currently produces TAP version 14, but
989 * pretends to be version 13. The driver produces a TAP `test
990 * point' -- i.e., a result reported as `ok' or `not ok' -- for
991 * each input test group. Failure reports and register dumps
992 * are produced as diagnostic messages before the final group
993 * result. (TAP permits structuerd YAML data after the
994 * test-point result, which could be used to report details, but
995 * (a) postponing the details until after the report is
996 * inconvenient, and (b) there is no standardization for the
997 * YAML anyway, so in practice it's no more useful than the
998 * unstructured diagnostics.
1001 extern struct tvec_output *tvec_tapoutput(FILE */*fp*/);
1003 /* --- @tvec_dfltoutput@ --- *
1005 * Arguments: @FILE *fp@ = output file to write on
1007 * Returns: An output formatter.
1009 * Use: Selects and instantiates an output formatter suitable for
1010 * writing on @fp@. The policy is subject to change, but
1011 * currently the `human' output format is selected if @fp@ is
1012 * interactive (i.e., if @isatty(fileno(fp))@ is true), and
1013 * otherwise the `machine' format is used.
1016 extern struct tvec_output *tvec_dfltoutput(FILE */*fp*/);
1018 /* --- @tvec_amoutput@ --- *
1020 * Arguments: @const struct tvec_amargs *a@ = arguments from Automake
1021 * command-line protocol
1023 * Returns: An output formatter.
1025 * Use: Returns an output formatter which writes on standard output
1026 * in human format, pretending that the output is to a terminal
1027 * (in order to cope with %%\manpage{make}{1}%%'s output-
1028 * buffering behaviour, writes to the log file @a->log@ in
1029 * machine-readable format, and writes an Automake rST-format
1030 * test result file to @a->trs@. The `test name' is currently
1031 * ignored, because the framework has its own means of
1032 * determining test names.
1035 struct tvec_amargs {
1036 unsigned f; /* flags */
1037 #define TVAF_COLOUR 1u /* produce colour output */
1038 const char *name; /* test name */
1039 FILE *log; /* `log' output file */
1040 FILE *trs; /* `trs' summary file */
1043 extern struct tvec_output *tvec_amoutput(const struct tvec_amargs */*a*/);
1045 /*------ Serialization utilities ------------------------------------------*/
1047 /* Serialization format.
1049 * The `candidate register definitions' are those entries @r@ in the @regs@
1050 * vector whose index @r.i@ is strictly less than @nr@ and where
1051 * @r.f&mask == want@* . The `selected register definitions' are those
1052 * candidate register definitions @r@ for which the indicated register
1053 * @rv[r.i]@ has the @TVRF_LIVE@ flag set. The serialized output begins with
1054 * a header bitmap: if there are %$n$% candidate register definitions then
1055 * the header bitmap consists of %$\lceil n/8 \rceil$% bytes. Bits are
1056 * ordered starting from the least significant bit of the first byte, end
1057 * ending at the most significant bit of the final byte. The bit
1058 * corresponding to a candidate register definition is set if and only if
1059 * that register defintion is selected. The header bitmap is then followed
1060 * by the serializations of the selected registers -- i.e., for each selected
1061 * register definition @r@, the serialized value of register @rv[r.i]@ --
1062 * simply concatenated together, with no padding or alignment.
1065 /* --- @tvec_serialize@ --- *
1067 * Arguments: @const struct tvec_reg *rv@ = vector of registers
1068 * @buf *b@ = buffer to write on
1069 * @const struct tvec_regdef *regs@ = vector of register
1070 * descriptions, terminated by an entry with a null
1072 * @unsigned mask, want@ = flag-based selection
1073 * @unsigned nr@ = number of entries in the @rv@ vector
1074 * @size_t regsz@ = true size of each element of @rv@
1076 * Returns: Zero on success, %$-1$% on failure.
1078 * Use: Serialize a collection of register values.
1080 * The serialized output is written to the buffer @b@. Failure
1081 * can be caused by running out of buffer space, or a failing
1085 extern int tvec_serialize(const struct tvec_reg */*rv*/, buf */*b*/,
1086 const struct tvec_regdef */*regs*/,
1087 unsigned /*mask*/, unsigned /*want*/,
1088 unsigned /*nr*/, size_t /*regsz*/);
1090 /* --- @tvec_deserialize@ --- *
1092 * Arguments: @struct tvec_reg *rv@ = vector of registers
1093 * @buf *b@ = buffer to write on
1094 * @const struct tvec_regdef *regs@ = vector of register
1095 * descriptions, terminated by an entry with a null
1097 * @unsigned mask, want@ = flag-based selection
1098 * @unsigned nr@ = number of entries in the @rv@ vector
1099 * @size_t regsz@ = true size of each element of @rv@
1101 * Returns: Zero on success, %$-1$% on failure.
1103 * Use: Deserialize a collection of register values.
1105 * The size of the register vector @nr@ and the register
1106 * definitions @regs@ must match those used when producing the
1107 * serialization. For each serialized register value,
1108 * deserialize and store the value into the appropriate register
1109 * slot, and set the @TVRF_LIVE@ flag on the register. See
1110 * @tvec_serialize@ for a description of the format.
1112 * Failure results only from an input too small for the initial
1113 * bitmap or a failing register type handler.
1116 extern int tvec_deserialize(struct tvec_reg */*rv*/, buf */*b*/,
1117 const struct tvec_regdef */*regs*/,
1118 unsigned /*mask*/, unsigned /*want*/,
1119 unsigned /*nr*/, size_t /*regsz*/);
1121 /*----- Input utilities ---------------------------------------------------*/
1123 /* These are provided by the core for the benefit of type @parse@ methods,
1124 * and test-environment @set@ functions, which get to read from the test
1125 * input file. The latter are usually best implemented by calling on the
1128 * The two main rules are as follows.
1130 * * Leave the file position at the beginning of the line following
1131 * whatever it was that you read.
1133 * * When you read and consume a newline (which you do at least once, by
1134 * the previous rule), then increment @tv->lno@ to keep track of the
1135 * current line number.
1138 /* --- @tvec_syntax@, @tvec_syntax_v@ --- *
1140 * Arguments: @struct tvec_state *tv@ = test-vector state
1141 * @int ch@ = the character found (in @fgetc@ format)
1142 * @const char *expect@, @va_list *ap@ = what was expected
1146 * Use: Report a syntax error quoting @ch@ and @expect@.
1148 * If @ch@ is a newline, or if @TVSF_NEXT@ is set, then unread
1149 * it so that it can be read again (e.g., by @tvec_nexttoken@).
1150 * The intent here is that you can safely read a character,
1151 * inspect it, and then complain about it with @tvec_syntax@
1152 * without having to worry too much about backing up. The
1153 * flipside of this is that you %%\emph{must}%% read a
1154 * character, even if you don't have one ready, e,g, if you
1155 * called @tvec_nexttoken@ and it said there wasn't one
1159 extern PRINTF_LIKE(3, 4)
1160 int tvec_syntax(struct tvec_state */*tv*/, int /*ch*/,
1161 const char */*expect*/, ...);
1162 extern int tvec_syntax_v(struct tvec_state */*tv*/, int /*ch*/,
1163 const char */*expect*/, va_list */*ap*/);
1165 /* --- @tvec_skipspc@ --- *
1167 * Arguments: @struct tvec_state *tv@ = test-vector state
1171 * Use: Advance over any whitespace characters other than newlines.
1172 * This will stop at `;', end-of-file, or any other kind of
1173 * non-whitespace; and it won't consume a newline.
1176 extern void tvec_skipspc(struct tvec_state */*tv*/);
1178 /* --- @tvec_nexttoken@ --- *
1180 * Arguments: @struct tvec_state *tv@ = test-vector state
1182 * Returns: Zero if there is a next token which can be read; %$-1$% if no
1183 * token is available.
1185 * Use: Advance to the next whitespace-separated token, which may be
1188 * Tokens are separated by non-newline whitespace, comments, and
1189 * newlines followed by whitespace; a newline /not/ followed by
1190 * whitespace instead begins the next assignment, and two
1191 * newlines separated only by whitespace terminate the data for
1194 * If this function returns zero, then the next character in the
1195 * file begins a suitable token which can be read and processed.
1196 * If it returns %$-1$% then there is no such token, @TVSF_NEXT@
1197 * is set, and the file position is left correctly. The line
1198 * number count is updated appropriately.
1201 extern int tvec_nexttoken(struct tvec_state */*tv*/);
1203 /* --- @tvec_readword@, @tvec_readword_v@ --- *
1205 * Arguments: @struct tvec_state *tv@ = test-vector state
1206 * @dstr *d@ = string to append the word to
1207 * @const char **p_inout@ = pointer into string, updated
1208 * @const char *delims@ = additional delimiters to stop at
1209 * @const char *expect@, @va_list *ap@ = what was expected
1211 * Returns: Zero on success, %$-1$% on failure.
1213 * Use: A `word' consists of characters other than whitespace, null
1214 * characters, and other than those listed in @delims@;
1215 * furthermore, a word does not begin with a `;'. (If you want
1216 * reading to stop at comments not preceded by whitespace, then
1217 * include `;' in @delims@. This is a common behaviour.)
1219 * The function advances past whitespace and comments, as for
1220 * @tvec_nexttoken@. If there is no word beginning after the
1221 * current file position, but before the start of the next
1222 * non-continuation line, then return %$-1$%; furthermore, if
1223 * @expect@ is not null, then report an appropriate error via
1226 * Otherwise, the word is accumulated in @d@ and zero is
1227 * returned; if @d@ was not empty at the start of the call, the
1228 * newly read word is separated from the existing material by a
1229 * single space character. Since null bytes are never valid
1230 * word constituents, a null terminator is written to @d@, and
1231 * it is safe to treat the string in @d@ as being null-
1234 * If @p_inout@ is not null, then @*p_inout@ must be a pointer
1235 * into @d->buf@, which will be adjusted so that it will
1236 * continue to point at the same position even if the buffer is
1237 * reallocated. As a subtle tweak, if @*p_inout@ initially
1238 * points at the end of the buffer, then it will be adjusted to
1239 * point at the beginning of the next word, rather than at the
1240 * additional intervening space.
1243 extern PRINTF_LIKE(5, 6)
1244 int tvec_readword(struct tvec_state */*tv*/, dstr */*d*/,
1245 const char **/*p_inout*/, const char */*delims*/,
1246 const char */*expect*/, ...);
1247 extern int tvec_readword_v(struct tvec_state */*tv*/, dstr */*d*/,
1248 const char **/*p_inout*/, const char */*delims*/,
1249 const char */*expect*/, va_list */*ap*/);
1251 /*----- That's all, folks -------------------------------------------------*/