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 / _ \\ /| '_ \ / _` | __|
9 | __// \| |_) | (_| | |_
10 \___/_/\_\ .__/ \__,_|\__|
11 |_| XML parser
12
13 Copyright (c) 1997-2000 Thai Open Source Software Center Ltd
14 Copyright (c) 2000-2017 Expat development team
15 Licensed under the MIT license:
16
17 Permission is hereby granted, free of charge, to any person obtaining
18 a copy of this software and associated documentation files (the
19 "Software"), to deal in the Software without restriction, including
20 without limitation the rights to use, copy, modify, merge, publish,
21 distribute, sublicense, and/or sell copies of the Software, and to permit
22 persons to whom the Software is furnished to do so, subject to the
23 following conditions:
24
25 The above copyright notice and this permission notice shall be included
26 in all copies or substantial portions of the Software.
27
28 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
29 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
30 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
31 NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
32 DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
33 OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
34 USE OR OTHER DEALINGS IN THE SOFTWARE.
35 */
36
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <setjmp.h>
40 #include <assert.h>
41 #include <string.h>
42
43 #include "internal.h" /* for UNUSED_P only */
44 #include "minicheck.h"
45
46 Suite *
suite_create(const char * name)47 suite_create(const char *name)
48 {
49 Suite *suite = (Suite *) calloc(1, sizeof(Suite));
50 if (suite != NULL) {
51 suite->name = name;
52 }
53 return suite;
54 }
55
56 TCase *
tcase_create(const char * name)57 tcase_create(const char *name)
58 {
59 TCase *tc = (TCase *) calloc(1, sizeof(TCase));
60 if (tc != NULL) {
61 tc->name = name;
62 }
63 return tc;
64 }
65
66 void
suite_add_tcase(Suite * suite,TCase * tc)67 suite_add_tcase(Suite *suite, TCase *tc)
68 {
69 assert(suite != NULL);
70 assert(tc != NULL);
71 assert(tc->next_tcase == NULL);
72
73 tc->next_tcase = suite->tests;
74 suite->tests = tc;
75 }
76
77 void
tcase_add_checked_fixture(TCase * tc,tcase_setup_function setup,tcase_teardown_function teardown)78 tcase_add_checked_fixture(TCase *tc,
79 tcase_setup_function setup,
80 tcase_teardown_function teardown)
81 {
82 assert(tc != NULL);
83 tc->setup = setup;
84 tc->teardown = teardown;
85 }
86
87 void
tcase_add_test(TCase * tc,tcase_test_function test)88 tcase_add_test(TCase *tc, tcase_test_function test)
89 {
90 assert(tc != NULL);
91 if (tc->allocated == tc->ntests) {
92 int nalloc = tc->allocated + 100;
93 size_t new_size = sizeof(tcase_test_function) * nalloc;
94 tcase_test_function *new_tests = realloc(tc->tests, new_size);
95 assert(new_tests != NULL);
96 tc->tests = new_tests;
97 tc->allocated = nalloc;
98 }
99 tc->tests[tc->ntests] = test;
100 tc->ntests++;
101 }
102
103 static void
tcase_free(TCase * tc)104 tcase_free(TCase *tc)
105 {
106 if (! tc) {
107 return;
108 }
109
110 free(tc->tests);
111 free(tc);
112 }
113
114 static void
suite_free(Suite * suite)115 suite_free(Suite *suite)
116 {
117 if (! suite) {
118 return;
119 }
120
121 while (suite->tests != NULL) {
122 TCase *next = suite->tests->next_tcase;
123 tcase_free(suite->tests);
124 suite->tests = next;
125 }
126 free(suite);
127 }
128
129 SRunner *
srunner_create(Suite * suite)130 srunner_create(Suite *suite)
131 {
132 SRunner *runner = calloc(1, sizeof(SRunner));
133 if (runner != NULL) {
134 runner->suite = suite;
135 }
136 return runner;
137 }
138
139 static jmp_buf env;
140
141 static char const *_check_current_function = NULL;
142 static int _check_current_lineno = -1;
143 static char const *_check_current_filename = NULL;
144
145 void
_check_set_test_info(char const * function,char const * filename,int lineno)146 _check_set_test_info(char const *function, char const *filename, int lineno)
147 {
148 _check_current_function = function;
149 _check_current_lineno = lineno;
150 _check_current_filename = filename;
151 }
152
153
154 static void
add_failure(SRunner * runner,int verbosity)155 add_failure(SRunner *runner, int verbosity)
156 {
157 runner->nfailures++;
158 if (verbosity >= CK_VERBOSE) {
159 printf("%s:%d: %s\n", _check_current_filename,
160 _check_current_lineno, _check_current_function);
161 }
162 }
163
164 void
srunner_run_all(SRunner * runner,int verbosity)165 srunner_run_all(SRunner *runner, int verbosity)
166 {
167 Suite *suite;
168 TCase *tc;
169 assert(runner != NULL);
170 suite = runner->suite;
171 tc = suite->tests;
172 while (tc != NULL) {
173 int i;
174 for (i = 0; i < tc->ntests; ++i) {
175 runner->nchecks++;
176
177 if (tc->setup != NULL) {
178 /* setup */
179 if (setjmp(env)) {
180 add_failure(runner, verbosity);
181 continue;
182 }
183 tc->setup();
184 }
185 /* test */
186 if (setjmp(env)) {
187 add_failure(runner, verbosity);
188 continue;
189 }
190 (tc->tests[i])();
191
192 /* teardown */
193 if (tc->teardown != NULL) {
194 if (setjmp(env)) {
195 add_failure(runner, verbosity);
196 continue;
197 }
198 tc->teardown();
199 }
200 }
201 tc = tc->next_tcase;
202 }
203 if (verbosity) {
204 int passed = runner->nchecks - runner->nfailures;
205 double percentage = ((double) passed) / runner->nchecks;
206 int display = (int) (percentage * 100);
207 printf("%d%%: Checks: %d, Failed: %d\n",
208 display, runner->nchecks, runner->nfailures);
209 }
210 }
211
212 void
_fail_unless(int UNUSED_P (condition),const char * UNUSED_P (file),int UNUSED_P (line),const char * msg)213 _fail_unless(int UNUSED_P(condition), const char *UNUSED_P(file), int UNUSED_P(line), const char *msg)
214 {
215 /* Always print the error message so it isn't lost. In this case,
216 we have a failure, so there's no reason to be quiet about what
217 it is.
218 */
219 if (msg != NULL) {
220 const int has_newline = (msg[strlen(msg) - 1] == '\n');
221 fprintf(stderr, "ERROR: %s%s", msg, has_newline ? "" : "\n");
222 }
223 longjmp(env, 1);
224 }
225
226 int
srunner_ntests_failed(SRunner * runner)227 srunner_ntests_failed(SRunner *runner)
228 {
229 assert(runner != NULL);
230 return runner->nfailures;
231 }
232
233 void
srunner_free(SRunner * runner)234 srunner_free(SRunner *runner)
235 {
236 if (! runner) {
237 return;
238 }
239
240 suite_free(runner->suite);
241 free(runner);
242 }
243