03c3ba462c3786f1926a3f0f0fe4ab13dee605ca
[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 /*----- Header files ------------------------------------------------------*/
36
37 #include <stdarg.h>
38 #include <stddef.h>
39 #include <stdio.h>
40 #include <string.h>
41
42 #ifndef MLIB_BUF_H
43 # include "buf.h"
44 #endif
45
46 #ifndef MLIB_CONTROL_H
47 # include "control.h"
48 #endif
49
50 #ifndef MLIB_BUF_H
51 # include "dstr.h"
52 #endif
53
54 #ifndef MLIB_GPRINTF_H
55 # include "gprintf.h"
56 #endif
57
58 #ifndef MLIB_MACROS_H
59 # include "macros.h"
60 #endif
61
62 /*----- Miscellaneous values ----------------------------------------------*/
63
64 /* These are attached to structures which represent extension points, as a
65 * way to pass an opaque parameter to whatever things are hooked onto them.
66 */
67
68 #define TVEC_MISCSLOTS(_) \
69 _(PTR, const void *, p) /* arbitrary pointer */ \
70 _(INT, long, i) /* signed integer */ \
71 _(UINT, unsigned long, u) /* signed integer */ \
72 _(FLT, double, f) /* floating point */
73
74 union tvec_misc {
75 #define TVEC_DEFSLOT(tag, ty, slot) ty slot;
76 TVEC_MISCSLOTS(TVEC_DEFSLOT)
77 #undef TVEC_DEFSLOT
78 };
79 enum {
80 #define TVEC_DEFCONST(tag, ty, slot) TVMISC_##tag,
81 TVEC_MISCSLOTS(TVEC_DEFCONST)
82 TVMISC_LIMIT
83 };
84
85 /*----- Register values ---------------------------------------------------*/
86
87 /* The framework doesn't have a preconceived idea about what's in a register
88 * value: it just allocates them and accesses them through the register type
89 * functions. It doesn't even have a baked-in idea of how big a register
90 * value is: instead, it gets that via the `regsz' slot in `struct
91 * tvec_testinfo'. So, as far as the framework is concerned, it's safe to
92 * add new slots to this union, even if they make the overall union larger.
93 * This can be done by defining the preprocessor macro `TVEC_REGSLOTS' to be
94 * a `union' fragment defining any additional union members.
95 *
96 * This creates a distinction between code which does and doesn't know the
97 * size of a register value. Code which does, which typically means the test
98 * functions, benchmarking setup and teardown functions, and tightly-bound
99 * runner functions, is free to index the register vectors directly. Code
100 * which doesn't, which means the framework core itself and output formatting
101 * machinery, must use the `TVEC_REG' macro (or its more general `TVEC_GREG'
102 * companion) for indexing register vectors. (In principle, register type
103 * handlers also fit into this category, but they have no business peering
104 * into register values other than the one's they're given.)
105 */
106
107 union tvec_regval {
108 /* The actual register value. This is what the type handler sees.
109 * Additional members can be added by setting `TVEC_REGSLOTS' before
110 * including this file.
111 *
112 * A register value can be /initialized/, which simply means that its
113 * contents represent a valid value according to its type -- the
114 * register can be compared, dumped, serialized, parsed into, etc.
115 * You can't do anything safely to an uninitialized register value
116 * other than initialize it.
117 */
118
119 long i; /* signed integer */
120 unsigned long u; /* unsigned integer */
121 void *p; /* pointer */
122 double f; /* floating point */
123 struct { unsigned char *p; size_t sz; } bytes; /* binary string of bytes */
124 struct { char *p; size_t sz; } str; /* text string */
125 #ifdef TVEC_REGSLOTS
126 TVEC_REGSLOTS
127 #endif
128 };
129
130 struct tvec_reg {
131 /* A register.
132 *
133 * Note that all of the registers listed as being used by a
134 * particular test group are initialized at all times[1] while that
135 * test group is being processed. (The other register slots don't
136 * even have types associated with them, so there's nothing useful we
137 * could do with them.)
138 *
139 * The `TVRF_LIVE' flag indicates that the register was assigned a
140 * value by the test vector file: it's the right thing to use to
141 * check whether an optional register is actually present. Even
142 * `dead' registers are still initialized, though.
143 *
144 * [1] This isn't quite true. Between individual tests, the
145 * registers are released and reinitialized in order to reset
146 * them to known values ready for the next test. But you won't
147 * see them at this point.
148 */
149
150 unsigned f; /* flags */
151 #define TVRF_LIVE 1u /* used in current test */
152 union tvec_regval v; /* register value */
153 };
154
155 struct tvec_regdef {
156 /* A register definition. Register definitions list the registers
157 * which are used by a particular test group (see `struct tvec_test'
158 * below).
159 *
160 * A vector of register definitions is terminated by a definition
161 * whose `name' slot is null.
162 */
163
164 const char *name; /* register name (for input files) */
165 unsigned i; /* register index */
166 const struct tvec_regty *ty; /* register type descriptor */
167 unsigned f; /* flags */
168 #define TVRF_OPT 1u /* optional register */
169 #define TVRF_ID 2u /* part of test identity */
170 union tvec_misc arg; /* extra detail for the type */
171 };
172
173 /* @TVEC_GREG(vec, i, regsz)@
174 *
175 * If @vec@ is a data pointer which happens to contain the address of a
176 * vector of @struct tvec_reg@ objects, @i@ is an integer, and @regsz@ is the
177 * size of a @struct tvec_reg@, then this evaluates to the address of the
178 * @i@th element of the vector.
179 *
180 * This is the general tool you need for accessing register vectors when you
181 * don't have absolute knowledge of the size of a @union tvec_regval@.
182 * Usually you want to access one of the register vectors in a @struct
183 * tvec_state@, and @TVEC_REG@ will be more convenient.
184 */
185 #define TVEC_GREG(vec, i, regsz) \
186 ((struct tvec_reg *)((unsigned char *)(vec) + (i)*(regsz)))
187
188 /*------ Serialization utilities ------------------------------------------*/
189
190 /* --- @tvec_serialize@ --- *
191 *
192 * Arguments: @const struct tvec_reg *rv@ = vector of registers
193 * @buf *b@ = buffer to write on
194 * @const struct tvec_regdef *regs@ = vector of register
195 * descriptions, terminated by an entry with a null
196 * @name@ slot
197 * @unsigned nr@ = number of entries in the @rv@ vector
198 * @size_t regsz@ = true size of each element of @rv@
199 *
200 * Returns: Zero on success, @-1@ on failure.
201 *
202 * Use: Serialize a collection of register values.
203 *
204 * The `candidate register definitions' are those entries @r@ in
205 * the @regs@ vector whose index @r.i@ is strictly less than
206 * @nr@. The `selected register definitions' are those
207 * candidate register definitions @r@ for which the indicated
208 * register @rv[r.i]@ has the @TVRF_LIVE@ flag set. The
209 * serialized output begins with a header bitmap: if there are
210 * %$n$% candidate register definitions then the header bitmap
211 * consists of %$\lceil n/8 \rceil$% bytes. Bits are ordered
212 * starting from the least significant bit of the first byte,
213 * end ending at the most significant bit of the final byte.
214 * The bit corresponding to a candidate register definition is
215 * set if and only if that register defintion is selected. The
216 * header bitmap is then followed by the serializations of the
217 * selected registers -- i.e., for each selected register
218 * definition @r@, the serialized value of register @rv[r.i]@ --
219 * simply concatenated together, with no padding or alignment.
220 *
221 * The serialized output is written to the buffer @b@. Failure
222 * can be caused by running out of buffer space, or a failing
223 * type handler.
224 */
225
226 extern int tvec_serialize(const struct tvec_reg */*rv*/, buf */*b*/,
227 const struct tvec_regdef */*regs*/,
228 unsigned /*nr*/, size_t /*regsz*/);
229
230 /* --- @tvec_deserialize@ --- *
231 *
232 * Arguments: @struct tvec_reg *rv@ = vector of registers
233 * @buf *b@ = buffer to write on
234 * @const struct tvec_regdef *regs@ = vector of register
235 * descriptions, terminated by an entry with a null
236 * @name@ slot
237 * @unsigned nr@ = number of entries in the @rv@ vector
238 * @size_t regsz@ = true size of each element of @rv@
239 *
240 * Returns: Zero on success, @-1@ on failure.
241 *
242 * Use: Deserialize a collection of register values.
243 *
244 * The size of the register vector @nr@ and the register
245 * definitions @regs@ must match those used when producing the
246 * serialization. For each serialized register value,
247 * deserialize and store the value into the appropriate register
248 * slot, and set the @TVRF_LIVE@ flag on the register. See
249 * @tvec_serialize@ for a description of the format.
250 *
251 * On successful completion, store the address of the first byte
252 * after the serialized data in @*end_out@ if @end_out@ is not
253 * null. Failure results only from a failing register type
254 * handler.
255 */
256
257 extern int tvec_deserialize(struct tvec_reg */*rv*/, buf */*b*/,
258 const struct tvec_regdef */*regs*/,
259 unsigned /*nr*/, size_t /*regsz*/);
260
261 /*----- Test state --------------------------------------------------------*/
262
263 enum {
264 /* Possible test outcomes. */
265
266 TVOUT_LOSE, /* test failed */
267 TVOUT_SKIP, /* test skipped */
268 TVOUT_WIN, /* test passed */
269 TVOUT_LIMIT /* (number of possible outcomes) */
270 };
271
272 struct tvec_state {
273 /* The primary state structure for the test vector machinery. */
274
275 unsigned f; /* flags */
276 #define TVSF_SKIP 1u /* skip this test group */
277 #define TVSF_OPEN 2u /* test is open */
278 #define TVSF_ACTIVE 4u /* test is active */
279 #define TVSF_ERROR 8u /* an error occurred */
280 #define TVSF_OUTMASK 0xf0 /* test outcome (@TVOUT_...@) */
281 #define TVSF_OUTSHIFT 4 /* shift applied to outcome */
282
283 /* Registers. Available to execution environments. */
284 unsigned nrout, nreg; /* number of output/total registers */
285 size_t regsz; /* size of register entry */
286 struct tvec_reg *in, *out; /* register vectors */
287
288 /* Test groups state. Available to output formatters. */
289 const struct tvec_test *tests, *test; /* all tests and current test */
290
291 /* Test scoreboard. Available to output formatters. */
292 unsigned curr[TVOUT_LIMIT], all[TVOUT_LIMIT], grps[TVOUT_LIMIT];
293
294 /* Output machinery. */
295 struct tvec_output *output; /* output formatter */
296
297 /* Input machinery. Available to type parsers. */
298 const char *infile; unsigned lno, test_lno; /* input file name, line */
299 FILE *fp; /* input file stream */
300 };
301
302 /* @TVEC_REG(tv, vec, i)@
303 *
304 * If @tv@ is a pointer to a @struct tvec_state@, @vec@ is either @in@ or
305 * @out@, and @i@ is an integer, then this evaluates to the address of the
306 * @i@th register in the selected vector.
307 */
308 #define TVEC_REG(tv, vec, i) TVEC_GREG((tv)->vec, (i), (tv)->regsz)
309
310 /*----- Test descriptions -------------------------------------------------*/
311
312 typedef void tvec_testfn(const struct tvec_reg */*in*/,
313 struct tvec_reg */*out*/,
314 void */*ctx*/);
315 /* A test function. It should read inputs from @in@ and write outputs to
316 * @out@. The @TVRF_LIVE@ is set on inputs which are actually present, and
317 * on outputs which are wanted to test. A test function can set additional
318 * `gratuitous outputs' by setting @TVRF_LIVE@ on them; clearing
319 * @TVRF_LIVE@ on a wanted output causes a mismatch.
320 *
321 * A test function may be called zero or more times by the environment. In
322 * particular, it may be called multiple times, though usually by prior
323 * arrangement with the environment.
324 *
325 * The @ctx@ is supplied by the environment's @run@ function (see below).
326 * The default environment calls the test function once, with a null
327 * @ctx@. There is no expectation that the environment's context has
328 * anything to do with the test function's context.
329 */
330
331 struct tvec_env {
332 /* A test environment sets things up for and arranges to run the test.
333 *
334 * The caller is responsible for allocating storage for the environment's
335 * context, based on the @ctxsz@ slot, and freeing it later; this space is
336 * passed in as the @ctx@ parameter to the remaining functions; if @ctxsz@
337 * is zero then @ctx@ is null.
338 */
339
340 size_t ctxsz; /* environment context size */
341
342 int (*setup)(struct tvec_state */*tv*/, const struct tvec_env */*env*/,
343 void */*pctx*/, void */*ctx*/);
344 /* Initialize the context; called at the start of a test group. Return
345 * zero on success, or @-1@ on failure. If setup fails, the context is
346 * freed, and the test group is skipped.
347 */
348
349 int (*set)(struct tvec_state */*tv*/, const char */*var*/,
350 const struct tvec_env */*env*/, void */*ctx*/);
351 /* Called when the parser finds a %|@var|%' setting to parse and store
352 * the value. If @setup@ failed, this is still called (so as to skip the
353 * value), but @ctx@ is null.
354 */
355
356 int (*before)(struct tvec_state */*tv*/, void */*ctx*/);
357 /* Called prior to running a test. This is the right place to act on any
358 * `%|@var|%' settings. Return zero on success or @-1@ on failure (which
359 * causes the test to be skipped). This function is never called if the
360 * test group is skipped.
361 */
362
363 void (*run)(struct tvec_state */*tv*/, tvec_testfn */*fn*/, void */*ctx*/);
364 /* Run the test. It should either call @tvec_skip@, or run @fn@ one or
365 * more times. In the latter case, it is responsible for checking the
366 * outputs, and calling @tvec_fail@ as necessary; @tvec_checkregs@ will
367 * check the register values against the supplied test vector, while
368 * @tvec_check@ does pretty much everything necessary. This function is
369 * never called if the test group is skipped.
370 */
371
372 void (*after)(struct tvec_state */*tv*/, void */*ctx*/);
373 /* Called after running or skipping a test. Typical actions involve
374 * resetting whatever things were established by @set@. This function is
375 * never called if the test group is skipped.
376 */
377
378 void (*teardown)(struct tvec_state */*tv*/, void */*ctx*/);
379 /* Tear down the environment: called at the end of a test group. If the
380 * setup failed, then this function is still called, with a null @ctx@.
381 */
382 };
383
384 struct tvec_test {
385 /* A test description. */
386
387 const char *name; /* name of the test */
388 const struct tvec_regdef *regs; /* descriptions of the registers */
389 const struct tvec_env *env; /* environment to run test in */
390 tvec_testfn *fn; /* test function */
391 };
392
393
394 enum {
395 /* Register output dispositions. */
396
397 TVRD_INPUT, /* input-only register */
398 TVRD_OUTPUT, /* output-only (input is dead) */
399 TVRD_MATCH, /* matching (equal) registers */
400 TVRD_FOUND, /* mismatching output register */
401 TVRD_EXPECT /* mismatching input register */
402 };
403
404 /* --- @tvec_skipgroup@, @tvec_skipgroup_v@ --- *
405 *
406 * Arguments: @struct tvec_state *tv@ = test-vector state
407 * @const char *excuse@, @va_list *ap@ = reason why skipped
408 *
409 * Returns: ---
410 *
411 * Use: Skip the current group. This should only be called from a
412 * test environment @setup@ function; a similar effect occurs if
413 * the @setup@ function fails.
414 */
415
416 extern void PRINTF_LIKE(2, 3)
417 tvec_skipgroup(struct tvec_state */*tv*/, const char */*excuse*/, ...);
418 extern void tvec_skipgroup_v(struct tvec_state */*tv*/,
419 const char */*excuse*/, va_list */*ap*/);
420
421 /* --- @tvec_skip@, @tvec_skip_v@ --- *
422 *
423 * Arguments: @struct tvec_state *tv@ = test-vector state
424 * @const char *excuse@, @va_list *ap@ = reason why test skipped
425 *
426 * Returns: ---
427 *
428 * Use: Skip the current test. This should only be called from a
429 * test environment @run@ function; a similar effect occurs if
430 * the @before@ function fails.
431 */
432
433 extern void PRINTF_LIKE(2, 3)
434 tvec_skip(struct tvec_state */*tv*/, const char */*excuse*/, ...);
435 extern void tvec_skip_v(struct tvec_state */*tv*/,
436 const char */*excuse*/, va_list */*ap*/);
437
438 /* --- @tvec_resetoutputs@ --- *
439 *
440 * Arguments: @struct tvec_state *tv@ = test-vector state
441 *
442 * Returns: ---
443 *
444 * Use: Reset (releases and reinitializes) the output registers in
445 * the test state. This is mostly of use to test environment
446 * @run@ functions, between invocations of the test function.
447 */
448
449 extern void tvec_resetoutputs(struct tvec_state */*tv*/);
450
451 /* --- @tvec_checkregs@ --- *
452 *
453 * Arguments: @struct tvec_state *tv@ = test-vector state
454 *
455 * Returns: Zero on success, @-1@ on mismatch.
456 *
457 * Use: Compare the active output registers (according to the current
458 * test group definition) with the corresponding input register
459 * values. A mismatch occurs if the two values differ
460 * (according to the register type's @eq@ method), or if the
461 * input is live but the output is dead.
462 *
463 * This function only checks for a mismatch and returns the
464 * result; it takes no other action. In particular, it doesn't
465 * report a failure, or dump register values.
466 */
467
468 extern int tvec_checkregs(struct tvec_state */*tv*/);
469
470 /* --- @tvec_fail@, @tvec_fail_v@ --- *
471 *
472 * Arguments: @struct tvec_state *tv@ = test-vector state
473 * @const char *detail@, @va_list *ap@ = description of test
474 *
475 * Returns: ---
476 *
477 * Use: Report the current test as a failure. This function can be
478 * called multiple times for a single test, e.g., if the test
479 * environment's @run@ function invokes the test function
480 * repeatedly; but a single test that fails repeatedly still
481 * only counts as a single failure in the statistics. The
482 * @detail@ string and its format parameters can be used to
483 * distinguish which of several invocations failed; it can
484 * safely be left null if the test function is run only once.
485 */
486
487 extern void PRINTF_LIKE(2, 3)
488 tvec_fail(struct tvec_state */*tv*/, const char */*detail*/, ...);
489 extern void tvec_fail_v(struct tvec_state */*tv*/,
490 const char */*detail*/, va_list */*ap*/);
491
492 /* --- @tvec_dumpreg@ --- *
493 *
494 * Arguments: @struct tvec_state *tv@ = test-vector state
495 * @unsigned disp@ = the register disposition (@TVRD_...@)
496 * @const union tvec_regval *tv@ = register value
497 * @const struct tvec_regdef *rd@ = register definition
498 *
499 * Returns: ---
500 *
501 * Use: Dump a register value to the output. This is the lowest-
502 * level function for dumping registers, and calls the output
503 * formatter directly.
504 *
505 * Usually @tvec_mismatch@ is much more convenient. Low-level
506 * access is required for reporting `virtual' registers
507 * corresponding to test environment settings.
508 */
509
510 extern void tvec_dumpreg(struct tvec_state */*tv*/,
511 unsigned /*disp*/, const union tvec_regval */*rv*/,
512 const struct tvec_regdef */*rd*/);
513
514 /* --- @tvec_mismatch@ --- *
515 *
516 * Arguments: @struct tvec_state *tv@ = test-vector state
517 * @unsigned f@ = flags (@TVMF_...@)
518 *
519 * Returns: ---
520 *
521 * Use: Dumps registers suitably to report a mismatch. The flag bits
522 * @TVMF_IN@ and @TVF_OUT@ select input-only and output
523 * registers. If both are reset then nothing happens.
524 * Suppressing the output registers may be useful, e.g., if the
525 * test function crashed rather than returning outputs.
526 */
527
528 #define TVMF_IN 1u
529 #define TVMF_OUT 2u
530 extern void tvec_mismatch(struct tvec_state */*tv*/, unsigned /*f*/);
531
532 /* --- @tvec_check@, @tvec_check_v@ --- *
533 *
534 * Arguments: @struct tvec_state *tv@ = test-vector state
535 * @const char *detail@, @va_list *ap@ = description of test
536 *
537 * Returns: ---
538 *
539 * Use: Check the register values, reporting a failure and dumping
540 * the registers in the event of a mismatch. This just wraps up
541 * @tvec_checkregs@, @tvec_fail@ and @tvec_mismatch@ in the
542 * obvious way.
543 */
544
545 extern void PRINTF_LIKE(2, 3)
546 tvec_check(struct tvec_state */*tv*/, const char */*detail*/, ...);
547 extern void tvec_check_v(struct tvec_state */*tv*/,
548 const char */*detail*/, va_list */*ap*/);
549
550 /*----- Session lifecycle -------------------------------------------------*/
551
552 struct tvec_config {
553 /* An overall test configuration. */
554
555 const struct tvec_test *tests; /* the tests to be performed */
556 unsigned nrout, nreg; /* number of output/total regs */
557 size_t regsz; /* size of a register */
558 };
559
560 /* --- @tvec_begin@ --- *
561 *
562 * Arguments: @struct tvec_state *tv_out@ = state structure to fill in
563 * @const struct tvec_config *config@ = test configuration
564 * @struct tvec_output *o@ = output driver
565 *
566 * Returns: ---
567 *
568 * Use: Initialize a state structure ready to do some testing.
569 */
570
571 extern void tvec_begin(struct tvec_state */*tv_out*/,
572 const struct tvec_config */*config*/,
573 struct tvec_output */*o*/);
574
575 /* --- @tvec_end@ --- *
576 *
577 * Arguments: @struct tvec_state *tv@ = test-vector state
578 *
579 * Returns: A proposed exit code.
580 *
581 * Use: Conclude testing and suggests an exit code to be returned to
582 * the calling program. (The exit code comes from the output
583 * driver's @esession@ method.)
584 */
585
586 extern int tvec_end(struct tvec_state */*tv*/);
587
588 /* --- @tvec_read@ --- *
589 *
590 * Arguments: @struct tvec_state *tv@ = test-vector state
591 * @const char *infile@ = the name of the input file
592 * @FILE *fp@ = stream to read from
593 *
594 * Returns: Zero on success, @-1@ on error.
595 *
596 * Use: Read test vector data from @fp@ and exercise test functions.
597 * THe return code doesn't indicate test failures: it's only
598 * concerned with whether there were problems with the input
599 * file or with actually running the tests.
600 */
601
602 extern int tvec_read(struct tvec_state */*tv*/,
603 const char */*infile*/, FILE */*fp*/);
604
605 /*----- Input utilities ---------------------------------------------------*/
606
607 /* These are provided by the core for the benefit of type @parse@ methods,
608 * and test-environment @set@ functions, which get to read from the test
609 * input file. The latter are usually best implemented by calling on the
610 * former.
611 *
612 * The two main rules are as follows.
613 *
614 * * Leave the file position at the beginning of the line following
615 * whatever it was that you read.
616 *
617 * * When you read and consume a newline (which you do at least once, by
618 * the previous rule), then increment @tv->lno@ to keep track of the
619 * current line number.
620 */
621
622 /* --- @tvec_skipspc@ --- *
623 *
624 * Arguments: @struct tvec_state *tv@ = test-vector state
625 *
626 * Returns: ---
627 *
628 * Use: Advance over any whitespace characters other than newlines.
629 * This will stop at `;', end-of-file, or any other kind of
630 * non-whitespace; and it won't consume a newline.
631 */
632
633 extern void tvec_skipspc(struct tvec_state */*tv*/);
634
635 /* --- @tvec_syntax@, @tvec_syntax_v@ --- *
636 *
637 * Arguments: @struct tvec_state *tv@ = test-vector state
638 * @int ch@ = the character found (in @fgetc@ format)
639 * @const char *expect@, @va_list ap@ = what was expected
640 *
641 * Returns: @-1@
642 *
643 * Use: Report a syntax error quoting @ch@ and @expect@. If @ch@ is
644 * a newline, then back up so that it can be read again (e.g.,
645 * by @tvec_flushtoeol@ or @tvec_nexttoken@, which will also
646 * advance the line number).
647 */
648
649 extern int PRINTF_LIKE(3, 4)
650 tvec_syntax(struct tvec_state */*tv*/, int /*ch*/,
651 const char */*expect*/, ...);
652 extern int tvec_syntax_v(struct tvec_state */*tv*/, int /*ch*/,
653 const char */*expect*/, va_list */*ap*/);
654
655 /* --- @tvec_flushtoeol@ --- *
656 *
657 * Arguments: @struct tvec_state *tv@ = test-vector state
658 * @unsigned f@ = flags (@TVFF_...@)
659 *
660 * Returns: Zero on success, @-1@ on error.
661 *
662 * Use: Advance to the start of the next line, consuming the
663 * preceding newline.
664 *
665 * A syntax error is reported if no newline character is found,
666 * i.e., the file ends in mid-line. A syntax error is also
667 * reported if material other than whitespace or a comment is
668 * found before the end of the line end, and @TVFF_ALLOWANY@ is
669 * not set in @f@. The line number count is updated
670 * appropriately.
671 */
672
673 #define TVFF_ALLOWANY 1u
674 extern int tvec_flushtoeol(struct tvec_state */*tv*/, unsigned /*f*/);
675
676 /* --- @tvec_nexttoken@ --- *
677 *
678 * Arguments: @struct tvec_state *tv@ = test-vector state
679 *
680 * Returns: Zero if there is a next token which can be read; @-1@ if no
681 * token is available.
682 *
683 * Use: Advance to the next whitespace-separated token, which may be
684 * on the next line.
685 *
686 * Tokens are separated by non-newline whitespace, comments, and
687 * newlines followed by whitespace; a newline /not/ followed by
688 * whitespace instead begins the next assignment, and two
689 * newlines separated only by whitespace terminate the data for
690 * a test.
691 *
692 * If this function returns zero, then the next character in the
693 * file begins a suitable token which can be read and
694 * processed. If it returns @-1@ then there is no such token,
695 * and the file position is left correctly. The line number
696 * count is updated appropriately.
697 */
698
699 extern int tvec_nexttoken(struct tvec_state */*tv*/);
700
701 /* --- @tvec_readword@ --- *
702 *
703 * Arguments: @struct tvec_state *tv@ = test-vector state
704 * @dstr *d@ = string to append the word to
705 * @const char *delims@ = additional delimiters to stop at
706 * @const char *expect@, @va_list ap@ = what was expected
707 *
708 * Returns: Zero on success, @-1@ on failure.
709 *
710 * Use: A `word' consists of characters other than whitespace, null
711 * characters, and other than those listed in @delims@;
712 * furthermore, a word does not begin with a `;'. (If you want
713 * reading to stop at comments not preceded by whitespace, then
714 * include `;' in @delims@. This is a common behaviour.)
715 *
716 * If there is no word beginning at the current file position,
717 * then return @-1@; furthermore, if @expect@ is not null, then
718 * report an appropriate error via @tvec_syntax@.
719 *
720 * Otherwise, the word is accumulated in @d@ and zero is
721 * returned; if @d@ was not empty at the start of the call, the
722 * newly read word is separated from the existing material by a
723 * single space character. Since null bytes are never valid
724 * word constituents, a null terminator is written to @d@, and
725 * it is safe to treat the string in @d@ as being null-
726 * terminated.
727 */
728
729 extern int PRINTF_LIKE(4, 5)
730 tvec_readword(struct tvec_state */*tv*/, dstr */*d*/,
731 const char */*delims*/, const char */*expect*/, ...);
732 extern int tvec_readword_v(struct tvec_state */*tv*/, dstr */*d*/,
733 const char */*delims*/, const char */*expect*/,
734 va_list */*ap*/);
735
736 /*----- Ad-hoc testing ----------------------------------------------------*/
737
738 /* --- @tvec_adhoc@ --- *
739 *
740 * Arguments: @struct tvec_state *tv@ = test-vector state
741 * @struct tvec_test *t@ = space for a test definition
742 *
743 * Returns: ---
744 *
745 * Use: Begin ad-hoc testing, i.e., without reading a file of
746 * test-vector data.
747 *
748 * The structure at @t@ will be used to record information about
749 * the tests underway, which would normally come from a static
750 * test definition. The other functions in this section assume
751 * that @tvec_adhoc@ has been called.
752 */
753
754 extern void tvec_adhoc(struct tvec_state */*tv*/, struct tvec_test */*t*/);
755
756 /* --- @tvec_begingroup@, @TVEC_BEGINGROUP@ --- *
757 *
758 * Arguments: @struct tvec_state *tv@ = test-vector state
759 * @const char *name@ = name for this test group
760 * @const char *file@, @unsigned @lno@ = calling file and line
761 *
762 * Returns: ---
763 *
764 * Use: Begin an ad-hoc test group with the given name. The @file@
765 * and @lno@ can be anything, but it's usually best if they
766 * refer to the source code performing the test: the macro
767 * @TVEC_BEGINGROUP@ does this automatically.
768 */
769
770 extern void tvec_begingroup(struct tvec_state */*tv*/, const char */*name*/,
771 const char */*file*/, unsigned /*lno*/);
772 #define TVEC_BEGINGROUP(tv, name) \
773 do tvec_begingroup(tv, name, __FILE__, __LINE__); while (0)
774
775 /* --- @tvec_endgroup@ --- *
776 *
777 * Arguments: @struct tvec_state *tv@ = test-vector state
778 *
779 * Returns: ---
780 *
781 * Use: End an ad-hoc test group. The statistics are updated and the
782 * outcome is reported to the output formatter.
783 */
784
785 extern void tvec_endgroup(struct tvec_state */*tv*/);
786
787 /* --- @TVEC_TESTGROUP@, @TVEC_TESTGROUP_TAG@ --- *
788 *
789 * Arguments: @tag@ = label-disambiguation tag
790 * @const struct tvec_state *tv = test-vector state
791 * @const char *name@ = test-group name
792 *
793 * Returns: ---
794 *
795 * Use: Control-structure macro: @TVEC_TESTGROUP(tv, name) stmt@
796 * establishes a test group with the given @name@ (attributing
797 * it to the source file and lie number), executes @stmt@, and
798 * ends the test group. If @stmt@ invokes @break@ then the test
799 * group is skipped. @TVEC_TESTGROUP_TAG@ is the same, with an
800 * additional @tag@ argument for use in higher-level macros.
801 */
802
803 #define TVEC_TESTGROUP_TAG(tag, tv, name) \
804 MC_WRAP(tag##__around, \
805 { TVEC_BEGINGROUP(tv, name); }, \
806 { tvec_endgroup(tv); }, \
807 { if (!((tv)->f&TVSF_SKIP)) tvec_skipgroup(tv, 0); \
808 tvec_endgroup(tv); })
809 #define TVEC_TESTGROUP(tv, name) TVEC_TESTGROUP_TAG(grp, tv, name)
810
811 /* --- @tvec_begintest@, @TVEC_BEGINTEST@ --- *
812 *
813 * Arguments: @struct tvec_state *tv@ = test-vector state
814 * @const char *file@, @unsigned @lno@ = calling file and line
815 *
816 * Returns: ---
817 *
818 * Use: Begin an ad-hoc test case. The @file@ and @lno@ can be
819 * anything, but it's usually best if they refer to the source
820 * code performing the test: the macro @TVEC_BEGINGROUP@ does
821 * this automatically.
822 */
823
824 extern void tvec_begintest(struct tvec_state */*tv*/,
825 const char */*file*/, unsigned /*lno*/);
826 #define TVEC_BEGINTEST(tv) \
827 do tvec_begintest(tv, __FILE__, __LINE__); while (0)
828
829 /* --- *tvec_endtest@ --- *
830 *
831 * Arguments: @struct tvec_state *tv@ = test-vector state
832 *
833 * Returns: ---
834 *
835 * Use: End a ad-hoc test case, The statistics are updated and the
836 * outcome is reported to the output formatter.
837 */
838
839 extern void tvec_endtest(struct tvec_state */*tv*/);
840
841 /* --- @TVEC_TEST@, @TVEC_TEST_TAG@ --- *
842 *
843 * Arguments: @tag@ = label-disambiguation tag
844 * @struct tvec_test *t@ = space for a test definition
845 *
846 * Returns: ---
847 *
848 * Use: Control-structure macro: @TVEC_TEST(tv) stmt@ begins a test
849 * case, executes @stmt@, and ends the test case. If @stmt@
850 * invokes @break@ then the test case is skipped.
851 * @TVEC_TEST_TAG@ is the same, with an additional @tag@ argumet
852 * for use in higher-level macros.
853 */
854
855 #define TVEC_TEST_TAG(tag, tv) \
856 MC_WRAP(tag##__around, \
857 { TVEC_BEGINTEST(tv); }, \
858 { tvec_endtest(tv); }, \
859 { if ((tv)->f&TVSF_ACTIVE) tvec_skip((tv), 0); \
860 tvec_endtest(tv); })
861 #define TVEC_TEST(tv) TVEC_TEST_TAG(test, tv)
862
863 /* --- @tvec_claim@, @tvec_claim_v@, @TVEC_CLAIM@ --- *
864 *
865 * Arguments: @struct tvec_state *tv@ = test-vector state
866 * @int ok@ = a flag
867 * @const char *file@, @unsigned @lno@ = calling file and line
868 * @const char *msg@, @va_list *ap@ = message to report on
869 * failure
870 *
871 * Returns: The value @ok@.
872 *
873 * Use: Check that a claimed condition holds, as (part of) a test.
874 * If no test case is underway (i.e., if @TVSF_OPEN@ is reset in
875 * @tv->f@), then a new test case is begun and ended. The
876 * @file@ and @lno@ are passed to the output formatter to be
877 * reported in case of a failure. If @ok@ is nonzero, then
878 * nothing else happens; so, in particular, if @tvec_claim@
879 * established a new test case, then the test case succeeds. If
880 * @ok@ is zero, then a failure is reported, quoting @msg@.
881 *
882 * The @TVEC_CLAIM@ macro is similar, only it (a) identifies the
883 * file and line number of the call site automatically, and (b)
884 * implicitly quotes the source text of the @ok@ condition in
885 * the failure message.
886 */
887
888 extern int PRINTF_LIKE(5, 6)
889 tvec_claim(struct tvec_state */*tv*/, int /*ok*/,
890 const char */*file*/, unsigned /*lno*/,
891 const char */*msg*/, ...);
892 extern int tvec_claim_v(struct tvec_state */*tv*/, int /*ok*/,
893 const char */*file*/, unsigned /*lno*/,
894 const char */*msg*/, va_list */*ap*/);
895 #define TVEC_CLAIM(tv, cond) \
896 (tvec_claim(tv, !!(cond), __FILE__, __LINE__, "%s untrue", #cond))
897
898 /* --- @tvec_claimeq@ --- *
899 *
900 * Arguments: @struct tvec_state *tv@ = test-vector state
901 * @const struct tvec_regty *ty@ = register type
902 * @const union tvec_misc *arg@ = register type argument
903 * @const char *file@, @unsigned @lno@ = calling file and line
904 * @const char *expr@ = the expression to quote on failure
905 *
906 * Returns: Nonzero if the input and output values of register 0 are
907 * equal, zero if they differ.
908 *
909 * Use: Check that the input and output values of register 0 are
910 * equal (according to the register type @ty@). As for
911 * @tvec_claim@ above, a test case is automatically begun and
912 * ended if none is already underway. If the values are
913 * unequal, then @tvec_fail@ is called, quoting @expr@, and the
914 * mismatched values are dumped.
915 *
916 * This function is not expected to be called directly, but
917 * through type-specific wrapper functions or macros such as
918 * @TVEC_CLAIMEQ_INT@.
919 */
920
921 extern int tvec_claimeq(struct tvec_state */*tv*/,
922 const struct tvec_regty */*ty*/,
923 const union tvec_misc */*arg*/,
924 const char */*file*/, unsigned /*lno*/,
925 const char */*expr*/);
926
927 /*----- Output formatting -------------------------------------------------*/
928
929 struct tvec_output {
930 /* An output formatter. */
931 const struct tvec_outops *ops; /* pointer to operations */
932 };
933
934 /* Benchmarking details. */
935 enum {
936 TVBU_OP, /* counting operations of some kind */
937 TVBU_BYTE /* counting bytes (@RBUF >= 0@) */
938 };
939 struct bench_timing; /* forward declaration */
940
941 struct tvec_outops {
942 /* Output operations. */
943
944 void (*bsession)(struct tvec_output */*o*/, struct tvec_state */*tv*/);
945 /* Begin a test session. The output driver will probably want to
946 * save @tv@, because this isn't provided to any other methods.
947 */
948
949 int (*esession)(struct tvec_output */*o*/);
950 /* End a session, and return the suggested exit code. */
951
952 void (*bgroup)(struct tvec_output */*o*/);
953 /* Begin a test group. The test group description is @tv->test@. */
954
955 void (*skipgroup)(struct tvec_output */*o*/,
956 const char */*excuse*/, va_list */*ap*/);
957 /* The group is being skipped; @excuse@ may be null or a format
958 * string explaining why. The @egroup@ method will not be called
959 * separately.
960 */
961
962 void (*egroup)(struct tvec_output */*o*/);
963 /* End a test group. At least one test was attempted or @skipgroup@
964 * would have been called instead. If @tv->curr[TVOUT_LOSE]@ is
965 * nonzero then the test group as a whole failed; otherwise it
966 * passed.
967 */
968
969 void (*btest)(struct tvec_output */*o*/);
970 /* Begin a test case. */
971
972 void (*skip)(struct tvec_output */*o*/,
973 const char */*excuse*/, va_list */*ap*/);
974 /* The test case is being skipped; @excuse@ may be null or a format
975 * string explaining why. The @etest@ function will still be called
976 * (so this works differently from @skipgroup@ and @egroup@). A test
977 * case can be skipped at most once, and, if skipped, it cannot fail.
978 */
979
980 void (*fail)(struct tvec_output */*o*/,
981 const char */*detail*/, va_list */*ap*/);
982 /* The test case failed.
983 *
984 * The output driver should preferably report the filename (@infile@)
985 * and line number (@test_lno@, not @lno@) for the failing test.
986 *
987 * The @detail@ may be null or a format string describing detail
988 * about how the failing test was run which can't be determined from
989 * the registers; a @detail@ is usually provided when (and only when)
990 * the test environment potentially invokes the test function more
991 * than once.
992 *
993 * A single test case can fail multiple times!
994 */
995
996 void (*dumpreg)(struct tvec_output */*o*/,
997 unsigned /*disp*/, const union tvec_regval */*rv*/,
998 const struct tvec_regdef */*rd*/);
999 /* Dump a register. The `disposition' @disp@ explains what condition
1000 * the register is in; see @tvec_dumpreg@ and the @TVRD_...@ codes.
1001 * The register value is at @rv@, and its definition, including its
1002 * type, at @rd@. Note that this function may be called on virtual
1003 * registers which aren't in either of the register vectors or
1004 * mentioned by the test description.
1005 */
1006
1007 void (*etest)(struct tvec_output */*o*/, unsigned /*outcome*/);
1008 /* The test case concluded with the given @outcome@ (one of the
1009 * @TVOUT_...@ codes.
1010 */
1011
1012 void (*bbench)(struct tvec_output */*o*/,
1013 const char */*ident*/, unsigned /*unit*/);
1014 /* Begin a benchmark. The @ident@ is a formatted string identifying
1015 * the benchmark based on the values of the input registered marked
1016 * @TVRF_ID@; the output driver is free to use this or come up with
1017 * its own way to identify the test, e.g., by inspecting the register
1018 * values for itself. The @unit@ is one of the @TVBU_...@ constants
1019 * explaining what sort of thing is being measured.
1020 */
1021
1022 void (*ebench)(struct tvec_output */*o*/,
1023 const char */*ident*/, unsigned /*unit*/,
1024 const struct bench_timing */*tm*/);
1025 /* End a benchmark. The @ident@ and @unit@ arguments are as for
1026 * @bbench@. If @tm@ is zero then the measurement failed; otherwise
1027 * @tm->n@ counts total number of things (operations or bytes, as
1028 * indicated by @unit@) processed in the indicated time.
1029 */
1030
1031 void (*error)(struct tvec_output */*o*/,
1032 const char */*msg*/, va_list */*ap*/);
1033 /* Report an error. The driver should ideally report the filename
1034 * (@infile@) and line number (@lno@) prompting the error.
1035 */
1036
1037 void (*notice)(struct tvec_output */*o*/,
1038 const char */*msg*/, va_list */*ap*/);
1039 /* Report a miscellaneous message. The driver should ideally report
1040 * the filename (@infile@) and line number (@lno@) prompting the
1041 * error.
1042 */
1043
1044 void (*destroy)(struct tvec_output */*o*/);
1045 /* Release any resources acquired by the driver. */
1046 };
1047
1048 /* --- @tvec_error@, @tvec_error_v@ --- *
1049 *
1050 * Arguments: @struct tvec_state *tv@ = test-vector state
1051 * @const char *msg@, @va_list ap@ = error message
1052 *
1053 * Returns: @-1@.
1054 *
1055 * Use: Report an error. Errors are distinct from test failures,
1056 * and indicate that a problem was encountered which compromised
1057 * the activity of testing.
1058 */
1059
1060 extern int PRINTF_LIKE(2, 3)
1061 tvec_error(struct tvec_state */*tv*/, const char */*msg*/, ...);
1062 extern int tvec_error_v(struct tvec_state */*tv*/,
1063 const char */*msg*/, va_list */*ap*/);
1064
1065 /* --- @tvec_notice@, @tvec_notice_v@ --- *
1066 *
1067 * Arguments: @struct tvec_state *tv@ = test-vector state
1068 * @const char *msg@, @va_list ap@ = message
1069 *
1070 * Returns: ---
1071 *
1072 * Use: Output a notice: essentially, some important information
1073 * which doesn't fit into any of the existing categories.
1074 */
1075
1076 extern void PRINTF_LIKE(2, 3)
1077 tvec_notice(struct tvec_state */*tv*/, const char */*msg*/, ...);
1078 extern void tvec_notice_v(struct tvec_state */*tv*/,
1079 const char */*msg*/, va_list */*ap*/);
1080
1081 /* --- @tvec_humanoutput@ --- *
1082 *
1083 * Arguments: @FILE *fp@ = output file to write on
1084 *
1085 * Returns: An output formatter.
1086 *
1087 * Use: Return an output formatter which writes on @fp@ with the
1088 * expectation that a human will be watching and interpreting
1089 * the output. If @fp@ denotes a terminal, the display shows a
1090 * `scoreboard' indicating the outcome of each test case
1091 * attempted, and may in addition use colour and other
1092 * highlighting.
1093 */
1094
1095 extern struct tvec_output *tvec_humanoutput(FILE */*fp*/);
1096
1097 /* --- @tvec_tapoutput@ --- *
1098 *
1099 * Arguments: @FILE *fp@ = output file to write on
1100 *
1101 * Returns: An output formatter.
1102 *
1103 * Use: Return an output formatter which writes on @fp@ in `TAP'
1104 * (`Test Anything Protocol') format.
1105 *
1106 * TAP comes from the Perl community, but has spread rather
1107 * further. This driver produces TAP version 13. The driver
1108 * produces a TAP `test point' -- i.e., a result reported as
1109 * `ok' or `not ok' -- for each input test group. Failure
1110 * reports and register dumps are produced as diagnostic
1111 * messages before the final group result. (TAP permits
1112 * structuerd YAML data after the test-point result, which could
1113 * be used to report details, but (a) postponing the details
1114 * until after the report is inconvenient, and (b) there is no
1115 * standardization for the YAML anyway, so in practice it's no
1116 * more useful than the unstructured diagnostics.
1117 */
1118
1119 extern struct tvec_output *tvec_tapoutput(FILE */*fp*/);
1120
1121 /* --- @tvec_dfltoutput@ --- *
1122 *
1123 * Arguments: @FILE *fp@ = output file to write on
1124 *
1125 * Returns: An output formatter.
1126 *
1127 * Use: Selects and instantiates an output formatter suitable for
1128 * writing on @fp@. The policy is subject to change, but
1129 * currently the `human' output format is selected if @fp@ is
1130 * interactive (i.e., if @isatty(fileno(fp))@ is true), and
1131 * otherwise the `tap' format is used.
1132 */
1133
1134 extern struct tvec_output *tvec_dfltout(FILE */*fp*/);
1135
1136 /*----- Register types ----------------------------------------------------*/
1137
1138 struct tvec_regty {
1139 /* A register type. */
1140
1141 void (*init)(union tvec_regval */*rv*/, const struct tvec_regdef */*rd*/);
1142 /* Initialize the value in @*rv@. This will be called before any
1143 * other function acting on the value, including @release@.
1144 */
1145
1146 void (*release)(union tvec_regval */*rv*/,
1147 const struct tvec_regdef */*rd*/);
1148 /* Release any resources associated with the value in @*rv@. */
1149
1150 int (*eq)(const union tvec_regval */*rv0*/,
1151 const union tvec_regval */*rv1*/,
1152 const struct tvec_regdef */*rd*/);
1153 /* Return nonzero if @*rv0@ and @*rv1@ are equal values.
1154 * Asymmetric criteria are permitted: @tvec_checkregs@ calls @eq@
1155 * with the input register as @rv0@ and the output as @rv1@.
1156 */
1157
1158 int (*tobuf)(buf */*b*/, const union tvec_regval */*rv*/,
1159 const struct tvec_regdef */*rd*/);
1160 /* Serialize the value @*rv@, writing the result to @b@. Return
1161 * zero on success, or @-1@ on error.
1162 */
1163
1164 int (*frombuf)(buf */*b*/, union tvec_regval */*rv*/,
1165 const struct tvec_regdef */*rd*/);
1166 /* Deserialize a value from @b@, storing it in @*rv@. Return zero on
1167 * success, or @-1@ on error.
1168 */
1169
1170 int (*parse)(union tvec_regval */*rv*/, const struct tvec_regdef */*rd*/,
1171 struct tvec_state */*tv*/);
1172 /* Parse a value from @tv->fp@, storing it in @*rv@. Return zero on
1173 * success, or @-1@ on error, having reported one or more errors via
1174 * @tvec_error@ or @tvec_syntax@. A successful return should leave
1175 * the input position at the start of the next line; the caller will
1176 * flush the remainder of the line itself.
1177 */
1178
1179 void (*dump)(const union tvec_regval */*rv*/,
1180 const struct tvec_regdef */*rd*/,
1181 unsigned /*style*/,
1182 const struct gprintf_ops */*gops*/, void */*go*/);
1183 #define TVSF_COMPACT 1u
1184 /* Write a human-readable representation of the value @*rv@ using
1185 * @gprintf@ on @gops@ and @go@. The @style@ is a collection of
1186 * flags: if @TVSF_COMPACT@ is set, then output should be minimal,
1187 * and must fit on a single line; otherwise, output may consist of
1188 * multiple lines and may contain redundant information if that is
1189 * likely to be useful to a human reader.
1190 */
1191 };
1192
1193 /*----- Integer types: signed and unsigned ------------------------------- */
1194
1195 /* Integers may be input in decimal, hex, binary, or octal, following
1196 * approximately usual conventions.
1197 *
1198 * * Signed integers may be preceded with a `+' or `-' sign.
1199 *
1200 * * Decimal integers are just a sequence of decimal digits `0' ... `9'.
1201 *
1202 * * Octal integers are a sequence of digits `0' ... `7', preceded by `0o'
1203 * or `0O'.
1204 *
1205 * * Hexadecimal integers are a sequence of digits `0' ... `9', `a'
1206 * ... `f', or `A' ... `F', preceded by `0x' or `0X'.
1207 *
1208 * * Radix-B integers are a sequence of digits `0' ... `9', `a' ... `f', or
1209 * `A' ... `F', each with value less than B, preceded by `Br' or `BR',
1210 * where 0 < B < 36 is expressed in decimal without any leading `0' or
1211 * internal underscores `_'.
1212 *
1213 * * A digit sequence may contain internal underscore `_' separators, but
1214 * not before or after all of the digits; and two consecutive `_'
1215 * characters are not permitted.
1216 */
1217
1218 extern const struct tvec_regty tvty_int, tvty_uint;
1219
1220 /* The @arg.p@ slot may be null or a pointer to @struct tvec_irange@ or
1221 * @struct tvec_urange@ as appropriate. The bounds are inclusive; use, e.g.,
1222 * @LONG_MAX@ explicitly if one or the other bound is logically inapplicable.
1223 */
1224 struct tvec_irange { long min, max; };
1225 struct tvec_urange { unsigned long min, max; };
1226
1227 /* Bounds corresponding to common integer types. */
1228 extern const struct tvec_irange
1229 tvrange_schar, tvrange_short, tvrange_int, tvrange_long,
1230 tvrange_sbyte, tvrange_i16, tvrange_i32;
1231 extern const struct tvec_urange
1232 tvrange_uchar, tvrange_ushort, tvrange_uint, tvrange_ulong, tvrange_size,
1233 tvrange_byte, tvrange_u16, tvrange_u32;
1234
1235 /* --- tvec_claimeq_int@, @TVEC_CLAIMEQ_INT@ --- *
1236 *
1237 * Arguments: @struct tvec_state *tv@ = test-vector state
1238 * @long i0, i1@ = two signed integers
1239 * @const char *file@, @unsigned @lno@ = calling file and line
1240 * @const char *expr@ = the expression to quote on failure
1241 *
1242 * Returns: Nonzero if @i0@ and @i1@ are equal, otherwise zero.
1243 *
1244 * Use: Check that values of @i0@ and @i1@ are equal. As for
1245 * @tvec_claim@ above, a test case is automatically begun and
1246 * ended if none is already underway. If the values are
1247 * unequal, then @tvec_fail@ is called, quoting @expr@, and the
1248 * mismatched values are dumped: @i0@ is printed as the output
1249 * value and @i1@ is printed as the input reference.
1250 *
1251 * The @TVEC_CLAIM_INT@ macro is similar, only it (a) identifies
1252 * the file and line number of the call site automatically, and
1253 * (b) implicitly quotes the source text of the @i0@ and @i1@
1254 * arguments in the failure message.
1255 */
1256
1257 extern int tvec_claimeq_int(struct tvec_state */*tv*/,
1258 long /*i0*/, long /*i1*/,
1259 const char */*file*/, unsigned /*lno*/,
1260 const char */*expr*/);
1261 #define TVEC_CLAIMEQ_INT(tv, i0, i1) \
1262 (tvec_claimeq_int(tv, i0, i1, __FILE__, __LINE__, #i0 " /= " #i1))
1263
1264 /* --- @tvec_claimeq_uint@, @TVEC_CLAIMEQ_UINT@ --- *
1265 *
1266 * Arguments: @struct tvec_state *tv@ = test-vector state
1267 * @unsigned long u0, u1@ = two unsigned integers
1268 * @const char *file@, @unsigned @lno@ = calling file and line
1269 * @const char *expr@ = the expression to quote on failure
1270 *
1271 * Returns: Nonzero if @u0@ and @u1@ are equal, otherwise zero.
1272 *
1273 * Use: Check that values of @u0@ and @u1@ are equal. As for
1274 * @tvec_claim@ above, a test case is automatically begun and
1275 * ended if none is already underway. If the values are
1276 * unequal, then @tvec_fail@ is called, quoting @expr@, and the
1277 * mismatched values are dumped: @u0@ is printed as the output
1278 * value and @u1@ is printed as the input reference.
1279 *
1280 * The @TVEC_CLAIM_UINT@ macro is similar, only it (a)
1281 * identifies the file and line number of the call site
1282 * automatically, and (b) implicitly quotes the source text of
1283 * the @u0@ and @u1@ arguments in the failure message.
1284 */
1285
1286 extern int tvec_claimeq_uint(struct tvec_state */*tv*/,
1287 unsigned long /*u0*/, unsigned long /*u1*/,
1288 const char */*file*/, unsigned /*lno*/,
1289 const char */*expr*/);
1290 #define TVEC_CLAIMEQ_UINT(tv, u0, u1) \
1291 (tvec_claimeq_uint(tv, u0, u1, __FILE__, __LINE__, #u0 " /= " #u1))
1292
1293 /*----- Floating-point type -----------------------------------------------*/
1294
1295 /* Floating-point are either NaN (`#nan', if supported by the platform);
1296 * positive or negative infinity (`#inf', `+#inf', or, preferred, `#+inf',
1297 * and `-#inf' or, preferred, `#-inf', if supported by the platform), or a
1298 * number in strtod(3) syntax.
1299 *
1300 * The comparison rules for floating-point numbers are complex: see
1301 * @tvec_claimeqish_float@ for details.
1302 */
1303
1304 extern const struct tvec_regty tvty_float;
1305
1306 struct tvec_floatinfo {
1307 /* Details about acceptable floating-point values. */
1308
1309 unsigned f; /* flags (@TVFF_...@ bits) */
1310 #define TVFF_NOMIN 1u /* ignore @min@ (allow -inf) */
1311 #define TVFF_NOMAX 2u /* ignore @max@ (allow +inf) */
1312 #define TVFF_NANOK 4u /* permit NaN */
1313 #define TVFF_EQMASK 0xf0 /* how to compare */
1314 #define TVFF_EXACT 0x00 /* must equal exactly */
1315 #define TVFF_ABSDELTA 0x10 /* must be within @delta@ */
1316 #define TVFF_RELDELTA 0x20 /* diff < @delta@ fraction */
1317 double min, max; /* smallest/largest value allowed */
1318 double delta; /* maximum tolerable difference */
1319 };
1320
1321 /* --- @tvec_claimeqish_float@, @TVEC_CLAIMEQISH_FLOAT@ --- *
1322 *
1323 * Arguments: @struct tvec_state *tv@ = test-vector state
1324 * @double f0, f1@ = two floating-point numbers
1325 * @unsigned f@ = flags (@TVFF_...@)
1326 * @double delta@ = maximum tolerable difference
1327 * @const char *file@, @unsigned @lno@ = calling file and line
1328 * @const char *expr@ = the expression to quote on failure
1329 *
1330 * Returns: Nonzero if @f0@ and @u1@ are sufficiently close, otherwise
1331 * zero.
1332 *
1333 * Use: Check that values of @f0@ and @f1@ are sufficiently close.
1334 * As for @tvec_claim@ above, a test case is automatically begun
1335 * and ended if none is already underway. If the values are
1336 * too far apart, then @tvec_fail@ is called, quoting @expr@,
1337 * and the mismatched values are dumped: @f0@ is printed as the
1338 * output value and @f1@ is printed as the input reference.
1339 *
1340 * The details for the comparison are as follows.
1341 *
1342 * * A NaN value matches any other NaN, and nothing else.
1343 *
1344 * * An infinity matches another infinity of the same sign,
1345 * and nothing else.
1346 *
1347 * * If @f&TVFF_EQMASK@ is @TVFF_EXACT@, then any
1348 * representable number matches only itself: in particular,
1349 * positive and negative zero are considered distinct.
1350 * (This allows tests to check that they land on the correct
1351 * side of branch cuts, for example.)
1352 *
1353 * * If @f&TVFF_EQMASK@ is @TVFF_ABSDELTA@, then %$x$% matches
1354 * %$y$% when %$|x - y| < \delta$%.
1355 *
1356 * * If @f&TVFF_EQMASK@ is @TVFF_RELDELTA@, then %$x$% matches
1357 * %$y$% when %$|1 - y/x| < \delta$%. (Note that this
1358 * criterion is asymmetric
1359 *
1360 * The @TVEC_CLAIM_FLOAT@ macro is similar, only it (a)
1361 * identifies the file and line number of the call site
1362 * automatically, and (b) implicitly quotes the source text of
1363 * the @f0@ and @f1@ arguments (and @delta@) in the failure
1364 * message.
1365 */
1366
1367 extern int tvec_claimeqish_float(struct tvec_state */*tv*/,
1368 double /*f0*/, double /*f1*/,
1369 unsigned /*f*/, double /*delta*/,
1370 const char */*file*/, unsigned /*lno*/,
1371 const char */*expr*/);
1372 #define TVEC_CLAIMEQISH_FLOAT(tv, f0, f1, f, delta) \
1373 (tvec_claimeqish_float(tv, f0, f1, f, delta, , __FILE__, __LINE__, \
1374 #f0 " /= " #f1 " (+/- " #delta ")"))
1375
1376 /* --- @tvec_claimeq_float@, @TVEC_CLAIMEQ_FLOAT@ --- *
1377 *
1378 * Arguments: @struct tvec_state *tv@ = test-vector state
1379 * @double f0, f1@ = two floating-point numbers
1380 * @const char *file@, @unsigned @lno@ = calling file and line
1381 * @const char *expr@ = the expression to quote on failure
1382 *
1383 * Returns: Nonzero if @f0@ and @u1@ are identical, otherwise zero.
1384 *
1385 * Use: Check that values of @f0@ and @f1@ are identical. The
1386 * function is exactly equivalent to @tvec_claimeqish_float@
1387 * with @f == TVFF_EXACT@; the macro is similarly like
1388 * @TVEC_CLAIMEQISH_FLOAT@ with @f == TVFF_EXACT@, except that
1389 * it doesn't bother to quote a delta.
1390 */
1391
1392 extern int tvec_claimeq_float(struct tvec_state */*tv*/,
1393 double /*f0*/, double /*f1*/,
1394 const char */*file*/, unsigned /*lno*/,
1395 const char */*expr*/);
1396 #define TVEC_CLAIMEQ_FLOAT(tv, f0, f1) \
1397 (tvec_claimeq_float(tv, f0, f1, __FILE__, __LINE__, #f0 " /= " #f1))
1398
1399 /*----- Enumerated types --------------------------------------------------*/
1400
1401 /* There is a distinct enumerated type for each of the branches of
1402 * @tvec_misc@. In the following, we write @t@ for the type code, which is
1403 * @i@ for signed integer, @u@ for unsigned integer, @f@ for floating-point,
1404 * and @p@ for pointer.
1405 */
1406
1407 #define DEFENUMTY(tag, ty, slot) \
1408 extern const struct tvec_regty tvty_##slot##enum;
1409 TVEC_MISCSLOTS(DEFENUMTY)
1410 #undef DEFENUMTY
1411
1412 /* A @struct tvec_tassoc@ associates a string tag with a value. */
1413 #define DEFASSOC(tag_, ty, slot) \
1414 struct tvec_##slot##assoc { const char *tag; ty slot; };
1415 TVEC_MISCSLOTS(DEFASSOC)
1416 #undef DEFASSOC
1417
1418 /* Information about an enumerated type. */
1419 #define DEFINFO(tag, ty, slot) \
1420 struct tvec_##slot##enuminfo { \
1421 const char *name; /* type name for diagnostics */ \
1422 const struct tvec_##slot##assoc *av; /* name/value mappings */ \
1423 EXTRA_##tag##_INFOSLOTS /* type-specific extra info */ \
1424 };
1425
1426 #define EXTRA_INT_INFOSLOTS \
1427 const struct tvec_irange *ir; /* allowed range of raw values */
1428
1429 #define EXTRA_UINT_INFOSLOTS \
1430 const struct tvec_urange *ur; /* allowed range of raw values */
1431
1432 #define EXTRA_FLT_INFOSLOTS \
1433 const struct tvec_floatinfo *fi; /* range and matching policy */
1434
1435 #define EXTRA_PTR_INFOSLOTS /* (nothing) */
1436
1437 TVEC_MISCSLOTS(DEFINFO)
1438
1439 #undef EXTRA_INT_INFOSLOTS
1440 #undef EXTRA_UINT_INFOSLOTS
1441 #undef EXTRA_FLT_INFOSLOTS
1442 #undef EXTRA_PTR_INFOSLOTS
1443
1444 #undef DEFINFO
1445
1446 /* Standard enumerations. */
1447 const struct tvec_ienuminfo tvenum_bool;
1448
1449 /* --- @tvec_claimeq_tenum@, @TVEC_CLAIMEQ_TENUM@ --- *
1450 *
1451 * Arguments: @struct tvec_state *tv@ = test-vector state
1452 * @ty t0, t1@ = two values
1453 * @const char *file@, @unsigned @lno@ = calling file and line
1454 * @const char *expr@ = the expression to quote on failure
1455 *
1456 * Returns: Nonzero if @t0@ and @t1@ are equal, otherwise zero.
1457 *
1458 * Use: Check that values of @t0@ and @t1@ are equal. As for
1459 * @tvec_claim@ above, a test case is automatically begun and
1460 * ended if none is already underway. If the values are
1461 * unequal, then @tvec_fail@ is called, quoting @expr@, and the
1462 * mismatched values are dumped: @u0@ is printed as the output
1463 * value and @u1@ is printed as the input reference.
1464 *
1465 * The @TVEC_CLAIM_TENUM@ macro is similar, only it (a)
1466 * identifies the file and line number of the call site
1467 * automatically, and (b) implicitly quotes the source text of
1468 * the @u0@ and @u1@ arguments in the failure message.
1469 */
1470
1471 #define DECLCLAIM(tag, ty, slot) \
1472 extern int tvec_claimeq_##slot##enum \
1473 (struct tvec_state */*tv*/, \
1474 const struct tvec_##slot##enuminfo */*ei*/, \
1475 ty /*t0*/, ty /*t1*/, \
1476 const char */*file*/, unsigned /*lno*/, const char */*expr*/);
1477 TVEC_MISCSLOTS(DECLCLAIM)
1478 #undef DECLCLAIM
1479 #define TVEC_CLAIMEQ_IENUM(tv, ei, i0, i1) \
1480 (tvec_claimeq_ienum(tv, ei, i0, i1, \
1481 __FILE__, __LINE__, #i0 " /= " #i1))
1482 #define TVEC_CLAIMEQ_UENUM(tv, ei, u0, u1) \
1483 (tvec_claimeq_uenum(tv, ei, u0, u1, \
1484 __FILE__, __LINE__, #u0 " /= " #u1))
1485 #define TVEC_CLAIMEQ_FENUM(tv, ei, f0, f1) \
1486 (tvec_claimeq_fenum(tv, ei, f0, f1, \
1487 __FILE__, __LINE__, #f0 " /= " #f1))
1488 #define TVEC_CLAIMEQ_PENUM(tv, ei, p0, p1) \
1489 (tvec_claimeq_penum(tv, ei, p0, p1, \
1490 __FILE__, __LINE__, #p0 " /= " #p1))
1491
1492 /*----- Flags type -------------------------------------------------------*/
1493
1494 extern const struct tvec_regty tvty_flags;
1495
1496 struct tvec_flag {
1497 /* Definition of a single flag or bitfield value.
1498 *
1499 * Each named setting comes with a value @v@ and a mask @m@; the mask
1500 * should cover all of the value bits, i.e., @(v&~m) == 0@. On input,
1501 * exactly
1502 */
1503
1504 const char *tag; /* name */
1505 unsigned long m, v; /* mask and value */
1506 };
1507
1508 struct tvec_flaginfo {
1509 const char *name;
1510 const struct tvec_flag *fv;
1511 const struct tvec_urange *range;
1512 };
1513
1514 extern int tvec_claimeq_flags(struct tvec_state */*tv*/,
1515 const struct tvec_flaginfo */*fi*/,
1516 unsigned long /*f0*/, unsigned long /*f1*/,
1517 const char */*file*/, unsigned /*lno*/,
1518 const char */*expr*/);
1519 #define TVEC_CLAIMEQ_FLAGS(tv, fi, f0, f1) \
1520 (tvec_claimeq_flags(tv, fi, f0, f1, \
1521 __FILE__, __LINE__, #f0 " /= " #f1))
1522
1523 extern const struct tvec_regty tvty_char;
1524 extern int tvec_claimeq_char(struct tvec_state */*tv*/,
1525 int /*ch0*/, int /*ch1*/,
1526 const char */*file*/, unsigned /*lno*/,
1527 const char */*expr*/);
1528 #define TVEC_CLAIMEQ_CHAR(tv, c0, c1) \
1529 (tvec_claimeq_char(tv, c0, c1, __FILE__, __LINE__, #c0 " /= " #c1))
1530
1531 extern const struct tvec_regty tvty_string, tvty_bytes;
1532
1533 extern int tvec_claimeq_string(struct tvec_state */*tv*/,
1534 const char */*p0*/, size_t /*sz0*/,
1535 const char */*p1*/, size_t /*sz1*/,
1536 const char */*file*/, unsigned /*lno*/,
1537 const char */*expr*/);
1538 extern int tvec_claimeq_strz(struct tvec_state */*tv*/,
1539 const char */*p0*/, const char */*p1*/,
1540 const char */*file*/, unsigned /*lno*/,
1541 const char */*expr*/);
1542 extern int tvec_claimeq_bytes(struct tvec_state */*tv*/,
1543 const void */*p0*/, size_t /*sz0*/,
1544 const void */*p1*/, size_t /*sz1*/,
1545 const char */*file*/, unsigned /*lno*/,
1546 const char */*expr*/);
1547 #define TVEC_CLAIMEQ_STRING(tv, p0, sz0, p1, sz1) \
1548 (tvec_claimeq_string(tv, p0, sz0, p1, sz1, __FILE__, __LINE__, \
1549 #p0 "[" #sz0 "] /= " #p1 "[" #sz1 "]"))
1550 #define TVEC_CLAIMEQ_STRZ(tv, p0, p1) \
1551 (tvec_claimeq_strz(tv, p0, p1, __FILE__, __LINE__, #p0 " /= " #p1))
1552 #define TVEC_CLAIMEQ_BYTES(tv, p0, sz0, p1, sz1) \
1553 (tvec_claimeq(tv, p0, sz0, p1, sz1, __FILE__, __LINE__, \
1554 #p0 "[" #sz0 "] /= " #p1 "[" #sz1 "]"))
1555
1556 extern const struct tvec_regty tvty_buffer;
1557
1558 extern void tvec_allocstring(union tvec_regval */*rv*/, size_t /*sz*/);
1559 extern void tvec_allocbytes(union tvec_regval */*rv*/, size_t /*sz*/);
1560
1561 /*----- Benchmarking ------------------------------------------------------*/
1562
1563 struct tvec_bench {
1564 struct tvec_env _env; /* benchmarking is an environment */
1565 struct bench_state **bst; /* benchmark state anchor or null */
1566 unsigned long niter; /* iterations done per unit */
1567 int riter, rbuf; /* iterations and buffer registers */
1568 const struct tvec_env *env; /* environment (per test, not grp) */
1569 };
1570 #define TVEC_BENCHENV \
1571 { sizeof(struct tvec_benchctx), \
1572 tvec_benchsetup, \
1573 tvec_benchset, \
1574 tvec_benchbefore, \
1575 tvec_benchrun, \
1576 tvec_benchafter, \
1577 tvec_benchteardown }
1578 #define TVEC_BENCHINIT TVEC_BENCHENV, &tvec_benchstate
1579
1580 struct tvec_benchctx {
1581 const struct tvec_bench *b;
1582 struct bench_state *bst;
1583 double dflt_target;
1584 void *subctx;
1585 };
1586
1587 extern struct bench_state *tvec_benchstate;
1588
1589 extern int tvec_benchsetup(struct tvec_state */*tv*/,
1590 const struct tvec_env */*env*/,
1591 void */*pctx*/, void */*ctx*/);
1592 extern int tvec_benchset(struct tvec_state */*tv*/, const char */*var*/,
1593 const struct tvec_env */*env*/, void */*ctx*/);
1594 extern int tvec_benchbefore(struct tvec_state */*tv*/, void */*ctx*/);
1595 extern void tvec_benchrun(struct tvec_state */*tv*/,
1596 tvec_testfn */*fn*/, void */*ctx*/);
1597 extern void tvec_benchafter(struct tvec_state */*tv*/, void */*ctx*/);
1598 extern void tvec_benchteardown(struct tvec_state */*tv*/, void */*ctx*/);
1599
1600 extern void tvec_benchreport
1601 (const struct gprintf_ops */*gops*/, void */*go*/,
1602 unsigned /*unit*/, const struct bench_timing */*tm*/);
1603
1604 /*----- Command-line interface --------------------------------------------*/
1605
1606 extern const struct tvec_config tvec_adhocconfig;
1607
1608 extern void tvec_parseargs(int /*argc*/, char */*argv*/[],
1609 struct tvec_state */*tv_out*/,
1610 int */*argpos_out*/,
1611 const struct tvec_config */*config*/);
1612
1613 extern int tvec_readstdin(struct tvec_state */*tv*/);
1614 extern int tvec_readfile(struct tvec_state */*tv*/, const char */*file*/);
1615 extern int tvec_readdflt(struct tvec_state */*tv*/, const char */*file*/);
1616 extern int tvec_readarg(struct tvec_state */*tv*/, const char */*arg*/);
1617
1618 extern int tvec_readargs(int /*argc*/, char */*argv*/[],
1619 struct tvec_state */*tv*/,
1620 int */*argpos_inout*/, const char */*dflt*/);
1621
1622 extern int tvec_main(int /*argc*/, char */*argv*/[],
1623 const struct tvec_config */*config*/,
1624 const char */*dflt*/);
1625
1626 /*----- That's all, folks -------------------------------------------------*/
1627
1628 #ifdef __cplusplus
1629 }
1630 #endif
1631
1632 #endif