chiark / gitweb /
struct/buf.3.in: Correct the type of `buf_put' in the synopsis.
[mLib] / test / tvec-adhoc.h
1 /* -*-c-*-
2  *
3  * Test-vector framework ad-hoc testing interface
4  *
5  * (c) 2024 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_ADHOC_H
29 #define MLIB_TVEC_ADHOC_H
30
31 #ifdef __cplusplus
32   extern "C" {
33 #endif
34
35 /*----- Header files ------------------------------------------------------*/
36
37 #include <stdarg.h>
38
39 #ifndef MLIB_TVEC_H
40 #  include "tvec.h"
41 #endif
42
43 /*----- Data structures ---------------------------------------------------*/
44
45 struct tvec_withtest {
46   /* State for @tvec_withtest_setup@ and @tvec_withtest_teardown@. */
47
48   unsigned f;                           /* flags */
49 #define ACF_FRESH 1u                    /*   started a new test */
50   const char *saved_file; unsigned saved_lno; /* saved location from state */
51 };
52
53 extern const struct tvec_config tvec_adhocconfig;
54   /* A special @struct tvec_config@ to use for programs which perform ad-hoc
55    * testing.
56    */
57
58 /*----- Functions provided ------------------------------------------------*/
59
60 /* --- @tvec_begingroup@, @TVEC_BEGINGROUP@ --- *
61  *
62  * Arguments:   @struct tvec_state *tv@ = test-vector state
63  *              @const char *name@ = name for this test group
64  *              @const char *file@, @unsigned @lno@ = calling file and line
65  *
66  * Returns:     ---
67  *
68  * Use:         Begin an ad-hoc test group with the given name.  The @file@
69  *              and @lno@ can be anything, but it's usually best if they
70  *              refer to the source code performing the test: the macro
71  *              @TVEC_BEGINGROUP@ does this automatically.
72  */
73
74 extern void tvec_begingroup(struct tvec_state */*tv*/, const char */*name*/,
75                             const char */*file*/, unsigned /*lno*/);
76 #define TVEC_BEGINGROUP(tv, name)                                       \
77         do tvec_begingroup(tv, name, __FILE__, __LINE__); while (0)
78
79 /* --- @tvec_endgroup@ --- *
80  *
81  * Arguments:   @struct tvec_state *tv@ = test-vector state
82  *
83  * Returns:     ---
84  *
85  * Use:         End an ad-hoc test group.  The statistics are updated and the
86  *              outcome is reported to the output formatter.
87  */
88
89 extern void tvec_endgroup(struct tvec_state */*tv*/);
90
91 /* --- @TVEC_TESTGROUP@, @TVEC_TESTGROUP_TAG@ --- *
92  *
93  * Arguments:   @tag@ = label-disambiguation tag
94  *              @const struct tvec_state *tv = test-vector state
95  *              @const char *name@ = test-group name
96  *
97  * Returns:     ---
98  *
99  * Use:         Control-structure macro: @TVEC_TESTGROUP(tv, name) stmt@
100  *              establishes a test group with the given @name@ (attributing
101  *              it to the source file and lie number), executes @stmt@, and
102  *              ends the test group.  If @stmt@ invokes @break@ then the test
103  *              group is skipped.  @TVEC_TESTGROUP_TAG@ is the same, with an
104  *              additional @tag@ argument for use in higher-level macros.
105  */
106
107 #define TVEC_TESTGROUP_TAG(tag, tv, name)                               \
108         MC_WRAP(tag##__around,                                          \
109           { TVEC_BEGINGROUP(tv, name); },                               \
110           { tvec_endgroup(tv); },                                       \
111           { if (!((tv)->f&TVSF_SKIP)) tvec_skipgroup(tv, 0);            \
112             tvec_endgroup(tv); })
113 #define TVEC_TESTGROUP(tv, name) TVEC_TESTGROUP_TAG(grp, tv, name)
114
115 /* --- @tvec_begintest@, @TVEC_BEGINTEST@ --- *
116  *
117  * Arguments:   @struct tvec_state *tv@ = test-vector state
118  *              @const char *file@, @unsigned @lno@ = calling file and line
119  *
120  * Returns:     ---
121  *
122  * Use:         Begin an ad-hoc test case.  The @file@ and @lno@ can be
123  *              anything, but it's usually best if they refer to the source
124  *              code performing the test: the macro @TVEC_BEGINGROUP@ does
125  *              this automatically.
126  */
127
128 extern void tvec_begintest(struct tvec_state */*tv*/,
129                            const char */*file*/, unsigned /*lno*/);
130 #define TVEC_BEGINTEST(tv)                                              \
131         do tvec_begintest(tv, __FILE__, __LINE__); while (0)
132
133 /* --- @tvec_endtest@ --- *
134  *
135  * Arguments:   @struct tvec_state *tv@ = test-vector state
136  *
137  * Returns:     ---
138  *
139  * Use:         End an ad-hoc test case,  The statistics are updated and the
140  *              outcome is reported to the output formatter.
141  */
142
143 extern void tvec_endtest(struct tvec_state */*tv*/);
144
145 /* --- @TVEC_TEST@, @TVEC_TEST_TAG@ --- *
146  *
147  * Arguments:   @tag@ = label-disambiguation tag
148  *              @struct tvec_test *t@ = space for a test definition
149  *
150  * Returns:     ---
151  *
152  * Use:         Control-structure macro: @TVEC_TEST(tv) stmt@ begins a test
153  *              case, executes @stmt@, and ends the test case.  If @stmt@
154  *              invokes @break@ then the test case is skipped.
155  *              @TVEC_TEST_TAG@ is the same, with an additional @tag@ argumet
156  *              for use in higher-level macros.
157  */
158
159 #define TVEC_TEST_TAG(tag, tv)                                          \
160         MC_WRAP(tag##__around,                                          \
161           { TVEC_BEGINTEST(tv); },                                      \
162           { tvec_endtest(tv); },                                        \
163           { if ((tv)->f&TVSF_ACTIVE) tvec_skip((tv), 0);                \
164             tvec_endtest(tv); })
165 #define TVEC_TEST(tv) TVEC_TEST_TAG(test, tv)
166
167 /* --- @tvec_withtest_setup@, @tvec_withttest_teardown@ --- *
168  *
169  * Arguments:   @struct tvec_state *tv@ = test-vector state
170  *              @struct tvec_withtest *wt@ = structure for internal state
171  *              @const char *file@, @unsigned lno@ = file and line
172  *                      information to set
173  *
174  * Returns:     ---
175  *
176  * Use:         These functions bracket an adhoc test, or a piece of a test.
177  *
178  *              The @tvec_withtest_setup@ function begins a new test if one
179  *              is not currently active, and (unconditionally) sets the
180  *              test-vector state's filename and line number to the values
181  *              given, saving some information in @*wt@ so that everything
182  *              can be restored later.
183  *
184  *              The @tvec_withtest_teardown@ function restores the previous
185  *              filename and line number, and ends a new test if
186  *              @tvec_withtest_setup@ begun one.  It also unconditionally
187  *              clears the register definitions and register-vector pointers.
188  *
189  *              These are the underlying functionality for the
190  *              @TVEC_WITHTEST_...@ family of macros.
191  */
192
193 extern void tvec_withtest_setup(struct tvec_state */*tv*/,
194                                 struct tvec_withtest */*wt*/,
195                                 const char */*file*/, unsigned /*lno*/);
196
197 extern void tvec_withtest_teardown(struct tvec_state */*tv*/,
198                                    struct tvec_withtest */*wt*/);
199
200 /* --- @TVEC_WITHTEST_DECLS@ --- *
201  *
202  * Declarations required by @TVEC_WITHTEST@ and related macros.
203  */
204
205 #define TVEC_WITHTEST_DECLS                                             \
206         struct tvec_state *_tvwt_tv;                                    \
207         struct tvec_withtest _tvwt_wt
208
209 /* --- @TVEC_WITHTEST_LOCTAG@, @TVEC_WITHTEST_TAG@,
210  *     @TVEC_WITHTEST_LOC@, @TVEC_WITHTEST@ --- *
211  *
212  * Arguments:   @tag@ = control-macro tag
213  *              @struct tvec_state *tv@ = test-vector state
214  *              @const char *file@, @unsigned lno@ = file and line
215  *                      information to set
216  *
217  * Returns:     ---
218  *
219  * Use:         These are statement heads.
220  *
221  *              If no test is active, then begin a new test.  Set the test
222  *              state's filename and line number to @file@ and @lno@, for the
223  *              @_LOC@ macros, or to the toplevel source filename and line
224  *              number.  Execute the statement.  If a new test was begun,
225  *              then end the test; restore the state's previous filename and
226  *              line number; and clear the current test register definitions
227  *              and register-vector pointers.
228  */
229
230 #define TVEC_WITHTEST_LOCTAG(tag, tv, file, lno)                        \
231         MC_BEFORE(tag##__tvwt_setup, {                                  \
232           _tvwt_tv = (tv);                                              \
233           tvec_withtest_setup(_tvwt_tv, &_tvwt_wt, (file), (lno));      \
234         })                                                              \
235         MC_AFTER(tag##__tvwt_teardown, {                                \
236           tvec_withtest_teardown(_tvwt_tv, &_tvwt_wt);                  \
237         })
238
239 #define TVEC_WITHTEST_LOC(tv, file, lno)                                \
240         TVEC_WITHTEST_LOCTAG(tvec_withtest, (tv), (file), (lno))
241
242 #define TVEC_WITHTEST_TAG(tag, tv)                                      \
243         TVEC_WITHTEST_LOCTAG(tag, (tv), __FILE__, __LINE__)
244
245 #define TVEC_WITHTEST(tag, tv)                                          \
246         TVEC_WITHTEST_LOCTAG(tvec_withtest, (tv), __FILE__, __LINE__)
247
248 /* --- @tvec_claim@, @tvec_claim_v@, @TVEC_CLAIM@ --- *
249  *
250  * Arguments:   @struct tvec_state *tv@ = test-vector state
251  *              @int ok@ = a flag
252  *              @const char *file@, @unsigned @lno@ = calling file and line
253  *              @const char *msg@, @va_list *ap@ = message to report on
254  *                      failure
255  *
256  * Returns:     The value @ok@.
257  *
258  * Use:         Check that a claimed condition holds, as (part of) a test.
259  *              If no test case is underway (i.e., if @TVSF_OPEN@ is reset in
260  *              @tv->f@), then a new test case is begun and ended.  The
261  *              @file@ and @lno@ are passed to the output formatter to be
262  *              reported in case of a failure.  If @ok@ is nonzero, then
263  *              nothing else happens; so, in particular, if @tvec_claim@
264  *              established a new test case, then the test case succeeds.  If
265  *              @ok@ is zero, then a failure is reported, quoting @msg@.
266  *
267  *              The @TVEC_CLAIM@ macro is similar, only it (a) identifies the
268  *              file and line number of the call site automatically, and (b)
269  *              implicitly quotes the source text of the @ok@ condition in
270  *              the failure message.
271  */
272
273 extern PRINTF_LIKE(5, 6)
274   int tvec_claim(struct tvec_state */*tv*/, int /*ok*/,
275                  const char */*file*/, unsigned /*lno*/,
276                  const char */*msg*/, ...);
277 extern int tvec_claim_v(struct tvec_state */*tv*/, int /*ok*/,
278                         const char */*file*/, unsigned /*lno*/,
279                         const char */*msg*/, va_list */*ap*/);
280 #define TVEC_CLAIM(tv, cond)                                            \
281         (tvec_claim(tv, !!(cond), __FILE__, __LINE__, "%s untrue", #cond))
282
283 /* --- @tvec_claimeq@ --- *
284  *
285  * Arguments:   @struct tvec_state *tv@ = test-vector state
286  *              @const struct tvec_regty *ty@ = register type
287  *              @const union tvec_misc *arg@ = register type argument
288  *              @const struct tvec_reg *rval, *rref@ = computed and reference
289  *                      registers
290  *              @const char *file@, @unsigned @lno@ = calling file and line
291  *              @const char *expr@ = the expression to quote on failure
292  *
293  * Returns:     Nonzero if the input and output values of register 0 are
294  *              equal, zero if they differ.
295  *
296  * Use:         Check that the (computed) value of @rval@ is equal to the
297  *              (reference) value of @rref@ (according to the register type
298  *              @ty@).  As for @tvec_claim@ above, a test case is
299  *              automatically begun and ended if none is already underway.
300  *              If the values are unequal, then @tvec_fail@ is called,
301  *              quoting @expr@, and the mismatched values are dumped.
302  *
303  *              The registers must have their @TVRF_LIVE@ flags set.
304  *
305  *              This function is not expected to be called directly, but
306  *              through type-specific wrapper functions or macros such as
307  *              @TVEC_CLAIMEQ_INT@.
308  */
309
310 int tvec_claimeq
311   (struct tvec_state */*tv*/,
312    const struct tvec_regty */*ty*/, const union tvec_misc */*arg*/,
313    const struct tvec_reg */*rval*/, const struct tvec_reg */*rref*/,
314    const char */*file*/, unsigned /*lno*/, const char */*expr*/);
315
316 /*----- That's all, folks -------------------------------------------------*/
317
318 #ifdef __cplusplus
319   }
320 #endif
321
322 #endif