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