1251876Speter/* Licensed to the Apache Software Foundation (ASF) under one or more
2251876Speter * contributor license agreements.  See the NOTICE file distributed with
3251876Speter * this work for additional information regarding copyright ownership.
4251876Speter * The ASF licenses this file to You under the Apache License, Version 2.0
5251876Speter * (the "License"); you may not use this file except in compliance with
6251876Speter * the License.  You may obtain a copy of the License at
7251876Speter *
8251876Speter *     http://www.apache.org/licenses/LICENSE-2.0
9251876Speter *
10251876Speter * Unless required by applicable law or agreed to in writing, software
11251876Speter * distributed under the License is distributed on an "AS IS" BASIS,
12251876Speter * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13251876Speter * See the License for the specific language governing permissions and
14251876Speter * limitations under the License.
15251876Speter */
16251876Speter
17251876Speter#include "abts.h"
18251876Speter#include "abts_tests.h"
19251876Speter#include "testutil.h"
20251876Speter
21251876Speter#define ABTS_STAT_SIZE 6
22251876Speterstatic char status[ABTS_STAT_SIZE] = {'|', '/', '-', '|', '\\', '-'};
23251876Speterstatic int curr_char;
24251876Speterstatic int verbose = 0;
25251876Speterstatic int exclude = 0;
26251876Speterstatic int quiet = 0;
27251876Speterstatic int list_tests = 0;
28251876Speter
29251876Speterconst char **testlist = NULL;
30251876Speter
31251876Speterstatic int find_test_name(const char *testname) {
32251876Speter    int i;
33251876Speter    for (i = 0; testlist[i] != NULL; i++) {
34251876Speter        if (!strcmp(testlist[i], testname)) {
35251876Speter            return 1;
36251876Speter        }
37251876Speter    }
38251876Speter    return 0;
39251876Speter}
40251876Speter
41251876Speter/* Determine if the test should be run at all */
42251876Speterstatic int should_test_run(const char *testname) {
43251876Speter    int found = 0;
44251876Speter    if (list_tests == 1) {
45251876Speter        return 0;
46251876Speter    }
47251876Speter    if (testlist == NULL) {
48251876Speter        return 1;
49251876Speter    }
50251876Speter    found = find_test_name(testname);
51251876Speter    if ((found && !exclude) || (!found && exclude)) {
52251876Speter        return 1;
53251876Speter    }
54251876Speter    return 0;
55251876Speter}
56251876Speter
57251876Speterstatic void reset_status(void)
58251876Speter{
59251876Speter    curr_char = 0;
60251876Speter}
61251876Speter
62251876Speterstatic void update_status(void)
63251876Speter{
64251876Speter    if (!quiet) {
65251876Speter        curr_char = (curr_char + 1) % ABTS_STAT_SIZE;
66251876Speter        fprintf(stdout, "\b%c", status[curr_char]);
67251876Speter        fflush(stdout);
68251876Speter    }
69251876Speter}
70251876Speter
71251876Speterstatic void end_suite(abts_suite *suite)
72251876Speter{
73251876Speter    if (suite != NULL) {
74251876Speter        sub_suite *last = suite->tail;
75251876Speter        if (!quiet) {
76251876Speter            fprintf(stdout, "\b");
77251876Speter            fflush(stdout);
78251876Speter        }
79251876Speter        if (last->failed == 0) {
80251876Speter            fprintf(stdout, "SUCCESS\n");
81251876Speter            fflush(stdout);
82251876Speter        }
83251876Speter        else {
84251876Speter            fprintf(stdout, "FAILED %d of %d\n", last->failed, last->num_test);
85251876Speter            fflush(stdout);
86251876Speter        }
87251876Speter    }
88251876Speter}
89251876Speter
90251876Speterabts_suite *abts_add_suite(abts_suite *suite, const char *suite_name_full)
91251876Speter{
92251876Speter    sub_suite *subsuite;
93251876Speter    char *p;
94251876Speter    const char *suite_name;
95251876Speter    curr_char = 0;
96251876Speter
97251876Speter    /* Only end the suite if we actually ran it */
98251876Speter    if (suite && suite->tail &&!suite->tail->not_run) {
99251876Speter        end_suite(suite);
100251876Speter    }
101251876Speter
102251876Speter    subsuite = malloc(sizeof(*subsuite));
103251876Speter    subsuite->num_test = 0;
104251876Speter    subsuite->failed = 0;
105251876Speter    subsuite->next = NULL;
106251876Speter    /* suite_name_full may be an absolute path depending on __FILE__
107251876Speter     * expansion */
108251876Speter    suite_name = strrchr(suite_name_full, '/');
109262253Speter    if (!suite_name) {
110262253Speter        suite_name = strrchr(suite_name_full, '\\');
111262253Speter    }
112251876Speter    if (suite_name) {
113251876Speter        suite_name++;
114251876Speter    } else {
115251876Speter        suite_name = suite_name_full;
116251876Speter    }
117251876Speter    p = strrchr(suite_name, '.');
118251876Speter    if (p) {
119251876Speter        subsuite->name = memcpy(calloc(p - suite_name + 1, 1),
120251876Speter                                suite_name, p - suite_name);
121251876Speter    }
122251876Speter    else {
123251876Speter        subsuite->name = suite_name;
124251876Speter    }
125251876Speter
126251876Speter    if (list_tests) {
127251876Speter        fprintf(stdout, "%s\n", subsuite->name);
128251876Speter    }
129251876Speter
130251876Speter    subsuite->not_run = 0;
131251876Speter
132251876Speter    if (suite == NULL) {
133251876Speter        suite = malloc(sizeof(*suite));
134251876Speter        suite->head = subsuite;
135251876Speter        suite->tail = subsuite;
136251876Speter    }
137251876Speter    else {
138251876Speter        suite->tail->next = subsuite;
139251876Speter        suite->tail = subsuite;
140251876Speter    }
141251876Speter
142251876Speter    if (!should_test_run(subsuite->name)) {
143251876Speter        subsuite->not_run = 1;
144251876Speter        return suite;
145251876Speter    }
146251876Speter
147251876Speter    reset_status();
148251876Speter    fprintf(stdout, "%-20s:  ", subsuite->name);
149251876Speter    update_status();
150251876Speter    fflush(stdout);
151251876Speter
152251876Speter    return suite;
153251876Speter}
154251876Speter
155251876Spetervoid abts_run_test(abts_suite *ts, test_func f, void *value)
156251876Speter{
157251876Speter    abts_case *tc;
158251876Speter    sub_suite *ss;
159251876Speter
160251876Speter    if (!should_test_run(ts->tail->name)) {
161251876Speter        return;
162251876Speter    }
163251876Speter    ss = ts->tail;
164251876Speter
165251876Speter    tc = malloc(sizeof(*tc));
166251876Speter    tc->failed = 0;
167251876Speter    tc->suite = ss;
168251876Speter
169251876Speter    ss->num_test++;
170251876Speter    update_status();
171251876Speter
172251876Speter    f(tc, value);
173251876Speter
174251876Speter    if (tc->failed) {
175251876Speter        ss->failed++;
176251876Speter    }
177251876Speter    free(tc);
178251876Speter}
179251876Speter
180251876Speterstatic int report(abts_suite *suite)
181251876Speter{
182251876Speter    int count = 0;
183251876Speter    sub_suite *dptr;
184251876Speter
185251876Speter    if (suite && suite->tail &&!suite->tail->not_run) {
186251876Speter        end_suite(suite);
187251876Speter    }
188251876Speter
189251876Speter    for (dptr = suite->head; dptr; dptr = dptr->next) {
190251876Speter        count += dptr->failed;
191251876Speter    }
192251876Speter
193251876Speter    if (list_tests) {
194251876Speter        return 0;
195251876Speter    }
196251876Speter
197251876Speter    if (count == 0) {
198251876Speter        printf("All tests passed.\n");
199251876Speter        return 0;
200251876Speter    }
201251876Speter
202251876Speter    dptr = suite->head;
203251876Speter    fprintf(stdout, "%-15s\t\tTotal\tFail\tFailed %%\n", "Failed Tests");
204251876Speter    fprintf(stdout, "===================================================\n");
205251876Speter    while (dptr != NULL) {
206251876Speter        if (dptr->failed != 0) {
207251876Speter            float percent = ((float)dptr->failed / (float)dptr->num_test);
208251876Speter            fprintf(stdout, "%-15s\t\t%5d\t%4d\t%6.2f%%\n", dptr->name,
209251876Speter                    dptr->num_test, dptr->failed, percent * 100);
210251876Speter        }
211251876Speter        dptr = dptr->next;
212251876Speter    }
213251876Speter    return 1;
214251876Speter}
215251876Speter
216251876Spetervoid abts_log_message(const char *fmt, ...)
217251876Speter{
218251876Speter    va_list args;
219251876Speter    update_status();
220251876Speter
221251876Speter    if (verbose) {
222251876Speter        va_start(args, fmt);
223251876Speter        vfprintf(stderr, fmt, args);
224251876Speter        va_end(args);
225251876Speter        fprintf(stderr, "\n");
226251876Speter        fflush(stderr);
227251876Speter    }
228251876Speter}
229251876Speter
230251876Spetervoid abts_int_equal(abts_case *tc, const int expected, const int actual, int lineno)
231251876Speter{
232251876Speter    update_status();
233251876Speter    if (tc->failed) return;
234251876Speter
235251876Speter    if (expected == actual) return;
236251876Speter
237251876Speter    tc->failed = TRUE;
238251876Speter    if (verbose) {
239251876Speter        fprintf(stderr, "Line %d: expected <%d>, but saw <%d>\n", lineno, expected, actual);
240251876Speter        fflush(stderr);
241251876Speter    }
242251876Speter}
243251876Speter
244251876Spetervoid abts_int_nequal(abts_case *tc, const int expected, const int actual, int lineno)
245251876Speter{
246251876Speter    update_status();
247251876Speter    if (tc->failed) return;
248251876Speter
249251876Speter    if (expected != actual) return;
250251876Speter
251251876Speter    tc->failed = TRUE;
252251876Speter    if (verbose) {
253262253Speter        fprintf(stderr, "Line %d: expected something other than <%d>, but saw <%d>\n",
254262253Speter                lineno, expected, actual);
255251876Speter        fflush(stderr);
256251876Speter    }
257251876Speter}
258251876Speter
259251876Spetervoid abts_str_equal(abts_case *tc, const char *expected, const char *actual, int lineno)
260251876Speter{
261251876Speter    update_status();
262251876Speter    if (tc->failed) return;
263251876Speter
264251876Speter    /* If both are NULL, match is good */
265251876Speter    if (!expected && !actual) return;
266251876Speter    if (expected && actual)
267251876Speter        if (!strcmp(expected, actual)) return;
268251876Speter
269251876Speter    tc->failed = TRUE;
270251876Speter    if (verbose) {
271251876Speter        fprintf(stderr, "Line %d: expected <%s>, but saw <%s>\n", lineno, expected, actual);
272251876Speter        fflush(stderr);
273251876Speter    }
274251876Speter}
275251876Speter
276251876Spetervoid abts_str_nequal(abts_case *tc, const char *expected, const char *actual,
277251876Speter                       size_t n, int lineno)
278251876Speter{
279251876Speter    update_status();
280251876Speter    if (tc->failed) return;
281251876Speter
282251876Speter    if (!strncmp(expected, actual, n)) return;
283251876Speter
284251876Speter    tc->failed = TRUE;
285251876Speter    if (verbose) {
286262253Speter        fprintf(stderr, "Line %d: expected something other than <%s>, but saw <%s>\n",
287262253Speter                lineno, expected, actual);
288251876Speter        fflush(stderr);
289251876Speter    }
290251876Speter}
291251876Speter
292251876Spetervoid abts_ptr_notnull(abts_case *tc, const void *ptr, int lineno)
293251876Speter{
294251876Speter    update_status();
295251876Speter    if (tc->failed) return;
296251876Speter
297251876Speter    if (ptr != NULL) return;
298251876Speter
299251876Speter    tc->failed = TRUE;
300251876Speter    if (verbose) {
301251876Speter        fprintf(stderr, "Line %d: expected non-NULL, but saw NULL\n", lineno);
302251876Speter        fflush(stderr);
303251876Speter    }
304251876Speter}
305251876Speter
306251876Spetervoid abts_ptr_equal(abts_case *tc, const void *expected, const void *actual, int lineno)
307251876Speter{
308251876Speter    update_status();
309251876Speter    if (tc->failed) return;
310251876Speter
311251876Speter    if (expected == actual) return;
312251876Speter
313251876Speter    tc->failed = TRUE;
314251876Speter    if (verbose) {
315251876Speter        fprintf(stderr, "Line %d: expected <%p>, but saw <%p>\n", lineno, expected, actual);
316251876Speter        fflush(stderr);
317251876Speter    }
318251876Speter}
319251876Speter
320251876Spetervoid abts_fail(abts_case *tc, const char *message, int lineno)
321251876Speter{
322251876Speter    update_status();
323251876Speter    if (tc->failed) return;
324251876Speter
325251876Speter    tc->failed = TRUE;
326251876Speter    if (verbose) {
327251876Speter        fprintf(stderr, "Line %d: %s\n", lineno, message);
328251876Speter        fflush(stderr);
329251876Speter    }
330251876Speter}
331251876Speter
332251876Spetervoid abts_assert(abts_case *tc, const char *message, int condition, int lineno)
333251876Speter{
334251876Speter    update_status();
335251876Speter    if (tc->failed) return;
336251876Speter
337251876Speter    if (condition) return;
338251876Speter
339251876Speter    tc->failed = TRUE;
340251876Speter    if (verbose) {
341251876Speter        fprintf(stderr, "Line %d: %s\n", lineno, message);
342251876Speter        fflush(stderr);
343251876Speter    }
344251876Speter}
345251876Speter
346251876Spetervoid abts_true(abts_case *tc, int condition, int lineno)
347251876Speter{
348251876Speter    update_status();
349251876Speter    if (tc->failed) return;
350251876Speter
351251876Speter    if (condition) return;
352251876Speter
353251876Speter    tc->failed = TRUE;
354251876Speter    if (verbose) {
355251876Speter        fprintf(stderr, "Line %d: Condition is false, but expected true\n", lineno);
356251876Speter        fflush(stderr);
357251876Speter    }
358251876Speter}
359251876Speter
360251876Spetervoid abts_not_impl(abts_case *tc, const char *message, int lineno)
361251876Speter{
362251876Speter    update_status();
363251876Speter
364251876Speter    tc->suite->not_impl++;
365251876Speter    if (verbose) {
366251876Speter        fprintf(stderr, "Line %d: %s\n", lineno, message);
367251876Speter        fflush(stderr);
368251876Speter    }
369251876Speter}
370251876Speter
371251876Speterint main(int argc, const char *const argv[]) {
372251876Speter    int i;
373251876Speter    int rv;
374251876Speter    int list_provided = 0;
375251876Speter    abts_suite *suite = NULL;
376251876Speter
377251876Speter    initialize();
378251876Speter
379251876Speter    quiet = !isatty(STDOUT_FILENO);
380251876Speter
381251876Speter    for (i = 1; i < argc; i++) {
382251876Speter        if (!strcmp(argv[i], "-v")) {
383251876Speter            verbose = 1;
384251876Speter            continue;
385251876Speter        }
386251876Speter        if (!strcmp(argv[i], "-x")) {
387251876Speter            exclude = 1;
388251876Speter            continue;
389251876Speter        }
390251876Speter        if (!strcmp(argv[i], "-l")) {
391251876Speter            list_tests = 1;
392251876Speter            continue;
393251876Speter        }
394251876Speter        if (!strcmp(argv[i], "-q")) {
395251876Speter            quiet = 1;
396251876Speter            continue;
397251876Speter        }
398251876Speter        if (argv[i][0] == '-') {
399251876Speter            fprintf(stderr, "Invalid option: `%s'\n", argv[i]);
400251876Speter            exit(1);
401251876Speter        }
402251876Speter        list_provided = 1;
403251876Speter    }
404251876Speter
405251876Speter    if (list_provided) {
406251876Speter        /* Waste a little space here, because it is easier than counting the
407251876Speter         * number of tests listed.  Besides it is at most three char *.
408251876Speter         */
409251876Speter        testlist = calloc(argc + 1, sizeof(char *));
410251876Speter        for (i = 1; i < argc; i++) {
411251876Speter            testlist[i - 1] = argv[i];
412251876Speter        }
413251876Speter    }
414251876Speter
415251876Speter    for (i = 0; i < (sizeof(alltests) / sizeof(struct testlist *)); i++) {
416251876Speter        suite = alltests[i].func(suite);
417251876Speter        apr_pool_clear(p);
418251876Speter    }
419251876Speter
420251876Speter    rv = report(suite);
421251876Speter    return rv;
422251876Speter}
423251876Speter
424