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, '/');
109251876Speter    if (suite_name) {
110251876Speter        suite_name++;
111251876Speter    } else {
112251876Speter        suite_name = suite_name_full;
113251876Speter    }
114251876Speter    p = strrchr(suite_name, '.');
115251876Speter    if (p) {
116251876Speter        subsuite->name = memcpy(calloc(p - suite_name + 1, 1),
117251876Speter                                suite_name, p - suite_name);
118251876Speter    }
119251876Speter    else {
120251876Speter        subsuite->name = suite_name;
121251876Speter    }
122251876Speter
123251876Speter    if (list_tests) {
124251876Speter        fprintf(stdout, "%s\n", subsuite->name);
125251876Speter    }
126251876Speter
127251876Speter    subsuite->not_run = 0;
128251876Speter
129251876Speter    if (suite == NULL) {
130251876Speter        suite = malloc(sizeof(*suite));
131251876Speter        suite->head = subsuite;
132251876Speter        suite->tail = subsuite;
133251876Speter    }
134251876Speter    else {
135251876Speter        suite->tail->next = subsuite;
136251876Speter        suite->tail = subsuite;
137251876Speter    }
138251876Speter
139251876Speter    if (!should_test_run(subsuite->name)) {
140251876Speter        subsuite->not_run = 1;
141251876Speter        return suite;
142251876Speter    }
143251876Speter
144251876Speter    reset_status();
145251876Speter    fprintf(stdout, "%-20s:  ", subsuite->name);
146251876Speter    update_status();
147251876Speter    fflush(stdout);
148251876Speter
149251876Speter    return suite;
150251876Speter}
151251876Speter
152251876Spetervoid abts_run_test(abts_suite *ts, test_func f, void *value)
153251876Speter{
154251876Speter    abts_case *tc;
155251876Speter    sub_suite *ss;
156251876Speter
157251876Speter    if (!should_test_run(ts->tail->name)) {
158251876Speter        return;
159251876Speter    }
160251876Speter    ss = ts->tail;
161251876Speter
162251876Speter    tc = malloc(sizeof(*tc));
163251876Speter    tc->failed = 0;
164251876Speter    tc->suite = ss;
165251876Speter
166251876Speter    ss->num_test++;
167251876Speter    update_status();
168251876Speter
169251876Speter    f(tc, value);
170251876Speter
171251876Speter    if (tc->failed) {
172251876Speter        ss->failed++;
173251876Speter    }
174251876Speter    free(tc);
175251876Speter}
176251876Speter
177251876Speterstatic int report(abts_suite *suite)
178251876Speter{
179251876Speter    int count = 0;
180251876Speter    sub_suite *dptr;
181251876Speter
182251876Speter    if (suite && suite->tail &&!suite->tail->not_run) {
183251876Speter        end_suite(suite);
184251876Speter    }
185251876Speter
186251876Speter    for (dptr = suite->head; dptr; dptr = dptr->next) {
187251876Speter        count += dptr->failed;
188251876Speter    }
189251876Speter
190251876Speter    if (list_tests) {
191251876Speter        return 0;
192251876Speter    }
193251876Speter
194251876Speter    if (count == 0) {
195251876Speter        printf("All tests passed.\n");
196251876Speter        return 0;
197251876Speter    }
198251876Speter
199251876Speter    dptr = suite->head;
200251876Speter    fprintf(stdout, "%-15s\t\tTotal\tFail\tFailed %%\n", "Failed Tests");
201251876Speter    fprintf(stdout, "===================================================\n");
202251876Speter    while (dptr != NULL) {
203251876Speter        if (dptr->failed != 0) {
204251876Speter            float percent = ((float)dptr->failed / (float)dptr->num_test);
205251876Speter            fprintf(stdout, "%-15s\t\t%5d\t%4d\t%6.2f%%\n", dptr->name,
206251876Speter                    dptr->num_test, dptr->failed, percent * 100);
207251876Speter        }
208251876Speter        dptr = dptr->next;
209251876Speter    }
210251876Speter    return 1;
211251876Speter}
212251876Speter
213251876Spetervoid abts_log_message(const char *fmt, ...)
214251876Speter{
215251876Speter    va_list args;
216251876Speter    update_status();
217251876Speter
218251876Speter    if (verbose) {
219251876Speter        va_start(args, fmt);
220251876Speter        vfprintf(stderr, fmt, args);
221251876Speter        va_end(args);
222251876Speter        fprintf(stderr, "\n");
223251876Speter        fflush(stderr);
224251876Speter    }
225251876Speter}
226251876Speter
227251876Spetervoid abts_int_equal(abts_case *tc, const int expected, const int actual, int lineno)
228251876Speter{
229251876Speter    update_status();
230251876Speter    if (tc->failed) return;
231251876Speter
232251876Speter    if (expected == actual) return;
233251876Speter
234251876Speter    tc->failed = TRUE;
235251876Speter    if (verbose) {
236251876Speter        fprintf(stderr, "Line %d: expected <%d>, but saw <%d>\n", lineno, expected, actual);
237251876Speter        fflush(stderr);
238251876Speter    }
239251876Speter}
240251876Speter
241251876Spetervoid abts_int_nequal(abts_case *tc, const int expected, const int actual, int lineno)
242251876Speter{
243251876Speter    update_status();
244251876Speter    if (tc->failed) return;
245251876Speter
246251876Speter    if (expected != actual) return;
247251876Speter
248251876Speter    tc->failed = TRUE;
249251876Speter    if (verbose) {
250251876Speter        fprintf(stderr, "Line %d: expected <%d>, but saw <%d>\n", lineno, expected, actual);
251251876Speter        fflush(stderr);
252251876Speter    }
253251876Speter}
254251876Speter
255251876Spetervoid abts_str_equal(abts_case *tc, const char *expected, const char *actual, int lineno)
256251876Speter{
257251876Speter    update_status();
258251876Speter    if (tc->failed) return;
259251876Speter
260251876Speter    /* If both are NULL, match is good */
261251876Speter    if (!expected && !actual) return;
262251876Speter    if (expected && actual)
263251876Speter        if (!strcmp(expected, actual)) return;
264251876Speter
265251876Speter    tc->failed = TRUE;
266251876Speter    if (verbose) {
267251876Speter        fprintf(stderr, "Line %d: expected <%s>, but saw <%s>\n", lineno, expected, actual);
268251876Speter        fflush(stderr);
269251876Speter    }
270251876Speter}
271251876Speter
272251876Spetervoid abts_str_nequal(abts_case *tc, const char *expected, const char *actual,
273251876Speter                       size_t n, int lineno)
274251876Speter{
275251876Speter    update_status();
276251876Speter    if (tc->failed) return;
277251876Speter
278251876Speter    if (!strncmp(expected, actual, n)) return;
279251876Speter
280251876Speter    tc->failed = TRUE;
281251876Speter    if (verbose) {
282251876Speter        fprintf(stderr, "Line %d: expected <%s>, but saw <%s>\n", lineno, expected, actual);
283251876Speter        fflush(stderr);
284251876Speter    }
285251876Speter}
286251876Speter
287251876Spetervoid abts_ptr_notnull(abts_case *tc, const void *ptr, int lineno)
288251876Speter{
289251876Speter    update_status();
290251876Speter    if (tc->failed) return;
291251876Speter
292251876Speter    if (ptr != NULL) return;
293251876Speter
294251876Speter    tc->failed = TRUE;
295251876Speter    if (verbose) {
296251876Speter        fprintf(stderr, "Line %d: expected non-NULL, but saw NULL\n", lineno);
297251876Speter        fflush(stderr);
298251876Speter    }
299251876Speter}
300251876Speter
301251876Spetervoid abts_ptr_equal(abts_case *tc, const void *expected, const void *actual, int lineno)
302251876Speter{
303251876Speter    update_status();
304251876Speter    if (tc->failed) return;
305251876Speter
306251876Speter    if (expected == actual) return;
307251876Speter
308251876Speter    tc->failed = TRUE;
309251876Speter    if (verbose) {
310251876Speter        fprintf(stderr, "Line %d: expected <%p>, but saw <%p>\n", lineno, expected, actual);
311251876Speter        fflush(stderr);
312251876Speter    }
313251876Speter}
314251876Speter
315251876Spetervoid abts_fail(abts_case *tc, const char *message, int lineno)
316251876Speter{
317251876Speter    update_status();
318251876Speter    if (tc->failed) return;
319251876Speter
320251876Speter    tc->failed = TRUE;
321251876Speter    if (verbose) {
322251876Speter        fprintf(stderr, "Line %d: %s\n", lineno, message);
323251876Speter        fflush(stderr);
324251876Speter    }
325251876Speter}
326251876Speter
327251876Spetervoid abts_assert(abts_case *tc, const char *message, int condition, int lineno)
328251876Speter{
329251876Speter    update_status();
330251876Speter    if (tc->failed) return;
331251876Speter
332251876Speter    if (condition) return;
333251876Speter
334251876Speter    tc->failed = TRUE;
335251876Speter    if (verbose) {
336251876Speter        fprintf(stderr, "Line %d: %s\n", lineno, message);
337251876Speter        fflush(stderr);
338251876Speter    }
339251876Speter}
340251876Speter
341251876Spetervoid abts_true(abts_case *tc, int condition, int lineno)
342251876Speter{
343251876Speter    update_status();
344251876Speter    if (tc->failed) return;
345251876Speter
346251876Speter    if (condition) return;
347251876Speter
348251876Speter    tc->failed = TRUE;
349251876Speter    if (verbose) {
350251876Speter        fprintf(stderr, "Line %d: Condition is false, but expected true\n", lineno);
351251876Speter        fflush(stderr);
352251876Speter    }
353251876Speter}
354251876Speter
355251876Spetervoid abts_not_impl(abts_case *tc, const char *message, int lineno)
356251876Speter{
357251876Speter    update_status();
358251876Speter
359251876Speter    tc->suite->not_impl++;
360251876Speter    if (verbose) {
361251876Speter        fprintf(stderr, "Line %d: %s\n", lineno, message);
362251876Speter        fflush(stderr);
363251876Speter    }
364251876Speter}
365251876Speter
366251876Speterint main(int argc, const char *const argv[]) {
367251876Speter    int i;
368251876Speter    int rv;
369251876Speter    int list_provided = 0;
370251876Speter    abts_suite *suite = NULL;
371251876Speter
372251876Speter    initialize();
373251876Speter
374251876Speter    quiet = !isatty(STDOUT_FILENO);
375251876Speter
376251876Speter    for (i = 1; i < argc; i++) {
377251876Speter        if (!strcmp(argv[i], "-v")) {
378251876Speter            verbose = 1;
379251876Speter            continue;
380251876Speter        }
381251876Speter        if (!strcmp(argv[i], "-x")) {
382251876Speter            exclude = 1;
383251876Speter            continue;
384251876Speter        }
385251876Speter        if (!strcmp(argv[i], "-l")) {
386251876Speter            list_tests = 1;
387251876Speter            continue;
388251876Speter        }
389251876Speter        if (!strcmp(argv[i], "-q")) {
390251876Speter            quiet = 1;
391251876Speter            continue;
392251876Speter        }
393251876Speter        if (argv[i][0] == '-') {
394251876Speter            fprintf(stderr, "Invalid option: `%s'\n", argv[i]);
395251876Speter            exit(1);
396251876Speter        }
397251876Speter        list_provided = 1;
398251876Speter    }
399251876Speter
400251876Speter    if (list_provided) {
401251876Speter        /* Waste a little space here, because it is easier than counting the
402251876Speter         * number of tests listed.  Besides it is at most three char *.
403251876Speter         */
404251876Speter        testlist = calloc(argc + 1, sizeof(char *));
405251876Speter        for (i = 1; i < argc; i++) {
406251876Speter            testlist[i - 1] = argv[i];
407251876Speter        }
408251876Speter    }
409251876Speter
410251876Speter    for (i = 0; i < (sizeof(alltests) / sizeof(struct testlist *)); i++) {
411251876Speter        suite = alltests[i].func(suite);
412251876Speter        apr_pool_clear(p);
413251876Speter    }
414251876Speter
415251876Speter    rv = report(suite);
416251876Speter    return rv;
417251876Speter}
418251876Speter
419