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
+static void msg_with_prefix(const char *prefix, const char *format, va_list ap)
25
+{
26
+ fflush(stderr);
27
+ if (prefix)
28
+ fprintf(stdout, "%s", prefix);
29
+ vprintf(format, ap); /* TODO: handle newlines */
30
+ putc('\n', stdout);
31
+ fflush(stdout);
32
+}
33
+
34
+void test_msg(const char *format, ...)
35
+{
36
+ va_list ap;
37
+
38
+ va_start(ap, format);
39
+ msg_with_prefix("# ", format, ap);
40
+ va_end(ap);
41
+}
42
+
43
+void test_plan(int count)
44
+{
45
+ assert(!ctx.running);
46
+
47
+ fflush(stderr);
48
+ printf("1..%d\n", count);
49
+ fflush(stdout);
50
+ ctx.lazy_plan = 0;
51
+}
52
+
53
+int test_done(void)
54
+{
55
+ assert(!ctx.running);
56
+
57
+ if (ctx.lazy_plan)
58
+ test_plan(ctx.count);
59
+
60
+ return ctx.failed;
61
+}
62
+
63
+void test_skip(const char *format, ...)
64
+{
65
+ va_list ap;
66
+
67
+ assert(ctx.running);
68
+
69
+ ctx.result = RESULT_SKIP;
70
+ va_start(ap, format);
71
+ if (format)
72
+ msg_with_prefix("# skipping test - ", format, ap);
73
+ va_end(ap);
74
+}
75
+
76
+void test_skip_all(const char *format, ...)
77
+{
78
+ va_list ap;
79
+ const char *prefix;
80
+
81
+ if (!ctx.count && ctx.lazy_plan) {
82
+ /* We have not printed a test plan yet */
83
+ prefix = "1..0 # SKIP ";
84
+ ctx.lazy_plan = 0;
85
+ } else {
86
+ /* We have already printed a test plan */
87
+ prefix = "Bail out! # ";
88
+ ctx.failed = 1;
89
+ }
90
+ ctx.skip_all = 1;
91
+ ctx.result = RESULT_SKIP;
92
+ va_start(ap, format);
93
+ msg_with_prefix(prefix, format, ap);
94
+ va_end(ap);
95
+}
96
+
97
+int test__run_begin(void)
98
+{
99
+ assert(!ctx.running);
100
+
101
+ ctx.count++;
102
+ ctx.result = RESULT_NONE;
103
+ ctx.running = 1;
104
+
105
+ return ctx.skip_all;
106
+}
107
+
108
+static void print_description(const char *format, va_list ap)
109
+{
110
+ if (format) {
111
+ fputs(" - ", stdout);
112
+ vprintf(format, ap);
113
+ }
114
+}
115
+
116
+int test__run_end(int was_run UNUSED, const char *location, const char *format, ...)
117
+{
118
+ va_list ap;
119
+
120
+ assert(ctx.running);
121
+ assert(!ctx.todo);
122
+
123
+ fflush(stderr);
124
+ va_start(ap, format);
125
+ if (!ctx.skip_all) {
126
+ switch (ctx.result) {
127
+ case RESULT_SUCCESS:
128
+ printf("ok %d", ctx.count);
129
+ print_description(format, ap);
130
+ break;
131
+
132
+ case RESULT_FAILURE:
133
+ printf("not ok %d", ctx.count);
134
+ print_description(format, ap);
135
+ break;
136
+
137
+ case RESULT_TODO:
138
+ printf("not ok %d", ctx.count);
139
+ print_description(format, ap);
140
+ printf(" # TODO");
141
+ break;
142
+
143
+ case RESULT_SKIP:
144
+ printf("ok %d", ctx.count);
145
+ print_description(format, ap);
146
+ printf(" # SKIP");
147
+ break;
148
+
149
+ case RESULT_NONE:
150
+ test_msg("BUG: test has no checks at %s", location);
151
+ printf("not ok %d", ctx.count);
152
+ print_description(format, ap);
153
+ ctx.result = RESULT_FAILURE;
154
+ break;
155
+ }
156
+ }
157
+ va_end(ap);
158
+ ctx.running = 0;
159
+ if (ctx.skip_all)
160
+ return 1;
161
+ putc('\n', stdout);
162
+ fflush(stdout);
163
+ ctx.failed |= ctx.result == RESULT_FAILURE;
164
+
165
+ return ctx.result != RESULT_FAILURE;
166
+}
167
+
168
+static void test_fail(void)
169
+{
170
+ assert(ctx.result != RESULT_SKIP);
171
+
172
+ ctx.result = RESULT_FAILURE;
173
+}
174
+
175
+static void test_pass(void)
176
+{
177
+ assert(ctx.result != RESULT_SKIP);
178
+
179
+ if (ctx.result == RESULT_NONE)
180
+ ctx.result = RESULT_SUCCESS;
181
+}
182
+
183
+static void test_todo(void)
184
+{
185
+ assert(ctx.result != RESULT_SKIP);
186
+
187
+ if (ctx.result != RESULT_FAILURE)
188
+ ctx.result = RESULT_TODO;
189
+}
190
+
191
+int test_assert(const char *location, const char *check, int ok)
192
+{
193
+ assert(ctx.running);
194
+
195
+ if (ctx.result == RESULT_SKIP) {
196
+ test_msg("skipping check '%s' at %s", check, location);
197
+ return 1;
198
+ }
199
+ if (!ctx.todo) {
200
+ if (ok) {
201
+ test_pass();
202
+ } else {
203
+ test_msg("check \"%s\" failed at %s", check, location);
204
+ test_fail();
205
+ }
206
+ }
207
+
208
+ return !!ok;
209
+}
210
+
211
+void test__todo_begin(void)
212
+{
213
+ assert(ctx.running);
214
+ assert(!ctx.todo);
215
+
216
+ ctx.todo = 1;
217
+}
218
+
219
+int test__todo_end(const char *location, const char *check, int res)
220
+{
221
+ assert(ctx.running);
222
+ assert(ctx.todo);
223
+
224
+ ctx.todo = 0;
225
+ if (ctx.result == RESULT_SKIP)
226
+ return 1;
227
+ if (res) {
228
+ test_msg("todo check '%s' succeeded at %s", check, location);
229
+ test_fail();
230
+ } else {
231
+ test_todo();
232
+ }
233
+
234
+ return !res;
235
+}
236
+
237
+int check_bool_loc(const char *loc, const char *check, int ok)
238
+{
239
+ return test_assert(loc, check, ok);
240
+}
241
+
242
+union test__tmp test__tmp[2];
243
+
244
+int check_int_loc(const char *loc, const char *check, int ok,
245
+ intmax_t a, intmax_t b)
246
+{
247
+ int ret = test_assert(loc, check, ok);
248
+
249
+ if (!ret) {
250
+ test_msg(" left: %"PRIdMAX, a);
251
+ test_msg(" right: %"PRIdMAX, b);
252
+ }
253
+
254
+ return ret;
255
+}
256
+
257
+int check_uint_loc(const char *loc, const char *check, int ok,
258
+ uintmax_t a, uintmax_t b)
259
+{
260
+ int ret = test_assert(loc, check, ok);
261
+
262
+ if (!ret) {
263
+ test_msg(" left: %"PRIuMAX, a);
264
+ test_msg(" right: %"PRIuMAX, b);
265
+ }
266
+
267
+ return ret;
268
+}
269
+
270
+static void print_one_char(char ch, char quote)
271
+{
272
+ if ((unsigned char)ch < 0x20u || ch == 0x7f) {
273
+ /* TODO: improve handling of \a, \b, \f ... */
274
+ printf("\\%03o", (unsigned char)ch);
275
+ } else {
276
+ if (ch == '\\' || ch == quote)
277
+ putc('\\', stdout);
278
+ putc(ch, stdout);
279
+ }
280
+}
281
+
282
+static void print_char(const char *prefix, char ch)
283
+{
284
+ printf("# %s: '", prefix);
285
+ print_one_char(ch, '\'');
286
+ fputs("'\n", stdout);
287
+}
288
+
289
+int check_char_loc(const char *loc, const char *check, int ok, char a, char b)
290
+{
291
+ int ret = test_assert(loc, check, ok);
292
+
293
+ if (!ret) {
294
+ fflush(stderr);
295
+ print_char(" left", a);
296
+ print_char(" right", b);
297
+ fflush(stdout);
298
+ }
299
+
300
+ return ret;
301
+}
302
+
303
+static void print_str(const char *prefix, const char *str)
304
+{
305
+ printf("# %s: ", prefix);
306
+ if (!str) {
307
+ fputs("NULL\n", stdout);
308
+ } else {
309
+ putc('"', stdout);
310
+ while (*str)
311
+ print_one_char(*str++, '"');
312
+ fputs("\"\n", stdout);
313
+ }
314
+}
315
+
316
+int check_str_loc(const char *loc, const char *check,
317
+ const char *a, const char *b)
318
+{
319
+ int ok = (!a && !b) || (a && b && !strcmp(a, b));
320
+ int ret = test_assert(loc, check, ok);
321
+
322
+ if (!ret) {
323
+ fflush(stderr);
324
+ print_str(" left", a);
325
+ print_str(" right", b);
326
+ fflush(stdout);
327
+ }
328
+
329
+ return ret;
330
+}