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