#include <stdio.h>
#include <string.h>
-#ifndef MLIB_BUF_H
-# include "buf.h"
+#ifndef MLIB_ARENA_H
+# include "arena.h"
#endif
-#ifndef MLIB_CONTROL_H
-# include "control.h"
+#ifndef MLIB_BUF_H
+# include "buf.h"
#endif
-#ifndef MLIB_BUF_H
+#ifndef MLIB_DSTR_H
# include "dstr.h"
#endif
# include "gprintf.h"
#endif
-#ifndef MLIB_LBUF_H
-# include "lbuf.h"
-#endif
-
#ifndef MLIB_MACROS_H
# include "macros.h"
#endif
const struct tvec_env *env; /* environment to run test in */
tvec_testfn *fn; /* test function */
};
-#define TVEC_ENDTESTS { 0, 0, 0, 0 }
/*----- Test state --------------------------------------------------------*/
+struct tvec_output;
+
enum {
/* Possible test outcomes. */
struct tvec_config {
/* An overall test configuration. */
- const struct tvec_test *tests; /* the tests to be performed */
+ const struct tvec_test *const *tests; /* the tests to be performed */
unsigned nrout, nreg; /* number of output/total regs */
size_t regsz; /* size of a register */
};
#define TVSF_XFAIL 0x0100u /* test expected to fail */
#define TVSF_MUFFLE 0x0200u /* muffle errors */
+ /* Memory allocation. Read-only for all callers. */
+ arena *a;
+
/* Test configuration. Read-only for all callers. */
struct tvec_config cfg; /* test configuration */
/* Test scoreboard. Available to output formatters. */
unsigned curr[TVOUT_LIMIT], all[TVOUT_LIMIT], grps[TVOUT_LIMIT];
- /* Output machinery. */
+ /* Output machinery. Read-only for environments. */
struct tvec_output *output; /* output formatter */
/* Input machinery. Available to type parsers. */
const char *infile; unsigned lno, test_lno; /* input file name, line */
FILE *fp; /* input file stream */
+
+ /* Adhoc testing state. Private. */
+ struct tvec_test adhoc_test;
+ const struct tvec_test *adhoc_tests[];
};
/* @TVEC_REG(tv, vec, i)@
*/
#define TVEC_REG(tv, vec, i) TVEC_GREG((tv)->vec, (i), (tv)->cfg.regsz)
-/*----- Output formatting -------------------------------------------------*/
-
-struct tvec_output {
- /* An output formatter. */
- const struct tvec_outops *ops; /* pointer to operations */
-};
-
-enum {
- /* Register output dispositions. */
-
- TVRD_INPUT, /* input-only register */
- TVRD_OUTPUT, /* output-only (input is dead) */
- TVRD_MATCH, /* matching (equal) registers */
- TVRD_FOUND, /* mismatching output register */
- TVRD_EXPECT, /* mismatching input register */
- TVRD_LIMIT /* (number of dispositions) */
-};
-
-#define TVEC_LEVELS(_) \
- _(NOTE, "notice", 4) \
- _(ERR, "ERROR", 8)
-enum {
-#define TVEC_DEFLEVEL(tag, name, val) TVLEV_##tag = val,
- TVEC_LEVELS(TVEC_DEFLEVEL)
-#undef TVEC_DEFLEVEL
- TVLEV_LIMIT
-};
-
-/* Benchmarking details. */
-enum {
- TVBU_OP, /* counting operations of some kind */
- TVBU_BYTE, /* counting bytes (@rbuf >= 0@) */
- TVBU_LIMIT /* (number of units) */
-};
-struct bench_timing; /* include <mLib/bench.h> for the real definition */
-
-struct tvec_outops {
- /* Output operations. */
-
- void (*bsession)(struct tvec_output */*o*/, struct tvec_state */*tv*/);
- /* Begin a test session. The output driver will probably want to
- * save @tv@, because this isn't provided to any other methods.
- */
-
- int (*esession)(struct tvec_output */*o*/);
- /* End a session, and return the suggested exit code. */
-
- void (*bgroup)(struct tvec_output */*o*/);
- /* Begin a test group. The test group description is @tv->test@. */
-
- void (*skipgroup)(struct tvec_output */*o*/,
- const char */*excuse*/, va_list */*ap*/);
- /* The group is being skipped; @excuse@ may be null or a format
- * string explaining why. The @egroup@ method will not be called
- * separately.
- */
-
- void (*egroup)(struct tvec_output */*o*/);
- /* End a test group. At least one test was attempted or @skipgroup@
- * would have been called instead. If @tv->curr[TVOUT_LOSE]@ is nonzero
- * then the test group as a whole failed; otherwise it passed.
- */
-
- void (*btest)(struct tvec_output */*o*/);
- /* Begin a test case. */
-
- void (*skip)(struct tvec_output */*o*/,
- const char */*excuse*/, va_list */*ap*/);
- /* The test case is being skipped; @excuse@ may be null or a format
- * string explaining why. The @etest@ function will still be called (so
- * this works differently from @skipgroup@ and @egroup@). A test case
- * can be skipped at most once, and, if skipped, it cannot fail.
- */
-
- void (*fail)(struct tvec_output */*o*/,
- const char */*detail*/, va_list */*ap*/);
- /* The test case failed.
- *
- * The output driver should preferably report the filename (@infile@) and
- * line number (@test_lno@, not @lno@) for the failing test.
- *
- * The @detail@ may be null or a format string describing detail about
- * how the failing test was run which can't be determined from the
- * registers; a @detail@ is usually provided when (and only when) the
- * test environment potentially invokes the test function more than once.
- *
- * A single test case can fail multiple times!
- */
-
- void (*dumpreg)(struct tvec_output */*o*/,
- unsigned /*disp*/, const union tvec_regval */*rv*/,
- const struct tvec_regdef */*rd*/);
- /* Dump a register. The `disposition' @disp@ explains what condition the
- * register is in; see @tvec_dumpreg@ and the @TVRD_...@ codes. The
- * register value is at @rv@, and its definition, including its type, at
- * @rd@. Note that this function may be called on virtual registers
- * which aren't in either of the register vectors or mentioned by the
- * test description. It may also be called with @rv@ null, indicating
- * that the register is not live.
- */
-
- void (*etest)(struct tvec_output */*o*/, unsigned /*outcome*/);
- /* The test case concluded with the given @outcome@ (one of the
- * @TVOUT_...@ codes.
- */
-
- void (*bbench)(struct tvec_output */*o*/,
- const char */*ident*/, unsigned /*unit*/);
- /* Begin a benchmark. The @ident@ is a formatted string identifying the
- * benchmark based on the values of the input registered marked
- * @TVRF_ID@; the output driver is free to use this or come up with its
- * own way to identify the test, e.g., by inspecting the register values
- * for itself. The @unit@ is one of the @TVBU_...@ constants explaining
- * what sort of thing is being measured.
- */
-
- void (*ebench)(struct tvec_output */*o*/,
- const char */*ident*/, unsigned /*unit*/,
- const struct bench_timing */*tm*/);
- /* End a benchmark. The @ident@ and @unit@ arguments are as for
- * @bbench@. If @tm@ is zero then the measurement failed; otherwise
- * @tm->n@ counts total number of things (operations or bytes, as
- * indicated by @unit@) processed in the indicated time.
- */
-
- void (*report)(struct tvec_output */*o*/, unsigned /*level*/,
- const char */*msg*/, va_list */*ap*/);
- /* Report a message. The driver should ideally report the filename
- * (@infile@) and line number (@lno@) prompting the error.
- */
-
- void (*destroy)(struct tvec_output */*o*/);
- /* Release any resources acquired by the driver. */
-};
-
/*----- Session lifecycle -------------------------------------------------*/
/* --- @tvec_begin@ --- *
/*----- Command-line interface --------------------------------------------*/
-extern const struct tvec_config tvec_adhocconfig;
- /* A special @struct tvec_config@ to use for programs which perform ad-hoc
- * testing.
- */
-
/* --- @tvec_parseargs@ --- *
*
* Arguments: @int argc@ = number of command-line arguments
extern void tvec_check_v(struct tvec_state */*tv*/,
const char */*detail*/, va_list */*ap*/);
-/*----- Ad-hoc testing ----------------------------------------------------*/
-
-/* --- @tvec_adhoc@ --- *
- *
- * Arguments: @struct tvec_state *tv@ = test-vector state
- * @struct tvec_test *t@ = space for a test definition
- *
- * Returns: ---
- *
- * Use: Begin ad-hoc testing, i.e., without reading a file of
- * test-vector data.
- *
- * The structure at @t@ will be used to record information about
- * the tests underway, which would normally come from a static
- * test definition. The other functions in this section assume
- * that @tvec_adhoc@ has been called.
- */
-
-extern void tvec_adhoc(struct tvec_state */*tv*/, struct tvec_test */*t*/);
-
-/* --- @tvec_begingroup@, @TVEC_BEGINGROUP@ --- *
- *
- * Arguments: @struct tvec_state *tv@ = test-vector state
- * @const char *name@ = name for this test group
- * @const char *file@, @unsigned @lno@ = calling file and line
- *
- * Returns: ---
- *
- * Use: Begin an ad-hoc test group with the given name. The @file@
- * and @lno@ can be anything, but it's usually best if they
- * refer to the source code performing the test: the macro
- * @TVEC_BEGINGROUP@ does this automatically.
- */
-
-extern void tvec_begingroup(struct tvec_state */*tv*/, const char */*name*/,
- const char */*file*/, unsigned /*lno*/);
-#define TVEC_BEGINGROUP(tv, name) \
- do tvec_begingroup(tv, name, __FILE__, __LINE__); while (0)
-
-/* --- @tvec_endgroup@ --- *
- *
- * Arguments: @struct tvec_state *tv@ = test-vector state
- *
- * Returns: ---
- *
- * Use: End an ad-hoc test group. The statistics are updated and the
- * outcome is reported to the output formatter.
- */
-
-extern void tvec_endgroup(struct tvec_state */*tv*/);
-
-/* --- @TVEC_TESTGROUP@, @TVEC_TESTGROUP_TAG@ --- *
- *
- * Arguments: @tag@ = label-disambiguation tag
- * @const struct tvec_state *tv = test-vector state
- * @const char *name@ = test-group name
- *
- * Returns: ---
- *
- * Use: Control-structure macro: @TVEC_TESTGROUP(tv, name) stmt@
- * establishes a test group with the given @name@ (attributing
- * it to the source file and lie number), executes @stmt@, and
- * ends the test group. If @stmt@ invokes @break@ then the test
- * group is skipped. @TVEC_TESTGROUP_TAG@ is the same, with an
- * additional @tag@ argument for use in higher-level macros.
- */
-
-#define TVEC_TESTGROUP_TAG(tag, tv, name) \
- MC_WRAP(tag##__around, \
- { TVEC_BEGINGROUP(tv, name); }, \
- { tvec_endgroup(tv); }, \
- { if (!((tv)->f&TVSF_SKIP)) tvec_skipgroup(tv, 0); \
- tvec_endgroup(tv); })
-#define TVEC_TESTGROUP(tv, name) TVEC_TESTGROUP_TAG(grp, tv, name)
-
-/* --- @tvec_begintest@, @TVEC_BEGINTEST@ --- *
- *
- * Arguments: @struct tvec_state *tv@ = test-vector state
- * @const char *file@, @unsigned @lno@ = calling file and line
- *
- * Returns: ---
- *
- * Use: Begin an ad-hoc test case. The @file@ and @lno@ can be
- * anything, but it's usually best if they refer to the source
- * code performing the test: the macro @TVEC_BEGINGROUP@ does
- * this automatically.
- */
-
-extern void tvec_begintest(struct tvec_state */*tv*/,
- const char */*file*/, unsigned /*lno*/);
-#define TVEC_BEGINTEST(tv) \
- do tvec_begintest(tv, __FILE__, __LINE__); while (0)
-
-/* --- @tvec_endtest@ --- *
- *
- * Arguments: @struct tvec_state *tv@ = test-vector state
- *
- * Returns: ---
- *
- * Use: End an ad-hoc test case, The statistics are updated and the
- * outcome is reported to the output formatter.
- */
-
-extern void tvec_endtest(struct tvec_state */*tv*/);
-
-/* --- @TVEC_TEST@, @TVEC_TEST_TAG@ --- *
- *
- * Arguments: @tag@ = label-disambiguation tag
- * @struct tvec_test *t@ = space for a test definition
- *
- * Returns: ---
- *
- * Use: Control-structure macro: @TVEC_TEST(tv) stmt@ begins a test
- * case, executes @stmt@, and ends the test case. If @stmt@
- * invokes @break@ then the test case is skipped.
- * @TVEC_TEST_TAG@ is the same, with an additional @tag@ argumet
- * for use in higher-level macros.
- */
-
-#define TVEC_TEST_TAG(tag, tv) \
- MC_WRAP(tag##__around, \
- { TVEC_BEGINTEST(tv); }, \
- { tvec_endtest(tv); }, \
- { if ((tv)->f&TVSF_ACTIVE) tvec_skip((tv), 0); \
- tvec_endtest(tv); })
-#define TVEC_TEST(tv) TVEC_TEST_TAG(test, tv)
-
-/* --- @tvec_claim@, @tvec_claim_v@, @TVEC_CLAIM@ --- *
- *
- * Arguments: @struct tvec_state *tv@ = test-vector state
- * @int ok@ = a flag
- * @const char *file@, @unsigned @lno@ = calling file and line
- * @const char *msg@, @va_list *ap@ = message to report on
- * failure
- *
- * Returns: The value @ok@.
- *
- * Use: Check that a claimed condition holds, as (part of) a test.
- * If no test case is underway (i.e., if @TVSF_OPEN@ is reset in
- * @tv->f@), then a new test case is begun and ended. The
- * @file@ and @lno@ are passed to the output formatter to be
- * reported in case of a failure. If @ok@ is nonzero, then
- * nothing else happens; so, in particular, if @tvec_claim@
- * established a new test case, then the test case succeeds. If
- * @ok@ is zero, then a failure is reported, quoting @msg@.
- *
- * The @TVEC_CLAIM@ macro is similar, only it (a) identifies the
- * file and line number of the call site automatically, and (b)
- * implicitly quotes the source text of the @ok@ condition in
- * the failure message.
- */
-
-extern PRINTF_LIKE(5, 6)
- int tvec_claim(struct tvec_state */*tv*/, int /*ok*/,
- const char */*file*/, unsigned /*lno*/,
- const char */*msg*/, ...);
-extern int tvec_claim_v(struct tvec_state */*tv*/, int /*ok*/,
- const char */*file*/, unsigned /*lno*/,
- const char */*msg*/, va_list */*ap*/);
-#define TVEC_CLAIM(tv, cond) \
- (tvec_claim(tv, !!(cond), __FILE__, __LINE__, "%s untrue", #cond))
-
-/* --- @tvec_claimeq@ --- *
- *
- * Arguments: @struct tvec_state *tv@ = test-vector state
- * @const struct tvec_regty *ty@ = register type
- * @const union tvec_misc *arg@ = register type argument
- * @const char *file@, @unsigned @lno@ = calling file and line
- * @const char *expr@ = the expression to quote on failure
- *
- * Returns: Nonzero if the input and output values of register 0 are
- * equal, zero if they differ.
- *
- * Use: Check that the input and output values of register 0 are
- * equal (according to the register type @ty@). As for
- * @tvec_claim@ above, a test case is automatically begun and
- * ended if none is already underway. If the values are
- * unequal, then @tvec_fail@ is called, quoting @expr@, and the
- * mismatched values are dumped.
- *
- * This function is not expected to be called directly, but
- * through type-specific wrapper functions or macros such as
- * @TVEC_CLAIMEQ_INT@.
- */
-
-extern int tvec_claimeq(struct tvec_state */*tv*/,
- const struct tvec_regty */*ty*/,
- const union tvec_misc */*arg*/,
- const char */*file*/, unsigned /*lno*/,
- const char */*expr*/);
-
-/*----- Benchmarking ------------------------------------------------------*/
-
-struct tvec_benchenv {
- struct tvec_env _env; /* benchmarking is an environment */
- struct bench_state **bst; /* benchmark state anchor or null */
- unsigned long niter; /* iterations done per unit */
- int riter, rbuf; /* iterations and buffer registers */
- const struct tvec_env *env; /* subordinate environment */
-};
-
-struct tvec_benchctx {
- const struct tvec_benchenv *be; /* environment configuration */
- struct bench_state *bst; /* benchmark state */
- double dflt_target; /* default time in seconds */
- unsigned f; /* flags */
-#define TVBF_SETTRG 1u /* set `@target' */
-#define TVBF_SETMASK (TVBF_SETTRG)) /* mask of @TVBF_SET...@ */
- void *subctx; /* subsidiary environment context */
-};
-
-extern struct bench_state *tvec_benchstate;
-
-/* --- Environment implementation --- *
- *
- * The following special variables are supported.
- *
- * * %|@target|% is the (approximate) number of seconds to run the
- * benchmark.
- *
- * Unrecognized variables are passed to the subordinate environment, if there
- * is one. Other events are passed through to the subsidiary environment.
- */
-
-extern tvec_envsetupfn tvec_benchsetup;
-extern tvec_envfindvarfn tvec_benchfindvar;
-extern tvec_envbeforefn tvec_benchbefore;
-extern tvec_envrunfn tvec_benchrun;
-extern tvec_envafterfn tvec_benchafter;
-extern tvec_envteardownfn tvec_benchteardown;
-
-#define TVEC_BENCHENV \
- { sizeof(struct tvec_benchctx), \
- tvec_benchsetup, \
- tvec_benchfindvar, \
- tvec_benchbefore, \
- tvec_benchrun, \
- tvec_benchafter, \
- tvec_benchteardown }
-#define TVEC_BENCHINIT TVEC_BENCHENV, &tvec_benchstate
-
-/* --- @tvec_benchreport@ --- *
- *
- * Arguments: @const struct gprintf_ops *gops@ = print operations
- * @void *go@ = print destination
- * @unsigned unit@ = the unit being measured (~TVBU_...@)
- * @unsigned style@ = output style (@TVSF_...@)
- * @const struct bench_timing *tm@ = the benchmark result
- *
- * Returns: ---
- *
- * Use: Formats a report about the benchmark performance. This
- * function is intended to be called on by an output @ebench@
- * function.
- */
-
-extern void tvec_benchreport
- (const struct gprintf_ops */*gops*/, void */*go*/,
- unsigned /*unit*/, unsigned /*style*/, const struct bench_timing */*tm*/);
-
-/*----- Remote execution --------------------------------------------------*/
-
-struct tvec_remoteenv;
-
-struct tvec_remotecomms {
- int infd, outfd; /* input and output descriptors */
- dbuf bout; /* output buffer */
- unsigned char *bin; /* input buffer */
- size_t binoff, binlen, binsz; /* input offset, length, and size */
- size_t t; /* temporary offset */
- unsigned f; /* flags */
-#define TVRF_BROKEN 0x0001u /* communications have failed */
-};
-#define TVEC_REMOTECOMMS_INIT { -1, -1, DBUF_INIT, 0, 0, 0, 0, 0, 0 }
-
-struct tvec_remotectx {
- struct tvec_state *tv; /* test vector state */
- struct tvec_remotecomms rc; /* communication state */
- const struct tvec_remoteenv *re; /* environment configuration */
- void *subctx; /* subenvironment context */
- struct tvec_vardef vd; /* temporary variable definition */
- unsigned ver; /* protocol version */
- pid_t kid; /* child process id */
- int errfd; /* child stderr descriptor */
- lbuf errbuf; /* child stderr line buffer */
- dstr prgwant, progress; /* progress: wanted/reported */
- unsigned exwant, exit; /* exit status wanted/reported */
-#define TVRF_RCNMASK 0x0300u /* reconnection behaviour: */
-#define TVRCN_DEMAND 0x0000u /* connect on demand */
-#define TVRCN_SKIP 0x0100u /* skip unless connected */
-#define TVRCN_FORCE 0x0200u /* force reconnection */
-#define TVRF_MUFFLE 0x0400u /* muffle child stderr */
-#define TVRF_SETEXIT 0x0800u /* set `@exit' */
-#define TVRF_SETPRG 0x1000u /* set `@progress' */
-#define TVRF_SETRCN 0x2000u /* set `@reconnect' */
-#define TVRF_SETMASK (TVRF_SETEXIT | TVRF_SETPRG | TVRF_SETRCN)
- /* mask of @TVTF_SET...@ */
-};
-
-typedef int tvec_connectfn(pid_t */*kid_out*/, int */*infd_out*/,
- int */*outfd_out*/, int */*errfd_out*/,
- struct tvec_state */*tv*/,
- const struct tvec_remoteenv */*env*/);
- /* A connection function. On entry, @tv@ holds the test-vector state, and
- * @env@ is the test group's remote environment structure, which will
- * typically really be some subclass of @struct tvec_remoteenv@ containing
- * additional parameters for establishing the child process.
- *
- * On successful completion, the function stores input and output
- * descriptors (which need not be distinct) in @*infd_out@ and
- * @*outfd_out@, and returns zero; if it creates a child process, it should
- * additionally store the child's process-id in @*kid_out@ and store in
- * @*errfd_out@ a descriptor from which the child's error output can be
- * read. On error, the function should report an appropriate message via
- * @tvec_error@ and return %$-1$%.
- */
-
-struct tvec_remoteenv_slots {
- tvec_connectfn *connect; /* connection function */
- const struct tvec_env *env; /* subsidiary environment */
- unsigned dflt_reconn; /* default reconnection */
-};
-
-struct tvec_remoteenv {
- struct tvec_env _env;
- struct tvec_remoteenv_slots r;
-};
-
-struct tvec_remotefork_slots {
- const struct tvec_test *tests; /* child tests (or null) */
-};
-
-struct tvec_remotefork {
- struct tvec_env _env;
- struct tvec_remoteenv_slots r;
- struct tvec_remotefork_slots f;
-};
-
-struct tvec_remoteexec_slots {
- const char *const *args; /* command line to execute */
-};
-
-struct tvec_remoteexec {
- struct tvec_env _env;
- struct tvec_remoteenv_slots r;
- struct tvec_remoteexec_slots x;
-};
-
-union tvec_remoteenv_subclass_kludge {
- struct tvec_env _env;
- struct tvec_remoteenv renv;
- struct tvec_remotefork fork;
- struct tvec_remoteexec exec;
-};
-
-/* Exit status.
- *
- * We don't use the conventional encoding returned by the @wait@(2) family of
- * system calls because it's too hard for our flags type to decode. Instead,
- * we use our own encoding.
- *
- * The exit code or signal number ends up in the `value' field in the low 12
- * bits; bit 12 is set if the value field holds a signal, and it if holds an
- * exit code. Bits 13--15 hold a code which describes the status of a child
- * process or connection.
- */
-#define TVXF_VALMASK 0x0fffu /* value (exit code or signal) */
-#define TVXF_SIG 0x1000u /* value is signal, not exit code */
-#define TVXF_CAUSEMASK 0xe000u /* mask for cause bits */
-#define TVXST_RUN 0x0000u /* still running */
-#define TVXST_EXIT 0x2000u /* child exited */
-#define TVXST_KILL 0x4000u /* child killed by signal */
-#define TVXST_CONT 0x6000u /* child continued (?) */
-#define TVXST_STOP 0x8000u /* child stopped (?) */
-#define TVXST_DISCONN 0xa000u /* disconnected */
-#define TVXST_UNK 0xc000u /* unknown */
-#define TVXST_ERR 0xe000u /* local error prevented diagnosis */
-
-/* Remote environment. */
-extern tvec_envsetupfn tvec_remotesetup;
-extern tvec_envfindvarfn tvec_remotefindvar;
-extern tvec_envbeforefn tvec_remotebefore;
-extern tvec_envrunfn tvec_remoterun;
-extern tvec_envafterfn tvec_remoteafter;
-extern tvec_envteardownfn tvec_remoteteardown;
-#define TVEC_REMOTEENV \
- { sizeof(struct tvec_remotectx), \
- tvec_remotesetup, \
- tvec_remotefindvar, \
- tvec_remotebefore, \
- tvec_remoterun, \
- tvec_remoteafter, \
- tvec_remoteteardown }
-
-/* --- @tvec_setprogress@, @tvec_setprogress_v@ --- *
- *
- * Arguments: @const char *status@ = progress status token format
- * @va_list ap@ = argument tail
- *
- * Returns: ---
- *
- * Use: Reports the progress of a test execution to the client.
- *
- * The framework makes use of tokens beginning with %|%|%:
- *
- * * %|%IDLE|%: during the top-level server code;
- *
- * * %|%SETUP|%: during the enclosing environment's @before@
- * function;
- *
- * * %|%RUN|%: during the environment's @run@ function, or the
- * test function; and
- *
- * * %|%DONE|%: during the enclosing environment's @after@
- * function.
- *
- * The intent is that a test can use the progress token to check
- * that a function which is expected to crash does so at the
- * correct point, so it's expected that more complex test
- * functions and/or environments will set their own progress
- * tokens to reflect what's going on.
- */
-
-extern PRINTF_LIKE(1, 2) int tvec_setprogress(const char */*status*/, ...);
-extern int tvec_setprogress_v(const char */*status*/, va_list */*ap*/);
-
-/* --- @tvec_remoteserver@ --- *
- *
- * Arguments: @int infd@, @int outfd@ = input and output file descriptors
- * @const struct tvec_config *config@ = test configuration
- *
- * Returns: Suggested exit code.
- *
- * Use: Run a test server, reading packets from @infd@ and writing
- * responses and notifications to @outfd@, and invoking tests as
- * described by @config@.
- *
- * This function is not particularly general purpose. It
- * expects to `take over' the process, and makes use of private
- * global variables.
- */
-
-extern int tvec_remoteserver(int /*infd*/, int /*outfd*/,
- const struct tvec_config */*config*/);
-
-extern tvec_connectfn tvec_fork, tvec_exec;
-
-#define TVEC_REMOTEFORK(subenv, tests) \
- TVEC_REMOTEENV, { tvec_fork, subenv }, { tests }
-
-#define TVEC_REMOTEEXEC(subenv, args) \
- TVEC_REMOTEENV, { tvec_exec, subenv }, { args }
-
-/*----- Timeouts ----------------------------------------------------------*/
-
-struct tvec_timeoutenv {
- struct tvec_env _env;
- int timer; /* the timer (@ITIMER_...@) */
- double t; /* time to wait (in seconds) */
- const struct tvec_env *env; /* subsidiary environment */
-};
-
-struct tvec_timeoutctx {
- const struct tvec_timeoutenv *te; /* saved environment description */
- int timer; /* timer code (as overridden) */
- double t; /* time to wait (as overridden) */
- unsigned f; /* flags */
-#define TVTF_SETTMO 1u /* set `@timeout' */
-#define TVTF_SETTMR 2u /* set `@timer' */
-#define TVTF_SETMASK (TVTF_SETTMO | TVTF_SETTMR)
- /* mask of @TVTF_SET...@ */
- void *subctx;
-};
-
-extern tvec_envsetupfn tvec_timeoutsetup;
-extern tvec_envfindvarfn tvec_timeoutfindvar;
-extern tvec_envbeforefn tvec_timeoutbefore;
-extern tvec_envrunfn tvec_timeoutrun;
-extern tvec_envafterfn tvec_timeoutafter;
-extern tvec_envteardownfn tvec_timeoutteardown;
-#define TVEC_TIMEOUTENV \
- { sizeof(struct tvec_timeoutctx), \
- tvec_timeoutsetup, \
- tvec_timeoutfindvar, \
- tvec_timeoutbefore, \
- tvec_timeoutrun, \
- tvec_timeoutafter, \
- tvec_timeoutteardown }
-#define TVEC_TIMEOUTINIT(timer, t) TVEC_TIMEOUTENV, timer, t
-
/*----- Output functions --------------------------------------------------*/
/* --- @tvec_strlevel@ --- *
* @TVLEV_ERR@ or higher force a nonzero exit code.
*/
+#define TVEC_LEVELS(_) \
+ _(INFO, "info", 3) \
+ _(NOTE, "notice", 4) \
+ _(ERR, "ERROR", 8)
+enum {
+#define TVEC_DEFLEVEL(tag, name, val) TVLEV_##tag = val,
+ TVEC_LEVELS(TVEC_DEFLEVEL)
+#undef TVEC_DEFLEVEL
+ TVLEV_LIMIT
+};
+
extern PRINTF_LIKE(3, 4)
void tvec_report(struct tvec_state */*tv*/, unsigned /*level*/,
const char */*msg*/, ...);
extern void tvec_report_v(struct tvec_state */*tv*/, unsigned /*level*/,
const char */*msg*/, va_list */*ap*/);
-/* --- @tvec_error@, @tvec_notice@ --- *
+/* --- @tvec_error@, @tvec_notice@, @tvec_info@ --- *
*
* Arguments: @struct tvec_state *tv@ = test-vector state
* @const char *msg@, @va_list ap@ = error message
* Returns: The @tvec_error@ function returns %$-1$% as a trivial
* convenience; @tvec_notice@ does not return a value.
*
- * Use: Report an error or a notice. Errors are distinct from test
+ * Use: Report a message. Errors are distinct from test
* failures, and indicate that a problem was encountered which
* compromised the activity of testing. Notices are important
* information which doesn't fit into any other obvious
- * category.
+ * category. Information is anything else, and is a reasonable
+ * fallback for writing unstructured information in the absence
+ * of dedicated support in an output driver.
+ *
+ * These functions are simple convenience wrappers around
+ * @tvec_report@. Use @tvec_report_v@ directly if you have a
+ * captured @va_list@ of arguments to format.
*/
extern PRINTF_LIKE(2, 3)
int tvec_error(struct tvec_state */*tv*/, const char */*msg*/, ...);
extern PRINTF_LIKE(2, 3)
void tvec_notice(struct tvec_state */*tv*/, const char */*msg*/, ...);
+extern PRINTF_LIKE(2, 3)
+ void tvec_info(struct tvec_state */*tv*/, const char */*msg*/, ...);
/* --- @tvec_unkregerr@ --- *
*
* writing on @fp@. The policy is subject to change, but
* currently the `human' output format is selected if @fp@ is
* interactive (i.e., if @isatty(fileno(fp))@ is true), and
- * otherwise the `tap' format is used.
+ * otherwise the `machine' format is used.
*/
extern struct tvec_output *tvec_dfltout(FILE */*fp*/);
/* Serialization format.
*
* The `candidate register definitions' are those entries @r@ in the @regs@
- * vector whose index @r.i@ is strictly less than @nr@. The `selected
- * register definitions' are those candidate register definitions @r@ for
- * which the indicated register @rv[r.i]@ has the @TVRF_LIVE@ flag set. The
- * serialized output begins with a header bitmap: if there are %$n$%
- * candidate register definitions then the header bitmap consists of %$\lceil
- * n/8 \rceil$% bytes. Bits are ordered starting from the least significant
- * bit of the first byte, end ending at the most significant bit of the final
- * byte. The bit corresponding to a candidate register definition is set if
- * and only if that register defintion is selected. The header bitmap is
- * then followed by the serializations of the selected registers -- i.e., for
- * each selected register definition @r@, the serialized value of register
- * @rv[r.i]@ -- simply concatenated together, with no padding or alignment.
+ * vector whose index @r.i@ is strictly less than @nr@ and where
+ * @r.f&mask == want@* . The `selected register definitions' are those
+ * candidate register definitions @r@ for which the indicated register
+ * @rv[r.i]@ has the @TVRF_LIVE@ flag set. The serialized output begins with
+ * a header bitmap: if there are %$n$% candidate register definitions then
+ * the header bitmap consists of %$\lceil n/8 \rceil$% bytes. Bits are
+ * ordered starting from the least significant bit of the first byte, end
+ * ending at the most significant bit of the final byte. The bit
+ * corresponding to a candidate register definition is set if and only if
+ * that register defintion is selected. The header bitmap is then followed
+ * by the serializations of the selected registers -- i.e., for each selected
+ * register definition @r@, the serialized value of register @rv[r.i]@ --
+ * simply concatenated together, with no padding or alignment.
*/
/* --- @tvec_serialize@ --- *
* @const struct tvec_regdef *regs@ = vector of register
* descriptions, terminated by an entry with a null
* @name@ slot
+ * @unsigned mask, want@ = flag-based selection
* @unsigned nr@ = number of entries in the @rv@ vector
* @size_t regsz@ = true size of each element of @rv@
*
extern int tvec_serialize(const struct tvec_reg */*rv*/, buf */*b*/,
const struct tvec_regdef */*regs*/,
+ unsigned /*mask*/, unsigned /*want*/,
unsigned /*nr*/, size_t /*regsz*/);
/* --- @tvec_deserialize@ --- *
* @const struct tvec_regdef *regs@ = vector of register
* descriptions, terminated by an entry with a null
* @name@ slot
+ * @unsigned mask, want@ = flag-based selection
* @unsigned nr@ = number of entries in the @rv@ vector
* @size_t regsz@ = true size of each element of @rv@
*
* slot, and set the @TVRF_LIVE@ flag on the register. See
* @tvec_serialize@ for a description of the format.
*
- * Failure results only from a failing register type handler.
+ * Failure results only from an input too small for the initial
+ * bitmap or a failing register type handler.
*/
extern int tvec_deserialize(struct tvec_reg */*rv*/, buf */*b*/,
const struct tvec_regdef */*regs*/,
+ unsigned /*mask*/, unsigned /*want*/,
unsigned /*nr*/, size_t /*regsz*/);
/*----- Input utilities ---------------------------------------------------*/
const char **/*p_inout*/, const char */*delims*/,
const char */*expect*/, va_list */*ap*/);
-/*----- Integer types: signed and unsigned --------------------------------*/
-
-/* Integers may be input in decimal, hex, binary, or octal, following
- * approximately usual conventions.
- *
- * * Signed integers may be preceded with a `+' or `-' sign.
- *
- * * Decimal integers are just a sequence of decimal digits `0' ... `9'.
- *
- * * Octal integers are a sequence of digits `0' ... `7', preceded by `0o'
- * or `0O'.
- *
- * * Hexadecimal integers are a sequence of digits `0' ... `9', `a'
- * ... `f', or `A' ... `F', preceded by `0x' or `0X'.
- *
- * * Radix-B integers are a sequence of digits `0' ... `9', `a' ... `f', or
- * `A' ... `F', each with value less than B, preceded by `Br' or `BR',
- * where 0 < B < 36 is expressed in decimal without any leading `0' or
- * internal underscores `_'.
- *
- * * A digit sequence may contain internal underscore `_' separators, but
- * not before or after all of the digits; and two consecutive `_'
- * characters are not permitted.
- */
-
-extern const struct tvec_regty tvty_int, tvty_uint;
-
-/* The @arg.p@ slot may be null or a pointer to @struct tvec_irange@ or
- * @struct tvec_urange@ as appropriate. The bounds are inclusive; use, e.g.,
- * @LONG_MAX@ explicitly if one or the other bound is logically inapplicable.
- */
-struct tvec_irange { long min, max; };
-struct tvec_urange { unsigned long min, max; };
-
-/* Bounds corresponding to common integer types. */
-extern const struct tvec_irange
- tvrange_schar, tvrange_short, tvrange_int, tvrange_long,
- tvrange_sbyte, tvrange_i16, tvrange_i32;
-extern const struct tvec_urange
- tvrange_uchar, tvrange_ushort, tvrange_uint, tvrange_ulong, tvrange_size,
- tvrange_byte, tvrange_u16, tvrange_u32;
-
-/* --- @tvec_claimeq_int@, @TVEC_CLAIMEQ_INT@ --- *
- *
- * Arguments: @struct tvec_state *tv@ = test-vector state
- * @long i0, i1@ = two signed integers
- * @const char *file@, @unsigned @lno@ = calling file and line
- * @const char *expr@ = the expression to quote on failure
- *
- * Returns: Nonzero if @i0@ and @i1@ are equal, otherwise zero.
- *
- * Use: Check that values of @i0@ and @i1@ are equal. As for
- * @tvec_claim@ above, a test case is automatically begun and
- * ended if none is already underway. If the values are
- * unequal, then @tvec_fail@ is called, quoting @expr@, and the
- * mismatched values are dumped: @i0@ is printed as the output
- * value and @i1@ is printed as the input reference.
- *
- * The @TVEC_CLAIM_INT@ macro is similar, only it (a) identifies
- * the file and line number of the call site automatically, and
- * (b) implicitly quotes the source text of the @i0@ and @i1@
- * arguments in the failure message.
- */
-
-extern int tvec_claimeq_int(struct tvec_state */*tv*/,
- long /*i0*/, long /*i1*/,
- const char */*file*/, unsigned /*lno*/,
- const char */*expr*/);
-#define TVEC_CLAIMEQ_INT(tv, i0, i1) \
- (tvec_claimeq_int(tv, i0, i1, __FILE__, __LINE__, #i0 " /= " #i1))
-
-/* --- @tvec_claimeq_uint@, @TVEC_CLAIMEQ_UINT@ --- *
- *
- * Arguments: @struct tvec_state *tv@ = test-vector state
- * @unsigned long u0, u1@ = two unsigned integers
- * @const char *file@, @unsigned @lno@ = calling file and line
- * @const char *expr@ = the expression to quote on failure
- *
- * Returns: Nonzero if @u0@ and @u1@ are equal, otherwise zero.
- *
- * Use: Check that values of @u0@ and @u1@ are equal. As for
- * @tvec_claim@ above, a test case is automatically begun and
- * ended if none is already underway. If the values are
- * unequal, then @tvec_fail@ is called, quoting @expr@, and the
- * mismatched values are dumped: @u0@ is printed as the output
- * value and @u1@ is printed as the input reference.
- *
- * The @TVEC_CLAIM_UINT@ macro is similar, only it (a)
- * identifies the file and line number of the call site
- * automatically, and (b) implicitly quotes the source text of
- * the @u0@ and @u1@ arguments in the failure message.
- */
-
-extern int tvec_claimeq_uint(struct tvec_state */*tv*/,
- unsigned long /*u0*/, unsigned long /*u1*/,
- const char */*file*/, unsigned /*lno*/,
- const char */*expr*/);
-#define TVEC_CLAIMEQ_UINT(tv, u0, u1) \
- (tvec_claimeq_uint(tv, u0, u1, __FILE__, __LINE__, #u0 " /= " #u1))
-
-/*----- Size type ---------------------------------------------------------*/
-
-/* A size is an unsigned integer followed by an optional unit specifier
- * consisting of an SI unit prefix and (optionally) the letter `B'.
- */
-
-extern const struct tvec_regty tvty_size;
-
-/* --- @tvec_claimeq_size@ --- *
- *
- * Arguments: @struct tvec_state *tv@ = test-vector state
- * @unsigned long sz0, sz1@ = two sizes
- * @const char *file@, @unsigned @lno@ = calling file and line
- * @const char *expr@ = the expression to quote on failure
- *
- * Returns: Nonzero if @sz0@ and @sz1@ are equal, otherwise zero.
- *
- * Use: Check that values of @u0@ and @u1@ are equal. As for
- * @tvec_claim@ above, a test case is automatically begun and
- * ended if none is already underway. If the values are
- * unequal, then @tvec_fail@ is called, quoting @expr@, and the
- * mismatched values are dumped: @u0@ is printed as the output
- * value and @u1@ is printed as the input reference.
- *
- * The @TVEC_CLAIM_SIZE@ macro is similar, only it (a)
- * identifies the file and line number of the call site
- * automatically, and (b) implicitly quotes the source text of
- * the @u0@ and @u1@ arguments in the failure message.
- */
-
-int tvec_claimeq_size(struct tvec_state *tv,
- unsigned long sz0, unsigned long sz1,
- const char *file, unsigned lno, const char *expr);
-#define TVEC_CLAIMEQ_UINT(tv, u0, u1) \
- (tvec_claimeq_uint(tv, u0, u1, __FILE__, __LINE__, #u0 " /= " #u1))
-
-/*----- Floating-point type -----------------------------------------------*/
-
-/* Floating-point values are either NaN (%|#nan|%, if supported by the
- * platform); positive or negative infinity (%|#inf|%, %|+#inf|%, or
- * %|#+inf|% (preferring the last), and %|-#inf|% or %|#-inf|% (preferring
- * the latter), if supported by the platform); or a number in strtod(3)
- * syntax.
- *
- * The comparison rules for floating-point numbers are complex: see
- * @tvec_claimeqish_float@ for details.
- */
-
-extern const struct tvec_regty tvty_float;
-
-struct tvec_floatinfo {
- /* Details about acceptable floating-point values. */
-
- unsigned f; /* flags (@TVFF_...@ bits) */
-#define TVFF_NOMIN 1u /* ignore @min@ (allow -inf) */
-#define TVFF_NOMAX 2u /* ignore @max@ (allow +inf) */
-#define TVFF_NANOK 4u /* permit NaN */
-#define TVFF_EQMASK 0xf0 /* how to compare */
-#define TVFF_EXACT 0x00 /* must equal exactly */
-#define TVFF_ABSDELTA 0x10 /* must be within @delta@ */
-#define TVFF_RELDELTA 0x20 /* diff < @delta@ fraction */
- double min, max; /* smallest/largest value allowed */
- double delta; /* maximum tolerable difference */
-};
-
-extern const struct tvec_floatinfo tvflt_finite, tvflt_nonneg;
-
-/* --- @tvec_claimeqish_float@, @TVEC_CLAIMEQISH_FLOAT@ --- *
- *
- * Arguments: @struct tvec_state *tv@ = test-vector state
- * @double f0, f1@ = two floating-point numbers
- * @unsigned f@ = flags (@TVFF_...@)
- * @double delta@ = maximum tolerable difference
- * @const char *file@, @unsigned @lno@ = calling file and line
- * @const char *expr@ = the expression to quote on failure
- *
- * Returns: Nonzero if @f0@ and @f1@ are sufficiently close, otherwise
- * zero.
- *
- * Use: Check that values of @f0@ and @f1@ are sufficiently close.
- * As for @tvec_claim@ above, a test case is automatically begun
- * and ended if none is already underway. If the values are
- * too far apart, then @tvec_fail@ is called, quoting @expr@,
- * and the mismatched values are dumped: @f0@ is printed as the
- * output value and @f1@ is printed as the input reference.
- *
- * The details for the comparison are as follows.
- *
- * * A NaN value matches any other NaN, and nothing else.
- *
- * * An infinity matches another infinity of the same sign,
- * and nothing else.
- *
- * * If @f&TVFF_EQMASK@ is @TVFF_EXACT@, then any
- * representable number matches only itself: in particular,
- * positive and negative zero are considered distinct.
- * (This allows tests to check that they land on the correct
- * side of branch cuts, for example.)
- *
- * * If @f&TVFF_EQMASK@ is @TVFF_ABSDELTA@, then %$x$% matches
- * %$y$% when %$|x - y| < \delta$%.
- *
- * * If @f&TVFF_EQMASK@ is @TVFF_RELDELTA@, then %$x$% matches
- * %$y$% when %$|1 - x/y| < \delta$%. (Note that this
- * criterion is asymmetric. Write %$x \approx_\delta y$%
- * if and only if %$|1 - x/y < \delta$%. Then, for example,
- * if %$y/(1 + \delta) < x < y (1 - \delta)$%, then
- * %$x \approx_\delta y$%, but %$y \not\approx_\delta x$%.)
- *
- * The @TVEC_CLAIM_FLOAT@ macro is similar, only it (a)
- * identifies the file and line number of the call site
- * automatically, and (b) implicitly quotes the source text of
- * the @f0@ and @f1@ arguments (and @delta@) in the failure
- * message.
- */
-
-extern int tvec_claimeqish_float(struct tvec_state */*tv*/,
- double /*f0*/, double /*f1*/,
- unsigned /*f*/, double /*delta*/,
- const char */*file*/, unsigned /*lno*/,
- const char */*expr*/);
-#define TVEC_CLAIMEQISH_FLOAT(tv, f0, f1, f, delta) \
- (tvec_claimeqish_float(tv, f0, f1, f, delta, __FILE__, __LINE__, \
- #f0 " /= " #f1 " (+/- " #delta ")"))
-
-/* --- @tvec_claimeq_float@, @TVEC_CLAIMEQ_FLOAT@ --- *
- *
- * Arguments: @struct tvec_state *tv@ = test-vector state
- * @double f0, f1@ = two floating-point numbers
- * @const char *file@, @unsigned @lno@ = calling file and line
- * @const char *expr@ = the expression to quote on failure
- *
- * Returns: Nonzero if @f0@ and @u1@ are identical, otherwise zero.
- *
- * Use: Check that values of @f0@ and @f1@ are identical. The
- * function is exactly equivalent to @tvec_claimeqish_float@
- * with @f == TVFF_EXACT@; the macro is similarly like
- * @TVEC_CLAIMEQISH_FLOAT@ with @f == TVFF_EXACT@, except that
- * it doesn't bother to quote a delta.
- */
-
-extern int tvec_claimeq_float(struct tvec_state */*tv*/,
- double /*f0*/, double /*f1*/,
- const char */*file*/, unsigned /*lno*/,
- const char */*expr*/);
-#define TVEC_CLAIMEQ_FLOAT(tv, f0, f1) \
- (tvec_claimeq_float(tv, f0, f1, __FILE__, __LINE__, #f0 " /= " #f1))
-
-/*----- Durations ---------------------------------------------------------*/
-
-/* A duration measures a time interval in seconds. The input format consists
- * of a nonnegative decimal floating-point number in @strtod@ format followed
- * by an optional unit specification.
- */
-
-extern const struct tvec_regty tvty_duration;
-
-/* --- @tvec_parsedurunit@ --- *
- *
- * Arguments: @double *scale_out@ = where to leave the scale
- * @const char **p_inout@ = input unit string, updated
- *
- * Returns: Zero on success, %$-1$% on error.
- *
- * Use: If @*p_inout@ begins with a unit string followed by the end
- * of the string or some non-alphanumeric character, then store
- * the corresponding scale factor in @*scale_out@, advance
- * @*p_inout@ past the unit string, and return zero. Otherwise,
- * return %$-1$%.
- */
-
-extern int tvec_parsedurunit(double */*scale_out*/,
- const char **/*p_inout*/);
-
-/* --- @tvec_claimeqish_duration@, @TVEC_CLAIMEQISH_DURATION@ --- *
- *
- * Arguments: @struct tvec_state *tv@ = test-vector state
- * @double to, t1@ = two durations
- * @unsigned f@ = flags (@TVFF_...@)
- * @double delta@ = maximum tolerable difference
- * @const char *file@, @unsigned @lno@ = calling file and line
- * @const char *expr@ = the expression to quote on failure
- *
- * Returns: Nonzero if @t0@ and @t1@ are sufficiently close, otherwise
- * zero.
- *
- * Use: Check that values of @t0@ and @t1@ are sufficiently close.
- * This is essentially the same as @tvec_claimeqish_float@, only
- * it dumps the values as durations on a mismatch.
- *
- * The @TVEC_CLAIM_FLOAT@ macro is similar, only it (a)
- * identifies the file and line number of the call site
- * automatically, and (b) implicitly quotes the source text of
- * the @t0@ and @t1@ arguments (and @delta@) in the failure
- * message.
- */
-
-extern int tvec_claimeqish_duration(struct tvec_state */*tv*/,
- double /*t0*/, double /*t1*/,
- unsigned /*f*/, double /*delta*/,
- const char */*file*/, unsigned /*lno*/,
- const char */*expr*/);
-#define TVEC_CLAIMEQISH_DURATION(tv, t0, t1, f, delta) \
- (tvec_claimeqish_duration(tv, t0, t1, f, delta, __FILE__, __LINE__, \
- #t0 " /= " #t1 " (+/- " #delta ")"))
-
-/* --- @tvec_claimeq_duration@, @TVEC_CLAIMEQ_DURATION@ --- *
- *
- * Arguments: @struct tvec_state *tv@ = test-vector state
- * @double t0, t1@ = two durations
- * @const char *file@, @unsigned @lno@ = calling file and line
- * @const char *expr@ = the expression to quote on failure
- *
- * Returns: Nonzero if @t0@ and @t1@ are identical, otherwise zero.
- *
- * Use: Check that values of @t0@ and @t1@ are identical. The
- * function is exactly equivalent to @tvec_claimeqish_duration@
- * with @f == TVFF_EXACT@; the macro is similarly like
- * @TVEC_CLAIMEQISH_DURATION@ with @f == TVFF_EXACT@, except
- * that it doesn't bother to quote a delta.
- */
-
-int tvec_claimeq_duration(struct tvec_state */*tv*/,
- double /*t0*/, double /*t1*/,
- const char */*file*/, unsigned /*lno*/,
- const char */*expr*/);
-#define TVEC_CLAIMEQ_DURATION(tv, t0, t1) \
- (tvec_claimeq_float(tv, t0, t1, __FILE__, __LINE__, #t0 " /= " #t1))
-
-/*----- Enumerated types --------------------------------------------------*/
-
-/* An enumeration describes a set of values of some underlying type, each of
- * which has a symbolic name. Values outside of the defined set can occur --
- * on output, because of bugs in the tested code, or on input to test
- * handling of unexpected values.
- *
- * There is a distinct enumerated type for each of the branches of
- * @tvec_misc@. In the following, we write @t@ for the type code, which is
- * @i@ for signed integer, @u@ for unsigned integer, @f@ for floating-point,
- * and @p@ for pointer.
- *
- * On input, an enumerated value may be given by name or as a literal value.
- * For enumerations based on numeric types, the literal values can be written
- * in the same syntax as the underlying values. For enumerations based on
- * pointers, the only permitted literal is %|#nil|%, which denotes a null
- * pointer. On output, names are preferred (with the underlying value given
- * in a comment).
- */
-
-#define DEFENUMTY(tag, ty, slot) \
- extern const struct tvec_regty tvty_##slot##enum;
-TVEC_MISCSLOTS(DEFENUMTY)
-#undef DEFENUMTY
-
-/* A @struct tvec_tassoc@ associates a string tag with a value. */
-#define DEFASSOC(tag_, ty, slot) \
- struct tvec_##slot##assoc { const char *tag; ty slot; };
-TVEC_MISCSLOTS(DEFASSOC)
-#undef DEFASSOC
-
-#define TVEC_ENDENUM { 0, 0 }
-
-/* Information about an enumerated type. */
-#define DEFINFO(tag, ty, slot) \
- struct tvec_##slot##enuminfo { \
- const char *name; /* type name for diagnostics */ \
- const struct tvec_##slot##assoc *av; /* name/value mappings */ \
- EXTRA_##tag##_INFOSLOTS /* type-specific extra info */ \
- };
-
-#define EXTRA_INT_INFOSLOTS \
- const struct tvec_irange *ir; /* allowed range of raw values */
-
-#define EXTRA_UINT_INFOSLOTS \
- const struct tvec_urange *ur; /* allowed range of raw values */
-
-#define EXTRA_FLT_INFOSLOTS \
- const struct tvec_floatinfo *fi; /* range and matching policy */
-
-#define EXTRA_PTR_INFOSLOTS /* (nothing) */
-
-TVEC_MISCSLOTS(DEFINFO)
-
-#undef EXTRA_INT_INFOSLOTS
-#undef EXTRA_UINT_INFOSLOTS
-#undef EXTRA_FLT_INFOSLOTS
-#undef EXTRA_PTR_INFOSLOTS
-
-#undef DEFINFO
-
-/* Standard enumerations. */
-extern const struct tvec_ienuminfo tvenum_bool;
-extern const struct tvec_ienuminfo tvenum_cmp;
-
-/* --- @tvec_claimeq_tenum@, @TVEC_CLAIMEQ_TENUM@ --- *
- *
- * Arguments: @struct tvec_state *tv@ = test-vector state
- * @const struct tvec_typeenuminfo *ei@ = enumeration type info
- * @ty t0, t1@ = two values
- * @const char *file@, @unsigned @lno@ = calling file and line
- * @const char *expr@ = the expression to quote on failure
- *
- * Returns: Nonzero if @t0@ and @t1@ are equal, otherwise zero.
- *
- * Use: Check that values of @t0@ and @t1@ are equal. As for
- * @tvec_claim@ above, a test case is automatically begun and
- * ended if none is already underway. If the values are
- * unequal, then @tvec_fail@ is called, quoting @expr@, and the
- * mismatched values are dumped: @t0@ is printed as the output
- * value and @t1@ is printed as the input reference.
- *
- * The @TVEC_CLAIM_TENUM@ macro is similar, only it (a)
- * identifies the file and line number of the call site
- * automatically, and (b) implicitly quotes the source text of
- * the @t0@ and @t1@ arguments in the failure message.
- */
-
-#define DECLCLAIM(tag, ty, slot) \
- extern int tvec_claimeq_##slot##enum \
- (struct tvec_state */*tv*/, \
- const struct tvec_##slot##enuminfo */*ei*/, \
- ty /*t0*/, ty /*t1*/, \
- const char */*file*/, unsigned /*lno*/, const char */*expr*/);
-TVEC_MISCSLOTS(DECLCLAIM)
-#undef DECLCLAIM
-#define TVEC_CLAIMEQ_IENUM(tv, ei, i0, i1) \
- (tvec_claimeq_ienum(tv, ei, i0, i1, \
- __FILE__, __LINE__, #i0 " /= " #i1))
-#define TVEC_CLAIMEQ_UENUM(tv, ei, u0, u1) \
- (tvec_claimeq_uenum(tv, ei, u0, u1, \
- __FILE__, __LINE__, #u0 " /= " #u1))
-#define TVEC_CLAIMEQ_FENUM(tv, ei, f0, f1) \
- (tvec_claimeq_fenum(tv, ei, f0, f1, \
- __FILE__, __LINE__, #f0 " /= " #f1))
-#define TVEC_CLAIMEQ_PENUM(tv, ei, p0, p1) \
- (tvec_claimeq_penum(tv, ei, p0, p1, \
- __FILE__, __LINE__, #p0 " /= " #p1))
-
-/*----- Flags type --------------------------------------------------------*/
-
-/* A flags value packs a number of fields into a single nonnegative integer.
- * Symbolic names are associated with the possible values of the various
- * fields; more precisely, each name is associated with a value and a
- * covering bitmask.
- *
- * The input syntax is a sequence of items separated by `%|||%' signs. Each
- * item may be the symbolic name of a field value, or a literal unsigned
- * integer. The masks associated with the given symbolic names must be
- * disjoint. The resulting numerical value is simply the bitwise OR of the
- * given values.
- *
- * On output, the table of symbolic names and their associated values and
- * masks is repeatedly scanned, in order, to find disjoint matches -- i.e.,
- * entries whose value matches the target value in the bit positions
- * indicated by the mask, and whose mask doesn't overlap with any previously
- * found matches; the names are then output, separated by `%|||%'. Any
- * remaining nonzero bits not covered by any of the matching masks are output
- * as a single literal integer, in hex.
- */
-
-extern const struct tvec_regty tvty_flags;
-
-struct tvec_flag {
- /* Definition of a single flag or bitfield value.
- *
- * Each named setting comes with a value @v@ and a mask @m@; the mask
- * should cover all of the value bits, i.e., @(v&~m) == 0@.
- */
-
- const char *tag; /* name */
- unsigned long m, v; /* mask and value */
-};
-
-#define TVEC_ENDFLAGS { 0, 0, 0 }
-
-struct tvec_flaginfo {
- /* Information about a flags type. */
-
- const char *name; /* type name for diagnostics */
- const struct tvec_flag *fv; /* name/mask/value mappings */
- const struct tvec_urange *range; /* permitted range for literals */
-};
-
-/* --- @tvec_claimeq_flags@, @TVEC_CLAIMEQ_FLAGS@ --- *
- *
- * Arguments: @struct tvec_state *tv@ = test-vector state
- * @const struct tvec_flaginfo *fi@ = flags type info
- * @unsigned long f0, f1@ = two values
- * @const char *file@, @unsigned @lno@ = calling file and line
- * @const char *expr@ = the expression to quote on failure
- *
- * Returns: Nonzero if @f0@ and @f1@ are equal, otherwise zero.
- *
- * Use: Check that values of @f0@ and @f1@ are equal. As for
- * @tvec_claim@ above, a test case is automatically begun and
- * ended if none is already underway. If the values are
- * unequal, then @tvec_fail@ is called, quoting @expr@, and the
- * mismatched values are dumped: @f0@ is printed as the output
- * value and @f1@ is printed as the input reference.
- *
- * The @TVEC_CLAIM_FLAGS@ macro is similar, only it (a)
- * identifies the file and line number of the call site
- * automatically, and (b) implicitly quotes the source text of
- * the @f0@ and @f1@ arguments in the failure message.
- */
-
-extern int tvec_claimeq_flags(struct tvec_state */*tv*/,
- const struct tvec_flaginfo */*fi*/,
- unsigned long /*f0*/, unsigned long /*f1*/,
- const char */*file*/, unsigned /*lno*/,
- const char */*expr*/);
-#define TVEC_CLAIMEQ_FLAGS(tv, fi, f0, f1) \
- (tvec_claimeq_flags(tv, fi, f0, f1, \
- __FILE__, __LINE__, #f0 " /= " #f1))
-
-/*----- Character type ----------------------------------------------------*/
-
-/* A character value holds a character, as read by @fgetc@. The special
- * @EOF@ value can also be represented.
- *
- * On input, a character value can be given by symbolic name, with a leading
- * `%|#|%'; or a character or `%|\|%'-escape sequence, optionally in single
- * quotes.
- *
- * The following escape sequences and character names are recognized.
- *
- * * `%|#eof|%' is the special end-of-file marker.
- *
- * * `%|#nul|%' is the NUL character, sometimes used to terminate strings.
- *
- * * `%|bell|%', `%|bel|%', `%|ding|%', or `%|\a|%' is the BEL character
- * used to ring the terminal bell (or do some other thing to attract the
- * user's attention).
- *
- * * %|#backspace|%, %|#bs|%, or %|\b|% is the backspace character, used to
- * move the cursor backwords by one cell.
- *
- * * %|#escape|% %|#esc|%, or%|\e|% is the escape character, used to
- * introduce special terminal commands.
- *
- * * %|#formfeed|%, %|#ff|%, or %|\f|% is the formfeed character, used to
- * separate pages of text.
- *
- * * %|#newline|%, %|#linefeed|%, %|#lf|%, %|#nl|%, or %|\n|% is the
- * newline character, used to terminate lines of text or advance the
- * cursor to the next line (perhaps without returning it to the start of
- * the line).
- *
- * * %|#return|%, %|#carriage-return|%, %|#cr|%, or %|\r|% is the
- * carriage-return character, used to return the cursor to the start of
- * the line.
- *
- * * %|#tab|%, %|#horizontal-tab|%, %|#ht|%, or %|\t|% is the tab
- * character, used to advance the cursor to the next tab stop on the
- * current line.
- *
- * * %|#vertical-tab|%, %|#vt|%, %|\v|% is the vertical tab character.
- *
- * * %|#space|%, %|#spc|% is the space character.
- *
- * * %|#delete|%, %|#del|% is the delete character, used to erase the most
- * recent character.
- *
- * * %|\'|% is the single-quote character.
- *
- * * %|\\|% is the backslash character.
- *
- * * %|\"|% is the double-quote character.
- *
- * * %|\NNN|% or %|\{NNN}|% is the character with code NNN in octal. The
- * NNN may be up to three digits long.
- *
- * * %|\xNN|% or %|\x{NN}|% is the character with code NNN in hexadecimal.
- */
-
-extern const struct tvec_regty tvty_char;
-
-/* --- @tvec_claimeq_char@, @TVEC_CLAIMEQ_CHAR@ --- *
- *
- * Arguments: @struct tvec_state *tv@ = test-vector state
- * @int ch0, ch1@ = two character codes
- * @const char *file@, @unsigned @lno@ = calling file and line
- * @const char *expr@ = the expression to quote on failure
- *
- * Returns: Nonzero if @ch0@ and @ch1@ are equal, otherwise zero.
- *
- * Use: Check that values of @ch0@ and @ch1@ are equal. As for
- * @tvec_claim@ above, a test case is automatically begun and
- * ended if none is already underway. If the values are
- * unequal, then @tvec_fail@ is called, quoting @expr@, and the
- * mismatched values are dumped: @ch0@ is printed as the output
- * value and @ch1@ is printed as the input reference.
- *
- * The @TVEC_CLAIM_CHAR@ macro is similar, only it (a)
- * identifies the file and line number of the call site
- * automatically, and (b) implicitly quotes the source text of
- * the @ch0@ and @ch1@ arguments in the failure message.
- */
-
-extern int tvec_claimeq_char(struct tvec_state */*tv*/,
- int /*ch0*/, int /*ch1*/,
- const char */*file*/, unsigned /*lno*/,
- const char */*expr*/);
-#define TVEC_CLAIMEQ_CHAR(tv, c0, c1) \
- (tvec_claimeq_char(tv, c0, c1, __FILE__, __LINE__, #c0 " /= " #c1))
-
-/*----- Text and binary string types --------------------------------------*/
-
-/* A string is a sequence of octets. Text and binary strings differ
- * primarily in presentation: text strings are shown as raw characters where
- * possible; binary strings are shown as hex dumps with an auxiliary text
- * display.
- *
- * The input format for both kinds of strings is basically the same: a
- * `compound string', consisting of
- *
- * * single-quoted strings, which are interpreted entirely literally, but
- * can't contain single quotes or newlines;
- *
- * * double-quoted strings, in which `%|\|%'-escapes are interpreted as for
- * characters;
- *
- * * character names, marked by an initial `%|#|%' sign;
- *
- * * special tokens marked by an initial `%|!|%' sign; or
- *
- * * barewords interpreted according to the current coding scheme.
- *
- * The special tokens are
- *
- * * `%|!bare|%', which causes subsequent sequences of barewords to be
- * treated as plain text;
- *
- * * `%|!hex|%', `%|!base32|%', `%|!base64|%', which cause subsequent
- * barewords to be decoded in the requested manner.
- *
- * * `%|!repeat|% %$n$% %|{|% %%\textit{string}%% %|}|%', which includes
- * %$n$% copies of the (compound) string.
- *
- * The only difference between text and binary strings is that the initial
- * coding scheme is %|bare|% for text strings and %|hex|% for binary strings.
- *
- * Either kind of string can contain internal nul characters. A trailing nul
- * is appended -- beyond the stated input length -- to input strings as a
- * convenience to test functions. Test functions may include such a nul
- * character on output but this is not checked by the equality test.
- *
- * A @struct tvec_urange@ may be supplied as an argument: the length of the
- * string (in bytes) will be checked against the permitted range.
- */
-
-extern const struct tvec_regty tvty_text, tvty_bytes;
-
-/* --- @tvec_alloctext@, @tvec_allocbytes@ --- *
- *
- * Arguments: @union tvec_regval *rv@ = register value
- * @size_t sz@ = required size
- *
- * Returns: ---
- *
- * Use: Allocated space in a text or binary string register. If the
- * current register size is sufficient, its buffer is left
- * alone; otherwise, the old buffer, if any, is freed and a
- * fresh buffer allocated. These functions are not intended to
- * be used to adjust a buffer repeatedly, e.g., while building
- * output incrementally: (a) they will perform badly, and (b)
- * the old buffer contents are simply discarded if reallocation
- * is necessary. Instead, use a @dbuf@ or @dstr@.
- *
- * The @tvec_alloctext@ function sneakily allocates an extra
- * byte for a terminating zero. The @tvec_allocbytes@ function
- * doesn't do this.
- */
-
-extern void tvec_alloctext(union tvec_regval */*rv*/, size_t /*sz*/);
-extern void tvec_allocbytes(union tvec_regval */*rv*/, size_t /*sz*/);
-
-/* --- @tvec_claimeq_text@, @TVEC_CLAIMEQ_TEXT@ --- *
- *
- * Arguments: @struct tvec_state *tv@ = test-vector state
- * @const char *p0@, @size_t sz0@ = first string with length
- * @const char *p1@, @size_t sz1@ = second string with length
- * @const char *file@, @unsigned @lno@ = calling file and line
- * @const char *expr@ = the expression to quote on failure
- *
- * Returns: Nonzero if the strings at @p0@ and @p1@ are equal, otherwise
- * zero.
- *
- * Use: Check that strings at @p0@ and @p1@ are equal. As for
- * @tvec_claim@ above, a test case is automatically begun and
- * ended if none is already underway. If the values are
- * unequal, then @tvec_fail@ is called, quoting @expr@, and the
- * mismatched values are dumped: @p0@ is printed as the output
- * value and @p1@ is printed as the input reference.
- *
- * The @TVEC_CLAIM_TEXT@ macro is similar, only it (a)
- * identifies the file and line number of the call site
- * automatically, and (b) implicitly quotes the source text of
- * the @ch0@ and @ch1@ arguments in the failure message.
- */
-
-extern int tvec_claimeq_text(struct tvec_state */*tv*/,
- const char */*p0*/, size_t /*sz0*/,
- const char */*p1*/, size_t /*sz1*/,
- const char */*file*/, unsigned /*lno*/,
- const char */*expr*/);
-#define TVEC_CLAIMEQ_TEXT(tv, p0, sz0, p1, sz1) \
- (tvec_claimeq_text(tv, p0, sz0, p1, sz1, __FILE__, __LINE__, \
- #p0 "[" #sz0 "] /= " #p1 "[" #sz1 "]"))
-
-/* --- @tvec_claimeq_textz@, @TVEC_CLAIMEQ_TEXTZ@ --- *
- *
- * Arguments: @struct tvec_state *tv@ = test-vector state
- * @const char *p0, *p1@ = two strings to compare
- * @const char *file@, @unsigned @lno@ = calling file and line
- * @const char *expr@ = the expression to quote on failure
- *
- * Returns: Nonzero if the strings at @p0@ and @p1@ are equal, otherwise
- * zero.
- *
- * Use: Check that strings at @p0@ and @p1@ are equal, as for
- * @tvec_claimeq_string@, except that the strings are assumed
- * null-terminated, so their lengths don't need to be supplied
- * explicitly. The macro is similarly like @TVEC_CLAIMEQ_TEXT@.
- */
-
-extern int tvec_claimeq_textz(struct tvec_state */*tv*/,
- const char */*p0*/, const char */*p1*/,
- const char */*file*/, unsigned /*lno*/,
- const char */*expr*/);
-#define TVEC_CLAIMEQ_TEXTZ(tv, p0, p1) \
- (tvec_claimeq_textz(tv, p0, p1, __FILE__, __LINE__, #p0 " /= " #p1))
-
-/* --- @tvec_claimeq_bytes@, @TVEC_CLAIMEQ_BYTES@ --- *
- *
- * Arguments: @struct tvec_state *tv@ = test-vector state
- * @const void *p0@, @size_t sz0@ = first string with length
- * @const void *p1@, @size_t sz1@ = second string with length
- * @const char *file@, @unsigned @lno@ = calling file and line
- * @const char *expr@ = the expression to quote on failure
- *
- * Returns: Nonzero if the strings at @p0@ and @p1@ are equal, otherwise
- * zero.
- *
- * Use: Check that binary strings at @p0@ and @p1@ are equal. As for
- * @tvec_claim@ above, a test case is automatically begun and
- * ended if none is already underway. If the values are
- * unequal, then @tvec_fail@ is called, quoting @expr@, and the
- * mismatched values are dumped: @p0@ is printed as the output
- * value and @p1@ is printed as the input reference.
- *
- * The @TVEC_CLAIM_STRING@ macro is similar, only it (a)
- * identifies the file and line number of the call site
- * automatically, and (b) implicitly quotes the source text of
- * the @ch0@ and @ch1@ arguments in the failure message.
- */
-
-extern int tvec_claimeq_bytes(struct tvec_state */*tv*/,
- const void */*p0*/, size_t /*sz0*/,
- const void */*p1*/, size_t /*sz1*/,
- const char */*file*/, unsigned /*lno*/,
- const char */*expr*/);
-#define TVEC_CLAIMEQ_BYTES(tv, p0, sz0, p1, sz1) \
- (tvec_claimeq(tv, p0, sz0, p1, sz1, __FILE__, __LINE__, \
- #p0 "[" #sz0 "] /= " #p1 "[" #sz1 "]"))
-
-/*----- Buffer type -------------------------------------------------------*/
-
-/* Buffer registers are primarily used for benchmarking. Only a buffer's
- * allocation parameters are significant: its contents are ignored on
- * comparison and output, and unspecified on input.
- *
- * The input format gives the buffer's size, and an optional alignment
- * specification, in the form %|SZ [`@' M [`+' A]]|%. Each of %|SZ|%, %|M|%
- * and %|A|% are sizes, as an integer, optionally suffixed with a unit `kB',
- * `MB', `GB', `TB', `PB', `EB', `ZB', `YB' (with or without the `B')
- * denoting a power of 1024. The %|SZ|% gives the (effective) buffer size.
- * %|M|% is the `alignment quantum' and %|A|% is the `alignment offset'; both
- * default to zero, but if %|M|% is nonzero then the start of the buffer is
- * aligned such that it is %|A|% more than a multiple of %|M|% bytes. Note
- * that %|M|% need not be a power of two, though this is common.
- *
- * Units other than `B' are used on output only when the size would be
- * expressed exactly.
- *
- * Buffers are %%\emph{not}%% allocated by default. In benchmarks, this is
- * best done in a @before@ function.
- *
- * No @claimeq@ functions or macros are provided for buffers because they
- * don't seem very useful.
- */
-
-extern const struct tvec_regty tvty_buffer;
-
-/* --- @tvec_initbuffer@ --- *
- *
- * Arguments: @union tvec_regval *rv@ = register value
- * @const union tvec_regval *ref@ = reference buffer
- * @size_t sz@ = size to allocate
- *
- * Returns: ---
- *
- * Use: Initialize the alignment parameters in @rv@ to match @ref@,
- * and the size to @sz@.
- */
-
-extern void tvec_initbuffer(union tvec_regval */*rv*/,
- const union tvec_regval */*ref*/, size_t /*sz*/);
-
-/* --- @tvec_allocbuffer@ --- *
- *
- * Arguments: @union tvec_regval *rv@ = register value
- *
- * Returns: ---
- *
- * Use: Allocate @sz@ bytes to the buffer and fill the space with a
- * distinctive pattern.
- */
-
-extern void tvec_allocbuffer(union tvec_regval */*rv*/);
-
/*----- That's all, folks -------------------------------------------------*/
#ifdef __cplusplus