]> git.ipfire.org Git - thirdparty/git.git/blob - t/unit-tests/test-lib.c
Merge branch 'es/add-doc-list-short-form-of-all-in-synopsis'
[thirdparty/git.git] / t / unit-tests / test-lib.c
1 #include "test-lib.h"
2
3 enum result {
4 RESULT_NONE,
5 RESULT_FAILURE,
6 RESULT_SKIP,
7 RESULT_SUCCESS,
8 RESULT_TODO
9 };
10
11 static struct {
12 enum result result;
13 int count;
14 unsigned failed :1;
15 unsigned lazy_plan :1;
16 unsigned running :1;
17 unsigned skip_all :1;
18 unsigned todo :1;
19 } ctx = {
20 .lazy_plan = 1,
21 .result = RESULT_NONE,
22 };
23
24 #ifndef _MSC_VER
25 #define make_relative(location) location
26 #else
27 /*
28 * Visual C interpolates the absolute Windows path for `__FILE__`,
29 * but we want to see relative paths, as verified by t0080.
30 */
31 #include "dir.h"
32
33 static const char *make_relative(const char *location)
34 {
35 static char prefix[] = __FILE__, buf[PATH_MAX], *p;
36 static size_t prefix_len;
37
38 if (!prefix_len) {
39 size_t len = strlen(prefix);
40 const char *needle = "\\t\\unit-tests\\test-lib.c";
41 size_t needle_len = strlen(needle);
42
43 if (len < needle_len || strcmp(needle, prefix + len - needle_len))
44 die("unexpected suffix of '%s'", prefix);
45
46 /* let it end in a directory separator */
47 prefix_len = len - needle_len + 1;
48 }
49
50 /* Does it not start with the expected prefix? */
51 if (fspathncmp(location, prefix, prefix_len))
52 return location;
53
54 strlcpy(buf, location + prefix_len, sizeof(buf));
55 /* convert backslashes to forward slashes */
56 for (p = buf; *p; p++)
57 if (*p == '\\')
58 *p = '/';
59
60 return buf;
61 }
62 #endif
63
64 static void msg_with_prefix(const char *prefix, const char *format, va_list ap)
65 {
66 fflush(stderr);
67 if (prefix)
68 fprintf(stdout, "%s", prefix);
69 vprintf(format, ap); /* TODO: handle newlines */
70 putc('\n', stdout);
71 fflush(stdout);
72 }
73
74 void test_msg(const char *format, ...)
75 {
76 va_list ap;
77
78 va_start(ap, format);
79 msg_with_prefix("# ", format, ap);
80 va_end(ap);
81 }
82
83 void test_plan(int count)
84 {
85 assert(!ctx.running);
86
87 fflush(stderr);
88 printf("1..%d\n", count);
89 fflush(stdout);
90 ctx.lazy_plan = 0;
91 }
92
93 int test_done(void)
94 {
95 assert(!ctx.running);
96
97 if (ctx.lazy_plan)
98 test_plan(ctx.count);
99
100 return ctx.failed;
101 }
102
103 void test_skip(const char *format, ...)
104 {
105 va_list ap;
106
107 assert(ctx.running);
108
109 ctx.result = RESULT_SKIP;
110 va_start(ap, format);
111 if (format)
112 msg_with_prefix("# skipping test - ", format, ap);
113 va_end(ap);
114 }
115
116 void test_skip_all(const char *format, ...)
117 {
118 va_list ap;
119 const char *prefix;
120
121 if (!ctx.count && ctx.lazy_plan) {
122 /* We have not printed a test plan yet */
123 prefix = "1..0 # SKIP ";
124 ctx.lazy_plan = 0;
125 } else {
126 /* We have already printed a test plan */
127 prefix = "Bail out! # ";
128 ctx.failed = 1;
129 }
130 ctx.skip_all = 1;
131 ctx.result = RESULT_SKIP;
132 va_start(ap, format);
133 msg_with_prefix(prefix, format, ap);
134 va_end(ap);
135 }
136
137 int test__run_begin(void)
138 {
139 assert(!ctx.running);
140
141 ctx.count++;
142 ctx.result = RESULT_NONE;
143 ctx.running = 1;
144
145 return ctx.skip_all;
146 }
147
148 static void print_description(const char *format, va_list ap)
149 {
150 if (format) {
151 fputs(" - ", stdout);
152 vprintf(format, ap);
153 }
154 }
155
156 int test__run_end(int was_run UNUSED, const char *location, const char *format, ...)
157 {
158 va_list ap;
159
160 assert(ctx.running);
161 assert(!ctx.todo);
162
163 fflush(stderr);
164 va_start(ap, format);
165 if (!ctx.skip_all) {
166 switch (ctx.result) {
167 case RESULT_SUCCESS:
168 printf("ok %d", ctx.count);
169 print_description(format, ap);
170 break;
171
172 case RESULT_FAILURE:
173 printf("not ok %d", ctx.count);
174 print_description(format, ap);
175 break;
176
177 case RESULT_TODO:
178 printf("not ok %d", ctx.count);
179 print_description(format, ap);
180 printf(" # TODO");
181 break;
182
183 case RESULT_SKIP:
184 printf("ok %d", ctx.count);
185 print_description(format, ap);
186 printf(" # SKIP");
187 break;
188
189 case RESULT_NONE:
190 test_msg("BUG: test has no checks at %s",
191 make_relative(location));
192 printf("not ok %d", ctx.count);
193 print_description(format, ap);
194 ctx.result = RESULT_FAILURE;
195 break;
196 }
197 }
198 va_end(ap);
199 ctx.running = 0;
200 if (ctx.skip_all)
201 return 1;
202 putc('\n', stdout);
203 fflush(stdout);
204 ctx.failed |= ctx.result == RESULT_FAILURE;
205
206 return ctx.result != RESULT_FAILURE;
207 }
208
209 static void test_fail(void)
210 {
211 assert(ctx.result != RESULT_SKIP);
212
213 ctx.result = RESULT_FAILURE;
214 }
215
216 static void test_pass(void)
217 {
218 assert(ctx.result != RESULT_SKIP);
219
220 if (ctx.result == RESULT_NONE)
221 ctx.result = RESULT_SUCCESS;
222 }
223
224 static void test_todo(void)
225 {
226 assert(ctx.result != RESULT_SKIP);
227
228 if (ctx.result != RESULT_FAILURE)
229 ctx.result = RESULT_TODO;
230 }
231
232 int test_assert(const char *location, const char *check, int ok)
233 {
234 assert(ctx.running);
235
236 if (ctx.result == RESULT_SKIP) {
237 test_msg("skipping check '%s' at %s", check,
238 make_relative(location));
239 return 1;
240 }
241 if (!ctx.todo) {
242 if (ok) {
243 test_pass();
244 } else {
245 test_msg("check \"%s\" failed at %s", check,
246 make_relative(location));
247 test_fail();
248 }
249 }
250
251 return !!ok;
252 }
253
254 void test__todo_begin(void)
255 {
256 assert(ctx.running);
257 assert(!ctx.todo);
258
259 ctx.todo = 1;
260 }
261
262 int test__todo_end(const char *location, const char *check, int res)
263 {
264 assert(ctx.running);
265 assert(ctx.todo);
266
267 ctx.todo = 0;
268 if (ctx.result == RESULT_SKIP)
269 return 1;
270 if (res) {
271 test_msg("todo check '%s' succeeded at %s", check,
272 make_relative(location));
273 test_fail();
274 } else {
275 test_todo();
276 }
277
278 return !res;
279 }
280
281 int check_bool_loc(const char *loc, const char *check, int ok)
282 {
283 return test_assert(loc, check, ok);
284 }
285
286 union test__tmp test__tmp[2];
287
288 int check_int_loc(const char *loc, const char *check, int ok,
289 intmax_t a, intmax_t b)
290 {
291 int ret = test_assert(loc, check, ok);
292
293 if (!ret) {
294 test_msg(" left: %"PRIdMAX, a);
295 test_msg(" right: %"PRIdMAX, b);
296 }
297
298 return ret;
299 }
300
301 int check_uint_loc(const char *loc, const char *check, int ok,
302 uintmax_t a, uintmax_t b)
303 {
304 int ret = test_assert(loc, check, ok);
305
306 if (!ret) {
307 test_msg(" left: %"PRIuMAX, a);
308 test_msg(" right: %"PRIuMAX, b);
309 }
310
311 return ret;
312 }
313
314 static void print_one_char(char ch, char quote)
315 {
316 if ((unsigned char)ch < 0x20u || ch == 0x7f) {
317 /* TODO: improve handling of \a, \b, \f ... */
318 printf("\\%03o", (unsigned char)ch);
319 } else {
320 if (ch == '\\' || ch == quote)
321 putc('\\', stdout);
322 putc(ch, stdout);
323 }
324 }
325
326 static void print_char(const char *prefix, char ch)
327 {
328 printf("# %s: '", prefix);
329 print_one_char(ch, '\'');
330 fputs("'\n", stdout);
331 }
332
333 int check_char_loc(const char *loc, const char *check, int ok, char a, char b)
334 {
335 int ret = test_assert(loc, check, ok);
336
337 if (!ret) {
338 fflush(stderr);
339 print_char(" left", a);
340 print_char(" right", b);
341 fflush(stdout);
342 }
343
344 return ret;
345 }
346
347 static void print_str(const char *prefix, const char *str)
348 {
349 printf("# %s: ", prefix);
350 if (!str) {
351 fputs("NULL\n", stdout);
352 } else {
353 putc('"', stdout);
354 while (*str)
355 print_one_char(*str++, '"');
356 fputs("\"\n", stdout);
357 }
358 }
359
360 int check_str_loc(const char *loc, const char *check,
361 const char *a, const char *b)
362 {
363 int ok = (!a && !b) || (a && b && !strcmp(a, b));
364 int ret = test_assert(loc, check, ok);
365
366 if (!ret) {
367 fflush(stderr);
368 print_str(" left", a);
369 print_str(" right", b);
370 fflush(stdout);
371 }
372
373 return ret;
374 }