minicheck.c revision b80e287d54a028e744f9fe412840a89ec7f8084b
1/* Miniature re-implementation of the "check" library.
2 *
3 * This is intended to support just enough of check to run the Expat
4 * tests.  This interface is based entirely on the portion of the
5 * check library being used.
6 */
7
8#include <stdio.h>
9#include <stdlib.h>
10#include <setjmp.h>
11#include <assert.h>
12
13#include "minicheck.h"
14
15Suite *
16suite_create(char *name)
17{
18    Suite *suite = (Suite *) calloc(1, sizeof(Suite));
19    if (suite != NULL) {
20        suite->name = name;
21    }
22    return suite;
23}
24
25TCase *
26tcase_create(char *name)
27{
28    TCase *tc = (TCase *) calloc(1, sizeof(TCase));
29    if (tc != NULL) {
30        tc->name = name;
31    }
32    return tc;
33}
34
35void
36suite_add_tcase(Suite *suite, TCase *tc)
37{
38    assert(suite != NULL);
39    assert(tc != NULL);
40    assert(tc->next_tcase == NULL);
41
42    tc->next_tcase = suite->tests;
43    suite->tests = tc;
44}
45
46void
47tcase_add_checked_fixture(TCase *tc,
48                          tcase_setup_function setup,
49                          tcase_teardown_function teardown)
50{
51    assert(tc != NULL);
52    tc->setup = setup;
53    tc->teardown = teardown;
54}
55
56void
57tcase_add_test(TCase *tc, tcase_test_function test)
58{
59    assert(tc != NULL);
60    if (tc->allocated == tc->ntests) {
61        int nalloc = tc->allocated + 100;
62        size_t new_size = sizeof(tcase_test_function) * nalloc;
63        tcase_test_function *new_tests = realloc(tc->tests, new_size);
64        assert(new_tests != NULL);
65        if (new_tests != tc->tests) {
66            free(tc->tests);
67            tc->tests = new_tests;
68        }
69        tc->allocated = nalloc;
70    }
71    tc->tests[tc->ntests] = test;
72    tc->ntests++;
73}
74
75SRunner *
76srunner_create(Suite *suite)
77{
78    SRunner *runner = calloc(1, sizeof(SRunner));
79    if (runner != NULL) {
80        runner->suite = suite;
81    }
82    return runner;
83}
84
85void
86srunner_set_fork_status(SRunner *runner, int status)
87{
88    /* We ignore this. */
89}
90
91static jmp_buf env;
92
93static char const *_check_current_function = NULL;
94static int _check_current_lineno = -1;
95static char const *_check_current_filename = NULL;
96
97void
98_check_set_test_info(char const *function, char const *filename, int lineno)
99{
100    _check_current_function = function;
101    _check_current_lineno = lineno;
102    _check_current_filename = filename;
103}
104
105
106static void
107add_failure(SRunner *runner, int verbosity)
108{
109    runner->nfailures++;
110    if (verbosity >= CK_VERBOSE) {
111        printf("%s:%d: %s\n", _check_current_filename,
112               _check_current_lineno, _check_current_function);
113    }
114}
115
116void
117srunner_run_all(SRunner *runner, int verbosity)
118{
119    Suite *suite;
120    TCase *tc;
121    assert(runner != NULL);
122    suite = runner->suite;
123    tc = suite->tests;
124    while (tc != NULL) {
125        int i;
126        for (i = 0; i < tc->ntests; ++i) {
127            runner->nchecks++;
128
129            if (tc->setup != NULL) {
130                /* setup */
131                if (setjmp(env)) {
132                    add_failure(runner, verbosity);
133                    continue;
134                }
135                tc->setup();
136            }
137            /* test */
138            if (setjmp(env)) {
139                add_failure(runner, verbosity);
140                continue;
141            }
142            (tc->tests[i])();
143
144            /* teardown */
145            if (tc->teardown != NULL) {
146                if (setjmp(env)) {
147                    add_failure(runner, verbosity);
148                    continue;
149                }
150                tc->teardown();
151            }
152        }
153        tc = tc->next_tcase;
154    }
155    if (verbosity) {
156        int passed = runner->nchecks - runner->nfailures;
157        double percentage = ((double) passed) / runner->nchecks;
158        int display = (int) (percentage * 100);
159        printf("%d%%: Checks: %d, Failed: %d\n",
160               display, runner->nchecks, runner->nfailures);
161    }
162}
163
164void
165_fail_unless(int condition, const char *file, int line, char *msg)
166{
167    longjmp(env, 1);
168}
169
170int
171srunner_ntests_failed(SRunner *runner)
172{
173    assert(runner != NULL);
174    return runner->nfailures;
175}
176
177void
178srunner_free(SRunner *runner)
179{
180    free(runner->suite);
181    free(runner);
182}
183