Commit | Line | Data |
---|---|---|
b1a20bee MW |
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 | extern const struct tvec_config tvec_adhocconfig; | |
46 | /* A special @struct tvec_config@ to use for programs which perform ad-hoc | |
47 | * testing. | |
48 | */ | |
49 | ||
50 | /*----- Functions provided ------------------------------------------------*/ | |
51 | ||
52 | /* --- @tvec_adhoc@ --- * | |
53 | * | |
54 | * Arguments: @struct tvec_state *tv@ = test-vector state | |
55 | * | |
56 | * Returns: --- | |
57 | * | |
58 | * Use: Begin ad-hoc testing, i.e., without reading a file of | |
59 | * test-vector data. | |
60 | * | |
61 | * The other functions in this section assume that @tvec_adhoc@ | |
62 | * has been called. | |
63 | */ | |
64 | ||
65 | extern void tvec_adhoc(struct tvec_state */*tv*/); | |
66 | ||
67 | /* --- @tvec_begingroup@, @TVEC_BEGINGROUP@ --- * | |
68 | * | |
69 | * Arguments: @struct tvec_state *tv@ = test-vector state | |
70 | * @const char *name@ = name for this test group | |
71 | * @const char *file@, @unsigned @lno@ = calling file and line | |
72 | * | |
73 | * Returns: --- | |
74 | * | |
75 | * Use: Begin an ad-hoc test group with the given name. The @file@ | |
76 | * and @lno@ can be anything, but it's usually best if they | |
77 | * refer to the source code performing the test: the macro | |
78 | * @TVEC_BEGINGROUP@ does this automatically. | |
79 | */ | |
80 | ||
81 | extern void tvec_begingroup(struct tvec_state */*tv*/, const char */*name*/, | |
82 | const char */*file*/, unsigned /*lno*/); | |
83 | #define TVEC_BEGINGROUP(tv, name) \ | |
84 | do tvec_begingroup(tv, name, __FILE__, __LINE__); while (0) | |
85 | ||
86 | /* --- @tvec_endgroup@ --- * | |
87 | * | |
88 | * Arguments: @struct tvec_state *tv@ = test-vector state | |
89 | * | |
90 | * Returns: --- | |
91 | * | |
92 | * Use: End an ad-hoc test group. The statistics are updated and the | |
93 | * outcome is reported to the output formatter. | |
94 | */ | |
95 | ||
96 | extern void tvec_endgroup(struct tvec_state */*tv*/); | |
97 | ||
98 | /* --- @TVEC_TESTGROUP@, @TVEC_TESTGROUP_TAG@ --- * | |
99 | * | |
100 | * Arguments: @tag@ = label-disambiguation tag | |
101 | * @const struct tvec_state *tv = test-vector state | |
102 | * @const char *name@ = test-group name | |
103 | * | |
104 | * Returns: --- | |
105 | * | |
106 | * Use: Control-structure macro: @TVEC_TESTGROUP(tv, name) stmt@ | |
107 | * establishes a test group with the given @name@ (attributing | |
108 | * it to the source file and lie number), executes @stmt@, and | |
109 | * ends the test group. If @stmt@ invokes @break@ then the test | |
110 | * group is skipped. @TVEC_TESTGROUP_TAG@ is the same, with an | |
111 | * additional @tag@ argument for use in higher-level macros. | |
112 | */ | |
113 | ||
114 | #define TVEC_TESTGROUP_TAG(tag, tv, name) \ | |
115 | MC_WRAP(tag##__around, \ | |
116 | { TVEC_BEGINGROUP(tv, name); }, \ | |
117 | { tvec_endgroup(tv); }, \ | |
118 | { if (!((tv)->f&TVSF_SKIP)) tvec_skipgroup(tv, 0); \ | |
119 | tvec_endgroup(tv); }) | |
120 | #define TVEC_TESTGROUP(tv, name) TVEC_TESTGROUP_TAG(grp, tv, name) | |
121 | ||
122 | /* --- @tvec_begintest@, @TVEC_BEGINTEST@ --- * | |
123 | * | |
124 | * Arguments: @struct tvec_state *tv@ = test-vector state | |
125 | * @const char *file@, @unsigned @lno@ = calling file and line | |
126 | * | |
127 | * Returns: --- | |
128 | * | |
129 | * Use: Begin an ad-hoc test case. The @file@ and @lno@ can be | |
130 | * anything, but it's usually best if they refer to the source | |
131 | * code performing the test: the macro @TVEC_BEGINGROUP@ does | |
132 | * this automatically. | |
133 | */ | |
134 | ||
135 | extern void tvec_begintest(struct tvec_state */*tv*/, | |
136 | const char */*file*/, unsigned /*lno*/); | |
137 | #define TVEC_BEGINTEST(tv) \ | |
138 | do tvec_begintest(tv, __FILE__, __LINE__); while (0) | |
139 | ||
140 | /* --- @tvec_endtest@ --- * | |
141 | * | |
142 | * Arguments: @struct tvec_state *tv@ = test-vector state | |
143 | * | |
144 | * Returns: --- | |
145 | * | |
146 | * Use: End an ad-hoc test case, The statistics are updated and the | |
147 | * outcome is reported to the output formatter. | |
148 | */ | |
149 | ||
150 | extern void tvec_endtest(struct tvec_state */*tv*/); | |
151 | ||
152 | /* --- @TVEC_TEST@, @TVEC_TEST_TAG@ --- * | |
153 | * | |
154 | * Arguments: @tag@ = label-disambiguation tag | |
155 | * @struct tvec_test *t@ = space for a test definition | |
156 | * | |
157 | * Returns: --- | |
158 | * | |
159 | * Use: Control-structure macro: @TVEC_TEST(tv) stmt@ begins a test | |
160 | * case, executes @stmt@, and ends the test case. If @stmt@ | |
161 | * invokes @break@ then the test case is skipped. | |
162 | * @TVEC_TEST_TAG@ is the same, with an additional @tag@ argumet | |
163 | * for use in higher-level macros. | |
164 | */ | |
165 | ||
166 | #define TVEC_TEST_TAG(tag, tv) \ | |
167 | MC_WRAP(tag##__around, \ | |
168 | { TVEC_BEGINTEST(tv); }, \ | |
169 | { tvec_endtest(tv); }, \ | |
170 | { if ((tv)->f&TVSF_ACTIVE) tvec_skip((tv), 0); \ | |
171 | tvec_endtest(tv); }) | |
172 | #define TVEC_TEST(tv) TVEC_TEST_TAG(test, tv) | |
173 | ||
174 | /* --- @tvec_claim@, @tvec_claim_v@, @TVEC_CLAIM@ --- * | |
175 | * | |
176 | * Arguments: @struct tvec_state *tv@ = test-vector state | |
177 | * @int ok@ = a flag | |
178 | * @const char *file@, @unsigned @lno@ = calling file and line | |
179 | * @const char *msg@, @va_list *ap@ = message to report on | |
180 | * failure | |
181 | * | |
182 | * Returns: The value @ok@. | |
183 | * | |
184 | * Use: Check that a claimed condition holds, as (part of) a test. | |
185 | * If no test case is underway (i.e., if @TVSF_OPEN@ is reset in | |
186 | * @tv->f@), then a new test case is begun and ended. The | |
187 | * @file@ and @lno@ are passed to the output formatter to be | |
188 | * reported in case of a failure. If @ok@ is nonzero, then | |
189 | * nothing else happens; so, in particular, if @tvec_claim@ | |
190 | * established a new test case, then the test case succeeds. If | |
191 | * @ok@ is zero, then a failure is reported, quoting @msg@. | |
192 | * | |
193 | * The @TVEC_CLAIM@ macro is similar, only it (a) identifies the | |
194 | * file and line number of the call site automatically, and (b) | |
195 | * implicitly quotes the source text of the @ok@ condition in | |
196 | * the failure message. | |
197 | */ | |
198 | ||
199 | extern PRINTF_LIKE(5, 6) | |
200 | int tvec_claim(struct tvec_state */*tv*/, int /*ok*/, | |
201 | const char */*file*/, unsigned /*lno*/, | |
202 | const char */*msg*/, ...); | |
203 | extern int tvec_claim_v(struct tvec_state */*tv*/, int /*ok*/, | |
204 | const char */*file*/, unsigned /*lno*/, | |
205 | const char */*msg*/, va_list */*ap*/); | |
206 | #define TVEC_CLAIM(tv, cond) \ | |
207 | (tvec_claim(tv, !!(cond), __FILE__, __LINE__, "%s untrue", #cond)) | |
208 | ||
209 | /* --- @tvec_claimeq@ --- * | |
210 | * | |
211 | * Arguments: @struct tvec_state *tv@ = test-vector state | |
212 | * @const struct tvec_regty *ty@ = register type | |
213 | * @const union tvec_misc *arg@ = register type argument | |
214 | * @const char *file@, @unsigned @lno@ = calling file and line | |
215 | * @const char *expr@ = the expression to quote on failure | |
216 | * | |
217 | * Returns: Nonzero if the input and output values of register 0 are | |
218 | * equal, zero if they differ. | |
219 | * | |
220 | * Use: Check that the input and output values of register 0 are | |
221 | * equal (according to the register type @ty@). As for | |
222 | * @tvec_claim@ above, a test case is automatically begun and | |
223 | * ended if none is already underway. If the values are | |
224 | * unequal, then @tvec_fail@ is called, quoting @expr@, and the | |
225 | * mismatched values are dumped. | |
226 | * | |
227 | * This function is not expected to be called directly, but | |
228 | * through type-specific wrapper functions or macros such as | |
229 | * @TVEC_CLAIMEQ_INT@. | |
230 | */ | |
231 | ||
232 | extern int tvec_claimeq(struct tvec_state */*tv*/, | |
233 | const struct tvec_regty */*ty*/, | |
234 | const union tvec_misc */*arg*/, | |
235 | const char */*file*/, unsigned /*lno*/, | |
236 | const char */*expr*/); | |
237 | ||
238 | /*----- That's all, folks -------------------------------------------------*/ | |
239 | ||
240 | #ifdef __cplusplus | |
241 | } | |
242 | #endif | |
243 | ||
244 | #endif |