minicheck.c revision 178848
1178848Scokane/* Miniature re-implementation of the "check" library.
2178848Scokane *
3178848Scokane * This is intended to support just enough of check to run the Expat
4178848Scokane * tests.  This interface is based entirely on the portion of the
5178848Scokane * check library being used.
6178848Scokane */
7178848Scokane
8178848Scokane#include <stdio.h>
9178848Scokane#include <stdlib.h>
10178848Scokane#include <setjmp.h>
11178848Scokane#include <assert.h>
12178848Scokane
13178848Scokane#include "minicheck.h"
14178848Scokane
15178848ScokaneSuite *
16178848Scokanesuite_create(char *name)
17178848Scokane{
18178848Scokane    Suite *suite = (Suite *) calloc(1, sizeof(Suite));
19178848Scokane    if (suite != NULL) {
20178848Scokane        suite->name = name;
21178848Scokane    }
22178848Scokane    return suite;
23178848Scokane}
24178848Scokane
25178848ScokaneTCase *
26178848Scokanetcase_create(char *name)
27178848Scokane{
28178848Scokane    TCase *tc = (TCase *) calloc(1, sizeof(TCase));
29178848Scokane    if (tc != NULL) {
30178848Scokane        tc->name = name;
31178848Scokane    }
32178848Scokane    return tc;
33178848Scokane}
34178848Scokane
35178848Scokanevoid
36178848Scokanesuite_add_tcase(Suite *suite, TCase *tc)
37178848Scokane{
38178848Scokane    assert(suite != NULL);
39178848Scokane    assert(tc != NULL);
40178848Scokane    assert(tc->next_tcase == NULL);
41178848Scokane
42178848Scokane    tc->next_tcase = suite->tests;
43178848Scokane    suite->tests = tc;
44178848Scokane}
45178848Scokane
46178848Scokanevoid
47178848Scokanetcase_add_checked_fixture(TCase *tc,
48178848Scokane                          tcase_setup_function setup,
49178848Scokane                          tcase_teardown_function teardown)
50178848Scokane{
51178848Scokane    assert(tc != NULL);
52178848Scokane    tc->setup = setup;
53178848Scokane    tc->teardown = teardown;
54178848Scokane}
55178848Scokane
56178848Scokanevoid
57178848Scokanetcase_add_test(TCase *tc, tcase_test_function test)
58178848Scokane{
59178848Scokane    assert(tc != NULL);
60178848Scokane    if (tc->allocated == tc->ntests) {
61178848Scokane        int nalloc = tc->allocated + 100;
62178848Scokane        size_t new_size = sizeof(tcase_test_function) * nalloc;
63178848Scokane        tcase_test_function *new_tests = realloc(tc->tests, new_size);
64178848Scokane        assert(new_tests != NULL);
65178848Scokane        if (new_tests != tc->tests) {
66178848Scokane            free(tc->tests);
67178848Scokane            tc->tests = new_tests;
68178848Scokane        }
69178848Scokane        tc->allocated = nalloc;
70178848Scokane    }
71178848Scokane    tc->tests[tc->ntests] = test;
72178848Scokane    tc->ntests++;
73178848Scokane}
74178848Scokane
75178848ScokaneSRunner *
76178848Scokanesrunner_create(Suite *suite)
77178848Scokane{
78178848Scokane    SRunner *runner = calloc(1, sizeof(SRunner));
79178848Scokane    if (runner != NULL) {
80178848Scokane        runner->suite = suite;
81178848Scokane    }
82178848Scokane    return runner;
83178848Scokane}
84178848Scokane
85178848Scokanestatic jmp_buf env;
86178848Scokane
87178848Scokanestatic char const *_check_current_function = NULL;
88178848Scokanestatic int _check_current_lineno = -1;
89178848Scokanestatic char const *_check_current_filename = NULL;
90178848Scokane
91178848Scokanevoid
92178848Scokane_check_set_test_info(char const *function, char const *filename, int lineno)
93178848Scokane{
94178848Scokane    _check_current_function = function;
95178848Scokane    _check_current_lineno = lineno;
96178848Scokane    _check_current_filename = filename;
97178848Scokane}
98178848Scokane
99178848Scokane
100178848Scokanestatic void
101178848Scokaneadd_failure(SRunner *runner, int verbosity)
102178848Scokane{
103178848Scokane    runner->nfailures++;
104178848Scokane    if (verbosity >= CK_VERBOSE) {
105178848Scokane        printf("%s:%d: %s\n", _check_current_filename,
106178848Scokane               _check_current_lineno, _check_current_function);
107178848Scokane    }
108178848Scokane}
109178848Scokane
110178848Scokanevoid
111178848Scokanesrunner_run_all(SRunner *runner, int verbosity)
112178848Scokane{
113178848Scokane    Suite *suite;
114178848Scokane    TCase *tc;
115178848Scokane    assert(runner != NULL);
116178848Scokane    suite = runner->suite;
117178848Scokane    tc = suite->tests;
118178848Scokane    while (tc != NULL) {
119178848Scokane        int i;
120178848Scokane        for (i = 0; i < tc->ntests; ++i) {
121178848Scokane            runner->nchecks++;
122178848Scokane
123178848Scokane            if (tc->setup != NULL) {
124178848Scokane                /* setup */
125178848Scokane                if (setjmp(env)) {
126178848Scokane                    add_failure(runner, verbosity);
127178848Scokane                    continue;
128178848Scokane                }
129178848Scokane                tc->setup();
130178848Scokane            }
131178848Scokane            /* test */
132178848Scokane            if (setjmp(env)) {
133178848Scokane                add_failure(runner, verbosity);
134178848Scokane                continue;
135178848Scokane            }
136178848Scokane            (tc->tests[i])();
137178848Scokane
138178848Scokane            /* teardown */
139178848Scokane            if (tc->teardown != NULL) {
140178848Scokane                if (setjmp(env)) {
141178848Scokane                    add_failure(runner, verbosity);
142178848Scokane                    continue;
143178848Scokane                }
144178848Scokane                tc->teardown();
145178848Scokane            }
146178848Scokane        }
147178848Scokane        tc = tc->next_tcase;
148178848Scokane    }
149178848Scokane    if (verbosity) {
150178848Scokane        int passed = runner->nchecks - runner->nfailures;
151178848Scokane        double percentage = ((double) passed) / runner->nchecks;
152178848Scokane        int display = (int) (percentage * 100);
153178848Scokane        printf("%d%%: Checks: %d, Failed: %d\n",
154178848Scokane               display, runner->nchecks, runner->nfailures);
155178848Scokane    }
156178848Scokane}
157178848Scokane
158178848Scokanevoid
159178848Scokane_fail_unless(int condition, const char *file, int line, char *msg)
160178848Scokane{
161178848Scokane    /* Always print the error message so it isn't lost.  In this case,
162178848Scokane       we have a failure, so there's no reason to be quiet about what
163178848Scokane       it is.
164178848Scokane    */
165178848Scokane    if (msg != NULL)
166178848Scokane        printf("%s", msg);
167178848Scokane    longjmp(env, 1);
168178848Scokane}
169178848Scokane
170178848Scokaneint
171178848Scokanesrunner_ntests_failed(SRunner *runner)
172178848Scokane{
173178848Scokane    assert(runner != NULL);
174178848Scokane    return runner->nfailures;
175178848Scokane}
176178848Scokane
177178848Scokanevoid
178178848Scokanesrunner_free(SRunner *runner)
179178848Scokane{
180178848Scokane    free(runner->suite);
181178848Scokane    free(runner);
182178848Scokane}
183