blob: f224eddaa0e1b96c96f1f9ae960c9c7634e01682 [file] [log] [blame]
lh9ed821d2023-04-07 01:36:19 -07001/* Copyright 2000-2004 Ryan Bloom
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 *
15 * Portions of this file were taken from testall.c in the APR test suite,
16 * written by members of the Apache Software Foundation.
17 */
18
19#include "abts.h"
20#include "abts_tests.h"
21#include "testutil.h"
22
23#define ABTS_STAT_SIZE 6
24static char status[ABTS_STAT_SIZE] = {'|', '/', '-', '|', '\\', '-'};
25static int curr_char;
26static int verbose = 1;
27static int exclude = 0;
28static int quiet = 0;
29static int list_tests = 0;
30
31const char **testlist = NULL;
32
33static int find_test_name(const char *testname) {
34 int i;
35 for (i = 0; testlist[i] != NULL; i++) {
36 if (!strcmp(testlist[i], testname)) {
37 return 1;
38 }
39 }
40 return 0;
41}
42
43/* Determine if the test should be run at all */
44static int should_test_run(const char *testname) {
45 int found = 0;
46 if (list_tests == 1) {
47 return 0;
48 }
49 if (testlist == NULL) {
50 return 1;
51 }
52 found = find_test_name(testname);
53 if ((found && !exclude) || (!found && exclude)) {
54 return 1;
55 }
56 return 0;
57}
58
59static void reset_status(void)
60{
61 curr_char = 0;
62}
63
64static void update_status(void)
65{
66 if (!quiet) {
67 curr_char = (curr_char + 1) % ABTS_STAT_SIZE;
68 fprintf(stdout, "\b%c", status[curr_char]);
69 fflush(stdout);
70 }
71}
72
73static void end_suite(abts_suite *suite)
74{
75 if (suite != NULL) {
76 sub_suite *last = suite->tail;
77 if (!quiet) {
78 fprintf(stdout, "\b");
79 fflush(stdout);
80 }
81 if (last->failed == 0) {
82 fprintf(stdout, "SUCCESS\n");
83 fflush(stdout);
84 }
85 else {
86 fprintf(stdout, "FAILED %d of %d\n", last->failed, last->num_test);
87 fflush(stdout);
88 }
89 }
90}
91
92abts_suite *abts_add_suite(abts_suite *suite, const char *suite_name_full)
93{
94 sub_suite *subsuite;
95 char *p;
96 const char *suite_name;
97 curr_char = 0;
98
99 /* Only end the suite if we actually ran it */
100 if (suite && suite->tail &&!suite->tail->not_run) {
101 end_suite(suite);
102 }
103
104 subsuite = malloc(sizeof(*subsuite));
105 subsuite->num_test = 0;
106 subsuite->failed = 0;
107 subsuite->next = NULL;
108 /* suite_name_full may be an absolute path depending on __FILE__
109 * expansion */
110 suite_name = strrchr(suite_name_full, '/');
111 if (suite_name) {
112 suite_name++;
113 } else {
114 suite_name = suite_name_full;
115 }
116 p = strrchr(suite_name, '.');
117 if (p) {
118 subsuite->name = memcpy(calloc(p - suite_name + 1, 1),
119 suite_name, p - suite_name);
120 }
121 else {
122 subsuite->name = suite_name;
123 }
124
125 if (list_tests) {
126 fprintf(stdout, "%s\n", subsuite->name);
127 }
128
129 subsuite->not_run = 0;
130
131 if (suite == NULL) {
132 suite = malloc(sizeof(*suite));
133 suite->head = subsuite;
134 suite->tail = subsuite;
135 }
136 else {
137 suite->tail->next = subsuite;
138 suite->tail = subsuite;
139 }
140
141 if (!should_test_run(subsuite->name)) {
142 subsuite->not_run = 1;
143 return suite;
144 }
145
146 reset_status();
147 fprintf(stdout, "%-20s: ", subsuite->name);
148 update_status();
149 fflush(stdout);
150
151 return suite;
152}
153
154void abts_run_test(abts_suite *ts, test_func f, void *value)
155{
156 abts_case tc;
157 sub_suite *ss;
158
159 if (!should_test_run(ts->tail->name)) {
160 return;
161 }
162 ss = ts->tail;
163
164 tc.failed = 0;
165 tc.suite = ss;
166
167 ss->num_test++;
168 update_status();
169
170 f(&tc, value);
171
172 if (tc.failed) {
173 ss->failed++;
174 }
175}
176
177static int report(abts_suite *suite)
178{
179 int count = 0;
180 sub_suite *dptr;
181
182 if (suite && suite->tail &&!suite->tail->not_run) {
183 end_suite(suite);
184 }
185
186 for (dptr = suite->head; dptr; dptr = dptr->next) {
187 count += dptr->failed;
188 }
189
190 if (list_tests) {
191 return 0;
192 }
193
194 if (count == 0) {
195 printf("All tests passed.\n");
196 return 0;
197 }
198
199 dptr = suite->head;
200 fprintf(stdout, "%-15s\t\tTotal\tFail\tFailed %%\n", "Failed Tests");
201 fprintf(stdout, "===================================================\n");
202 while (dptr != NULL) {
203 if (dptr->failed != 0) {
204 float percent = ((float)dptr->failed / (float)dptr->num_test);
205 fprintf(stdout, "%-15s\t\t%5d\t%4d\t%6.2f%%\n", dptr->name,
206 dptr->num_test, dptr->failed, percent * 100);
207 }
208 dptr = dptr->next;
209 }
210 return 1;
211}
212
213void abts_log_message(const char *fmt, ...)
214{
215 va_list args;
216 update_status();
217
218 if (verbose) {
219 va_start(args, fmt);
220 vfprintf(stderr, fmt, args);
221 va_end(args);
222 fprintf(stderr, "\n");
223 fflush(stderr);
224 }
225}
226
227void abts_int_equal(abts_case *tc, const int expected, const int actual, int lineno)
228{
229 update_status();
230 if (tc->failed) return;
231
232 if (expected == actual) return;
233
234 tc->failed = TRUE;
235 if (verbose) {
236 fprintf(stderr, "Line %d: expected <%d>, but saw <%d>\n", lineno, expected, actual);
237 fflush(stderr);
238 }
239}
240
241void abts_int_nequal(abts_case *tc, const int expected, const int actual, int lineno)
242{
243 update_status();
244 if (tc->failed) return;
245
246 if (expected != actual) return;
247
248 tc->failed = TRUE;
249 if (verbose) {
250 fprintf(stderr, "Line %d: expected <%d>, but saw <%d>\n", lineno, expected, actual);
251 fflush(stderr);
252 }
253}
254
255void abts_str_equal(abts_case *tc, const char *expected, const char *actual, int lineno)
256{
257 update_status();
258 if (tc->failed) return;
259
260 if (!expected && !actual) return;
261 if (expected && actual)
262 if (!strcmp(expected, actual)) return;
263
264 tc->failed = TRUE;
265 if (verbose) {
266 fprintf(stderr, "Line %d: expected <%s>, but saw <%s>\n", lineno, expected, actual);
267 fflush(stderr);
268 }
269}
270
271void abts_str_notequal(abts_case *tc, const char *expected, const char *actual, int lineno)
272{
273 update_status();
274 if (tc->failed) return;
275
276 if (!expected && !actual) return;
277 if (expected && actual)
278 if (strcmp(expected, actual) != 0) return;
279
280 tc->failed = TRUE;
281 if (verbose) {
282 fprintf(stderr, "Line %d: expected <%s> == saw <%s>, but we expect it not equal!\n", lineno, expected, actual);
283 fflush(stderr);
284 }
285}
286
287void abts_str_nequal(abts_case *tc, const char *expected, const char *actual,
288 size_t n, int lineno)
289{
290 update_status();
291 if (tc->failed) return;
292
293 if (!strncmp(expected, actual, n)) return;
294
295 tc->failed = TRUE;
296 if (verbose) {
297 fprintf(stderr, "Line %d: expected <%s>, but saw <%s>\n", lineno, expected, actual);
298 fflush(stderr);
299 }
300}
301
302void abts_ptr_notnull(abts_case *tc, const void *ptr, int lineno)
303{
304 update_status();
305 if (tc->failed) return;
306
307 if (ptr != NULL) return;
308
309 tc->failed = TRUE;
310 if (verbose) {
311 fprintf(stderr, "Line %d: Expected NULL, but saw <%p>\n", lineno, ptr);
312 fflush(stderr);
313 }
314}
315
316void abts_ptr_equal(abts_case *tc, const void *expected, const void *actual, int lineno)
317{
318 update_status();
319 if (tc->failed) return;
320
321 if (expected == actual) return;
322
323 tc->failed = TRUE;
324 if (verbose) {
325 fprintf(stderr, "Line %d: expected <%p>, but saw <%p>\n", lineno, expected, actual);
326 fflush(stderr);
327 }
328}
329
330void abts_fail(abts_case *tc, const char *message, int lineno)
331{
332 update_status();
333 if (tc->failed) return;
334
335 tc->failed = TRUE;
336 if (verbose) {
337 fprintf(stderr, "Line %d: %s\n", lineno, message);
338 fflush(stderr);
339 }
340}
341
342void abts_assert(abts_case *tc, const char *message, int condition, int lineno)
343{
344 update_status();
345 if (tc->failed) return;
346
347 if (condition) return;
348
349 tc->failed = TRUE;
350 if (verbose) {
351 fprintf(stderr, "Line %d: %s\n", lineno, message);
352 fflush(stderr);
353 }
354}
355
356void abts_true(abts_case *tc, int condition, int lineno)
357{
358 update_status();
359 if (tc->failed) return;
360
361 if (condition) return;
362
363 tc->failed = TRUE;
364 if (verbose) {
365 fprintf(stderr, "Line %d: Condition is false, but expected true\n", lineno);
366 fflush(stderr);
367 }
368}
369
370void abts_not_impl(abts_case *tc, const char *message, int lineno)
371{
372 update_status();
373
374 tc->suite->not_impl++;
375 if (verbose) {
376 fprintf(stderr, "Line %d: %s\n", lineno, message);
377 fflush(stderr);
378 }
379}
380
381int main(int argc, const char *const argv[]) {
382 int i;
383 int rv;
384 int list_provided = 0;
385 abts_suite *suite = NULL;
386
387 for (i = 1; i < argc; i++) {
388 if (!strcmp(argv[i], "-v")) {
389 verbose = 1;
390 continue;
391 }
392 if (!strcmp(argv[i], "-x")) {
393 exclude = 1;
394 continue;
395 }
396 if (!strcmp(argv[i], "-l")) {
397 list_tests = 1;
398 continue;
399 }
400 if (!strcmp(argv[i], "-q")) {
401 quiet = 1;
402 continue;
403 }
404 if (argv[i][0] == '-') {
405 fprintf(stderr, "Invalid option: `%s'\n", argv[i]);
406 exit(1);
407 }
408 list_provided = 1;
409 }
410
411 if (list_provided) {
412 /* Waste a little space here, because it is easier than counting the
413 * number of tests listed. Besides it is at most three char *.
414 */
415 testlist = calloc(argc + 1, sizeof(char *));
416 for (i = 1; i < argc; i++) {
417 testlist[i - 1] = argv[i];
418 }
419 }
420
421 initialize();
422
423 printf("sizeof alltests is: %d\n", (int)(sizeof(alltests) / sizeof(struct testlist *)));
424
425 for (i = 0; i < (sizeof(alltests) / sizeof(struct testlist *)); i++) {
426 suite = alltests[i].func(suite);
427 }
428
429 rv = report(suite);
430
431 return rv;
432}
433