3 * Test-vector framework ad-hoc testing interface
5 * (c) 2024 Straylight/Edgeware
8 /*----- Licensing notice --------------------------------------------------*
10 * This file is part of the mLib utilities library.
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.
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.
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,
28 #ifndef MLIB_TVEC_ADHOC_H
29 #define MLIB_TVEC_ADHOC_H
35 /*----- Header files ------------------------------------------------------*/
43 /*----- Data structures ---------------------------------------------------*/
45 struct tvec_withtest {
46 /* State for @tvec_withtest_setup@ and @tvec_withtest_teardown@. */
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 */
53 extern const struct tvec_config tvec_adhocconfig;
54 /* A special @struct tvec_config@ to use for programs which perform ad-hoc
58 /*----- Functions provided ------------------------------------------------*/
60 /* --- @tvec_begingroup@, @TVEC_BEGINGROUP@ --- *
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
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.
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)
79 /* --- @tvec_endgroup@ --- *
81 * Arguments: @struct tvec_state *tv@ = test-vector state
85 * Use: End an ad-hoc test group. The statistics are updated and the
86 * outcome is reported to the output formatter.
89 extern void tvec_endgroup(struct tvec_state */*tv*/);
91 /* --- @TVEC_TESTGROUP@, @TVEC_TESTGROUP_TAG@ --- *
93 * Arguments: @tag@ = label-disambiguation tag
94 * @const struct tvec_state *tv = test-vector state
95 * @const char *name@ = test-group name
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.
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)
115 /* --- @tvec_begintest@, @TVEC_BEGINTEST@ --- *
117 * Arguments: @struct tvec_state *tv@ = test-vector state
118 * @const char *file@, @unsigned @lno@ = calling file and line
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.
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)
133 /* --- @tvec_endtest@ --- *
135 * Arguments: @struct tvec_state *tv@ = test-vector state
139 * Use: End an ad-hoc test case, The statistics are updated and the
140 * outcome is reported to the output formatter.
143 extern void tvec_endtest(struct tvec_state */*tv*/);
145 /* --- @TVEC_TEST@, @TVEC_TEST_TAG@ --- *
147 * Arguments: @tag@ = label-disambiguation tag
148 * @struct tvec_test *t@ = space for a test definition
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.
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); \
165 #define TVEC_TEST(tv) TVEC_TEST_TAG(test, tv)
167 /* --- @tvec_withtest_setup@, @tvec_withttest_teardown@ --- *
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
176 * Use: These functions bracket an adhoc test, or a piece of a test.
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.
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.
189 * These are the underlying functionality for the
190 * @TVEC_WITHTEST_...@ family of macros.
193 extern void tvec_withtest_setup(struct tvec_state */*tv*/,
194 struct tvec_withtest */*wt*/,
195 const char */*file*/, unsigned /*lno*/);
197 extern void tvec_withtest_teardown(struct tvec_state */*tv*/,
198 struct tvec_withtest */*wt*/);
200 /* --- @TVEC_WITHTEST_DECLS@ --- *
202 * Declarations required by @TVEC_WITHTEST@ and related macros.
205 #define TVEC_WITHTEST_DECLS \
206 struct tvec_state *_tvwt_tv; \
207 struct tvec_withtest _tvwt_wt
209 /* --- @TVEC_WITHTEST_LOCTAG@, @TVEC_WITHTEST_TAG@,
210 * @TVEC_WITHTEST_LOC@, @TVEC_WITHTEST@ --- *
212 * Arguments: @tag@ = control-macro tag
213 * @struct tvec_state *tv@ = test-vector state
214 * @const char *file@, @unsigned lno@ = file and line
219 * Use: These are statement heads.
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.
230 #define TVEC_WITHTEST_LOCTAG(tag, tv, file, lno) \
231 MC_BEFORE(tag##__tvwt_setup, { \
233 tvec_withtest_setup(_tvwt_tv, &_tvwt_wt, (file), (lno)); \
235 MC_AFTER(tag##__tvwt_teardown, { \
236 tvec_withtest_teardown(_tvwt_tv, &_tvwt_wt); \
239 #define TVEC_WITHTEST_LOC(tv, file, lno) \
240 TVEC_WITHTEST_LOCTAG(tvec_withtest, (tv), (file), (lno))
242 #define TVEC_WITHTEST_TAG(tag, tv) \
243 TVEC_WITHTEST_LOCTAG(tag, (tv), __FILE__, __LINE__)
245 #define TVEC_WITHTEST(tag, tv) \
246 TVEC_WITHTEST_LOCTAG(tvec_withtest, (tv), __FILE__, __LINE__)
248 /* --- @tvec_claim@, @tvec_claim_v@, @TVEC_CLAIM@ --- *
250 * Arguments: @struct tvec_state *tv@ = test-vector state
252 * @const char *file@, @unsigned @lno@ = calling file and line
253 * @const char *msg@, @va_list *ap@ = message to report on
256 * Returns: The value @ok@.
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@.
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.
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))
283 /* --- @tvec_claimeq@ --- *
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
290 * @const char *file@, @unsigned @lno@ = calling file and line
291 * @const char *expr@ = the expression to quote on failure
293 * Returns: Nonzero if the input and output values of register 0 are
294 * equal, zero if they differ.
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.
303 * The registers must have their @TVRF_LIVE@ flags set.
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@.
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*/);
316 /*----- That's all, folks -------------------------------------------------*/