• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "internal.h"  /* for UNUSED_P only */
14 #include "minicheck.h"
15 
16 Suite *
suite_create(const char * name)17 suite_create(const char *name)
18 {
19     Suite *suite = (Suite *) calloc(1, sizeof(Suite));
20     if (suite != NULL) {
21         suite->name = name;
22     }
23     return suite;
24 }
25 
26 TCase *
tcase_create(const char * name)27 tcase_create(const char *name)
28 {
29     TCase *tc = (TCase *) calloc(1, sizeof(TCase));
30     if (tc != NULL) {
31         tc->name = name;
32     }
33     return tc;
34 }
35 
36 void
suite_add_tcase(Suite * suite,TCase * tc)37 suite_add_tcase(Suite *suite, TCase *tc)
38 {
39     assert(suite != NULL);
40     assert(tc != NULL);
41     assert(tc->next_tcase == NULL);
42 
43     tc->next_tcase = suite->tests;
44     suite->tests = tc;
45 }
46 
47 void
tcase_add_checked_fixture(TCase * tc,tcase_setup_function setup,tcase_teardown_function teardown)48 tcase_add_checked_fixture(TCase *tc,
49                           tcase_setup_function setup,
50                           tcase_teardown_function teardown)
51 {
52     assert(tc != NULL);
53     tc->setup = setup;
54     tc->teardown = teardown;
55 }
56 
57 void
tcase_add_test(TCase * tc,tcase_test_function test)58 tcase_add_test(TCase *tc, tcase_test_function test)
59 {
60     assert(tc != NULL);
61     if (tc->allocated == tc->ntests) {
62         int nalloc = tc->allocated + 100;
63         size_t new_size = sizeof(tcase_test_function) * nalloc;
64         tcase_test_function *new_tests = realloc(tc->tests, new_size);
65         assert(new_tests != NULL);
66         if (new_tests != tc->tests) {
67             free(tc->tests);
68             tc->tests = new_tests;
69         }
70         tc->allocated = nalloc;
71     }
72     tc->tests[tc->ntests] = test;
73     tc->ntests++;
74 }
75 
76 SRunner *
srunner_create(Suite * suite)77 srunner_create(Suite *suite)
78 {
79     SRunner *runner = calloc(1, sizeof(SRunner));
80     if (runner != NULL) {
81         runner->suite = suite;
82     }
83     return runner;
84 }
85 
86 static jmp_buf env;
87 
88 static char const *_check_current_function = NULL;
89 static int _check_current_lineno = -1;
90 static char const *_check_current_filename = NULL;
91 
92 void
_check_set_test_info(char const * function,char const * filename,int lineno)93 _check_set_test_info(char const *function, char const *filename, int lineno)
94 {
95     _check_current_function = function;
96     _check_current_lineno = lineno;
97     _check_current_filename = filename;
98 }
99 
100 
101 static void
add_failure(SRunner * runner,int verbosity)102 add_failure(SRunner *runner, int verbosity)
103 {
104     runner->nfailures++;
105     if (verbosity >= CK_VERBOSE) {
106         printf("%s:%d: %s\n", _check_current_filename,
107                _check_current_lineno, _check_current_function);
108     }
109 }
110 
111 void
srunner_run_all(SRunner * runner,int verbosity)112 srunner_run_all(SRunner *runner, int verbosity)
113 {
114     Suite *suite;
115     TCase *tc;
116     assert(runner != NULL);
117     suite = runner->suite;
118     tc = suite->tests;
119     while (tc != NULL) {
120         int i;
121         for (i = 0; i < tc->ntests; ++i) {
122             runner->nchecks++;
123 
124             if (tc->setup != NULL) {
125                 /* setup */
126                 if (setjmp(env)) {
127                     add_failure(runner, verbosity);
128                     continue;
129                 }
130                 tc->setup();
131             }
132             /* test */
133             if (setjmp(env)) {
134                 add_failure(runner, verbosity);
135                 continue;
136             }
137             (tc->tests[i])();
138 
139             /* teardown */
140             if (tc->teardown != NULL) {
141                 if (setjmp(env)) {
142                     add_failure(runner, verbosity);
143                     continue;
144                 }
145                 tc->teardown();
146             }
147         }
148         tc = tc->next_tcase;
149     }
150     if (verbosity) {
151         int passed = runner->nchecks - runner->nfailures;
152         double percentage = ((double) passed) / runner->nchecks;
153         int display = (int) (percentage * 100);
154         printf("%d%%: Checks: %d, Failed: %d\n",
155                display, runner->nchecks, runner->nfailures);
156     }
157 }
158 
159 void
_fail_unless(int UNUSED_P (condition),const char * UNUSED_P (file),int UNUSED_P (line),const char * msg)160 _fail_unless(int UNUSED_P(condition), const char *UNUSED_P(file), int UNUSED_P(line), const char *msg)
161 {
162     /* Always print the error message so it isn't lost.  In this case,
163        we have a failure, so there's no reason to be quiet about what
164        it is.
165     */
166     if (msg != NULL)
167         printf("%s", msg);
168     longjmp(env, 1);
169 }
170 
171 int
srunner_ntests_failed(SRunner * runner)172 srunner_ntests_failed(SRunner *runner)
173 {
174     assert(runner != NULL);
175     return runner->nfailures;
176 }
177 
178 void
srunner_free(SRunner * runner)179 srunner_free(SRunner *runner)
180 {
181     free(runner->suite);
182     free(runner);
183 }
184