@@@ more mess
[mLib] / test / tvec.h
index 2f1cc56..740b6be 100644 (file)
@@ -543,132 +543,189 @@ extern void tvec_check_v(struct tvec_state */*tv*/,
 
 /*----- Session lifecycle -------------------------------------------------*/
 
-struct tvec_info {
-  const struct tvec_test *tests;
-  unsigned nrout, nreg;
-  size_t regsz;
-};
-
-extern void tvec_begin(struct tvec_state */*tv_out*/,
-                      const struct tvec_info */*info*/,
-                      struct tvec_output */*o*/);
-extern int tvec_end(struct tvec_state */*tv*/);
-
-extern int tvec_read(struct tvec_state */*tv*/,
-                    const char */*infile*/, FILE */*fp*/);
-
-/*----- Benchmarking ------------------------------------------------------*/
-
-struct tvec_bench {
-  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;          /* environment (per test, not grp) */
-};
-#define TVEC_BENCHENV                                                  \
-  { sizeof(struct tvec_benchctx),                                      \
-    tvec_benchsetup,                                                   \
-    tvec_benchset,                                                     \
-    tvec_benchbefore,                                                  \
-    tvec_benchrun,                                                     \
-    tvec_benchafter,                                                   \
-    tvec_benchteardown }
-#define TVEC_BENCHINIT TVEC_BENCHENV, &tvec_benchstate
+struct tvec_config {
+  /* An overall test configuration. */
 
-struct tvec_benchctx {
-  const struct tvec_bench *b;
-  struct bench_state *bst;
-  double dflt_target;
-  void *subctx;
+  const struct tvec_test *tests;       /* the tests to be performed */
+  unsigned nrout, nreg;                        /* number of output/total regs */
+  size_t regsz;                                /* size of a register */
 };
 
-struct bench_timing;
-extern struct bench_state *tvec_benchstate;
-
-extern int tvec_benchsetup(struct tvec_state */*tv*/,
-                          const struct tvec_env */*env*/,
-                          void */*pctx*/, void */*ctx*/);
-extern int tvec_benchset(struct tvec_state */*tv*/, const char */*var*/,
-                        const struct tvec_env */*env*/, void */*ctx*/);
-extern int tvec_benchbefore(struct tvec_state */*tv*/, void */*ctx*/);
-extern void tvec_benchrun(struct tvec_state */*tv*/,
-                         tvec_testfn */*fn*/, void */*ctx*/);
-extern void tvec_benchafter(struct tvec_state */*tv*/, void */*ctx*/);
-extern void tvec_benchteardown(struct tvec_state */*tv*/, void */*ctx*/);
-
-extern void tvec_benchreport
-  (const struct gprintf_ops */*gops*/, void */*go*/,
-   unsigned /*unit*/, const struct bench_timing */*tm*/);
+/* --- @tvec_begin@ --- *
+ *
+ * Arguments:  @struct tvec_state *tv_out@ = state structure to fill in
+ *             @const struct tvec_config *config@ = test configuration
+ *             @struct tvec_output *o@ = output driver
+ *
+ * Returns:    ---
+ *
+ * Use:                Initialize a state structure ready to do some testing.
+ */
 
-/*----- Ad-hoc testing ----------------------------------------------------*/
+extern void tvec_begin(struct tvec_state */*tv_out*/,
+                      const struct tvec_config */*config*/,
+                      struct tvec_output */*o*/);
 
-extern void tvec_adhoc(struct tvec_state */*tv*/, struct tvec_test */*t*/);
+/* --- @tvec_end@ --- *
+ *
+ * Arguments:  @struct tvec_state *tv@ = test-vector state
+ *
+ * Returns:    A proposed exit code.
+ *
+ * Use:                Conclude testing and suggests an exit code to be returned to
+ *             the calling program.  (The exit code comes from the output
+ *             driver's @esession@ method.)
+ */
 
-extern void tvec_begingroup(struct tvec_state */*tv*/, const char */*name*/,
-                           const char */*file*/, unsigned /*lno*/);
-extern void tvec_reportgroup(struct tvec_state */*tv*/);
-extern void tvec_endgroup(struct tvec_state */*tv*/);
+extern int tvec_end(struct tvec_state */*tv*/);
 
-#define TVEC_BEGINGROUP(tv, name)                                      \
-       do tvec_begingroup(tv, name, __FILE__, __LINE__); while (0)
+/* --- @tvec_read@ --- *
+ *
+ * Arguments:  @struct tvec_state *tv@ = test-vector state
+ *             @const char *infile@ = the name of the input file
+ *             @FILE *fp@ = stream to read from
+ *
+ * Returns:    Zero on success, @-1@ on error.
+ *
+ * Use:                Read test vector data from @fp@ and exercise test functions.
+ *             THe return code doesn't indicate test failures: it's only
+ *             concerned with whether there were problems with the input
+ *             file or with actually running the tests.
+ */
 
-#define TVEC_TESTGROUP(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); })
+extern int tvec_read(struct tvec_state */*tv*/,
+                    const char */*infile*/, FILE */*fp*/);
 
-extern void tvec_begintest(struct tvec_state */*tv*/,
-                          const char */*file*/, unsigned /*lno*/);
-extern void tvec_endtest(struct tvec_state */*tv*/);
+/*----- Input utilities ---------------------------------------------------*/
 
-#define TVEC_BEGINTEST(tv)                                             \
-       do tvec_begintest(tv, __FILE__, __LINE__); while (0)
+/* These are provided by the core for the benefit of type @parse@ methods,
+ * and test-environment @set@ functions, which get to read from the test
+ * input file.  The latter are usually best implemented by calling on the
+ * former.
+ *
+ * The two main rules are as follows.
+ *
+ *   * Leave the file position at the beginning of the line following
+ *     whatever it was that you read.
+ *
+ *   * When you read and consume a newline (which you do at least once, by
+ *     the previous rule), then increment @tv->lno@ to keep track of the
+ *     current line number.
+ */
 
-#define TVEC_TEST(tag, tv)                                             \
-       MC_WRAP(tag##__around,                                          \
-         { TVEC_BEGINTEST(tv); },                                      \
-         { tvec_endtest(tv); },                                        \
-         { if ((tv)->f&TVSF_ACTIVE) tvec_skipgroup((tv), 0);           \
-           tvec_endtest(tv); })
+/* --- @tvec_skipspc@ --- *
+ *
+ * Arguments:  @struct tvec_state *tv@ = test-vector state
+ *
+ * Returns:    ---
+ *
+ * Use:                Advance over any whitespace characters other than newlines.
+ *             This will stop at `;', end-of-file, or any other kind of
+ *             non-whitespace; and it won't consume a newline.
+ */
 
-extern int PRINTF_LIKE(5, 6)
-  tvec_claim(struct tvec_state */*tv*/, int /*ok*/,
-            const char */*file*/, unsigned /*lno*/,
-            const char */*expr*/, ...);
+extern void tvec_skipspc(struct tvec_state */*tv*/);
 
-#define TVEC_CLAIM(tv, cond)                                           \
-       (tvec_claim(tv, !!(cond), __FILE__, __LINE__, #cond " untrue"))
+/* --- @tvec_syntax@, @tvec_syntax_v@ --- *
+ *
+ * Arguments:  @struct tvec_state *tv@ = test-vector state
+ *             @int ch@ = the character found (in @fgetc@ format)
+ *             @const char *expect@, @va_list ap@ = what was expected
+ *
+ * Returns:    @-1@
+ *
+ * Use:                Report a syntax error quoting @ch@ and @expect@.  If @ch@ is
+ *             a newline, then back up so that it can be read again (e.g.,
+ *             by @tvec_flushtoeol@ or @tvec_nexttoken@, which will also
+ *             advance the line number).
+ */
 
-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*/);
+extern int PRINTF_LIKE(3, 4)
+  tvec_syntax(struct tvec_state */*tv*/, int /*ch*/,
+             const char */*expect*/, ...);
+extern int tvec_syntax_v(struct tvec_state */*tv*/, int /*ch*/,
+                        const char */*expect*/, va_list */*ap*/);
 
-/*----- Command-line interface --------------------------------------------*/
+/* --- @tvec_flushtoeol@ --- *
+ *
+ * Arguments:  @struct tvec_state *tv@ = test-vector state
+ *             @unsigned f@ = flags (@TVFF_...@)
+ *
+ * Returns:    Zero on success, @-1@ on error.
+ *
+ * Use:                Advance to the start of the next line, consuming the
+ *             preceding newline.
+ *
+ *             A syntax error is reported if no newline character is found,
+ *             i.e., the file ends in mid-line.  A syntax error is also
+ *             reported if material other than whitespace or a comment is
+ *             found before the end of the line end, and @TVFF_ALLOWANY@ is
+ *             not set in @f@.  The line number count is updated
+ *             appropriately.
+ */
 
-extern const struct tvec_info tvec_adhocinfo;
+#define TVFF_ALLOWANY 1u
+extern int tvec_flushtoeol(struct tvec_state */*tv*/, unsigned /*f*/);
 
-extern void tvec_parseargs(int /*argc*/, char */*argv*/[],
-                          struct tvec_state */*tv_out*/,
-                          int */*argpos_out*/,
-                          const struct tvec_info */*info*/);
+/* --- @tvec_nexttoken@ --- *
+ *
+ * Arguments:  @struct tvec_state *tv@ = test-vector state
+ *
+ * Returns:    Zero if there is a next token which can be read; @-1@ if no
+ *             token is available.
+ *
+ * Use:                Advance to the next whitespace-separated token, which may be
+ *             on the next line.
+ *
+ *             Tokens are separated by non-newline whitespace, comments, and
+ *             newlines followed by whitespace; a newline /not/ followed by
+ *             whitespace instead begins the next assignment, and two
+ *             newlines separated only by whitespace terminate the data for
+ *             a test.
+ *
+ *             If this function returns zero, then the next character in the
+ *             file begins a suitable token which can be read and
+ *             processed.  If it returns @-1@ then there is no such token,
+ *             and the file position is left correctly.  The line number
+ *             count is updated appropriately.
+ */
 
-extern int tvec_readstdin(struct tvec_state */*tv*/);
-extern int tvec_readfile(struct tvec_state */*tv*/, const char */*file*/);
-extern int tvec_readdflt(struct tvec_state */*tv*/, const char */*file*/);
-extern int tvec_readarg(struct tvec_state */*tv*/, const char */*arg*/);
+extern int tvec_nexttoken(struct tvec_state */*tv*/);
 
-extern int tvec_readargs(int /*argc*/, char */*argv*/[],
-                        struct tvec_state */*tv*/,
-                        int */*argpos_inout*/, const char */*dflt*/);
+/* --- @tvec_readword@ --- *
+ *
+ * Arguments:  @struct tvec_state *tv@ = test-vector state
+ *             @dstr *d@ = string to append the word to
+ *             @const char *delims@ = additional delimiters to stop at
+ *             @const char *expect@, @va_list ap@ = what was expected
+ *
+ * Returns:    Zero on success, @-1@ on failure.
+ *
+ * Use:                A `word' consists of characters other than whitespace, null
+ *             characters, and other than those listed in @delims@;
+ *             furthermore, a word does not begin with a `;'.  (If you want
+ *             reading to stop at comments not preceded by whitespace, then
+ *             include `;' in @delims@.  This is a common behaviour.)
+ *
+ *             If there is no word beginning at the current file position,
+ *             then return @-1@; furthermore, if @expect@ is not null, then
+ *             report an appropriate error via @tvec_syntax@.
+ *
+ *             Otherwise, the word is accumulated in @d@ and zero is
+ *             returned; if @d@ was not empty at the start of the call, the
+ *             newly read word is separated from the existing material by a
+ *             single space character.  Since null bytes are never valid
+ *             word constituents, a null terminator is written to @d@, and
+ *             it is safe to treat the string in @d@ as being null-
+ *             terminated.
+ */
 
-extern int tvec_main(int /*argc*/, char */*argv*/[],
-                    const struct tvec_info */*info*/,
-                    const char */*dflt*/);
+extern int PRINTF_LIKE(4, 5)
+  tvec_readword(struct tvec_state */*tv*/, dstr */*d*/,
+               const char */*delims*/, const char */*expect*/, ...);
+extern int tvec_readword_v(struct tvec_state */*tv*/, dstr */*d*/,
+                          const char */*delims*/, const char */*expect*/,
+                          va_list */*ap*/);
 
 /*----- Output formatting -------------------------------------------------*/
 
@@ -679,6 +736,8 @@ struct tvec_output {
 
 enum { TVBU_OP, TVBU_BYTE };
 
+struct bench_timing;
+
 struct tvec_outops {
   void (*error)(struct tvec_output */*o*/,
                const char */*msg*/, va_list */*ap*/);
@@ -722,32 +781,10 @@ extern void PRINTF_LIKE(2, 3)
 extern void tvec_notice_v(struct tvec_state */*tv*/,
                          const char */*msg*/, va_list */*ap*/);
 
-extern int PRINTF_LIKE(3, 4)
-  tvec_syntax(struct tvec_state */*tv*/, int /*ch*/,
-             const char */*expect*/, ...);
-extern int tvec_syntax_v(struct tvec_state */*tv*/, int /*ch*/,
-                        const char */*expect*/, va_list */*ap*/);
-
 extern struct tvec_output *tvec_humanoutput(FILE */*fp*/);
 extern struct tvec_output *tvec_tapoutput(FILE */*fp*/);
 extern struct tvec_output *tvec_dfltout(FILE */*fp*/);
 
-/*----- Input utilities ---------------------------------------------------*/
-
-extern void tvec_skipspc(struct tvec_state */*tv*/);
-
-#define TVFF_ALLOWANY 1u
-extern int tvec_flushtoeol(struct tvec_state */*tv*/, unsigned /*f*/);
-
-extern int PRINTF_LIKE(4, 5)
-  tvec_readword(struct tvec_state */*tv*/, dstr */*d*/,
-               const char */*delims*/, const char */*expect*/, ...);
-extern int tvec_readword_v(struct tvec_state */*tv*/, dstr */*d*/,
-                          const char */*delims*/, const char */*expect*/,
-                          va_list */*ap*/);
-
-extern int tvec_nexttoken(struct tvec_state */*tv*/);
-
 /*----- Register types ----------------------------------------------------*/
 
 struct tvec_regty {
@@ -931,6 +968,118 @@ extern const struct tvec_regty tvty_buffer;
 extern void tvec_allocstring(union tvec_regval */*rv*/, size_t /*sz*/);
 extern void tvec_allocbytes(union tvec_regval */*rv*/, size_t /*sz*/);
 
+/*----- Ad-hoc testing ----------------------------------------------------*/
+
+extern void tvec_adhoc(struct tvec_state */*tv*/, struct tvec_test */*t*/);
+
+extern void tvec_begingroup(struct tvec_state */*tv*/, const char */*name*/,
+                           const char */*file*/, unsigned /*lno*/);
+extern void tvec_reportgroup(struct tvec_state */*tv*/);
+extern void tvec_endgroup(struct tvec_state */*tv*/);
+
+#define TVEC_BEGINGROUP(tv, name)                                      \
+       do tvec_begingroup(tv, name, __FILE__, __LINE__); while (0)
+
+#define TVEC_TESTGROUP(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); })
+
+extern void tvec_begintest(struct tvec_state */*tv*/,
+                          const char */*file*/, unsigned /*lno*/);
+extern void tvec_endtest(struct tvec_state */*tv*/);
+
+#define TVEC_BEGINTEST(tv)                                             \
+       do tvec_begintest(tv, __FILE__, __LINE__); while (0)
+
+#define TVEC_TEST(tag, tv)                                             \
+       MC_WRAP(tag##__around,                                          \
+         { TVEC_BEGINTEST(tv); },                                      \
+         { tvec_endtest(tv); },                                        \
+         { if ((tv)->f&TVSF_ACTIVE) tvec_skipgroup((tv), 0);           \
+           tvec_endtest(tv); })
+
+extern int PRINTF_LIKE(5, 6)
+  tvec_claim(struct tvec_state */*tv*/, int /*ok*/,
+            const char */*file*/, unsigned /*lno*/,
+            const char */*expr*/, ...);
+
+#define TVEC_CLAIM(tv, cond)                                           \
+       (tvec_claim(tv, !!(cond), __FILE__, __LINE__, #cond " untrue"))
+
+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_bench {
+  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;          /* environment (per test, not grp) */
+};
+#define TVEC_BENCHENV                                                  \
+  { sizeof(struct tvec_benchctx),                                      \
+    tvec_benchsetup,                                                   \
+    tvec_benchset,                                                     \
+    tvec_benchbefore,                                                  \
+    tvec_benchrun,                                                     \
+    tvec_benchafter,                                                   \
+    tvec_benchteardown }
+#define TVEC_BENCHINIT TVEC_BENCHENV, &tvec_benchstate
+
+struct tvec_benchctx {
+  const struct tvec_bench *b;
+  struct bench_state *bst;
+  double dflt_target;
+  void *subctx;
+};
+
+extern struct bench_state *tvec_benchstate;
+
+extern int tvec_benchsetup(struct tvec_state */*tv*/,
+                          const struct tvec_env */*env*/,
+                          void */*pctx*/, void */*ctx*/);
+extern int tvec_benchset(struct tvec_state */*tv*/, const char */*var*/,
+                        const struct tvec_env */*env*/, void */*ctx*/);
+extern int tvec_benchbefore(struct tvec_state */*tv*/, void */*ctx*/);
+extern void tvec_benchrun(struct tvec_state */*tv*/,
+                         tvec_testfn */*fn*/, void */*ctx*/);
+extern void tvec_benchafter(struct tvec_state */*tv*/, void */*ctx*/);
+extern void tvec_benchteardown(struct tvec_state */*tv*/, void */*ctx*/);
+
+extern void tvec_benchreport
+  (const struct gprintf_ops */*gops*/, void */*go*/,
+   unsigned /*unit*/, const struct bench_timing */*tm*/);
+
+/*----- Command-line interface --------------------------------------------*/
+
+extern const struct tvec_config tvec_adhocconfig;
+
+extern void tvec_parseargs(int /*argc*/, char */*argv*/[],
+                          struct tvec_state */*tv_out*/,
+                          int */*argpos_out*/,
+                          const struct tvec_config */*config*/);
+
+extern int tvec_readstdin(struct tvec_state */*tv*/);
+extern int tvec_readfile(struct tvec_state */*tv*/, const char */*file*/);
+extern int tvec_readdflt(struct tvec_state */*tv*/, const char */*file*/);
+extern int tvec_readarg(struct tvec_state */*tv*/, const char */*arg*/);
+
+extern int tvec_readargs(int /*argc*/, char */*argv*/[],
+                        struct tvec_state */*tv*/,
+                        int */*argpos_inout*/, const char */*dflt*/);
+
+extern int tvec_main(int /*argc*/, char */*argv*/[],
+                    const struct tvec_config */*config*/,
+                    const char */*dflt*/);
+
 /*----- That's all, folks -------------------------------------------------*/
 
 #ifdef __cplusplus