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